diffstat for mbedtls-3.6.5 mbedtls-3.6.6

 3rdparty/everest/CMakeLists.txt                                      |    4 
 3rdparty/p256-m/CMakeLists.txt                                       |    4 
 BRANCHES.md                                                          |   21 
 CMakeLists.txt                                                       |   37 
 ChangeLog                                                            |  114 
 Makefile                                                             |    4 
 SECURITY.md                                                          |   26 
 debian/changelog                                                     |   19 
 debian/libmbedcrypto16.symbols                                       |    8 
 debian/libmbedtls21.symbols                                          |    2 
 docs/architecture/psa-shared-memory.md                               |    2 
 doxygen/input/doc_mainpage.h                                         |    2 
 doxygen/mbedtls.doxyfile                                             |    2 
 framework/data_files/Makefile                                        |   38 
 framework/data_files/ec_256_prv.der                                  |binary
 framework/data_files/ec_256_prv.pk8.der                              |binary
 framework/data_files/ec_256_prv.pk8.pem                              |    5 
 framework/data_files/ec_256_pub.der                                  |binary
 framework/data_files/parse_input/server5-rsa-signed.crt              |   15 
 framework/data_files/server11-rsa-signed.crt                         |   15 
 framework/data_files/server11.key                                    |    5 
 framework/data_files/server5-rsa-signed.crt                          |   15 
 framework/docs/architecture/config-check-framework.md                |  149 +
 framework/history/config-adjust-tfpsacrypto-1.0.txt                  |   26 
 framework/history/config-options-mbedtls-4.0.txt                     |    1 
 framework/history/config-options-tfpsacrypto-1.0.txt                 |   25 
 framework/psasim/.gitignore                                          |   26 
 framework/psasim/Makefile                                            |  172 -
 framework/psasim/README.md                                           |   68 
 framework/psasim/include/client.h                                    |   75 
 framework/psasim/include/common.h                                    |   52 
 framework/psasim/include/error_ext.h                                 |   19 
 framework/psasim/include/init.h                                      |   15 
 framework/psasim/include/lifecycle.h                                 |   17 
 framework/psasim/include/psa/client.h                                |   78 
 framework/psasim/include/psa/error.h                                 |   36 
 framework/psasim/include/psa/lifecycle.h                             |   17 
 framework/psasim/include/psa/service.h                               |  249 --
 framework/psasim/include/psasim/init.h                               |   15 
 framework/psasim/include/service.h                                   |  253 ++
 framework/psasim/include/util.h                                      |   33 
 framework/psasim/src/aut_main.c                                      |   71 
 framework/psasim/src/aut_psa_aead_encrypt.c                          |  227 +
 framework/psasim/src/aut_psa_aead_encrypt_decrypt.c                  |  126 +
 framework/psasim/src/aut_psa_asymmetric_encrypt_decrypt.c            |   81 
 framework/psasim/src/aut_psa_cipher_encrypt_decrypt.c                |   84 
 framework/psasim/src/aut_psa_hash.c                                  |  167 +
 framework/psasim/src/aut_psa_hash_compute.c                          |   81 
 framework/psasim/src/aut_psa_hkdf.c                                  |  121 +
 framework/psasim/src/aut_psa_key_agreement.c                         |  146 +
 framework/psasim/src/aut_psa_mac.c                                   |  162 +
 framework/psasim/src/aut_psa_random.c                                |   47 
 framework/psasim/src/aut_psa_sign_verify.c                           |   93 
 framework/psasim/src/client.c                                        |  379 ---
 framework/psasim/src/common.c                                        |   23 
 framework/psasim/src/common.h                                        |   85 
 framework/psasim/src/manifest.json                                   |   29 
 framework/psasim/src/psa_ff_client.c                                 |  385 +++
 framework/psasim/src/psa_ff_server.c                                 |  655 +++++
 framework/psasim/src/psa_sim_generate.pl                             | 1208 ++++++++++
 framework/psasim/src/psa_sim_serialise.pl                            | 1082 ++++++++
 framework/psasim/src/server.c                                        |  117 
 framework/psasim/src/service.c                                       |  655 -----
 framework/psasim/test/Makefile                                       |   12 
 framework/psasim/test/client.c                                       |   48 
 framework/psasim/test/kill_servers.sh                                |   17 
 framework/psasim/test/manifest.json                                  |   29 
 framework/psasim/test/run_test.sh                                    |   24 
 framework/psasim/test/server.c                                       |  105 
 framework/psasim/test/start_server.sh                                |   24 
 framework/psasim/tools/psa_autogen.py                                |  119 
 framework/scripts/all-core.sh                                        |   62 
 framework/scripts/assemble_changelog.py                              |    9 
 framework/scripts/audit-validity-dates.py                            |  468 +++
 framework/scripts/check-doxy-blocks.pl                               |    3 
 framework/scripts/check-python-files.sh                              |   28 
 framework/scripts/check_names.py                                     |  462 ++-
 framework/scripts/ci.requirements.txt                                |   11 
 framework/scripts/code_style.py                                      |   64 
 framework/scripts/ecp_comb_table.py                                  |  237 +
 framework/scripts/gen_ctr_drbg.pl                                    |   96 
 framework/scripts/gen_gcm_decrypt.pl                                 |  101 
 framework/scripts/gen_gcm_encrypt.pl                                 |   84 
 framework/scripts/gen_pkcs1_v21_sign_verify.pl                       |   74 
 framework/scripts/generate-afl-tests.sh                              |   71 
 framework/scripts/generate_config_tests.py                           |   11 
 framework/scripts/generate_psa_tests.py                              |   36 
 framework/scripts/generate_server9_bad_saltlen.py                    |   87 
 framework/scripts/generate_test_cert_macros.py                       |    3 
 framework/scripts/generate_test_code.py                              |    2 
 framework/scripts/generate_test_keys.py                              |   63 
 framework/scripts/generate_tls_handshake_tests.py                    |  213 -
 framework/scripts/lcov.sh                                            |  103 
 framework/scripts/make_generated_files.py                            |  175 -
 framework/scripts/massif_max.pl                                      |   36 
 framework/scripts/mbedtls_framework/asymmetric_key_data.py           |   88 
 framework/scripts/mbedtls_framework/c_build_helper.py                |    3 
 framework/scripts/mbedtls_framework/c_wrapper_generator.py           |   16 
 framework/scripts/mbedtls_framework/code_wrapper/psa_buffer.py       |    4 
 framework/scripts/mbedtls_framework/code_wrapper/psa_test_wrapper.py |   20 
 framework/scripts/mbedtls_framework/code_wrapper/psa_wrapper.py      |   60 
 framework/scripts/mbedtls_framework/config_checks_generator.py       |    7 
 framework/scripts/mbedtls_framework/config_history.py                |    2 
 framework/scripts/mbedtls_framework/config_macros.py                 |  180 +
 framework/scripts/mbedtls_framework/crypto_data_tests.py             |    7 
 framework/scripts/mbedtls_framework/crypto_knowledge.py              |   52 
 framework/scripts/mbedtls_framework/ecp.py                           |    8 
 framework/scripts/mbedtls_framework/generate_files_helper.py         |  182 +
 framework/scripts/mbedtls_framework/generated_files.py               |  167 +
 framework/scripts/mbedtls_framework/interface_checks.py              |  679 +++++
 framework/scripts/mbedtls_framework/macro_collector.py               |   33 
 framework/scripts/mbedtls_framework/psa_storage.py                   |    2 
 framework/scripts/mbedtls_framework/psa_test_case.py                 |   11 
 framework/scripts/mbedtls_framework/test_case.py                     |   20 
 framework/scripts/mbedtls_framework/test_data_generation.py          |   35 
 framework/scripts/mbedtls_framework/test_driver.py                   |  341 ++
 framework/scripts/mbedtls_framework/tls_handshake_tests.py           |  228 +
 framework/scripts/output_env.sh                                      |    3 
 framework/scripts/run-metatests.sh                                   |   89 
 framework/scripts/run_demos.py                                       |   65 
 framework/scripts/test_config_script.py                              |  175 +
 framework/scripts/test_psa_constant_names.py                         |    1 
 framework/tests/include/test/arguments.h                             |    2 
 framework/tests/include/test/asn1_helpers.h                          |    1 
 framework/tests/include/test/bignum_codepath_check.h                 |    2 
 framework/tests/include/test/bignum_helpers.h                        |    2 
 framework/tests/include/test/build_info.h                            |   24 
 framework/tests/include/test/constant_flow.h                         |    2 
 framework/tests/include/test/drivers/test_driver.h                   |    1 
 framework/tests/include/test/drivers/test_driver_common.h            |   62 
 framework/tests/include/test/drivers/xof.h                           |   63 
 framework/tests/include/test/fake_external_rng_for_test.h            |    2 
 framework/tests/include/test/fork_helpers.h                          |   61 
 framework/tests/include/test/helpers.h                               |   39 
 framework/tests/include/test/macros.h                                |   17 
 framework/tests/include/test/memory.h                                |    3 
 framework/tests/include/test/pk_helpers.h                            |   96 
 framework/tests/include/test/psa_crypto_helpers.h                    |    1 
 framework/tests/include/test/psa_exercise_key.h                      |    1 
 framework/tests/include/test/psa_helpers.h                           |    2 
 framework/tests/include/test/psa_memory_poisoning_wrappers.h         |    2 
 framework/tests/include/test/random.h                                |    2 
 framework/tests/include/test/threading_helpers.h                     |    8 
 framework/tests/programs/metatest.c                                  |   24 
 framework/tests/src/asn1_helpers.c                                   |    1 
 framework/tests/src/bignum_codepath_check.c                          |    1 
 framework/tests/src/bignum_helpers.c                                 |    3 
 framework/tests/src/drivers/hash.c                                   |    6 
 framework/tests/src/drivers/test_driver_aead.c                       |    6 
 framework/tests/src/drivers/test_driver_asymmetric_encryption.c      |    6 
 framework/tests/src/drivers/test_driver_cipher.c                     |    6 
 framework/tests/src/drivers/test_driver_key_agreement.c              |    8 
 framework/tests/src/drivers/test_driver_key_management.c             |   22 
 framework/tests/src/drivers/test_driver_mac.c                        |    6 
 framework/tests/src/drivers/test_driver_pake.c                       |    6 
 framework/tests/src/drivers/test_driver_signature.c                  |   17 
 framework/tests/src/drivers/xof.c                                    |  163 +
 framework/tests/src/fake_external_rng_for_test.c                     |    2 
 framework/tests/src/fork_helpers.c                                   |  244 ++
 framework/tests/src/helpers.c                                        |   50 
 framework/tests/src/pk_helpers.c                                     |  137 +
 framework/tests/src/psa_crypto_helpers.c                             |    1 
 framework/tests/src/psa_crypto_stubs.c                               |    1 
 framework/tests/src/psa_exercise_key.c                               |   10 
 framework/tests/src/psa_memory_poisoning_wrappers.c                  |    2 
 framework/tests/src/random.c                                         |    1 
 framework/tests/src/test_common.h                                    |   55 
 framework/tests/src/test_memory.c                                    |    1 
 framework/tests/src/threading_helpers.c                              |    1 
 framework/util/generate_mldsa_tests.py                               |  206 +
 framework/util/requirements.txt                                      |    5 
 framework/util/scripts_path.py                                       |   18 
 include/CMakeLists.txt                                               |    4 
 include/mbedtls/asn1write.h                                          |    4 
 include/mbedtls/build_info.h                                         |    8 
 include/mbedtls/config_adjust_legacy_crypto.h                        |   43 
 include/mbedtls/ctr_drbg.h                                           |    3 
 include/mbedtls/debug.h                                              |    2 
 include/mbedtls/ecdh.h                                               |    2 
 include/mbedtls/mbedtls_config.h                                     |   45 
 include/mbedtls/pk.h                                                 |    9 
 include/mbedtls/platform.h                                           |   31 
 include/mbedtls/ssl.h                                                |   75 
 include/psa/crypto_extra.h                                           |  182 +
 include/psa/crypto_sizes.h                                           |   16 
 library/CMakeLists.txt                                               |    9 
 library/Makefile                                                     |    1 
 library/aesce.c                                                      |   18 
 library/alignment.h                                                  |   23 
 library/base64.c                                                     |    3 
 library/ccm.c                                                        |   13 
 library/check_crypto_config.h                                        |    5 
 library/common.h                                                     |   46 
 library/constant_time.c                                              |    5 
 library/ctr_drbg.c                                                   |    4 
 library/debug.c                                                      |   10 
 library/debug_internal.h                                             |   13 
 library/entropy_poll.c                                               |    4 
 library/hmac_drbg.c                                                  |    4 
 library/net_sockets.c                                                |    4 
 library/pk.c                                                         |  133 -
 library/pk_internal.h                                                |   34 
 library/pk_wrap.c                                                    |   35 
 library/pkwrite.c                                                    |   30 
 library/platform_util.c                                              |   15 
 library/psa_crypto.c                                                 |  138 -
 library/psa_crypto_aead.c                                            |    3 
 library/psa_crypto_ffdh.c                                            |   62 
 library/psa_crypto_random.c                                          |  181 +
 library/psa_crypto_random.h                                          |   72 
 library/psa_crypto_random_impl.h                                     |   74 
 library/psa_crypto_slot_management.c                                 |    6 
 library/rsa.c                                                        |  146 -
 library/rsa_alt_helpers.c                                            |    2 
 library/sha256.c                                                     |   19 
 library/sha512.c                                                     |    9 
 library/ssl_debug_helpers.h                                          |    2 
 library/ssl_misc.h                                                   |    4 
 library/ssl_msg.c                                                    |  156 +
 library/ssl_tls.c                                                    |   32 
 library/ssl_tls12_client.c                                           |   52 
 library/ssl_tls12_server.c                                           |  224 -
 library/ssl_tls13_client.c                                           |    3 
 library/ssl_tls13_server.c                                           |   25 
 library/threading.c                                                  |    4 
 library/timing.c                                                     |    4 
 library/x509_create.c                                                |    3 
 library/x509_crt.c                                                   |   21 
 programs/Makefile                                                    |    2 
 programs/README.md                                                   |    2 
 programs/ssl/ssl_server2.c                                           |    8 
 programs/test/query_config.c                                         |   12 
 scripts/abi_check.py                                                 |  695 -----
 scripts/bump_version.sh                                              |    3 
 scripts/common.make                                                  |    2 
 scripts/generate_tls_handshake_tests.py                              |   14 
 scripts/lcov.sh                                                      |   87 
 scripts/make_generated_files.bat                                     |    3 
 scripts/prepare_release.sh                                           |   83 
 tests/.gitignore                                                     |    2 
 tests/CMakeLists.txt                                                 |    4 
 tests/Makefile                                                       |   10 
 tests/include/test/psa_test_wrappers.h                               |   15 
 tests/include/test/ssl_helpers.h                                     |   33 
 tests/include/test/test_certs.h                                      |  112 
 tests/include/test/test_keys.h                                       |  990 +++++++-
 tests/opt-testcases/handshake-generated.sh                           |   46 
 tests/scripts/analyze_outcomes.py                                    |   11 
 tests/scripts/check-generated-files.sh                               |    8 
 tests/scripts/components-basic-checks.sh                             |    2 
 tests/scripts/components-compiler.sh                                 |   42 
 tests/scripts/components-configuration-crypto.sh                     |    2 
 tests/scripts/components-configuration-tls.sh                        |    1 
 tests/scripts/components-configuration-x509.sh                       |    3 
 tests/scripts/components-configuration.sh                            |    2 
 tests/src/certs.c                                                    |    4 
 tests/src/psa_test_wrappers.c                                        |   34 
 tests/src/test_helpers/ssl_helpers.c                                 |    6 
 tests/ssl-opt.sh                                                     |  552 +++-
 tests/suites/host_test.function                                      |    5 
 tests/suites/main_test.function                                      |   11 
 tests/suites/test_suite_ccm.data                                     |   66 
 tests/suites/test_suite_ccm.function                                 |   45 
 tests/suites/test_suite_config.crypto_combinations.data              |   16 
 tests/suites/test_suite_config.function                              |    2 
 tests/suites/test_suite_debug.data                                   |   34 
 tests/suites/test_suite_debug.function                               |    6 
 tests/suites/test_suite_entropy.data                                 |    3 
 tests/suites/test_suite_entropy.function                             |   23 
 tests/suites/test_suite_pkwrite.function                             |   90 
 tests/suites/test_suite_platform.function                            |    2 
 tests/suites/test_suite_platform_printf.data                         |   64 
 tests/suites/test_suite_platform_printf.function                     |   57 
 tests/suites/test_suite_platform_unix.data                           |   16 
 tests/suites/test_suite_platform_unix.function                       |   68 
 tests/suites/test_suite_psa_crypto.data                              |  254 +-
 tests/suites/test_suite_psa_crypto.function                          |  311 ++
 tests/suites/test_suite_psa_crypto_entropy.data                      |   93 
 tests/suites/test_suite_psa_crypto_entropy.function                  |  609 +++++
 tests/suites/test_suite_psa_crypto_init.data                         |   49 
 tests/suites/test_suite_psa_crypto_init.function                     |  214 -
 tests/suites/test_suite_psa_crypto_op_fail.generated.data            |   74 
 tests/suites/test_suite_psa_crypto_persistent_key.data               |  150 +
 tests/suites/test_suite_psa_crypto_persistent_key.function           |  238 +
 tests/suites/test_suite_psa_crypto_storage_format.current.data       |   47 
 tests/suites/test_suite_psa_crypto_storage_format.v0.data            |   47 
 tests/suites/test_suite_ssl.data                                     |   22 
 tests/suites/test_suite_ssl.function                                 |  317 ++
 tests/suites/test_suite_version.data                                 |    4 
 tests/suites/test_suite_x509parse.data                               |    3 
 tests/suites/test_suite_x509parse.function                           |   12 
 visualc/VS2017/mbedTLS.vcxproj                                       |    9 
 292 files changed, 17367 insertions(+), 4904 deletions(-)

diff -Nru mbedtls-3.6.5/3rdparty/everest/CMakeLists.txt mbedtls-3.6.6/3rdparty/everest/CMakeLists.txt
--- mbedtls-3.6.5/3rdparty/everest/CMakeLists.txt	2025-10-14 19:12:36.729719400 +0300
+++ mbedtls-3.6.6/3rdparty/everest/CMakeLists.txt	2026-03-27 19:00:27.509472800 +0200
@@ -8,7 +8,7 @@
 target_include_directories(${everest_target}
   PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
          $<BUILD_INTERFACE:${MBEDTLS_DIR}/include>
-         $<INSTALL_INTERFACE:include>
+         $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
   PRIVATE include/everest
           include/everest/kremlib
           ${MBEDTLS_DIR}/library/)
@@ -29,7 +29,7 @@
 if(INSTALL_MBEDTLS_HEADERS)
 
   install(DIRECTORY include/everest
-    DESTINATION include
+    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
     FILE_PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
     DIRECTORY_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
     FILES_MATCHING PATTERN "*.h")
diff -Nru mbedtls-3.6.5/3rdparty/p256-m/CMakeLists.txt mbedtls-3.6.6/3rdparty/p256-m/CMakeLists.txt
--- mbedtls-3.6.5/3rdparty/p256-m/CMakeLists.txt	2025-10-14 19:12:36.743961300 +0300
+++ mbedtls-3.6.6/3rdparty/p256-m/CMakeLists.txt	2026-03-27 19:00:27.514543800 +0200
@@ -8,7 +8,7 @@
   PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
          $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/p256-m>
          $<BUILD_INTERFACE:${MBEDTLS_DIR}/include>
-         $<INSTALL_INTERFACE:include>
+         $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
   PRIVATE ${MBEDTLS_DIR}/library/)
 
 # Pass-through MBEDTLS_CONFIG_FILE and MBEDTLS_USER_CONFIG_FILE
@@ -27,7 +27,7 @@
 if(INSTALL_MBEDTLS_HEADERS)
 
   install(DIRECTORY :${CMAKE_CURRENT_SOURCE_DIR}
-    DESTINATION include
+    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
     FILE_PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
     DIRECTORY_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
     FILES_MATCHING PATTERN "*.h")
diff -Nru mbedtls-3.6.5/BRANCHES.md mbedtls-3.6.6/BRANCHES.md
--- mbedtls-3.6.5/BRANCHES.md	2025-10-14 19:12:36.747884800 +0300
+++ mbedtls-3.6.6/BRANCHES.md	2026-03-27 19:00:27.516376700 +0200
@@ -11,8 +11,8 @@
   as well as all the new features and bug fixes and security fixes.
 - One or more long-time support (LTS) branches: these only get bug fixes and
   security fixes. Currently, the supported LTS branches are:
-- [`mbedtls-2.28`](https://github.com/Mbed-TLS/mbedtls/tree/mbedtls-2.28).
 - [`mbedtls-3.6`](https://github.com/Mbed-TLS/mbedtls/tree/mbedtls-3.6).
+- [`mbedtls-4.1`](https://github.com/Mbed-TLS/mbedtls/tree/mbedtls-4.1).
 
 We retain a number of historical branches, whose names are prefixed by `archive/`,
 such as [`archive/mbedtls-2.7`](https://github.com/Mbed-TLS/mbedtls/tree/archive/mbedtls-2.7).
@@ -24,11 +24,11 @@
 compatibility on major version changes (e.g. from 3.x to 4.0). We also maintain
 ABI compatibility within LTS branches; see the next section for details.
 
-We will make regular LTS releases on an 18-month cycle, each of which will have
-a 3 year support lifetime. On this basis, 3.6 LTS (released March 2024) will be
-supported until March 2027. The next LTS release will be a 4.x release. Due to
-the size and scope of the 4.0 release, the release date of the first 4.x LTS is
-yet to be determined.
+We plan to make regular LTS releases on an 18-month cycle, each with a support
+lifetime of three years.On this basis, Mbed TLS 3.6 LTS (released in March 2024)
+will be supported until March 2027. Due to the size and scope of the 4.0 release,
+the first 4.x LTS, version 4.1, was released two years after 3.6, in March 2026,
+and will be supported until March 2029.
 
 ## Backwards Compatibility for application code
 
@@ -108,10 +108,9 @@
 - [`development`](https://github.com/Mbed-TLS/mbedtls/)
 - [`mbedtls-3.6`](https://github.com/Mbed-TLS/mbedtls/tree/mbedtls-3.6)
  maintained until March 2027, see
-  <https://github.com/Mbed-TLS/mbedtls/releases/tag/v3.6.5>.
-
-> Note: [**`mbedtls-2.28.10`**](https://github.com/Mbed-TLS/mbedtls/releases/tag/v2.28.10)
-is the last release of the 2.28 LTS and won't receive bug fixes or security fixes anymore.
-Users are advised to upgrade to a maintained version.
+  <https://github.com/Mbed-TLS/mbedtls/releases/tag/v3.6.6>.
+- [`mbedtls-4.1`](https://github.com/Mbed-TLS/mbedtls/tree/mbedtls-4.1)
+ maintained until March 2029, see
+  <https://github.com/Mbed-TLS/mbedtls/releases/tag/v4.1.0>.
 
 Users are urged to always use the latest version of a maintained branch.
diff -Nru mbedtls-3.6.5/ChangeLog mbedtls-3.6.6/ChangeLog
--- mbedtls-3.6.5/ChangeLog	2025-10-14 19:12:36.753099700 +0300
+++ mbedtls-3.6.6/ChangeLog	2026-03-27 19:00:27.518461500 +0200
@@ -1,5 +1,119 @@
 Mbed TLS ChangeLog (Sorted per branch, date)
 
+= Mbed TLS 3.6.6 branch released 2026-03-31
+
+Features
+   * The automatic computation of MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE has
+     been improved to take into account the following key types:
+     asymmetric keys, ciphers, AEADs, CMAC and HMAC.
+   * The device for reading entropy on platforms without a dedicated system
+     call can now be configured with MBEDTLS_PLATFORM_DEV_RANDOM or
+     mbedtls_platform_dev_random.
+   * Applications can use the new functions psa_random_reseed() to
+     request an immediate reseed of the PSA random generator, or
+     psa_random_deplete() to force a reseed on the next random generator call.
+   * Applications can call psa_random_set_prediction_resistance() to toggle
+     prediction resistance in the PSA random generator.
+
+Security
+   * The documentation of mbedtls_ssl_session_save(),
+     mbedtls_ssl_session_load(), mbedtls_ssl_context_save(), and
+     mbedtls_ssl_context_load() has been updated to clarify the responsibility
+     of the application to preserve the confidentiality and integrity of
+     serialized data, mitigating the risk of misuse of these APIs.
+     Credit to Haruto Kimura (Stella) and Eva Crystal (0xiviel) for
+     highlighting risks associated with tampered serialized data.
+   * The default device for reading entropy on platforms without a dedicated
+     system call is now /dev/random instead of /dev/urandom. This is safer
+     on Linux in case the application runs early after the kernel boots,
+     but may block needlessly on Linux <= 5.6. Reported by supers1ngular
+     (BayLibre).
+   * Fix missing validation of the peer's key in key agreement operations using
+     PSA_ALG_FFDH: low-order elements were not rejected as they should be. This
+     is a problem for protocols using FFDH that expect contributory behaviour,
+     that is, where neither party should be able to force the shared secret
+     into a small set. Reported independently by Eva Crystal (0xiviel) and
++    another reporter.
+   * Add tag length validation in mbedtls_ccm_finish() to prevent
+     out-of-bounds reads and mitigate potential application buffer
+     overflows where applications relied on the library to enforce
+     tag length constraints.
+     Reported by Eva Crystal (0xiviel).
+   * Fix a NULL pointer dereference in mbedtls_x509_string_to_names() when
+     mbedtls_calloc() fails to allocate memory. This was caused by failing to
+     check whether mbedtls_calloc() returned NULL. Found and reported by
+     Haruto Kimura (Stella).
+   * Fix a buffer overflow in psa_export_public_key() for FFDH keys when the
+     output buffer is too small. Found by Haruto Kimura (Stella).
+   * Fix a limited buffer underflow in x509_inet_pton_ipv6(). In rare cases
+     (e.g. on platforms with memory protection when the overread crosses page
+     boundary) this could lead to DoS. Found and reported by Haruto Kimura
+     (Stella). CVE-2026-25833
+   * If an application called psa_crypto_init() then fork() and continued to
+     use cryptography APIs (possibly indirectly, e.g. for TLS), the random
+     generator states were duplicated. Fix this by forcing a RNG reseed in
+     the child process. CVE-2026-25835
+   * Applications running in environments where the application state is
+     cloned (for example due to resuming a frozen system state multiple
+     times, or due to cloning a virtual machine image) should arrange to
+     reseed the random generator using one of the new functions
+     psa_random_reseed() or psa_random_deplete(). CVE-2026-25835
+   * Fix a bug in the TLS 1.2 client's signature algorithm check, which caused
+     the client to accept server key exchange messages signed with a signature
+     algorithm explicitly disallowed by the client. Found and reported by
+     EFR-GmbH and M. Heuft of Security-Research-Consulting GmbH. CVE-2026-25834
+   * Fixed an issue in TLS 1.3 server handling of the second ClientHello, after
+     sending a HelloRetryRequest message. A man-in-the-middle attacker could
+     force a TLS 1.3 session resumption using a ticket to fall back to an
+     unintended TLS 1.2 session resumption with an all-zero master secret.
+     This could result in client authentication being bypassed and allow client
+     impersonation.
+     Found and reported by Jaehun Lee, Pohang University of Science and
+     Technology (POSTECH).
+
+Bugfix
+   * Appease GCC 14.3's array bounds checker by inserting checks in mbedtls_xor
+     that bail before the byte-at-a-time loop when the array size is a constant
+     (using MBEDTLS_HAS_BUILTIN) and an exact multiple of the larger loop size.
+   * CMake now installs headers to `CMAKE_INSTALL_INCLUDEDIR` instead of the
+     hard-coded `include` directory.
+   * Prevent loading of peristent keys whose key ID belong to the volatile
+     range.
+   * Partially fix a performance regression in RSA operations introduced by a
+     security fix in 3.6.5, by improving the performance of RSA private key
+     operations when MBEDTLS_RSA_NO_CRT is disabled, which is the default.
+   * Fix compilation errors in `aesce.c` in some Visual Studio builds.
+     Fixes Mbed-TLS/TF-PSA-Crypto#548.
+   * Fix a build failure with MinGW when the __USE_MINGW_ANSI_STDIO option
+     is set. This was caused by the wrong format specifier being used to
+     print long long values (MBEDTLS_PRINTF_LONGLONG).
+   * Fix a bug that caused GCM tag calculations to fail, so that data was
+     correctly encrypted but could not be authenticated. The bug was only
+     observed with GCC 10.0 to 14.2 inclusive, when compiling with -O3, and
+     running without AESNI or AESCE.
+     Fixes #665.
+   * Fix a build failure with dietlibc.
+   * Support re-assembly of fragmented DTLS 1.2 ClientHello in Mbed TLS server.
+   * Support re-assembly of fragmented TLS 1.2 ClientHello in Mbed TLS server
+     even if TLS 1.3 support is disabled. This removes the main limitation on
+     support for re-assembly of fragmented handshake messages in TLS 1.2.
+   * Some functions in PK were using large buffers (around 2KB in the default
+     configuration) on the stack, which was a problem in environments with a
+     small stack. Those buffers are now allocated on the heap, except in
+     configurations where ECC is the only supported key type in PK, making PK
+     still independent of the heap in such configurations (if the ECC driver
+     itself is not using the heap). Fixes #476.
+
+Changes
+   * Add casts to some Enums to remove compiler errors thrown by IAR 6.5.
+     Removes Warning "mixed ENUM with other type".
+   * Tweak the detection of Unix-like platforms, which makes more system
+     interfaces (timing, threading) available on Haiku, QNX and Midipix.
+   * Harden mbedtls_ssl_get_verify_result() against misuse.
+     If the handshake has not yet been attempted, return -1u to indicate
+     that the result is not available. Previously the result of verification
+     was zero-initialized so the function would return 0 (indicating success).
+
 = Mbed TLS 3.6.5 branch released 2025-10-15
 
 API changes
diff -Nru mbedtls-3.6.5/CMakeLists.txt mbedtls-3.6.6/CMakeLists.txt
--- mbedtls-3.6.5/CMakeLists.txt	2025-10-14 19:12:36.749465700 +0300
+++ mbedtls-3.6.6/CMakeLists.txt	2026-03-27 19:00:27.516970000 +0200
@@ -40,12 +40,12 @@
 if(TEST_CPP)
     project("Mbed TLS"
         LANGUAGES C CXX
-        VERSION 3.6.5
+        VERSION 3.6.6
     )
 else()
     project("Mbed TLS"
         LANGUAGES C
-        VERSION 3.6.5
+        VERSION 3.6.6
     )
 endif()
 
@@ -352,9 +352,31 @@
          ${CMAKE_CURRENT_SOURCE_DIR}/framework/tests/src/*.c
          ${CMAKE_CURRENT_SOURCE_DIR}/framework/tests/src/drivers/*.c)
     add_library(mbedtls_test OBJECT ${MBEDTLS_TEST_FILES})
+
     if(GEN_FILES)
         add_custom_command(
             OUTPUT
+                ${CMAKE_CURRENT_BINARY_DIR}/tests/include/test/psa_test_wrappers.h
+                ${CMAKE_CURRENT_BINARY_DIR}/tests/src/psa_test_wrappers.c
+            COMMAND ${CMAKE_COMMAND} -E make_directory
+                ${CMAKE_CURRENT_BINARY_DIR}/tests/include/test
+                ${CMAKE_CURRENT_BINARY_DIR}/tests/src
+            COMMAND
+                "${MBEDTLS_PYTHON_EXECUTABLE}"
+                "${CMAKE_CURRENT_SOURCE_DIR}/framework/scripts/generate_psa_wrappers.py"
+                "--output-h" "${CMAKE_CURRENT_BINARY_DIR}/tests/include/test/psa_test_wrappers.h"
+                "--output-c" "${CMAKE_CURRENT_BINARY_DIR}/tests/src/psa_test_wrappers.c"
+            DEPENDS
+                ${CMAKE_CURRENT_SOURCE_DIR}/framework/scripts/generate_psa_wrappers.py
+        )
+        add_custom_target(psa_test_wrappers
+            DEPENDS
+                ${CMAKE_CURRENT_BINARY_DIR}/tests/include/test/psa_test_wrappers.h
+                ${CMAKE_CURRENT_BINARY_DIR}/tests/src/psa_test_wrappers.c)
+        add_dependencies(mbedtls_test psa_test_wrappers)
+
+        add_custom_command(
+            OUTPUT
                 ${CMAKE_CURRENT_BINARY_DIR}/tests/include/test/test_keys.h
             COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/tests/include/test
             COMMAND
@@ -367,6 +389,8 @@
         )
         add_custom_target(test_keys_header
             DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/tests/include/test/test_keys.h)
+        add_dependencies(mbedtls_test test_keys_header)
+
         add_custom_command(
             OUTPUT
                 ${CMAKE_CURRENT_BINARY_DIR}/tests/include/test/test_certs.h
@@ -382,8 +406,9 @@
                 ${CMAKE_CURRENT_SOURCE_DIR}/framework/scripts/generate_test_cert_macros.py
         )
         add_custom_target(test_certs_header DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/tests/include/test/test_certs.h)
-        add_dependencies(mbedtls_test test_keys_header test_certs_header)
+        add_dependencies(mbedtls_test test_certs_header)
     endif()
+
     target_include_directories(mbedtls_test
         PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/tests/include
         PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/framework/tests/include
@@ -443,9 +468,9 @@
         # 2. Run the relevant tests for the part of the code you're interested in.
         #    For the reference coverage measurement, see
         #    tests/scripts/basic-build-test.sh
-        # 3. Run scripts/lcov.sh to generate an HTML report.
+        # 3. Run ${MBEDTLS_FRAMEWORK_DIR}/scripts/lcov.sh to generate an HTML report.
         ADD_CUSTOM_TARGET(lcov
-            COMMAND scripts/lcov.sh
+            COMMAND ${MBEDTLS_FRAMEWORK_DIR}/scripts/lcov.sh
         )
 
         ADD_CUSTOM_TARGET(memcheck
@@ -476,7 +501,7 @@
     write_basic_package_version_file(
         "cmake/MbedTLSConfigVersion.cmake"
             COMPATIBILITY SameMajorVersion
-            VERSION 3.6.5)
+            VERSION 3.6.6)
 
     install(
         FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/MbedTLSConfig.cmake"
diff -Nru mbedtls-3.6.5/debian/changelog mbedtls-3.6.6/debian/changelog
--- mbedtls-3.6.5/debian/changelog	2026-01-02 23:05:58.000000000 +0200
+++ mbedtls-3.6.6/debian/changelog	2026-05-21 13:49:04.000000000 +0300
@@ -1,9 +1,24 @@
-mbedtls (3.6.5-0.1~deb13u1) trixie; urgency=medium
+mbedtls (3.6.6-0.1~deb13u1) trixie; urgency=medium
 
   * Non-maintainer upload.
   * Rebuild for trixie.
 
- -- Adrian Bunk <bunk@debian.org>  Fri, 02 Jan 2026 23:05:58 +0200
+ -- Adrian Bunk <bunk@debian.org>  Thu, 21 May 2026 13:49:04 +0300
+
+mbedtls (3.6.6-0.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * New upstream release.
+    - CVE-2026-25834: Signature Algorithm Injection
+    - CVE-2026-25835: PSA random generator cloning
+    - CVE-2026-34872: FFDH: improper input validation
+    - CVE-2026-34873: Client impersonation resuming a TLS 1.3 session
+    - CVE-2026-34874: Null pointer dereference setting a distinguished name
+    - CVE-2026-34875: Buffer overflow in FFDH public key export
+    - CVE-2026-34876: CCM multipart finish tag-length validation bypass
+    (Closes: #1133841, #1132577)
+
+ -- Adrian Bunk <bunk@debian.org>  Thu, 30 Apr 2026 15:38:39 +0300
 
 mbedtls (3.6.5-0.1) unstable; urgency=medium
 
diff -Nru mbedtls-3.6.5/debian/libmbedcrypto16.symbols mbedtls-3.6.6/debian/libmbedcrypto16.symbols
--- mbedtls-3.6.5/debian/libmbedcrypto16.symbols	2025-11-14 22:00:32.000000000 +0200
+++ mbedtls-3.6.6/debian/libmbedcrypto16.symbols	2026-04-30 15:38:39.000000000 +0300
@@ -537,6 +537,7 @@
  mbedtls_pkcs5_pbkdf2_hmac@Base 3.6.0
  mbedtls_pkcs5_pbkdf2_hmac_ext@Base 3.6.0
  mbedtls_pkcs5_self_test@Base 3.6.0
+ mbedtls_platform_dev_random@Base 3.6.6
  mbedtls_platform_entropy_poll@Base 3.6.0
  mbedtls_platform_gmtime_r@Base 3.6.0
  mbedtls_platform_setup@Base 3.6.0
@@ -841,6 +842,13 @@
  psa_parse_key_data_from_storage@Base 3.6.0
  psa_pk_status_to_mbedtls@Base 3.6.0
  psa_purge_key@Base 3.6.0
+ psa_random_deplete@Base 3.6.6
+ psa_random_internal_free@Base 3.6.6
+ psa_random_internal_generate@Base 3.6.6
+ psa_random_internal_init@Base 3.6.6
+ psa_random_internal_seed@Base 3.6.6
+ psa_random_reseed@Base 3.6.6
+ psa_random_set_prediction_resistance@Base 3.6.6
  psa_raw_key_agreement@Base 3.6.0
  psa_remove_key_data_from_memory@Base 3.6.0
  psa_reserve_free_key_slot@Base 3.6.0
diff -Nru mbedtls-3.6.5/debian/libmbedtls21.symbols mbedtls-3.6.6/debian/libmbedtls21.symbols
--- mbedtls-3.6.5/debian/libmbedtls21.symbols	2025-07-14 16:19:49.000000000 +0300
+++ mbedtls-3.6.6/debian/libmbedtls21.symbols	2026-04-30 15:38:39.000000000 +0300
@@ -8,6 +8,7 @@
  mbedtls_debug_print_ret@Base 3.6.0
  mbedtls_debug_printf_ecdh@Base 3.6.0
  mbedtls_debug_set_threshold@Base 3.6.0
+ mbedtls_debug_snprintf@Base 3.6.6
  mbedtls_mps_reader_commit@Base 3.6.0
  mbedtls_mps_reader_feed@Base 3.6.0
  mbedtls_mps_reader_free@Base 3.6.0
@@ -139,6 +140,7 @@
  mbedtls_ssl_get_extension_name@Base 3.6.0
  mbedtls_ssl_get_handshake_transcript@Base 3.6.0
  mbedtls_ssl_get_hostname_pointer@Base 3.6.3
+ mbedtls_ssl_get_hs_msg_name@Base 3.6.6
  mbedtls_ssl_get_hs_sni@Base 3.6.0
  mbedtls_ssl_get_input_max_frag_len@Base 3.6.0
  mbedtls_ssl_get_key_exchange_md_tls1_2@Base 3.6.0
diff -Nru mbedtls-3.6.5/docs/architecture/psa-shared-memory.md mbedtls-3.6.6/docs/architecture/psa-shared-memory.md
--- mbedtls-3.6.5/docs/architecture/psa-shared-memory.md	2025-10-14 19:12:36.846067000 +0300
+++ mbedtls-3.6.6/docs/architecture/psa-shared-memory.md	2026-03-27 19:00:27.526535500 +0200
@@ -663,7 +663,7 @@
 
 There now exists a more generic mechanism for making exactly this kind of transformation - the PSA test wrappers, which exist in the files `tests/include/test/psa_test_wrappers.h` and `tests/src/psa_test_wrappers.c`. These are wrappers around all PSA functions that allow testing code to be inserted at the start and end of a PSA function call.
 
-The test wrappers are generated by a script, although they are not automatically generated as part of the build process. Instead, they are checked into source control and must be manually updated when functions change by running `framework/scripts/generate_psa_wrappers.py`.
+The test wrappers are generated by a script `framework/scripts/generate_psa_wrappers.py` as part of the product build.
 
 Poisoning code is added to these test wrappers where relevant in order to pre-poison and post-unpoison the parameters to the functions.
 
diff -Nru mbedtls-3.6.5/doxygen/input/doc_mainpage.h mbedtls-3.6.6/doxygen/input/doc_mainpage.h
--- mbedtls-3.6.5/doxygen/input/doc_mainpage.h	2025-10-14 19:12:36.854489300 +0300
+++ mbedtls-3.6.6/doxygen/input/doc_mainpage.h	2026-03-27 19:00:27.530133700 +0200
@@ -10,7 +10,7 @@
  */
 
 /**
- * @mainpage Mbed TLS v3.6.5 API Documentation
+ * @mainpage Mbed TLS v3.6.6 API Documentation
  *
  * This documentation describes the internal structure of Mbed TLS.  It was
  * automatically generated from specially formatted comment blocks in
diff -Nru mbedtls-3.6.5/doxygen/mbedtls.doxyfile mbedtls-3.6.6/doxygen/mbedtls.doxyfile
--- mbedtls-3.6.5/doxygen/mbedtls.doxyfile	2025-10-14 19:12:36.855042000 +0300
+++ mbedtls-3.6.6/doxygen/mbedtls.doxyfile	2026-03-27 19:00:27.530455000 +0200
@@ -1,4 +1,4 @@
-PROJECT_NAME           = "Mbed TLS v3.6.5"
+PROJECT_NAME           = "Mbed TLS v3.6.6"
 OUTPUT_DIRECTORY       = ../apidoc/
 FULL_PATH_NAMES        = NO
 OPTIMIZE_OUTPUT_FOR_C  = YES
Binary files /tmp/vnP8b_MfUc/mbedtls-3.6.5/framework/data_files/ec_256_prv.der and /tmp/eylE9a1AUf/mbedtls-3.6.6/framework/data_files/ec_256_prv.der differ
Binary files /tmp/vnP8b_MfUc/mbedtls-3.6.5/framework/data_files/ec_256_prv.pk8.der and /tmp/eylE9a1AUf/mbedtls-3.6.6/framework/data_files/ec_256_prv.pk8.der differ
diff -Nru mbedtls-3.6.5/framework/data_files/ec_256_prv.pk8.pem mbedtls-3.6.6/framework/data_files/ec_256_prv.pk8.pem
--- mbedtls-3.6.5/framework/data_files/ec_256_prv.pk8.pem	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/data_files/ec_256_prv.pk8.pem	2026-03-27 12:34:57.703135500 +0200
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgfudpOVgKLbhYchqT
+OKGwquNHzbXu6Ftboqiz+7vWkFShRANCAASnNM81vPFrIDRSxd9q1KdnmCEKYY+f
+9cAHHHwPyWm6JIUGtE8dKTR15ECaVosFCUNuhS3ZZ7yJepqXUXISbMO5
+-----END PRIVATE KEY-----
Binary files /tmp/vnP8b_MfUc/mbedtls-3.6.5/framework/data_files/ec_256_pub.der and /tmp/eylE9a1AUf/mbedtls-3.6.6/framework/data_files/ec_256_pub.der differ
diff -Nru mbedtls-3.6.5/framework/data_files/Makefile mbedtls-3.6.6/framework/data_files/Makefile
--- mbedtls-3.6.5/framework/data_files/Makefile	2025-10-01 18:24:20.125367200 +0300
+++ mbedtls-3.6.6/framework/data_files/Makefile	2026-03-27 12:34:57.678974400 +0200
@@ -469,6 +469,17 @@
         -out $@
 all_final += server5-selfsigned.crt
 
+# Create a certificate which is almost identical to "server3.crt", i.e.
+# it contains a public EC key and it is signed with RSA. The main difference
+# compared to "server3.crt" is that in this case we use a secp256r1 key ("server5.key")
+# instead of secp192r1 one that is used in "server3.crt".
+parse_input/server5-rsa-signed.crt server5-rsa-signed.crt: server5.key
+	$(MBEDTLS_CERT_WRITE) subject_key=$< subject_name="C=NL,O=PolarSSL,CN=localhost" serial=13 \
+		issuer_crt=$(test_ca_crt) issuer_key=$(test_ca_key_file_rsa) issuer_pwd=$(test_ca_pwd_rsa) \
+		not_before=20251201101530 not_after=20351201101530 \
+		md=SHA256 version=3 output_file=$@
+all_final += server5-rsa-signed.crt
+
 parse_input/server5-othername.crt.der: server5.key
 	$(OPENSSL) req -x509 -new -subj "/C=UK/O=Mbed TLS/CN=Mbed TLS othername SAN" -set_serial 77 -config $(test_ca_config_file) -extensions othername_san -days 3650 -sha256 -key $< -outform der -out $@
 
@@ -625,6 +636,18 @@
 	cat $^ > $@
 all_final += server10_int3_spurious_int-ca2.crt
 
+# server11 *
+
+# This is basically identical to "server5-rsa-signed.crt" but using a secp256k1
+# key instead of secp256r1 one in order not to fall in the list of allowed curves
+# for suite-b profile.
+server11-rsa-signed.crt: server11.key
+	$(MBEDTLS_CERT_WRITE) subject_key=$< subject_name="C=NL,O=PolarSSL,CN=localhost" serial=13 \
+		issuer_crt=$(test_ca_crt) issuer_key=$(test_ca_key_file_rsa) issuer_pwd=$(test_ca_pwd_rsa) \
+		not_before=20251201101530 not_after=20351201101530 \
+		md=SHA1 version=3 output_file=$@
+all_final += server11-rsa-signed.crt
+
 rsa_pkcs1_2048_public.pem: server8.key
 	$(OPENSSL)  rsa -in $< -outform PEM -RSAPublicKey_out -out $@
 all_final += rsa_pkcs1_2048_public.pem
@@ -1635,6 +1658,10 @@
 	$(OPENSSL) genpkey -algorithm EC -pkeyopt ec_paramgen_curve:prime192v1 -pkeyopt ec_param_enc:named_curve -out $@ -outform DER
 all_final += ec_prv.pk8.der
 
+ec_256_prv.pk8.der:
+	$(OPENSSL) genpkey -algorithm EC -pkeyopt ec_paramgen_curve:prime256v1 -pkeyopt ec_param_enc:named_curve -out $@ -outform DER
+all_final += ec_256_prv.pk8.der
+
 # ### Instructions for creating `ec_prv.pk8nopub.der`,
 # ### `ec_prv.pk8nopubparam.der`, and `ec_prv.pk8param.der` by hand from
 # ### `ec_prv.pk8.der`.
@@ -1694,6 +1721,9 @@
 ec_prv.pk8.pem: ec_prv.pk8.der
 	$(OPENSSL) pkey -in $< -inform DER -out $@
 all_final += ec_prv.pk8.pem
+ec_256_prv.pk8.pem: ec_256_prv.pk8.der
+	$(OPENSSL) pkey -in $< -outform PEM -out $@
+all_final += ec_256_prv.pk8.pem
 ec_prv.pk8nopub.pem: ec_prv.pk8nopub.der
 	$(OPENSSL) pkey -in $< -inform DER -out $@
 all_final += ec_prv.pk8nopub.pem
@@ -1839,6 +1869,14 @@
 	$(OPENSSL) pkey -in $< -out $@ -outform DER
 all_final += ec_prv.sec1.der
 
+ec_256_prv.der: ec_256_prv.pem
+	$(OPENSSL) pkey -in $< -out $@ -outform DER
+all_final += ec_256_prv.pem
+
+ec_256_pub.der: ec_256_prv.pem
+	$(OPENSSL) pkey -in $< -outform DER -pubout -out $@
+all_final += ec_256_pub.der
+
 ec_256_long_prv.der: ec_256_long_prv.pem
 	$(OPENSSL) pkey -in $< -out $@ -outform DER
 all_final += ec_256_long_prv.der
diff -Nru mbedtls-3.6.5/framework/data_files/parse_input/server5-rsa-signed.crt mbedtls-3.6.6/framework/data_files/parse_input/server5-rsa-signed.crt
--- mbedtls-3.6.5/framework/data_files/parse_input/server5-rsa-signed.crt	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/data_files/parse_input/server5-rsa-signed.crt	2026-03-27 12:34:57.718529500 +0200
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICbDCCAVSgAwIBAgIBDTANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER
+MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN
+MjUxMjAxMTAxNTMwWhcNMzUxMjAxMTAxNTMwWjA0MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxEjAQBgNVBAMMCWxvY2FsaG9zdDBZMBMGByqGSM49AgEG
+CCqGSM49AwEHA0IABDfMVtl2CR5acj7HWS3/IG7ufPkGkXTQrRS192giWWKSTuUA
+2CMR/+ov0jRdXRa9iojCa3cNVc2KKg76Aci07f+jTTBLMAkGA1UdEwQCMAAwHQYD
+VR0OBBYEFFBhpY/UB9nXggEM5WV/jGNGpxO+MB8GA1UdIwQYMBaAFLRa5KWz3tJS
+9rnVppUP6z68x/3/MA0GCSqGSIb3DQEBCwUAA4IBAQBFbdhHbGhpR2TXjHDMqRTx
+epceYFPm0bL8h/gWUMsZ196DgrInm4u42txiWX6Ckekv/yeEOUEx90faACLmGGfk
+1QwWWVGShgUcl5d6DljtgTTx6jHiH3tHbcG8Rmmfmh+DKZ/4wjQ80FgbW7gEUyis
+xizhFI8+gYH6aT4fdYicyIzysul/0FF3c9nzn+Mt+VRzaPIAYgIujkQAiJO4/QB8
+2wuET09K9uWeHseXbjQ8O7yPnIpimX7G3TrUwBKb0QEE9IoDTbHjnxM0nxWkPSht
+wCZFuTfCcnjBi5ps+KJE2iJeK4D5zjS42VX08/ysFViejtY4vUMz3SXrulGg7NKE
+-----END CERTIFICATE-----
diff -Nru mbedtls-3.6.5/framework/data_files/server11.key mbedtls-3.6.6/framework/data_files/server11.key
--- mbedtls-3.6.5/framework/data_files/server11.key	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/data_files/server11.key	2026-03-27 12:34:57.757439600 +0200
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHQCAQEEIDzXde5ZiqF4VOJ4mFFJyzLOPz0RHkeJdF9quDdy67oGoAcGBSuBBAAK
+oUQDQgAEhOf8vez37gxdEN6efVX/hPgHSKCOU9bnYEpyXlk1LmMyoM45SOXNdKFY
+yrPYjOGxrb1zGxM5k3x5PinwF50Pqw==
+-----END EC PRIVATE KEY-----
diff -Nru mbedtls-3.6.5/framework/data_files/server11-rsa-signed.crt mbedtls-3.6.6/framework/data_files/server11-rsa-signed.crt
--- mbedtls-3.6.5/framework/data_files/server11-rsa-signed.crt	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/data_files/server11-rsa-signed.crt	2026-03-27 12:34:57.757348800 +0200
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICaTCCAVGgAwIBAgIBDTANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER
+MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN
+MjUxMjAxMTAxNTMwWhcNMzUxMjAxMTAxNTMwWjA0MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxEjAQBgNVBAMMCWxvY2FsaG9zdDBWMBAGByqGSM49AgEG
+BSuBBAAKA0IABITn/L3s9+4MXRDenn1V/4T4B0igjlPW52BKcl5ZNS5jMqDOOUjl
+zXShWMqz2Izhsa29cxsTOZN8eT4p8BedD6ujTTBLMAkGA1UdEwQCMAAwHQYDVR0O
+BBYEFE8fs/ywDn6xlnYK1tDkG/lCZ0ZmMB8GA1UdIwQYMBaAFLRa5KWz3tJS9rnV
+ppUP6z68x/3/MA0GCSqGSIb3DQEBBQUAA4IBAQAC/yhdzzdYHCSmvg+Hp9UjWR4l
+7g2g+AjeecH3zPNwzXXoFTMQh9oVNlwJf0Kohit24GTfkOu9jgDFm2Os5HQudLJj
+QBxdN5D/hCa7ZMT5ing8CFYPoMovlJBqFwtVVVNs+zTGwnij3el+96fTm/qXg2+L
+DjulIeKmxylY8RZxbEZfOpaC/krWvYlVrX2OWE0/FsTFJQDYLIJF1mJi90+lbIKN
+vn68o5WLRahn9Om20AE3ZLshBsMtprkXo7IR/P8bPzGaaC/WZ13A7rI6ZSsRGKKr
+sWZ0fOLEXylcbzaEhkNEPcKUQTFs9JzcvS5Z0sP8bB8nAtQgRzwFhW9rqFyc
+-----END CERTIFICATE-----
diff -Nru mbedtls-3.6.5/framework/data_files/server5-rsa-signed.crt mbedtls-3.6.6/framework/data_files/server5-rsa-signed.crt
--- mbedtls-3.6.5/framework/data_files/server5-rsa-signed.crt	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/data_files/server5-rsa-signed.crt	2026-03-27 12:34:57.761285500 +0200
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICbDCCAVSgAwIBAgIBDTANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER
+MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN
+MjUxMjAxMTAxNTMwWhcNMzUxMjAxMTAxNTMwWjA0MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxEjAQBgNVBAMMCWxvY2FsaG9zdDBZMBMGByqGSM49AgEG
+CCqGSM49AwEHA0IABDfMVtl2CR5acj7HWS3/IG7ufPkGkXTQrRS192giWWKSTuUA
+2CMR/+ov0jRdXRa9iojCa3cNVc2KKg76Aci07f+jTTBLMAkGA1UdEwQCMAAwHQYD
+VR0OBBYEFFBhpY/UB9nXggEM5WV/jGNGpxO+MB8GA1UdIwQYMBaAFLRa5KWz3tJS
+9rnVppUP6z68x/3/MA0GCSqGSIb3DQEBCwUAA4IBAQBFbdhHbGhpR2TXjHDMqRTx
+epceYFPm0bL8h/gWUMsZ196DgrInm4u42txiWX6Ckekv/yeEOUEx90faACLmGGfk
+1QwWWVGShgUcl5d6DljtgTTx6jHiH3tHbcG8Rmmfmh+DKZ/4wjQ80FgbW7gEUyis
+xizhFI8+gYH6aT4fdYicyIzysul/0FF3c9nzn+Mt+VRzaPIAYgIujkQAiJO4/QB8
+2wuET09K9uWeHseXbjQ8O7yPnIpimX7G3TrUwBKb0QEE9IoDTbHjnxM0nxWkPSht
+wCZFuTfCcnjBi5ps+KJE2iJeK4D5zjS42VX08/ysFViejtY4vUMz3SXrulGg7NKE
+-----END CERTIFICATE-----
diff -Nru mbedtls-3.6.5/framework/docs/architecture/config-check-framework.md mbedtls-3.6.6/framework/docs/architecture/config-check-framework.md
--- mbedtls-3.6.5/framework/docs/architecture/config-check-framework.md	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/docs/architecture/config-check-framework.md	2026-03-27 12:34:57.772116700 +0200
@@ -0,0 +1,149 @@
+# Mbed TLS and TF-PSA-Crypto configuration check framework
+
+This document describes the compile-time configuration check framework. The goal of this framework is to detect bad configurations when the library is compiled. It consists of three parts:
+
+* [manually written checks](#manually-written-checks) (since PolarSSL);
+* [generated checks](#generated-checks) (since TF-PSA-Crypto 1.0 and Mbed TLS 4.0);
+* [validating that some configurations are recognized as bad](#validation) (since TF-PSA-Crypto 1.0 and Mbed TLS 4.0).
+
+## Introduction
+
+### What is a configuration?
+
+A configuration (“config” for short) is a set of macro definitions that are chosen by the user who compiles the library, with defaults provided by the library maintainers. Those definitions may come from:
+
+* the compiler command line (`-D`);
+* The subproject's configuration files, if applicable (i.e. TF-PSA-Crypto's config files are part of the Mbed TLS config);
+* The project's main configuration file: the macro expansion of `MBEDTLS_CONFIG_FILE` or `TF_PSA_CRYPTO_CONFIG_FILE`, defaulting to `"mbedtls/mbedtls_config.h"` or `"psa/crypto_config.h"` respectively;
+* The project's user configuration, given by the macro `MBEDTLS_USER_CONFIG_FILE` or `TF_PSA_CRYPTO_USER_CONFIG_FILE`, if defined.
+
+### Why are configurations bad?
+
+There are several reasons why we might consider a configuration undesirable (“bad”) for short, including:
+
+* The configuration would lead to a compile-time error. We prefer to emit a comprehensible error message, rather than let the user puzzle over e.g. a missing symbol at link time.
+* The configuration is technically valid but unlikely to be desirable. For example, enabling ECC support but not at least one curve. Since we don't test such configurations, they may or may not work anyway.
+* The configuration is technically valid and should work, but potentially dangerous. For example, building with a weak random generator. In such cases, if the configuration may be accidentally weak, we may want to require the user to an additional “`I_KNOW_WHAT_I_M_DOING`” macro.
+* The user defined or undefined a macro which is normally set internally (typically in `*adjust*.h`). This is very likely to lead to internal consistencies, so we would like to reject the attempt.
+* The user defined or undefined a macro that used to be meaningful in a previous version of the library, but no longer is. We would like to emit an error that points the user to a replacement, if applicable.
+* The user defined a configuration option in the wrong project. A superproject must have the same configuration of the subproject that was used to build the subproject — concretely, setting a crypto option in Mbed TLS to a different value than in TF-PSA-Crypto is very likely to lead to inconsistencies in Mbed TLS.
+
+Some of these cases follow generic patterns that are susceptible for automation (e.g. options removed in the last major release), while others are very ad hoc and need to be defined manually (e.g. at least one of a set). Hence we have both [generated checks](#generated-checks) and [manually written checks](#manually-written-checks).
+
+### When is the configuration checked?
+
+We want to check the configuration when building the library.
+
+Applications are very likely to misbehave if they are built with different compilation options from the library.
+It is tempting to check the configuration when building applications: what if the user tried editing the config file after the library was built, or passed different options on the compiler command line?
+
+Users who try to change the configuration are very likely to reach a configuration that's still internally consistent, for example just a few more features, or different sizes. Configuration checks during the application build cannot detect that, since they have no access to the actual library configuration. Hence application-build-time checks would provide very little safety, but a false sense of safety. So since TF-PSA-Crypto 1.0 and Mbed TLS 4.0, we perform the checks only when building the library. (It was different before — see “[Configuration checks up to Mbed TLS 3.x](#configuration-checks-up-to-mbed-tls-3-x)” — but only for historical reasons, because in PolarSSL, all header files were public.)
+
+## Analysis of bad configurations
+
+This section analyses why certain kinds of configurations are bad. Note that not all bad configurations are actually rejected; consult the generator code for details (see “[How the checks are generated](#how-the-checks-are-generated)”).
+
+### Command line definitions
+
+Applications using the library must be built with the same configuration as the library. Otherwise they may make incompatible assumptions leading to undefined behavior at run time. Therefore it is problematic to define configuration options on the compiler command line (`cc -DMBEDTLS_XXX ...`).
+
+The configuration file variables (<code><em>PROJECT</em>\_CONFIG\_FILE</code>, and possibly <code><em>PROJECT</em>\_USER\_CONFIG\_FILE</code>) are exceptions because it makes sense to, for example, compile the library with `MBEDTLS_CONFIG_FILE="../../acme_platform/include/mbedtls_config.h"` (avoiding changes to the source tree and constraints on the include path order) and then install the file as `/usr/include/mbedtls/mbedtls_config.h`. For those, what matters is the content.
+
+The config check generator script makes it easy to detect if an option was set on the compiler command line. However, many embedded projects compile the whole platform with a single set of compiler options, and those options may include some of our config options. So if we reject command line options, we should provide an official way to bypass accept them.
+
+As of TF-PSA-Crypto 1.0 and Mbed TLS 4.0, configuration checks do not treat options set on the command line differently from options set in the config file.
+
+### Derived macros
+
+We derive many macros conditionally from the configuration options, mostly in `*adjust*.h`. (These headers can also define additional options to handle implicit requirements, but that part is not relevant here.) These macros must be consistent with the configuration, otherwise the library may misbehave (e.g. overflow internal buffers).
+
+Thus it is dangerous for derived macros to be set in the configuration file. (We could make it inoffensive by systematically either defining or explicitly undefining each derived macro, but that would be extra burden for which a mistake is easily made.)
+
+Unsetting a derived macro is not dangerous, but won't have any effect since the macro is not set yet. So we can reject it but it isn't particularly important.
+
+We can detect bad setting of derived macros by erroring if they are set after including the config files and before doing the adjustments.
+
+### Subproject options
+
+The superproject (Mbed TLS) reads the configuration of the subproject (TF-PSA-Crypto), but the converse is not true. Therefore:
+
+* Setting a superproject option identically in the subproject and in the superproject is perfectly fine.
+* Setting a superproject option only in the subproject is maybe a little weird, but harmless.
+* Setting a superproject option to different values in the superproject and in a subproject has a well-defined effect, but is probably a mistake. (Note that for boolean options, setting to off is usually indistinguishable from not setting, but can technically be done with `#undef`.)
+* Setting a subproject option in the superproject, except when it was already set (to the same value if applicable), is dangerous. It won't enable the feature and may lead to undefined behavior in the superproject.
+* It is also dangerous to set or unset a macro in the superproject's configuration if that macro is a derived one in the subproject.
+
+In Mbed TLS 4.x, there is a high risk that users migrating from Mbed TLS 3.6 will accidentally leave a crypto option in `mbedtls_config.h` instead of moving it to `crypto_config.h`. So we should particularly try to handle this case: macros that were configuration options in Mbed TLS 3.6 and that are now a configuration option or a derived macro in TF-PSA-Crypto.
+
+### Removed options
+
+Users who are upgrading from a previous major version of Mbed TLS (or TF-PSA-Crypto, once TF-PSA-Crypto 2.0 is released) may still attempt to use removed options, if they haven't fully upgraded their configuration file. This will likely not have the intended effect. Worse, if a former option has become an [internal macro that is now derived from other options](#derived-macros), this may result in an inconsistent configuration. This is notably the case for legacy crypto options from Mbed TLS 3.6, which for the most part are internal macros in TF-PSA-Crypto 1.0.
+
+A configuration file may use removed options harmlessly if the configuration was intended to work with both the old and the new version of the library. Users who want to do that can make the definitions conditional on the library version (e.g. `#if defined(TF_PSA_CRYPTO_VERSION_MAJOR) && TF_PSA_CRYPTO_VERSION_MAJOR > 1`), so if we have a mechanism to forbid removed options, it is not particularly useful to allow users to bypass it.
+
+Options that exist in Mbed TLS 3.6 and Mbed TLS 4.0 should not be considered removed from TF-PSA-Crypto 1.0, since it is perfectly legitimate to set them for the sake of Mbed TLS (see “[Subproject options](#subproject-options)”).
+
+## Manually written checks
+
+### Location of the manually written checks
+
+Most manually configuration checks are located in <code><em>LIBRARY\_DIRECTORY</em>/<em>PROJECT\_NAME</em>\_check\_config.h</code>.
+This header is included by <code><em>LIBRARY\_DIRECTORY</em>/<em>PROJECT\_NAME</em>_config.c</code>.
+
+### Behavior of the manually written checks
+
+The manually written checks run on the finalized configuration, i.e. at the end of `build_info.h`, after `*adjust*.h`.
+
+The checks generally fit into a few patterns:
+
+* If X is enabled then Y must be enabled because Y requires X to work. This was very common historically. Since Mbed TLS 3.0, we have gradually moved towards a more additive system, where enabling Y automatically enables its dependencies, but many cases of direct requirements still need to be specified manually.
+* If X is enabled then one of Y1, Y2, Y3… must be enabled. We can't enable a Y automatically because we don't know which one.
+* X and Y can't both be enabled.
+
+### Configuration checks up to Mbed TLS 3.x
+
+In Mbed TLS 2.x, there were manually written config checks in `<mbedtls/check_config.h>`. It was the job of `mbedtls/config.h` (which could be overridden by the user) to include that file. The configuration checks were thus performed whenever building a library source file or an application source file.
+
+In Mbed TLS 3.x, there were manually written config checks in `<mbedtls/check_config.h>`. This header was systematically included by `<mbedtls/build_info.h>`. The configuration checks were thus performed whenever building a library source file or an application source file.
+
+## Generated checks
+
+### Location of the generated checks
+
+The generated checks are located in
+<code><em>LIBRARY\_DIRECTORY</em>/<em>PROJECT\_NAME</em>\_config\_check\_\*.h</code>.
+These headers are included by <code><em>LIBRARY\_DIRECTORY</em>/<em>PROJECT\_NAME</em>\_config.c</code>.
+
+These are internal headers, included by one library file. This way, we run the config checks exactly once during a normal build.
+
+### Behavior of the generated checks
+
+The generated checks consist of three parts:
+
+1. Some initial setup in `*_before.h`, to detect the situation before including the user's configuration file (but after the command line — this is unavoidable). This header is included before `build_info.h`.
+2. The actual checks on the user configuration, in `*_after.h`. This header should also clean up by undefining some temporary macros. This header is included by `build_info.h` after reading the user's configuration files, but before defining derived macros in `*adjust*.h`. (This is not the normal behavior of `build_info.h`, it is done only if the file that includes `build_info.h` defines the macro <code><em>PROJECT\_NAME</em>\_INCLUDE\_AFTER\_RAW\_CONFIG</code>.)
+3. Additional checks that can be performed on the final configuration. At the time of writing, all such checks are [written manually](#manually-written-checks), but the infrastructure is in place if we want to generate some.
+
+### How the checks are generated
+
+The checks are generated by `scripts/generate_config_checks.py` in each project. Each project contains a description of what do check. A Python module in the framework contains code to transform this description into the C header files.
+
+The generation happens before build time as part of `make generated_files` or similar.
+
+### Use of historical configuration information
+
+The generated checks are based at least in part on historical information about what configuration options and derived macros existed in previous versions of the library. This historical information is stored in the [`history`](https://github.com/Mbed-TLS/mbedtls-framework/tree/main/history) directory of the framework repository. It can be created with [`scripts/save_config_history.sh`](https://github.com/Mbed-TLS/mbedtls-framework/blob/main/scripts/save_config_history.sh).
+
+## Validation
+
+Each project contains a script `tests/scripts/test_generate_config_checks.py` which is invoked by `all.sh`.
+
+### Unit tests for code generation
+
+The config check tests include some basic unit tests around the code generation, validating that certain configurations are accepted and that others are rejected with an assertion on the `#error` message.
+
+### Checks for forbidden configurations
+
+The config check tests can validate that certain configurations are forbidden.
+
+The config check tests work by attempting to compile <code><em>LIBRARY\_DIRECTORY</em>/<em>PROJECT\_NAME</em>_config.c</code> which includes both [manually written checks](#manually-written-checks) and [generated checks](#generated-checks). Both preprocessor `#error` and `static_assert` can be detected.
diff -Nru mbedtls-3.6.5/framework/history/config-adjust-tfpsacrypto-1.0.txt mbedtls-3.6.6/framework/history/config-adjust-tfpsacrypto-1.0.txt
--- mbedtls-3.6.5/framework/history/config-adjust-tfpsacrypto-1.0.txt	2025-10-01 18:29:09.507637300 +0300
+++ mbedtls-3.6.6/framework/history/config-adjust-tfpsacrypto-1.0.txt	2026-03-27 12:34:57.772650700 +0200
@@ -32,9 +32,7 @@
 MBEDTLS_CMAC_C
 MBEDTLS_CONFIG_ADJUST_LEGACY_CRYPTO_H
 MBEDTLS_CONFIG_ADJUST_LEGACY_FROM_PSA_H
-MBEDTLS_CONFIG_ADJUST_PSA_SUPERSET_LEGACY_H
 MBEDTLS_CONFIG_ADJUST_TEST_ACCELERATORS_H
-MBEDTLS_DES_C
 MBEDTLS_ECDH_C
 MBEDTLS_ECDSA_C
 MBEDTLS_ECDSA_DETERMINISTIC
@@ -127,7 +125,6 @@
 MBEDTLS_PSA_ACCEL_KEY_TYPE_CAMELLIA
 MBEDTLS_PSA_ACCEL_KEY_TYPE_CHACHA20
 MBEDTLS_PSA_ACCEL_KEY_TYPE_DERIVE
-MBEDTLS_PSA_ACCEL_KEY_TYPE_DES
 MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_KEY_PAIR_BASIC
 MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_KEY_PAIR_EXPORT
 MBEDTLS_PSA_ACCEL_KEY_TYPE_DH_KEY_PAIR_GENERATE
@@ -211,7 +208,6 @@
 MBEDTLS_PSA_BUILTIN_KEY_TYPE_ARIA
 MBEDTLS_PSA_BUILTIN_KEY_TYPE_CAMELLIA
 MBEDTLS_PSA_BUILTIN_KEY_TYPE_CHACHA20
-MBEDTLS_PSA_BUILTIN_KEY_TYPE_DES
 MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_BASIC
 MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_EXPORT
 MBEDTLS_PSA_BUILTIN_KEY_TYPE_DH_KEY_PAIR_GENERATE
@@ -235,7 +231,6 @@
 MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_ALGS
 MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_GROUPS
 MBEDTLS_PSA_DH_ACCEL_INCOMPLETE_KEY_TYPES
-MBEDTLS_PSA_DRIVER_GET_ENTROPY
 MBEDTLS_PSA_DRIVER_GET_ENTROPY_DEFINED
 MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_ALGS
 MBEDTLS_PSA_ECC_ACCEL_INCOMPLETE_CURVES
@@ -247,8 +242,6 @@
 MBEDTLS_SHA1_C
 MBEDTLS_SHA224_C
 MBEDTLS_SHA256_C
-MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT
-MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY
 MBEDTLS_SHA384_C
 MBEDTLS_SHA512_C
 MBEDTLS_SSL_HAVE_AEAD
@@ -266,7 +259,6 @@
 PSA_HAVE_SOFT_KEY_TYPE_AES
 PSA_HAVE_SOFT_KEY_TYPE_ARIA
 PSA_HAVE_SOFT_KEY_TYPE_CAMELLIA
-PSA_HAVE_SOFT_KEY_TYPE_DES
 PSA_HAVE_SOFT_PBKDF2
 PSA_HAVE_SOFT_PBKDF2_CMAC
 PSA_HAVE_SOFT_PBKDF2_HMAC
@@ -275,29 +267,11 @@
 PSA_WANT_ALG_ECDSA
 PSA_WANT_ALG_ECDSA_ANY
 PSA_WANT_ALG_HMAC
-PSA_WANT_ALG_MD5
-PSA_WANT_ALG_RIPEMD160
 PSA_WANT_ALG_RSA_PKCS1V15_SIGN
 PSA_WANT_ALG_RSA_PKCS1V15_SIGN_RAW
 PSA_WANT_ALG_RSA_PSS
 PSA_WANT_ALG_RSA_PSS_ANY_SALT
-PSA_WANT_ALG_SHA_1
-PSA_WANT_ALG_SHA_224
-PSA_WANT_ALG_SHA_256
-PSA_WANT_ALG_SHA_384
-PSA_WANT_ALG_SHA_512
 PSA_WANT_ALG_SOME_PAKE
-PSA_WANT_ECC_BRAINPOOL_P_R1_256
-PSA_WANT_ECC_BRAINPOOL_P_R1_384
-PSA_WANT_ECC_BRAINPOOL_P_R1_512
-PSA_WANT_ECC_MONTGOMERY_255
-PSA_WANT_ECC_MONTGOMERY_448
-PSA_WANT_ECC_SECP_K1_192
-PSA_WANT_ECC_SECP_K1_256
-PSA_WANT_ECC_SECP_R1_192
-PSA_WANT_ECC_SECP_R1_256
-PSA_WANT_ECC_SECP_R1_384
-PSA_WANT_ECC_SECP_R1_521
 PSA_WANT_KEY_TYPE_AES
 PSA_WANT_KEY_TYPE_DERIVE
 PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC
diff -Nru mbedtls-3.6.5/framework/history/config-options-mbedtls-4.0.txt mbedtls-3.6.6/framework/history/config-options-mbedtls-4.0.txt
--- mbedtls-3.6.5/framework/history/config-options-mbedtls-4.0.txt	2025-10-01 18:29:09.508531000 +0300
+++ mbedtls-3.6.6/framework/history/config-options-mbedtls-4.0.txt	2026-03-27 12:34:57.772868900 +0200
@@ -40,6 +40,7 @@
 MBEDTLS_SSL_KEYING_MATERIAL_EXPORT
 MBEDTLS_SSL_MAX_EARLY_DATA_SIZE
 MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+MBEDTLS_SSL_NULL_CIPHERSUITES
 MBEDTLS_SSL_OUT_CONTENT_LEN
 MBEDTLS_SSL_PROTO_DTLS
 MBEDTLS_SSL_PROTO_TLS1_2
diff -Nru mbedtls-3.6.5/framework/history/config-options-tfpsacrypto-1.0.txt mbedtls-3.6.6/framework/history/config-options-tfpsacrypto-1.0.txt
--- mbedtls-3.6.5/framework/history/config-options-tfpsacrypto-1.0.txt	2025-10-01 18:29:09.509018000 +0300
+++ mbedtls-3.6.6/framework/history/config-options-tfpsacrypto-1.0.txt	2026-03-27 12:34:57.773002400 +0200
@@ -7,31 +7,14 @@
 MBEDTLS_ASN1_PARSE_C
 MBEDTLS_ASN1_WRITE_C
 MBEDTLS_BASE64_C
-MBEDTLS_BIGNUM_C
 MBEDTLS_BLOCK_CIPHER_NO_DECRYPT
 MBEDTLS_CAMELLIA_SMALL_MEMORY
 MBEDTLS_CHECK_RETURN
 MBEDTLS_CHECK_RETURN_WARNING
-MBEDTLS_CIPHER_NULL_CIPHER
 MBEDTLS_CTR_DRBG_C
 MBEDTLS_DEPRECATED_REMOVED
 MBEDTLS_DEPRECATED_WARNING
-MBEDTLS_ECDH_C
 MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED
-MBEDTLS_ECDSA_C
-MBEDTLS_ECJPAKE_C
-MBEDTLS_ECP_C
-MBEDTLS_ECP_DP_BP256R1_ENABLED
-MBEDTLS_ECP_DP_BP384R1_ENABLED
-MBEDTLS_ECP_DP_BP512R1_ENABLED
-MBEDTLS_ECP_DP_CURVE25519_ENABLED
-MBEDTLS_ECP_DP_CURVE448_ENABLED
-MBEDTLS_ECP_DP_SECP192K1_ENABLED
-MBEDTLS_ECP_DP_SECP192R1_ENABLED
-MBEDTLS_ECP_DP_SECP256K1_ENABLED
-MBEDTLS_ECP_DP_SECP256R1_ENABLED
-MBEDTLS_ECP_DP_SECP384R1_ENABLED
-MBEDTLS_ECP_DP_SECP521R1_ENABLED
 MBEDTLS_ECP_FIXED_POINT_OPTIM
 MBEDTLS_ECP_NIST_OPTIM
 MBEDTLS_ECP_RESTARTABLE
@@ -74,7 +57,6 @@
 MBEDTLS_PLATFORM_FPRINTF_ALT
 MBEDTLS_PLATFORM_FPRINTF_MACRO
 MBEDTLS_PLATFORM_FREE_MACRO
-MBEDTLS_PLATFORM_GET_ENTROPY_ALT
 MBEDTLS_PLATFORM_GMTIME_R_ALT
 MBEDTLS_PLATFORM_MEMORY
 MBEDTLS_PLATFORM_MS_TIME_ALT
@@ -136,8 +118,6 @@
 MBEDTLS_RSA_NO_CRT
 MBEDTLS_SELF_TEST
 MBEDTLS_SHA256_SMALLER
-MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT
-MBEDTLS_SHA256_USE_A64_CRYPTO_ONLY
 MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT
 MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY
 MBEDTLS_SHA512_SMALLER
@@ -212,14 +192,12 @@
 PSA_WANT_KEY_TYPE_CAMELLIA
 PSA_WANT_KEY_TYPE_CHACHA20
 PSA_WANT_KEY_TYPE_DERIVE
-PSA_WANT_KEY_TYPE_DES
 PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC
 PSA_WANT_KEY_TYPE_DH_KEY_PAIR_DERIVE
 PSA_WANT_KEY_TYPE_DH_KEY_PAIR_EXPORT
 PSA_WANT_KEY_TYPE_DH_KEY_PAIR_GENERATE
 PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT
 PSA_WANT_KEY_TYPE_DH_PUBLIC_KEY
-PSA_WANT_KEY_TYPE_ECC_KEY_PAIR
 PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC
 PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE
 PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT
@@ -230,13 +208,14 @@
 PSA_WANT_KEY_TYPE_PASSWORD
 PSA_WANT_KEY_TYPE_PASSWORD_HASH
 PSA_WANT_KEY_TYPE_RAW_DATA
-PSA_WANT_KEY_TYPE_RSA_KEY_PAIR
 PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC
 PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_DERIVE
 PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_EXPORT
 PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE
 PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT
 PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY
+TF_PSA_CRYPTO_ALLOW_REMOVED_MECHANISMS
 TF_PSA_CRYPTO_CONFIG_FILE
+TF_PSA_CRYPTO_CONFIG_VERSION
 TF_PSA_CRYPTO_USER_CONFIG_FILE
 TF_PSA_CRYPTO_VERSION
diff -Nru mbedtls-3.6.5/framework/psasim/.gitignore mbedtls-3.6.6/framework/psasim/.gitignore
--- mbedtls-3.6.5/framework/psasim/.gitignore	2025-10-14 18:57:30.029369000 +0300
+++ mbedtls-3.6.6/framework/psasim/.gitignore	2026-03-27 12:41:32.011899500 +0200
@@ -1,12 +1,20 @@
-bin/*
-*.o
+# Intermediate generated files
+/include/psa_manifest/manifest.h
+/include/psa_manifest/pid.h
+/include/psa_manifest/sid.h
+/src/psa_functions_codes.h
+/src/psa_sim_crypto_client.c
+/src/psa_sim_crypto_server.c
+/src/psa_sim_serialise.c
+/src/psa_sim_serialise.h
+
+# Build products
+/test/psa_manifest/*
+/test/client
+/test/partition
 *.so
-test/psa_ff_bootstrap.c
-test/psa_manifest/*
-test/client
-test/partition
-cscope.out
-*.orig
+*psa_ff_bootstrap_*
+
+# Local files from editors and indexing tools
 *.swp
 *.DS_Store
-*psa_ff_bootstrap_*
diff -Nru mbedtls-3.6.5/framework/psasim/include/client.h mbedtls-3.6.6/framework/psasim/include/client.h
--- mbedtls-3.6.5/framework/psasim/include/client.h	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/include/client.h	2026-03-27 12:34:57.773500200 +0200
@@ -0,0 +1,75 @@
+/* PSA Firmware Framework client header for psasim. */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef __PSA_CLIENT_H__
+#define __PSA_CLIENT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "psa/crypto.h"
+
+#include "error_ext.h"
+/*********************** PSA Client Macros and Types *************************/
+
+#define PSA_FRAMEWORK_VERSION  (0x0100)
+
+#define PSA_VERSION_NONE       (0)
+
+/* PSA response types */
+#define PSA_CONNECTION_REFUSED PSA_ERROR_CONNECTION_REFUSED
+#define PSA_CONNECTION_BUSY    PSA_ERROR_CONNECTION_BUSY
+#define PSA_DROP_CONNECTION    PSA_ERROR_PROGRAMMER_ERROR
+
+/* PSA message handles */
+#define PSA_NULL_HANDLE        ((psa_handle_t) 0)
+
+#define PSA_HANDLE_IS_VALID(handle) ((psa_handle_t) (handle) > 0)
+#define PSA_HANDLE_TO_ERROR(handle) ((psa_status_t) (handle))
+
+/**
+ * A read-only input memory region provided to an RoT Service.
+ */
+typedef struct psa_invec {
+    const void *base;
+    size_t len;
+} psa_invec;
+
+/**
+ * A writable output memory region provided to an RoT Service.
+ */
+typedef struct psa_outvec {
+    void *base;
+    size_t len;
+} psa_outvec;
+
+/*************************** PSA Client API **********************************/
+
+uint32_t psa_framework_version(void);
+
+uint32_t psa_version(uint32_t sid);
+
+psa_handle_t psa_connect(uint32_t sid, uint32_t version);
+
+psa_status_t psa_call(psa_handle_t handle,
+                      int32_t type,
+                      const psa_invec *in_vec,
+                      size_t in_len,
+                      psa_outvec *out_vec,
+                      size_t out_len);
+
+void psa_close(psa_handle_t handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PSA_CLIENT_H__ */
diff -Nru mbedtls-3.6.5/framework/psasim/include/common.h mbedtls-3.6.6/framework/psasim/include/common.h
--- mbedtls-3.6.5/framework/psasim/include/common.h	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/include/common.h	2026-03-27 12:34:57.773604400 +0200
@@ -0,0 +1,52 @@
+/* Common definitions used for clients and services */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+#include <stdint.h>
+#include <stddef.h>
+
+/* Increasing this might break on some platforms */
+#define MAX_FRAGMENT_SIZE 200
+
+#define CONNECT_REQUEST 1
+#define CALL_REQUEST 2
+#define CLOSE_REQUEST 3
+#define VERSION_REQUEST 4
+#define READ_REQUEST    5
+#define READ_RESPONSE   6
+#define WRITE_REQUEST   7
+#define WRITE_RESPONSE  8
+#define SKIP_REQUEST    9
+#define PSA_REPLY       10
+
+#define NON_SECURE (1 << 30)
+
+typedef int32_t psa_handle_t;
+
+#define PSA_MAX_IOVEC (4u)
+
+#define PSA_IPC_CALL (0)
+
+struct message_text {
+    int qid;
+    int32_t psa_type;
+    char buf[MAX_FRAGMENT_SIZE];
+};
+
+struct message {
+    long message_type;
+    struct message_text message_text;
+};
+
+typedef struct vector_sizes {
+    size_t invec_sizes[PSA_MAX_IOVEC];
+    size_t outvec_sizes[PSA_MAX_IOVEC];
+} vector_sizes_t;
+
+#endif /* _COMMON_H_ */
diff -Nru mbedtls-3.6.5/framework/psasim/include/error_ext.h mbedtls-3.6.6/framework/psasim/include/error_ext.h
--- mbedtls-3.6.5/framework/psasim/include/error_ext.h	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/include/error_ext.h	2026-03-27 12:34:57.773708300 +0200
@@ -0,0 +1,19 @@
+/* PSA status codes used by psasim. */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef PSA_ERROR_H
+#define PSA_ERROR_H
+
+#include <stdint.h>
+
+#include "common.h"
+
+#define PSA_ERROR_PROGRAMMER_ERROR      ((psa_status_t) -129)
+#define PSA_ERROR_CONNECTION_REFUSED    ((psa_status_t) -130)
+#define PSA_ERROR_CONNECTION_BUSY       ((psa_status_t) -131)
+
+#endif
diff -Nru mbedtls-3.6.5/framework/psasim/include/init.h mbedtls-3.6.6/framework/psasim/include/init.h
--- mbedtls-3.6.5/framework/psasim/include/init.h	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/include/init.h	2026-03-27 12:34:57.773780000 +0200
@@ -0,0 +1,15 @@
+/* Declarations of internal functions. */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <stdint.h>
+#include <service.h>
+void raise_signal(psa_signal_t signal);
+void __init_psasim(const char **array,
+                   int size,
+                   const int allow_ns_clients_array[32],
+                   const uint32_t versions[32],
+                   const int strict_policy_array[32]);
diff -Nru mbedtls-3.6.5/framework/psasim/include/lifecycle.h mbedtls-3.6.6/framework/psasim/include/lifecycle.h
--- mbedtls-3.6.5/framework/psasim/include/lifecycle.h	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/include/lifecycle.h	2026-03-27 12:34:57.773885000 +0200
@@ -0,0 +1,17 @@
+/* PSA lifecycle states used by psasim. */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#define PSA_LIFECYCLE_PSA_STATE_MASK (0xff00u)
+#define PSA_LIFECYCLE_IMP_STATE_MASK (0x00ffu)
+#define PSA_LIFECYCLE_UNKNOWN (0x0000u)
+#define PSA_LIFECYCLE_ASSEMBLY_AND_TEST (0x1000u)
+#define PSA_LIFECYCLE_PSA_ROT_PROVISIONING (0x2000u)
+#define PSA_LIFECYCLE_SECURED (0x3000u)
+#define PSA_LIFECYCLE_NON_PSA_ROT_DEBUG (0x4000u)
+#define PSA_LIFECYCLE_RECOVERABLE_PSA_ROT_DEBUG (0x5000u)
+#define PSA_LIFECYCLE_DECOMMISSIONED (0x6000u)
+#define psa_rot_lifecycle_state(void) PSA_LIFECYCLE_UNKNOWN
diff -Nru mbedtls-3.6.5/framework/psasim/include/psa/client.h mbedtls-3.6.6/framework/psasim/include/psa/client.h
--- mbedtls-3.6.5/framework/psasim/include/psa/client.h	2025-10-01 18:24:20.266423000 +0300
+++ mbedtls-3.6.6/framework/psasim/include/psa/client.h	1970-01-01 02:00:00.000000000 +0200
@@ -1,78 +0,0 @@
-/* PSA Firmware Framework client header for psasim. */
-
-/*
- *  Copyright The Mbed TLS Contributors
- *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
- */
-
-#ifndef __PSA_CLIENT_H__
-#define __PSA_CLIENT_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdint.h>
-#include <stddef.h>
-#include <psa/error.h>
-/*********************** PSA Client Macros and Types *************************/
-
-#define PSA_FRAMEWORK_VERSION  (0x0100)
-
-#define PSA_VERSION_NONE       (0)
-
-/* PSA response types */
-#define PSA_CONNECTION_REFUSED PSA_ERROR_CONNECTION_REFUSED
-#define PSA_CONNECTION_BUSY    PSA_ERROR_CONNECTION_BUSY
-#define PSA_DROP_CONNECTION    PSA_ERROR_PROGRAMMER_ERROR
-
-/* PSA message handles */
-#define PSA_NULL_HANDLE        ((psa_handle_t) 0)
-
-#define PSA_HANDLE_IS_VALID(handle) ((psa_handle_t) (handle) > 0)
-#define PSA_HANDLE_TO_ERROR(handle) ((psa_status_t) (handle))
-
-#define PSA_MAX_IOVEC (4u)
-
-#define PSA_IPC_CALL (0)
-
-typedef int32_t psa_handle_t;
-
-/**
- * A read-only input memory region provided to an RoT Service.
- */
-typedef struct psa_invec {
-    const void *base;
-    size_t len;
-} psa_invec;
-
-/**
- * A writable output memory region provided to an RoT Service.
- */
-typedef struct psa_outvec {
-    void *base;
-    size_t len;
-} psa_outvec;
-
-/*************************** PSA Client API **********************************/
-
-uint32_t psa_framework_version(void);
-
-uint32_t psa_version(uint32_t sid);
-
-psa_handle_t psa_connect(uint32_t sid, uint32_t version);
-
-psa_status_t psa_call(psa_handle_t handle,
-                      int32_t type,
-                      const psa_invec *in_vec,
-                      size_t in_len,
-                      psa_outvec *out_vec,
-                      size_t out_len);
-
-void psa_close(psa_handle_t handle);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __PSA_CLIENT_H__ */
diff -Nru mbedtls-3.6.5/framework/psasim/include/psa/error.h mbedtls-3.6.6/framework/psasim/include/psa/error.h
--- mbedtls-3.6.5/framework/psasim/include/psa/error.h	2025-10-01 18:24:20.266509000 +0300
+++ mbedtls-3.6.6/framework/psasim/include/psa/error.h	1970-01-01 02:00:00.000000000 +0200
@@ -1,36 +0,0 @@
-/* PSA status codes used by psasim. */
-
-/*
- *  Copyright The Mbed TLS Contributors
- *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
- */
-
-#ifndef PSA_ERROR_H
-#define PSA_ERROR_H
-#include <stdint.h>
-typedef int32_t psa_status_t;
-
-#define PSA_SUCCESS                     ((psa_status_t) 0)
-
-#define PSA_ERROR_PROGRAMMER_ERROR      ((psa_status_t) -129)
-#define PSA_ERROR_CONNECTION_REFUSED    ((psa_status_t) -130)
-#define PSA_ERROR_CONNECTION_BUSY       ((psa_status_t) -131)
-#define PSA_ERROR_GENERIC_ERROR         ((psa_status_t) -132)
-#define PSA_ERROR_NOT_PERMITTED         ((psa_status_t) -133)
-#define PSA_ERROR_NOT_SUPPORTED         ((psa_status_t) -134)
-#define PSA_ERROR_INVALID_ARGUMENT      ((psa_status_t) -135)
-#define PSA_ERROR_INVALID_HANDLE        ((psa_status_t) -136)
-#define PSA_ERROR_BAD_STATE             ((psa_status_t) -137)
-#define PSA_ERROR_BUFFER_TOO_SMALL      ((psa_status_t) -138)
-#define PSA_ERROR_ALREADY_EXISTS        ((psa_status_t) -139)
-#define PSA_ERROR_DOES_NOT_EXIST        ((psa_status_t) -140)
-#define PSA_ERROR_INSUFFICIENT_MEMORY   ((psa_status_t) -141)
-#define PSA_ERROR_INSUFFICIENT_STORAGE  ((psa_status_t) -142)
-#define PSA_ERROR_INSUFFICIENT_DATA     ((psa_status_t) -143)
-#define PSA_ERROR_SERVICE_FAILURE       ((psa_status_t) -144)
-#define PSA_ERROR_COMMUNICATION_FAILURE ((psa_status_t) -145)
-#define PSA_ERROR_STORAGE_FAILURE       ((psa_status_t) -146)
-#define PSA_ERROR_HARDWARE_FAILURE      ((psa_status_t) -147)
-#define PSA_ERROR_INVALID_SIGNATURE     ((psa_status_t) -149)
-
-#endif
diff -Nru mbedtls-3.6.5/framework/psasim/include/psa/lifecycle.h mbedtls-3.6.6/framework/psasim/include/psa/lifecycle.h
--- mbedtls-3.6.5/framework/psasim/include/psa/lifecycle.h	2025-10-01 18:24:20.266591800 +0300
+++ mbedtls-3.6.6/framework/psasim/include/psa/lifecycle.h	1970-01-01 02:00:00.000000000 +0200
@@ -1,17 +0,0 @@
-/* PSA lifecycle states used by psasim. */
-
-/*
- *  Copyright The Mbed TLS Contributors
- *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
- */
-
-#define PSA_LIFECYCLE_PSA_STATE_MASK (0xff00u)
-#define PSA_LIFECYCLE_IMP_STATE_MASK (0x00ffu)
-#define PSA_LIFECYCLE_UNKNOWN (0x0000u)
-#define PSA_LIFECYCLE_ASSEMBLY_AND_TEST (0x1000u)
-#define PSA_LIFECYCLE_PSA_ROT_PROVISIONING (0x2000u)
-#define PSA_LIFECYCLE_SECURED (0x3000u)
-#define PSA_LIFECYCLE_NON_PSA_ROT_DEBUG (0x4000u)
-#define PSA_LIFECYCLE_RECOVERABLE_PSA_ROT_DEBUG (0x5000u)
-#define PSA_LIFECYCLE_DECOMMISSIONED (0x6000u)
-#define psa_rot_lifecycle_state(void) PSA_LIFECYCLE_UNKNOWN
diff -Nru mbedtls-3.6.5/framework/psasim/include/psa/service.h mbedtls-3.6.6/framework/psasim/include/psa/service.h
--- mbedtls-3.6.5/framework/psasim/include/psa/service.h	2025-10-01 18:24:20.266700700 +0300
+++ mbedtls-3.6.6/framework/psasim/include/psa/service.h	1970-01-01 02:00:00.000000000 +0200
@@ -1,249 +0,0 @@
-/* PSA Firmware Framework service header for psasim. */
-
-/*
- *  Copyright The Mbed TLS Contributors
- *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
- */
-
-#ifndef __PSA_SERVICE_H__
-#define __PSA_SERVICE_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-#include <stdlib.h>
-#include <stdint.h>
-#include <stddef.h>
-#include <psa/client.h>
-/********************** PSA Secure Partition Macros and Types ****************/
-
-/* PSA wait timeouts */
-#define PSA_POLL                (0x00000000u)
-#define PSA_BLOCK               (0x80000000u)
-
-/* A mask value that includes all Secure Partition signals */
-#define PSA_WAIT_ANY            (~0u)
-
-/* Doorbell signal */
-#define PSA_DOORBELL            (0x00000008u)
-
-/* PSA message types */
-#define PSA_IPC_CONNECT         (-1)
-#define PSA_IPC_DISCONNECT      (-2)
-
-/* Return code from psa_get() */
-#define PSA_ERR_NOMSG           (INT32_MIN + 3)
-
-/* Store a set of one or more Secure Partition signals */
-typedef uint32_t psa_signal_t;
-
-/**
- * Describe a message received by an RoT Service after calling \ref psa_get().
- */
-typedef struct psa_msg_t {
-    uint32_t type;              /* One of the following values:
-                                 * \ref PSA_IPC_CONNECT
-                                 * \ref PSA_IPC_CALL
-                                 * \ref PSA_IPC_DISCONNECT
-                                 */
-    psa_handle_t handle;        /* A reference generated by the SPM to the
-                                 * message returned by psa_get().
-                                 */
-    int32_t client_id;          /* Partition ID of the sender of the message */
-    void *rhandle;              /* Be useful for binding a connection to some
-                                 * application-specific data or function
-                                 * pointer within the RoT Service
-                                 * implementation.
-                                 */
-    size_t in_size[PSA_MAX_IOVEC]; /* Provide the size of each client input
-                                    * vector in bytes.
-                                    */
-    size_t out_size[PSA_MAX_IOVEC];/* Provide the size of each client output
-                                    * vector in bytes.
-                                    */
-} psa_msg_t;
-
-/************************* PSA Secure Partition API **************************/
-
-/**
- * \brief Return the Secure Partition interrupt signals that have been asserted
- *        from a subset of signals provided by the caller.
- *
- * \param[in] signal_mask       A set of signals to query. Signals that are not
- *                              in this set will be ignored.
- * \param[in] timeout           Specify either blocking \ref PSA_BLOCK or
- *                              polling \ref PSA_POLL operation.
- *
- * \retval >0                   At least one signal is asserted.
- * \retval 0                    No signals are asserted. This is only seen when
- *                              a polling timeout is used.
- */
-psa_signal_t psa_wait(psa_signal_t signal_mask, uint32_t timeout);
-
-/**
- * \brief Retrieve the message which corresponds to a given RoT Service signal
- *        and remove the message from the RoT Service queue.
- *
- * \param[in] signal            The signal value for an asserted RoT Service.
- * \param[out] msg              Pointer to \ref psa_msg_t object for receiving
- *                              the message.
- *
- * \retval PSA_SUCCESS          Success, *msg will contain the delivered
- *                              message.
- * \retval PSA_ERR_NOMSG        Message could not be delivered.
- * \retval "Does not return"    The call is invalid because one or more of the
- *                              following are true:
- * \arg                           signal has more than a single bit set.
- * \arg                           signal does not correspond to an RoT Service.
- * \arg                           The RoT Service signal is not currently
- *                                asserted.
- * \arg                           The msg pointer provided is not a valid memory
- *                                reference.
- */
-psa_status_t psa_get(psa_signal_t signal, psa_msg_t *msg);
-
-/**
- * \brief Associate some RoT Service private data with a client connection.
- *
- * \param[in] msg_handle        Handle for the client's message.
- * \param[in] rhandle           Reverse handle allocated by the RoT Service.
- *
- * \retval void                 Success, rhandle will be provided with all
- *                              subsequent messages delivered on this
- *                              connection.
- * \retval "Does not return"    msg_handle is invalid.
- */
-void psa_set_rhandle(psa_handle_t msg_handle, void *rhandle);
-
-/**
- * \brief Read a message parameter or part of a message parameter from a client
- *        input vector.
- *
- * \param[in] msg_handle        Handle for the client's message.
- * \param[in] invec_idx         Index of the input vector to read from. Must be
- *                              less than \ref PSA_MAX_IOVEC.
- * \param[out] buffer           Buffer in the Secure Partition to copy the
- *                              requested data to.
- * \param[in] num_bytes         Maximum number of bytes to be read from the
- *                              client input vector.
- *
- * \retval >0                   Number of bytes copied.
- * \retval 0                    There was no remaining data in this input
- *                              vector.
- * \retval "Does not return"    The call is invalid, one or more of the
- *                              following are true:
- * \arg                           msg_handle is invalid.
- * \arg                           msg_handle does not refer to a
- *                                \ref PSA_IPC_CALL message.
- * \arg                           invec_idx is equal to or greater than
- *                                \ref PSA_MAX_IOVEC.
- * \arg                           the memory reference for buffer is invalid or
- *                                not writable.
- */
-size_t psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
-                void *buffer, size_t num_bytes);
-
-/**
- * \brief Skip over part of a client input vector.
- *
- * \param[in] msg_handle        Handle for the client's message.
- * \param[in] invec_idx         Index of input vector to skip from. Must be
- *                              less than \ref PSA_MAX_IOVEC.
- * \param[in] num_bytes         Maximum number of bytes to skip in the client
- *                              input vector.
- *
- * \retval >0                   Number of bytes skipped.
- * \retval 0                    There was no remaining data in this input
- *                              vector.
- * \retval "Does not return"    The call is invalid, one or more of the
- *                              following are true:
- * \arg                           msg_handle is invalid.
- * \arg                           msg_handle does not refer to a
- *                                \ref PSA_IPC_CALL message.
- * \arg                           invec_idx is equal to or greater than
- *                                \ref PSA_MAX_IOVEC.
- */
-size_t psa_skip(psa_handle_t msg_handle, uint32_t invec_idx, size_t num_bytes);
-
-/**
- * \brief Write a message response to a client output vector.
- *
- * \param[in] msg_handle        Handle for the client's message.
- * \param[out] outvec_idx       Index of output vector in message to write to.
- *                              Must be less than \ref PSA_MAX_IOVEC.
- * \param[in] buffer            Buffer with the data to write.
- * \param[in] num_bytes         Number of bytes to write to the client output
- *                              vector.
- *
- * \retval void                 Success
- * \retval "Does not return"    The call is invalid, one or more of the
- *                              following are true:
- * \arg                           msg_handle is invalid.
- * \arg                           msg_handle does not refer to a
- *                                \ref PSA_IPC_CALL message.
- * \arg                           outvec_idx is equal to or greater than
- *                                \ref PSA_MAX_IOVEC.
- * \arg                           The memory reference for buffer is invalid.
- * \arg                           The call attempts to write data past the end
- *                                of the client output vector.
- */
-void psa_write(psa_handle_t msg_handle, uint32_t outvec_idx,
-               const void *buffer, size_t num_bytes);
-
-/**
- * \brief Complete handling of a specific message and unblock the client.
- *
- * \param[in] msg_handle        Handle for the client's message.
- * \param[in] status            Message result value to be reported to the
- *                              client.
- *
- * \retval void                 Success.
- * \retval "Does not return"    The call is invalid, one or more of the
- *                              following are true:
- * \arg                         msg_handle is invalid.
- * \arg                         An invalid status code is specified for the
- *                              type of message.
- */
-void psa_reply(psa_handle_t msg_handle, psa_status_t status);
-
-/**
- * \brief Send a PSA_DOORBELL signal to a specific Secure Partition.
- *
- * \param[in] partition_id      Secure Partition ID of the target partition.
- *
- * \retval void                 Success.
- * \retval "Does not return"    partition_id does not correspond to a Secure
- *                              Partition.
- */
-void psa_notify(int32_t partition_id);
-
-/**
- * \brief Clear the PSA_DOORBELL signal.
- *
- * \retval void                 Success.
- * \retval "Does not return"    The Secure Partition's doorbell signal is not
- *                              currently asserted.
- */
-void psa_clear(void);
-
-/**
- * \brief Inform the SPM that an interrupt has been handled (end of interrupt).
- *
- * \param[in] irq_signal        The interrupt signal that has been processed.
- *
- * \retval void                 Success.
- * \retval "Does not return"    The call is invalid, one or more of the
- *                              following are true:
- * \arg                           irq_signal is not an interrupt signal.
- * \arg                           irq_signal indicates more than one signal.
- * \arg                           irq_signal is not currently asserted.
- */
-void psa_eoi(psa_signal_t irq_signal);
-
-#define psa_panic(X) abort();
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __PSA_SERVICE_H__ */
diff -Nru mbedtls-3.6.5/framework/psasim/include/psasim/init.h mbedtls-3.6.6/framework/psasim/include/psasim/init.h
--- mbedtls-3.6.5/framework/psasim/include/psasim/init.h	2025-10-01 18:24:20.266839300 +0300
+++ mbedtls-3.6.6/framework/psasim/include/psasim/init.h	1970-01-01 02:00:00.000000000 +0200
@@ -1,15 +0,0 @@
-/* Declarations of internal functions. */
-
-/*
- *  Copyright The Mbed TLS Contributors
- *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
- */
-
-#include <stdint.h>
-#include <psa/service.h>
-void raise_signal(psa_signal_t signal);
-void __init_psasim(const char **array,
-                   int size,
-                   const int allow_ns_clients_array[32],
-                   const uint32_t versions[32],
-                   const int strict_policy_array[32]);
diff -Nru mbedtls-3.6.5/framework/psasim/include/service.h mbedtls-3.6.6/framework/psasim/include/service.h
--- mbedtls-3.6.5/framework/psasim/include/service.h	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/include/service.h	2026-03-27 12:34:57.774002800 +0200
@@ -0,0 +1,253 @@
+/* PSA Firmware Framework service header for psasim. */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef __PSA_SERVICE_H__
+#define __PSA_SERVICE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#include "common.h"
+
+#include "psa/crypto.h"
+
+/********************** PSA Secure Partition Macros and Types ****************/
+
+/* PSA wait timeouts */
+#define PSA_POLL                (0x00000000u)
+#define PSA_BLOCK               (0x80000000u)
+
+/* A mask value that includes all Secure Partition signals */
+#define PSA_WAIT_ANY            (~0u)
+
+/* Doorbell signal */
+#define PSA_DOORBELL            (0x00000008u)
+
+/* PSA message types */
+#define PSA_IPC_CONNECT         (-1)
+#define PSA_IPC_DISCONNECT      (-2)
+
+/* Return code from psa_get() */
+#define PSA_ERR_NOMSG           (INT32_MIN + 3)
+
+/* Store a set of one or more Secure Partition signals */
+typedef uint32_t psa_signal_t;
+
+/**
+ * Describe a message received by an RoT Service after calling \ref psa_get().
+ */
+typedef struct psa_msg_t {
+    uint32_t type;              /* One of the following values:
+                                 * \ref PSA_IPC_CONNECT
+                                 * \ref PSA_IPC_CALL
+                                 * \ref PSA_IPC_DISCONNECT
+                                 */
+    psa_handle_t handle;        /* A reference generated by the SPM to the
+                                 * message returned by psa_get().
+                                 */
+    int32_t client_id;          /* Partition ID of the sender of the message */
+    void *rhandle;              /* Be useful for binding a connection to some
+                                 * application-specific data or function
+                                 * pointer within the RoT Service
+                                 * implementation.
+                                 */
+    size_t in_size[PSA_MAX_IOVEC]; /* Provide the size of each client input
+                                    * vector in bytes.
+                                    */
+    size_t out_size[PSA_MAX_IOVEC];/* Provide the size of each client output
+                                    * vector in bytes.
+                                    */
+} psa_msg_t;
+
+/************************* PSA Secure Partition API **************************/
+
+/**
+ * \brief Return the Secure Partition interrupt signals that have been asserted
+ *        from a subset of signals provided by the caller.
+ *
+ * \param[in] signal_mask       A set of signals to query. Signals that are not
+ *                              in this set will be ignored.
+ * \param[in] timeout           Specify either blocking \ref PSA_BLOCK or
+ *                              polling \ref PSA_POLL operation.
+ *
+ * \retval >0                   At least one signal is asserted.
+ * \retval 0                    No signals are asserted. This is only seen when
+ *                              a polling timeout is used.
+ */
+psa_signal_t psa_wait(psa_signal_t signal_mask, uint32_t timeout);
+
+/**
+ * \brief Retrieve the message which corresponds to a given RoT Service signal
+ *        and remove the message from the RoT Service queue.
+ *
+ * \param[in] signal            The signal value for an asserted RoT Service.
+ * \param[out] msg              Pointer to \ref psa_msg_t object for receiving
+ *                              the message.
+ *
+ * \retval PSA_SUCCESS          Success, *msg will contain the delivered
+ *                              message.
+ * \retval PSA_ERR_NOMSG        Message could not be delivered.
+ * \retval "Does not return"    The call is invalid because one or more of the
+ *                              following are true:
+ * \arg                           signal has more than a single bit set.
+ * \arg                           signal does not correspond to an RoT Service.
+ * \arg                           The RoT Service signal is not currently
+ *                                asserted.
+ * \arg                           The msg pointer provided is not a valid memory
+ *                                reference.
+ */
+psa_status_t psa_get(psa_signal_t signal, psa_msg_t *msg);
+
+/**
+ * \brief Associate some RoT Service private data with a client connection.
+ *
+ * \param[in] msg_handle        Handle for the client's message.
+ * \param[in] rhandle           Reverse handle allocated by the RoT Service.
+ *
+ * \retval void                 Success, rhandle will be provided with all
+ *                              subsequent messages delivered on this
+ *                              connection.
+ * \retval "Does not return"    msg_handle is invalid.
+ */
+void psa_set_rhandle(psa_handle_t msg_handle, void *rhandle);
+
+/**
+ * \brief Read a message parameter or part of a message parameter from a client
+ *        input vector.
+ *
+ * \param[in] msg_handle        Handle for the client's message.
+ * \param[in] invec_idx         Index of the input vector to read from. Must be
+ *                              less than \ref PSA_MAX_IOVEC.
+ * \param[out] buffer           Buffer in the Secure Partition to copy the
+ *                              requested data to.
+ * \param[in] num_bytes         Maximum number of bytes to be read from the
+ *                              client input vector.
+ *
+ * \retval >0                   Number of bytes copied.
+ * \retval 0                    There was no remaining data in this input
+ *                              vector.
+ * \retval "Does not return"    The call is invalid, one or more of the
+ *                              following are true:
+ * \arg                           msg_handle is invalid.
+ * \arg                           msg_handle does not refer to a
+ *                                \ref PSA_IPC_CALL message.
+ * \arg                           invec_idx is equal to or greater than
+ *                                \ref PSA_MAX_IOVEC.
+ * \arg                           the memory reference for buffer is invalid or
+ *                                not writable.
+ */
+size_t psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
+                void *buffer, size_t num_bytes);
+
+/**
+ * \brief Skip over part of a client input vector.
+ *
+ * \param[in] msg_handle        Handle for the client's message.
+ * \param[in] invec_idx         Index of input vector to skip from. Must be
+ *                              less than \ref PSA_MAX_IOVEC.
+ * \param[in] num_bytes         Maximum number of bytes to skip in the client
+ *                              input vector.
+ *
+ * \retval >0                   Number of bytes skipped.
+ * \retval 0                    There was no remaining data in this input
+ *                              vector.
+ * \retval "Does not return"    The call is invalid, one or more of the
+ *                              following are true:
+ * \arg                           msg_handle is invalid.
+ * \arg                           msg_handle does not refer to a
+ *                                \ref PSA_IPC_CALL message.
+ * \arg                           invec_idx is equal to or greater than
+ *                                \ref PSA_MAX_IOVEC.
+ */
+size_t psa_skip(psa_handle_t msg_handle, uint32_t invec_idx, size_t num_bytes);
+
+/**
+ * \brief Write a message response to a client output vector.
+ *
+ * \param[in] msg_handle        Handle for the client's message.
+ * \param[out] outvec_idx       Index of output vector in message to write to.
+ *                              Must be less than \ref PSA_MAX_IOVEC.
+ * \param[in] buffer            Buffer with the data to write.
+ * \param[in] num_bytes         Number of bytes to write to the client output
+ *                              vector.
+ *
+ * \retval void                 Success
+ * \retval "Does not return"    The call is invalid, one or more of the
+ *                              following are true:
+ * \arg                           msg_handle is invalid.
+ * \arg                           msg_handle does not refer to a
+ *                                \ref PSA_IPC_CALL message.
+ * \arg                           outvec_idx is equal to or greater than
+ *                                \ref PSA_MAX_IOVEC.
+ * \arg                           The memory reference for buffer is invalid.
+ * \arg                           The call attempts to write data past the end
+ *                                of the client output vector.
+ */
+void psa_write(psa_handle_t msg_handle, uint32_t outvec_idx,
+               const void *buffer, size_t num_bytes);
+
+/**
+ * \brief Complete handling of a specific message and unblock the client.
+ *
+ * \param[in] msg_handle        Handle for the client's message.
+ * \param[in] status            Message result value to be reported to the
+ *                              client.
+ *
+ * \retval void                 Success.
+ * \retval "Does not return"    The call is invalid, one or more of the
+ *                              following are true:
+ * \arg                         msg_handle is invalid.
+ * \arg                         An invalid status code is specified for the
+ *                              type of message.
+ */
+void psa_reply(psa_handle_t msg_handle, psa_status_t status);
+
+/**
+ * \brief Send a PSA_DOORBELL signal to a specific Secure Partition.
+ *
+ * \param[in] partition_id      Secure Partition ID of the target partition.
+ *
+ * \retval void                 Success.
+ * \retval "Does not return"    partition_id does not correspond to a Secure
+ *                              Partition.
+ */
+void psa_notify(int32_t partition_id);
+
+/**
+ * \brief Clear the PSA_DOORBELL signal.
+ *
+ * \retval void                 Success.
+ * \retval "Does not return"    The Secure Partition's doorbell signal is not
+ *                              currently asserted.
+ */
+void psa_clear(void);
+
+/**
+ * \brief Inform the SPM that an interrupt has been handled (end of interrupt).
+ *
+ * \param[in] irq_signal        The interrupt signal that has been processed.
+ *
+ * \retval void                 Success.
+ * \retval "Does not return"    The call is invalid, one or more of the
+ *                              following are true:
+ * \arg                           irq_signal is not an interrupt signal.
+ * \arg                           irq_signal indicates more than one signal.
+ * \arg                           irq_signal is not currently asserted.
+ */
+void psa_eoi(psa_signal_t irq_signal);
+
+#define psa_panic(X) abort();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PSA_SERVICE_H__ */
diff -Nru mbedtls-3.6.5/framework/psasim/include/util.h mbedtls-3.6.6/framework/psasim/include/util.h
--- mbedtls-3.6.5/framework/psasim/include/util.h	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/include/util.h	2026-03-27 12:34:57.774087700 +0200
@@ -0,0 +1,33 @@
+/* Common definitions used for clients and services */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "service.h"
+
+#include <stdio.h>
+
+#define PRINT(fmt, ...) \
+    fprintf(stdout, fmt "\n", ##__VA_ARGS__)
+
+#if defined(DEBUG)
+#define INFO(fmt, ...) \
+    fprintf(stdout, "Info (%s - %d): " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
+#else /* !DEBUG */
+#define INFO(...)
+#endif /* DEBUG*/
+
+#define ERROR(fmt, ...) \
+    fprintf(stderr, "Error (%s - %d): " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
+
+#define FATAL(fmt, ...) \
+    { \
+        fprintf(stderr, "Fatal (%s - %d): " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \
+        abort(); \
+    }
+
+#define PROJECT_ID              'M'
+#define PATHNAMESIZE            256
+#define TMP_FILE_BASE_PATH      "./"
diff -Nru mbedtls-3.6.5/framework/psasim/Makefile mbedtls-3.6.6/framework/psasim/Makefile
--- mbedtls-3.6.5/framework/psasim/Makefile	2025-10-01 18:24:20.266078000 +0300
+++ mbedtls-3.6.6/framework/psasim/Makefile	2026-03-27 12:34:57.773258000 +0200
@@ -1,64 +1,118 @@
-CFLAGS ?=  -Wall -std=c99
-INCLUDE := -I./include/
-DESTDIR ?= /usr/local
-PREFIX := libpsaff
-BUILDDIR ?= bin
-
-.PHONY: all install test uninstall run docker ci
-
-all: libpsaff.so
-
-libpsaff.so:
-	$(CC) $(INCLUDE) $(CFLAGS) -c -fpic src/common.c -o common.o
-	$(CC) $(INCLUDE) $(CFLAGS) -c -fpic src/client.c -o client.o
-	$(CC) $(INCLUDE) $(CFLAGS) -c -fpic src/service.c -o server.o
-	$(CC) -shared -o libpsaff.so common.o client.o server.o
+ifeq ($(wildcard ../../tf-psa-crypto),)
+TF_PSA_CRYPTO_PATH ?= ../..
+MBEDTLS_PATH ?= ../../..
+else
+MBEDTLS_PATH ?= ../..
+TF_PSA_CRYPTO_PATH ?= ../../tf-psa-crypto
+endif
+
+include $(TF_PSA_CRYPTO_PATH)/scripts/crypto-common.make
+
+CFLAGS += -Wall -Werror -std=c99 -D_XOPEN_SOURCE=1 -D_POSIX_C_SOURCE=200809L
 
 ifeq ($(DEBUG),1)
-  CFLAGS += -DDEBUG -g
+override CFLAGS += -DDEBUG -O0 -g
 endif
 
-clean:
-	rm -rf $(BUILDDIR)
-	rm -f *.so *.o
-	rm -rf test/*dSYM
-	cd test && make clean
-
-test:
-	cd test && make
-
-test/partition:
-	cd test && make
-
-run: test/partition
-	pkill partition || true
-	pkill client || true
-	ipcs | grep q | awk '{ printf " -q " $$2 }' | xargs ipcrm > /dev/null 2>&1 || true
-	(sleep 3 && ./test/client)&
-	./test/partition
-
-ci:
-	pkill client || true
-	ipcs | grep q | awk '{ printf " -q " $$2 }' | xargs ipcrm > /dev/null 2>&1 || true
-	./test/partition 2>&1  &
-	sleep 3 && ./test/client
-	pkill partition || true
-
-docker:
-	@docker run --rm -ti -v $$PWD:/opt --entrypoint /bin/bash ubuntu \
-		-c "cd /opt && ls && apt-get update -qq && apt install \
-		-y gcc make gdb python -qq && make clean && make install && make test && ldconfig && make run"
-
-install: libpsaff.so
-	mkdir -p $(DESTDIR)/lib
-	mkdir -p $(DESTDIR)/include
-	cp libpsaff.so $(DESTDIR)/lib/
-	cp -r include/* $(DESTDIR)/include/
-	cp tools/psa_autogen /usr/local/bin/
-
-uninstall:
-	rm $(DESTDIR)/lib/libpsaff.so
-	rm -rf $(DESTDIR)/include/psa
-	rm -rf $(DESTDIR)/include/psasim
-	rm -f /usr/local/bin/psa_autogen
+CLIENT_LIBS := -Lclient_libs -lpsaclient -lmbedtls -lmbedx509 -lmbedcrypto
+SERVER_LIBS := -Lserver_libs -lmbedcrypto
+
+COMMON_INCLUDE := -I./include -I$(MBEDTLS_PATH)/include \
+	$(TF_PSA_CRYPTO_LIBRARY_PUBLIC_INCLUDE)
+
+GENERATED_MANIFEST_H_FILES = \
+	include/psa_manifest/manifest.h \
+	include/psa_manifest/pid.h \
+	include/psa_manifest/sid.h
+
+GENERATED_WRAPPER_H_FILES = \
+	src/psa_sim_serialise.h \
+	src/psa_functions_codes.h
+
+GENERATED_H_FILES = $(GENERATED_MANIFEST_H_FILES) $(GENERATED_WRAPPER_H_FILES)
+
+GENERATED_C_FILES = \
+	src/psa_sim_serialise.c \
+	src/psa_sim_crypto_client.c src/psa_sim_crypto_server.c
+
+PSASIM_GENERATED_FILES = $(GENERATED_H_FILES) $(PARTITION_SERVER_BOOTSTRAP) $(GENERATED_C_FILES)
+
+LIBPSACLIENT_SRC = src/psa_ff_client.c \
+		 		src/psa_sim_crypto_client.c \
+		 		src/psa_sim_serialise.c
+LIBPSACLIENT_OBJS=$(LIBPSACLIENT_SRC:.c=.o)
+
+PSA_CLIENT_BASE_SRC = $(LIBPSACLIENT_SRC) src/client.c
+
+PSA_CLIENT_FULL_SRC = $(LIBPSACLIENT_SRC) \
+				$(wildcard src/aut_*.c)
+
+PARTITION_SERVER_BOOTSTRAP = src/psa_ff_bootstrap_TEST_PARTITION.c
+
+PSA_SERVER_SRC = $(PARTITION_SERVER_BOOTSTRAP) \
+				 src/psa_ff_server.c \
+				 src/psa_sim_crypto_server.c \
+				 src/psa_sim_serialise.c
+
+.PHONY: all clean client_libs server_libs
+
+all:
+
+generated_files: $(PSASIM_GENERATED_FILES)
+
+test/seedfile:
+	dd if=/dev/urandom of=./test/seedfile bs=64 count=1
+
+src/%.o: src/%.c $(GENERATED_H_FILES)
+	$(CC) $(COMMON_INCLUDE) $(CFLAGS) -c $< $(LDFLAGS) -o $@
+
+client_libs/libpsaclient: $(LIBPSACLIENT_OBJS)
+	mkdir -p client_libs
+	$(AR) -src client_libs/libpsaclient.a $(LIBPSACLIENT_OBJS)
+
+test/psa_client_base: $(PSA_CLIENT_BASE_SRC) $(GENERATED_H_FILES) test/seedfile
+	$(CC) $(COMMON_INCLUDE) $(CFLAGS) $(PSA_CLIENT_BASE_SRC) $(CLIENT_LIBS) $(LDFLAGS) -o $@
+
+test/psa_client_full: $(PSA_CLIENT_FULL_SRC) $(GENERATED_H_FILES) test/seedfile
+	$(CC) $(COMMON_INCLUDE) $(CFLAGS) $(PSA_CLIENT_FULL_SRC) $(CLIENT_LIBS) $(LDFLAGS) -o $@
+
+test/psa_server: $(PSA_SERVER_SRC) $(GENERATED_H_FILES)
+	$(CC) $(COMMON_INCLUDE) $(CFLAGS) $(PSA_SERVER_SRC) $(SERVER_LIBS) $(LDFLAGS) -o $@
+
+$(PARTITION_SERVER_BOOTSTRAP) $(GENERATED_MANIFEST_H_FILES): src/manifest.json src/server.c
+	tools/psa_autogen.py src/manifest.json
+
+src/psa_sim_serialise.h: src/psa_sim_serialise.pl
+	cd src && ./psa_sim_serialise.pl h >$(@F)
+
+src/psa_sim_serialise.c: src/psa_sim_serialise.pl
+	cd src && ./psa_sim_serialise.pl c >$(@F)
+
+src/psa_functions_codes.h src/psa_sim_crypto_client.c src/psa_sim_crypto_server.c: $(TF_PSA_CRYPTO_PATH)/include/psa/crypto.h
+src/psa_functions_codes.h src/psa_sim_crypto_client.c src/psa_sim_crypto_server.c: $(TF_PSA_CRYPTO_PATH)/include/psa/crypto_extra.h
+src/psa_functions_codes.h src/psa_sim_crypto_client.c src/psa_sim_crypto_server.c: src/psa_sim_generate.pl
+	cd $(TF_PSA_CRYPTO_PATH) && $(abspath src/psa_sim_generate.pl)
+
+# Build MbedTLS libraries (crypto, x509 and tls) and copy them locally to
+# build client/server applications.
+#
+# Note: these rules assume that mbedtls_config.h is already configured by all.sh.
+# If not using all.sh then the user must do it manually.
+client_libs: client_libs/libpsaclient
+client_libs server_libs:
+	$(MAKE) -C $(MBEDTLS_PATH)/library CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" libmbedcrypto.a libmbedx509.a libmbedtls.a
+	mkdir -p $@
+	cp $(MBEDTLS_PATH)/library/libmbed*.a $@/
+
+clean_server_intermediate_files:
+	rm -f $(PARTITION_SERVER_BOOTSTRAP)
+	rm -rf include/psa_manifest
+
+clean: clean_server_intermediate_files
+	rm -f test/psa_client_base test/psa_client_full test/psa_server
+	rm -rf client_libs server_libs
+	rm -f test/psa_service_* test/psa_notify_* test/*.log
+	rm -f test/seedfile
 
+neat: clean
+	rm -f $(PSASIM_GENERATED_FILES)
diff -Nru mbedtls-3.6.5/framework/psasim/README.md mbedtls-3.6.6/framework/psasim/README.md
--- mbedtls-3.6.5/framework/psasim/README.md	2025-10-01 18:24:20.266168400 +0300
+++ mbedtls-3.6.6/framework/psasim/README.md	2026-03-27 12:34:57.773342000 +0200
@@ -1,60 +1,46 @@
 # psasim
 
-This tool simulates a PSA Firmware Framework implementation.
-It allows you to develop secure partitions and their clients on a desktop computer.
-It should be able to run on all systems that support POSIX and System V IPC:
-e.g. macOS, Linux, FreeBSD, and perhaps Windows 10 WSL2.
+PSASIM holds necessary C source and header files which allows to test Mbed TLS in a "pure crypto client" scenario, i.e `MBEDTLS_PSA_CRYPTO_CLIENT && !MBEDTLS_PSA_CRYPTO_C`.
+In practical terms it means that this allow to build PSASIM with Mbed TLS sources and get 2 Linux applications, a client and a server, which are connected through Linux's shared memeory, and in which the client relies on the server to perform all PSA Crypto operations.
 
-Please note that the code in this directory is maintained by the Mbed TLS / PSA Crypto project solely for the purpose of testing the use of Mbed TLS with client/service separation. We do not recommend using this code for any other purpose. In particular:
+The goal of PSASIM is _not_ to provide a ready-to-use solution for anyone looking to implement the pure crypto client structure (see [Limitations](#limitations) for details), but to provide an example of TF-PSA-Crypto RPC (Remote Procedure Call) implementation using Mbed TLS.
 
-* This simulator is not intended to pass or demonstrate compliance.
-* This code is only intended for simulation and does not have any security goals. It does not isolate services from clients.
+## Limitations
 
-## Building
-
-To build and run the test program make sure you have `make`, `python` and a
-C compiler installed and then enter the following commands:
+In the current implementation:
 
-```sh
-make install
-make run
-```
+- Only Linux PC is supported.
+- There can be only 1 client connected to 1 server.
+- Shared memory is the only communication medium allowed. Others can be implemented (ex: net sockets), but in terms of simulation speed shared memory proved to be the fastest.
+- Server is not secure at all: keys and operation structs are stored on the RAM, so they can easily be dumped.
 
-On Linux you may need to run `ldconfig` to ensure the library is properly installed.
-
-An example pair of programs is included in the `test` directory.
+## Building
 
-## Features
+### Build tooling
 
-The implemented API is intended to be compliant with PSA-FF 1.0.0 with the exception of a couple of things that are a work in progress:
+Building PSASIM requires the following tools:
 
-* `psa_notify` support
-* "strict" policy in manifest
+* GNU make.
+* A C compiler.
+* Perl.
+* The JSON package for Perl (`cpain -i JSON` or `apt install libjson-perl`).
 
-The only supported "interrupts" are POSIX signals, which act
-as a "virtual interrupt".
+### Build instructions
 
-The standard PSA RoT APIs are not included (e.g. cryptography, attestation, lifecycle etc).
+The build instructions are in `framework/psasim/Makefile`, with the assistance of `scripts/crypto-common.make` in TF-PSA-Crypto. The main targets are:
 
-## Design
+* `client_libs`: builds object files to be linked with a client. The client code is expected to include TF-PSA-Crypto with `MBEDTLS_PSA_CRYPTO_CLIENT` enabled and `MBEDTLS_PSA_CRYPTO_C` disabled, with no local cryptographic primitives.
+* `test/psa_server`: builds a server, including the crypto partition. This requires TF-PSA-Crypto compiled with the PSA core (`MBEDTLS_PSA_CRYPTO_C`) and cryptographic primitives.
 
-The code is designed to be readable rather than fast or secure.
-In this implementation only one message is delivered to a
-RoT service at a time.
-The code is not thread-safe.
+Note in particular that the client and the server require different builds of `libtfpsacrypto`, since they must have different configurations.
 
-To debug the simulator enable the debug flag:
+Note that at the time of writing, building PSASIM only officially works from an Mbed TLS tree. It might not work from a standalone TF-PSA-Crypto tree.
 
-```sh
-make DEBUG=1 install
-```
+Some C files are generated from JSON data and from parsing TF-PSA-Crypto header files, using the scripts `src/psa_sim_generate.pl` and `src/psa_sim_serialise.pl`. They are not committed into version control, but rather generated during the build of the client or the server, according to the instructions in the makefile.
 
-## Unsupported features
+### Testing
 
-Because this is a simulator there are a few things that
-can't be reasonably emulated:
+Please refer to [`tests/scripts/components-psasim.sh` in Mbed TLS](https://github.com/Mbed-TLS/mbedtls/blob/development/tests/scripts/components-psasim.sh) and the `helper_psasim_xxx` auxiliary functions in [`framework/scripts/all-helpers.sh`](../scripts/all-helpers.sh) for guidance on how to build & test PSASIM:
 
-* Manifest MMIO regions are unsupported
-* Manifest priority field is ignored
-* Partition IDs are in fact POSIX `pid_t`, which are only assigned at runtime,
-  making it infeasible to populate pid.h with correct values.
+- `component_test_psasim()`: builds the server and a couple of test clients which are used to evaluate some basic PSA Crypto API commands.
+- `component_test_suite_with_psasim()`: builds the server and _all_ the usual test suites (those found under the `<mbedtls-root>/tests/suites/*` folder) which are used by the CI and runs them. A small subset of test suites (`test_suite_constant_time_hmac`,`test_suite_lmots`,`test_suite_lms`) are being skipped, for CI turnover time optimization. They can be run locally if required.
diff -Nru mbedtls-3.6.5/framework/psasim/src/aut_main.c mbedtls-3.6.6/framework/psasim/src/aut_main.c
--- mbedtls-3.6.5/framework/psasim/src/aut_main.c	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/src/aut_main.c	2026-03-27 12:34:57.774216200 +0200
@@ -0,0 +1,71 @@
+/**
+ * This is the base AUT that exectues all other AUTs meant to test PSA APIs
+ * through PSASIM.
+ */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+/* First include Mbed TLS headers to get the Mbed TLS configuration and
+ * platform definitions that we'll use in this program. Also include
+ * standard C headers for functions we'll use here. */
+#include "mbedtls/build_info.h"
+
+#include "psa/crypto.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+int psa_hash_compute_main(void);
+int psa_hash_main(void);
+int psa_aead_encrypt_main(char *cipher_name);
+int psa_aead_encrypt_decrypt_main(void);
+int psa_cipher_encrypt_decrypt_main(void);
+int psa_asymmetric_encrypt_decrypt_main(void);
+int psa_random_main(void);
+int psa_mac_main(void);
+int psa_key_agreement_main(void);
+int psa_sign_verify_main(void);
+int psa_hkdf_main(void);
+
+#define TEST_MODULE(main_func) \
+    do {    \
+        char title[128] = { 0 }; \
+        char separator[128] = { 0 }; \
+        int title_len = snprintf(title, sizeof(title), "=== Test: %s ===", #main_func); \
+        memset(separator, '=', title_len); \
+        printf("%s\n%s\n%s\n", separator, title, separator); \
+        ret = main_func; \
+        if (ret != 0) { \
+            goto exit; \
+        } \
+    } while (0)
+
+int main()
+{
+    int ret;
+
+    TEST_MODULE(psa_hash_compute_main());
+    TEST_MODULE(psa_hash_main());
+
+    TEST_MODULE(psa_aead_encrypt_main("aes128-gcm"));
+    TEST_MODULE(psa_aead_encrypt_main("aes256-gcm"));
+    TEST_MODULE(psa_aead_encrypt_main("aes128-gcm_8"));
+    TEST_MODULE(psa_aead_encrypt_main("chachapoly"));
+    TEST_MODULE(psa_aead_encrypt_decrypt_main());
+    TEST_MODULE(psa_cipher_encrypt_decrypt_main());
+    TEST_MODULE(psa_asymmetric_encrypt_decrypt_main());
+
+    TEST_MODULE(psa_random_main());
+
+    TEST_MODULE(psa_mac_main());
+    TEST_MODULE(psa_key_agreement_main());
+    TEST_MODULE(psa_sign_verify_main());
+    TEST_MODULE(psa_hkdf_main());
+
+exit:
+    return (ret != 0) ? 1 : 0;
+}
diff -Nru mbedtls-3.6.5/framework/psasim/src/aut_psa_aead_encrypt.c mbedtls-3.6.6/framework/psasim/src/aut_psa_aead_encrypt.c
--- mbedtls-3.6.5/framework/psasim/src/aut_psa_aead_encrypt.c	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/src/aut_psa_aead_encrypt.c	2026-03-27 12:34:57.774356400 +0200
@@ -0,0 +1,227 @@
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "mbedtls/build_info.h"
+
+#include "psa/crypto.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+const char usage[] =
+    "Usage: aead_demo [aes128-gcm|aes256-gcm|aes128-gcm_8|chachapoly]";
+
+/* Dummy data for encryption: IV/nonce, additional data, 2-part message */
+const unsigned char iv1[12] = { 0x00 };
+const unsigned char add_data1[] = { 0x01, 0x02 };
+const unsigned char msg1_part1[] = { 0x03, 0x04 };
+const unsigned char msg1_part2[] = { 0x05, 0x06, 0x07 };
+
+/* Dummy data (2nd message) */
+const unsigned char iv2[12] = { 0x10 };
+const unsigned char add_data2[] = { 0x11, 0x12 };
+const unsigned char msg2_part1[] = { 0x13, 0x14 };
+const unsigned char msg2_part2[] = { 0x15, 0x16, 0x17 };
+
+/* Maximum total size of the messages */
+#define MSG1_SIZE (sizeof(msg1_part1) + sizeof(msg1_part2))
+#define MSG2_SIZE (sizeof(msg2_part1) + sizeof(msg2_part2))
+#define MSG_MAX_SIZE (MSG1_SIZE > MSG2_SIZE ? MSG1_SIZE : MSG2_SIZE)
+
+/* Dummy key material - never do this in production!
+ * 32-byte is enough to all the key size supported by this program. */
+const unsigned char key_bytes[32] = { 0x2a };
+
+/* Print the contents of a buffer in hex */
+void print_buf(const char *title, uint8_t *buf, size_t len)
+{
+    printf("%s:", title);
+    for (size_t i = 0; i < len; i++) {
+        printf(" %02x", buf[i]);
+    }
+    printf("\n");
+}
+
+/* Run a PSA function and bail out if it fails.
+ * The symbolic name of the error code can be recovered using:
+ * programs/psa/psa_constant_name status <value> */
+#define PSA_CHECK(expr)                                       \
+    do                                                          \
+    {                                                           \
+        status = (expr);                                      \
+        if (status != PSA_SUCCESS)                             \
+        {                                                       \
+            printf("Error %d at line %d: %s\n",                \
+                   (int) status,                               \
+                   __LINE__,                                   \
+                   #expr);                                    \
+            goto exit;                                          \
+        }                                                       \
+    }                                                           \
+    while (0)
+
+/*
+ * Prepare encryption material:
+ * - interpret command-line argument
+ * - set up key
+ * - outputs: key and algorithm, which together hold all the information
+ */
+static psa_status_t aead_prepare(const char *info,
+                                 psa_key_id_t *key,
+                                 psa_algorithm_t *alg)
+{
+    psa_status_t status;
+
+    /* Convert arg to alg + key_bits + key_type */
+    size_t key_bits;
+    psa_key_type_t key_type;
+    if (strcmp(info, "aes128-gcm") == 0) {
+        *alg = PSA_ALG_GCM;
+        key_bits = 128;
+        key_type = PSA_KEY_TYPE_AES;
+    } else if (strcmp(info, "aes256-gcm") == 0) {
+        *alg = PSA_ALG_GCM;
+        key_bits = 256;
+        key_type = PSA_KEY_TYPE_AES;
+    } else if (strcmp(info, "aes128-gcm_8") == 0) {
+        *alg = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, 8);
+        key_bits = 128;
+        key_type = PSA_KEY_TYPE_AES;
+    } else if (strcmp(info, "chachapoly") == 0) {
+        *alg = PSA_ALG_CHACHA20_POLY1305;
+        key_bits = 256;
+        key_type = PSA_KEY_TYPE_CHACHA20;
+    } else {
+        puts(usage);
+        return PSA_ERROR_INVALID_ARGUMENT;
+    }
+
+    /* Prepare key attributes */
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);
+    psa_set_key_algorithm(&attributes, *alg);
+    psa_set_key_type(&attributes, key_type);
+    psa_set_key_bits(&attributes, key_bits);   // optional
+
+    /* Import key */
+    PSA_CHECK(psa_import_key(&attributes, key_bytes, key_bits / 8, key));
+
+exit:
+    return status;
+}
+
+/*
+ * Print out some information.
+ *
+ * All of this information was present in the command line argument, but his
+ * function demonstrates how each piece can be recovered from (key, alg).
+ */
+static void aead_info(psa_key_id_t key, psa_algorithm_t alg)
+{
+    psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT;
+    (void) psa_get_key_attributes(key, &attr);
+    psa_key_type_t key_type = psa_get_key_type(&attr);
+    size_t key_bits = psa_get_key_bits(&attr);
+    psa_algorithm_t base_alg = PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(alg);
+    size_t tag_len = PSA_AEAD_TAG_LENGTH(key_type, key_bits, alg);
+
+    const char *type_str = key_type == PSA_KEY_TYPE_AES ? "AES"
+                         : key_type == PSA_KEY_TYPE_CHACHA20 ? "Chacha"
+                         : "???";
+    const char *base_str = base_alg == PSA_ALG_GCM ? "GCM"
+                         : base_alg == PSA_ALG_CHACHA20_POLY1305 ? "ChachaPoly"
+                         : "???";
+
+    printf("%s, %u, %s, %u\n",
+           type_str, (unsigned) key_bits, base_str, (unsigned) tag_len);
+}
+
+/*
+ * Encrypt a 2-part message.
+ */
+static int aead_encrypt(psa_key_id_t key, psa_algorithm_t alg,
+                        const unsigned char *iv, size_t iv_len,
+                        const unsigned char *ad, size_t ad_len,
+                        const unsigned char *part1, size_t part1_len,
+                        const unsigned char *part2, size_t part2_len)
+{
+    psa_status_t status;
+    size_t olen, olen_tag;
+    unsigned char out[PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE(MSG_MAX_SIZE)];
+    unsigned char *p = out, *end = out + sizeof(out);
+    unsigned char tag[PSA_AEAD_TAG_MAX_SIZE];
+
+    psa_aead_operation_t op = PSA_AEAD_OPERATION_INIT;
+    PSA_CHECK(psa_aead_encrypt_setup(&op, key, alg));
+
+    PSA_CHECK(psa_aead_set_nonce(&op, iv, iv_len));
+    PSA_CHECK(psa_aead_update_ad(&op, ad, ad_len));
+    PSA_CHECK(psa_aead_update(&op, part1, part1_len, p, end - p, &olen));
+    p += olen;
+    PSA_CHECK(psa_aead_update(&op, part2, part2_len, p, end - p, &olen));
+    p += olen;
+    PSA_CHECK(psa_aead_finish(&op, p, end - p, &olen,
+                              tag, sizeof(tag), &olen_tag));
+    p += olen;
+    memcpy(p, tag, olen_tag);
+    p += olen_tag;
+
+    olen = p - out;
+    print_buf("out", out, olen);
+
+exit:
+    psa_aead_abort(&op);   // required on errors, harmless on success
+    return status;
+}
+
+/*
+ * AEAD demo: set up key/alg, print out info, encrypt messages.
+ */
+static psa_status_t aead_demo(const char *info)
+{
+    psa_status_t status;
+
+    psa_key_id_t key;
+    psa_algorithm_t alg;
+
+    PSA_CHECK(aead_prepare(info, &key, &alg));
+
+    aead_info(key, alg);
+
+    PSA_CHECK(aead_encrypt(key, alg,
+                           iv1, sizeof(iv1), add_data1, sizeof(add_data1),
+                           msg1_part1, sizeof(msg1_part1),
+                           msg1_part2, sizeof(msg1_part2)));
+    PSA_CHECK(aead_encrypt(key, alg,
+                           iv2, sizeof(iv2), add_data2, sizeof(add_data2),
+                           msg2_part1, sizeof(msg2_part1),
+                           msg2_part2, sizeof(msg2_part2)));
+
+exit:
+    psa_destroy_key(key);
+
+    return status;
+}
+
+/*
+ * Main function
+ */
+int psa_aead_encrypt_main(char *cipher_name)
+{
+    psa_status_t status = PSA_SUCCESS;
+
+    /* Initialize the PSA crypto library. */
+    PSA_CHECK(psa_crypto_init());
+
+    /* Run the demo */
+    PSA_CHECK(aead_demo(cipher_name));
+
+    /* Deinitialize the PSA crypto library. */
+    mbedtls_psa_crypto_free();
+
+exit:
+    return status == PSA_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff -Nru mbedtls-3.6.5/framework/psasim/src/aut_psa_aead_encrypt_decrypt.c mbedtls-3.6.6/framework/psasim/src/aut_psa_aead_encrypt_decrypt.c
--- mbedtls-3.6.5/framework/psasim/src/aut_psa_aead_encrypt_decrypt.c	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/src/aut_psa_aead_encrypt_decrypt.c	2026-03-27 12:34:57.774499000 +0200
@@ -0,0 +1,126 @@
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "psa/crypto.h"
+/*
+ * Temporary hack: psasim’s Makefile only does:
+ *  -Itests/psa-client-server/psasim/include
+ *  -I$(MBEDTLS_ROOT_PATH)/include
+ *  -I$(MBEDTLS_ROOT_PATH)/tf-psa-crypto/include
+ *  -I$(MBEDTLS_ROOT_PATH)/tf-psa-crypto/drivers/builtin/include
+ * None of those cover tf-psa-crypto/core, so we rely on the
+ * “-I$(MBEDTLS_ROOT_PATH)/include” entry plus a parent-relative
+ * include "../tf-psa-crypto/core/tf_psa_crypto_common.h" in order to pull in tf_psa_crypto_common.h here,
+ * which in turn gets MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING (to silence the
+ * new GCC-15 unterminated-string-initialization warning).
+ * See GitHub issue #10223 for the proper long-term fix.
+ * https://github.com/Mbed-TLS/mbedtls/issues/10223
+ */
+#include "../tf-psa-crypto/core/tf_psa_crypto_common.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define BUFFER_SIZE 500
+
+static void print_bytestr(const uint8_t *bytes, size_t len)
+{
+    for (unsigned int idx = 0; idx < len; idx++) {
+        printf("%02X", bytes[idx]);
+    }
+}
+
+int psa_aead_encrypt_decrypt_main(void)
+{
+    psa_status_t status;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_id_t key_id = 0;
+    uint8_t encrypt[BUFFER_SIZE] = { 0 };
+    uint8_t decrypt[BUFFER_SIZE] = { 0 };
+    const uint8_t plaintext[] = "Hello World!";
+    /* We need to tell the compiler that we meant to leave out the null character. */
+    const uint8_t key_bytes[32] MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING =
+        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+    uint8_t nonce[PSA_AEAD_NONCE_LENGTH(PSA_KEY_TYPE_AES, PSA_ALG_CCM)];
+    size_t nonce_length = sizeof(nonce);
+    size_t ciphertext_length;
+    size_t plaintext_length;
+
+    status = psa_crypto_init();
+    if (status != PSA_SUCCESS) {
+        printf("psa_crypto_init failed\n");
+        return EXIT_FAILURE;
+    }
+
+    psa_set_key_usage_flags(&attributes,
+                            PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
+    psa_set_key_algorithm(&attributes, PSA_ALG_CCM);
+    psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
+    psa_set_key_bits(&attributes, 256);
+
+    status = psa_import_key(&attributes, key_bytes, sizeof(key_bytes), &key_id);
+    if (status != PSA_SUCCESS) {
+        printf("psa_import_key failed\n");
+        return EXIT_FAILURE;
+    }
+
+    status = psa_generate_random(nonce, nonce_length);
+    if (status != PSA_SUCCESS) {
+        printf("psa_generate_random failed\n");
+        return EXIT_FAILURE;
+    }
+
+    status = psa_aead_encrypt(key_id,                            // key
+                              PSA_ALG_CCM,                       // algorithm
+                              nonce, nonce_length,               // nonce
+                              NULL, 0,                           // additional data
+                              plaintext, sizeof(plaintext),      // plaintext
+                              encrypt, sizeof(encrypt),          // ciphertext
+                              &ciphertext_length);               // length of output
+    if (status != PSA_SUCCESS) {
+        printf("psa_aead_encrypt failed\n");
+        return EXIT_FAILURE;
+    }
+
+    printf("AES-CCM encryption:\n");
+    printf("- Plaintext: '%s':\n", plaintext);
+    printf("- Key: ");
+    print_bytestr(key_bytes, sizeof(key_bytes));
+    printf("\n- Nonce: ");
+    print_bytestr(nonce, nonce_length);
+    printf("\n- No additional data\n");
+    printf("- Ciphertext:\n");
+
+    for (size_t j = 0; j < ciphertext_length; j++) {
+        if (j % 8 == 0) {
+            printf("\n    ");
+        }
+        printf("%02x ", encrypt[j]);
+    }
+
+    printf("\n");
+
+    status = psa_aead_decrypt(key_id,                       // key
+                              PSA_ALG_CCM,                  // algorithm
+                              nonce, nonce_length,          // nonce
+                              NULL, 0,                      // additional data
+                              encrypt, ciphertext_length,   // ciphertext
+                              decrypt, sizeof(decrypt),     // plaintext
+                              &plaintext_length);           // length of output
+    if (status != PSA_SUCCESS) {
+        printf("psa_aead_decrypt failed\n");
+        return EXIT_FAILURE;
+    }
+
+    if (memcmp(plaintext, decrypt, sizeof(plaintext)) != 0) {
+        printf("\nEncryption/Decryption failed!\n");
+    } else {
+        printf("\nEncryption/Decryption successful!\n");
+    }
+
+    psa_destroy_key(key_id);
+    mbedtls_psa_crypto_free();
+    return 0;
+}
diff -Nru mbedtls-3.6.5/framework/psasim/src/aut_psa_asymmetric_encrypt_decrypt.c mbedtls-3.6.6/framework/psasim/src/aut_psa_asymmetric_encrypt_decrypt.c
--- mbedtls-3.6.5/framework/psasim/src/aut_psa_asymmetric_encrypt_decrypt.c	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/src/aut_psa_asymmetric_encrypt_decrypt.c	2026-03-27 12:34:57.774568300 +0200
@@ -0,0 +1,81 @@
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "psa/crypto.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define KEY_BITS        4096
+#define BUFFER_SIZE     PSA_BITS_TO_BYTES(KEY_BITS)
+
+static void print_bytestr(const uint8_t *bytes, size_t len)
+{
+    for (unsigned int idx = 0; idx < len; idx++) {
+        printf("%02X", bytes[idx]);
+    }
+}
+
+int psa_asymmetric_encrypt_decrypt_main(void)
+{
+    psa_status_t status;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_id_t key_id = 0;
+    uint8_t original[BUFFER_SIZE/2] = { 0 };
+    uint8_t encrypt[BUFFER_SIZE] = { 0 };
+    uint8_t decrypt[BUFFER_SIZE] = { 0 };
+    size_t encrypted_length;
+    size_t decrypted_length;
+
+    status = psa_crypto_init();
+    if (status != PSA_SUCCESS) {
+        printf("psa_crypto_init failed\n");
+        return EXIT_FAILURE;
+    }
+
+    status = psa_generate_random(original, sizeof(original));
+    if (status != PSA_SUCCESS) {
+        printf("psa_generate_random() failed\n");
+        return EXIT_FAILURE;
+    }
+
+    psa_set_key_usage_flags(&attributes,
+                            PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
+    psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PKCS1V15_CRYPT);
+    psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
+    psa_set_key_bits(&attributes, KEY_BITS);
+
+    status = psa_generate_key(&attributes, &key_id);
+    if (status != PSA_SUCCESS) {
+        printf("psa_generate_key failed (%d)\n", status);
+        return EXIT_FAILURE;
+    }
+
+    status = psa_asymmetric_encrypt(key_id, PSA_ALG_RSA_PKCS1V15_CRYPT,
+                                    original, sizeof(original), NULL, 0,
+                                    encrypt, sizeof(encrypt), &encrypted_length);
+    if (status != PSA_SUCCESS) {
+        printf("psa_asymmetric_encrypt failed (%d)\n", status);
+        return EXIT_FAILURE;
+    }
+
+    status = psa_asymmetric_decrypt(key_id, PSA_ALG_RSA_PKCS1V15_CRYPT,
+                                    encrypt, encrypted_length, NULL, 0,
+                                    decrypt, sizeof(decrypt), &decrypted_length);
+    if (status != PSA_SUCCESS) {
+        printf("psa_cipher_decrypt failed (%d)\n", status);
+        return EXIT_FAILURE;
+    }
+
+    if (memcmp(original, decrypt, sizeof(original)) != 0) {
+        printf("\nEncryption/Decryption failed!\n");
+    } else {
+        printf("\nEncryption/Decryption successful!\n");
+    }
+
+    psa_destroy_key(key_id);
+    mbedtls_psa_crypto_free();
+    return 0;
+}
diff -Nru mbedtls-3.6.5/framework/psasim/src/aut_psa_cipher_encrypt_decrypt.c mbedtls-3.6.6/framework/psasim/src/aut_psa_cipher_encrypt_decrypt.c
--- mbedtls-3.6.5/framework/psasim/src/aut_psa_cipher_encrypt_decrypt.c	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/src/aut_psa_cipher_encrypt_decrypt.c	2026-03-27 12:34:57.774694200 +0200
@@ -0,0 +1,84 @@
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "psa/crypto.h"
+#include "../tf-psa-crypto/core/tf_psa_crypto_common.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define BUFFER_SIZE 4096
+
+static void print_bytestr(const uint8_t *bytes, size_t len)
+{
+    for (unsigned int idx = 0; idx < len; idx++) {
+        printf("%02X", bytes[idx]);
+    }
+}
+
+int psa_cipher_encrypt_decrypt_main(void)
+{
+    psa_status_t status;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_id_t key_id = 0;
+    uint8_t original[BUFFER_SIZE] = { 0 };
+    uint8_t encrypt[BUFFER_SIZE] = { 0 };
+    uint8_t decrypt[BUFFER_SIZE] = { 0 };
+    /* We need to tell the compiler that we meant to leave out the null character. */
+    const uint8_t key_bytes[32] MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING =
+        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+    size_t encrypted_length;
+    size_t decrypted_length;
+
+    status = psa_crypto_init();
+    if (status != PSA_SUCCESS) {
+        printf("psa_crypto_init failed\n");
+        return EXIT_FAILURE;
+    }
+
+    status = psa_generate_random(original, sizeof(original));
+    if (status != PSA_SUCCESS) {
+        printf("psa_generate_random() failed\n");
+        return EXIT_FAILURE;
+    }
+
+    psa_set_key_usage_flags(&attributes,
+                            PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
+    psa_set_key_algorithm(&attributes, PSA_ALG_ECB_NO_PADDING);
+    psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
+    psa_set_key_bits(&attributes, 256);
+
+    status = psa_import_key(&attributes, key_bytes, sizeof(key_bytes), &key_id);
+    if (status != PSA_SUCCESS) {
+        printf("psa_import_key failed\n");
+        return EXIT_FAILURE;
+    }
+
+    status = psa_cipher_encrypt(key_id, PSA_ALG_ECB_NO_PADDING,
+                                original, sizeof(original),
+                                encrypt, sizeof(encrypt), &encrypted_length);
+    if (status != PSA_SUCCESS) {
+        printf("psa_cipher_encrypt failed\n");
+        return EXIT_FAILURE;
+    }
+
+    status = psa_cipher_decrypt(key_id, PSA_ALG_ECB_NO_PADDING,
+                                encrypt, encrypted_length,
+                                decrypt, sizeof(decrypt), &decrypted_length);
+    if (status != PSA_SUCCESS) {
+        printf("psa_cipher_decrypt failed\n");
+        return EXIT_FAILURE;
+    }
+
+    if (memcmp(original, decrypt, sizeof(original)) != 0) {
+        printf("\nEncryption/Decryption failed!\n");
+    } else {
+        printf("\nEncryption/Decryption successful!\n");
+    }
+
+    psa_destroy_key(key_id);
+    mbedtls_psa_crypto_free();
+    return 0;
+}
diff -Nru mbedtls-3.6.5/framework/psasim/src/aut_psa_hash.c mbedtls-3.6.6/framework/psasim/src/aut_psa_hash.c
--- mbedtls-3.6.5/framework/psasim/src/aut_psa_hash.c	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/src/aut_psa_hash.c	2026-03-27 12:34:57.774857500 +0200
@@ -0,0 +1,167 @@
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "psa/crypto.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mbedtls/build_info.h"
+#include "mbedtls/platform.h"
+
+#define HASH_ALG PSA_ALG_SHA_256
+
+static const uint8_t sample_message[] = "Hello World!";
+/* sample_message is terminated with a null byte which is not part of
+ * the message itself so we make sure to subtract it in order to get
+ * the message length. */
+static const size_t sample_message_length = sizeof(sample_message) - 1;
+
+#define EXPECTED_HASH_VALUE {                                                    \
+        0x7f, 0x83, 0xb1, 0x65, 0x7f, 0xf1, 0xfc, 0x53, 0xb9, 0x2d, 0xc1, 0x81, \
+        0x48, 0xa1, 0xd6, 0x5d, 0xfc, 0x2d, 0x4b, 0x1f, 0xa3, 0xd6, 0x77, 0x28, \
+        0x4a, 0xdd, 0xd2, 0x00, 0x12, 0x6d, 0x90, 0x69 \
+}
+
+static const uint8_t expected_hash[] = EXPECTED_HASH_VALUE;
+static const size_t expected_hash_len = sizeof(expected_hash);
+
+int psa_hash_main(void)
+{
+    psa_status_t status;
+    uint8_t hash[PSA_HASH_LENGTH(HASH_ALG)];
+    size_t hash_length;
+    psa_hash_operation_t hash_operation = PSA_HASH_OPERATION_INIT;
+    psa_hash_operation_t cloned_hash_operation = PSA_HASH_OPERATION_INIT;
+
+    mbedtls_printf("PSA Crypto API: SHA-256 example\n\n");
+
+    status = psa_crypto_init();
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_crypto_init failed\n");
+        return EXIT_FAILURE;
+    }
+
+    /* Compute hash using multi-part operation */
+    status = psa_hash_setup(&hash_operation, HASH_ALG);
+    if (status == PSA_ERROR_NOT_SUPPORTED) {
+        mbedtls_printf("unknown hash algorithm supplied\n");
+        return EXIT_FAILURE;
+    } else if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_hash_setup failed\n");
+        return EXIT_FAILURE;
+    }
+
+    status = psa_hash_update(&hash_operation, sample_message, sample_message_length);
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_hash_update failed\n");
+        goto cleanup;
+    }
+
+    status = psa_hash_clone(&hash_operation, &cloned_hash_operation);
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("PSA hash clone failed\n");
+        goto cleanup;
+    }
+
+    status = psa_hash_finish(&hash_operation, hash, sizeof(hash), &hash_length);
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_hash_finish failed\n");
+        goto cleanup;
+    }
+
+    /* Check the result of the operation against the sample */
+    if (hash_length != expected_hash_len ||
+        (memcmp(hash, expected_hash, expected_hash_len) != 0)) {
+        mbedtls_printf("Multi-part hash operation gave the wrong result!\n\n");
+        goto cleanup;
+    }
+
+    status =
+        psa_hash_verify(&cloned_hash_operation, expected_hash,
+                        expected_hash_len);
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_hash_verify failed\n");
+        goto cleanup;
+    } else {
+        mbedtls_printf("Multi-part hash operation successful!\n");
+    }
+
+    /* A bit of white-box testing: ensure that we can abort an operation more
+     * times than there are operation slots on the simulator server.
+     */
+    for (int i = 0; i < 200; i++) {
+        /* This should be a no-op */
+        status = psa_hash_abort(&hash_operation);
+        if (status != PSA_SUCCESS) {
+            mbedtls_printf("psa_hash_abort failed\n");
+            goto cleanup;
+        }
+    }
+
+    /* Compute hash using multi-part operation using the same operation struct */
+    status = psa_hash_setup(&hash_operation, HASH_ALG);
+    if (status == PSA_ERROR_NOT_SUPPORTED) {
+        mbedtls_printf("unknown hash algorithm supplied\n");
+        goto cleanup;
+    } else if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_hash_setup failed: %d\n", status);
+        goto cleanup;
+    }
+
+    status = psa_hash_update(&hash_operation, sample_message, sample_message_length);
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_hash_update failed\n");
+        goto cleanup;
+    }
+
+    /* Don't use psa_hash_finish() when going to check against an expected result */
+    status = psa_hash_verify(&hash_operation, expected_hash, expected_hash_len);
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_hash_verify failed: %d\n", status);
+        goto cleanup;
+    } else {
+        mbedtls_printf("Second multi-part hash operation successful!\n");
+    }
+
+    /* Clear local variables prior to one-shot hash demo */
+    memset(hash, 0, sizeof(hash));
+    hash_length = 0;
+
+    /* Compute hash using one-shot function call */
+    status = psa_hash_compute(HASH_ALG,
+                              sample_message, sample_message_length,
+                              hash, sizeof(hash),
+                              &hash_length);
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_hash_compute failed\n");
+        goto cleanup;
+    }
+
+    if (hash_length != expected_hash_len ||
+        (memcmp(hash, expected_hash, expected_hash_len) != 0)) {
+        mbedtls_printf("One-shot hash operation gave the wrong result!\n\n");
+        goto cleanup;
+    }
+
+    mbedtls_printf("One-shot hash operation successful!\n\n");
+
+    /* Print out result */
+    mbedtls_printf("The SHA-256( '%s' ) is: ", sample_message);
+
+    for (size_t j = 0; j < expected_hash_len; j++) {
+        mbedtls_printf("%02x", hash[j]);
+    }
+
+    mbedtls_printf("\n");
+
+    mbedtls_psa_crypto_free();
+    return EXIT_SUCCESS;
+
+cleanup:
+    psa_hash_abort(&hash_operation);
+    psa_hash_abort(&cloned_hash_operation);
+    return EXIT_FAILURE;
+}
diff -Nru mbedtls-3.6.5/framework/psasim/src/aut_psa_hash_compute.c mbedtls-3.6.6/framework/psasim/src/aut_psa_hash_compute.c
--- mbedtls-3.6.5/framework/psasim/src/aut_psa_hash_compute.c	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/src/aut_psa_hash_compute.c	2026-03-27 12:34:57.774951200 +0200
@@ -0,0 +1,81 @@
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "psa/crypto.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mbedtls/build_info.h"
+#include "mbedtls/platform.h"
+
+#define HASH_ALG PSA_ALG_SHA_256
+
+static const uint8_t sample_message[] = "Hello World!";
+/* sample_message is terminated with a null byte which is not part of
+ * the message itself so we make sure to subtract it in order to get
+ * the message length. */
+static const size_t sample_message_length = sizeof(sample_message) - 1;
+
+#define EXPECTED_HASH_VALUE {                                                    \
+        0x7f, 0x83, 0xb1, 0x65, 0x7f, 0xf1, 0xfc, 0x53, 0xb9, 0x2d, 0xc1, 0x81, \
+        0x48, 0xa1, 0xd6, 0x5d, 0xfc, 0x2d, 0x4b, 0x1f, 0xa3, 0xd6, 0x77, 0x28, \
+        0x4a, 0xdd, 0xd2, 0x00, 0x12, 0x6d, 0x90, 0x69 \
+}
+
+static const uint8_t expected_hash[] = EXPECTED_HASH_VALUE;
+static const size_t expected_hash_len = sizeof(expected_hash);
+
+int psa_hash_compute_main(void)
+{
+    psa_status_t status;
+    uint8_t hash[PSA_HASH_LENGTH(HASH_ALG)];
+    size_t hash_length;
+
+    mbedtls_printf("PSA Crypto API: SHA-256 example\n\n");
+
+    status = psa_crypto_init();
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_crypto_init failed\n");
+        return EXIT_FAILURE;
+    }
+
+    /* Clear local variables prior to one-shot hash demo */
+    memset(hash, 0, sizeof(hash));
+    hash_length = 0;
+
+    /* Compute hash using one-shot function call */
+    status = psa_hash_compute(HASH_ALG,
+                              sample_message, sample_message_length,
+                              hash, sizeof(hash),
+                              &hash_length);
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_hash_compute failed\n");
+        goto cleanup;
+    }
+
+    if (hash_length != expected_hash_len ||
+        (memcmp(hash, expected_hash, expected_hash_len) != 0)) {
+        mbedtls_printf("One-shot hash operation gave the wrong result!\n\n");
+        goto cleanup;
+    }
+
+    mbedtls_printf("One-shot hash operation successful!\n\n");
+
+    /* Print out result */
+    mbedtls_printf("The SHA-256( '%s' ) is: ", sample_message);
+
+    for (size_t j = 0; j < expected_hash_len; j++) {
+        mbedtls_printf("%02x", hash[j]);
+    }
+
+    mbedtls_printf("\n");
+
+    mbedtls_psa_crypto_free();
+    return EXIT_SUCCESS;
+
+cleanup:
+    return EXIT_FAILURE;
+}
diff -Nru mbedtls-3.6.5/framework/psasim/src/aut_psa_hkdf.c mbedtls-3.6.6/framework/psasim/src/aut_psa_hkdf.c
--- mbedtls-3.6.5/framework/psasim/src/aut_psa_hkdf.c	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/src/aut_psa_hkdf.c	2026-03-27 12:34:57.775104300 +0200
@@ -0,0 +1,121 @@
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "psa/crypto.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "mbedtls/build_info.h"
+
+int psa_hkdf_main(void)
+{
+    psa_status_t status;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_id_t key_id = 0;
+    psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT;
+
+    /* Example test vector from RFC 5869 */
+
+    /* Input keying material (IKM) */
+    unsigned char ikm[] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+                            0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b };
+
+    unsigned char salt[] =
+    { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c };
+
+    /* Context and application specific information, which can be of zero length */
+    unsigned char info[] = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 };
+
+    /* Expected OKM based on the RFC 5869-provided test vector */
+    unsigned char expected_okm[] = { 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43,
+                                     0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90,
+                                     0xcf, 0x1a, 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4,
+                                     0xc5, 0xbf, 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18,
+                                     0x58, 0x65 };
+
+    /* The output size of the HKDF function depends on the hash function used.
+     * In our case we use SHA-256, which produces a 32 byte fingerprint.
+     * Therefore, we allocate a buffer of 32 bytes to hold the output keying
+     * material (OKM).
+     */
+    unsigned char output[32];
+
+    psa_algorithm_t alg = PSA_ALG_HKDF(PSA_ALG_SHA_256);
+
+    printf("PSA Crypto API: HKDF SHA-256 example\n\n");
+
+    status = psa_crypto_init();
+    if (status != PSA_SUCCESS) {
+        printf("psa_crypto_init failed\n");
+        return EXIT_FAILURE;
+    }
+
+    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
+    psa_set_key_algorithm(&attributes, PSA_ALG_HKDF(PSA_ALG_SHA_256));
+    psa_set_key_type(&attributes, PSA_KEY_TYPE_DERIVE);
+
+    status = psa_import_key(&attributes, ikm, sizeof(ikm), &key_id);
+    if (status != PSA_SUCCESS) {
+        printf("psa_import_key failed\n");
+        return EXIT_FAILURE;
+    }
+
+    status = psa_key_derivation_setup(&operation, alg);
+    if (status != PSA_SUCCESS) {
+        printf("psa_key_derivation_setup failed");
+        return EXIT_FAILURE;
+    }
+
+    status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_SALT,
+                                            salt, sizeof(salt));
+    if (status != PSA_SUCCESS) {
+        printf("psa_key_derivation_input_bytes (salt) failed");
+        return EXIT_FAILURE;
+    }
+
+    status = psa_key_derivation_input_key(&operation, PSA_KEY_DERIVATION_INPUT_SECRET,
+                                          key_id);
+    if (status != PSA_SUCCESS) {
+        printf("psa_key_derivation_input_key failed");
+        return EXIT_FAILURE;
+    }
+
+    status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_INFO,
+                                            info, sizeof(info));
+    if (status != PSA_SUCCESS) {
+        printf("psa_key_derivation_input_bytes (info) failed");
+        return EXIT_FAILURE;
+    }
+
+    status = psa_key_derivation_output_bytes(&operation, output, sizeof(output));
+    if (status != PSA_SUCCESS) {
+        printf("psa_key_derivation_output_bytes failed");
+        return EXIT_FAILURE;
+    }
+
+    status = psa_key_derivation_abort(&operation);
+    if (status != PSA_SUCCESS) {
+        printf("psa_key_derivation_abort failed");
+        return EXIT_FAILURE;
+    }
+
+    printf("OKM: \n");
+
+    for (size_t j = 0; j < sizeof(output); j++) {
+        if (output[j] != expected_okm[j]) {
+            printf("\n --- Unexpected outcome!\n");
+            return EXIT_FAILURE;
+        }
+
+        if (j % 8 == 0) {
+            printf("\n    ");
+        }
+        printf("%02x ", output[j]);
+    }
+
+    printf("\n");
+    mbedtls_psa_crypto_free();
+    return EXIT_SUCCESS;
+}
diff -Nru mbedtls-3.6.5/framework/psasim/src/aut_psa_key_agreement.c mbedtls-3.6.6/framework/psasim/src/aut_psa_key_agreement.c
--- mbedtls-3.6.5/framework/psasim/src/aut_psa_key_agreement.c	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/src/aut_psa_key_agreement.c	2026-03-27 12:34:57.775247000 +0200
@@ -0,0 +1,146 @@
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+
+#include "psa/crypto.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "mbedtls/build_info.h"
+#include "mbedtls/debug.h"
+#include "mbedtls/platform.h"
+
+#define BUFFER_SIZE 500
+
+#define SERVER_PK_VALUE {                                     \
+        0x04, 0xde, 0xa5, 0xe4, 0x5d, 0x0e, 0xa3, 0x7f, 0xc5, \
+        0x66, 0x23, 0x2a, 0x50, 0x8f, 0x4a, 0xd2, 0x0e, 0xa1, \
+        0x3d, 0x47, 0xe4, 0xbf, 0x5f, 0xa4, 0xd5, 0x4a, 0x57, \
+        0xa0, 0xba, 0x01, 0x20, 0x42, 0x08, 0x70, 0x97, 0x49, \
+        0x6e, 0xfc, 0x58, 0x3f, 0xed, 0x8b, 0x24, 0xa5, 0xb9, \
+        0xbe, 0x9a, 0x51, 0xde, 0x06, 0x3f, 0x5a, 0x00, 0xa8, \
+        0xb6, 0x98, 0xa1, 0x6f, 0xd7, 0xf2, 0x9b, 0x54, 0x85, \
+        0xf3, 0x20                                            \
+}
+
+#define KEY_BITS 256
+
+int psa_key_agreement_main(void)
+{
+    psa_status_t status;
+    psa_key_attributes_t client_attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_attributes_t server_attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_attributes_t check_attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_id_t client_key_id = 0;
+    psa_key_id_t server_key_id = 0;
+    uint8_t client_pk[BUFFER_SIZE] = { 0 };
+    size_t client_pk_len;
+    size_t key_bits;
+    psa_key_type_t key_type;
+
+    const uint8_t server_pk[] = SERVER_PK_VALUE;
+    uint8_t derived_key[BUFFER_SIZE] = { 0 };
+    size_t derived_key_len;
+
+    status = psa_crypto_init();
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_crypto_init failed\n");
+        return EXIT_FAILURE;
+    }
+
+    psa_set_key_usage_flags(&client_attributes, PSA_KEY_USAGE_DERIVE);
+    psa_set_key_algorithm(&client_attributes, PSA_ALG_ECDH);
+    psa_set_key_type(&client_attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
+    psa_set_key_bits(&client_attributes, KEY_BITS);
+
+    /* Generate ephemeral key pair */
+    status = psa_generate_key(&client_attributes, &client_key_id);
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_generate_key failed\n");
+        return EXIT_FAILURE;
+    }
+    status = psa_export_public_key(client_key_id,
+                                   client_pk, sizeof(client_pk),
+                                   &client_pk_len);
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_export_public_key failed\n");
+        return EXIT_FAILURE;
+    }
+
+    mbedtls_printf("Client Public Key (%zu bytes):\n", client_pk_len);
+
+    for (size_t j = 0; j < client_pk_len; j++) {
+        if (j % 8 == 0) {
+            mbedtls_printf("\n    ");
+        }
+        mbedtls_printf("%02x ", client_pk[j]);
+    }
+    mbedtls_printf("\n\n");
+
+    psa_set_key_usage_flags(&server_attributes, PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_EXPORT);
+    psa_set_key_algorithm(&server_attributes, PSA_ALG_ECDSA_ANY);
+    psa_set_key_type(&server_attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
+
+    /* Import server public key */
+    status = psa_import_key(&server_attributes, server_pk, sizeof(server_pk), &server_key_id);
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_import_key failed\n");
+        return EXIT_FAILURE;
+    }
+
+    status = psa_get_key_attributes(server_key_id, &check_attributes);
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_get_key_attributes failed\n");
+        return EXIT_FAILURE;
+    }
+
+    key_bits = psa_get_key_bits(&check_attributes);
+    if (key_bits != 256) {
+        mbedtls_printf("Incompatible key size!\n");
+        return EXIT_FAILURE;
+    }
+
+    key_type = psa_get_key_type(&check_attributes);
+    if (key_type != PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)) {
+        mbedtls_printf("Unsupported key type!\n");
+        return EXIT_FAILURE;
+    }
+
+    mbedtls_printf("Server Public Key (%zu bytes):\n", sizeof(server_pk));
+
+    for (size_t j = 0; j < sizeof(server_pk); j++) {
+        if (j % 8 == 0) {
+            mbedtls_printf("\n    ");
+        }
+        mbedtls_printf("%02x ", server_pk[j]);
+    }
+    mbedtls_printf("\n\n");
+
+    /* Generate ECDHE derived key */
+    status = psa_raw_key_agreement(PSA_ALG_ECDH,                        // algorithm
+                                   client_key_id,                   // client secret key
+                                   server_pk, sizeof(server_pk),        // server public key
+                                   derived_key, sizeof(derived_key),    // buffer to store derived key
+                                   &derived_key_len);
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_raw_key_agreement failed\n");
+        return EXIT_FAILURE;
+    }
+
+    mbedtls_printf("Derived Key (%zu bytes):\n", derived_key_len);
+
+    for (size_t j = 0; j < derived_key_len; j++) {
+        if (j % 8 == 0) {
+            mbedtls_printf("\n    ");
+        }
+        mbedtls_printf("%02x ", derived_key[j]);
+    }
+    mbedtls_printf("\n");
+
+    psa_destroy_key(server_key_id);
+    psa_destroy_key(client_key_id);
+    mbedtls_psa_crypto_free();
+    return EXIT_SUCCESS;
+}
diff -Nru mbedtls-3.6.5/framework/psasim/src/aut_psa_mac.c mbedtls-3.6.6/framework/psasim/src/aut_psa_mac.c
--- mbedtls-3.6.5/framework/psasim/src/aut_psa_mac.c	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/src/aut_psa_mac.c	2026-03-27 12:34:57.775378200 +0200
@@ -0,0 +1,162 @@
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "psa/crypto.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mbedtls/build_info.h"
+
+/* constant-time buffer comparison */
+static inline int safer_memcmp(const void *a, const void *b, size_t n)
+{
+    size_t i;
+    volatile const unsigned char *A = (volatile const unsigned char *) a;
+    volatile const unsigned char *B = (volatile const unsigned char *) b;
+    volatile unsigned char diff = 0;
+
+    for (i = 0; i < n; i++) {
+        /* Read volatile data in order before computing diff.
+         * This avoids IAR compiler warning:
+         * 'the order of volatile accesses is undefined ..' */
+        unsigned char x = A[i], y = B[i];
+        diff |= x ^ y;
+    }
+
+    return diff;
+}
+
+
+int psa_mac_main(void)
+{
+    uint8_t input[] = "Hello World!";
+    psa_status_t status;
+    size_t mac_size_real = 0;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_id_t key_id = 0;
+    uint8_t mac[PSA_MAC_MAX_SIZE];
+    psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT;
+    const uint8_t key_bytes[16] = "kkkkkkkkkkkkkkkk";
+    const uint8_t mbedtls_test_hmac_sha256[] = {
+        0xae, 0x72, 0x34, 0x5a, 0x10, 0x36, 0xfb, 0x71,
+        0x35, 0x3c, 0x7d, 0x6c, 0x81, 0x98, 0x52, 0x86,
+        0x00, 0x4a, 0x43, 0x7c, 0x2d, 0xb3, 0x1a, 0xd8,
+        0x67, 0xb1, 0xad, 0x11, 0x4d, 0x18, 0x49, 0x8b
+    };
+
+    status = psa_crypto_init();
+    if (status != PSA_SUCCESS) {
+        printf("psa_crypto_init failed\n");
+        return EXIT_FAILURE;
+    }
+
+    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_MESSAGE |
+                            PSA_KEY_USAGE_SIGN_HASH |
+                            PSA_KEY_USAGE_SIGN_MESSAGE);
+    psa_set_key_algorithm(&attributes, PSA_ALG_HMAC(PSA_ALG_SHA_256));
+    psa_set_key_type(&attributes, PSA_KEY_TYPE_HMAC);
+
+    status = psa_import_key(&attributes, key_bytes, sizeof(key_bytes), &key_id);
+    if (status != PSA_SUCCESS) {
+        printf("psa_import_key failed\n");
+        return EXIT_FAILURE;
+    }
+
+    /* Single-part MAC operation with psa_mac_compute() */
+    status = psa_mac_compute(key_id,
+                             PSA_ALG_HMAC(PSA_ALG_SHA_256),
+                             input,
+                             sizeof(input),
+                             mac,
+                             sizeof(mac),
+                             &mac_size_real);
+    if (status != PSA_SUCCESS) {
+        printf("psa_mac_compute failed\n");
+        return EXIT_FAILURE;
+    }
+
+    printf("HMAC-SHA-256(%s) with psa_mac_compute():\n", input);
+
+    for (size_t j = 0; j < mac_size_real; j++) {
+        if (j % 8 == 0) {
+            printf("\n    ");
+        }
+        printf("%02x ", mac[j]);
+    }
+
+    printf("\n");
+
+    if (safer_memcmp(mac,
+                     mbedtls_test_hmac_sha256,
+                     mac_size_real
+                     ) != 0) {
+        printf("\nMAC verified incorrectly!\n");
+    } else {
+        printf("\nMAC verified correctly!\n");
+    }
+
+    psa_destroy_key(key_id);
+
+    status = psa_import_key(&attributes, key_bytes, sizeof(key_bytes), &key_id);
+    if (status != PSA_SUCCESS) {
+        printf("psa_import_key failed\n");
+        return EXIT_FAILURE;
+    }
+
+    /* Single-part MAC operation with psa_mac_verify() */
+    status = psa_mac_verify(key_id,
+                            PSA_ALG_HMAC(PSA_ALG_SHA_256),
+                            input,
+                            sizeof(input),
+                            mbedtls_test_hmac_sha256,
+                            sizeof(mbedtls_test_hmac_sha256));
+    if (status != PSA_SUCCESS) {
+        printf("psa_mac_verify failed\n");
+        return EXIT_FAILURE;
+    } else {
+        printf("psa_mac_verify passed successfully\n");
+    }
+
+    psa_destroy_key(key_id);
+
+    status = psa_import_key(&attributes, key_bytes, sizeof(key_bytes), &key_id);
+    if (status != PSA_SUCCESS) {
+        printf("psa_import_key failed\n");
+        return EXIT_FAILURE;
+    }
+
+    /* Multi-part MAC operation */
+    status = psa_mac_sign_setup(&operation, key_id, PSA_ALG_HMAC(PSA_ALG_SHA_256));
+    if (status != PSA_SUCCESS) {
+        printf("psa_mac_sign_setup failed\n");
+        return EXIT_FAILURE;
+    }
+
+    status = psa_mac_update(&operation, input, sizeof(input));
+    if (status != PSA_SUCCESS) {
+        printf("psa_mac_update failed\n");
+        return EXIT_FAILURE;
+    }
+
+    status = psa_mac_sign_finish(&operation, mac, sizeof(mac), &mac_size_real);
+    if (status != PSA_SUCCESS) {
+        printf("psa_mac_sign_finish failed\n");
+        return EXIT_FAILURE;
+    }
+
+    if (safer_memcmp(mac,
+                     mbedtls_test_hmac_sha256,
+                     mac_size_real
+                     ) != 0) {
+        printf("MAC, calculated with multi-part MAC operation, verified incorrectly!\n");
+    } else {
+        printf("MAC, calculated with multi-part MAC operation, verified correctly!\n");
+    }
+
+    psa_destroy_key(key_id);
+    mbedtls_psa_crypto_free();
+    return EXIT_SUCCESS;
+}
diff -Nru mbedtls-3.6.5/framework/psasim/src/aut_psa_random.c mbedtls-3.6.6/framework/psasim/src/aut_psa_random.c
--- mbedtls-3.6.5/framework/psasim/src/aut_psa_random.c	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/src/aut_psa_random.c	2026-03-27 12:34:57.775456700 +0200
@@ -0,0 +1,47 @@
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "mbedtls/build_info.h"
+
+#include <psa/crypto.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mbedtls/private/entropy.h"
+
+#define BUFFER_SIZE 100
+
+int psa_random_main(void)
+{
+    psa_status_t status;
+    uint8_t output[BUFFER_SIZE] = { 0 };
+
+    status = psa_crypto_init();
+    if (status != PSA_SUCCESS) {
+        printf("psa_crypto_init failed\n");
+        return EXIT_FAILURE;
+    }
+
+    status = psa_generate_random(output, BUFFER_SIZE);
+    if (status != PSA_SUCCESS) {
+        printf("psa_generate_random failed\n");
+        return EXIT_FAILURE;
+    }
+
+    printf("Random bytes generated:\n");
+
+    for (size_t j = 0; j < BUFFER_SIZE; j++) {
+        if (j % 8 == 0) {
+            printf("\n    ");
+        }
+        printf("%02x ", output[j]);
+    }
+
+    printf("\n");
+
+    mbedtls_psa_crypto_free();
+    return 0;
+}
diff -Nru mbedtls-3.6.5/framework/psasim/src/aut_psa_sign_verify.c mbedtls-3.6.6/framework/psasim/src/aut_psa_sign_verify.c
--- mbedtls-3.6.5/framework/psasim/src/aut_psa_sign_verify.c	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/src/aut_psa_sign_verify.c	2026-03-27 12:34:57.775570000 +0200
@@ -0,0 +1,93 @@
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+
+#include "psa/crypto.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mbedtls/build_info.h"
+#include "mbedtls/platform.h"
+
+#define KEY_BYTES_VALUE {                                                       \
+        0x49, 0xc9, 0xa8, 0xc1, 0x8c, 0x4b, 0x88, 0x56, 0x38, 0xc4, 0x31, 0xcf, \
+        0x1d, 0xf1, 0xc9, 0x94, 0x13, 0x16, 0x09, 0xb5, 0x80, 0xd4, 0xfd, 0x43, \
+        0xa0, 0xca, 0xb1, 0x7d, 0xb2, 0xf1, 0x3e, 0xee                          \
+}
+
+#define PLAINTEXT_VALUE "Hello World!"
+
+/* SHA-256(plaintext) */
+#define HASH_VALUE {                                                            \
+        0x5a, 0x09, 0xe8, 0xfa, 0x9c, 0x77, 0x80, 0x7b, 0x24, 0xe9, 0x9c, 0x9c, \
+        0xf9, 0x99, 0xde, 0xbf, 0xad, 0x84, 0x41, 0xe2, 0x69, 0xeb, 0x96, 0x0e, \
+        0x20, 0x1f, 0x61, 0xfc, 0x3d, 0xe2, 0x0d, 0x5a                          \
+}
+
+int psa_sign_verify_main(void)
+{
+    psa_status_t status;
+    psa_key_id_t key_id = 0;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    uint8_t signature[PSA_SIGNATURE_MAX_SIZE] = { 0 };
+    size_t signature_length;
+    const uint8_t key_bytes[] = KEY_BYTES_VALUE;
+    const uint8_t plaintext[] = PLAINTEXT_VALUE;
+    const uint8_t hash[] = HASH_VALUE;
+
+    status = psa_crypto_init();
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_crypto_init failed\n");
+        return EXIT_FAILURE;
+    }
+
+    psa_set_key_usage_flags(&attributes,
+                            PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH);
+    psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
+    psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
+
+    status = psa_import_key(&attributes, key_bytes, sizeof(key_bytes), &key_id);
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_import_key failed\n");
+        return EXIT_FAILURE;
+    }
+
+    status = psa_sign_hash(key_id,                          // key handle
+                           PSA_ALG_ECDSA(PSA_ALG_SHA_256),  // signature algorithm
+                           hash, sizeof(hash),              // hash of the message
+                           signature, sizeof(signature),    // signature (as output)
+                           &signature_length);              // length of signature output
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_sign_hash failed\n");
+        return EXIT_FAILURE;
+    }
+
+    mbedtls_printf("ECDSA-SHA256 signature of SHA-256('%s'):\n", plaintext);
+
+    for (size_t j = 0; j < signature_length; j++) {
+        if (j % 8 == 0) {
+            mbedtls_printf("\n    ");
+        }
+        mbedtls_printf("%02x ", signature[j]);
+    }
+
+    mbedtls_printf("\n");
+
+    status = psa_verify_hash(key_id,                          // key handle
+                             PSA_ALG_ECDSA(PSA_ALG_SHA_256),  // signature algorithm
+                             hash, sizeof(hash),              // hash of message
+                             signature, signature_length);    // signature
+    if (status != PSA_SUCCESS) {
+        mbedtls_printf("psa_verify_hash failed\n");
+        return EXIT_FAILURE;
+    } else {
+        mbedtls_printf("\nSignature verification successful!\n");
+    }
+
+    psa_destroy_key(key_id);
+    mbedtls_psa_crypto_free();
+    return EXIT_SUCCESS;
+}
diff -Nru mbedtls-3.6.5/framework/psasim/src/client.c mbedtls-3.6.6/framework/psasim/src/client.c
--- mbedtls-3.6.5/framework/psasim/src/client.c	2025-10-01 18:24:20.267015000 +0300
+++ mbedtls-3.6.6/framework/psasim/src/client.c	2026-03-27 12:34:57.775653600 +0200
@@ -1,380 +1,23 @@
-/* PSA firmware framework client API */
+/* psasim test client */
 
 /*
  *  Copyright The Mbed TLS Contributors
  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  */
 
-#include <stdint.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-#include <strings.h>
-#include <inttypes.h>
-#include <sys/types.h>
-#include <sys/ipc.h>
-#include <sys/msg.h>
-#include <psa/error.h>
+/* Includes from mbedtls */
+#include "psa/crypto.h"
+#include "util.h"
 
-#include "common.h"
-
-typedef struct internal_handle {
-    int server_qid;
-    int client_qid;
-    int internal_server_qid;
-    int valid;
-} internal_handle_t;
-
-/* Access to this global is not thread safe */
-#define MAX_HANDLES 32
-static internal_handle_t handles[MAX_HANDLES] = { { 0 } };
-
-static int get_next_free_handle()
-{
-    /* Never return handle 0 as it's a special null handle */
-    for (int i = 1; i < MAX_HANDLES; i++) {
-        if (handles[i].valid == 0) {
-            return i;
-        }
-    }
-    return -1;
-}
-
-static int handle_is_valid(psa_handle_t handle)
-{
-    if (handle > 0 && handle < MAX_HANDLES) {
-        if (handles[handle].valid == 1) {
-            return 1;
-        }
-    }
-    PROGRAMMER_ERROR("ERROR: Invalid handle");
-    return 0;
-}
-
-static int get_queue_info(char *path, int *cqid, int *sqid)
+int main()
 {
-
-    key_t server_queue_key;
-    int rx_qid, server_qid;
-
-    INFO("Attempting to contact a RoT service queue");
-
-    if ((rx_qid = msgget(IPC_PRIVATE, 0660)) == -1) {
-        INFO("msgget: rx_qid");
-        return -1;
-    }
-
-    if ((server_queue_key = ftok(path, PROJECT_ID)) == -1) {
-        INFO("ftok");
-        return -2;
-    }
-
-    if ((server_qid = msgget(server_queue_key, 0)) == -1) {
-        INFO("msgget: server_qid");
-        return -3;
+    /* psa_crypto_init() connects to the server */
+    psa_status_t status = psa_crypto_init();
+    if (status != PSA_SUCCESS) {
+        ERROR("psa_crypto_init returned %d", status);
+        return 1;
     }
 
-    *cqid = rx_qid;
-    *sqid = server_qid;
-
+    mbedtls_psa_crypto_free();
     return 0;
 }
-
-static psa_status_t process_response(int rx_qid, vectors_t *vecs, int type,
-                                     int *internal_server_qid)
-{
-
-    struct message response, request;
-    psa_status_t ret = PSA_ERROR_CONNECTION_REFUSED;
-    size_t invec_seek[4] = { 0 };
-    size_t data_size;
-    psa_status_t invec, outvec; /* TODO: Should these be size_t ? */
-
-    assert(internal_server_qid > 0);
-
-    while (1) {
-        data_size = 0;
-        invec = 0;
-        outvec = 0;
-
-        // read response from server
-        if (msgrcv(rx_qid, &response, sizeof(struct message_text), 0, 0) == -1) {
-            puts("   msgrcv failed");
-            return ret;
-        }
-
-        // process return message from server
-        switch (response.message_type) {
-            case PSA_REPLY:
-                memcpy(&ret, response.message_text.buf, sizeof(psa_status_t));
-                printf("   Message received from server: %d\n", ret);
-                if (type == PSA_IPC_CONNECT && ret > 0) {
-                    *internal_server_qid = ret;
-                    INFO("   ASSSIGNED q ID %d", *internal_server_qid);
-                    ret = PSA_SUCCESS;
-                }
-                return ret;
-                break;
-            case READ_REQUEST:
-                /* read data request */
-                request.message_type = READ_RESPONSE;
-
-                assert(vecs != 0);
-
-                memcpy(&invec, response.message_text.buf, sizeof(psa_status_t));
-                memcpy(&data_size, response.message_text.buf+sizeof(size_t), sizeof(size_t));
-                INFO("   Partition asked for %lu bytes from invec %d", data_size, invec);
-
-                /* need to add more checks here */
-                assert(invec >= 0 && invec < PSA_MAX_IOVEC);
-
-                if (data_size > MAX_FRAGMENT_SIZE) {
-                    data_size = MAX_FRAGMENT_SIZE;
-                }
-
-                /* send response */
-                INFO("   invec_seek[invec] is %lu", invec_seek[invec]);
-                INFO("   Reading from offset %p", vecs->in_vec[invec].base + invec_seek[invec]);
-                memcpy(request.message_text.buf,
-                       (vecs->in_vec[invec].base + invec_seek[invec]),
-                       data_size);
-
-                /* update invec base TODO: check me */
-                invec_seek[invec] = invec_seek[invec] + data_size;
-
-                INFO("   Sending message of type %li", request.message_type);
-                INFO("       with content %s\n", request.message_text.buf);
-
-                if (msgsnd(*internal_server_qid, &request,
-                           sizeof(int) + sizeof(uint32_t) + data_size, 0) == -1) {
-                    INFO("Internal error: failed to respond to read request");
-                }
-                break;
-            case WRITE_REQUEST:
-                assert(vecs != 0);
-
-                request.message_type = WRITE_RESPONSE;
-
-                memcpy(&outvec, response.message_text.buf, sizeof(psa_status_t));
-                memcpy(&data_size, response.message_text.buf + sizeof(size_t), sizeof(size_t));
-                INFO("   Partition wants to write %lu bytes to outvec %d", data_size, outvec);
-
-                assert(outvec >= 0 && outvec < PSA_MAX_IOVEC);
-
-                /* copy memory into message and send back amount written */
-                size_t sofar = vecs->out_vec[outvec].len;
-                memcpy(vecs->out_vec[outvec].base + sofar,
-                       response.message_text.buf+(sizeof(size_t)*2), data_size);
-                INFO("   Data size is %lu\n", data_size);
-                vecs->out_vec[outvec].len += data_size;
-
-                INFO("   Sending message of type %li\n", request.message_type);
-
-                /* send response */
-                if (msgsnd(*internal_server_qid, &request, sizeof(int) + data_size, 0) == -1) {
-                    INFO("Internal error: failed to respond to write request");
-                }
-                break;
-            case SKIP_REQUEST:
-                memcpy(&invec, response.message_text.buf, sizeof(psa_status_t));
-                memcpy(&data_size, response.message_text.buf+sizeof(size_t), sizeof(size_t));
-                INFO("   Partition asked to skip %lu bytes in invec %d", data_size, invec);
-                assert(invec >= 0 && invec < PSA_MAX_IOVEC);
-                /* update invec base TODO: check me */
-                invec_seek[invec] = invec_seek[invec] + data_size;
-                break;
-
-            default:
-                FATAL("   ERROR: unknown internal message type: %ld\n",
-                      response.message_type);
-                return ret;
-        }
-    }
-}
-
-static psa_status_t send(int rx_qid, int server_qid, int *internal_server_qid,
-                         int32_t type, uint32_t minor_version, vectors_t *vecs)
-{
-    {
-        psa_status_t ret = PSA_ERROR_CONNECTION_REFUSED;
-        size_t request_msg_size = (sizeof(int) + sizeof(long)); /* msg type plus queue id */
-        struct message request;
-        request.message_type = 1; /* TODO: change this */
-        request.message_text.psa_type = type;
-        vector_sizes_t vec_sizes;
-
-        /* If the client is non-secure then set the NS bit */
-        if (__psa_ff_client_security_state != 0) {
-            request.message_type |= NON_SECURE;
-        }
-
-        assert(request.message_type >= 0);
-
-        INFO("SEND: Sending message of type %ld with psa_type %d", request.message_type, type);
-        INFO("     internal_server_qid = %i", *internal_server_qid);
-
-        request.message_text.qid = rx_qid;
-
-        if (type == PSA_IPC_CONNECT) {
-            memcpy(request.message_text.buf, &minor_version, sizeof(minor_version));
-            request_msg_size = request_msg_size + sizeof(minor_version);
-            INFO("   Request msg size is %lu", request_msg_size);
-        } else {
-            assert(internal_server_qid > 0);
-        }
-
-        if (vecs != NULL && type >= PSA_IPC_CALL) {
-
-            bzero(&vec_sizes, sizeof(vec_sizes));
-
-            /* Copy invec sizes */
-            for (size_t i = 0; i < (vecs->in_len); i++) {
-                vec_sizes.invec_sizes[i] = vecs->in_vec[i].len;
-                INFO("   Client sending vector %lu: %lu", i, vec_sizes.invec_sizes[i]);
-            }
-
-            /* Copy outvec sizes */
-            for (size_t i = 0; i < (vecs->out_len); i++) {
-                vec_sizes.outvec_sizes[i] = vecs->out_vec[i].len;
-
-                /* Reset to 0 since we need to eventually fill in with bytes written */
-                vecs->out_vec[i].len = 0;
-            }
-
-            memcpy(request.message_text.buf, &vec_sizes, sizeof(vec_sizes));
-            request_msg_size = request_msg_size + sizeof(vec_sizes);
-        }
-
-        INFO("   Sending and then waiting");
-
-        // send message to server
-        if (msgsnd(server_qid, &request, request_msg_size, 0) == -1) {
-            puts("   msgsnd failed");
-            return ret;
-        }
-
-        return process_response(rx_qid, vecs, type, internal_server_qid);
-    }
-}
-
-
-uint32_t psa_framework_version(void)
-{
-    return PSA_FRAMEWORK_VERSION;
-}
-
-psa_handle_t psa_connect(uint32_t sid, uint32_t minor_version)
-{
-
-    int idx;
-    psa_status_t ret;
-    char pathname[PATHNAMESIZE] = { 0 };
-
-    idx = get_next_free_handle();
-
-    /* if there's a free handle available */
-    if (idx >= 0) {
-        snprintf(pathname, PATHNAMESIZE - 1, "/tmp/psa_service_%u", sid);
-        INFO("Attempting to contact RoT service at %s", pathname);
-
-        /* if communication is possible */
-        if (get_queue_info(pathname, &handles[idx].client_qid, &handles[idx].server_qid) >= 0) {
-
-            ret = send(handles[idx].client_qid,
-                       handles[idx].server_qid,
-                       &handles[idx].internal_server_qid,
-                       PSA_IPC_CONNECT,
-                       minor_version,
-                       NULL);
-
-            /* if connection accepted by RoT service */
-            if (ret >= 0) {
-                handles[idx].valid = 1;
-                return idx;
-            } else {
-                INFO("Server didn't like you");
-            }
-        } else {
-            INFO("Couldn't contact RoT service. Does it exist?");
-
-            if (__psa_ff_client_security_state == 0) {
-                PROGRAMMER_ERROR("Invalid SID");
-            }
-        }
-    }
-
-    INFO("Couldn't obtain a free handle");
-    return PSA_ERROR_CONNECTION_REFUSED;
-}
-
-uint32_t psa_version(uint32_t sid)
-{
-    int idx;
-    psa_status_t ret;
-    char pathname[PATHNAMESIZE] = { 0 };
-
-    idx = get_next_free_handle();
-
-    if (idx >= 0) {
-        snprintf(pathname, PATHNAMESIZE, "/tmp/psa_service_%u", sid);
-        if (get_queue_info(pathname, &handles[idx].client_qid, &handles[idx].server_qid) >= 0) {
-            ret = send(handles[idx].client_qid,
-                       handles[idx].server_qid,
-                       &handles[idx].internal_server_qid,
-                       VERSION_REQUEST,
-                       0,
-                       NULL);
-            INFO("psa_version: Recieved from server %d\n", ret);
-            if (ret > 0) {
-                return ret;
-            }
-        }
-    }
-    INFO("psa_version failed: does the service exist?");
-    return PSA_VERSION_NONE;
-}
-
-psa_status_t psa_call(psa_handle_t handle,
-                      int32_t type,
-                      const psa_invec *in_vec,
-                      size_t in_len,
-                      psa_outvec *out_vec,
-                      size_t out_len)
-{
-
-    handle_is_valid(handle);
-
-    if ((in_len + out_len) > PSA_MAX_IOVEC) {
-        PROGRAMMER_ERROR("Too many iovecs: %lu + %lu", in_len, out_len);
-    }
-
-    vectors_t vecs = { 0 };
-    vecs.in_vec = in_vec;
-    vecs.in_len = in_len;
-    vecs.out_vec = out_vec;
-    vecs.out_len = out_len;
-
-    return send(handles[handle].client_qid,
-                handles[handle].server_qid,
-                &handles[handle].internal_server_qid,
-                type,
-                0,
-                &vecs);
-}
-
-void psa_close(psa_handle_t handle)
-{
-    handle_is_valid(handle);
-    if (send(handles[handle].client_qid, handles[handle].server_qid,
-             &handles[handle].internal_server_qid, PSA_IPC_DISCONNECT, 0, NULL)) {
-        puts("ERROR: Couldn't send disconnect msg");
-    } else {
-        if (msgctl(handles[handle].client_qid, IPC_RMID, NULL) != 0) {
-            puts("ERROR: Failed to delete msg queue");
-        }
-    }
-    INFO("Closing handle %u", handle);
-    handles[handle].valid = 0;
-}
diff -Nru mbedtls-3.6.5/framework/psasim/src/common.c mbedtls-3.6.6/framework/psasim/src/common.c
--- mbedtls-3.6.5/framework/psasim/src/common.c	2025-10-01 18:24:20.267105300 +0300
+++ mbedtls-3.6.6/framework/psasim/src/common.c	1970-01-01 02:00:00.000000000 +0200
@@ -1,23 +0,0 @@
-/* Common code between clients and services */
-
-/*
- *  Copyright The Mbed TLS Contributors
- *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
- */
-
-#include "common.h"
-int __psa_ff_client_security_state = NON_SECURE;
-
-#if 0
-static void _printbits(uint32_t num)
-{
-    for (int i = 0; i < 32; i++) {
-        if ((num >> (31-i) & 0x1)) {
-            INFO("1");
-        } else {
-            INFO("0");
-        }
-    }
-    INFO("\n");
-}
-#endif
diff -Nru mbedtls-3.6.5/framework/psasim/src/common.h mbedtls-3.6.6/framework/psasim/src/common.h
--- mbedtls-3.6.5/framework/psasim/src/common.h	2025-10-01 18:24:20.267255000 +0300
+++ mbedtls-3.6.6/framework/psasim/src/common.h	1970-01-01 02:00:00.000000000 +0200
@@ -1,85 +0,0 @@
-/* Common definitions used for clients and services */
-
-/*
- *  Copyright The Mbed TLS Contributors
- *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
- */
-
-#include <psa/service.h>
-
-#ifdef DEBUG
-#define DEBUG_TEST 1
-#else
-#define DEBUG_TEST 0
-#endif
-
-#define PRINT(...) \
-    do { if (DEBUG_TEST) fprintf(stderr, __VA_ARGS__); } while (0)
-#define INFO(...) \
-    do { if (DEBUG_TEST) { PRINT("%s", __FILE__); PRINT(" INFO: " __VA_ARGS__); printf("\n"); \
-         } } while (0)
-
-#define PROGRAMMER_ERROR(...) \
-    do { if (DEBUG_TEST) { PRINT("%s:%d:%s(): PROGRAMMER ERROR", __FILE__, __LINE__, __func__); \
-                           PRINT(__VA_ARGS__); } abort(); } while (0)
-
-#define FATAL(...) \
-    do { if (DEBUG_TEST) { PRINT("%s:%d:%s(): INTERNAL ERROR", __FILE__, __LINE__, __func__); PRINT( \
-                               __VA_ARGS__); } abort(); } while (0)
-
-
-#define PROJECT_ID 'M'
-#define PATHNAMESIZE 64
-
-/* Increasing this might break on some platforms */
-#define MAX_FRAGMENT_SIZE 200
-
-#define CONNECT_REQUEST 1
-#define CALL_REQUEST 2
-#define CLOSE_REQUEST 3
-#define VERSION_REQUEST 4
-#define READ_REQUEST    5
-#define READ_RESPONSE   6
-#define WRITE_REQUEST   7
-#define WRITE_RESPONSE  8
-#define SKIP_REQUEST    9
-#define PSA_REPLY       10
-
-#define NON_SECURE (1 << 30)
-
-/* Note that this implementation is functional and not secure */
-extern int __psa_ff_client_security_state;
-
-struct message_text {
-    int qid;
-    int32_t psa_type;
-    char buf[MAX_FRAGMENT_SIZE];
-};
-
-
-struct message {
-    long message_type;
-    struct message_text message_text;
-};
-
-struct request_msg_internal {
-    psa_invec invec;
-    size_t skip_num;
-};
-
-struct skip_request_msg {
-    long message_type;
-    struct request_msg_internal message_text;
-};
-
-typedef struct vectors {
-    const psa_invec *in_vec;
-    size_t in_len;
-    psa_outvec *out_vec;
-    size_t out_len;
-} vectors_t;
-
-typedef struct vector_sizes {
-    size_t invec_sizes[PSA_MAX_IOVEC];
-    size_t outvec_sizes[PSA_MAX_IOVEC];
-} vector_sizes_t;
diff -Nru mbedtls-3.6.5/framework/psasim/src/manifest.json mbedtls-3.6.6/framework/psasim/src/manifest.json
--- mbedtls-3.6.5/framework/psasim/src/manifest.json	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/src/manifest.json	2026-03-27 12:34:57.775749400 +0200
@@ -0,0 +1,29 @@
+{
+   "psa_framework_version":1.0,
+   "name":"TEST_PARTITION",
+   "type":"PSA-ROT",
+   "priority":"LOW",
+   "entry_point":"psa_server_main",
+   "stack_size":"0x400",
+   "heap_size":"0x100",
+   "services":[
+      {
+         "name":"PSA_SID_CRYPTO",
+         "sid":"0x0000F000",
+         "signal":"PSA_CRYPTO",
+         "non_secure_clients": "true",
+         "minor_version":1,
+         "minor_policy":"STRICT"
+      }
+   ],
+   "irqs": [
+        {
+                "source": "SIGINT",
+                "signal": "SIGINT_SIG"
+        },
+        {
+                "source": "SIGTSTP",
+                "signal": "SIGSTP_SIG"
+        }
+   ]
+}
diff -Nru mbedtls-3.6.5/framework/psasim/src/psa_ff_client.c mbedtls-3.6.6/framework/psasim/src/psa_ff_client.c
--- mbedtls-3.6.5/framework/psasim/src/psa_ff_client.c	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/src/psa_ff_client.c	2026-03-27 12:34:57.775901000 +0200
@@ -0,0 +1,385 @@
+/* PSA firmware framework client API */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+
+#include "client.h"
+#include "common.h"
+#include "error_ext.h"
+#include "util.h"
+
+typedef struct internal_handle {
+    int server_qid;
+    int client_qid;
+    int internal_server_qid;
+    int valid;
+} internal_handle_t;
+
+typedef struct vectors {
+    const psa_invec *in_vec;
+    size_t in_len;
+    psa_outvec *out_vec;
+    size_t out_len;
+} vectors_t;
+
+/* Note that this implementation is functional and not secure */
+int __psa_ff_client_security_state = NON_SECURE;
+
+/* Access to this global is not thread safe */
+#define MAX_HANDLES 32
+static internal_handle_t handles[MAX_HANDLES] = { { 0 } };
+
+static int get_next_free_handle()
+{
+    /* Never return handle 0 as it's a special null handle */
+    for (int i = 1; i < MAX_HANDLES; i++) {
+        if (handles[i].valid == 0) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+static int handle_is_valid(psa_handle_t handle)
+{
+    if (handle > 0 && handle < MAX_HANDLES) {
+        if (handles[handle].valid == 1) {
+            return 1;
+        }
+    }
+    ERROR("ERROR: Invalid handle");
+    return 0;
+}
+
+static int get_queue_info(char *path, int *cqid, int *sqid)
+{
+    key_t server_queue_key;
+    int rx_qid, server_qid;
+
+    INFO("Attempting to contact a RoT service queue");
+
+    if ((rx_qid = msgget(IPC_PRIVATE, 0660)) == -1) {
+        ERROR("msgget: rx_qid");
+        return -1;
+    }
+
+    if ((server_queue_key = ftok(path, PROJECT_ID)) == -1) {
+        ERROR("ftok");
+        return -2;
+    }
+
+    if ((server_qid = msgget(server_queue_key, 0)) == -1) {
+        ERROR("msgget: server_qid");
+        return -3;
+    }
+
+    *cqid = rx_qid;
+    *sqid = server_qid;
+
+    return 0;
+}
+
+static psa_status_t process_response(int rx_qid, vectors_t *vecs, int type,
+                                     int *internal_server_qid)
+{
+    struct message response, request;
+    psa_status_t ret = PSA_ERROR_CONNECTION_REFUSED;
+    size_t invec_seek[4] = { 0 };
+    size_t data_size;
+    psa_status_t invec, outvec; /* TODO: Should these be size_t ? */
+
+    assert(internal_server_qid > 0);
+
+    while (1) {
+        data_size = 0;
+        invec = 0;
+        outvec = 0;
+
+        /* read response from server */
+        if (msgrcv(rx_qid, &response, sizeof(struct message_text), 0, 0) == -1) {
+            ERROR("   msgrcv failed");
+            return ret;
+        }
+
+        /* process return message from server */
+        switch (response.message_type) {
+            case PSA_REPLY:
+                memcpy(&ret, response.message_text.buf, sizeof(psa_status_t));
+                INFO("   Message received from server: %d", ret);
+                if (type == PSA_IPC_CONNECT && ret > 0) {
+                    *internal_server_qid = ret;
+                    INFO("   ASSSIGNED q ID %d", *internal_server_qid);
+                    ret = PSA_SUCCESS;
+                }
+                return ret;
+                break;
+            case READ_REQUEST:
+                /* read data request */
+                request.message_type = READ_RESPONSE;
+
+                assert(vecs != 0);
+
+                memcpy(&invec, response.message_text.buf, sizeof(psa_status_t));
+                memcpy(&data_size, response.message_text.buf+sizeof(size_t), sizeof(size_t));
+                INFO("   Partition asked for %lu bytes from invec %d", data_size, invec);
+
+                /* need to add more checks here */
+                assert(invec >= 0 && invec < PSA_MAX_IOVEC);
+
+                if (data_size > MAX_FRAGMENT_SIZE) {
+                    data_size = MAX_FRAGMENT_SIZE;
+                }
+
+                /* send response */
+                INFO("   invec_seek[invec] is %lu", invec_seek[invec]);
+                INFO("   Reading from offset %p", vecs->in_vec[invec].base + invec_seek[invec]);
+                memcpy(request.message_text.buf,
+                       (vecs->in_vec[invec].base + invec_seek[invec]),
+                       data_size);
+
+                /* update invec base TODO: check me */
+                invec_seek[invec] = invec_seek[invec] + data_size;
+
+                INFO("   Sending message of type %li", request.message_type);
+                INFO("       with content %s", request.message_text.buf);
+
+                if (msgsnd(*internal_server_qid, &request,
+                           sizeof(int) + sizeof(uint32_t) + data_size, 0) == -1) {
+                    ERROR("Internal error: failed to respond to read request");
+                }
+                break;
+            case WRITE_REQUEST:
+                assert(vecs != 0);
+
+                request.message_type = WRITE_RESPONSE;
+
+                memcpy(&outvec, response.message_text.buf, sizeof(psa_status_t));
+                memcpy(&data_size, response.message_text.buf + sizeof(size_t), sizeof(size_t));
+                INFO("   Partition wants to write %lu bytes to outvec %d", data_size, outvec);
+
+                assert(outvec >= 0 && outvec < PSA_MAX_IOVEC);
+
+                /* copy memory into message and send back amount written */
+                size_t sofar = vecs->out_vec[outvec].len;
+                memcpy(vecs->out_vec[outvec].base + sofar,
+                       response.message_text.buf+(sizeof(size_t)*2), data_size);
+                INFO("   Data size is %lu", data_size);
+                vecs->out_vec[outvec].len += data_size;
+
+                INFO("   Sending message of type %li", request.message_type);
+
+                /* send response */
+                if (msgsnd(*internal_server_qid, &request, sizeof(int) + data_size, 0) == -1) {
+                    ERROR("Internal error: failed to respond to write request");
+                }
+                break;
+            case SKIP_REQUEST:
+                memcpy(&invec, response.message_text.buf, sizeof(psa_status_t));
+                memcpy(&data_size, response.message_text.buf+sizeof(size_t), sizeof(size_t));
+                INFO("   Partition asked to skip %lu bytes in invec %d", data_size, invec);
+                assert(invec >= 0 && invec < PSA_MAX_IOVEC);
+                /* update invec base TODO: check me */
+                invec_seek[invec] = invec_seek[invec] + data_size;
+                break;
+
+            default:
+                FATAL("   ERROR: unknown internal message type: %ld",
+                      response.message_type);
+        }
+    }
+}
+
+static psa_status_t send(int rx_qid, int server_qid, int *internal_server_qid,
+                         int32_t type, uint32_t minor_version, vectors_t *vecs)
+{
+    psa_status_t ret = PSA_ERROR_CONNECTION_REFUSED;
+    size_t request_msg_size = (sizeof(int) + sizeof(long)); /* msg type plus queue id */
+    struct message request;
+    request.message_type = 1; /* TODO: change this */
+    request.message_text.psa_type = type;
+    vector_sizes_t vec_sizes;
+
+    /* If the client is non-secure then set the NS bit */
+    if (__psa_ff_client_security_state != 0) {
+        request.message_type |= NON_SECURE;
+    }
+
+    assert(request.message_type >= 0);
+
+    INFO("SEND: Sending message of type %ld with psa_type %d", request.message_type, type);
+    INFO("     internal_server_qid = %i", *internal_server_qid);
+
+    request.message_text.qid = rx_qid;
+
+    if (type == PSA_IPC_CONNECT) {
+        memcpy(request.message_text.buf, &minor_version, sizeof(minor_version));
+        request_msg_size = request_msg_size + sizeof(minor_version);
+        INFO("   Request msg size is %lu", request_msg_size);
+    } else {
+        assert(internal_server_qid > 0);
+    }
+
+    if (vecs != NULL && type >= PSA_IPC_CALL) {
+
+        memset(&vec_sizes, 0, sizeof(vec_sizes));
+
+        /* Copy invec sizes */
+        for (size_t i = 0; i < (vecs->in_len); i++) {
+            vec_sizes.invec_sizes[i] = vecs->in_vec[i].len;
+            INFO("   Client sending vector %lu: %lu", i, vec_sizes.invec_sizes[i]);
+        }
+
+        /* Copy outvec sizes */
+        for (size_t i = 0; i < (vecs->out_len); i++) {
+            vec_sizes.outvec_sizes[i] = vecs->out_vec[i].len;
+
+            /* Reset to 0 since we need to eventually fill in with bytes written */
+            vecs->out_vec[i].len = 0;
+        }
+
+        memcpy(request.message_text.buf, &vec_sizes, sizeof(vec_sizes));
+        request_msg_size = request_msg_size + sizeof(vec_sizes);
+    }
+
+    INFO("   Sending and then waiting");
+
+    /* send message to server */
+    if (msgsnd(server_qid, &request, request_msg_size, 0) == -1) {
+        ERROR("   msgsnd failed");
+        return ret;
+    }
+
+    return process_response(rx_qid, vecs, type, internal_server_qid);
+}
+
+
+uint32_t psa_framework_version(void)
+{
+    return PSA_FRAMEWORK_VERSION;
+}
+
+psa_handle_t psa_connect(uint32_t sid, uint32_t minor_version)
+{
+    int idx;
+    psa_status_t ret;
+    char pathname[PATHNAMESIZE] = { 0 };
+
+    idx = get_next_free_handle();
+
+    /* if there's a free handle available */
+    if (idx >= 0) {
+        snprintf(pathname, PATHNAMESIZE - 1, TMP_FILE_BASE_PATH "psa_service_%u", sid);
+        INFO("Attempting to contact RoT service at %s", pathname);
+
+        /* if communication is possible */
+        if (get_queue_info(pathname, &handles[idx].client_qid, &handles[idx].server_qid) >= 0) {
+
+            ret = send(handles[idx].client_qid,
+                       handles[idx].server_qid,
+                       &handles[idx].internal_server_qid,
+                       PSA_IPC_CONNECT,
+                       minor_version,
+                       NULL);
+
+            /* if connection accepted by RoT service */
+            if (ret >= 0) {
+                handles[idx].valid = 1;
+                return idx;
+            } else {
+                ERROR("Server didn't like you");
+            }
+        } else {
+            ERROR("Couldn't contact RoT service. Does it exist?");
+
+            if (__psa_ff_client_security_state == 0) {
+                ERROR("Invalid SID");
+            }
+        }
+    }
+
+    INFO("Couldn't obtain a free handle");
+    return PSA_ERROR_CONNECTION_REFUSED;
+}
+
+uint32_t psa_version(uint32_t sid)
+{
+    int idx;
+    psa_status_t ret;
+    char pathname[PATHNAMESIZE] = { 0 };
+
+    idx = get_next_free_handle();
+
+    if (idx >= 0) {
+        snprintf(pathname, PATHNAMESIZE, TMP_FILE_BASE_PATH "psa_service_%u", sid);
+        if (get_queue_info(pathname, &handles[idx].client_qid, &handles[idx].server_qid) >= 0) {
+            ret = send(handles[idx].client_qid,
+                       handles[idx].server_qid,
+                       &handles[idx].internal_server_qid,
+                       VERSION_REQUEST,
+                       0,
+                       NULL);
+            INFO("psa_version: Recieved from server %d", ret);
+            if (ret > 0) {
+                return ret;
+            }
+        }
+    }
+    ERROR("psa_version failed: does the service exist?");
+    return PSA_VERSION_NONE;
+}
+
+psa_status_t psa_call(psa_handle_t handle,
+                      int32_t type,
+                      const psa_invec *in_vec,
+                      size_t in_len,
+                      psa_outvec *out_vec,
+                      size_t out_len)
+{
+    handle_is_valid(handle);
+
+    if ((in_len + out_len) > PSA_MAX_IOVEC) {
+        ERROR("Too many iovecs: %lu + %lu", in_len, out_len);
+    }
+
+    vectors_t vecs = { 0 };
+    vecs.in_vec = in_vec;
+    vecs.in_len = in_len;
+    vecs.out_vec = out_vec;
+    vecs.out_len = out_len;
+
+    return send(handles[handle].client_qid,
+                handles[handle].server_qid,
+                &handles[handle].internal_server_qid,
+                type,
+                0,
+                &vecs);
+}
+
+void psa_close(psa_handle_t handle)
+{
+    handle_is_valid(handle);
+    if (send(handles[handle].client_qid, handles[handle].server_qid,
+             &handles[handle].internal_server_qid, PSA_IPC_DISCONNECT, 0, NULL)) {
+        ERROR("ERROR: Couldn't send disconnect msg");
+    } else {
+        if (msgctl(handles[handle].client_qid, IPC_RMID, NULL) != 0) {
+            ERROR("ERROR: Failed to delete msg queue");
+        }
+    }
+    INFO("Closing handle %u", handle);
+    handles[handle].valid = 0;
+}
diff -Nru mbedtls-3.6.5/framework/psasim/src/psa_ff_server.c mbedtls-3.6.6/framework/psasim/src/psa_ff_server.c
--- mbedtls-3.6.5/framework/psasim/src/psa_ff_server.c	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/src/psa_ff_server.c	2026-03-27 12:34:57.776016700 +0200
@@ -0,0 +1,655 @@
+/* PSA Firmware Framework service API */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <time.h>
+#include <assert.h>
+
+#include "service.h"
+#include "init.h"
+#include "error_ext.h"
+#include "common.h"
+#include "util.h"
+
+#define MAX_CLIENTS 128
+#define MAX_MESSAGES 32
+
+struct connection {
+    uint32_t client;
+    void *rhandle;
+    int client_to_server_q;
+};
+
+/* Note that this implementation is functional and not secure. */
+int __psa_ff_client_security_state = NON_SECURE;
+
+static psa_msg_t messages[MAX_MESSAGES]; /* Message slots */
+static uint8_t pending_message[MAX_MESSAGES] = { 0 }; /* Booleans indicating active message slots */
+static uint32_t message_client[MAX_MESSAGES] = { 0 }; /* Each client's response queue  */
+static int nsacl[32];
+static int strict_policy[32] = { 0 };
+static uint32_t rot_svc_versions[32];
+static int rot_svc_incoming_queue[32] = { -1 };
+static struct connection connections[MAX_CLIENTS] = { { 0 } };
+
+static uint32_t exposed_signals = 0;
+
+void print_vectors(vector_sizes_t *sizes)
+{
+    INFO("Printing iovec sizes");
+    for (int j = 0; j < PSA_MAX_IOVEC; j++) {
+        INFO("Invec  %d: %lu", j, sizes->invec_sizes[j]);
+    }
+
+    for (int j = 0; j < PSA_MAX_IOVEC; j++) {
+        INFO("Outvec %d: %lu", j, sizes->outvec_sizes[j]);
+    }
+}
+
+int find_connection(uint32_t client)
+{
+    for (int i = 1; i < MAX_CLIENTS; i++) {
+        if (client == connections[i].client) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+void destroy_connection(uint32_t client)
+{
+    int idx = find_connection(client);
+    if (idx >= 0) {
+        connections[idx].client = 0;
+        connections[idx].rhandle = 0;
+        INFO("Destroying connection");
+    } else {
+        ERROR("Couldn't destroy connection for %u", client);
+    }
+}
+
+int find_free_connection()
+{
+    INFO("Allocating connection");
+    return find_connection(0);
+}
+
+static void reply(psa_handle_t msg_handle, psa_status_t status)
+{
+    pending_message[msg_handle] = 1;
+    psa_reply(msg_handle, status);
+    pending_message[msg_handle] = 0;
+}
+
+psa_signal_t psa_wait(psa_signal_t signal_mask, uint32_t timeout)
+{
+    psa_signal_t mask;
+    struct message msg;
+    vector_sizes_t sizes;
+    struct msqid_ds qinfo;
+    uint32_t requested_version;
+    ssize_t len;
+    int idx;
+
+    if (timeout == PSA_POLL) {
+        INFO("psa_wait: Called in polling mode");
+    }
+
+    do {
+        mask = signal_mask;
+
+        /* Check the status of each queue */
+        for (int i = 0; i < 32; i++) {
+            if (mask & 0x1) {
+                if (i < 3) {
+                    // do nothing (reserved)
+                } else if (i == 3) {
+                    // this must be psa doorbell
+                } else {
+                    /* Check if this signal corresponds to a queue */
+                    if (rot_svc_incoming_queue[i] >= 0 && (pending_message[i] == 0)) {
+
+                        /* AFAIK there is no "peek" method in SysV, so try to get a message */
+                        len = msgrcv(rot_svc_incoming_queue[i],
+                                     &msg,
+                                     sizeof(struct message_text),
+                                     0,
+                                     IPC_NOWAIT);
+                        if (len > 0) {
+
+                            INFO("Storing that QID in message_client[%d]", i);
+                            INFO("The message handle will be %d", i);
+
+                            msgctl(rot_svc_incoming_queue[i], IPC_STAT, &qinfo);
+                            messages[i].client_id = qinfo.msg_lspid; /* PID of last msgsnd(2) call */
+                            message_client[i] = msg.message_text.qid;
+                            idx = find_connection(msg.message_text.qid);
+
+                            if (msg.message_type & NON_SECURE) {
+                                /* This is a non-secure message */
+
+                                /* Check if NS client is allowed for this RoT service */
+                                if (nsacl[i] <= 0) {
+#if 0
+                                    INFO(
+                                        "Rejecting non-secure client due to manifest security policy");
+                                    reply(i, PSA_ERROR_CONNECTION_REFUSED);
+                                    continue; /* Skip to next signal */
+#endif
+                                }
+
+                                msg.message_type &= ~(NON_SECURE); /* clear */
+                                messages[i].client_id = messages[i].client_id * -1;
+                            }
+
+                            INFO("Got a message from client ID %d", messages[i].client_id);
+                            INFO("Message type is %lu", msg.message_type);
+                            INFO("PSA message type is %d", msg.message_text.psa_type);
+
+                            messages[i].handle = i;
+
+                            switch (msg.message_text.psa_type) {
+                                case PSA_IPC_CONNECT:
+
+                                    if (len >= 16) {
+                                        memcpy(&requested_version, msg.message_text.buf,
+                                               sizeof(requested_version));
+                                        INFO("Requesting version %u", requested_version);
+                                        INFO("Implemented version %u", rot_svc_versions[i]);
+                                        /* TODO: need to check whether the policy is strict,
+                                         * and if so, then reject the client if the number doesn't match */
+
+                                        if (requested_version > rot_svc_versions[i]) {
+                                            INFO(
+                                                "Rejecting client because requested version that was too high");
+                                            reply(i, PSA_ERROR_CONNECTION_REFUSED);
+                                            continue; /* Skip to next signal */
+                                        }
+
+                                        if (strict_policy[i] == 1 &&
+                                            (requested_version != rot_svc_versions[i])) {
+                                            INFO(
+                                                "Rejecting client because enforcing a STRICT version policy");
+                                            reply(i, PSA_ERROR_CONNECTION_REFUSED);
+                                            continue; /* Skip to next signal */
+                                        } else {
+                                            INFO("Not rejecting client");
+                                        }
+                                    }
+
+                                    messages[i].type = PSA_IPC_CONNECT;
+
+                                    if (idx < 0) {
+                                        idx = find_free_connection();
+                                    }
+
+                                    if (idx >= 0) {
+                                        connections[idx].client = msg.message_text.qid;
+                                    } else {
+                                        /* We've run out of system wide connections */
+                                        reply(i, PSA_ERROR_CONNECTION_BUSY);
+                                        ERROR("Ran out of free connections");
+                                        continue;
+                                    }
+
+                                    break;
+                                case PSA_IPC_DISCONNECT:
+                                    messages[i].type = PSA_IPC_DISCONNECT;
+                                    break;
+                                case VERSION_REQUEST:
+                                    INFO("Got a version request");
+                                    reply(i, rot_svc_versions[i]);
+                                    continue; /* Skip to next signal */
+                                    break;
+
+                                default:
+
+                                    /* PSA CALL */
+                                    if (msg.message_text.psa_type >= 0) {
+                                        messages[i].type = msg.message_text.psa_type;
+                                        memcpy(&sizes, msg.message_text.buf, sizeof(sizes));
+                                        print_vectors(&sizes);
+                                        memcpy(&messages[i].in_size, &sizes.invec_sizes,
+                                               (sizeof(size_t) * PSA_MAX_IOVEC));
+                                        memcpy(&messages[i].out_size, &sizes.outvec_sizes,
+                                               (sizeof(size_t) * PSA_MAX_IOVEC));
+                                    } else {
+                                        FATAL("UNKNOWN MESSAGE TYPE RECEIVED %li",
+                                              msg.message_type);
+                                    }
+                                    break;
+                            }
+                            messages[i].handle = i;
+
+                            /* Check if the client has a connection */
+                            if (idx >= 0) {
+                                messages[i].rhandle = connections[idx].rhandle;
+                            } else {
+                                /* Client is begging for a programmer error */
+                                reply(i, PSA_ERROR_PROGRAMMER_ERROR);
+                                continue;
+                            }
+
+                            /* House keeping */
+                            pending_message[i] = 1; /* set message as pending */
+                            exposed_signals |= (0x1 << i); /* assert the signal */
+                        }
+                    }
+                }
+                mask = mask >> 1;
+            }
+        }
+
+        if ((timeout == PSA_BLOCK) && (exposed_signals > 0)) {
+            break;
+        } else {
+            /* There is no 'select' function in SysV to block on multiple queues, so busy-wait :( */
+        }
+    } while (timeout == PSA_BLOCK);
+
+    /* Assert signals */
+    return signal_mask & exposed_signals;
+}
+
+static int signal_to_index(psa_signal_t signal)
+{
+    int i;
+    int count = 0;
+    int ret = -1;
+
+    for (i = 0; i < 32; i++) {
+        if (signal & 0x1) {
+            ret = i;
+            count++;
+        }
+        signal = signal >> 1;
+    }
+
+    if (count > 1) {
+        ERROR("ERROR: Too many signals");
+        return -1; /* Too many signals */
+    }
+    return ret;
+}
+
+static void clear_signal(psa_signal_t signal)
+{
+    exposed_signals = exposed_signals & ~signal;
+}
+
+void raise_signal(psa_signal_t signal)
+{
+    exposed_signals |= signal;
+}
+
+psa_status_t psa_get(psa_signal_t signal, psa_msg_t *msg)
+{
+    int index = signal_to_index(signal);
+    if (index < 0) {
+        ERROR("Bad signal");
+    }
+
+    clear_signal(signal);
+
+    assert(messages[index].handle != 0);
+
+    if (pending_message[index] == 1) {
+        INFO("There is a pending message!");
+        memcpy(msg, &messages[index], sizeof(struct psa_msg_t));
+        assert(msg->handle != 0);
+        return PSA_SUCCESS;
+    } else {
+        INFO("no pending message");
+    }
+
+    return PSA_ERROR_DOES_NOT_EXIST;
+}
+
+static inline int is_valid_msg_handle(psa_handle_t h)
+{
+    if (h > 0 && h < MAX_MESSAGES) {
+        return 1;
+    }
+    ERROR("Not a valid message handle");
+    return 0;
+}
+
+static inline int is_call_msg(psa_handle_t h)
+{
+    assert(messages[h].type >= PSA_IPC_CALL);
+    return 1;
+}
+
+void psa_set_rhandle(psa_handle_t msg_handle, void *rhandle)
+{
+    is_valid_msg_handle(msg_handle);
+    int idx = find_connection(message_client[msg_handle]);
+    INFO("Setting rhandle to %p", rhandle);
+    assert(idx >= 0);
+    connections[idx].rhandle = rhandle;
+}
+
+/* Sends a message from the server to the client. Does not wait for a response */
+static void send_msg(psa_handle_t msg_handle,
+                     int ctrl_msg,
+                     psa_status_t status,
+                     size_t amount,
+                     const void *data,
+                     size_t data_amount)
+{
+    struct message response;
+    int flags = 0;
+
+    assert(ctrl_msg > 0); /* According to System V, it must be greater than 0 */
+
+    response.message_type = ctrl_msg;
+    if (ctrl_msg == PSA_REPLY) {
+        memcpy(response.message_text.buf, &status, sizeof(psa_status_t));
+    } else if (ctrl_msg == READ_REQUEST || ctrl_msg == WRITE_REQUEST || ctrl_msg == SKIP_REQUEST) {
+        memcpy(response.message_text.buf, &status, sizeof(psa_status_t));
+        memcpy(response.message_text.buf+sizeof(size_t), &amount, sizeof(size_t));
+        if (ctrl_msg == WRITE_REQUEST) {
+            /* TODO: Check if too big */
+            memcpy(response.message_text.buf + (sizeof(size_t) * 2), data, data_amount);
+        }
+    }
+
+    /* TODO: sizeof doesn't need to be so big here for small responses */
+    if (msgsnd(message_client[msg_handle], &response, sizeof(response.message_text), flags) == -1) {
+        ERROR("Failed to reply");
+    }
+}
+
+static size_t skip(psa_handle_t msg_handle, uint32_t invec_idx, size_t num_bytes)
+{
+    if (num_bytes < (messages[msg_handle].in_size[invec_idx] - num_bytes)) {
+        messages[msg_handle].in_size[invec_idx] = messages[msg_handle].in_size[invec_idx] -
+                                                  num_bytes;
+        return num_bytes;
+    } else {
+        if (num_bytes >= messages[msg_handle].in_size[invec_idx]) {
+            size_t ret = messages[msg_handle].in_size[invec_idx];
+            messages[msg_handle].in_size[invec_idx] = 0;
+            return ret;
+        } else {
+            return num_bytes;
+        }
+    }
+}
+
+size_t psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
+                void *buffer, size_t num_bytes)
+{
+    size_t sofar = 0;
+    struct message msg = { 0 };
+    int idx;
+    ssize_t len;
+
+    is_valid_msg_handle(msg_handle);
+    is_call_msg(msg_handle);
+
+    if (invec_idx >= PSA_MAX_IOVEC) {
+        ERROR("Invalid iovec number");
+    }
+
+    /* If user wants more data than what's available, truncate their request */
+    if (num_bytes > messages[msg_handle].in_size[invec_idx]) {
+        num_bytes = messages[msg_handle].in_size[invec_idx];
+    }
+
+    while (sofar < num_bytes) {
+        INFO("Server: requesting %lu bytes from client", (num_bytes - sofar));
+        send_msg(msg_handle, READ_REQUEST, invec_idx, (num_bytes - sofar), NULL, 0);
+
+        idx = find_connection(message_client[msg_handle]);
+        assert(idx >= 0);
+
+        len = msgrcv(connections[idx].client_to_server_q, &msg, sizeof(struct message_text), 0, 0);
+        len = (len - offsetof(struct message_text, buf));
+
+        if (len < 0) {
+            FATAL("Internal error: failed to dispatch read request to the client");
+        }
+
+        if (len > (num_bytes - sofar)) {
+            if ((num_bytes - sofar) > 0) {
+                memcpy(buffer+sofar, msg.message_text.buf, (num_bytes - sofar));
+            }
+        } else {
+            memcpy(buffer + sofar, msg.message_text.buf, len);
+        }
+
+        INFO("Printing what i got so far: %s", msg.message_text.buf);
+
+        sofar = sofar + len;
+    }
+
+    /* Update the seek count */
+    skip(msg_handle, invec_idx, num_bytes);
+    INFO("Finished psa_read");
+    return sofar;
+}
+
+void psa_write(psa_handle_t msg_handle, uint32_t outvec_idx,
+               const void *buffer, size_t num_bytes)
+{
+    size_t sofar = 0;
+    struct message msg = { 0 };
+    int idx;
+    ssize_t len;
+
+    is_valid_msg_handle(msg_handle);
+    is_call_msg(msg_handle);
+
+    if (outvec_idx >= PSA_MAX_IOVEC) {
+        ERROR("Invalid iovec number");
+    }
+
+    if (num_bytes > messages[msg_handle].out_size[outvec_idx]) {
+        ERROR("Program tried to write too much data %lu/%lu", num_bytes,
+              messages[msg_handle].out_size[outvec_idx]);
+    }
+
+    while (sofar < num_bytes) {
+        size_t sending = (num_bytes - sofar);
+        if (sending > (MAX_FRAGMENT_SIZE - (sizeof(size_t) * 2))) {
+            sending = MAX_FRAGMENT_SIZE - (sizeof(size_t) * 2);
+        }
+
+        INFO("Server: sending %lu bytes to client, sofar = %lu", sending, (long) sofar);
+
+        send_msg(msg_handle, WRITE_REQUEST, outvec_idx, sending, buffer + sofar, sending);
+
+        idx = find_connection(message_client[msg_handle]);
+        assert(idx >= 0);
+
+        len = msgrcv(connections[idx].client_to_server_q, &msg, sizeof(struct message_text), 0, 0);
+        if (len < 1) {
+            FATAL("Client didn't give me a full response");
+        }
+        sofar = sofar + sending;
+    }
+
+    /* Update the seek count */
+    messages[msg_handle].out_size[outvec_idx] -= num_bytes;
+}
+
+size_t psa_skip(psa_handle_t msg_handle, uint32_t invec_idx, size_t num_bytes)
+{
+    is_valid_msg_handle(msg_handle);
+    is_call_msg(msg_handle);
+
+    size_t ret = skip(msg_handle, invec_idx, num_bytes);
+
+    /* notify client to skip */
+    send_msg(msg_handle, SKIP_REQUEST, invec_idx, num_bytes, NULL, 0);
+    return ret;
+}
+
+static void destroy_temporary_queue(int myqid)
+{
+    if (msgctl(myqid, IPC_RMID, NULL) != 0) {
+        INFO("ERROR: Failed to delete msg queue %d", myqid);
+    }
+}
+
+static int make_temporary_queue()
+{
+    int myqid;
+    if ((myqid = msgget(IPC_PRIVATE, 0660)) == -1) {
+        INFO("msgget: myqid");
+        return -1;
+    }
+    return myqid;
+}
+
+/**
+ * Assumes msg_handle is the index into the message array
+ */
+void psa_reply(psa_handle_t msg_handle, psa_status_t status)
+{
+    int idx, q;
+    is_valid_msg_handle(msg_handle);
+
+    if (pending_message[msg_handle] != 1) {
+        ERROR("Not a valid message handle");
+    }
+
+    if (messages[msg_handle].type == PSA_IPC_CONNECT) {
+        switch (status) {
+            case PSA_SUCCESS:
+                idx = find_connection(message_client[msg_handle]);
+                q = make_temporary_queue();
+                if (q > 0 && idx >= 0) {
+                    connections[idx].client_to_server_q = q;
+                    status = q;
+                } else {
+                    FATAL("What happened?");
+                }
+                break;
+            case PSA_ERROR_CONNECTION_REFUSED:
+                destroy_connection(message_client[msg_handle]);
+                break;
+            case PSA_ERROR_CONNECTION_BUSY:
+                destroy_connection(message_client[msg_handle]);
+                break;
+            case PSA_ERROR_PROGRAMMER_ERROR:
+                destroy_connection(message_client[msg_handle]);
+                break;
+            default:
+                ERROR("Not a valid reply %d", status);
+        }
+    } else if (messages[msg_handle].type == PSA_IPC_DISCONNECT) {
+        idx = find_connection(message_client[msg_handle]);
+        if (idx >= 0) {
+            destroy_temporary_queue(connections[idx].client_to_server_q);
+        }
+        destroy_connection(message_client[msg_handle]);
+    }
+
+    send_msg(msg_handle, PSA_REPLY, status, 0, NULL, 0);
+
+    pending_message[msg_handle] = 0;
+    message_client[msg_handle] = 0;
+}
+
+/* TODO: make sure you only clear interrupt signals, and not others */
+void psa_eoi(psa_signal_t signal)
+{
+    int index = signal_to_index(signal);
+    if (index >= 0 && (rot_svc_incoming_queue[index] >= 0)) {
+        clear_signal(signal);
+    } else {
+        ERROR("Tried to EOI a signal that isn't an interrupt");
+    }
+}
+
+void psa_notify(int32_t partition_id)
+{
+    char pathname[PATHNAMESIZE] = { 0 };
+
+    if (partition_id < 0) {
+        ERROR("Not a valid secure partition");
+    }
+
+    snprintf(pathname, PATHNAMESIZE, "/tmp/psa_notify_%u", partition_id);
+    INFO("psa_notify: notifying partition %u using %s",
+         partition_id, pathname);
+    INFO("psa_notify is unimplemented");
+}
+
+void psa_clear(void)
+{
+    clear_signal(PSA_DOORBELL);
+}
+
+void __init_psasim(const char **array,
+                   int size,
+                   const int allow_ns_clients_array[32],
+                   const uint32_t versions[32],
+                   const int strict_policy_array[32])
+{
+    static uint8_t library_initialised = 0;
+    key_t key;
+    int qid;
+    FILE *fp;
+    char doorbell_file[PATHNAMESIZE] = { 0 };
+    char queue_path[PATHNAMESIZE];
+    snprintf(doorbell_file, PATHNAMESIZE, "psa_notify_%u", getpid());
+
+    if (library_initialised > 0) {
+        return;
+    } else {
+        library_initialised = 1;
+    }
+
+    if (size != 32) {
+        FATAL("Unsupported value. Aborting.");
+    }
+
+    array[3] = doorbell_file;
+
+    for (int i = 0; i < 32; i++) {
+        if (strncmp(array[i], "", 1) != 0) {
+            INFO("Setting up %s", array[i]);
+            memset(queue_path, 0, sizeof(queue_path));
+            snprintf(queue_path, sizeof(queue_path), "%s%s", TMP_FILE_BASE_PATH, array[i]);
+
+            /* Create file if doesn't exist */
+            fp = fopen(queue_path, "ab+");
+            if (fp) {
+                fclose(fp);
+            }
+
+            if ((key = ftok(queue_path, PROJECT_ID)) == -1) {
+                FATAL("Error finding message queue during initialisation");
+            }
+
+            /* TODO: Investigate. Permissions are likely to be too relaxed */
+            if ((qid = msgget(key, IPC_CREAT | 0660)) == -1) {
+                FATAL("Error opening message queue during initialisation");
+            } else {
+                rot_svc_incoming_queue[i] = qid;
+            }
+        }
+    }
+
+    memcpy(nsacl, allow_ns_clients_array, sizeof(int) * 32);
+    memcpy(strict_policy, strict_policy_array, sizeof(int) * 32);
+    memcpy(rot_svc_versions, versions, sizeof(uint32_t) * 32);
+    memset(&connections, 0, sizeof(struct connection) * MAX_CLIENTS);
+
+    __psa_ff_client_security_state = 0; /* Set the client status to SECURE */
+}
diff -Nru mbedtls-3.6.5/framework/psasim/src/psa_sim_generate.pl mbedtls-3.6.6/framework/psasim/src/psa_sim_generate.pl
--- mbedtls-3.6.5/framework/psasim/src/psa_sim_generate.pl	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/src/psa_sim_generate.pl	2026-03-27 12:34:57.776246500 +0200
@@ -0,0 +1,1208 @@
+#!/usr/bin/env perl
+#
+# This is a proof-of-concept script to show that the client and server wrappers
+# can be created by a script. It is not hooked into the build, so is run
+# manually and the output files are what are to be reviewed. In due course
+# this will be replaced by a Python script based on the
+# code_wrapper.psa_wrapper module.
+#
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+#
+use strict;
+use Data::Dumper;
+use File::Basename;
+use JSON qw(encode_json);
+
+my $debug = 0;
+
+# Globals (sorry!)
+my $output_dir = dirname($0);
+
+my %functions = get_functions();
+my @functions = sort keys %functions;
+
+# We don't want these functions (e.g. because they are not implemented, etc)
+my @skip_functions = (
+    'mbedtls_psa_crypto_free', # redefined rather than wrapped
+    'mbedtls_psa_external_get_random', # not in the default config, uses unsupported type
+    'mbedtls_psa_get_stats', # uses unsupported type
+    'mbedtls_psa_platform_get_builtin_key', # not in the default config, uses unsupported type
+    'psa_get_key_slot_number', # not in the default config, uses unsupported type
+    'psa_key_derivation_verify_bytes', # not implemented yet
+    'psa_key_derivation_verify_key', # not implemented yet
+);
+
+my $skip_functions_re = '\A(' . join('|', @skip_functions). ')\Z';
+@functions = grep(!/$skip_functions_re
+                   |_pake_ # Skip everything PAKE
+                   |_init\Z # constructors
+                   /x, @functions);
+# Restore psa_crypto_init() and put it first.
+unshift @functions, 'psa_crypto_init';
+
+# get_functions(), called above, returns a data structure for each function
+# that we need to create client and server stubs for. The functions are
+# listed from PSA header files.
+#
+# In this script, the data for psa_crypto_init() looks like:
+#
+#   "psa_crypto_init": {
+#     "return": {               # Info on return type
+#       "type": "psa_status_t", # Return type
+#       "name": "status",       # Name to be used for this in C code
+#       "default": "PSA_ERROR_CORRUPTION_DETECTED"      # Default value
+#     },
+#     "args": [],               # void function, so args empty
+#   }
+#
+# The data for psa_hash_compute() looks like:
+#
+#  "psa_hash_compute": {
+#    "return": {                # Information on return type
+#      "type": "psa_status_t",
+#      "name": "status",
+#      "default": "PSA_ERROR_CORRUPTION_DETECTED"
+#    },
+#    "args": [{
+#        "type": "psa_algorithm_t",             # Type of first argument
+#        "ctypename": "psa_algorithm_t ",       # C type with trailing spaces
+#                                               # (so that e.g. `char *` looks ok)
+#        "name": "alg",
+#        "is_output": 0
+#      }, {
+#        "type": "const buffer",                # Specially created
+#        "ctypename": "",                       # (so no C type)
+#        "name": "input, input_length",         # A pair of arguments
+#        "is_output": 0                         # const, so not an output argument
+#      }, {
+#        "type": "buffer",                      # Specially created
+#        "ctypename": "",
+#        "name": "hash, hash_size",
+#        "is_output": 1                         # Not const, so output argument
+#      }, {
+#        "type": "size_t",                      # size_t *hash_length
+#        "ctypename": "size_t ",
+#        "name": "*hash_length",                # * comes into the name
+#        "is_output": 1
+#      }
+#    ],
+#  },
+#
+# It's possible that a production version might not need both type and ctypename;
+# that was done for convenience and future-proofing during development.
+
+write_function_codes("$output_dir/psa_functions_codes.h");
+
+write_client_calls("$output_dir/psa_sim_crypto_client.c");
+
+write_server_implementations("$output_dir/psa_sim_crypto_server.c");
+
+sub write_function_codes
+{
+    my ($file) = @_;
+
+    open(my $fh, ">", $file) || die("$0: $file: $!\n");
+
+    # NOTE: psa_crypto_init() is written manually
+
+    print $fh <<EOF;
+/* THIS FILE WAS AUTO-GENERATED BY psa_sim_generate.pl. DO NOT EDIT!! */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef _PSA_FUNCTIONS_CODES_H_
+#define  _PSA_FUNCTIONS_CODES_H_
+
+enum {
+    /* Start here to avoid overlap with PSA_IPC_CONNECT, PSA_IPC_DISCONNECT
+     * and VERSION_REQUEST */
+    PSA_CRYPTO_INIT = 100,
+EOF
+
+    for my $function (@functions) {
+        my $enum = uc($function);
+        if ($enum ne "PSA_CRYPTO_INIT") {
+            print $fh <<EOF;
+    $enum,
+EOF
+        }
+    }
+
+    print $fh <<EOF;
+};
+
+#endif /*  _PSA_FUNCTIONS_CODES_H_ */
+EOF
+
+    close($fh);
+}
+
+sub write_client_calls
+{
+    my ($file) = @_;
+
+    open(my $fh, ">", $file) || die("$0: $file: $!\n");
+
+    print $fh client_calls_header();
+
+    for my $function (@functions) {
+        # psa_crypto_init() is hand written to establish connection to server
+        if ($function ne "psa_crypto_init") {
+            my $f = $functions{$function};
+            output_client($fh, $f, $function);
+        }
+    }
+
+    close($fh);
+}
+
+sub write_server_implementations
+{
+    my ($file) = @_;
+
+    open(my $fh, ">", $file) || die("$0: $file: $!\n");
+
+    print $fh server_implementations_header();
+
+    print $fh debug_functions() if $debug;
+
+    for my $function (@functions) {
+        my $f = $functions{$function};
+        output_server_wrapper($fh, $f, $function);
+    }
+
+    # Now output a switch statement that calls each of the wrappers
+
+    print $fh <<EOF;
+
+psa_status_t psa_crypto_call(psa_msg_t msg)
+{
+    int ok = 0;
+
+    int func = msg.type;
+
+    /* We only expect a single input buffer, with everything serialised in it */
+    if (msg.in_size[1] != 0 || msg.in_size[2] != 0 || msg.in_size[3] != 0) {
+        return PSA_ERROR_INVALID_ARGUMENT;
+    }
+
+    /* We expect exactly 2 output buffers, one for size, the other for data */
+    if (msg.out_size[0] != sizeof(size_t) || msg.out_size[1] == 0 ||
+        msg.out_size[2] != 0 || msg.out_size[3] != 0) {
+        return PSA_ERROR_INVALID_ARGUMENT;
+    }
+
+    uint8_t *in_params = NULL;
+    size_t in_params_len = 0;
+    uint8_t *out_params = NULL;
+    size_t out_params_len = 0;
+
+    in_params_len = msg.in_size[0];
+    in_params = malloc(in_params_len);
+    if (in_params == NULL) {
+        return PSA_ERROR_INSUFFICIENT_MEMORY;
+    }
+
+    /* Read the bytes from the client */
+    size_t actual = psa_read(msg.handle, 0, in_params, in_params_len);
+    if (actual != in_params_len) {
+        free(in_params);
+        return PSA_ERROR_CORRUPTION_DETECTED;
+    }
+
+    switch (func) {
+EOF
+
+    for my $function (@functions) {
+        my $f = $functions{$function};
+        my $enum = uc($function);
+
+        # Create this call, in a way acceptable to uncustify:
+        #            ok = ${function}_wrapper(in_params, in_params_len,
+        #                                     &out_params, &out_params_len);
+        my $first_line = "            ok = ${function}_wrapper(in_params, in_params_len,";
+        my $idx = index($first_line, "(");
+        die("can't find (") if $idx < 0;
+        my $indent = " " x ($idx + 1);
+
+        print $fh <<EOF;
+        case $enum:
+$first_line
+$indent&out_params, &out_params_len);
+            break;
+EOF
+    }
+
+    print $fh <<EOF;
+    }
+
+    free(in_params);
+
+    if (out_params_len > msg.out_size[1]) {
+        fprintf(stderr, "unable to write %zu bytes into buffer of %zu bytes\\n",
+                out_params_len, msg.out_size[1]);
+        exit(1);
+    }
+
+    /* Write the exact amount of data we're returning */
+    psa_write(msg.handle, 0, &out_params_len, sizeof(out_params_len));
+
+    /* And write the data itself */
+    if (out_params_len) {
+        psa_write(msg.handle, 1, out_params, out_params_len);
+    }
+
+    free(out_params);
+
+    return ok ? PSA_SUCCESS : PSA_ERROR_GENERIC_ERROR;
+}
+EOF
+
+    # Finally, add psa_crypto_close()
+
+    print $fh <<EOF;
+
+void psa_crypto_close(void)
+{
+    psa_sim_serialize_reset();
+}
+EOF
+
+    close($fh);
+}
+
+sub server_implementations_header
+{
+    return <<'EOF';
+/* THIS FILE WAS AUTO-GENERATED BY psa_sim_generate.pl. DO NOT EDIT!! */
+
+/* server implementations */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <psa/crypto.h>
+
+#include "psa_functions_codes.h"
+#include "psa_sim_serialise.h"
+
+#include "service.h"
+
+#if !defined(MBEDTLS_PSA_CRYPTO_C)
+#error "Error: MBEDTLS_PSA_CRYPTO_C must be enabled on server build"
+#endif
+
+#if defined(MBEDTLS_TEST_HOOKS)
+void (*mbedtls_test_hook_error_add)(int, int, const char *, int);
+#endif
+EOF
+}
+
+sub client_calls_header
+{
+    my $code = <<'EOF';
+/* THIS FILE WAS AUTO-GENERATED BY psa_sim_generate.pl. DO NOT EDIT!! */
+
+/* client calls */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+/* Includes from psasim */
+#include <client.h>
+#include <util.h>
+#include "psa_manifest/sid.h"
+#include "psa_functions_codes.h"
+#include "psa_sim_serialise.h"
+
+/* Includes from mbedtls */
+#include "mbedtls/version.h"
+#include "psa/crypto.h"
+
+#define CLIENT_PRINT(fmt, ...) \
+    INFO("Client: " fmt, ##__VA_ARGS__)
+
+static psa_handle_t handle = -1;
+
+#if defined(MBEDTLS_PSA_CRYPTO_C)
+#error "Error: MBEDTLS_PSA_CRYPTO_C must be disabled on client build"
+#endif
+EOF
+
+    $code .= debug_functions() if $debug;
+
+    $code .= <<'EOF';
+
+int psa_crypto_call(int function,
+                    uint8_t *in_params, size_t in_params_len,
+                    uint8_t **out_params, size_t *out_params_len)
+{
+    // psa_outvec outvecs[1];
+    if (handle < 0) {
+        fprintf(stderr, "NOT CONNECTED\n");
+        exit(1);
+    }
+
+    psa_invec invec;
+    invec.base = in_params;
+    invec.len = in_params_len;
+
+    size_t max_receive = 24576;
+    uint8_t *receive = malloc(max_receive);
+    if (receive == NULL) {
+        fprintf(stderr, "FAILED to allocate %u bytes\n", (unsigned) max_receive);
+        exit(1);
+    }
+
+    size_t actual_received = 0;
+
+    psa_outvec outvecs[2];
+    outvecs[0].base = &actual_received;
+    outvecs[0].len = sizeof(actual_received);
+    outvecs[1].base = receive;
+    outvecs[1].len = max_receive;
+
+    psa_status_t status = psa_call(handle, function, &invec, 1, outvecs, 2);
+    if (status != PSA_SUCCESS) {
+        free(receive);
+        return 0;
+    }
+
+    *out_params = receive;
+    *out_params_len = actual_received;
+
+    return 1;   // success
+}
+
+psa_status_t psa_crypto_init(void)
+{
+    const char *mbedtls_version;
+    uint8_t *result = NULL;
+    size_t result_length;
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    mbedtls_version = mbedtls_version_get_string_full();
+    CLIENT_PRINT("%s", mbedtls_version);
+
+    CLIENT_PRINT("My PID: %d", getpid());
+
+    CLIENT_PRINT("PSA version: %u", psa_version(PSA_SID_CRYPTO_SID));
+    handle = psa_connect(PSA_SID_CRYPTO_SID, 1);
+
+    if (handle < 0) {
+        CLIENT_PRINT("Couldn't connect %d", handle);
+        return PSA_ERROR_COMMUNICATION_FAILURE;
+    }
+
+    int ok = psa_crypto_call(PSA_CRYPTO_INIT, NULL, 0, &result, &result_length);
+    CLIENT_PRINT("PSA_CRYPTO_INIT returned: %d", ok);
+
+    if (!ok) {
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_length;
+
+    ok = psasim_deserialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+
+    ok = psasim_deserialise_psa_status_t(&rpos, &rremain, &status);
+    if (!ok) {
+        goto fail;
+    }
+
+fail:
+    free(result);
+
+    return status;
+}
+
+void mbedtls_psa_crypto_free(void)
+{
+    /* Do not try to close a connection that was never started.*/
+    if (handle == -1) {
+        return;
+    }
+
+    CLIENT_PRINT("Closing handle");
+    psa_close(handle);
+    handle = -1;
+}
+EOF
+}
+
+sub debug_functions
+{
+    return <<EOF;
+
+static inline char hex_digit(char nibble) {
+    return (nibble < 10) ? (nibble + '0') : (nibble + 'a' - 10);
+}
+
+int hex_byte(char *p, uint8_t b)
+{
+    p[0] = hex_digit(b >> 4);
+    p[1] = hex_digit(b & 0x0F);
+
+    return 2;
+}
+
+int hex_uint16(char *p, uint16_t b)
+{
+    hex_byte(p, b >> 8);
+    hex_byte(p + 2, b & 0xFF);
+
+    return 4;
+}
+
+char human_char(uint8_t c)
+{
+    return (c >= ' ' && c <= '~') ? (char)c : '.';
+}
+
+void dump_buffer(const uint8_t *buffer, size_t len)
+{
+    char line[80];
+
+    const uint8_t *p = buffer;
+
+    size_t max = (len > 0xFFFF) ? 0xFFFF : len;
+
+    for (size_t i = 0; i < max; i += 16) {
+
+        char *q = line;
+
+        q += hex_uint16(q, (uint16_t)i);
+        *q++ = ' ';
+        *q++ = ' ';
+
+        size_t ll = (i + 16 > max) ? (max % 16) : 16;
+
+        size_t j;
+        for (j = 0; j < ll; j++) {
+            q += hex_byte(q, p[i + j]);
+            *q++ = ' ';
+        }
+
+        while (j++ < 16) {
+            *q++ = ' ';
+            *q++ = ' ';
+            *q++ = ' ';
+        }
+
+        *q++ = ' ';
+
+        for (j = 0; j < ll; j++) {
+            *q++ = human_char(p[i + j]);
+        }
+
+        *q = '\\0';
+
+        printf("%s\\n", line);
+    }
+}
+
+void hex_dump(uint8_t *p, size_t n)
+{
+    for (size_t i = 0; i < n; i++) {
+        printf("0x%02X ", p[i]);
+    }
+    printf("\\n");
+}
+EOF
+}
+
+sub output_server_wrapper
+{
+    my ($fh, $f, $name) = @_;
+
+    my $ret_type = $f->{return}->{type};
+    my $ret_name = $f->{return}->{name};
+    my $ret_default = $f->{return}->{default};
+
+    my @buffers = ();           # We need to free() these on exit
+
+    print $fh <<EOF;
+
+// Returns 1 for success, 0 for failure
+int ${name}_wrapper(
+    uint8_t *in_params, size_t in_params_len,
+    uint8_t **out_params, size_t *out_params_len)
+{
+EOF
+
+    print $fh <<EOF unless $ret_type eq "void";
+    $ret_type $ret_name = $ret_default;
+EOF
+    # Output the variables we will need when we call the target function
+
+    my $args = $f->{args};
+
+    for my $i (0 .. $#$args) {
+        my $arg = $args->[$i];
+        my $argtype = $arg->{type};     # e.g. int, psa_algorithm_t, or "buffer"
+        my $argname = $arg->{name};
+        $argtype =~ s/^const //;
+
+        if ($argtype =~ /^(const )?buffer$/) {
+            my ($n1, $n2) = split(/,\s*/, $argname);
+            print $fh <<EOF;
+    uint8_t *$n1 = NULL;
+    size_t $n2;
+EOF
+            push(@buffers, $n1);        # Add to the list to be free()d at end
+        } else {
+            $argname =~ s/^\*//;        # Remove any leading *
+            my $pointer = ($argtype =~ /^psa_\w+_operation_t/) ? "*" : "";
+            print $fh <<EOF;
+    $argtype $pointer$argname;
+EOF
+        }
+    }
+
+    print $fh "\n";
+
+    if ($#$args >= 0) {          # If we have any args (>= 0)
+        print $fh <<EOF;
+    uint8_t *pos = in_params;
+    size_t remaining = in_params_len;
+EOF
+    }
+
+    print $fh <<EOF;
+    uint8_t *result = NULL;
+    int ok;
+EOF
+
+    print $fh <<EOF if $debug;
+
+    printf("$name: server\\n");
+EOF
+    if ($#$args >= 0) {          # If we have any args (>= 0)
+        print $fh <<EOF;
+
+    ok = psasim_deserialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+EOF
+    }
+
+    for my $i (0 .. $#$args) {
+        my $arg = $args->[$i];
+        my $argtype = $arg->{type};     # e.g. int, psa_algorithm_t, or "buffer"
+        my $argname = $arg->{name};
+        my $sep = ($i == $#$args) ? ";" : " +";
+        $argtype =~ s/^const //;
+
+        if ($argtype =~ /^(const )?buffer$/) {
+            my ($n1, $n2) = split(/,\s*/, $argname);
+            print $fh <<EOF;
+
+    ok = psasim_deserialise_${argtype}(
+        &pos, &remaining,
+        &$n1, &$n2);
+    if (!ok) {
+        goto fail;
+    }
+EOF
+        } else {
+            $argname =~ s/^\*//;        # Remove any leading *
+            my $server_specific = ($argtype =~ /^psa_\w+_operation_t/) ? "server_" : "";
+            print $fh <<EOF;
+
+    ok = psasim_${server_specific}deserialise_${argtype}(
+        &pos, &remaining,
+        &$argname);
+    if (!ok) {
+        goto fail;
+    }
+EOF
+        }
+    }
+
+    print $fh <<EOF;
+
+    // Now we call the actual target function
+EOF
+    output_call($fh, $f, $name, 1);
+
+    my @outputs = grep($_->{is_output}, @$args);
+
+    my $sep1 = (($ret_type eq "void") and ($#outputs < 0)) ? ";" : " +";
+
+    print $fh <<EOF;
+
+    // NOTE: Should really check there is no overflow as we go along.
+    size_t result_size =
+        psasim_serialise_begin_needs()$sep1
+EOF
+
+    if ($ret_type ne "void") {
+        my $sep = ($#outputs < 0) ? ";" : " +";
+        print $fh <<EOF;
+        psasim_serialise_${ret_type}_needs($ret_name)$sep
+EOF
+    }
+
+    for my $i (0 .. $#outputs) {
+        my $arg = $outputs[$i];
+        die("$i: this should have been filtered out by grep") unless $arg->{is_output};
+        my $argtype = $arg->{type};     # e.g. int, psa_algorithm_t, or "buffer"
+        my $argname = $arg->{name};
+        my $sep = ($i == $#outputs) ? ";" : " +";
+        $argtype =~ s/^const //;
+        $argname =~ s/^\*//;        # Remove any leading *
+        my $server_specific = ($argtype =~ /^psa_\w+_operation_t/) ? "server_" : "";
+
+        print $fh <<EOF;
+        psasim_${server_specific}serialise_${argtype}_needs($argname)$sep
+EOF
+    }
+
+    print $fh <<EOF;
+
+    result = malloc(result_size);
+    if (result == NULL) {
+        goto fail;
+    }
+
+    uint8_t *rpos = result;
+    size_t rremain = result_size;
+
+    ok = psasim_serialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+EOF
+
+    if ($ret_type ne "void") {
+        print $fh <<EOF;
+
+    ok = psasim_serialise_${ret_type}(
+        &rpos, &rremain,
+        $ret_name);
+    if (!ok) {
+        goto fail;
+    }
+EOF
+    }
+
+    my @outputs = grep($_->{is_output}, @$args);
+
+    for my $i (0 .. $#outputs) {
+        my $arg = $outputs[$i];
+        die("$i: this should have been filtered out by grep") unless $arg->{is_output};
+        my $argtype = $arg->{type};     # e.g. int, psa_algorithm_t, or "buffer"
+        my $argname = $arg->{name};
+        my $sep = ($i == $#outputs) ? ";" : " +";
+        $argtype =~ s/^const //;
+
+        if ($argtype eq "buffer") {
+            print $fh <<EOF;
+
+    ok = psasim_serialise_buffer(
+        &rpos, &rremain,
+        $argname);
+    if (!ok) {
+        goto fail;
+    }
+EOF
+        } else {
+            if ($argname =~ /^\*/) {
+                $argname =~ s/^\*//;    # since it's already a pointer
+            } else {
+                die("$0: $argname: HOW TO OUTPUT?\n");
+            }
+
+            my $server_specific = ($argtype =~ /^psa_\w+_operation_t/) ? "server_" : "";
+
+            my $completed = ""; # Only needed on server serialise calls
+            if (length($server_specific)) {
+                # On server serialisation, which is only for operation types,
+                # we need to mark the operation as completed (variously called
+                # terminated or inactive in psa/crypto.h) on certain calls.
+                $completed = ($name =~ /_(abort|finish|hash_verify)$/) ? ", 1" : ", 0";
+            }
+
+            print $fh <<EOF;
+
+    ok = psasim_${server_specific}serialise_${argtype}(
+        &rpos, &rremain,
+        $argname$completed);
+    if (!ok) {
+        goto fail;
+    }
+EOF
+        }
+    }
+
+    my $free_buffers = join("", map { "    free($_);\n" } @buffers);
+    $free_buffers = "\n" . $free_buffers if length($free_buffers);
+
+    print $fh <<EOF;
+
+    *out_params = result;
+    *out_params_len = result_size;
+$free_buffers
+    return 1;   // success
+
+fail:
+    free(result);
+$free_buffers
+    return 0;       // This shouldn't happen!
+}
+EOF
+}
+
+sub output_client
+{
+    my ($fh, $f, $name) = @_;
+
+    print $fh "\n";
+
+    output_definition_begin($fh, $f, $name);
+
+    my $ret_type = $f->{return}->{type};
+    my $ret_name = $f->{return}->{name};
+    my $ret_default = $f->{return}->{default};
+
+    print $fh <<EOF;
+{
+    uint8_t *ser_params = NULL;
+    uint8_t *ser_result = NULL;
+    size_t result_length;
+EOF
+    print $fh <<EOF unless $ret_type eq "void";
+    $ret_type $ret_name = $ret_default;
+EOF
+
+    print $fh <<EOF if $debug;
+
+    printf("$name: client\\n");
+EOF
+
+    print $fh <<EOF;
+
+    size_t needed =
+        psasim_serialise_begin_needs() +
+EOF
+
+    my $args = $f->{args};
+
+    for my $i (0 .. $#$args) {
+        my $arg = $args->[$i];
+        my $argtype = $arg->{type};     # e.g. int, psa_algorithm_t, or "buffer"
+        my $argname = $arg->{name};
+        my $sep = ($i == $#$args) ? ";" : " +";
+        $argtype =~ s/^const //;
+
+        print $fh <<EOF;
+        psasim_serialise_${argtype}_needs($argname)$sep
+EOF
+    }
+
+    print $fh <<EOF if $#$args < 0;
+        0;
+EOF
+
+    print $fh <<EOF;
+
+    ser_params = malloc(needed);
+    if (ser_params == NULL) {
+EOF
+
+    if ($ret_type eq "psa_status_t") {
+        print $fh <<EOF if $;
+        $ret_name = PSA_ERROR_INSUFFICIENT_MEMORY;
+EOF
+    } elsif ($ret_type eq "uint32_t") {
+        print $fh <<EOF if $;
+        $ret_name = 0;
+EOF
+    }
+
+    print $fh <<EOF;
+        goto fail;
+    }
+
+    uint8_t *pos = ser_params;
+    size_t remaining = needed;
+    int ok;
+    ok = psasim_serialise_begin(&pos, &remaining);
+    if (!ok) {
+        goto fail;
+    }
+EOF
+
+    for my $i (0 .. $#$args) {
+        my $arg = $args->[$i];
+        my $argtype = $arg->{type};     # e.g. int, psa_algorithm_t, or "buffer"
+        my $argname = $arg->{name};
+        my $sep = ($i == $#$args) ? ";" : " +";
+        $argtype =~ s/^const //;
+
+        print $fh <<EOF;
+    ok = psasim_serialise_${argtype}(
+        &pos, &remaining,
+        $argname);
+    if (!ok) {
+        goto fail;
+    }
+EOF
+    }
+
+    print $fh <<EOF if $debug;
+
+    printf("client sending %d:\\n", (int)(pos - ser_params));
+    dump_buffer(ser_params, (size_t)(pos - ser_params));
+EOF
+
+    my $enum = uc($name);
+
+    print $fh <<EOF;
+
+    ok = psa_crypto_call($enum,
+                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
+    if (!ok) {
+        printf("$enum server call failed\\n");
+        goto fail;
+    }
+EOF
+
+    print $fh <<EOF if $debug;
+
+    printf("client receiving %d:\\n", (int)result_length);
+    dump_buffer(ser_result, result_length);
+EOF
+
+    print $fh <<EOF;
+
+    uint8_t *rpos = ser_result;
+    size_t rremain = result_length;
+
+    ok = psasim_deserialise_begin(&rpos, &rremain);
+    if (!ok) {
+        goto fail;
+    }
+EOF
+
+    print $fh <<EOF if $ret_type ne "void";
+
+    ok = psasim_deserialise_$ret_type(
+        &rpos, &rremain,
+        &$ret_name);
+    if (!ok) {
+        goto fail;
+    }
+EOF
+
+    my @outputs = grep($_->{is_output}, @$args);
+
+    for my $i (0 .. $#outputs) {
+        my $arg = $outputs[$i];
+        die("$i: this should have been filtered out by grep") unless $arg->{is_output};
+        my $argtype = $arg->{type};     # e.g. int, psa_algorithm_t, or "buffer"
+        my $argname = $arg->{name};
+        my $sep = ($i == $#outputs) ? ";" : " +";
+        $argtype =~ s/^const //;
+
+        if ($argtype eq "buffer") {
+            print $fh <<EOF;
+
+    ok = psasim_deserialise_return_buffer(
+        &rpos, &rremain,
+        $argname);
+    if (!ok) {
+        goto fail;
+    }
+EOF
+        } else {
+            if ($argname =~ /^\*/) {
+                $argname =~ s/^\*//;    # since it's already a pointer
+            } else {
+                die("$0: $argname: HOW TO OUTPUT?\n");
+            }
+
+            print $fh <<EOF;
+
+    ok = psasim_deserialise_${argtype}(
+        &rpos, &rremain,
+        $argname);
+    if (!ok) {
+        goto fail;
+    }
+EOF
+        }
+    }
+    print $fh <<EOF;
+
+fail:
+    free(ser_params);
+    free(ser_result);
+EOF
+
+    print $fh <<EOF if $ret_type ne "void";
+
+    return $ret_name;
+EOF
+
+    print $fh <<EOF;
+}
+EOF
+}
+
+sub output_declaration
+{
+    my ($f, $name) = @_;
+
+    output_signature($f, $name, "declaration");
+}
+
+sub output_definition_begin
+{
+    my ($fh, $f, $name) = @_;
+
+    output_signature($fh, $f, $name, "definition");
+}
+
+sub output_call
+{
+    my ($fh, $f, $name, $is_server) = @_;
+
+    my $ret_type = $f->{return}->{type};
+    my $ret_name = $f->{return}->{name};
+    my $args = $f->{args};
+
+    if ($ret_type eq "void") {
+        print $fh "\n    $name(\n";
+    } else {
+        print $fh "\n    $ret_name = $name(\n";
+    }
+
+    print $fh "        );\n" if $#$args < 0; # If no arguments, empty arg list
+
+    for my $i (0 .. $#$args) {
+        my $arg = $args->[$i];
+        my $argtype = $arg->{type};     # e.g. int, psa_algorithm_t, or "buffer"
+        my $argname = $arg->{name};
+
+        if ($argtype =~ /^(const )?buffer$/) {
+            my ($n1, $n2) = split(/,\s*/, $argname);
+            print $fh "        $n1, $n2";
+        } else {
+            $argname =~ s/^\*/\&/;      # Replace leading * with &
+            if ($is_server && $argtype =~ /^psa_\w+_operation_t/) {
+                $argname =~ s/^\&//;    # Actually, for psa_XXX_operation_t, don't do this on the server side
+            }
+            print $fh "        $argname";
+        }
+        my $sep = ($i == $#$args) ? "\n        );" : ",";
+        print $fh "$sep\n";
+    }
+}
+
+sub output_signature
+{
+    my ($fh, $f, $name, $what) = @_;
+
+    my $ret_type = $f->{return}->{type};
+    my $args = $f->{args};
+
+    my $final_sep = ($what eq "declaration") ? "\n);" : "\n    )";
+
+    print $fh "\n$ret_type $name(\n";
+
+    print $fh "    void\n    )\n" if $#$args < 0;   # No arguments
+
+    for my $i (0 .. $#$args) {
+        my $arg = $args->[$i];
+        my $argtype = $arg->{type};             # e.g. int, psa_algorithm_t, or "buffer"
+        my $ctypename = $arg->{ctypename};      # e.g. "int ", "char *"; empty for buffer
+        my $argname = $arg->{name};
+
+        if ($argtype =~ /^(const )?buffer$/) {
+            my $const = length($1) ? "const " : "";
+            my ($n1, $n2) = split(/,/, $argname);
+            print $fh "    ${const}uint8_t *$n1, size_t $n2";
+        } else {
+            print $fh "    $ctypename$argname";
+        }
+        my $sep = ($i == $#$args) ? $final_sep : ",";
+        print $fh "$sep\n";
+    }
+}
+
+sub get_functions
+{
+    my $header_dir = 'include';
+    my $src = "";
+    for my $header_file ('psa/crypto.h', 'psa/crypto_extra.h') {
+        local *HEADER;
+        open HEADER, '<', "$header_dir/$header_file"
+          or die "$header_dir/$header_file: $!";
+        while (<HEADER>) {
+            chomp;
+            s/\/\/.*//;
+            s/\s+^//;
+            s/\s+/ /g;
+            $_ .= "\n";
+            $src .= $_;
+        }
+        close HEADER;
+    }
+
+    $src =~ s/\/\*.*?\*\///gs;
+
+    my @src = split(/\n+/, $src);
+
+    my @rebuild = ();
+    my %funcs = ();
+    for (my $i = 0; $i <= $#src; $i++) {
+        my $line = $src[$i];
+        if ($line =~ /^(static(?:\s+inline)?\s+)?
+                       ((?:(?:enum|struct|union)\s+)?\w+\s*\**\s*)\s+
+                       ((?:mbedtls|psa)_\w*)\(/x) {
+            # begin function declaration
+            #print "have one $line\n";
+            while ($line !~ /;/) {
+                $line .= $src[$i + 1];
+                $i++;
+            }
+            if ($line =~ /^static/) {
+                # IGNORE static inline functions: they're local.
+                next;
+            }
+            $line =~ s/\s+/ /g;
+            if ($line =~ /(\w+)\s+\b(\w+)\s*\(\s*(.*\S)\s*\)\s*[;{]/s) {
+                my ($ret_type, $func, $args) = ($1, $2, $3);
+
+                my $copy = $line;
+                $copy =~ s/{$//;
+                my $f = {
+                    "orig" => $copy,
+                };
+
+                my @args = split(/\s*,\s*/, $args);
+
+                my $ret_name = "";
+                $ret_name = "status" if $ret_type eq "psa_status_t";
+                $ret_name = "value" if $ret_type eq "uint32_t";
+                $ret_name = "value" if $ret_type eq "int";
+                $ret_name = "(void)" if $ret_type eq "void";
+                die("ret_name for $ret_type?") unless length($ret_name);
+                my $ret_default = "";
+                $ret_default = "PSA_ERROR_CORRUPTION_DETECTED" if $ret_type eq "psa_status_t";
+                $ret_default = "0" if $ret_type eq "uint32_t";
+                $ret_default = "0" if $ret_type eq "int";
+                $ret_default = "(void)" if $ret_type eq "void";
+                die("ret_default for $ret_type?") unless length($ret_default);
+
+                #print "FUNC $func RET_NAME $ret_name RET_TYPE $ret_type ARGS (", join("; ", @args), ")\n";
+
+                $f->{return} = {
+                    "type" => $ret_type,
+                    "default" => $ret_default,
+                    "name" => $ret_name,
+                };
+                $f->{args} = [];
+                # psa_algorithm_t alg; const uint8_t *input; size_t input_length; uint8_t *hash; size_t hash_size; size_t *hash_length
+                for (my $i = 0; $i <= $#args; $i++) {
+                    my $arg = $args[$i];
+                    # "type" => "psa_algorithm_t",
+                    # "ctypename" => "psa_algorithm_t ",
+                    # "name" => "alg",
+                    # "is_output" => 0,
+                    my ($type, $ctype, $name, $is_output);
+                    if ($arg =~ /^(\w+)\s+(\w+)$/) {    # e.g. psa_algorithm_t alg
+                        ($type, $name) = ($1, $2);
+                        $ctype = $type . " ";
+                        $is_output = 0;
+                    } elsif ($arg =~ /^((const)\s+)?uint8_t\s*\*\s*(\w+)$/) {
+                        $type = "buffer";
+                        $is_output = (length($1) == 0) ? 1 : 0;
+                        $type = "const buffer" if !$is_output;
+                        $ctype = "";
+                        $name = $3;
+                        #print("$arg: $name: might be a buffer?\n");
+                        die("$arg: not a buffer 1!\n") if $i == $#args;
+                        my $next = $args[$i + 1];
+                        if ($func eq "psa_key_derivation_verify_bytes" &&
+                            $arg eq "const uint8_t *expected_output" &&
+                            $next eq "size_t output_length") {
+                            $next = "size_t expected_output_length";    # doesn't follow naming convention, so override
+                        }
+                        die("$arg: not a buffer 2!\n") if $next !~ /^size_t\s+(${name}_\w+)$/;
+                        $i++;                   # We're using the next param here
+                        my $nname = $1;
+                        $name .= ", " . $nname;
+                    } elsif ($arg =~ /^((const)\s+)?(\w+)\s*\*(\w+)$/) {
+                        ($type, $name) = ($3, "*" . $4);
+                        $ctype = $1 . $type . " ";
+                        $is_output = (length($1) == 0) ? 1 : 0;
+                    } elsif ($arg eq "void") {
+                         # we'll just ignore this one
+                    } else {
+                        die("ARG HELP $arg\n");
+                    }
+                    #print "$arg => <$type><$ctype><$name><$is_output>\n";
+                    if ($arg ne "void") {
+                        push(@{$f->{args}}, {
+                            "type" => $type,
+                            "ctypename" => $ctype,
+                            "name" => $name,
+                            "is_output" => $is_output,
+                        });
+                    }
+                }
+                $funcs{$func} = $f;
+            } else {
+                die("FAILED");
+            }
+            push(@rebuild, $line);
+        } elsif ($line =~ /^#/i) {
+            # IGNORE directive
+            while ($line =~ /\\$/) {
+                $i++;
+                $line = $src[$i];
+            }
+        } elsif ($line =~ /^(?:typedef +)?(enum|struct|union)[^;]*$/) {
+            # IGNORE compound type definition
+            while ($line !~ /^\}/) {
+                $i++;
+                $line = $src[$i];
+            }
+        } elsif ($line =~ /^typedef /i) {
+            # IGNORE type definition
+        } elsif ($line =~ / = .*;$/) {
+            # IGNORE assignment in inline function definition
+        } else {
+            if ($line =~ /psa_/) {
+                print "NOT PARSED: $line\n";
+            }
+            push(@rebuild, $line);
+        }
+    }
+
+    #print ::Dumper(\%funcs);
+    #exit;
+
+    return %funcs;
+}
diff -Nru mbedtls-3.6.5/framework/psasim/src/psa_sim_serialise.pl mbedtls-3.6.6/framework/psasim/src/psa_sim_serialise.pl
--- mbedtls-3.6.5/framework/psasim/src/psa_sim_serialise.pl	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/src/psa_sim_serialise.pl	2026-03-27 12:34:57.776357700 +0200
@@ -0,0 +1,1082 @@
+#!/usr/bin/env perl
+#
+# psa_sim_serialise.pl - Sample Perl script to show how many serialisation
+#                        functions can be created by templated scripting.
+#
+# This is an example only, and is expected to be replaced by a Python script
+# for production use. It is not hooked into the build: it needs to be run
+# manually:
+#
+# perl psa_sim_serialise.pl h > psa_sim_serialise.h
+# perl psa_sim_serialise.pl c > psa_sim_serialise.c
+#
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+#
+use strict;
+
+my $usage = "$0: usage: $0 c|h\n";
+my $which = lc(shift) || die($usage);
+die($usage) unless $which eq "c" || $which eq "h";
+
+# Most types are serialised as a fixed-size (per type) octet string, with
+# no type indication. This is acceptable as (a) this is for the test PSA crypto
+# simulator only, not production, and (b) these functions are called by
+# code that itself is written by script.
+#
+# We also want to keep serialised data reasonably compact as communication
+# between client and server goes in messages of less than 200 bytes each.
+#
+# This script is able to create serialisation functions for plain old C data
+# types (e.g. unsigned int), types typedef'd to those, and even structures
+# that don't contain pointers.
+#
+# Structures that contain pointers will need to have their serialisation and
+# deserialisation functions written manually (like those for the "buffer" type
+# are).
+#
+my @types = qw(unsigned unsigned-int int unsigned-long long size_t
+               uint16_t uint32_t uint64_t
+               int16_t int32_t int64_t
+               buffer
+               psa_custom_key_parameters_t
+               psa_status_t psa_algorithm_t psa_key_derivation_step_t
+               psa_hash_operation_t
+               psa_aead_operation_t
+               psa_key_attributes_t
+               psa_mac_operation_t
+               psa_cipher_operation_t
+               psa_key_derivation_operation_t
+               psa_sign_hash_interruptible_operation_t
+               psa_verify_hash_interruptible_operation_t
+               psa_xof_operation_t
+               mbedtls_svc_key_id_t
+               psa_key_agreement_iop_t
+               psa_generate_key_iop_t
+               psa_export_public_key_iop_t);
+
+grep(s/-/ /g, @types);
+
+# IS-A: Some data types are typedef'd or synonyms; we serialise them as
+# the other type.
+my %isa = (
+    "psa_status_t" => "int32_t",
+    "psa_algorithm_t" => "uint32_t",
+    "psa_key_derivation_step_t" => "uint16_t",
+    "unsigned" => "unsigned int",
+);
+
+# Compile-time guards for some types: the type $type is defined only
+# if the preprocessor conditional $type_guards{$type} is true.
+# If a type has no guard, assume that it's always defined.
+# The guard must be a preprocessor expression with no newline or comment.
+my %type_guards = (
+    psa_xof_operation_t => "defined(PSA_ALG_CATEGORY_XOF)",
+);
+
+sub type_guard {
+    my ($type, $start) = @_;
+    return unless exists $type_guards{$type};
+    if ($start) {
+        print "\n#if $type_guards{$type}";
+    } else {
+        print "#endif /* $type_guards{$type} */\n";
+    }
+}
+
+if ($which eq "h") {
+
+    print h_header();
+
+    for my $type (@types) {
+        type_guard($type, 1);
+        if ($type eq "buffer") {
+            print declare_buffer_functions();
+        } else {
+            print declare_needs($type, "");
+            print declare_serialise($type, "");
+            print declare_deserialise($type, "");
+
+            if ($type =~ /^psa_\w+_operation_t$/) {
+                print declare_needs($type, "server_");
+                print declare_serialise($type, "server_");
+                print declare_deserialise($type, "server_");
+            }
+        }
+        type_guard($type, 0);
+    }
+
+} elsif ($which eq "c") {
+
+    my $have_operation_types = (grep(/psa_\w+_operation_t/, @types)) ? 1 : 0;
+
+    print c_header();
+    print c_define_types_for_operation_types() if $have_operation_types;
+
+    for my $type (@types) {
+        next unless $type =~ /^psa_(\w+)_operation_t$/;
+        type_guard($type, 1);
+        print define_operation_type_data_and_functions($1);
+        type_guard($type, 0);
+    }
+
+    print c_define_begins();
+
+    for my $type (@types) {
+        type_guard($type, 1);
+        if ($type eq "buffer") {
+            print define_buffer_functions();
+        } elsif (exists($isa{$type})) {
+            print define_needs_isa($type, $isa{$type});
+            print define_serialise_isa($type, $isa{$type});
+            print define_deserialise_isa($type, $isa{$type});
+        } else {
+            print define_needs($type);
+            print define_serialise($type);
+            print define_deserialise($type);
+
+            if ($type =~ /^psa_\w+_operation_t$/) {
+                print define_server_needs($type);
+                print define_server_serialise($type);
+                print define_server_deserialise($type);
+            }
+        }
+        type_guard($type, 0);
+    }
+
+    print define_server_serialize_reset(@types);
+} else {
+    die("internal error - shouldn't happen");
+}
+
+sub declare_needs
+{
+    my ($type, $server) = @_;
+
+    my $an = ($type =~ /^[ui]/) ? "an" : "a";
+    my $type_d = $type;
+    $type_d =~ s/ /_/g;
+
+    my $ptr = (length($server)) ? "*" : "";
+
+    return <<EOF;
+
+/** Return how much buffer space is needed by \\c psasim_${server}serialise_$type_d()
+ *  to serialise $an `$type`.
+ *
+ * \\param value              The value that will be serialised into the buffer
+ *                           (needed in case some serialisations are value-
+ *                           dependent).
+ *
+ * \\return                   The number of bytes needed in the buffer by
+ *                           \\c psasim_serialise_$type_d() to serialise
+ *                           the given value.
+ */
+size_t psasim_${server}serialise_${type_d}_needs(
+    $type ${ptr}value);
+EOF
+}
+
+sub declare_serialise
+{
+    my ($type, $server) = @_;
+
+    my $an = ($type =~ /^[ui]/) ? "an" : "a";
+    my $type_d = $type;
+    $type_d =~ s/ /_/g;
+
+    if (length($server) && $type !~ /^psa_(\w+)_operation_t$/) {
+        die("$0: declare_server_serialise: $type: not supported\n");
+    }
+
+    my $server_side = (length($server)) ? " on the server side" : "";
+
+    my $ptr = (length($server)) ? "*" : "";
+
+    my $code = <<EOF;
+
+/** Serialise $an `$type` into a buffer${server_side}.
+ *
+ * \\param pos[in,out]        Pointer to a `uint8_t *` holding current position
+ *                           in the buffer.
+ * \\param remaining[in,out]  Pointer to a `size_t` holding number of bytes
+ *                           remaining in the buffer.
+ * \\param value              The value to serialise into the buffer.
+EOF
+
+    $code .= <<EOF if length($server);
+ * \\param completed          Non-zero if the operation is now completed (set by
+ *                           finish and abort calls).
+EOF
+
+    my $value_sep = (length($server)) ? "," : ");";
+
+    $code .= <<EOF;
+ *
+ * \\return                   \\c 1 on success ("okay"), \\c 0 on error.
+ */
+int psasim_${server}serialise_$type_d(uint8_t **pos,
+                             size_t *remaining,
+                             $type ${ptr}value$value_sep
+EOF
+
+    $code .= <<EOF if length($server);
+                             int completed);
+EOF
+
+    return align_declaration($code);
+}
+
+sub declare_deserialise
+{
+    my ($type, $server) = @_;
+
+    my $an = ($type =~ /^[ui]/) ? "an" : "a";
+    my $type_d = $type;
+    $type_d =~ s/ /_/g;
+
+    my $server_side = (length($server)) ? " on the server side" : "";
+
+    my $ptr = (length($server)) ? "*" : "";
+
+    return align_declaration(<<EOF);
+
+/** Deserialise $an `$type` from a buffer${server_side}.
+ *
+ * \\param pos[in,out]        Pointer to a `uint8_t *` holding current position
+ *                           in the buffer.
+ * \\param remaining[in,out]  Pointer to a `size_t` holding number of bytes
+ *                           remaining in the buffer.
+ * \\param value              Pointer to $an `$type` to receive the value
+ *                           deserialised from the buffer.
+ *
+ * \\return                   \\c 1 on success ("okay"), \\c 0 on error.
+ */
+int psasim_${server}deserialise_$type_d(uint8_t **pos,
+                               size_t *remaining,
+                               $type ${ptr}*value);
+EOF
+}
+
+sub declare_buffer_functions
+{
+    return <<'EOF';
+
+/** Return how much space is needed by \c psasim_serialise_buffer()
+ *  to serialise a buffer: a (`uint8_t *`, `size_t`) pair.
+ *
+ * \param buffer             Pointer to the buffer to be serialised
+ *                           (needed in case some serialisations are value-
+ *                           dependent).
+ * \param buffer_size        Number of bytes in the buffer to be serialised.
+ *
+ * \return                   The number of bytes needed in the buffer by
+ *                           \c psasim_serialise_buffer() to serialise
+ *                           the specified buffer.
+ */
+size_t psasim_serialise_buffer_needs(const uint8_t *buffer, size_t buffer_size);
+
+/** Serialise a buffer.
+ *
+ * \param pos[in,out]        Pointer to a `uint8_t *` holding current position
+ *                           in the buffer.
+ * \param remaining[in,out]  Pointer to a `size_t` holding number of bytes
+ *                           remaining in the buffer.
+ * \param buffer             Pointer to the buffer to be serialised.
+ * \param buffer_length      Number of bytes in the buffer to be serialised.
+ *
+ * \return                   \c 1 on success ("okay"), \c 0 on error.
+ */
+int psasim_serialise_buffer(uint8_t **pos, size_t *remaining,
+                            const uint8_t *buffer, size_t buffer_length);
+
+/** Deserialise a buffer.
+ *
+ * \param pos[in,out]        Pointer to a `uint8_t *` holding current position
+ *                           in the serialisation buffer.
+ * \param remaining[in,out]  Pointer to a `size_t` holding number of bytes
+ *                           remaining in the serialisation buffer.
+ * \param buffer             Pointer to a `uint8_t *` to receive the address
+ *                           of a newly-allocated buffer, which the caller
+ *                           must `free()`.
+ * \param buffer_length      Pointer to a `size_t` to receive the number of
+ *                           bytes in the deserialised buffer.
+ *
+ * \return                   \c 1 on success ("okay"), \c 0 on error.
+ */
+int psasim_deserialise_buffer(uint8_t **pos, size_t *remaining,
+                              uint8_t **buffer, size_t *buffer_length);
+
+/** Deserialise a buffer returned from the server.
+ *
+ * When the client is deserialising a buffer returned from the server, it needs
+ * to use this function to deserialised the  returned buffer. It should use the
+ * usual \c psasim_serialise_buffer() function to serialise the outbound
+ * buffer.
+ *
+ * \param pos[in,out]        Pointer to a `uint8_t *` holding current position
+ *                           in the serialisation buffer.
+ * \param remaining[in,out]  Pointer to a `size_t` holding number of bytes
+ *                           remaining in the serialisation buffer.
+ * \param buffer             Pointer to a `uint8_t *` to receive the address
+ *                           of a newly-allocated buffer, which the caller
+ *                           must `free()`.
+ * \param buffer_length      Pointer to a `size_t` to receive the number of
+ *                           bytes in the deserialised buffer.
+ *
+ * \return                   \c 1 on success ("okay"), \c 0 on error.
+ */
+int psasim_deserialise_return_buffer(uint8_t **pos, size_t *remaining,
+                                     uint8_t *buffer, size_t buffer_length);
+EOF
+}
+
+sub h_header
+{
+    return <<'EOF';
+/**
+ * \file psa_sim_serialise.h
+ *
+ * \brief Rough-and-ready serialisation and deserialisation for the PSA Crypto simulator
+ */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "psa/crypto.h"
+#include "psa/crypto_types.h"
+#include "psa/crypto_values.h"
+
+/* Basic idea:
+ *
+ * All arguments to a function will be serialised into a single buffer to
+ * be sent to the server with the PSA crypto function to be called.
+ *
+ * All returned data (the function's return value and any values returned
+ * via `out` parameters) will similarly be serialised into a buffer to be
+ * sent back to the client from the server.
+ *
+ * For each data type foo (e.g. int, size_t, psa_algorithm_t, but also "buffer"
+ * where "buffer" is a (uint8_t *, size_t) pair, we have a pair of functions,
+ * psasim_serialise_foo() and psasim_deserialise_foo().
+ *
+ * We also have psasim_serialise_foo_needs() functions, which return a
+ * size_t giving the number of bytes that serialising that instance of that
+ * type will need. This allows callers to size buffers for serialisation.
+ *
+ * Each serialised buffer starts with a version byte, bytes that indicate
+ * the size of basic C types, and four bytes that indicate the endianness
+ * (to avoid incompatibilities if we ever run this over a network - we are
+ * not aiming for universality, just for correctness and simplicity).
+ *
+ * Most types are serialised as a fixed-size (per type) octet string, with
+ * no type indication. This is acceptable as (a) this is for the test PSA crypto
+ * simulator only, not production, and (b) these functions are called by
+ * code that itself is written by script.
+ *
+ * We also want to keep serialised data reasonably compact as communication
+ * between client and server goes in messages of less than 200 bytes each.
+ *
+ * Many serialisation functions can be created by a script; an exemplar Perl
+ * script is included. It is not hooked into the build and so must be run
+ * manually, but is expected to be replaced by a Python script in due course.
+ * Types that can have their functions created by script include plain old C
+ * data types (e.g. int), types typedef'd to those, and even structures that
+ * don't contain pointers.
+ */
+
+/** Reset all operation slots.
+ *
+ * Should be called when all clients have disconnected.
+ */
+void psa_sim_serialize_reset(void);
+
+/** Return how much buffer space is needed by \c psasim_serialise_begin().
+ *
+ * \return                   The number of bytes needed in the buffer for
+ *                           \c psasim_serialise_begin()'s output.
+ */
+size_t psasim_serialise_begin_needs(void);
+
+/** Begin serialisation into a buffer.
+ *
+ *                           This must be the first serialisation API called
+ *                           on a buffer.
+ *
+ * \param pos[in,out]        Pointer to a `uint8_t *` holding current position
+ *                           in the buffer.
+ * \param remaining[in,out]  Pointer to a `size_t` holding number of bytes
+ *                           remaining in the buffer.
+ *
+ * \return                   \c 1 on success ("okay"), \c 0 on error (likely
+ *                           no space).
+ */
+int psasim_serialise_begin(uint8_t **pos, size_t *remaining);
+
+/** Begin deserialisation of a buffer.
+ *
+ *                           This must be the first deserialisation API called
+ *                           on a buffer.
+ *
+ * \param pos[in,out]        Pointer to a `uint8_t *` holding current position
+ *                           in the buffer.
+ * \param remaining[in,out]  Pointer to a `size_t` holding number of bytes
+ *                           remaining in the buffer.
+ *
+ * \return                   \c 1 on success ("okay"), \c 0 on error.
+ */
+int psasim_deserialise_begin(uint8_t **pos, size_t *remaining);
+EOF
+}
+
+sub define_needs
+{
+    my ($type) = @_;
+
+    my $type_d = $type;
+    $type_d =~ s/ /_/g;
+
+    return <<EOF;
+
+size_t psasim_serialise_${type_d}_needs(
+    $type value)
+{
+    return sizeof(value);
+}
+EOF
+}
+
+sub define_server_needs
+{
+    my ($type) = @_;
+
+    my $type_d = $type;
+    $type_d =~ s/ /_/g;
+
+    return <<EOF;
+
+size_t psasim_server_serialise_${type_d}_needs(
+    $type *operation)
+{
+    (void) operation;
+
+    /* We will actually return a handle */
+    return sizeof(psasim_operation_t);
+}
+EOF
+}
+
+sub define_needs_isa
+{
+    my ($type, $isa) = @_;
+
+    my $type_d = $type;
+    $type_d =~ s/ /_/g;
+
+    my $isa_d = $isa;
+    $isa_d =~ s/ /_/g;
+
+    return <<EOF;
+
+size_t psasim_serialise_${type_d}_needs(
+    $type value)
+{
+    return psasim_serialise_${isa_d}_needs(value);
+}
+EOF
+}
+
+sub define_serialise
+{
+    my ($type) = @_;
+
+    my $type_d = $type;
+    $type_d =~ s/ /_/g;
+
+    return align_signature(<<EOF);
+
+int psasim_serialise_$type_d(uint8_t **pos,
+                             size_t *remaining,
+                             $type value)
+{
+    if (*remaining < sizeof(value)) {
+        return 0;
+    }
+
+    memcpy(*pos, &value, sizeof(value));
+    *pos += sizeof(value);
+
+    return 1;
+}
+EOF
+}
+
+sub define_server_serialise
+{
+    my ($type) = @_;
+
+    my $t;
+    if ($type =~ /^psa_(\w+)_operation_t$/) {
+        $t = $1;
+    } else {
+        die("$0: define_server_serialise: $type: not supported\n");
+    }
+
+    my $type_d = $type;
+    $type_d =~ s/ /_/g;
+
+    return align_signature(<<EOF);
+
+int psasim_server_serialise_$type_d(uint8_t **pos,
+                             size_t *remaining,
+                             $type *operation,
+                             int completed)
+{
+    psasim_operation_t client_operation;
+
+    if (*remaining < sizeof(client_operation)) {
+        return 0;
+    }
+
+    ssize_t slot = operation - ${t}_operations;
+
+    if (completed) {
+        memset(&${t}_operations[slot],
+               0,
+               sizeof($type_d));
+        ${t}_operation_handles[slot] = 0;
+    }
+
+    client_operation.handle = ${t}_operation_handles[slot];
+
+    memcpy(*pos, &client_operation, sizeof(client_operation));
+    *pos += sizeof(client_operation);
+
+    return 1;
+}
+EOF
+}
+
+sub define_serialise_isa
+{
+    my ($type, $isa) = @_;
+
+    my $type_d = $type;
+    $type_d =~ s/ /_/g;
+
+    my $isa_d = $isa;
+    $isa_d =~ s/ /_/g;
+
+    return align_signature(<<EOF);
+
+int psasim_serialise_$type_d(uint8_t **pos,
+                             size_t *remaining,
+                             $type value)
+{
+    return psasim_serialise_$isa_d(pos, remaining, value);
+}
+EOF
+}
+
+sub define_deserialise
+{
+    my ($type) = @_;
+
+    my $type_d = $type;
+    $type_d =~ s/ /_/g;
+
+    return align_signature(<<EOF);
+
+int psasim_deserialise_$type_d(uint8_t **pos,
+                               size_t *remaining,
+                               $type *value)
+{
+    if (*remaining < sizeof(*value)) {
+        return 0;
+    }
+
+    memcpy(value, *pos, sizeof(*value));
+
+    *pos += sizeof(*value);
+    *remaining -= sizeof(*value);
+
+    return 1;
+}
+EOF
+}
+
+sub define_server_deserialise
+{
+    my ($type) = @_;
+
+    my $t;
+    if ($type =~ /^psa_(\w+)_operation_t$/) {
+        $t = $1;
+    } else {
+        die("$0: define_server_deserialise: $type: not supported\n");
+    }
+
+    my $type_d = $type;
+    $type_d =~ s/ /_/g;
+
+    return align_signature(<<EOF);
+
+int psasim_server_deserialise_$type_d(uint8_t **pos,
+                               size_t *remaining,
+                               $type **operation)
+{
+    psasim_operation_t client_operation;
+
+    if (*remaining < sizeof(psasim_operation_t)) {
+        return 0;
+    }
+
+    memcpy(&client_operation, *pos, sizeof(psasim_operation_t));
+    *pos += sizeof(psasim_operation_t);
+    *remaining -= sizeof(psasim_operation_t);
+
+    ssize_t slot;
+    if (client_operation.handle == 0) {         /* We need a new handle */
+        slot = allocate_${t}_operation_slot();
+    } else {
+        slot = find_${t}_slot_by_handle(client_operation.handle);
+    }
+
+    if (slot < 0) {
+        return 0;
+    }
+
+    *operation = &${t}_operations[slot];
+
+    return 1;
+}
+EOF
+}
+
+sub define_deserialise_isa
+{
+    my ($type, $isa) = @_;
+
+    my $type_d = $type;
+    $type_d =~ s/ /_/g;
+
+    my $isa_d = $isa;
+    $isa_d =~ s/ /_/g;
+
+    return align_signature(<<EOF);
+
+int psasim_deserialise_$type_d(uint8_t **pos,
+                              size_t *remaining,
+                              $type *value)
+{
+    return psasim_deserialise_$isa_d(pos, remaining, value);
+}
+EOF
+}
+
+sub define_buffer_functions
+{
+    return <<'EOF';
+
+size_t psasim_serialise_buffer_needs(const uint8_t *buffer, size_t buffer_size)
+{
+    (void) buffer;
+    return sizeof(buffer_size) + buffer_size;
+}
+
+int psasim_serialise_buffer(uint8_t **pos,
+                            size_t *remaining,
+                            const uint8_t *buffer,
+                            size_t buffer_length)
+{
+    if (*remaining < sizeof(buffer_length) + buffer_length) {
+        return 0;
+    }
+
+    memcpy(*pos, &buffer_length, sizeof(buffer_length));
+    *pos += sizeof(buffer_length);
+
+    if (buffer_length > 0) {    // To be able to serialise (NULL, 0)
+        memcpy(*pos, buffer, buffer_length);
+        *pos += buffer_length;
+    }
+
+    return 1;
+}
+
+int psasim_deserialise_buffer(uint8_t **pos,
+                              size_t *remaining,
+                              uint8_t **buffer,
+                              size_t *buffer_length)
+{
+    if (*remaining < sizeof(*buffer_length)) {
+        return 0;
+    }
+
+    memcpy(buffer_length, *pos, sizeof(*buffer_length));
+
+    *pos += sizeof(buffer_length);
+    *remaining -= sizeof(buffer_length);
+
+    if (*buffer_length == 0) {          // Deserialise (NULL, 0)
+        *buffer = NULL;
+        return 1;
+    }
+
+    if (*remaining < *buffer_length) {
+        return 0;
+    }
+
+    uint8_t *data = malloc(*buffer_length);
+    if (data == NULL) {
+        return 0;
+    }
+
+    memcpy(data, *pos, *buffer_length);
+    *pos += *buffer_length;
+    *remaining -= *buffer_length;
+
+    *buffer = data;
+
+    return 1;
+}
+
+/* When the client is deserialising a buffer returned from the server, it needs
+ * to use this function to deserialised the  returned buffer. It should use the
+ * usual \c psasim_serialise_buffer() function to serialise the outbound
+ * buffer. */
+int psasim_deserialise_return_buffer(uint8_t **pos,
+                                     size_t *remaining,
+                                     uint8_t *buffer,
+                                     size_t buffer_length)
+{
+    if (*remaining < sizeof(buffer_length)) {
+        return 0;
+    }
+
+    size_t length_check;
+
+    memcpy(&length_check, *pos, sizeof(buffer_length));
+
+    *pos += sizeof(buffer_length);
+    *remaining -= sizeof(buffer_length);
+
+    if (buffer_length != length_check) {        // Make sure we're sent back the same we sent to the server
+        return 0;
+    }
+
+    if (length_check == 0) {          // Deserialise (NULL, 0)
+        return 1;
+    }
+
+    if (*remaining < buffer_length) {
+        return 0;
+    }
+
+    memcpy(buffer, *pos, buffer_length);
+    *pos += buffer_length;
+    *remaining -= buffer_length;
+
+    return 1;
+}
+EOF
+}
+
+
+sub c_header
+{
+    return <<'EOF';
+/**
+ * \file psa_sim_serialise.c
+ *
+ * \brief Rough-and-ready serialisation and deserialisation for the PSA Crypto simulator
+ */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "psa_sim_serialise.h"
+#include "util.h"
+#include <stdlib.h>
+#include <string.h>
+
+/* Basic idea:
+ *
+ * All arguments to a function will be serialised into a single buffer to
+ * be sent to the server with the PSA crypto function to be called.
+ *
+ * All returned data (the function's return value and any values returned
+ * via `out` parameters) will similarly be serialised into a buffer to be
+ * sent back to the client from the server.
+ *
+ * For each data type foo (e.g. int, size_t, psa_algorithm_t, but also "buffer"
+ * where "buffer" is a (uint8_t *, size_t) pair, we have a pair of functions,
+ * psasim_serialise_foo() and psasim_deserialise_foo().
+ *
+ * We also have psasim_serialise_foo_needs() functions, which return a
+ * size_t giving the number of bytes that serialising that instance of that
+ * type will need. This allows callers to size buffers for serialisation.
+ *
+ * Each serialised buffer starts with a version byte, bytes that indicate
+ * the size of basic C types, and four bytes that indicate the endianness
+ * (to avoid incompatibilities if we ever run this over a network - we are
+ * not aiming for universality, just for correctness and simplicity).
+ *
+ * Most types are serialised as a fixed-size (per type) octet string, with
+ * no type indication. This is acceptable as (a) this is for the test PSA crypto
+ * simulator only, not production, and (b) these functions are called by
+ * code that itself is written by script.
+ *
+ * We also want to keep serialised data reasonably compact as communication
+ * between client and server goes in messages of less than 200 bytes each.
+ *
+ * Many serialisation functions can be created by a script; an exemplar Perl
+ * script is included. It is not hooked into the build and so must be run
+ * manually, but is expected to be replaced by a Python script in due course.
+ * Types that can have their functions created by script include plain old C
+ * data types (e.g. int), types typedef'd to those, and even structures that
+ * don't contain pointers.
+ */
+EOF
+}
+
+sub c_define_types_for_operation_types
+{
+    return <<'EOF';
+
+/* include/psa/crypto_platform.h:typedef uint32_t mbedtls_psa_client_handle_t;
+ * but we don't get it on server builds, so redefine it here with a unique type name
+ */
+typedef uint32_t psasim_client_handle_t;
+
+typedef struct psasim_operation_s {
+    psasim_client_handle_t handle;
+} psasim_operation_t;
+
+#define MAX_LIVE_HANDLES_PER_CLASS   100        /* this many slots */
+EOF
+}
+
+sub define_operation_type_data_and_functions
+{
+    my ($type) = @_;    # e.g. 'hash' rather than 'psa_hash_operation_t'
+
+    my $utype = ucfirst($type);
+
+    return <<EOF;
+
+static psa_${type}_operation_t ${type}_operations[
+    MAX_LIVE_HANDLES_PER_CLASS];
+static psasim_client_handle_t ${type}_operation_handles[
+    MAX_LIVE_HANDLES_PER_CLASS];
+static psasim_client_handle_t next_${type}_operation_handle = 1;
+
+/* Get a free slot */
+static ssize_t allocate_${type}_operation_slot(void)
+{
+    psasim_client_handle_t handle = next_${type}_operation_handle++;
+    if (next_${type}_operation_handle == 0) {      /* wrapped around */
+        FATAL("$utype operation handle wrapped");
+    }
+
+    for (ssize_t i = 0; i < MAX_LIVE_HANDLES_PER_CLASS; i++) {
+        if (${type}_operation_handles[i] == 0) {
+            ${type}_operation_handles[i] = handle;
+            return i;
+        }
+    }
+
+    ERROR("All slots are currently used. Unable to allocate a new one.");
+
+    return -1;  /* all in use */
+}
+
+/* Find the slot given the handle */
+static ssize_t find_${type}_slot_by_handle(psasim_client_handle_t handle)
+{
+    for (ssize_t i = 0; i < MAX_LIVE_HANDLES_PER_CLASS; i++) {
+        if (${type}_operation_handles[i] == handle) {
+            return i;
+        }
+    }
+
+    ERROR("Unable to find slot by handle %u", handle);
+
+    return -1;  /* not found */
+}
+EOF
+}
+
+sub c_define_begins
+{
+    return <<'EOF';
+
+size_t psasim_serialise_begin_needs(void)
+{
+    /* The serialisation buffer will
+     * start with a byte of 0 to indicate version 0,
+     * then have 1 byte each for length of int, long, void *,
+     * then have 4 bytes to indicate endianness. */
+    return 4 + sizeof(uint32_t);
+}
+
+int psasim_serialise_begin(uint8_t **pos, size_t *remaining)
+{
+    uint32_t endian = 0x1234;
+
+    if (*remaining < 4 + sizeof(endian)) {
+        return 0;
+    }
+
+    *(*pos)++ = 0;      /* version */
+    *(*pos)++ = (uint8_t) sizeof(int);
+    *(*pos)++ = (uint8_t) sizeof(long);
+    *(*pos)++ = (uint8_t) sizeof(void *);
+
+    memcpy(*pos, &endian, sizeof(endian));
+
+    *pos += sizeof(endian);
+
+    return 1;
+}
+
+int psasim_deserialise_begin(uint8_t **pos, size_t *remaining)
+{
+    uint8_t version = 255;
+    uint8_t int_size = 0;
+    uint8_t long_size = 0;
+    uint8_t ptr_size = 0;
+    uint32_t endian;
+
+    if (*remaining < 4 + sizeof(endian)) {
+        return 0;
+    }
+
+    memcpy(&version, (*pos)++, sizeof(version));
+    if (version != 0) {
+        return 0;
+    }
+
+    memcpy(&int_size, (*pos)++, sizeof(int_size));
+    if (int_size != sizeof(int)) {
+        return 0;
+    }
+
+    memcpy(&long_size, (*pos)++, sizeof(long_size));
+    if (long_size != sizeof(long)) {
+        return 0;
+    }
+
+    memcpy(&ptr_size, (*pos)++, sizeof(ptr_size));
+    if (ptr_size != sizeof(void *)) {
+        return 0;
+    }
+
+    *remaining -= 4;
+
+    memcpy(&endian, *pos, sizeof(endian));
+    if (endian != 0x1234) {
+        return 0;
+    }
+
+    *pos += sizeof(endian);
+    *remaining -= sizeof(endian);
+
+    return 1;
+}
+EOF
+}
+
+# Return the code for psa_sim_serialize_reset()
+sub define_server_serialize_reset
+{
+    my @types = @_;
+
+    my $code = <<EOF;
+
+void psa_sim_serialize_reset(void)
+{
+EOF
+
+    for my $type (@types) {
+        next unless $type =~ /^psa_(\w+_operation)_t$/;
+
+        my $what = $1;  # e.g. "hash_operation"
+
+        if (exists $type_guards{$type}) {
+            $code .= "#if $type_guards{$type}\n";
+        }
+        $code .= <<EOF;
+    memset(${what}_handles, 0,
+           sizeof(${what}_handles));
+    memset(${what}s, 0,
+           sizeof(${what}s));
+EOF
+        if (exists $type_guards{$type}) {
+            $code .= "#endif /* $type_guards{$type} */\n";
+        }
+    }
+
+    $code .= <<EOF;
+}
+EOF
+}
+
+# Horrible way to align first few lines of function signature to appease
+# uncrustify (these are usually the 2nd-4th lines of code, indices 1, 2 and 3)
+#
+sub align_signature
+{
+    my ($code) = @_;
+
+    my @code = split(/\n/, $code);
+
+    my $i = 1;
+    # Find where the ( is
+    my $idx = index($code[$i], "(");
+    die("can't find (") if $idx < 0;
+
+    my $indent = " " x ($idx + 1);
+
+    do {
+        # Indent each line up until the one that ends with )
+        $code[++$i] =~ s/^\s+/$indent/;
+    } while $code[$i] !~ /\)$/;
+
+    return join("\n", @code) . "\n";
+}
+
+# Horrible way to align the function declaration to appease uncrustify
+#
+sub align_declaration
+{
+    my ($code) = @_;
+
+    my @code = split(/\n/, $code);
+
+    # Find out which lines we need to massage
+    my $i;
+    for ($i = 0; $i <= $#code; $i++) {
+        last if $code[$i] =~ /^int psasim_/;
+    }
+    die("can't find int psasim_") if $i > $#code;
+
+    # Find where the ( is
+    my $idx = index($code[$i], "(");
+    die("can't find (") if $idx < 0;
+
+    my $indent = " " x ($idx + 1);
+    do {
+        # Indent each line up until the one with the ; on it
+        $code[++$i] =~ s/^\s+/$indent/;
+    } while ($code[$i] !~ /;/);
+
+    return join("\n", @code) . "\n";
+}
diff -Nru mbedtls-3.6.5/framework/psasim/src/server.c mbedtls-3.6.6/framework/psasim/src/server.c
--- mbedtls-3.6.5/framework/psasim/src/server.c	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/src/server.c	2026-03-27 12:34:57.776454400 +0200
@@ -0,0 +1,117 @@
+/* psasim test server */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+
+/* Includes from psasim */
+#include "service.h"
+#include "error_ext.h"
+#include "util.h"
+#include "psa_manifest/manifest.h"
+#include "psa_functions_codes.h"
+
+/* Includes from mbedtls */
+#include "mbedtls/version.h"
+#include "psa/crypto.h"
+
+#ifdef DEBUG
+#define SERVER_PRINT(fmt, ...) \
+    PRINT("Server: " fmt, ##__VA_ARGS__)
+#else
+#define SERVER_PRINT(...)
+#endif
+
+#define BUF_SIZE 25
+
+static int kill_on_disconnect = 0; /* Kill the server on client disconnection. */
+
+void parse_input_args(int argc, char *argv[])
+{
+    int opt;
+
+    while ((opt = getopt(argc, argv, "k")) != -1) {
+        switch (opt) {
+            case 'k':
+                kill_on_disconnect = 1;
+                break;
+            default:
+                fprintf(stderr, "Usage: %s [-k]\n", argv[0]);
+                exit(EXIT_FAILURE);
+        }
+    }
+}
+
+int psa_server_main(int argc, char *argv[])
+{
+    psa_status_t ret = PSA_ERROR_PROGRAMMER_ERROR;
+    psa_msg_t msg = { -1 };
+    const int magic_num = 66;
+    int client_disconnected = 0;
+    extern psa_status_t psa_crypto_call(psa_msg_t msg);
+    extern psa_status_t psa_crypto_close(void);
+
+#if defined(MBEDTLS_VERSION_C)
+    const char *mbedtls_version = mbedtls_version_get_string_full();
+    SERVER_PRINT("%s", mbedtls_version);
+#endif
+
+    parse_input_args(argc, argv);
+    SERVER_PRINT("Starting");
+
+    while (!(kill_on_disconnect && client_disconnected)) {
+        psa_signal_t signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
+
+        if (signals > 0) {
+            SERVER_PRINT("Signals: 0x%08x", signals);
+        }
+
+        if (signals & PSA_CRYPTO_SIGNAL) {
+            if (PSA_SUCCESS == psa_get(PSA_CRYPTO_SIGNAL, &msg)) {
+                SERVER_PRINT("handle: %d - rhandle: %p", msg.handle, (int *) msg.rhandle);
+                switch (msg.type) {
+                    case PSA_IPC_CONNECT:
+                        SERVER_PRINT("Got a connection message");
+                        psa_set_rhandle(msg.handle, (void *) &magic_num);
+                        ret = PSA_SUCCESS;
+                        break;
+                    case PSA_IPC_DISCONNECT:
+                        SERVER_PRINT("Got a disconnection message");
+                        ret = PSA_SUCCESS;
+                        client_disconnected = 1;
+                        psa_crypto_close();
+                        break;
+                    default:
+                        SERVER_PRINT("Got an IPC call of type %d", msg.type);
+                        ret = psa_crypto_call(msg);
+                        SERVER_PRINT("Internal function call returned %d", ret);
+
+                        if (msg.client_id > 0) {
+                            psa_notify(msg.client_id);
+                        } else {
+                            SERVER_PRINT("Client is non-secure, so won't notify");
+                        }
+                }
+
+                psa_reply(msg.handle, ret);
+            } else {
+                SERVER_PRINT("Failed to retrieve message");
+            }
+        } else if (SIGSTP_SIG & signals) {
+            SERVER_PRINT("Recieved SIGSTP signal. Gonna EOI it.");
+            psa_eoi(SIGSTP_SIG);
+        } else if (SIGINT_SIG & signals) {
+            SERVER_PRINT("Handling interrupt!");
+            SERVER_PRINT("Gracefully quitting");
+            psa_panic();
+        } else {
+            SERVER_PRINT("No signal asserted");
+        }
+    }
+
+    return 0;
+}
diff -Nru mbedtls-3.6.5/framework/psasim/src/service.c mbedtls-3.6.6/framework/psasim/src/service.c
--- mbedtls-3.6.5/framework/psasim/src/service.c	2025-10-01 18:24:20.267423200 +0300
+++ mbedtls-3.6.6/framework/psasim/src/service.c	1970-01-01 02:00:00.000000000 +0200
@@ -1,655 +0,0 @@
-/* PSA Firmware Framework service API */
-
-/*
- *  Copyright The Mbed TLS Contributors
- *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
- */
-
-#include <psa/service.h>
-#include <sys/types.h>
-#include <sys/ipc.h>
-#include <sys/msg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <strings.h>
-#include <unistd.h>
-#include <time.h>
-#include <assert.h>
-#include <psasim/init.h>
-#include "common.h"
-
-#define MAX_CLIENTS 128
-#define MAX_MESSAGES 32
-
-struct connection {
-    uint32_t client;
-    void *rhandle;
-    int client_to_server_q; // this should be called client to server
-};
-
-static psa_msg_t messages[MAX_MESSAGES]; /* Message slots */
-static uint8_t pending_message[MAX_MESSAGES] = { 0 }; /* Booleans indicating active message slots */
-static uint32_t message_client[MAX_MESSAGES] = { 0 }; /* Each client's response queue  */
-static int nsacl[32];
-static int strict_policy[32] = { 0 };
-static uint32_t rot_svc_versions[32];
-static int rot_svc_incoming_queue[32] = { -1 };
-static struct connection connections[MAX_CLIENTS] = { { 0 } };
-
-static uint32_t exposed_signals = 0;
-
-void print_vectors(vector_sizes_t *sizes)
-{
-    INFO("Printing iovec sizes");
-    for (int j = 0; j < PSA_MAX_IOVEC; j++) {
-        INFO("Invec  %d: %lu", j, sizes->invec_sizes[j]);
-    }
-
-    for (int j = 0; j < PSA_MAX_IOVEC; j++) {
-        INFO("Outvec %d: %lu", j, sizes->outvec_sizes[j]);
-    }
-}
-
-int find_connection(uint32_t client)
-{
-    for (int i = 1; i < MAX_CLIENTS; i++) {
-        if (client == connections[i].client) {
-            return i;
-        }
-    }
-    return -1;
-}
-
-void destroy_connection(uint32_t client)
-{
-    int idx = find_connection(client);
-    if (idx >= 0) {
-        connections[idx].client = 0;
-        connections[idx].rhandle = 0;
-        INFO("Destroying connection");
-    } else {
-        INFO("Couldn't destroy connection for %u", client);
-    }
-}
-
-int find_free_connection()
-{
-    INFO("Allocating connection");
-    return find_connection(0);
-}
-
-static void reply(psa_handle_t msg_handle, psa_status_t status)
-{
-    pending_message[msg_handle] = 1;
-    psa_reply(msg_handle, status);
-    pending_message[msg_handle] = 0;
-}
-
-psa_signal_t psa_wait(psa_signal_t signal_mask, uint32_t timeout)
-{
-
-    psa_signal_t mask;
-    struct message msg;
-    vector_sizes_t sizes;
-    struct msqid_ds qinfo;
-    uint32_t requested_version;
-    ssize_t len;
-    int idx;
-
-    if (timeout == PSA_POLL) {
-        INFO("psa_wait: Called in polling mode");
-    }
-
-    do {
-        mask = signal_mask;
-
-        /* Check the status of each queue */
-        for (int i = 0; i < 32; i++) {
-            if (mask & 0x1) {
-                if (i < 3) {
-                    // do nothing (reserved)
-                } else if (i == 3) {
-                    // this must be psa doorbell
-                } else {
-
-                    /* Check if this signal corresponds to a queue */
-                    if (rot_svc_incoming_queue[i] >= 0 && (pending_message[i] == 0)) {
-
-                        /* AFAIK there is no "peek" method in SysV, so try to get a message */
-                        len = msgrcv(rot_svc_incoming_queue[i],
-                                     &msg,
-                                     sizeof(struct message_text),
-                                     0,
-                                     IPC_NOWAIT);
-                        if (len > 0) {
-
-                            INFO("Storing that QID in message_client[%d]\n", i);
-                            INFO("The message handle will be %d\n", i);
-
-                            msgctl(rot_svc_incoming_queue[i], IPC_STAT, &qinfo);
-                            messages[i].client_id = qinfo.msg_lspid; /* PID of last msgsnd(2) call */
-                            message_client[i] = msg.message_text.qid;
-                            idx = find_connection(msg.message_text.qid);
-
-                            if (msg.message_type & NON_SECURE) {
-                                /* This is a non-secure message */
-
-                                /* Check if NS client is allowed for this RoT service */
-                                if (nsacl[i] <= 0) {
-#if 0
-                                    INFO(
-                                        "Rejecting non-secure client due to manifest security policy");
-                                    reply(i, PSA_ERROR_CONNECTION_REFUSED);
-                                    continue; /* Skip to next signal */
-#endif
-                                }
-
-                                msg.message_type &= ~(NON_SECURE); /* clear */
-                                messages[i].client_id = messages[i].client_id * -1;
-                            }
-
-                            INFO("Got a message from client ID %d\n", messages[i].client_id);
-                            INFO("Message type is %lu\n", msg.message_type);
-                            INFO("PSA message type is %d\n", msg.message_text.psa_type);
-
-                            messages[i].handle = i;
-
-                            switch (msg.message_text.psa_type) {
-                                case PSA_IPC_CONNECT:
-
-                                    if (len >= 16) {
-                                        memcpy(&requested_version, msg.message_text.buf,
-                                               sizeof(requested_version));
-                                        INFO("Requesting version %u\n", requested_version);
-                                        INFO("Implemented version %u\n", rot_svc_versions[i]);
-                                        /* TODO: need to check whether the policy is strict,
-                                         * and if so, then reject the client if the number doesn't match */
-
-                                        if (requested_version > rot_svc_versions[i]) {
-                                            INFO(
-                                                "Rejecting client because requested version that was too high");
-                                            reply(i, PSA_ERROR_CONNECTION_REFUSED);
-                                            continue; /* Skip to next signal */
-                                        }
-
-                                        if (strict_policy[i] == 1 &&
-                                            (requested_version != rot_svc_versions[i])) {
-                                            INFO(
-                                                "Rejecting client because enforcing a STRICT version policy");
-                                            reply(i, PSA_ERROR_CONNECTION_REFUSED);
-                                            continue; /* Skip to next signal */
-                                        } else {
-                                            INFO("Not rejecting client");
-                                        }
-                                    }
-
-                                    messages[i].type = PSA_IPC_CONNECT;
-
-                                    if (idx < 0) {
-                                        idx = find_free_connection();
-                                    }
-
-                                    if (idx >= 0) {
-                                        connections[idx].client = msg.message_text.qid;
-                                    } else {
-                                        /* We've run out of system wide connections */
-                                        reply(i, PSA_ERROR_CONNECTION_BUSY);
-                                        INFO("Ran out of free connections");
-                                        continue;
-                                    }
-
-                                    break;
-                                case PSA_IPC_DISCONNECT:
-                                    messages[i].type = PSA_IPC_DISCONNECT;
-                                    break;
-                                case VERSION_REQUEST:
-                                    INFO("Got a version request");
-                                    reply(i, rot_svc_versions[i]);
-                                    continue; /* Skip to next signal */
-                                    break;
-
-                                default:
-
-                                    /* PSA CALL */
-                                    if (msg.message_text.psa_type >= 0) {
-                                        messages[i].type = msg.message_text.psa_type;
-                                        memcpy(&sizes, msg.message_text.buf, sizeof(sizes));
-                                        print_vectors(&sizes);
-                                        memcpy(&messages[i].in_size, &sizes.invec_sizes,
-                                               (sizeof(size_t) * PSA_MAX_IOVEC));
-                                        memcpy(&messages[i].out_size, &sizes.outvec_sizes,
-                                               (sizeof(size_t) * PSA_MAX_IOVEC));
-                                    } else {
-                                        FATAL("UNKNOWN MESSAGE TYPE RECEIVED %li\n",
-                                              msg.message_type);
-                                    }
-                                    break;
-                            }
-                            messages[i].handle = i;
-
-                            /* Check if the client has a connection */
-                            if (idx >= 0) {
-                                messages[i].rhandle = connections[idx].rhandle;
-                            } else {
-                                /* Client is begging for a programmer error */
-                                reply(i, PSA_ERROR_PROGRAMMER_ERROR);
-                                continue;
-                            }
-
-                            /* House keeping */
-                            pending_message[i] = 1; /* set message as pending */
-                            exposed_signals |= (0x1 << i); /* assert the signal */
-                        }
-                    }
-                }
-                mask = mask >> 1;
-            }
-        }
-
-        if ((timeout == PSA_BLOCK) && (exposed_signals > 0)) {
-            break;
-        } else {
-            /* There is no 'select' function in SysV to block on multiple queues, so busy-wait :( */
-            usleep(50000);
-        }
-    } while (timeout == PSA_BLOCK);
-
-    INFO("\n");
-
-    /* Assert signals */
-    return signal_mask & exposed_signals;
-}
-
-static int signal_to_index(psa_signal_t signal)
-{
-
-    int i;
-    int count = 0;
-    int ret = -1;
-
-    for (i = 0; i < 32; i++) {
-        if (signal & 0x1) {
-            ret = i;
-            count++;
-        }
-        signal = signal >> 1;
-    }
-
-    if (count > 1) {
-        INFO("ERROR: Too many signals");
-        return -1; /* Too many signals */
-    }
-    return ret;
-}
-
-static void clear_signal(psa_signal_t signal)
-{
-    exposed_signals = exposed_signals & ~signal;
-}
-
-void raise_signal(psa_signal_t signal)
-{
-    exposed_signals |= signal;
-}
-
-psa_status_t psa_get(psa_signal_t signal, psa_msg_t *msg)
-{
-    int index = signal_to_index(signal);
-    if (index < 0) {
-        PROGRAMMER_ERROR("Bad signal\n");
-    }
-
-    clear_signal(signal);
-
-    assert(messages[index].handle != 0);
-
-    if (pending_message[index] == 1) {
-        INFO("There is a pending message!");
-        memcpy(msg, &messages[index], sizeof(struct psa_msg_t));
-        assert(msg->handle != 0);
-        return PSA_SUCCESS;
-    } else {
-        INFO("no pending message");
-    }
-
-    return PSA_ERROR_DOES_NOT_EXIST;
-}
-
-static int is_valid_msg_handle(psa_handle_t h)
-{
-    if (h > 0 && h < MAX_MESSAGES) {
-        return 1;
-    }
-    PROGRAMMER_ERROR("Not a valid message handle");
-}
-
-static inline int is_call_msg(psa_handle_t h)
-{
-    assert(messages[h].type >= PSA_IPC_CALL);
-    return 1;
-}
-
-void psa_set_rhandle(psa_handle_t msg_handle, void *rhandle)
-{
-    is_valid_msg_handle(msg_handle);
-    int idx = find_connection(message_client[msg_handle]);
-    INFO("Setting rhandle to %p", rhandle);
-    assert(idx >= 0);
-    connections[idx].rhandle = rhandle;
-}
-
-/* Sends a message from the server to the client. Does not wait for a response */
-static void send_msg(psa_handle_t msg_handle,
-                     int ctrl_msg,
-                     psa_status_t status,
-                     size_t amount,
-                     const void *data,
-                     size_t data_amount)
-{
-
-    struct message response;
-    int flags = 0;
-
-    assert(ctrl_msg > 0); /* According to System V, it must be greater than 0 */
-
-    response.message_type = ctrl_msg;
-    if (ctrl_msg == PSA_REPLY) {
-        memcpy(response.message_text.buf, &status, sizeof(psa_status_t));
-    } else if (ctrl_msg == READ_REQUEST || ctrl_msg == WRITE_REQUEST || ctrl_msg == SKIP_REQUEST) {
-        memcpy(response.message_text.buf, &status, sizeof(psa_status_t));
-        memcpy(response.message_text.buf+sizeof(size_t), &amount, sizeof(size_t));
-        if (ctrl_msg == WRITE_REQUEST) {
-            /* TODO: Check if too big */
-            memcpy(response.message_text.buf + (sizeof(size_t) * 2), data, data_amount);
-        }
-    }
-
-    /* TODO: sizeof doesn't need to be so big here for small responses */
-    if (msgsnd(message_client[msg_handle], &response, sizeof(response.message_text), flags) == -1) {
-        INFO("Failed to reply");
-    }
-}
-
-static size_t skip(psa_handle_t msg_handle, uint32_t invec_idx, size_t num_bytes)
-{
-    if (num_bytes < (messages[msg_handle].in_size[invec_idx] - num_bytes)) {
-        messages[msg_handle].in_size[invec_idx] = messages[msg_handle].in_size[invec_idx] -
-                                                  num_bytes;
-        return num_bytes;
-    } else {
-        if (num_bytes >= messages[msg_handle].in_size[invec_idx]) {
-            size_t ret = messages[msg_handle].in_size[invec_idx];
-            messages[msg_handle].in_size[invec_idx] = 0;
-            return ret;
-        } else {
-            return num_bytes;
-        }
-    }
-}
-
-size_t psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
-                void *buffer, size_t num_bytes)
-{
-    size_t sofar = 0;
-    struct message msg = { 0 };
-    int idx;
-    ssize_t len;
-
-    is_valid_msg_handle(msg_handle);
-    is_call_msg(msg_handle);
-
-    if (invec_idx >= PSA_MAX_IOVEC) {
-        PROGRAMMER_ERROR("Invalid iovec number");
-    }
-
-    /* If user wants more data than what's available, truncate their request */
-    if (num_bytes > messages[msg_handle].in_size[invec_idx]) {
-        num_bytes = messages[msg_handle].in_size[invec_idx];
-    }
-
-    while (sofar < num_bytes) {
-        INFO("Server: requesting %lu bytes from client\n", (num_bytes - sofar));
-        send_msg(msg_handle, READ_REQUEST, invec_idx, (num_bytes - sofar), NULL, 0);
-
-        idx = find_connection(message_client[msg_handle]);
-        assert(idx >= 0);
-
-        len = msgrcv(connections[idx].client_to_server_q, &msg, sizeof(struct message_text), 0, 0);
-        len = (len - sizeof(msg.message_text.qid));
-
-        if (len < 0) {
-            FATAL("Internal error: failed to dispatch read request to the client");
-        }
-
-        if (len > (num_bytes - sofar)) {
-            if ((num_bytes - sofar) > 0) {
-                memcpy(buffer+sofar, msg.message_text.buf, (num_bytes - sofar));
-            }
-        } else {
-            memcpy(buffer + sofar, msg.message_text.buf, len);
-        }
-
-        INFO("Printing what i got so far: %s\n", msg.message_text.buf);
-
-        sofar = sofar + len;
-    }
-
-    /* Update the seek count */
-    skip(msg_handle, invec_idx, num_bytes);
-    INFO("Finished psa_read");
-    return sofar;
-}
-
-void psa_write(psa_handle_t msg_handle, uint32_t outvec_idx,
-               const void *buffer, size_t num_bytes)
-{
-
-    size_t sofar = 0;
-    struct message msg = { 0 };
-    int idx;
-    ssize_t len;
-
-    is_valid_msg_handle(msg_handle);
-    is_call_msg(msg_handle);
-
-    if (outvec_idx >= PSA_MAX_IOVEC) {
-        PROGRAMMER_ERROR("Invalid iovec number");
-    }
-
-    if (num_bytes > messages[msg_handle].out_size[outvec_idx]) {
-        PROGRAMMER_ERROR("Program tried to write too much data %lu/%lu", num_bytes,
-                         messages[msg_handle].out_size[outvec_idx]);
-    }
-
-    while (sofar < num_bytes) {
-        size_t sending = (num_bytes - sofar);
-        if (sending >= MAX_FRAGMENT_SIZE) {
-            sending = MAX_FRAGMENT_SIZE - (sizeof(size_t) * 2);
-        }
-
-        INFO("Server: sending %lu bytes to client\n", sending);
-
-        send_msg(msg_handle, WRITE_REQUEST, outvec_idx, sending, buffer, sending);
-
-        idx = find_connection(message_client[msg_handle]);
-        assert(idx >= 0);
-
-        len = msgrcv(connections[idx].client_to_server_q, &msg, sizeof(struct message_text), 0, 0);
-        if (len < 1) {
-            FATAL("Client didn't give me a full response");
-        }
-        sofar = sofar + len;
-    }
-
-    /* Update the seek count */
-    messages[msg_handle].out_size[outvec_idx] -= num_bytes;
-}
-
-size_t psa_skip(psa_handle_t msg_handle, uint32_t invec_idx, size_t num_bytes)
-{
-
-    is_valid_msg_handle(msg_handle);
-    is_call_msg(msg_handle);
-
-    size_t ret = skip(msg_handle, invec_idx, num_bytes);
-
-    /* notify client to skip */
-    send_msg(msg_handle, SKIP_REQUEST, invec_idx, num_bytes, NULL, 0);
-    return ret;
-}
-
-static void destroy_temporary_queue(int myqid)
-{
-
-    if (msgctl(myqid, IPC_RMID, NULL) != 0) {
-        INFO("ERROR: Failed to delete msg queue %d", myqid);
-    }
-}
-
-static int make_temporary_queue()
-{
-    int myqid;
-    if ((myqid = msgget(IPC_PRIVATE, 0660)) == -1) {
-        INFO("msgget: myqid");
-        return -1;
-    }
-    return myqid;
-}
-
-/**
- * Assumes msg_handle is the index into the message array
- */
-void psa_reply(psa_handle_t msg_handle, psa_status_t status)
-{
-    int idx, q;
-    is_valid_msg_handle(msg_handle);
-
-    if (pending_message[msg_handle] != 1) {
-        PROGRAMMER_ERROR("Not a valid message handle");
-    }
-
-    if (messages[msg_handle].type == PSA_IPC_CONNECT) {
-        switch (status) {
-            case PSA_SUCCESS:
-                idx = find_connection(message_client[msg_handle]);
-                q = make_temporary_queue();
-                if (q > 0 && idx >= 0) {
-                    connections[idx].client_to_server_q = q;
-                    status = q;
-                } else {
-                    FATAL("What happened?");
-                }
-                break;
-            case PSA_ERROR_CONNECTION_REFUSED:
-                destroy_connection(message_client[msg_handle]);
-                break;
-            case PSA_ERROR_CONNECTION_BUSY:
-                destroy_connection(message_client[msg_handle]);
-                break;
-            case PSA_ERROR_PROGRAMMER_ERROR:
-                destroy_connection(message_client[msg_handle]);
-                break;
-            default:
-                PROGRAMMER_ERROR("Not a valid reply %d\n", status);
-        }
-    } else if (messages[msg_handle].type == PSA_IPC_DISCONNECT) {
-        idx = find_connection(message_client[msg_handle]);
-        if (idx >= 0) {
-            destroy_temporary_queue(connections[idx].client_to_server_q);
-        }
-        destroy_connection(message_client[msg_handle]);
-    }
-
-    send_msg(msg_handle, PSA_REPLY, status, 0, NULL, 0);
-
-    pending_message[msg_handle] = 0;
-    message_client[msg_handle] = 0;
-}
-
-/* TODO: make sure you only clear interrupt signals, and not others */
-void psa_eoi(psa_signal_t signal)
-{
-    int index = signal_to_index(signal);
-    if (index >= 0 && (rot_svc_incoming_queue[index] >= 0)) {
-        clear_signal(signal);
-    } else {
-        PROGRAMMER_ERROR("Tried to EOI a signal that isn't an interrupt");
-    }
-}
-
-void psa_notify(int32_t partition_id)
-{
-    char pathname[PATHNAMESIZE] = { 0 };
-
-    if (partition_id < 0) {
-        PROGRAMMER_ERROR("Not a valid secure partition");
-    }
-
-    snprintf(pathname, PATHNAMESIZE, "/tmp/psa_notify_%u", partition_id);
-    INFO("psa_notify: notifying partition %u using %s",
-         partition_id, pathname);
-    INFO("psa_notify is unimplemented");
-}
-
-void psa_clear(void)
-{
-    clear_signal(PSA_DOORBELL);
-}
-
-void __init_psasim(const char **array,
-                   int size,
-                   const int allow_ns_clients_array[32],
-                   const uint32_t versions[32],
-                   const int strict_policy_array[32])
-{
-
-    static uint8_t library_initialised = 0;
-    key_t key;
-    int qid;
-    FILE *fp;
-    char doorbell_path[PATHNAMESIZE] = { 0 };
-    snprintf(doorbell_path, PATHNAMESIZE, "/tmp/psa_notify_%u", getpid());
-
-    if (library_initialised > 0) {
-        return;
-    } else {
-        library_initialised = 1;
-    }
-
-    if (size != 32) {
-        FATAL("Unsupported value. Aborting.");
-    }
-
-    array[3] = doorbell_path;
-
-    for (int i = 0; i < 32; i++) {
-        if (strncmp(array[i], "", 1) != 0) {
-            INFO("Setting up %s", array[i]);
-
-            /* Create file if doesn't exist */
-            fp = fopen(array[i], "ab+");
-            if (fp) {
-                fclose(fp);
-            }
-
-            if ((key = ftok(array[i], PROJECT_ID)) == -1) {
-                FATAL("Error finding message queue during initialisation");
-            }
-
-            /* TODO: Investigate. Permissions are likely to be too relaxed */
-            if ((qid = msgget(key, IPC_CREAT | 0660)) == -1) {
-                FATAL("Error opening message queue during initialisation");
-            } else {
-                rot_svc_incoming_queue[i] = qid;
-            }
-        }
-    }
-
-    memcpy(nsacl, allow_ns_clients_array, sizeof(int) * 32);
-    memcpy(strict_policy, strict_policy_array, sizeof(int) * 32);
-    memcpy(rot_svc_versions, versions, sizeof(uint32_t) * 32);
-    bzero(&connections, sizeof(struct connection) * MAX_CLIENTS);
-
-    __psa_ff_client_security_state = 0; /* Set the client status to SECURE */
-}
diff -Nru mbedtls-3.6.5/framework/psasim/test/client.c mbedtls-3.6.6/framework/psasim/test/client.c
--- mbedtls-3.6.5/framework/psasim/test/client.c	2025-10-01 18:24:20.267764600 +0300
+++ mbedtls-3.6.6/framework/psasim/test/client.c	1970-01-01 02:00:00.000000000 +0200
@@ -1,48 +0,0 @@
-/* psasim test client */
-
-/*
- *  Copyright The Mbed TLS Contributors
- *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
- */
-
-#include <psa/client.h>
-#include "psa_manifest/sid.h"
-#include <stdio.h>
-#include <unistd.h>
-
-int main()
-{
-
-    const char *text = "FOOBARCOOL!!";
-
-    char output[100] = { 0 };
-    printf("My PID is %d\n", getpid());
-
-    printf("The version of the service is %u\n", psa_version(PSA_SID_SHA256_SID));
-    psa_handle_t h = psa_connect(PSA_SID_SHA256_SID, 1);
-
-    if (h < 0) {
-        printf("Couldn't connect %d\n", h);
-        return 1;
-    } else {
-        int type = 2;
-        puts("Calling!");
-        puts("Trying without invec");
-        printf("Answer to my call was %d (no invec)\n", psa_call(h, type, NULL, 0, NULL, 0));
-        psa_invec invecs[1];
-        psa_outvec outvecs[1];
-        invecs[0].base = text;
-        invecs[0].len = 24;
-        outvecs[0].base = output;
-        outvecs[0].len = 99;
-
-        printf("My iovec size should be %lu\n", invecs[0].len);
-        printf("Answer to my call was %d (with invec)\n", psa_call(h, type, invecs, 1, outvecs, 1));
-        printf("Here's the payload I recieved: %s\n", output);
-        printf("Apparently the server wrote %lu bytes in outvec %d\n", outvecs[0].len, 0);
-        puts("Closing handle");
-        psa_close(h);
-    }
-
-    return 0;
-}
diff -Nru mbedtls-3.6.5/framework/psasim/test/kill_servers.sh mbedtls-3.6.6/framework/psasim/test/kill_servers.sh
--- mbedtls-3.6.5/framework/psasim/test/kill_servers.sh	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/test/kill_servers.sh	2026-03-27 12:34:57.776563200 +0200
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+set -e
+
+pkill psa_server || true
+
+# Remove temporary files
+rm -f psa_notify_*
+
+# Remove all IPCs
+# Not just ipcrm -all=msg as it is not supported on macOS.
+# Filter out header and empty lines, choosing to select based on keys being
+# output in hex.
+ipcs -q | fgrep 0x | awk '{ printf " -q " $2 }' | xargs ipcrm > /dev/null 2>&1 || true
diff -Nru mbedtls-3.6.5/framework/psasim/test/Makefile mbedtls-3.6.6/framework/psasim/test/Makefile
--- mbedtls-3.6.5/framework/psasim/test/Makefile	2025-10-01 18:24:20.267669200 +0300
+++ mbedtls-3.6.6/framework/psasim/test/Makefile	1970-01-01 02:00:00.000000000 +0200
@@ -1,12 +0,0 @@
-INCLUDE := -I../include/ -I./psa_manifest
-
-.PHONY: all clean
-
-all:
-	psa_autogen manifest.json
-	$(CC) psa_ff_bootstrap_TEST_PARTITION.c -lpsaff -o partition
-	$(CC) client.c -lpsaff -o client
-
-clean:
-	rm -rf psa_manifest
-	rm -f client partition psa_ff_bootstrap_TEST_PARTITION.c
diff -Nru mbedtls-3.6.5/framework/psasim/test/manifest.json mbedtls-3.6.6/framework/psasim/test/manifest.json
--- mbedtls-3.6.5/framework/psasim/test/manifest.json	2025-10-01 18:24:20.267844000 +0300
+++ mbedtls-3.6.6/framework/psasim/test/manifest.json	1970-01-01 02:00:00.000000000 +0200
@@ -1,29 +0,0 @@
-{
-   "psa_framework_version":1.0,
-   "name":"TEST_PARTITION",
-   "type":"PSA-ROT",
-   "priority":"LOW",
-   "entry_point":"psa_sha256_main",
-   "stack_size":"0x400",
-   "heap_size":"0x100",
-   "services":[
-      {
-         "name":"PSA_SID_SHA256",
-         "sid":"0x0000F000",
-         "signal":"PSA_SHA256",
-         "non_secure_clients": "true",
-         "minor_version":1,
-         "minor_policy":"STRICT"
-      }
-   ],
-   "irqs": [
-        {
-                "source": "SIGINT",
-                "signal": "SIGINT_SIG"
-        },
-        {
-                "source": "SIGTSTP",
-                "signal": "SIGSTP_SIG"
-        }
-   ]
-}
diff -Nru mbedtls-3.6.5/framework/psasim/test/run_test.sh mbedtls-3.6.6/framework/psasim/test/run_test.sh
--- mbedtls-3.6.5/framework/psasim/test/run_test.sh	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/test/run_test.sh	2026-03-27 12:34:57.776635600 +0200
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+# This is a simple bash script that tests psa_client/psa_server interaction.
+# This script is automatically executed when "make run" is launched by the
+# "psasim" root folder. The script can also be launched manually once
+# binary files are built (i.e. after "make test" is executed from the "psasim"
+# root folder).
+
+set -e
+
+cd "$(dirname "$0")"
+
+CLIENT_BIN=$1
+shift
+
+./kill_servers.sh
+
+./start_server.sh
+./$CLIENT_BIN "$@"
+
+./kill_servers.sh
diff -Nru mbedtls-3.6.5/framework/psasim/test/server.c mbedtls-3.6.6/framework/psasim/test/server.c
--- mbedtls-3.6.5/framework/psasim/test/server.c	2025-10-01 18:24:20.267933000 +0300
+++ mbedtls-3.6.6/framework/psasim/test/server.c	1970-01-01 02:00:00.000000000 +0200
@@ -1,105 +0,0 @@
-/* psasim test server */
-
-/*
- *  Copyright The Mbed TLS Contributors
- *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
- */
-
-#include <psa/service.h>
-#include "psa_manifest/manifest.h"
-#include <unistd.h>
-#include <stdio.h>
-
-void printbits(uint32_t num)
-{
-    for (int i = 0; i < 32; i++) {
-        if ((num >> (31-i) & 0x1)) {
-            printf("1");
-        } else {
-            printf("0");
-        }
-    }
-    printf("\n");
-}
-
-#define BUF_SIZE 25
-
-int psa_sha256_main()
-{
-    psa_status_t ret = PSA_ERROR_PROGRAMMER_ERROR;
-    psa_msg_t msg = { -1 };
-    char foo[BUF_SIZE] = { 0 };
-    const int magic_num = 66;
-
-    puts("Starting");
-
-    while (1) {
-        puts("Calling psa_wait");
-        psa_signal_t signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
-
-        if (signals > 0) {
-            printbits(signals);
-        }
-
-        if (signals & PSA_SHA256_SIGNAL) {
-            puts("Oooh a signal!");
-
-            if (PSA_SUCCESS == psa_get(PSA_SHA256_SIGNAL, &msg)) {
-                printf("My handle is %d\n", msg.handle);
-                printf("My rhandle is %p\n", (int *) msg.rhandle);
-                switch (msg.type) {
-                    case PSA_IPC_CONNECT:
-                        puts("Got a connection message");
-                        psa_set_rhandle(msg.handle, (void *) &magic_num);
-                        ret = PSA_SUCCESS;
-                        break;
-                    case PSA_IPC_DISCONNECT:
-                        puts("Got a disconnection message");
-                        ret = PSA_SUCCESS;
-                        break;
-
-                    default:
-                        printf("Got an IPC call of type %d\n", msg.type);
-                        ret = 42;
-                        size_t size = msg.in_size[0];
-
-                        if ((size > 0) && (size <= sizeof(foo))) {
-                            psa_read(msg.handle, 0, foo, 6);
-                            foo[(BUF_SIZE-1)] = '\0';
-                            printf("Reading payload: %s\n", foo);
-                            psa_read(msg.handle, 0, foo+6, 6);
-                            foo[(BUF_SIZE-1)] = '\0';
-                            printf("Reading payload: %s\n", foo);
-                        }
-
-                        size = msg.out_size[0];
-                        if ((size > 0)) {
-                            puts("Writing response");
-                            psa_write(msg.handle, 0, "RESP", 4);
-                            psa_write(msg.handle, 0, "ONSE", 4);
-                        }
-
-                        if (msg.client_id > 0) {
-                            psa_notify(msg.client_id);
-                        } else {
-                            puts("Client is non-secure, so won't notify");
-                        }
-
-                }
-
-                psa_reply(msg.handle, ret);
-            } else {
-                puts("Failed to retrieve message");
-            }
-        } else if (SIGSTP_SIG & signals) {
-            puts("Recieved SIGSTP signal. Gonna EOI it.");
-            psa_eoi(SIGSTP_SIG);
-        } else if (SIGINT_SIG & signals) {
-            puts("Handling interrupt!\n");
-            puts("Gracefully quitting");
-            psa_panic();
-        } else {
-            puts("No signal asserted");
-        }
-    }
-}
diff -Nru mbedtls-3.6.5/framework/psasim/test/start_server.sh mbedtls-3.6.6/framework/psasim/test/start_server.sh
--- mbedtls-3.6.5/framework/psasim/test/start_server.sh	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/psasim/test/start_server.sh	2026-03-27 12:34:57.776702600 +0200
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+set -e
+
+# The server creates some local files when it starts up so we can wait for this
+# event as signal that the server is ready so that we can start client(s).
+function wait_for_server_startup() {
+    SECONDS=0
+    TIMEOUT=10
+
+    while [ $(find . -name "psa_notify_*" | wc -l) -eq 0 ]; do
+        if [ "$SECONDS" -ge "$TIMEOUT" ]; then
+            echo "Timeout: psa_server not started within $TIMEOUT seconds."
+            return 1
+        fi
+        sleep 0.1
+    done
+}
+
+$(dirname "$0")/psa_server &
+wait_for_server_startup
diff -Nru mbedtls-3.6.5/framework/psasim/tools/psa_autogen.py mbedtls-3.6.6/framework/psasim/tools/psa_autogen.py
--- mbedtls-3.6.5/framework/psasim/tools/psa_autogen.py	2025-10-01 18:24:20.268158000 +0300
+++ mbedtls-3.6.6/framework/psasim/tools/psa_autogen.py	2026-03-27 12:34:57.776879000 +0200
@@ -15,6 +15,13 @@
 
 FILENAME = str(sys.argv[1])
 
+SCRIPT_PATH = os.path.dirname(__file__)
+GENERATED_H_PATH = os.path.join(SCRIPT_PATH, "..", "include", "psa_manifest")
+GENERATED_C_PATH = os.path.join(SCRIPT_PATH, "..", "src")
+
+MANIFEST_FILE = os.path.join(GENERATED_H_PATH, "manifest.h")
+PID_FILE = os.path.join(GENERATED_H_PATH, "pid.h")
+SID_FILE = os.path.join(GENERATED_H_PATH, "sid.h")
 
 with open(str(FILENAME), "r") as read_file:
     data = json.load(read_file)
@@ -32,58 +39,58 @@
             irqs = []
 
         try:
-            os.mkdir("psa_manifest")
+            os.mkdir(GENERATED_H_PATH)
             print("Generating psa_manifest directory")
         except OSError:
-            print ("PSA manifest directory already exists")
+            print("PSA manifest directory already exists")
 
-        man  = open(str("psa_manifest/" + FILENAME + ".h"), "w")
-        pids = open("psa_manifest/pid.h", "a")
-        sids = open("psa_manifest/sid.h", "a")
+        manifest_content = []
+        pids_content = []
+        sids_content = []
 
         if len(services) > 28:
            print ("Unsupported number of services")
 
         count = 4 # For creating SID array
-        nsacl = "const int ns_allowed[32] = {"
-        policy = "const int strict_policy[32] = {"
-        qcode = "const char * psa_queues[] = { "
-        versions = "const uint32_t versions[32] = {"
-        queue_path = "/tmp/psa_service_"
+        nsacl = "const int ns_allowed[32] = { "
+        policy = "const int strict_policy[32] = { "
+        qcode = "const char *psa_queues[] = { "
+        versions = "const uint32_t versions[32] = { "
+        queue_path = "psa_service_"
         start = False
 
         for x in range(0, count):
             qcode = qcode + "\"\", "
-            nsacl = nsacl + " 0,"
-            policy = policy + "0,"
-            versions = versions + " 0,"
+            nsacl = nsacl + "0, "
+            policy = policy + "0, "
+            versions = versions + "0, "
 
         # Go through all the services to make sid.h and pid.h
         for svc in services:
-            man.write("#define " + str(svc['signal']) + "_SIGNAL " + str(2 ** (count)) + 'u\n')
-            sids.write("#define " + str(svc['name']) + "_SID " + str(svc['sid'] + '\n'))
+            manifest_content.append("#define {}_SIGNAL    0x{:08x}".format(svc['signal'], 2**count))
+            sids_content.append("#define {}_SID    {}".format(svc['name'], svc['sid']))
             qcode = qcode + "\"" + queue_path + str(int(svc['sid'], 16)) + "\","
             ns_clients = svc['non_secure_clients']
             print(str(svc))
             if ns_clients == "true":
-                nsacl = nsacl + " 1,"
+                nsacl = nsacl + "1, "
             else:
-                nsacl = nsacl + " 0,"
+                nsacl = nsacl + "0, "
             try:
-                versions = versions + str(svc['minor_version']) + ","
+                versions = versions + str(svc['minor_version']) + ", "
             except KeyError:
-                versions = versions + "1,"
+                versions = versions + "1, "
 
             strict = 0
             try:
                 if str(svc['minor_policy']).lower() == "strict":
                     strict = 1
-                    policy = policy + "1,"
+                    policy = policy + "1, "
                 else:
-                    policy = policy + "0,"
+                    policy = policy + "0, "
             except KeyError:
                 strict = 0
-                policy = policy + "0,"
+                policy = policy + "0, "
 
             count = count+1
 
@@ -91,18 +98,19 @@
         handlercode = "void __sig_handler(int signo) {\n"
         irqcount = count
         for irq in irqs:
-            man.write("#define " + str(irq['signal']) + " " + str(2 ** (irqcount)) + 'u\n')
-            sigcode = sigcode + "   signal(" + str(irq['source']) + ", __sig_handler);\n"
-            handlercode = handlercode + "   if (signo == " + str(irq['source']) + ") { raise_signal(" + str(2 ** (irqcount)) + 'u);' + " };\n"
+            manifest_content.append("#define {}    0x{:08x}".format(irq['signal'], 2**irqcount))
+            sigcode = sigcode + "    signal({}, __sig_handler);\n".format(irq['source'])
+            handlercode = handlercode + \
+                          "    if (signo == {}) {{ raise_signal(0x{:08x}); }};\n".format(irq['source'], 2**irqcount)
             irqcount = irqcount+1
 
         handlercode = handlercode + "}\n"
 
         while (count < 32):
-            qcode = qcode + "\"\","
-            nsacl = nsacl + "0,"
-            versions = versions + "0,"
-            policy = policy + "0,"
+            qcode = qcode + "\"\", "
+            nsacl = nsacl + "0, "
+            versions = versions + "0, "
+            policy = policy + "0, "
             count = count + 1
 
         qcode = qcode + "};\n"
@@ -110,28 +118,28 @@
         versions = versions + "};\n"
         policy = policy + "};\n"
 
-        pids.close()
-        sids.close()
-        man.close()
+        with open(MANIFEST_FILE, "wt") as output:
+            output.write("\n".join(manifest_content))
+        with open(SID_FILE, "wt") as output:
+            output.write("\n".join(sids_content))
+        with open(PID_FILE, "wt") as output:
+            output.write("\n".join(pids_content))
 
         symbols = []
-        # Go through all the files in the current directory and look for the entrypoint
 
-        for root, directories, filenames in os.walk('.'):
+        # Go through source files and look for the entrypoint
+        for root, directories, filenames in os.walk(GENERATED_C_PATH):
             for filename in filenames:
-
                 if "psa_ff_bootstrap" in filename or filename == "psa_manifest":
                     continue
-
                 try:
                     fullpath = os.path.join(root,filename)
                     with open(fullpath, encoding='utf-8') as currentFile:
                         text = currentFile.read()
                         if str(entry_point + "(") in text:
-                            symbols.append(fullpath)
+                            symbols.append(filename)
                 except IOError:
                     print("Couldn't open " + filename)
-
                 except UnicodeDecodeError:
                     pass
 
@@ -143,21 +151,24 @@
             print("Duplicate entrypoint symbol detected: " + str(symbols))
             sys.exit(2)
         else:
-            bs = open(str("psa_ff_bootstrap_" + str(partition_name) + ".c"), "w")
-            bs.write("#include <psasim/init.h>\n")
-            bs.write("#include \"" + symbols[0] + "\"\n")
-            bs.write("#include <signal.h>\n")
-            bs.write(qcode)
-            bs.write("\n")
-            bs.write(nsacl + "\n")
-            bs.write(policy + "\n")
-            bs.write(versions + "\n")
-            bs.write(handlercode)
-            bs.write("\n")
-            bs.write("int main() {\n")
-            bs.write(sigcode)
-            bs.write("   __init_psasim(psa_queues, 32, ns_allowed, versions, strict_policy);\n")
-            bs.write("   " + entry_point + "();\nfor(;;);\n}\n")
-            bs.close()
+            C_FILENAME = os.path.join(GENERATED_C_PATH, "psa_ff_bootstrap_" + partition_name + ".c")
+            c_content = []
+            c_content.append("#include <init.h>")
+            c_content.append("#include \"" + symbols[0] + "\"")
+            c_content.append("#include <signal.h>")
+            c_content.append(qcode)
+            c_content.append(nsacl)
+            c_content.append(policy)
+            c_content.append(versions)
+            c_content.append(handlercode)
+            c_content.append("int main(int argc, char *argv[]) {")
+            c_content.append("    (void) argc;")
+            c_content.append(sigcode)
+            c_content.append("    __init_psasim(psa_queues, 32, ns_allowed, versions,"
+                             "strict_policy);")
+            c_content.append("    " + entry_point + "(argc, argv);")
+            c_content.append("}")
+            with open(C_FILENAME, "wt") as output:
+                output.write("\n".join(c_content))
 
             print("Success")
diff -Nru mbedtls-3.6.5/framework/scripts/all-core.sh mbedtls-3.6.6/framework/scripts/all-core.sh
--- mbedtls-3.6.5/framework/scripts/all-core.sh	2025-10-01 18:24:20.268384500 +0300
+++ mbedtls-3.6.6/framework/scripts/all-core.sh	2026-03-27 12:34:57.777252200 +0200
@@ -267,7 +267,18 @@
     # defined in this script whose name starts with "component_".
     ALL_COMPONENTS=$(compgen -A function component_ | sed 's/component_//')
 
-    PSASIM_PATH='tests/psa-client-server/psasim/'
+
+    # Allow overriding PSASIM_PATH with the following priority:
+    #  1) Environment override
+    #  2) Mbed TLS's version of psa-client-server
+    #  3) Fallback to the framework location (default after move)
+    if [ -z "${PSASIM_PATH+set}" ]; then
+        if [ -d tests/psa-client-server ]; then
+            PSASIM_PATH='tests/psa-client-server/psasim/'
+        else
+            PSASIM_PATH='framework/psasim/'
+        fi
+    fi
 
     # Delay determining SUPPORTED_COMPONENTS until the command line options have a chance to override
     # the commands set by the environment
@@ -369,6 +380,19 @@
 EOF
 }
 
+# list_git_files PATTERN...
+# List files known to git, matching pattern.
+# Equivalent to `git ls-files --recurse-submodules PATTERN...`, but
+# works with older Git (especially on Ubuntu 16.04) that understand
+# submodules but not `git ls-files --recurse-submodules`.
+list_git_files ()
+{
+    git ls-files -- "$@"
+    for d in $(git submodule status --recursive | awk '{print $2}'); do
+        git ls-files "$@" | sed "s!^!$d/!"
+    done
+}
+
 # Cleanup before/after running a component.
 # Remove built files as well as the cmake cache/config.
 # Does not remove generated source files.
@@ -378,25 +402,23 @@
         command $MAKE_COMMAND clean
     fi
 
-    # Remove CMake artefacts
-    find . -name .git -prune -o \
-           -iname CMakeFiles -exec rm -rf {} \+ -o \
-           \( -iname cmake_install.cmake -o \
-              -iname CTestTestfile.cmake -o \
-              -iname CMakeCache.txt -o \
-              -path './cmake/*.cmake' \) -exec rm -f {} \+
-    # Remove Makefiles generated by in-tree CMake builds
-    # (Not all files will exist in all branches, but that's OK.)
-    rm -f 3rdparty/Makefile 3rdparty/*/Makefile
-    rm -f pkgconfig/Makefile framework/Makefile
-    rm -f include/Makefile programs/!(fuzz)/Makefile
-    rm -f tf-psa-crypto/Makefile tf-psa-crypto/include/Makefile
-    rm -f tf-psa-crypto/core/Makefile tf-psa-crypto/drivers/Makefile
-    rm -f tf-psa-crypto/tests/Makefile
-    rm -f tf-psa-crypto/drivers/everest/Makefile
-    rm -f tf-psa-crypto/drivers/p256-m/Makefile
-    rm -f tf-psa-crypto/drivers/builtin/Makefile
-    rm -f tf-psa-crypto/drivers/builtin/src/Makefile
+    # Remove files left over by an in-tree CMake build.
+    # Take care to only hit in-tree builds, not out-of-tree builds in
+    # subdirectories.
+    # Remove **/Makefile only if it looks like it was created by an in-tree
+    # CMake build.
+    local cmakelists=($(list_git_files 'CMakeLists.txt' '**/CMakeLists.txt'))
+    for f in "${cmakelists[@]}"; do
+        local d="$(dirname -- "$f")"
+        if [ -d "$d/CMakeFiles" ]; then
+            rm -rf "$d/CMakeFiles" \
+               "$d/cmake_install.cmake" \
+               "$d/CTestTestfile.cmake" \
+               "$d/CMakeCache.txt" \
+               "$d/Makefile"
+            rm -rf "$d/cmake"/*.cmake
+        fi
+    done
 
     # Remove any artifacts from the component_test_cmake_as_subdirectory test.
     rm -rf programs/test/cmake_subproject/build
diff -Nru mbedtls-3.6.5/framework/scripts/assemble_changelog.py mbedtls-3.6.6/framework/scripts/assemble_changelog.py
--- mbedtls-3.6.5/framework/scripts/assemble_changelog.py	2025-10-01 18:24:20.268814000 +0300
+++ mbedtls-3.6.6/framework/scripts/assemble_changelog.py	2026-03-27 12:34:57.777762700 +0200
@@ -94,11 +94,6 @@
         raise NotImplementedError
 
     @classmethod
-    def version_title_text(cls, version_title):
-        """Return the text of a formatted version section title."""
-        raise NotImplementedError
-
-    @classmethod
     def split_categories(cls, version_body):
         """Split a changelog version section body into categories.
 
@@ -141,10 +136,6 @@
                 top_version_title, top_version_body,
                 changelog_file_content[top_version_end:])
 
-    @classmethod
-    def version_title_text(cls, version_title):
-        return re.sub(r'\n.*', version_title, re.DOTALL)
-
     _category_title_re = re.compile(r'(^\w.*)\n+', re.MULTILINE)
     @classmethod
     def split_categories(cls, version_body):
diff -Nru mbedtls-3.6.5/framework/scripts/audit-validity-dates.py mbedtls-3.6.6/framework/scripts/audit-validity-dates.py
--- mbedtls-3.6.5/framework/scripts/audit-validity-dates.py	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/scripts/audit-validity-dates.py	2026-03-27 12:34:57.777868000 +0200
@@ -0,0 +1,468 @@
+#!/usr/bin/env python3
+#
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+"""Audit validity date of X509 crt/crl/csr.
+
+This script is used to audit the validity date of crt/crl/csr used for testing.
+It prints the information about X.509 objects excluding the objects that
+are valid throughout the desired validity period. The data are collected
+from framework/data_files/ and tests/suites/*.data files by default.
+"""
+
+import os
+import re
+import typing
+import argparse
+import datetime
+import glob
+import logging
+import hashlib
+from enum import Enum
+
+# The script requires cryptography >= 35.0.0 which is only available
+# for Python >= 3.6.
+import cryptography
+from cryptography import x509
+
+from generate_test_code import FileWrapper
+
+from mbedtls_framework import build_tree
+from mbedtls_framework import logging_util
+
+def check_cryptography_version():
+    match = re.match(r'^[0-9]+', cryptography.__version__)
+    if match is None or int(match.group(0)) < 35:
+        raise Exception("audit-validity-dates requires cryptography >= 35.0.0"
+                        + "({} is too old)".format(cryptography.__version__))
+
+class DataType(Enum):
+    CRT = 1 # Certificate
+    CRL = 2 # Certificate Revocation List
+    CSR = 3 # Certificate Signing Request
+
+
+class DataFormat(Enum):
+    PEM = 1 # Privacy-Enhanced Mail
+    DER = 2 # Distinguished Encoding Rules
+
+
+class AuditData:
+    """Store data location, type and validity period of X.509 objects."""
+    #pylint: disable=too-few-public-methods
+    def __init__(self, data_type: DataType, x509_obj):
+        self.data_type = data_type
+        # the locations that the x509 object could be found
+        self.locations = [] # type: typing.List[str]
+        self.fill_validity_duration(x509_obj)
+        self._obj = x509_obj
+        encoding = cryptography.hazmat.primitives.serialization.Encoding.DER
+        self._identifier = hashlib.sha1(self._obj.public_bytes(encoding)).hexdigest()
+
+    @property
+    def identifier(self):
+        """
+        Identifier of the underlying X.509 object, which is consistent across
+        different runs.
+        """
+        return self._identifier
+
+    def fill_validity_duration(self, x509_obj):
+        """Read validity period from an X.509 object."""
+        # Certificate expires after "not_valid_after"
+        # Certificate is invalid before "not_valid_before"
+        if self.data_type == DataType.CRT:
+            self.not_valid_after = x509_obj.not_valid_after
+            self.not_valid_before = x509_obj.not_valid_before
+        # CertificateRevocationList expires after "next_update"
+        # CertificateRevocationList is invalid before "last_update"
+        elif self.data_type == DataType.CRL:
+            self.not_valid_after = x509_obj.next_update
+            self.not_valid_before = x509_obj.last_update
+        # CertificateSigningRequest is always valid.
+        elif self.data_type == DataType.CSR:
+            self.not_valid_after = datetime.datetime.max
+            self.not_valid_before = datetime.datetime.min
+        else:
+            raise ValueError("Unsupported file_type: {}".format(self.data_type))
+
+
+class X509Parser:
+    """A parser class to parse crt/crl/csr file or data in PEM/DER format."""
+    PEM_REGEX = br'-{5}BEGIN (?P<type>.*?)-{5}(?P<data>.*?)-{5}END (?P=type)-{5}'
+    PEM_TAG_REGEX = br'-{5}BEGIN (?P<type>.*?)-{5}\n'
+    PEM_TAGS = {
+        DataType.CRT: 'CERTIFICATE',
+        DataType.CRL: 'X509 CRL',
+        DataType.CSR: 'CERTIFICATE REQUEST'
+    }
+
+    def __init__(self,
+                 backends:
+                 typing.Dict[DataType,
+                             typing.Dict[DataFormat,
+                                         typing.Callable[[bytes], object]]]) \
+    -> None:
+        self.backends = backends
+        self.__generate_parsers()
+
+    def __generate_parser(self, data_type: DataType):
+        """Parser generator for a specific DataType"""
+        tag = self.PEM_TAGS[data_type]
+        pem_loader = self.backends[data_type][DataFormat.PEM]
+        der_loader = self.backends[data_type][DataFormat.DER]
+        def wrapper(data: bytes):
+            pem_type = X509Parser.pem_data_type(data)
+            # It is in PEM format with target tag
+            if pem_type == tag:
+                return pem_loader(data)
+            # It is in PEM format without target tag
+            if pem_type:
+                return None
+            # It might be in DER format
+            try:
+                result = der_loader(data)
+            except ValueError:
+                result = None
+            return result
+        wrapper.__name__ = "{}.parser[{}]".format(type(self).__name__, tag)
+        return wrapper
+
+    def __generate_parsers(self):
+        """Generate parsers for all support DataType"""
+        self.parsers = {}
+        for data_type, _ in self.PEM_TAGS.items():
+            self.parsers[data_type] = self.__generate_parser(data_type)
+
+    def __getitem__(self, item):
+        return self.parsers[item]
+
+    @staticmethod
+    def pem_data_type(data: bytes) -> typing.Optional[str]:
+        """Get the tag from the data in PEM format
+
+        :param data: data to be checked in binary mode.
+        :return: PEM tag or "" when no tag detected.
+        """
+        m = re.search(X509Parser.PEM_TAG_REGEX, data)
+        if m is not None:
+            return m.group('type').decode('UTF-8')
+        else:
+            return None
+
+    @staticmethod
+    def check_hex_string(hex_str: str) -> bool:
+        """Check if the hex string is possibly DER data."""
+        hex_len = len(hex_str)
+        # At least 6 hex char for 3 bytes: Type + Length + Content
+        if hex_len < 6:
+            return False
+        # Check if Type (1 byte) is SEQUENCE.
+        if hex_str[0:2] != '30':
+            return False
+        # Check LENGTH (1 byte) value
+        content_len = int(hex_str[2:4], base=16)
+        consumed = 4
+        if content_len in (128, 255):
+            # Indefinite or Reserved
+            return False
+        elif content_len > 127:
+            # Definite, Long
+            length_len = (content_len - 128) * 2
+            content_len = int(hex_str[consumed:consumed+length_len], base=16)
+            consumed += length_len
+        # Check LENGTH
+        if hex_len != content_len * 2 + consumed:
+            return False
+        return True
+
+
+class Auditor:
+    """
+    A base class that uses X509Parser to parse files to a list of AuditData.
+
+    A subclass must implement the following methods:
+      - collect_default_files: Return a list of file names that are defaultly
+        used for parsing (auditing). The list will be stored in
+        Auditor.default_files.
+      - parse_file: Method that parses a single file to a list of AuditData.
+
+    A subclass may override the following methods:
+      - parse_bytes: Defaultly, it parses `bytes` that contains only one valid
+        X.509 data(DER/PEM format) to an X.509 object.
+      - walk_all: Defaultly, it iterates over all the files in the provided
+        file name list, calls `parse_file` for each file and stores the results
+        by extending the `results` passed to the function.
+    """
+    def __init__(self, logger):
+        self.logger = logger
+        self.default_files = self.collect_default_files()
+        self.parser = X509Parser({
+            DataType.CRT: {
+                DataFormat.PEM: x509.load_pem_x509_certificate,
+                DataFormat.DER: x509.load_der_x509_certificate
+            },
+            DataType.CRL: {
+                DataFormat.PEM: x509.load_pem_x509_crl,
+                DataFormat.DER: x509.load_der_x509_crl
+            },
+            DataType.CSR: {
+                DataFormat.PEM: x509.load_pem_x509_csr,
+                DataFormat.DER: x509.load_der_x509_csr
+            },
+        })
+
+    def collect_default_files(self) -> typing.List[str]:
+        """Collect the default files for parsing."""
+        raise NotImplementedError
+
+    def parse_file(self, filename: str) -> typing.List[AuditData]:
+        """
+        Parse a list of AuditData from file.
+
+        :param filename: name of the file to parse.
+        :return list of AuditData parsed from the file.
+        """
+        raise NotImplementedError
+
+    def parse_bytes(self, data: bytes):
+        """Parse AuditData from bytes."""
+        for data_type in list(DataType):
+            try:
+                result = self.parser[data_type](data)
+            except ValueError as val_error:
+                result = None
+                self.logger.warning(val_error)
+            if result is not None:
+                audit_data = AuditData(data_type, result)
+                return audit_data
+        return None
+
+    def walk_all(self,
+                 results: typing.Dict[str, AuditData],
+                 file_list: typing.Optional[typing.List[str]] = None) \
+        -> None:
+        """
+        Iterate over all the files in the list and get audit data. The
+        results will be written to `results` passed to this function.
+
+        :param results: The dictionary used to store the parsed
+                        AuditData. The keys of this dictionary should
+                        be the identifier of the AuditData.
+        """
+        if file_list is None:
+            file_list = self.default_files
+        for filename in file_list:
+            data_list = self.parse_file(filename)
+            for d in data_list:
+                if d.identifier in results:
+                    results[d.identifier].locations.extend(d.locations)
+                else:
+                    results[d.identifier] = d
+
+    @staticmethod
+    def find_test_dir():
+        """Get the relative path for the Mbed TLS test directory."""
+        return os.path.relpath(build_tree.guess_mbedtls_root() + '/tests')
+
+
+class TestDataAuditor(Auditor):
+    """Class for auditing files in `framework/data_files/`"""
+
+    def collect_default_files(self):
+        """Collect all files in `framework/data_files/`"""
+        test_data_glob = os.path.join(build_tree.guess_mbedtls_root(),
+                                      'framework', 'data_files/**')
+        data_files = [f for f in glob.glob(test_data_glob, recursive=True)
+                      if os.path.isfile(f)]
+        return data_files
+
+    def parse_file(self, filename: str) -> typing.List[AuditData]:
+        """
+        Parse a list of AuditData from data file.
+
+        :param filename: name of the file to parse.
+        :return list of AuditData parsed from the file.
+        """
+        with open(filename, 'rb') as f:
+            data = f.read()
+
+        results = []
+        # Try to parse all PEM blocks.
+        is_pem = False
+        for idx, m in enumerate(re.finditer(X509Parser.PEM_REGEX, data, flags=re.S), 1):
+            is_pem = True
+            result = self.parse_bytes(data[m.start():m.end()])
+            if result is not None:
+                result.locations.append("{}#{}".format(filename, idx))
+                results.append(result)
+
+        # Might be DER format.
+        if not is_pem:
+            result = self.parse_bytes(data)
+            if result is not None:
+                result.locations.append("{}".format(filename))
+                results.append(result)
+
+        return results
+
+
+def parse_suite_data(data_f):
+    """
+    Parses .data file for test arguments that possiblly have a
+    valid X.509 data. If you need a more precise parser, please
+    use generate_test_code.parse_test_data instead.
+
+    :param data_f: file object of the data file.
+    :return: Generator that yields test function argument list.
+    """
+    for line in data_f:
+        line = line.strip()
+        # Skip comments
+        if line.startswith('#'):
+            continue
+
+        # Check parameters line
+        match = re.search(r'\A\w+(.*:)?\"', line)
+        if match:
+            # Read test vectors
+            parts = re.split(r'(?<!\\):', line)
+            parts = [x for x in parts if x]
+            args = parts[1:]
+            yield args
+
+
+class SuiteDataAuditor(Auditor):
+    """Class for auditing files in `tests/suites/*.data`"""
+
+    def collect_default_files(self):
+        """Collect all files in `tests/suites/*.data`"""
+        test_dir = self.find_test_dir()
+        suites_data_folder = os.path.join(test_dir, 'suites')
+        data_files = glob.glob(os.path.join(suites_data_folder, '*.data'))
+        return data_files
+
+    def parse_file(self, filename: str):
+        """
+        Parse a list of AuditData from test suite data file.
+
+        :param filename: name of the file to parse.
+        :return list of AuditData parsed from the file.
+        """
+        audit_data_list = []
+        data_f = FileWrapper(filename)
+        for test_args in parse_suite_data(data_f):
+            for idx, test_arg in enumerate(test_args):
+                match = re.match(r'"(?P<data>[0-9a-fA-F]+)"', test_arg)
+                if not match:
+                    continue
+                if not X509Parser.check_hex_string(match.group('data')):
+                    continue
+                audit_data = self.parse_bytes(bytes.fromhex(match.group('data')))
+                if audit_data is None:
+                    continue
+                audit_data.locations.append("{}:{}:#{}".format(filename,
+                                                               data_f.line_no,
+                                                               idx + 1))
+                audit_data_list.append(audit_data)
+
+        return audit_data_list
+
+
+def list_all(audit_data: AuditData):
+    for loc in audit_data.locations:
+        print("{}\t{:20}\t{:20}\t{:3}\t{}".format(
+            audit_data.identifier,
+            audit_data.not_valid_before.isoformat(timespec='seconds'),
+            audit_data.not_valid_after.isoformat(timespec='seconds'),
+            audit_data.data_type.name,
+            loc))
+
+
+def main():
+    """
+    Perform argument parsing.
+    """
+    parser = argparse.ArgumentParser(description=__doc__)
+
+    parser.add_argument('-a', '--all',
+                        action='store_true',
+                        help='list the information of all the files')
+    parser.add_argument('-v', '--verbose',
+                        action='store_true', dest='verbose',
+                        help='show logs')
+    parser.add_argument('--from', dest='start_date',
+                        help=('Start of desired validity period (UTC, YYYY-MM-DD). '
+                              'Default: today'),
+                        metavar='DATE')
+    parser.add_argument('--to', dest='end_date',
+                        help=('End of desired validity period (UTC, YYYY-MM-DD). '
+                              'Default: --from'),
+                        metavar='DATE')
+    parser.add_argument('--data-files', action='append', nargs='*',
+                        help='data files to audit',
+                        metavar='FILE')
+    parser.add_argument('--suite-data-files', action='append', nargs='*',
+                        help='suite data files to audit',
+                        metavar='FILE')
+
+    args = parser.parse_args()
+
+    # start main routine
+    # setup logger
+    logger = logging.getLogger()
+    logging_util.configure_logger(logger)
+    logger.setLevel(logging.DEBUG if args.verbose else logging.ERROR)
+
+    td_auditor = TestDataAuditor(logger)
+    sd_auditor = SuiteDataAuditor(logger)
+
+    data_files = []
+    suite_data_files = []
+    if args.data_files is None and args.suite_data_files is None:
+        data_files = td_auditor.default_files
+        suite_data_files = sd_auditor.default_files
+    else:
+        if args.data_files is not None:
+            data_files = [x for l in args.data_files for x in l]
+        if args.suite_data_files is not None:
+            suite_data_files = [x for l in args.suite_data_files for x in l]
+
+    # validity period start date
+    if args.start_date:
+        start_date = datetime.datetime.fromisoformat(args.start_date)
+    else:
+        start_date = datetime.datetime.today()
+    # validity period end date
+    if args.end_date:
+        end_date = datetime.datetime.fromisoformat(args.end_date)
+    else:
+        end_date = start_date
+
+    # go through all the files
+    audit_results = {}
+    td_auditor.walk_all(audit_results, data_files)
+    sd_auditor.walk_all(audit_results, suite_data_files)
+
+    logger.info("Total: {} objects found!".format(len(audit_results)))
+
+    # we filter out the files whose validity duration covers the provided
+    # duration.
+    filter_func = lambda d: (start_date < d.not_valid_before) or \
+                            (d.not_valid_after < end_date)
+
+    sortby_end = lambda d: d.not_valid_after
+
+    if args.all:
+        filter_func = None
+
+    # filter and output the results
+    for d in sorted(filter(filter_func, audit_results.values()), key=sortby_end):
+        list_all(d)
+
+    logger.debug("Done!")
+
+check_cryptography_version()
+if __name__ == "__main__":
+    main()
diff -Nru mbedtls-3.6.5/framework/scripts/check-doxy-blocks.pl mbedtls-3.6.6/framework/scripts/check-doxy-blocks.pl
--- mbedtls-3.6.5/framework/scripts/check-doxy-blocks.pl	2025-10-01 18:24:20.268934500 +0300
+++ mbedtls-3.6.6/framework/scripts/check-doxy-blocks.pl	2026-03-27 12:34:57.777985000 +0200
@@ -20,7 +20,8 @@
 my @tf_psa_crypto_directories = qw(include/psa include/tf-psa-crypto
                                    include/mbedtls
                                    drivers/builtin/include/mbedtls
-                                   drivers/builtin/src core doxygen/input);
+                                   drivers/builtin/src core dispatch
+                                   doxygen/input extras platform utilities);
 
 # very naive pattern to find directives:
 # everything with a backslach except '\0' and backslash at EOL
diff -Nru mbedtls-3.6.5/framework/scripts/check_names.py mbedtls-3.6.6/framework/scripts/check_names.py
--- mbedtls-3.6.5/framework/scripts/check_names.py	2025-10-01 18:24:20.269275400 +0300
+++ mbedtls-3.6.6/framework/scripts/check_names.py	2026-03-27 12:34:57.778317200 +0200
@@ -46,6 +46,8 @@
 import subprocess
 import logging
 import tempfile
+import typing
+from typing import Dict, List, Pattern, Optional, Set, Tuple, Union
 
 import project_scripts # pylint: disable=unused-import
 from mbedtls_framework import build_tree
@@ -53,10 +55,16 @@
 
 # Naming patterns to check against. These are defined outside the NameCheck
 # class for ease of modification.
-PUBLIC_MACRO_PATTERN = r"^(MBEDTLS|PSA|TF_PSA_CRYPTO)_[0-9A-Z_]*[0-9A-Z]$"
-INTERNAL_MACRO_PATTERN = r"^[0-9A-Za-z_]*[0-9A-Z]$"
+PUBLIC_MACRO_PATTERN = re.compile(r"^(MBEDTLS|PSA|TF_PSA_CRYPTO)_[0-9A-Z_]*[0-9A-Z]$")
+# Macro names, even internal macros, must be all uppercase (common convention),
+# must not start with an underscore (these are reserved for the C
+# implementation), must not end with an underscore (for legibility),
+# and must not consist of a single letter (because we've seen embedded
+# platforms that claim single-uppercase-letter names for themselves).
+INTERNAL_MACRO_PATTERN = re.compile("^[A-Z][0-9A-Z_]*[A-Z0-9]$")
 CONSTANTS_PATTERN = PUBLIC_MACRO_PATTERN
-IDENTIFIER_PATTERN = r"^(mbedtls|psa|tf_psa_crypto)_[0-9a-z_]*[0-9a-z]$"
+IDENTIFIER_PATTERN = re.compile(r"^(mbedtls|psa|tf_psa_crypto)_[0-9a-z_]*[0-9a-z]$")
+
 
 class Match(): # pylint: disable=too-few-public-methods
     """
@@ -69,7 +77,9 @@
     * pos: a tuple of (start, end) positions on the line where the match is.
     * name: the match itself.
     """
-    def __init__(self, filename, line, line_no, pos, name):
+    def __init__(self,
+                 filename: str, line: str, line_no: int, pos: Tuple[int, int],
+                 name: str) -> None:
         # pylint: disable=too-many-arguments
         self.filename = filename
         self.line = line
@@ -77,7 +87,7 @@
         self.pos = pos
         self.name = name
 
-    def __str__(self):
+    def __str__(self) -> str:
         """
         Return a formatted code listing representation of the erroneous line.
         """
@@ -90,6 +100,33 @@
             " {0} | {1}\n".format(" " * len(gutter), underline)
         )
 
+
+class ParseResult(typing.NamedTuple):
+    """The data from analyzing the source code and the library."""
+    public_macros: List[Match]
+    internal_macros: List[Match]
+    private_macros: List[Match]
+    enum_consts: List[Match]
+    identifiers: List[Match]
+    excluded_identifiers: List[Match]
+    symbols: List[str]
+    mbed_psa_words: List[Match]
+
+    def add(self, more: Optional['ParseResult'] = None) -> 'ParseResult':
+        if more is None:
+            return self
+        return ParseResult(
+            public_macros=self.public_macros + more.public_macros,
+            internal_macros=self.internal_macros + more.internal_macros,
+            private_macros=self.private_macros + more.private_macros,
+            enum_consts=self.enum_consts + more.enum_consts,
+            identifiers=self.identifiers + more.identifiers,
+            excluded_identifiers=self.excluded_identifiers + more.excluded_identifiers,
+            symbols=self.symbols + more.symbols,
+            mbed_psa_words=self.mbed_psa_words + more.mbed_psa_words,
+        )
+
+
 class Problem(abc.ABC): # pylint: disable=too-few-public-methods
     """
     An abstract parent class representing a form of static analysis error.
@@ -98,13 +135,15 @@
     """
     # Class variable to control the quietness of all problems
     quiet = False
-    def __init__(self):
-        self.textwrapper = textwrap.TextWrapper()
+
+    def __init__(self) -> None:
+        self.textwrapper = textwrap.TextWrapper(break_on_hyphens=False,
+                                                break_long_words=False)
         self.textwrapper.width = 80
         self.textwrapper.initial_indent = "    > "
         self.textwrapper.subsequent_indent = "      "
 
-    def __str__(self):
+    def __str__(self) -> str:
         """
         Unified string representation method for all Problems.
         """
@@ -113,19 +152,20 @@
         return self.verbose_output()
 
     @abc.abstractmethod
-    def quiet_output(self):
+    def quiet_output(self) -> str:
         """
         The output when --quiet is enabled.
         """
         pass
 
     @abc.abstractmethod
-    def verbose_output(self):
+    def verbose_output(self) -> str:
         """
         The default output with explanation and code snippet if appropriate.
         """
         pass
 
+
 class SymbolNotInHeader(Problem): # pylint: disable=too-few-public-methods
     """
     A problem that occurs when an exported/available symbol in the object file
@@ -135,19 +175,20 @@
     Fields:
     * symbol_name: the name of the symbol.
     """
-    def __init__(self, symbol_name):
+    def __init__(self, symbol_name: str) -> None:
         self.symbol_name = symbol_name
         Problem.__init__(self)
 
-    def quiet_output(self):
+    def quiet_output(self) -> str:
         return "{0}".format(self.symbol_name)
 
-    def verbose_output(self):
+    def verbose_output(self) -> str:
         return self.textwrapper.fill(
             "'{0}' was found as an available symbol in the output of nm, "
             "however it was not declared in any header files."
             .format(self.symbol_name))
 
+
 class PatternMismatch(Problem): # pylint: disable=too-few-public-methods
     """
     A problem that occurs when something doesn't match the expected pattern.
@@ -157,19 +198,19 @@
     * pattern: the expected regex pattern
     * match: the Match object in question
     """
-    def __init__(self, pattern, match):
+    def __init__(self, pattern: Union[Pattern, str], match: Match) -> None:
         self.pattern = pattern
         self.match = match
         Problem.__init__(self)
 
 
-    def quiet_output(self):
+    def quiet_output(self) -> str:
         return (
             "{0}:{1}:{2}"
             .format(self.match.filename, self.match.line_no, self.match.name)
         )
 
-    def verbose_output(self):
+    def verbose_output(self) -> str:
         return self.textwrapper.fill(
             "{0}:{1}: '{2}' does not match the required pattern '{3}'."
             .format(
@@ -180,6 +221,7 @@
             )
         ) + "\n" + str(self.match)
 
+
 class Typo(Problem): # pylint: disable=too-few-public-methods
     """
     A problem that occurs when a word using MBED or PSA doesn't
@@ -189,17 +231,17 @@
     Fields:
     * match: the Match object of the MBED|PSA name in question.
     """
-    def __init__(self, match):
+    def __init__(self, match: Match) -> None:
         self.match = match
         Problem.__init__(self)
 
-    def quiet_output(self):
+    def quiet_output(self) -> str:
         return (
             "{0}:{1}:{2}"
             .format(self.match.filename, self.match.line_no, self.match.name)
         )
 
-    def verbose_output(self):
+    def verbose_output(self) -> str:
         return self.textwrapper.fill(
             "{0}:{1}: '{2}' looks like a typo. It was not found in any "
             "macros or any enums. If this is not a typo, put "
@@ -207,26 +249,29 @@
             .format(self.match.filename, self.match.line_no, self.match.name)
         ) + "\n" + str(self.match)
 
+
 class CodeParser():
     """
     Class for retrieving files and parsing the code. This can be used
     independently of the checks that NameChecker performs, for example for
     list_internal_identifiers.py.
     """
-    def __init__(self, log):
+    def __init__(self, log: logging.Logger) -> None:
         self.log = log
         if not build_tree.looks_like_root(os.getcwd()):
             raise Exception("This script must be run from Mbed TLS or TF-PSA-Crypto root")
 
-        # Memo for storing "glob expression": set(filepaths)
-        self.files = {}
-
         # Globally excluded filenames.
         # Note that "*" can match directory separators in exclude lists.
         self.excluded_files = ["*/bn_mul", "*/compat-2.x.h"]
 
-    def _parse(self, all_macros, enum_consts, identifiers,
-               excluded_identifiers, mbed_psa_words, symbols):
+    def _parse(self,
+               all_macros: Dict[str, List[Match]],
+               enum_consts: List[Match],
+               identifiers: List[Match],
+               excluded_identifiers: List[Match],
+               mbed_psa_words: List[Match],
+               symbols: List[str]) -> ParseResult:
         # pylint: disable=too-many-arguments
         """
         Parse macros, enums, identifiers, excluded identifiers, Mbed PSA word and Symbols.
@@ -241,8 +286,8 @@
         )
 
         # Remove identifier macros like mbedtls_printf or mbedtls_calloc
-        identifiers_justname = [x.name for x in identifiers]
-        actual_macros = {"public": [], "internal": []}
+        identifiers_justname = frozenset(x.name for x in identifiers)
+        actual_macros = {"public": [], "internal": []} #type: Dict[str, List[Match]]
         for scope in actual_macros:
             for macro in all_macros[scope]:
                 if macro.name not in identifiers_justname:
@@ -258,27 +303,31 @@
         self.log.debug("  {:4} Enum Constants".format(len(enum_consts)))
         self.log.debug("  {:4} Identifiers".format(len(identifiers)))
         self.log.debug("  {:4} Exported Symbols".format(len(symbols)))
-        return {
-            "public_macros": actual_macros["public"],
-            "internal_macros": actual_macros["internal"],
-            "private_macros": all_macros["private"],
-            "enum_consts": enum_consts,
-            "identifiers": identifiers,
-            "excluded_identifiers": excluded_identifiers,
-            "symbols": symbols,
-            "mbed_psa_words": mbed_psa_words
-        }
+        return ParseResult(
+            public_macros=actual_macros["public"],
+            internal_macros=actual_macros["internal"],
+            private_macros=all_macros["private"],
+            enum_consts=enum_consts,
+            identifiers=identifiers,
+            excluded_identifiers=excluded_identifiers,
+            symbols=symbols,
+            mbed_psa_words=mbed_psa_words,
+        )
 
-    def is_file_excluded(self, path, exclude_wildcards):
+    def is_file_excluded(self,
+                         path: str,
+                         exclude_wildcards: Optional[List[str]]) -> bool:
         """Whether the given file path is excluded."""
         # exclude_wildcards may be None. Also, consider the global exclusions.
-        exclude_wildcards = (exclude_wildcards or []) + self.excluded_files
-        for pattern in exclude_wildcards:
+        for pattern in (exclude_wildcards or []) + self.excluded_files:
             if fnmatch.fnmatch(path, pattern):
                 return True
         return False
 
-    def get_all_files(self, include_wildcards, exclude_wildcards):
+    def get_all_files(self,
+                      include_wildcards: List[str],
+                      exclude_wildcards: Optional[List[str]],
+                      ) -> Tuple[List[str], List[str]]:
         """
         Get all files that match any of the included UNIX-style wildcards
         and filter them into included and excluded lists.
@@ -288,16 +337,27 @@
 
         Args:
         * include_wildcards: a List of shell-style wildcards to match filepaths.
+          - "*" does not match a directory separator, e.g. "*/a.h"
+            matches "somedir/a.h" but not "somedir/subdir/a.h".
+          - "**" matches zero or more directory levels, e.g. "**/a.h"
+            matches "a.h", "somedir/a.h", "somedir/subdir/a.h", etc.
+          - The matching is case-insensitive.
         * exclude_wildcards: a List of shell-style wildcards to exclude.
+          - "*" matches every character including separators, e.g. "*/a.h"
+            matches "somedir/a.h" and "somedir/subdir/a.h" but not "a.h".
+          - "**" is equivalent to "*".
+          - The matching is case-sensitive.
 
         Returns:
         * inc_files: A List of relative filepaths for included files.
         * exc_files: A List of relative filepaths for excluded files.
         """
-        accumulator = set()
-        all_wildcards = include_wildcards + (exclude_wildcards or [])
+        if exclude_wildcards is None:
+            exclude_wildcards = []
+        accumulator = set() #type: Set[str]
+        all_wildcards = include_wildcards + exclude_wildcards
         for wildcard in all_wildcards:
-            accumulator = accumulator.union(glob.iglob(wildcard))
+            accumulator = accumulator.union(glob.iglob(wildcard, recursive=True))
 
         inc_files = []
         exc_files = []
@@ -306,9 +366,12 @@
                 exc_files.append(path)
             else:
                 inc_files.append(path)
-        return (inc_files, exc_files)
+        return (sorted(inc_files), sorted(exc_files))
 
-    def get_included_files(self, include_wildcards, exclude_wildcards):
+    def get_included_files(self,
+                           include_wildcards: List[str],
+                           exclude_wildcards: Optional[List[str]],
+                           ) -> List[str]:
         """
         Get all files that match any of the included UNIX-style wildcards.
         While the check_names script is designed only for use on UNIX/macOS
@@ -321,15 +384,19 @@
 
         Returns a List of relative filepaths.
         """
-        accumulator = set()
+        accumulator = set() #type: Set[str]
 
         for include_wildcard in include_wildcards:
-            accumulator = accumulator.union(glob.iglob(include_wildcard))
+            accumulator = accumulator.union(glob.iglob(include_wildcard,
+                                                       recursive=True))
 
-        return list(path for path in accumulator
-                    if not self.is_file_excluded(path, exclude_wildcards))
+        return sorted(path for path in accumulator
+                      if not self.is_file_excluded(path, exclude_wildcards))
 
-    def parse_macros(self, include, exclude=None):
+    def parse_macros(self,
+                     include: List[str],
+                     exclude: Optional[List[str]] = None,
+                     ) -> List[Match]:
         """
         Parse all macros defined by #define preprocessor directives.
 
@@ -349,6 +416,7 @@
 
         macros = []
         for header_file in files:
+            self.log.debug("Parsing macros in " + header_file)
             with open(header_file, "r", encoding="utf-8") as header:
                 for line_no, line in enumerate(header):
                     for macro in macro_regex.finditer(line):
@@ -364,7 +432,10 @@
 
         return macros
 
-    def parse_mbed_psa_words(self, include, exclude=None):
+    def parse_mbed_psa_words(self,
+                             include: List[str],
+                             exclude: Optional[List[str]] = None,
+                             ) -> List[Match]:
         """
         Parse all words in the file that begin with MBED|PSA, in and out of
         macros, comments, anything.
@@ -387,6 +458,7 @@
 
         mbed_psa_words = []
         for filename in files:
+            self.log.debug("Parsing words in " + filename)
             with open(filename, "r", encoding="utf-8") as fp:
                 for line_no, line in enumerate(fp):
                     if exclusions.search(line):
@@ -402,7 +474,10 @@
 
         return mbed_psa_words
 
-    def parse_enum_consts(self, include, exclude=None):
+    def parse_enum_consts(self,
+                          include: List[str],
+                          exclude: Optional[List[str]] = None,
+                          ) -> List[Match]:
         """
         Parse all enum value constants that are declared.
 
@@ -423,6 +498,7 @@
         enum_consts = []
         for header_file in files:
             state = states.OUTSIDE_KEYWORD
+            self.log.debug("Parsing enums in " + header_file)
             with open(header_file, "r", encoding="utf-8") as header:
                 for line_no, line in enumerate(header):
                     # Match typedefs and brackets only when they are at the
@@ -464,7 +540,8 @@
         r'(?P<string>")(?:[^\\\"]|\\.)*"', # string literal
     ]))
 
-    def strip_comments_and_literals(self, line, in_block_comment):
+    def strip_comments_and_literals(self, line: str,
+                                    in_block_comment: bool) -> Tuple[str, bool]:
         """Strip comments and string literals from line.
 
         Continuation lines are not supported.
@@ -530,7 +607,9 @@
         r"#",
     ]))
 
-    def parse_identifiers_in_file(self, header_file, identifiers):
+    def parse_identifiers_in_file(self,
+                                  header_file: str,
+                                  identifiers: List[Match]) -> None:
         """
         Parse all lines of a header where a function/enum/struct/union/typedef
         identifier is declared, based on some regex and heuristics. Highly
@@ -539,6 +618,7 @@
         Append found matches to the list ``identifiers``.
         """
 
+        self.log.debug("Parsing identifier declarations in " + header_file)
         with open(header_file, "r", encoding="utf-8") as header:
             in_block_comment = False
             # The previous line variable is used for concatenating lines
@@ -591,7 +671,10 @@
                         identifier.span(),
                         group))
 
-    def parse_identifiers(self, include, exclude=None):
+    def parse_identifiers(self,
+                          include: List[str],
+                          exclude: Optional[List[str]] = None,
+                          ) -> Tuple[List[Match], List[Match]]:
         """
         Parse all lines of a header where a function/enum/struct/union/typedef
         identifier is declared, based on some regex and heuristics. Highly
@@ -614,17 +697,19 @@
 
         self.log.debug("Looking for included identifiers in {} files".format \
             (len(included_files)))
-
-        included_identifiers = []
-        excluded_identifiers = []
+        included_identifiers = [] #type: List[Match]
         for header_file in included_files:
             self.parse_identifiers_in_file(header_file, included_identifiers)
+
+        self.log.debug("Looking for excluded identifiers in {} files".format \
+            (len(excluded_files)))
+        excluded_identifiers = [] #type: List[Match]
         for header_file in excluded_files:
             self.parse_identifiers_in_file(header_file, excluded_identifiers)
 
         return (included_identifiers, excluded_identifiers)
 
-    def parse_symbols(self):
+    def parse_symbols(self) -> List[str]:
         """
         Compile a library, and parse the object files using nm to retrieve the
         list of referenced symbols. Exceptions thrown here are rethrown because
@@ -635,7 +720,7 @@
         """
         raise NotImplementedError("parse_symbols must be implemented by a code parser")
 
-    def comprehensive_parse(self):
+    def comprehensive_parse(self) -> ParseResult:
         """
         (Must be defined as a class method)
         Comprehensive ("default") function to call each parsing function and
@@ -645,7 +730,7 @@
         """
         raise NotImplementedError("comprehension_parse must be implemented by a code parser")
 
-    def parse_symbols_from_nm(self, object_files):
+    def parse_symbols_from_nm(self, object_files: List[str]) -> List[str]:
         """
         Run nm to retrieve the list of referenced symbols in each object file.
         Does not return the position data since it is of no use.
@@ -659,7 +744,7 @@
         nm_undefined_regex = re.compile(r"^\S+: +U |^$|^\S+:$")
         nm_valid_regex = re.compile(r"^\S+( [0-9A-Fa-f]+)* . _*(?P<symbol>\w+)")
         exclusions = ("FStar", "Hacl")
-        symbols = []
+        symbols = [] #type: List[str]
         # Gather all outputs of nm
         nm_output = ""
         for lib in object_files:
@@ -679,100 +764,79 @@
                     self.log.error(line)
         return symbols
 
+
 class TFPSACryptoCodeParser(CodeParser):
     """
     Class for retrieving files and parsing TF-PSA-Crypto code. This can be used
     independently of the checks that NameChecker performs.
     """
 
-    def __init__(self, log):
+    def __init__(self, log: logging.Logger) -> None:
         super().__init__(log)
         if not build_tree.looks_like_tf_psa_crypto_root(os.getcwd()):
             raise Exception("This script must be run from TF-PSA-Crypto root.")
 
-    def comprehensive_parse(self):
+    H_PUBLIC = [
+        "include/**/*.h",
+        "drivers/*/include/**/*.h",
+    ]
+    H_PUBLIC_EXCLUDE = [
+        'drivers/everest/include/tf-psa-crypto/private/everest/[HhKk]*.h',
+        'drivers/everest/include/tf-psa-crypto/private/everest/k*/*.h',
+        'drivers/everest/include/tf-psa-crypto/private/everest/vs*/*.h',
+    ]
+
+    H_INTERNAL = [
+        "core/*.h",
+        "dispatch/*.h",
+        "drivers/*/src/*.h",
+        "extras/*.h",
+        "platform/*.h",
+        "utilities/*.h",
+    ]
+
+    H_TEST_DRIVERS = [
+        "framework/tests/include/test/drivers/*.h",
+    ]
+
+    C_INTERNAL = [
+        "core/*.c",
+        "dispatch/*.c",
+        "drivers/*/library/*.c",
+        "drivers/*/src/*.c",
+        "extras/*.c",
+        "platform/*.c",
+        "utilities/*.c",
+    ]
+
+    def comprehensive_parse(self) -> ParseResult:
         """
         Comprehensive ("default") function to call each parsing function and
         retrieve various elements of the code, together with the source location.
 
         Returns a dict of parsed item key to the corresponding List of Matches.
         """
-        all_macros = {"public": [], "internal": [], "private":[]}
-        all_macros["public"] = self.parse_macros([
-            "include/psa/*.h",
-            "include/tf-psa-crypto/*.h",
-            "include/mbedtls/*.h",
-            "drivers/builtin/include/mbedtls/*.h",
-            "include/mbedtls/private/*.h",
-            "drivers/builtin/include/mbedtls/private/*.h",
-            "drivers/everest/include/everest/everest.h",
-            "drivers/everest/include/everest/x25519.h",
-            "drivers/everest/include/tf-psa-crypto/private/everest/everest.h",
-            "drivers/everest/include/tf-psa-crypto/private/everest/x25519.h"
-        ])
-        all_macros["internal"] = self.parse_macros([
-            "core/*.h",
-            "drivers/builtin/src/*.h",
-            "framework/tests/include/test/drivers/*.h",
-        ])
-        all_macros["private"] = self.parse_macros([
-            "core/*.c",
-            "drivers/builtin/src/*.c",
-        ])
-        enum_consts = self.parse_enum_consts([
-            "include/psa/*.h",
-            "include/tf-psa-crypto/*.h",
-            "include/mbedtls/*.h",
-            "drivers/builtin/include/mbedtls/*.h",
-            "include/mbedtls/private/*.h",
-            "drivers/builtin/include/mbedtls/private/*.h",
-            "core/*.h",
-            "drivers/builtin/src/*.h",
-            "core/*.c",
-            "drivers/builtin/src/*.c",
-            "drivers/everest/include/everest/everest.h",
-            "drivers/everest/include/everest/x25519.h",
-            "drivers/everest/include/tf-psa-crypto/private/everest/everest.h",
-            "drivers/everest/include/tf-psa-crypto/private/everest/x25519.h"
-        ])
-        identifiers, excluded_identifiers = self.parse_identifiers([
-            "include/psa/*.h",
-            "include/tf-psa-crypto/*.h",
-            "include/mbedtls/*.h",
-            "drivers/builtin/include/mbedtls/*.h",
-            "include/mbedtls/private/*.h",
-            "drivers/builtin/include/mbedtls/private/*.h",
-            "core/*.h",
-            "drivers/builtin/src/*.h",
-            "drivers/everest/include/everest/everest.h",
-            "drivers/everest/include/everest/x25519.h",
-            "drivers/everest/include/tf-psa-crypto/private/everest/everest.h",
-            "drivers/everest/include/tf-psa-crypto/private/everest/x25519.h"
-        ], ["drivers/p256-m/p256-m/p256-m.h"])
-        mbed_psa_words = self.parse_mbed_psa_words([
-            "include/psa/*.h",
-            "include/tf-psa-crypto/*.h",
-            "include/mbedtls/*.h",
-            "drivers/builtin/include/mbedtls/*.h",
-            "include/mbedtls/private/*.h",
-            "drivers/builtin/include/mbedtls/private/*.h",
-            "core/*.h",
-            "drivers/builtin/src/*.h",
-            "drivers/everest/include/everest/everest.h",
-            "drivers/everest/include/everest/x25519.h",
-            "drivers/everest/include/tf-psa-crypto/private/everest/everest.h",
-            "drivers/everest/include/tf-psa-crypto/private/everest/x25519.h",
-            "core/*.c",
-            "drivers/builtin/src/*.c",
-            "drivers/everest/library/everest.c",
-            "drivers/everest/library/x25519.c"
-        ], ["core/psa_crypto_driver_wrappers.h"])
+        all_macros = {"public": [], "internal": [], "private":[]} #type: Dict[str, List[Match]]
+        all_macros["public"] = self.parse_macros(self.H_PUBLIC,
+                                                 self.H_PUBLIC_EXCLUDE)
+        all_macros["internal"] = self.parse_macros(self.H_INTERNAL +
+                                                   self.H_TEST_DRIVERS)
+        all_macros["private"] = self.parse_macros(self.C_INTERNAL)
+        enum_consts = self.parse_enum_consts(
+            self.H_PUBLIC + self.H_INTERNAL + self.C_INTERNAL,
+            self.H_PUBLIC_EXCLUDE)
+        identifiers, excluded_identifiers = self.parse_identifiers(
+            self.H_PUBLIC + self.H_INTERNAL,
+            self.H_PUBLIC_EXCLUDE + ["drivers/p256-m/p256-m/p256-m.h"])
+        mbed_psa_words = self.parse_mbed_psa_words(
+            self.H_PUBLIC + self.H_INTERNAL + self.C_INTERNAL,
+            self.H_PUBLIC_EXCLUDE + ["core/psa_crypto_driver_wrappers.h"])
         symbols = self.parse_symbols()
 
         return self._parse(all_macros, enum_consts, identifiers,
                            excluded_identifiers, mbed_psa_words, symbols)
 
-    def parse_symbols(self):
+    def parse_symbols(self) -> List[str]:
         """
         Compile the TF-PSA-Crypto libraries, and parse the
         object files using nm to retrieve the list of referenced symbols.
@@ -794,7 +858,7 @@
             # Use check=True in all subprocess calls so that failures are raised
             # as exceptions and logged.
             subprocess.run(
-                ["python3", "scripts/config.py", "full"],
+                [sys.executable, "scripts/config.py", "full"],
                 universal_newlines=True,
                 check=True
             )
@@ -810,7 +874,7 @@
                 check=True
             )
             subprocess.run(
-                ["cmake", "--build", "."],
+                ["cmake", "--build", ".", "--target", "tfpsacrypto"],
                 env=my_environment,
                 universal_newlines=True,
                 stdout=subprocess.PIPE,
@@ -838,27 +902,28 @@
 
         return symbols
 
+
 class MBEDTLSCodeParser(CodeParser):
     """
     Class for retrieving files and parsing Mbed TLS code. This can be used
     independently of the checks that NameChecker performs.
     """
 
-    def __init__(self, log):
+    def __init__(self, log: logging.Logger) -> None:
         super().__init__(log)
         if not build_tree.looks_like_mbedtls_root(os.getcwd()):
             raise Exception("This script must be run from Mbed TLS root.")
 
-    def comprehensive_parse(self):
+    def comprehensive_parse(self) -> ParseResult:
         """
         Comprehensive ("default") function to call each parsing function and
         retrieve various elements of the code, together with the source location.
 
         Returns a dict of parsed item key to the corresponding List of Matches.
         """
-        all_macros = {"public": [], "internal": [], "private":[]}
+        all_macros = {"public": [], "internal": [], "private":[]} #type: Dict[str, List[Match]]
         # TF-PSA-Crypto is in the same repo in 3.6 so initalise variable here.
-        tf_psa_crypto_parse_result = {}
+        tf_psa_crypto_parse_result = None
 
         if build_tree.is_mbedtls_3_6():
             all_macros["public"] = self.parse_macros([
@@ -938,12 +1003,9 @@
         mbedtls_parse_result = self._parse(all_macros, enum_consts,
                                            identifiers, excluded_identifiers,
                                            mbed_psa_words, symbols)
-        # Combile results for Mbed TLS and TF-PSA-Crypto
-        for key in tf_psa_crypto_parse_result:
-            mbedtls_parse_result[key] += tf_psa_crypto_parse_result[key]
-        return mbedtls_parse_result
+        return mbedtls_parse_result.add(tf_psa_crypto_parse_result)
 
-    def parse_symbols(self):
+    def parse_symbols(self) -> List[str]:
         """
         Compile the Mbed TLS libraries, and parse the TLS, Crypto, and x509
         object files using nm to retrieve the list of referenced symbols.
@@ -965,7 +1027,7 @@
             # Use check=True in all subprocess calls so that failures are raised
             # as exceptions and logged.
             subprocess.run(
-                ["python3", "scripts/config.py", "full"],
+                [sys.executable, "scripts/config.py", "full"],
                 universal_newlines=True,
                 check=True
             )
@@ -981,7 +1043,7 @@
                 check=True
             )
             subprocess.run(
-                ["cmake", "--build", "."],
+                ["cmake", "--build", ".", "--target", "lib"],
                 env=my_environment,
                 universal_newlines=True,
                 stdout=subprocess.PIPE,
@@ -1018,15 +1080,18 @@
 
         return symbols
 
+
 class NameChecker():
     """
     Representation of the core name checking operation performed by this script.
     """
-    def __init__(self, parse_result, log):
+    def __init__(self,
+                 parse_result: ParseResult,
+                 log: logging.Logger) -> None:
         self.parse_result = parse_result
         self.log = log
 
-    def perform_checks(self, quiet=False):
+    def perform_checks(self, quiet=False) -> int:
         """
         A comprehensive checker that performs each check in order, and outputs
         a final verdict.
@@ -1062,7 +1127,18 @@
             self.log.info("PASS")
             return 0
 
-    def check_symbols_declared_in_header(self):
+    @staticmethod
+    def symbol_may_be_undeclared(symbol: str) -> bool:
+        """Whether it's ok for the symbol not to be declared in any header."""
+        # The mldsa-native and mlkem-native headers use preprocessor tricks
+        # to construct identifiers. We can't recognize those. If a symbol
+        # found in the binary is in the expected sub-namespace for those
+        # parts of the library, allow it to be undeclared.
+        if symbol.startswith('tf_psa_crypto_pqcp_'):
+            return True
+        return False
+
+    def check_symbols_declared_in_header(self) -> int:
         """
         Perform a check that all detected symbols in the library object files
         are properly declared in headers.
@@ -1070,24 +1146,52 @@
 
         Returns the number of problems that need fixing.
         """
-        problems = []
-        all_identifiers = self.parse_result["identifiers"] +  \
-            self.parse_result["excluded_identifiers"]
-
-        for symbol in self.parse_result["symbols"]:
-            found_symbol_declared = False
-            for identifier_match in all_identifiers:
-                if symbol == identifier_match.name:
-                    found_symbol_declared = True
-                    break
+        problems = [] #type: List[Problem]
+        all_identifiers = frozenset(
+            match.name
+            for match in (self.parse_result.identifiers +
+                          self.parse_result.excluded_identifiers))
 
-            if not found_symbol_declared:
+        for symbol in self.parse_result.symbols:
+            if self.symbol_may_be_undeclared(symbol):
+                continue
+            if symbol not in all_identifiers:
                 problems.append(SymbolNotInHeader(symbol))
 
         self.output_check_result("All symbols in header", problems)
         return len(problems)
 
-    def check_match_pattern(self, group_to_check, check_pattern):
+    BIGNUM_SHORTHANDS = frozenset(['biH', 'biL', 'ciH', 'ciL'])
+    def name_pattern_exception(self, group: str, match: Match) -> bool:
+        """Whether the given match is an exception to normal naming patterns.
+
+        If you add an exception, make sure to explain why!
+        """
+        # The platform requirements headers define macros that are meant to
+        # be consumed by system headers. These macros are in a namespace
+        # reserved by the C language (two initial underscores, or an
+        # initial underscore followed by an uppercase letter).
+        if group == 'internal_macros' and \
+           '_platform_requirements.h' in match.filename and \
+           re.match(r'_[A-Z_]', match.name):
+            return True
+        # We use some short macros that start with a lowercase letter
+        # internally in bignum code. They are grandfathered in. They
+        # may be in a header file, but only in a source directory, not
+        # in any publicly visible header.
+        if group == 'internal_macros' and \
+           match.name in self.BIGNUM_SHORTHANDS and \
+           '/bignum' in match.filename and 'include' not in match.filename:
+            return True
+        # Allow pqcp driver code to use private names of mldsa-native and
+        # mlkem-native. This is a necessary part of configuring them.
+        if re.match(r'ml[dk]_', match.name, re.I) and \
+           'drivers/pqcp/src/' in match.filename:
+            return True
+        return False
+
+    def check_match_pattern(self, group_to_check: str,
+                            check_pattern: Pattern) -> int:
         """
         Perform a check that all items of a group conform to a regex pattern.
         Assumes parse_names_in_source() was called before this.
@@ -1098,9 +1202,11 @@
 
         Returns the number of problems that need fixing.
         """
-        problems = []
+        problems = [] #type: List[Problem]
 
-        for item_match in self.parse_result[group_to_check]:
+        for item_match in getattr(self.parse_result, group_to_check):
+            if self.name_pattern_exception(group_to_check, item_match):
+                continue
             if not re.search(check_pattern, item_match.name):
                 problems.append(PatternMismatch(check_pattern, item_match))
             # Double underscore should not be used for names
@@ -1113,7 +1219,7 @@
             problems)
         return len(problems)
 
-    def check_for_typos(self):
+    def check_for_typos(self) -> int:
         """
         Perform a check that all words in the source code beginning with MBED are
         either defined as macros, or as enum constants.
@@ -1121,22 +1227,19 @@
 
         Returns the number of problems that need fixing.
         """
-        problems = []
+        problems = [] #type: List[Problem]
 
-        # Set comprehension, equivalent to a list comprehension wrapped by set()
-        all_caps_names = {
+        all_caps_names = frozenset(
             match.name
-            for match
-            in self.parse_result["public_macros"] +
-            self.parse_result["internal_macros"] +
-            self.parse_result["private_macros"] +
-            self.parse_result["enum_consts"]
-            }
+            for match in (self.parse_result.public_macros +
+                          self.parse_result.internal_macros +
+                          self.parse_result.private_macros +
+                          self.parse_result.enum_consts))
         typo_exclusion = re.compile(r"XXX|__|_$|^MBEDTLS_.*CONFIG_FILE$|"
                                     r"MBEDTLS_TEST_LIBTESTDRIVER*|"
                                     r"PSA_CRYPTO_DRIVER_TEST")
 
-        for name_match in self.parse_result["mbed_psa_words"]:
+        for name_match in self.parse_result.mbed_psa_words:
             found = name_match.name in all_caps_names
 
             # Since MBEDTLS_PSA_ACCEL_XXX defines are defined by the
@@ -1154,7 +1257,7 @@
         self.output_check_result("Likely typos", problems)
         return len(problems)
 
-    def output_check_result(self, name, problems):
+    def output_check_result(self, name: str, problems: List[Problem]) -> None:
         """
         Write out the PASS/FAIL status of a performed check depending on whether
         there were problems.
@@ -1170,7 +1273,8 @@
         else:
             self.log.info("{}: PASS".format(name))
 
-def main():
+
+def main() -> None:
     """
     Perform argument parsing, and create an instance of CodeParser and
     NameChecker to begin the core operation.
diff -Nru mbedtls-3.6.5/framework/scripts/check-python-files.sh mbedtls-3.6.6/framework/scripts/check-python-files.sh
--- mbedtls-3.6.5/framework/scripts/check-python-files.sh	2025-10-01 18:30:17.253482800 +0300
+++ mbedtls-3.6.6/framework/scripts/check-python-files.sh	2026-03-27 12:34:57.778063300 +0200
@@ -55,20 +55,40 @@
 fi
 
 echo 'Running pylint ...'
-$PYTHON -m pylint framework/scripts/*.py framework/scripts/mbedtls_framework/*.py scripts/*.py tests/scripts/*.py || {
+# When we move Python code between repositories, there is a transition
+# period during which code is duplicated between the old repository and
+# the new repository.
+# Pylint looks for duplicate code inside files that are mentioned in the
+# same invocation. When we move some code from A to B, we want to skip
+# duplicate-code checks between A and B. So we arrange for two separate
+# runs of pylint: one for the A files, and one for the others.
+# Remove exceptions below once the A file (or the moved code in the A file)
+# has been removed from all consuming branches.
+find framework/scripts scripts tests/scripts -name '*.py' \( \
+     ! -path scripts/abi_check.py \
+     ! -path scripts/code_size_compare.py \
+     ! -path scripts/ecp_comb_table.py \
+     ! -path tests/scripts/audit-validity-dates.py \
+     ! -path tests/scripts/generate_server9_bad_saltlen.py \
+     ! -path tests/scripts/psa_collect_statuses.py \
+     ! -path tests/scripts/run_demos.py \
+     ! -path tests/scripts/test_config_script.py \
+     ! -path framework/scripts/make_generated_files.py \
+        -exec $PYTHON -m pylint {} + \
+     -o -exec $PYTHON -m pylint {} + \) || {
     echo >&2 "pylint reported errors"
     ret=1
 }
 
 echo
 echo 'Running mypy ...'
-$PYTHON -m mypy framework/scripts/*.py framework/scripts/mbedtls_framework/*.py || {
+$PYTHON -m mypy framework/scripts || {
     echo >&2 "mypy reported errors in the framework"
     ret=1
 }
 
-$PYTHON -m mypy scripts/*.py tests/scripts/*.py || {
-    echo >&2 "pylint reported errors in the parent repository"
+$PYTHON -m mypy scripts tests/scripts || {
+    echo >&2 "mypy reported errors in the parent repository"
     ret=1
 }
 
diff -Nru mbedtls-3.6.5/framework/scripts/ci.requirements.txt mbedtls-3.6.6/framework/scripts/ci.requirements.txt
--- mbedtls-3.6.5/framework/scripts/ci.requirements.txt	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/scripts/ci.requirements.txt	2026-03-27 12:34:57.778508000 +0200
@@ -0,0 +1,11 @@
+# Python package requirements for Mbed TLS testing.
+
+# At the time of writing, only needed for scripts/audit-validity-dates.py.
+# It needs >=35.0.0 for correct operation, and that requires Python >=3.6.
+# >=35.0.0 also requires Rust to build from source, which we are forced to do on
+# FreeBSD, since PyPI doesn't carry binary wheels for the BSDs.
+cryptography >= 35.0.0; platform_system == 'Linux'
+
+# At the time of writing, only needed for
+# scripts/generate_server9_bad_saltlen.py.
+asn1crypto; platform_system == 'Linux'
diff -Nru mbedtls-3.6.5/framework/scripts/code_style.py mbedtls-3.6.6/framework/scripts/code_style.py
--- mbedtls-3.6.5/framework/scripts/code_style.py	2025-10-01 18:24:20.269536700 +0300
+++ mbedtls-3.6.6/framework/scripts/code_style.py	2026-03-27 12:34:57.778643600 +0200
@@ -15,7 +15,6 @@
 
 UNCRUSTIFY_SUPPORTED_VERSION = "0.75.1"
 CONFIG_FILE = ".uncrustify.cfg"
-UNCRUSTIFY_EXE = "uncrustify"
 UNCRUSTIFY_ARGS = ["-c", CONFIG_FILE]
 CHECK_GENERATED_FILES = "tests/scripts/check-generated-files.sh"
 
@@ -164,27 +163,30 @@
     output = subprocess.check_output(cmd, universal_newlines=True)
     return output.split()[2]
 
-def get_uncrustify_version() -> str:
+def get_uncrustify_version(uncrustify_exe: str) -> str:
     """
-    Get the version string from Uncrustify
+    Get the version string from Uncrustify.
+
+    Return an empty string if Uncrustify is not found.
     """
-    result = subprocess.run([UNCRUSTIFY_EXE, "--version"],
-                            stdout=subprocess.PIPE, stderr=subprocess.PIPE,
-                            check=False)
-    if result.returncode != 0:
-        print_err("Could not get Uncrustify version:", str(result.stderr, "utf-8"))
-        return ""
-    else:
-        return str(result.stdout, "utf-8")
+    try:
+        output = subprocess.check_output([uncrustify_exe, "--version"],
+                                         stderr=subprocess.PIPE)
+        return str(output, "utf-8").strip()
+    except FileNotFoundError:
+        sys.stderr.write('Fatal: command {} not found in PATH.\n'
+                         .format(uncrustify_exe))
+        return ''
 
-def check_style_is_correct(src_file_list: List[str]) -> bool:
+def check_style_is_correct(uncrustify_exe: str,
+                           src_file_list: List[str]) -> bool:
     """
     Check the code style and output a diff for each file whose style is
     incorrect.
     """
     style_correct = True
     for src_file in src_file_list:
-        uncrustify_cmd = [UNCRUSTIFY_EXE] + UNCRUSTIFY_ARGS + [src_file]
+        uncrustify_cmd = [uncrustify_exe] + UNCRUSTIFY_ARGS + [src_file]
         result = subprocess.run(uncrustify_cmd, stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE, check=False)
         if result.returncode != 0:
@@ -210,13 +212,14 @@
 
     return style_correct
 
-def fix_style_single_pass(src_file_list: List[str]) -> bool:
+def fix_style_single_pass(uncrustify_exe: str,
+                          src_file_list: List[str]) -> bool:
     """
     Run Uncrustify once over the source files.
     """
     code_change_args = UNCRUSTIFY_ARGS + ["--no-backup"]
     for src_file in src_file_list:
-        uncrustify_cmd = [UNCRUSTIFY_EXE] + code_change_args + [src_file]
+        uncrustify_cmd = [uncrustify_exe] + code_change_args + [src_file]
         result = subprocess.run(uncrustify_cmd, check=False)
         if result.returncode != 0:
             print_err("Uncrustify with file returned: " +
@@ -225,18 +228,18 @@
             return False
     return True
 
-def fix_style(src_file_list: List[str]) -> int:
+def fix_style(uncrustify_exe: str, src_file_list: List[str]) -> int:
     """
     Fix the code style. This takes 2 passes of Uncrustify.
     """
-    if not fix_style_single_pass(src_file_list):
+    if not fix_style_single_pass(uncrustify_exe, src_file_list):
         return 1
-    if not fix_style_single_pass(src_file_list):
+    if not fix_style_single_pass(uncrustify_exe, src_file_list):
         return 1
 
     # Guard against future changes that cause the codebase to require
     # more passes.
-    if not check_style_is_correct(src_file_list):
+    if not check_style_is_correct(uncrustify_exe, src_file_list):
         print_err("Code style still incorrect after second run of Uncrustify.")
         return 1
     else:
@@ -246,13 +249,6 @@
     """
     Main with command line arguments.
     """
-    uncrustify_version = get_uncrustify_version().strip()
-    if UNCRUSTIFY_SUPPORTED_VERSION not in uncrustify_version:
-        print("Warning: Using unsupported Uncrustify version '" +
-              uncrustify_version + "'")
-        print("Note: The only supported version is " +
-              UNCRUSTIFY_SUPPORTED_VERSION)
-
     parser = argparse.ArgumentParser()
     parser.add_argument('-f', '--fix', action='store_true',
                         help=('modify source files to fix the code style '
@@ -268,11 +264,23 @@
     # way to restyle a possibly empty set of files.
     parser.add_argument('--subset', action='store_true',
                         help='only check the specified files (default with non-option arguments)')
+    parser.add_argument('--uncrustify',
+                        default='uncrustify',
+                        help='uncrustify command to run (default: uncrustify)')
     parser.add_argument('operands', nargs='*', metavar='FILE',
                         help='files to check (files MUST be known to git, if none: check all)')
 
     args = parser.parse_args()
 
+    uncrustify_version = get_uncrustify_version(args.uncrustify)
+    if UNCRUSTIFY_SUPPORTED_VERSION not in uncrustify_version:
+        if uncrustify_version != '':
+            sys.stderr.write('Fatal: wrong uncrustify version ({}).\n'
+                             .format(uncrustify_version))
+        sys.stderr.write('You need uncrustify {} for correct results.\n'
+                         .format(UNCRUSTIFY_SUPPORTED_VERSION))
+        return 2
+
     covered = frozenset(get_src_files(args.since))
     # We only check files that are known to git
     if args.subset or args.operands:
@@ -285,10 +293,10 @@
 
     if args.fix:
         # Fix mode
-        return fix_style(src_files)
+        return fix_style(args.uncrustify, src_files)
     else:
         # Check mode
-        if check_style_is_correct(src_files):
+        if check_style_is_correct(args.uncrustify, src_files):
             print("Checked {} files, style ok.".format(len(src_files)))
             return 0
         else:
diff -Nru mbedtls-3.6.5/framework/scripts/ecp_comb_table.py mbedtls-3.6.6/framework/scripts/ecp_comb_table.py
--- mbedtls-3.6.5/framework/scripts/ecp_comb_table.py	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/scripts/ecp_comb_table.py	2026-03-27 12:34:57.779070400 +0200
@@ -0,0 +1,237 @@
+#!/usr/bin/env python3
+"""
+Purpose
+
+This script dumps comb table of ec curve. When you add a new ec curve, you
+can use this script to generate codes to define `<curve>_T` in ecp_curves.c
+"""
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+import os
+import subprocess
+import sys
+import tempfile
+
+HOW_TO_ADD_NEW_CURVE = """
+If you are trying to add new curve, you can follow these steps:
+
+1. Define curve parameters (<curve>_p, <curve>_gx, etc...) in ecp_curves.c.
+2. Add a macro to define <curve>_T to NULL following these parameters.
+3. Build mbedcrypto
+4. Run this script with an argument of new curve
+5. Copy the output of this script into ecp_curves.c and replace the macro added
+   in Step 2
+6. Rebuild and test if everything is ok
+
+Replace the <curve> in the above with the name of the curve you want to add."""
+
+CC = os.getenv('CC', 'cc')
+MBEDTLS_LIBRARY_PATH = os.getenv('MBEDTLS_LIBRARY_PATH', "library")
+
+SRC_DUMP_COMB_TABLE = r'''
+#include <stdio.h>
+#include <stdlib.h>
+#include "mbedtls/ecp.h"
+#include "mbedtls/error.h"
+
+static void dump_mpi_initialize( const char *name, const mbedtls_mpi *d )
+{
+    uint8_t buf[128] = {0};
+    size_t olen;
+    uint8_t *p;
+
+    olen = mbedtls_mpi_size( d );
+    mbedtls_mpi_write_binary_le( d, buf, olen );
+    printf("static const mbedtls_mpi_uint %s[] = {\n", name);
+    for (p = buf; p < buf + olen; p += 8) {
+        printf( "    BYTES_TO_T_UINT_8( 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X ),\n",
+                p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7] );
+    }
+    printf("};\n");
+}
+
+static void dump_T( const mbedtls_ecp_group *grp )
+{
+    char name[128];
+
+    printf( "#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1\n" );
+
+    for (size_t i = 0; i < grp->T_size; ++i) {
+        snprintf( name, sizeof(name), "%s_T_%zu_X", CURVE_NAME, i );
+        dump_mpi_initialize( name, &grp->T[i].X );
+
+        snprintf( name, sizeof(name), "%s_T_%zu_Y", CURVE_NAME, i );
+        dump_mpi_initialize( name, &grp->T[i].Y );
+    }
+    printf( "static const mbedtls_ecp_point %s_T[%zu] = {\n", CURVE_NAME, grp->T_size );
+    size_t olen;
+    for (size_t i = 0; i < grp->T_size; ++i) {
+        int z;
+        if ( mbedtls_mpi_cmp_int(&grp->T[i].Z, 0) == 0 ) {
+            z = 0;
+        } else if ( mbedtls_mpi_cmp_int(&grp->T[i].Z, 1) == 0 ) {
+            z = 1;
+        } else {
+            fprintf( stderr, "Unexpected value of Z (i = %d)\n", (int)i );
+            exit( 1 );
+        }
+        printf( "    ECP_POINT_INIT_XY_Z%d(%s_T_%zu_X, %s_T_%zu_Y),\n",
+                z,
+                CURVE_NAME, i,
+                CURVE_NAME, i
+        );
+    }
+    printf("};\n#endif\n\n");
+}
+
+int main()
+{
+    int rc;
+    mbedtls_mpi m;
+    mbedtls_ecp_point R;
+    mbedtls_ecp_group grp;
+
+    mbedtls_ecp_group_init( &grp );
+    rc = mbedtls_ecp_group_load( &grp, CURVE_ID );
+    if (rc != 0) {
+        char buf[100];
+        mbedtls_strerror( rc, buf, sizeof(buf) );
+        fprintf( stderr, "mbedtls_ecp_group_load: %s (-0x%x)\n", buf, -rc );
+        return 1;
+    }
+    grp.T = NULL;
+    mbedtls_ecp_point_init( &R );
+    mbedtls_mpi_init( &m);
+    mbedtls_mpi_lset( &m, 1 );
+    rc = mbedtls_ecp_mul( &grp, &R, &m, &grp.G, NULL, NULL );
+    if ( rc != 0 ) {
+        char buf[100];
+        mbedtls_strerror( rc, buf, sizeof(buf) );
+        fprintf( stderr, "mbedtls_ecp_mul: %s (-0x%x)\n", buf, -rc );
+        return 1;
+    }
+    if ( grp.T == NULL ) {
+        fprintf( stderr, "grp.T is not generated. Please make sure"
+                         "MBEDTLS_ECP_FIXED_POINT_OPTIM is enabled in mbedtls_config.h\n" );
+        return 1;
+    }
+    dump_T( &grp );
+    return 0;
+}
+'''
+
+SRC_DUMP_KNOWN_CURVE = r'''
+#include <stdio.h>
+#include <stdlib.h>
+#include "mbedtls/ecp.h"
+
+int main() {
+    const mbedtls_ecp_curve_info *info = mbedtls_ecp_curve_list();
+    mbedtls_ecp_group grp;
+
+    mbedtls_ecp_group_init( &grp );
+    while ( info->name != NULL ) {
+        mbedtls_ecp_group_load( &grp, info->grp_id );
+        if ( mbedtls_ecp_get_type(&grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS ) {
+            printf( " %s", info->name );
+        }
+        info++;
+    }
+    printf( "\n" );
+    return 0;
+}
+'''
+
+
+def join_src_path(*args):
+    return os.path.normpath(os.path.join(os.path.dirname(__file__), "..", *args))
+
+
+def run_c_source(src, cflags):
+    """
+    Compile and run C source code
+    :param src: the c language code to run
+    :param cflags: additional cflags passing to compiler
+    :return:
+    """
+    binname = tempfile.mktemp(prefix="mbedtls")
+    fd, srcname = tempfile.mkstemp(prefix="mbedtls", suffix=".c")
+    srcfile = os.fdopen(fd, mode="w")
+    srcfile.write(src)
+    srcfile.close()
+    args = [CC,
+            *cflags,
+            '-I' + join_src_path("include"),
+            "-o", binname,
+            '-L' + MBEDTLS_LIBRARY_PATH,
+            srcname,
+            '-lmbedcrypto']
+
+    p = subprocess.run(args=args, check=False)
+    if p.returncode != 0:
+        return False
+    p = subprocess.run(args=[binname], check=False, env={
+        'LD_LIBRARY_PATH': MBEDTLS_LIBRARY_PATH
+    })
+    if p.returncode != 0:
+        return False
+    os.unlink(srcname)
+    os.unlink(binname)
+    return True
+
+
+def compute_curve(curve):
+    """compute comb table for curve"""
+    r = run_c_source(
+        SRC_DUMP_COMB_TABLE,
+        [
+            '-g',
+            '-DCURVE_ID=MBEDTLS_ECP_DP_%s' % curve.upper(),
+            '-DCURVE_NAME="%s"' % curve.lower(),
+        ])
+    if not r:
+        print("""\
+Unable to compile and run utility.""", file=sys.stderr)
+        sys.exit(1)
+
+
+def usage():
+    print("""
+Usage: python %s <curve>...
+
+Arguments:
+    curve       Specify one or more curve names (e.g secp256r1)
+
+All possible curves: """ % sys.argv[0])
+    run_c_source(SRC_DUMP_KNOWN_CURVE, [])
+    print("""
+Environment Variable:
+    CC          Specify which c compile to use to compile utility.
+    MBEDTLS_LIBRARY_PATH
+                Specify the path to mbedcrypto library. (e.g. build/library/)
+
+How to add a new curve: %s""" % HOW_TO_ADD_NEW_CURVE)
+
+
+def run_main():
+    shared_lib_path = os.path.normpath(os.path.join(MBEDTLS_LIBRARY_PATH, "libmbedcrypto.so"))
+    static_lib_path = os.path.normpath(os.path.join(MBEDTLS_LIBRARY_PATH, "libmbedcrypto.a"))
+    if not os.path.exists(shared_lib_path) and not os.path.exists(static_lib_path):
+        print("Warning: both '%s' and '%s' are not exists. This script will use "
+              "the library from your system instead of the library compiled by "
+              "this source directory.\n"
+              "You can specify library path using environment variable "
+              "'MBEDTLS_LIBRARY_PATH'." % (shared_lib_path, static_lib_path),
+              file=sys.stderr)
+
+    if len(sys.argv) <= 1:
+        usage()
+    else:
+        for curve in sys.argv[1:]:
+            compute_curve(curve)
+
+
+if __name__ == '__main__':
+    run_main()
diff -Nru mbedtls-3.6.5/framework/scripts/gen_ctr_drbg.pl mbedtls-3.6.6/framework/scripts/gen_ctr_drbg.pl
--- mbedtls-3.6.5/framework/scripts/gen_ctr_drbg.pl	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/scripts/gen_ctr_drbg.pl	2026-03-27 12:34:57.779210000 +0200
@@ -0,0 +1,96 @@
+#!/usr/bin/env perl
+#
+# Based on NIST CTR_DRBG.rsp validation file
+# Only uses AES-256-CTR cases that use a Derivation function
+# and concats nonce and personalization for initialization.
+#
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+use strict;
+
+my $file = shift;
+
+open(TEST_DATA, "$file") or die "Opening test cases '$file': $!";
+
+sub get_suite_val($)
+{
+    my $name = shift;
+    my $val = "";
+
+    my $line = <TEST_DATA>;
+    ($val) = ($line =~ /\[$name\s\=\s(\w+)\]/);
+
+    return $val;
+}
+
+sub get_val($)
+{
+    my $name = shift;
+    my $val = "";
+    my $line;
+
+    while($line = <TEST_DATA>)
+    {
+        next if($line !~ /=/);
+        last;
+    }
+
+    ($val) = ($line =~ /^$name = (\w+)/);
+
+    return $val;
+}
+
+my $cnt = 1;;
+while (my $line = <TEST_DATA>)
+{
+    next if ($line !~ /^\[AES-256 use df/);
+
+    my $PredictionResistanceStr = get_suite_val("PredictionResistance");
+    my $PredictionResistance = 0;
+    $PredictionResistance = 1 if ($PredictionResistanceStr eq 'True');
+    my $EntropyInputLen = get_suite_val("EntropyInputLen");
+    my $NonceLen = get_suite_val("NonceLen");
+    my $PersonalizationStringLen = get_suite_val("PersonalizationStringLen");
+    my $AdditionalInputLen = get_suite_val("AdditionalInputLen");
+
+    for ($cnt = 0; $cnt < 15; $cnt++)
+    {
+        my $Count = get_val("COUNT");
+        my $EntropyInput = get_val("EntropyInput");
+        my $Nonce = get_val("Nonce");
+        my $PersonalizationString = get_val("PersonalizationString");
+        my $AdditionalInput1 = get_val("AdditionalInput");
+        my $EntropyInputPR1 = get_val("EntropyInputPR") if ($PredictionResistance == 1);
+        my $EntropyInputReseed = get_val("EntropyInputReseed") if ($PredictionResistance == 0);
+        my $AdditionalInputReseed = get_val("AdditionalInputReseed") if ($PredictionResistance == 0);
+        my $AdditionalInput2 = get_val("AdditionalInput");
+        my $EntropyInputPR2 = get_val("EntropyInputPR") if ($PredictionResistance == 1);
+        my $ReturnedBits = get_val("ReturnedBits");
+
+        if ($PredictionResistance == 1)
+        {
+            print("CTR_DRBG NIST Validation (AES-256 use df,$PredictionResistanceStr,$EntropyInputLen,$NonceLen,$PersonalizationStringLen,$AdditionalInputLen) #$Count\n");
+            print("ctr_drbg_validate_pr");
+            print(":\"$Nonce$PersonalizationString\"");
+            print(":\"$EntropyInput$EntropyInputPR1$EntropyInputPR2\"");
+            print(":\"$AdditionalInput1\"");
+            print(":\"$AdditionalInput2\"");
+            print(":\"$ReturnedBits\"");
+            print("\n\n");
+        }
+        else
+        {
+            print("CTR_DRBG NIST Validation (AES-256 use df,$PredictionResistanceStr,$EntropyInputLen,$NonceLen,$PersonalizationStringLen,$AdditionalInputLen) #$Count\n");
+            print("ctr_drbg_validate_nopr");
+            print(":\"$Nonce$PersonalizationString\"");
+            print(":\"$EntropyInput$EntropyInputReseed\"");
+            print(":\"$AdditionalInput1\"");
+            print(":\"$AdditionalInputReseed\"");
+            print(":\"$AdditionalInput2\"");
+            print(":\"$ReturnedBits\"");
+            print("\n\n");
+        }
+    }
+}
+close(TEST_DATA);
diff -Nru mbedtls-3.6.5/framework/scripts/generate-afl-tests.sh mbedtls-3.6.6/framework/scripts/generate-afl-tests.sh
--- mbedtls-3.6.5/framework/scripts/generate-afl-tests.sh	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/scripts/generate-afl-tests.sh	2026-03-27 12:34:57.779496200 +0200
@@ -0,0 +1,71 @@
+#!/bin/sh
+
+# This script splits the data test files containing the test cases into
+# individual files (one test case per file) suitable for use with afl
+# (American Fuzzy Lop). http://lcamtuf.coredump.cx/afl/
+#
+# Usage: generate-afl-tests.sh <test data file path>
+#  <test data file path> - should be the path to one of the test suite files
+#                          such as 'test_suite_rsa.data'
+#
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+# Abort on errors
+set -e
+
+if [ -z $1 ]
+then
+    echo " [!] No test file specified" >&2
+    echo "Usage: $0 <test data file>" >&2
+    exit 1
+fi
+
+SRC_FILEPATH=$(dirname $1)/$(basename $1)
+TESTSUITE=$(basename $1 .data)
+
+THIS_DIR=$(basename $PWD)
+
+if [ -d ../library -a -d ../include -a -d ../tests -a $THIS_DIR == "tests" ];
+then :;
+else
+    echo " [!] Must be run from Mbed TLS tests directory" >&2
+    exit 1
+fi
+
+DEST_TESTCASE_DIR=$TESTSUITE-afl-tests
+DEST_OUTPUT_DIR=$TESTSUITE-afl-out
+
+echo " [+] Creating output directories" >&2
+
+if [ -e $DEST_OUTPUT_DIR/* ];
+then :
+    echo " [!] Test output files already exist." >&2
+    exit 1
+else
+    mkdir -p $DEST_OUTPUT_DIR
+fi
+
+if [ -e $DEST_TESTCASE_DIR/* ];
+then :
+    echo " [!] Test output files already exist." >&2
+else
+    mkdir -p $DEST_TESTCASE_DIR
+fi
+
+echo " [+] Creating test cases" >&2
+cd $DEST_TESTCASE_DIR
+
+split -p '^\s*$' ../$SRC_FILEPATH
+
+for f in *;
+do
+    # Strip out any blank lines (no trim on OS X)
+    sed '/^\s*$/d' $f >testcase_$f
+    rm $f
+done
+
+cd ..
+
+echo " [+] Test cases in $DEST_TESTCASE_DIR" >&2
+
diff -Nru mbedtls-3.6.5/framework/scripts/generate_config_tests.py mbedtls-3.6.6/framework/scripts/generate_config_tests.py
--- mbedtls-3.6.5/framework/scripts/generate_config_tests.py	2025-10-01 18:24:20.270137800 +0300
+++ mbedtls-3.6.6/framework/scripts/generate_config_tests.py	2026-03-27 12:34:57.779690700 +0200
@@ -69,8 +69,8 @@
     SIMPLE_DEPENDENCIES['MBEDTLS_NO_PLATFORM_ENTROPY'] = 'MBEDTLS_ENTROPY_C'
 
 BUILTIN_MODULE_ENABLEMENT_MACROS = [
-    'MBEDTLS_AES_C', 'MBEDTLS_CAMELLIA_C', 'MBEDTLS_CIPHER_C', 'MBEDTLS_GCM_C',
-    'MBEDTLS_ECDH_C', 'MBEDTLS_ECDSA_C', 'MBEDTLS_ECP_C',
+    'MBEDTLS_AES_C', 'MBEDTLS_CAMELLIA_C', 'MBEDTLS_GCM_C',
+    'MBEDTLS_ECP_C',
     'MBEDTLS_RSA_C',
     'MBEDTLS_SHA256_C', 'MBEDTLS_SHA512_C',
 ]
@@ -116,6 +116,13 @@
             return 'MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_SSL_PROTO_DTLS'
         if name.startswith('MBEDTLS_SSL_'):
             return 'MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C'
+        if name == 'MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED' and \
+           not build_tree.is_mbedtls_3_6():
+            # In 1.x the module ecdh.c is removed. This option remains, with its
+            # historical name for compatibility. It is still only relevant when
+            # the built-in implementation of ECDH is enabled, but this condition
+            # is no longer expressed as MBEDTLS_ECDH_C.
+            return 'MBEDTLS_PSA_BUILTIN_ALG_ECDH'
         for pos in re.finditer(r'_', name):
             super_name = name[:pos.start()] + '_C'
             if cfg.known(super_name):
diff -Nru mbedtls-3.6.5/framework/scripts/generate_psa_tests.py mbedtls-3.6.6/framework/scripts/generate_psa_tests.py
--- mbedtls-3.6.5/framework/scripts/generate_psa_tests.py	2025-10-01 18:30:17.256609400 +0300
+++ mbedtls-3.6.6/framework/scripts/generate_psa_tests.py	2026-03-27 12:34:57.780206700 +0200
@@ -253,6 +253,9 @@
         arguments = [] # type: List[str]
         if kt:
             bits = kt.sizes_to_test()[0]
+            if pretty_alg == "XTS" and kt.can_do(alg):
+                # XTS mode uses double-size keys for the underlying block cipher
+                bits = bits * 2
             tc.set_key_bits(bits)
             tc.set_key_pair_usage(['IMPORT'])
             key_material = kt.key_material(bits)
@@ -338,23 +341,31 @@
     def test_cases_for_algorithm(
             self,
             alg: crypto_knowledge.Algorithm,
+            categories: Iterable[crypto_knowledge.AlgorithmCategory]
     ) -> Iterator[test_case.TestCase]:
         """Generate operation failure test cases for the specified algorithm."""
-        for category in crypto_knowledge.AlgorithmCategory:
-            if category == crypto_knowledge.AlgorithmCategory.PAKE:
-                # PAKE operations are not implemented yet
-                pass
-            elif category.requires_key():
+        for category in categories:
+            if category.requires_key():
                 yield from self.one_key_test_cases(alg, category)
             else:
                 yield from self.no_key_test_cases(alg, category)
 
     def all_test_cases(self) -> Iterator[test_case.TestCase]:
         """Generate all test cases for operations that must fail."""
-        algorithms = sorted(self.constructors.algorithms)
-        for expr in self.constructors.generate_expressions(algorithms):
-            alg = crypto_knowledge.Algorithm(expr)
-            yield from self.test_cases_for_algorithm(alg)
+        algorithm_constructors = sorted(self.constructors.algorithms)
+        algorithms = [crypto_knowledge.Algorithm(alg)
+                      for alg in self.constructors.generate_expressions(
+                          algorithm_constructors)]
+        supported_categories = set()
+        for alg in algorithms:
+            supported_categories.add(alg.category)
+        # We don't have a pake_fail test function yet.
+        # https://github.com/Mbed-TLS/mbedtls-framework/issues/263
+        supported_categories.remove(crypto_knowledge.AlgorithmCategory.PAKE)
+        categories = sorted(supported_categories, key=lambda cat: cat.value)
+        assert categories # sanity check: at least one category detected
+        for alg in algorithms:
+            yield from self.test_cases_for_algorithm(alg, categories)
 
 
 class StorageKey(psa_storage.Key):
@@ -638,6 +649,13 @@
             compatible_algorithms = [alg for alg in all_algorithms
                                      if kt.can_do(alg)]
             for alg in compatible_algorithms:
+                if alg.expression == 'PSA_ALG_XTS':
+                    # XTS mode uses double-size keys for the underlying block cipher
+                    # XTS does not use 192-bit keys
+                    if bits != 192:
+                        bits = bits * 2
+                    else:
+                        continue
                 yield self.key_for_type_and_alg(kt, bits, alg)
 
     def all_keys_for_types(self) -> Iterator[StorageTestData]:
diff -Nru mbedtls-3.6.5/framework/scripts/generate_server9_bad_saltlen.py mbedtls-3.6.6/framework/scripts/generate_server9_bad_saltlen.py
--- mbedtls-3.6.5/framework/scripts/generate_server9_bad_saltlen.py	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/scripts/generate_server9_bad_saltlen.py	2026-03-27 12:34:57.780456800 +0200
@@ -0,0 +1,87 @@
+#!/usr/bin/env python3
+"""Generate server9-bad-saltlen.crt
+
+Generate a certificate signed with RSA-PSS, with an incorrect salt length.
+"""
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+import subprocess
+import argparse
+from asn1crypto import pem, x509, core #type: ignore #pylint: disable=import-error
+
+OPENSSL_RSA_PSS_CERT_COMMAND = r'''
+openssl x509 -req -CA {ca_name}.crt -CAkey {ca_name}.key -set_serial 24 {ca_password} \
+    {openssl_extfile} -days 3650 -outform DER -in {csr}  \
+    -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:{anounce_saltlen} \
+    -sigopt rsa_mgf1_md:sha256
+'''
+SIG_OPT = \
+    r'-sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:{saltlen} -sigopt rsa_mgf1_md:sha256'
+OPENSSL_RSA_PSS_DGST_COMMAND = r'''openssl dgst -sign {ca_name}.key {ca_password} \
+    -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:{actual_saltlen} \
+    -sigopt rsa_mgf1_md:sha256'''
+
+
+def auto_int(x):
+    return int(x, 0)
+
+
+def build_argparser(parser):
+    """Build argument parser"""
+    parser.description = __doc__
+    parser.add_argument('--ca-name', type=str, required=True,
+                        help='Basename of CA files')
+    parser.add_argument('--ca-password', type=str,
+                        required=True, help='CA key file password')
+    parser.add_argument('--csr', type=str, required=True,
+                        help='CSR file for generating certificate')
+    parser.add_argument('--openssl-extfile', type=str,
+                        required=True, help='X905 v3 extension config file')
+    parser.add_argument('--anounce_saltlen', type=auto_int,
+                        required=True, help='Announced salt length')
+    parser.add_argument('--actual_saltlen', type=auto_int,
+                        required=True, help='Actual salt length')
+    parser.add_argument('--output', type=str, required=True)
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    build_argparser(parser)
+    args = parser.parse_args()
+
+    return generate(**vars(args))
+
+def generate(**kwargs):
+    """Generate different salt length certificate file."""
+    ca_password = kwargs.get('ca_password', '')
+    if ca_password:
+        kwargs['ca_password'] = r'-passin "pass:{ca_password}"'.format(
+            **kwargs)
+    else:
+        kwargs['ca_password'] = ''
+    extfile = kwargs.get('openssl_extfile', '')
+    if extfile:
+        kwargs['openssl_extfile'] = '-extfile {openssl_extfile}'.format(
+            **kwargs)
+    else:
+        kwargs['openssl_extfile'] = ''
+
+    cmd = OPENSSL_RSA_PSS_CERT_COMMAND.format(**kwargs)
+    der_bytes = subprocess.check_output(cmd, shell=True)
+    target_certificate = x509.Certificate.load(der_bytes)
+
+    cmd = OPENSSL_RSA_PSS_DGST_COMMAND.format(**kwargs)
+    #pylint: disable=unexpected-keyword-arg
+    der_bytes = subprocess.check_output(cmd,
+                                        input=target_certificate['tbs_certificate'].dump(),
+                                        shell=True)
+
+    with open(kwargs.get('output'), 'wb') as f:
+        target_certificate['signature_value'] = core.OctetBitString(der_bytes)
+        f.write(pem.armor('CERTIFICATE', target_certificate.dump()))
+
+
+if __name__ == '__main__':
+    main()
diff -Nru mbedtls-3.6.5/framework/scripts/generate_test_cert_macros.py mbedtls-3.6.6/framework/scripts/generate_test_cert_macros.py
--- mbedtls-3.6.5/framework/scripts/generate_test_cert_macros.py	2025-10-01 18:24:20.270959400 +0300
+++ mbedtls-3.6.6/framework/scripts/generate_test_cert_macros.py	2026-03-27 12:34:57.780732000 +0200
@@ -60,7 +60,8 @@
     args = parser.parse_args()
 
     if args.list_dependencies:
-        files_list = [arg[2] for arg in INPUT_ARGS]
+        files_list = [arg[2] for arg in INPUT_ARGS
+                      if arg[0] != "password"]
         print(" ".join(files_list))
         return
 
diff -Nru mbedtls-3.6.5/framework/scripts/generate_test_code.py mbedtls-3.6.6/framework/scripts/generate_test_code.py
--- mbedtls-3.6.5/framework/scripts/generate_test_code.py	2025-10-01 18:24:20.271121000 +0300
+++ mbedtls-3.6.6/framework/scripts/generate_test_code.py	2026-03-27 12:34:57.780870400 +0200
@@ -762,7 +762,7 @@
         raise ValueError('Expected split character. Found string!')
     out = re.sub(r'(\\.)|' + split_char,
                  lambda m: m.group(1) or '\n', inp_str,
-                 len(inp_str)).split('\n')
+                 count=len(inp_str)).split('\n')
     out = [x for x in out if x]
     return out
 
diff -Nru mbedtls-3.6.5/framework/scripts/generate_test_keys.py mbedtls-3.6.6/framework/scripts/generate_test_keys.py
--- mbedtls-3.6.5/framework/scripts/generate_test_keys.py	2025-10-01 18:24:20.271312200 +0300
+++ mbedtls-3.6.6/framework/scripts/generate_test_keys.py	2026-03-27 12:34:57.781023300 +0200
@@ -15,7 +15,8 @@
 BYTES_PER_LINE = 16
 
 def c_byte_array_literal_content(array_name: str, key_data: bytes) -> Iterator[str]:
-    yield 'const unsigned char '
+    """Return C code that defines array_name as a byte array with the given content."""
+    yield 'static const unsigned char '
     yield array_name
     yield '[] = {'
     for index in range(0, len(key_data), BYTES_PER_LINE):
@@ -27,16 +28,23 @@
 def convert_der_to_c(array_name: str, key_data: bytes) -> str:
     return ''.join(c_byte_array_literal_content(array_name, key_data))
 
-def get_key_type(key: str) -> str:
-    if re.match('PSA_KEY_TYPE_RSA_.*', key):
-        return "rsa"
-    elif re.match('PSA_KEY_TYPE_ECC_.*', key):
+def get_key_type(key_type: str) -> str:
+    """Short name for a PSA key type."""
+    if key_type.startswith('PSA_KEY_TYPE_ECC_'):
         return "ec"
+    elif key_type.startswith('PSA_KEY_TYPE_ML_DSA_'):
+        return "mldsa"
+    elif key_type.startswith('PSA_KEY_TYPE_ML_KEM_'):
+        return "mlkem"
+    elif key_type.startswith('PSA_KEY_TYPE_RSA_'):
+        return "rsa"
+    elif key_type.startswith('PSA_KEY_TYPE_SLH_DSA_'):
+        return "slhdsa"
     else:
-        print("Unhandled key type {}".format(key))
-        return "unknown"
+        raise Exception(f"Unhandled key type {key_type}")
 
 def get_ec_key_family(key: str) -> str:
+    """Extract "PSA_ECC_xxx" from "PSA_KEY_TYPE_ECC_ttt(PSA_ECC_xxx)"."""
     match = re.search(r'.*\((.*)\)', key)
     if match is None:
         raise Exception("Unable to get EC family from {}".format(key))
@@ -70,6 +78,7 @@
 }
 
 def get_ec_curve_name(priv_key: str, bits: int) -> str:
+    """Short name for an elliptic curve key type."""
     ec_family = get_ec_key_family(priv_key)
     try:
         prefix = EC_NAME_CONVERSION[ec_family][bits][0]
@@ -78,8 +87,15 @@
         return ""
     return prefix + str(bits) + suffix
 
+def get_slh_dsa_family(key_type: str) -> str:
+    """Short name from an SLH-DSA family."""
+    m = re.search(r'PSA_SLH_FAMILY_(\w+)', key_type)
+    assert m
+    return m.group(1).replace('_', '').lower()
+
 def get_look_up_table_entry(key_type: str, group_id_or_keybits: str,
                             priv_array_name: str, pub_array_name: str) -> Iterator[str]:
+    """Yield C code lines for the definition of a key pair and its matching public key."""
     if key_type == "ec":
         yield "    {{ {}, 0,\n".format(group_id_or_keybits)
     else:
@@ -89,12 +105,25 @@
 
 
 def write_output_file(output_file_name: str, arrays: str, look_up_table: str):
+    """Write generated content to the output file"""
     with open(output_file_name, 'wt') as output:
         output.write("""\
 /*********************************************************************************
  * This file was automatically generated from framework/scripts/generate_test_keys.py.
  * Please do not edit it manually.
  *********************************************************************************/
+
+#ifndef TEST_TEST_KEYS_H
+#define TEST_TEST_KEYS_H
+
+#if TF_PSA_CRYPTO_VERSION_MAJOR >= 1
+#include <tf_psa_crypto_common.h>
+#include <mbedtls/private/ecp.h>
+#else
+#include <common.h>
+#include <mbedtls/ecp.h>
+#endif
+
 """)
         output.write(arrays)
         output.write("""
@@ -107,10 +136,12 @@
     size_t pub_key_len;
 }};
 
-struct predefined_key_element predefined_keys[] = {{
+MBEDTLS_MAYBE_UNUSED static struct predefined_key_element predefined_keys[] = {{
 {}
 }};
 
+#endif /* TEST_TEST_KEYS_H */
+
 /* End of generated file */
 """.format(look_up_table))
 
@@ -132,10 +163,6 @@
 
     for priv_key in priv_keys:
         key_type = get_key_type(priv_key)
-        # Ignore keys which are not EC or RSA
-        if key_type == "unknown":
-            continue
-
         pub_key = re.sub('_KEY_PAIR', '_PUBLIC_KEY', priv_key)
 
         for bits in ASYMMETRIC_KEY_DATA[priv_key]:
@@ -145,10 +172,13 @@
                 if curve == "":
                     continue
             # Create output array name
-            if key_type == "rsa":
-                array_name_base = "_".join(["test", key_type, str(bits)])
-            else:
+            if key_type == "ec":
                 array_name_base = "_".join(["test", key_type, curve])
+            elif key_type == "slhdsa":
+                family = get_slh_dsa_family(priv_key)
+                array_name_base = "_".join(["test", key_type, family, str(bits)])
+            else:
+                array_name_base = "_".join(["test", key_type, str(bits)])
             array_name_priv = array_name_base + "_priv"
             array_name_pub = array_name_base + "_pub"
             # Convert bytearray to C array
@@ -167,6 +197,7 @@
     return ''.join(arrays), '\n'.join(look_up_table)
 
 def main() -> None:
+    """Command line entry point."""
     default_output_path = build_tree.guess_project_root() + "/tests/include/test/test_keys.h"
 
     argparser = argparse.ArgumentParser()
@@ -179,6 +210,8 @@
     # tf-psa-crypto. It only remains available for 3.6 LTS branch.
     if not build_tree.is_mbedtls_3_6():
         del EC_NAME_CONVERSION['PSA_ECC_FAMILY_SECP_R1'][224]
+        del EC_NAME_CONVERSION['PSA_ECC_FAMILY_SECP_R1'][192]
+        del EC_NAME_CONVERSION['PSA_ECC_FAMILY_SECP_K1'][192]
 
     arrays, look_up_table = collect_keys()
 
diff -Nru mbedtls-3.6.5/framework/scripts/generate_tls_handshake_tests.py mbedtls-3.6.6/framework/scripts/generate_tls_handshake_tests.py
--- mbedtls-3.6.5/framework/scripts/generate_tls_handshake_tests.py	2025-10-01 18:24:20.271565000 +0300
+++ mbedtls-3.6.6/framework/scripts/generate_tls_handshake_tests.py	2026-03-27 12:34:57.781224000 +0200
@@ -1,219 +1,16 @@
 #!/usr/bin/env python3
-
 """
 Generate miscellaneous TLS test cases relating to the handshake.
+
+Transitional wrapper to facilitate the migration of consuming branches.
 """
 
 # Copyright The Mbed TLS Contributors
 # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
 
-import argparse
-import os
 import sys
-from typing import Optional
-
-from mbedtls_framework import tls_test_case
-from mbedtls_framework import typing_util
-from mbedtls_framework.tls_test_case import Side, Version
-import translate_ciphers
-
-
-# Assume that a TLS 1.2 ClientHello used in these tests will be at most
-# this many bytes long.
-TLS12_CLIENT_HELLO_ASSUMED_MAX_LENGTH = 255
-
-# Minimum handshake fragment length that Mbed TLS supports.
-TLS_HANDSHAKE_FRAGMENT_MIN_LENGTH = 4
-
-def write_tls_handshake_defragmentation_test(
-        #pylint: disable=too-many-arguments
-        out: typing_util.Writable,
-        side: Side,
-        length: Optional[int],
-        version: Optional[Version] = None,
-        cipher: Optional[str] = None,
-        etm: Optional[bool] = None, #encrypt-then-mac (only relevant for CBC)
-        variant: str = ''
-) -> None:
-    """Generate one TLS handshake defragmentation test.
-
-    :param out: file to write to.
-    :param side: which side is Mbed TLS.
-    :param length: fragment length, or None to not fragment.
-    :param version: protocol version, if forced.
-    """
-    #pylint: disable=chained-comparison,too-many-branches,too-many-statements
-
-    our_args = ''
-    their_args = ''
-
-    if length is None:
-        description = 'no fragmentation, for reference'
-    else:
-        description = 'len=' + str(length)
-    if version is not None:
-        description += ', TLS 1.' + str(version.value)
-    description = f'Handshake defragmentation on {side.name.lower()}: {description}'
-    tc = tls_test_case.TestCase(description)
-
-    if version is not None:
-        their_args += ' ' + version.openssl_option()
-        # Emit a version requirement, because we're forcing the version via
-        # OpenSSL, not via Mbed TLS, and the automatic depdendencies in
-        # ssl-opt.sh only handle forcing the version via Mbed TLS.
-        tc.requirements.append(version.requires_command())
-        if side == Side.SERVER and version == Version.TLS12 and \
-           length is not None and \
-           length <= TLS12_CLIENT_HELLO_ASSUMED_MAX_LENGTH:
-            # Server-side ClientHello defragmentation is only supported in
-            # the TLS 1.3 message parser. When that parser sees an 1.2-only
-            # ClientHello, it forwards the reassembled record to the
-            # TLS 1.2 ClientHello parser so the ClientHello can be fragmented.
-            # When TLS 1.3 support is disabled in the server (at compile-time
-            # or at runtime), the TLS 1.2 ClientHello parser only sees
-            # the first fragment of the ClientHello.
-            tc.requirements.append('requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3')
-            tc.description += ' with 1.3 support'
-
-    # To guarantee that the handhake messages are large enough and need to be
-    # split into fragments, the tests require certificate authentication.
-    # The party in control of the fragmentation operations is OpenSSL and
-    # will always use server5.crt (548 Bytes).
-    if length is not None and \
-       length >= TLS_HANDSHAKE_FRAGMENT_MIN_LENGTH:
-        tc.requirements.append('requires_certificate_authentication')
-        if version == Version.TLS12 and side == Side.CLIENT:
-            #The server uses an ECDSA cert, so make sure we have a compatible key exchange
-            tc.requirements.append(
-                'requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED')
-    else:
-        # This test case may run in a pure-PSK configuration. OpenSSL doesn't
-        # allow this by default with TLS 1.3.
-        their_args += ' -allow_no_dhe_kex'
-
-    if length is None:
-        forbidden_patterns = [
-            'waiting for more fragments',
-        ]
-        wanted_patterns = []
-    elif length < TLS_HANDSHAKE_FRAGMENT_MIN_LENGTH:
-        their_args += ' -split_send_frag ' + str(length)
-        tc.exit_code = 1
-        forbidden_patterns = []
-        wanted_patterns = [
-            'handshake message too short: ' + str(length),
-            'SSL - An invalid SSL record was received',
-        ]
-        if side == Side.SERVER:
-            wanted_patterns[0:0] = ['<= parse client hello']
-        elif version == Version.TLS13:
-            wanted_patterns[0:0] = ['=> ssl_tls13_process_server_hello']
-    else:
-        their_args += ' -split_send_frag ' + str(length)
-        forbidden_patterns = []
-        wanted_patterns = [
-            'reassembled record',
-            fr'initial handshake fragment: {length}, 0\.\.{length} of [0-9]\+',
-            fr'subsequent handshake fragment: [0-9]\+, {length}\.\.',
-            fr'Prepare: waiting for more handshake fragments {length}/',
-            fr'Consume: waiting for more handshake fragments {length}/',
-        ]
-
-    if cipher is not None:
-        mbedtls_cipher = translate_ciphers.translate_mbedtls(cipher)
-        if side == Side.CLIENT:
-            our_args += ' force_ciphersuite=' + mbedtls_cipher
-            if 'NULL' in cipher:
-                their_args += ' -cipher ALL@SECLEVEL=0:COMPLEMENTOFALL@SECLEVEL=0'
-        else:
-            # For TLS 1.2, when Mbed TLS is the server, we must force the
-            # cipher suite on the client side, because passing
-            # force_ciphersuite to ssl_server2 would force a TLS-1.2-only
-            # server, which does not support a fragmented ClientHello.
-            tc.requirements.append('requires_ciphersuite_enabled ' + mbedtls_cipher)
-            their_args += ' -cipher ' + translate_ciphers.translate_ossl(cipher)
-            if 'NULL' in cipher:
-                their_args += '@SECLEVEL=0'
-
-    if etm is not None:
-        if etm:
-            tc.requirements.append('requires_config_enabled MBEDTLS_SSL_ENCRYPT_THEN_MAC')
-        our_args += ' etm=' + str(int(etm))
-        (wanted_patterns if etm else forbidden_patterns)[0:0] = [
-            'using encrypt then mac',
-        ]
-
-    tc.description += variant
-
-    if side == Side.CLIENT:
-        tc.client = '$P_CLI debug_level=4' + our_args
-        tc.server = '$O_NEXT_SRV' + their_args
-        tc.wanted_client_patterns = wanted_patterns
-        tc.forbidden_client_patterns = forbidden_patterns
-    else:
-        their_args += ' -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key'
-        our_args += ' auth_mode=required'
-        tc.client = '$O_NEXT_CLI' + their_args
-        tc.server = '$P_SRV debug_level=4' + our_args
-        tc.wanted_server_patterns = wanted_patterns
-        tc.forbidden_server_patterns = forbidden_patterns
-    tc.write(out)
-
-
-CIPHERS_FOR_TLS12_HANDSHAKE_DEFRAGMENTATION = [
-    (None, 'default', None),
-    ('TLS_ECDHE_ECDSA_WITH_NULL_SHA', 'null', None),
-    ('TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256', 'ChachaPoly', None),
-    ('TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256', 'GCM', None),
-    ('TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256', 'CBC, etm=n', False),
-    ('TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256', 'CBC, etm=y', True),
-]
-
-def write_tls_handshake_defragmentation_tests(out: typing_util.Writable) -> None:
-    """Generate TLS handshake defragmentation tests."""
-    for side in Side.CLIENT, Side.SERVER:
-        write_tls_handshake_defragmentation_test(out, side, None)
-        for length in [512, 513, 256, 128, 64, 36, 32, 16, 13, 5, 4, 3]:
-            write_tls_handshake_defragmentation_test(out, side, length,
-                                                     Version.TLS13)
-            if length == 4:
-                for (cipher_suite, nickname, etm) in \
-                        CIPHERS_FOR_TLS12_HANDSHAKE_DEFRAGMENTATION:
-                    write_tls_handshake_defragmentation_test(
-                        out, side, length, Version.TLS12,
-                        cipher=cipher_suite, etm=etm,
-                        variant=', '+nickname)
-            else:
-                write_tls_handshake_defragmentation_test(out, side, length,
-                                                         Version.TLS12)
-
-
-def write_handshake_tests(out: typing_util.Writable) -> None:
-    """Generate handshake tests."""
-    out.write(f"""\
-# Miscellaneous tests related to the TLS handshake layer.
-#
-# Automatically generated by {os.path.basename(sys.argv[0])}. Do not edit!
-
-# Copyright The Mbed TLS Contributors
-# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
-
-""")
-    write_tls_handshake_defragmentation_tests(out)
-    out.write("""\
-# End of automatically generated file.
-""")
-
-def main() -> None:
-    """Command line entry point."""
-    parser = argparse.ArgumentParser()
-    parser = argparse.ArgumentParser(description=__doc__)
-    parser.add_argument('-o', '--output',
-                        default='tests/opt-testcases/handshake-generated.sh',
-                        help='Output file (default: tests/opt-testcases/handshake-generated.sh)')
-    args = parser.parse_args()
-    with open(args.output, 'w') as out:
-        write_handshake_tests(out)
+from mbedtls_framework import tls_handshake_tests
 
 if __name__ == '__main__':
-    main()
+    sys.argv[1:1] = ["--no-tls12-client-hello-defragmentation-support"]
+    tls_handshake_tests.main()
diff -Nru mbedtls-3.6.5/framework/scripts/gen_gcm_decrypt.pl mbedtls-3.6.6/framework/scripts/gen_gcm_decrypt.pl
--- mbedtls-3.6.5/framework/scripts/gen_gcm_decrypt.pl	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/scripts/gen_gcm_decrypt.pl	2026-03-27 12:34:57.779285200 +0200
@@ -0,0 +1,101 @@
+#!/usr/bin/env perl
+#
+# Based on NIST gcmDecryptxxx.rsp validation files
+# Only first 3 of every set used for compile time saving
+#
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+use strict;
+
+my $file = shift;
+
+open(TEST_DATA, "$file") or die "Opening test cases '$file': $!";
+
+sub get_suite_val($)
+{
+    my $name = shift;
+    my $val = "";
+
+    while(my $line = <TEST_DATA>)
+    {
+        next if ($line !~ /^\[/);
+        ($val) = ($line =~ /\[$name\s\=\s(\w+)\]/);
+        last;
+    }
+
+    return $val;
+}
+
+sub get_val($)
+{
+    my $name = shift;
+    my $val = "";
+    my $line;
+
+    while($line = <TEST_DATA>)
+    {
+        next if($line !~ /=/);
+        last;
+    }
+
+    ($val) = ($line =~ /^$name = (\w+)/);
+
+    return $val;
+}
+
+sub get_val_or_fail($)
+{
+    my $name = shift;
+    my $val = "FAIL";
+    my $line;
+
+    while($line = <TEST_DATA>)
+    {
+        next if($line !~ /=/ && $line !~ /FAIL/);
+        last;
+    }
+
+    ($val) = ($line =~ /^$name = (\w+)/) if ($line =~ /=/);
+
+    return $val;
+}
+
+my $cnt = 1;;
+while (my $line = <TEST_DATA>)
+{
+    my $key_len = get_suite_val("Keylen");
+    next if ($key_len !~ /\d+/);
+    my $iv_len = get_suite_val("IVlen");
+    my $pt_len = get_suite_val("PTlen");
+    my $add_len = get_suite_val("AADlen");
+    my $tag_len = get_suite_val("Taglen");
+
+    for ($cnt = 0; $cnt < 3; $cnt++)
+    {
+        my $Count = get_val("Count");
+        my $key = get_val("Key");
+        my $iv = get_val("IV");
+        my $ct = get_val("CT");
+        my $add = get_val("AAD");
+        my $tag = get_val("Tag");
+        my $pt = get_val_or_fail("PT");
+
+        print("GCM NIST Validation (AES-$key_len,$iv_len,$pt_len,$add_len,$tag_len) #$Count\n");
+        print("gcm_decrypt_and_verify");
+        print(":\"$key\"");
+        print(":\"$ct\"");
+        print(":\"$iv\"");
+        print(":\"$add\"");
+        print(":$tag_len");
+        print(":\"$tag\"");
+        print(":\"$pt\"");
+        print(":0");
+        print("\n\n");
+    }
+}
+
+print("GCM Selftest\n");
+print("gcm_selftest:\n\n");
+
+close(TEST_DATA);
diff -Nru mbedtls-3.6.5/framework/scripts/gen_gcm_encrypt.pl mbedtls-3.6.6/framework/scripts/gen_gcm_encrypt.pl
--- mbedtls-3.6.5/framework/scripts/gen_gcm_encrypt.pl	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/scripts/gen_gcm_encrypt.pl	2026-03-27 12:34:57.779353400 +0200
@@ -0,0 +1,84 @@
+#!/usr/bin/env perl
+#
+# Based on NIST gcmEncryptIntIVxxx.rsp validation files
+# Only first 3 of every set used for compile time saving
+#
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+use strict;
+
+my $file = shift;
+
+open(TEST_DATA, "$file") or die "Opening test cases '$file': $!";
+
+sub get_suite_val($)
+{
+    my $name = shift;
+    my $val = "";
+
+    while(my $line = <TEST_DATA>)
+    {
+        next if ($line !~ /^\[/);
+        ($val) = ($line =~ /\[$name\s\=\s(\w+)\]/);
+        last;
+    }
+
+    return $val;
+}
+
+sub get_val($)
+{
+    my $name = shift;
+    my $val = "";
+    my $line;
+
+    while($line = <TEST_DATA>)
+    {
+        next if($line !~ /=/);
+        last;
+    }
+
+    ($val) = ($line =~ /^$name = (\w+)/);
+
+    return $val;
+}
+
+my $cnt = 1;;
+while (my $line = <TEST_DATA>)
+{
+    my $key_len = get_suite_val("Keylen");
+    next if ($key_len !~ /\d+/);
+    my $iv_len = get_suite_val("IVlen");
+    my $pt_len = get_suite_val("PTlen");
+    my $add_len = get_suite_val("AADlen");
+    my $tag_len = get_suite_val("Taglen");
+
+    for ($cnt = 0; $cnt < 3; $cnt++)
+    {
+        my $Count = get_val("Count");
+        my $key = get_val("Key");
+        my $pt = get_val("PT");
+        my $add = get_val("AAD");
+        my $iv = get_val("IV");
+        my $ct = get_val("CT");
+        my $tag = get_val("Tag");
+
+        print("GCM NIST Validation (AES-$key_len,$iv_len,$pt_len,$add_len,$tag_len) #$Count\n");
+        print("gcm_encrypt_and_tag");
+        print(":\"$key\"");
+        print(":\"$pt\"");
+        print(":\"$iv\"");
+        print(":\"$add\"");
+        print(":\"$ct\"");
+        print(":$tag_len");
+        print(":\"$tag\"");
+        print(":0");
+        print("\n\n");
+    }
+}
+
+print("GCM Selftest\n");
+print("gcm_selftest:\n\n");
+
+close(TEST_DATA);
diff -Nru mbedtls-3.6.5/framework/scripts/gen_pkcs1_v21_sign_verify.pl mbedtls-3.6.6/framework/scripts/gen_pkcs1_v21_sign_verify.pl
--- mbedtls-3.6.5/framework/scripts/gen_pkcs1_v21_sign_verify.pl	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/scripts/gen_pkcs1_v21_sign_verify.pl	2026-03-27 12:34:57.779420400 +0200
@@ -0,0 +1,74 @@
+#!/usr/bin/env perl
+#
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+use strict;
+
+my $file = shift;
+
+open(TEST_DATA, "$file") or die "Opening test cases '$file': $!";
+
+sub get_val($$)
+{
+    my $str = shift;
+    my $name = shift;
+    my $val = "";
+
+    while(my $line = <TEST_DATA>)
+    {
+        next if($line !~ /^# $str/);
+        last;
+    }
+
+    while(my $line = <TEST_DATA>)
+    {
+        last if($line eq "\r\n");
+        $val .= $line;
+    }
+
+    $val =~ s/[ \r\n]//g;
+
+    return $val;
+}
+
+my $state = 0;
+my $val_n = "";
+my $val_e = "";
+my $val_p = "";
+my $val_q = "";
+my $mod = 0;
+my $cnt = 1;
+while (my $line = <TEST_DATA>)
+{
+    next if ($line !~ /^# Example/);
+
+    ( $mod ) = ($line =~ /A (\d+)/);
+    $val_n = get_val("RSA modulus n", "N");
+    $val_e = get_val("RSA public exponent e", "E");
+    $val_p = get_val("Prime p", "P");
+    $val_q = get_val("Prime q", "Q");
+
+    for(my $i = 1; $i <= 6; $i++)
+    {
+        my $val_m = get_val("Message to be", "M");
+        my $val_salt = get_val("Salt", "Salt");
+        my $val_sig = get_val("Signature", "Sig");
+
+        print("RSASSA-PSS Signature Example ${cnt}_${i}\n");
+        print("pkcs1_rsassa_pss_sign:$mod:16:\"$val_p\":16:\"$val_q\":16:\"$val_n\":16:\"$val_e\":SIG_RSA_SHA1:MBEDTLS_MD_SHA1");
+        print(":\"$val_m\"");
+        print(":\"$val_salt\"");
+        print(":\"$val_sig\":0");
+        print("\n\n");
+
+        print("RSASSA-PSS Signature Example ${cnt}_${i} (verify)\n");
+        print("pkcs1_rsassa_pss_verify:$mod:16:\"$val_n\":16:\"$val_e\":SIG_RSA_SHA1:MBEDTLS_MD_SHA1");
+        print(":\"$val_m\"");
+        print(":\"$val_salt\"");
+        print(":\"$val_sig\":0");
+        print("\n\n");
+    }
+    $cnt++;
+}
+close(TEST_DATA);
diff -Nru mbedtls-3.6.5/framework/scripts/lcov.sh mbedtls-3.6.6/framework/scripts/lcov.sh
--- mbedtls-3.6.5/framework/scripts/lcov.sh	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/scripts/lcov.sh	2026-03-27 12:34:57.781320600 +0200
@@ -0,0 +1,103 @@
+#!/bin/sh
+
+help () {
+    cat <<EOF
+Usage: $0 [-r]
+Collect coverage statistics of library code into an HTML report.
+
+General instructions:
+1. Build the library with CFLAGS="--coverage -O0 -g3" and link the test
+   programs with LDFLAGS="--coverage".
+   This can be an out-of-tree build.
+   For example (in-tree):
+        cmake -D CMAKE_BUILD_TYPE=Coverage . && make
+   Or (out-of-tree):
+        mkdir build-coverage && cd build-coverage &&
+        cmake -D CMAKE_BUILD_TYPE=Coverage .. && make
+2. Run whatever tests you want.
+3. Run this script from the parent of the directory containing the library
+   object files and coverage statistics files.
+4. Browse the coverage report in Coverage/index.html.
+5. After rework, run "$0 -r", then re-test and run "$0" to get a fresh report.
+
+Options
+  -r    Reset traces. Run this before re-testing to get fresh measurements.
+EOF
+}
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+# This script must be invoked from the project's root.
+
+set -eu
+scriptdir=$(dirname "$(realpath $0)")
+
+. $scriptdir/project_detection.sh
+
+# Collect stats and build a HTML report.
+lcov_library_report () {
+    rm -rf Coverage
+    mkdir Coverage Coverage/tmp
+    # Pass absolute paths as lcov output files. This works around a bug
+    # whereby lcov tries to create the output file in the root directory
+    # if it has emitted a warning. A fix was released in lcov 1.13 in 2016.
+    # Ubuntu 16.04 is affected, 18.04 and above are not.
+    # https://github.com/linux-test-project/lcov/commit/632c25a0d1f5e4d2f4fd5b28ce7c8b86d388c91f
+    COVTMP=$PWD/Coverage/tmp
+    lcov --capture --initial ${lcov_dirs} -o "$COVTMP/files.info"
+    lcov --rc lcov_branch_coverage=1 --capture ${lcov_dirs} -o "$COVTMP/tests.info"
+    lcov --rc lcov_branch_coverage=1 --add-tracefile "$COVTMP/files.info" --add-tracefile "$COVTMP/tests.info" -o "$COVTMP/all.info"
+    lcov --rc lcov_branch_coverage=1 --remove "$COVTMP/all.info" -o "$COVTMP/final.info" '*.h'
+    gendesc tests/Descriptions.txt -o "$COVTMP/descriptions"
+    genhtml --title "$title" --description-file "$COVTMP/descriptions" --keep-descriptions --legend --branch-coverage -o Coverage "$COVTMP/final.info"
+    rm -f "$COVTMP/"*.info "$COVTMP/descriptions"
+    echo "Coverage report in: Coverage/index.html"
+}
+
+# Reset the traces to 0.
+lcov_reset_traces () {
+    # Location with plain make
+    for dir in ${library_dirs}; do
+        rm -f ${dir}/*.gcda
+    done
+    # Location with CMake
+    for dir in ${library_dirs}; do
+        rm -f ${dir}/CMakeFiles/*.dir/*.gcda
+    done
+}
+
+if [ $# -gt 0 ] && [ "$1" = "--help" ]; then
+    help
+    exit
+fi
+
+if [ -d tf-psa-crypto ]; then
+    library_dirs='library tf-psa-crypto/core tf-psa-crypto/drivers/builtin'
+    title='Mbed TLS >= 4.0'
+elif in_mbedtls_repo; then
+    library_dirs='library'
+    title='Mbed TLS < 4.0'
+elif in_tf_psa_crypto_repo; then
+    library_dirs='core drivers/builtin'
+    title='TF-PSA-Crypto'
+else
+    echo "Cannot auto detect build files"
+    exit
+fi
+
+lcov_dirs=""
+for dir in ${library_dirs}; do
+    lcov_dirs="${lcov_dirs} --directory ${dir}"
+done
+
+main=lcov_library_report
+while getopts r OPTLET; do
+    case $OPTLET in
+        r) main=lcov_reset_traces;;
+        *) help 2>&1; exit 120;;
+    esac
+done
+shift $((OPTIND - 1))
+
+"$main" "$@"
diff -Nru mbedtls-3.6.5/framework/scripts/make_generated_files.py mbedtls-3.6.6/framework/scripts/make_generated_files.py
--- mbedtls-3.6.5/framework/scripts/make_generated_files.py	2025-10-01 18:29:09.511101700 +0300
+++ mbedtls-3.6.6/framework/scripts/make_generated_files.py	2026-03-27 12:34:57.781474400 +0200
@@ -1,91 +1,25 @@
 #!/usr/bin/env python3
+"""Generate, check and list the generated files
+Transitional wrapper to facilitate the migration of consuming branches.
+"""
 
-# make_generated_files.py
-#
 # Copyright The Mbed TLS Contributors
 # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
 
-"""
-Generate the TF-PSA-Crypto generated files
-"""
-import argparse
-import filecmp
-import os
-import shutil
-import subprocess
 import sys
-
 from pathlib import Path
-from typing import List, Optional
 
 from mbedtls_framework import build_tree
-
-class GenerationScript:
-    """
-    Representation of a script generating a configuration independent file.
-    """
-    # pylint: disable=too-few-public-methods,too-many-arguments
-    def __init__(self, script: Path, files: List[Path],
-                 output_dir_option: Optional[str] = None,
-                 output_file_option: Optional[str] = None,
-                 optional: bool = False):
-        # Path from the root of Mbed TLS or TF-PSA-Crypto of the generation script
-        self.script = script
-
-        # Executable to run the script, needed for Windows
-        if script.suffix == ".py":
-            self.exe = "python"
-        elif script.suffix == ".pl":
-            self.exe = "perl"
-
-        # List of the default paths from the Mbed TLS or TF-PSA-Crypto root of the
-        # files the script generates.
-        self.files = files
-
-        # Output directory script argument. Can be an empty string in case it is a
-        # positional argument.
-        self.output_dir_option = output_dir_option
-
-        # Output file script argument. Can be an empty string in case it is a
-        # positional argument.
-        self.output_file_option = output_file_option
-
-        # Optional files are skipped in --check mode if they don't exist.
-        # This normally shouldn't happen, but it can happen during transition
-        # periods where we're adding a new script or a new file, and a
-        # consuming repository hasn't been updated yet.
-        self.optional = optional
-
-def get_generation_script_files(generation_script: str):
-    """
-    Get the list of the default paths of the files that a given script
-    generates. It is assumed that the script supports the "--list" option.
-    """
-    files = []
-    if generation_script.endswith(".py"):
-        cmd = ["python"]
-    elif generation_script.endswith(".pl"):
-        cmd = ["perl"]
-    cmd += [generation_script, "--list"]
-
-    output = subprocess.check_output(cmd, universal_newlines=True)
-    for line in output.splitlines():
-        files.append(Path(line))
-
-    return files
+from mbedtls_framework import generated_files
+from mbedtls_framework.generated_files import GenerationScript, get_generation_script_files
 
 COMMON_GENERATION_SCRIPTS = [
-]
-
-# Once the script has been added to both Mbed TLS and TF-PSA-Crypto,
-# we can include this unconditionally.
-# https://github.com/Mbed-TLS/mbedtls/issues/10305
-if os.path.exists("scripts/generate_config_checks.py"):
-    COMMON_GENERATION_SCRIPTS.append(GenerationScript(
+    GenerationScript(
         Path("scripts/generate_config_checks.py"),
         get_generation_script_files("scripts/generate_config_checks.py"),
         output_dir_option="",
-        optional=True))
+        optional=True)
+]
 
 if build_tree.looks_like_tf_psa_crypto_root("."):
     TF_PSA_CRYPTO_GENERATION_SCRIPTS = [
@@ -188,89 +122,7 @@
                 get_generation_script_files("scripts/generate_visualc_files.pl"),
                 "--directory", None))
 
-def get_generated_files(generation_scripts: List[GenerationScript]):
-    """
-    List the generated files in Mbed TLS or TF-PSA-Crypto. The path from root
-    is returned for each generated files.
-    """
-    files = []
-    for generation_script in generation_scripts:
-        files += generation_script.files
-
-    return files
-
-def make_generated_files(generation_scripts: List[GenerationScript]):
-    """
-    Generate the configuration independent files in their default location in
-    the Mbed TLS or TF-PSA-Crypto tree.
-    """
-    for generation_script in generation_scripts:
-        subprocess.run([generation_script.exe, str(generation_script.script)], check=True)
-
-def check_generated_files(generation_scripts: List[GenerationScript], root: Path):
-    """
-    Check that the given root directory contains the generated files as expected/
-    generated by this script.
-    """
-    for generation_script in generation_scripts:
-        for file in generation_script.files:
-            file = root / file
-            if not file.exists():
-                # If the script is just being added, allow its files not
-                # to exist. This can happen, at least, when adding a new
-                # generation script in crypto: until mbedtls is updated,
-                # the files from that script won't be present when
-                # the updated crypto is built from mbedtls development.
-                if generation_script.optional:
-                    continue
-                raise Exception(f"Expected generated file does not exist: {file}")
-            bak_file = file.with_name(file.name + ".bak")
-            if bak_file.exists():
-                bak_file.unlink()
-            file.rename(bak_file)
-
-        command = [generation_script.exe, str(generation_script.script)]
-        if generation_script.output_dir_option is not None:
-            command += [generation_script.output_dir_option,
-                        str(root / Path(generation_script.files[0].parent))]
-        elif generation_script.output_file_option is not None:
-            command += generation_script.output_file_option.split()
-            command += [str(root / Path(generation_script.files[0]))]
-        subprocess.run([item for item in command if item.strip()], check=True)
-
-        for file in generation_script.files:
-            file = root / file
-            bak_file = file.with_name(file.name + ".bak")
-            if generation_script.optional and not bak_file.exists():
-                # This file is optional and didn't exist before, so
-                # there's nothing to compare to, or clean up.
-                continue
-            if not filecmp.cmp(file, bak_file):
-                ref_file = file.with_name(file.name + ".ref")
-                ref_file = root / ref_file
-                if ref_file.exists():
-                    ref_file.unlink()
-                shutil.copy(file, ref_file)
-                print(f"Generated file {file} not identical to the reference one {ref_file}.")
-            file.unlink()
-            bak_file.rename(file)
-
-def main():
-    """
-    Main function of this program
-    """
-    parser = argparse.ArgumentParser()
-
-    parser.add_argument('--list', action='store_true',
-                        default=False, help='List generated files.')
-    parser.add_argument('--root', metavar='DIR',
-                        help='Root of the tree containing the generated files \
-                              to check (default: Mbed TLS or TF-PSA-Cryto root.)')
-    parser.add_argument('--check', action='store_true',
-                        default=False, help='Check the generated files in root')
-
-    args = parser.parse_args()
-
+def main() -> int:
     if not build_tree.looks_like_root("."):
         raise RuntimeError("This script must be run from Mbed TLS or TF-PSA-Crypto root.")
 
@@ -282,14 +134,7 @@
         raise Exception("No support for Mbed TLS 3.6")
     generation_scripts += COMMON_GENERATION_SCRIPTS
 
-    if args.list:
-        files = get_generated_files(generation_scripts)
-        for file in files:
-            print(str(file))
-    elif args.check:
-        check_generated_files(generation_scripts, Path(args.root or "."))
-    else:
-        make_generated_files(generation_scripts)
+    return generated_files.main(generation_scripts)
 
 if __name__ == "__main__":
     sys.exit(main())
diff -Nru mbedtls-3.6.5/framework/scripts/massif_max.pl mbedtls-3.6.6/framework/scripts/massif_max.pl
--- mbedtls-3.6.5/framework/scripts/massif_max.pl	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/scripts/massif_max.pl	2026-03-27 12:34:57.781558000 +0200
@@ -0,0 +1,36 @@
+#!/usr/bin/env perl
+
+# Parse a massif.out.xxx file and output peak total memory usage
+#
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+use warnings;
+use strict;
+
+use utf8;
+use open qw(:std utf8);
+
+die unless @ARGV == 1;
+
+my @snaps;
+open my $fh, '<', $ARGV[0] or die;
+{ local $/ = 'snapshot='; @snaps = <$fh>; }
+close $fh or die;
+
+my ($max, $max_heap, $max_he, $max_stack) = (0, 0, 0, 0);
+for (@snaps)
+{
+    my ($heap, $heap_extra, $stack) = m{
+        mem_heap_B=(\d+)\n
+        mem_heap_extra_B=(\d+)\n
+        mem_stacks_B=(\d+)
+    }xm;
+    next unless defined $heap;
+    my $total = $heap + $heap_extra + $stack;
+    if( $total > $max ) {
+        ($max, $max_heap, $max_he, $max_stack) = ($total, $heap, $heap_extra, $stack);
+    }
+}
+
+printf "$max (heap $max_heap+$max_he, stack $max_stack)\n";
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/asymmetric_key_data.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/asymmetric_key_data.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/asymmetric_key_data.py	2025-10-01 18:24:20.272037500 +0300
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/asymmetric_key_data.py	2026-03-27 12:34:57.781973400 +0200
@@ -38,6 +38,7 @@
 ## pairs consist of a private key and its public key.
 #pylint: disable=line-too-long
 ASYMMETRIC_KEY_DATA = construct_asymmetric_key_data({
+    # Randomly generated with OpenSSL
     'ECC(PSA_ECC_FAMILY_SECP_K1)': {
         192: ("297ac1722ccac7589ecb240dc719842538ca974beb79f228",
               "0426b7bb38da649ac2138fc050c6548b32553dab68afebc36105d325b75538c12323cb0764789ecb992671beb2b6bef2f5"),
@@ -46,6 +47,8 @@
         256: ("7fa06fa02d0e911b9a47fdc17d2d962ca01e2f31d60c6212d0ed7e3bba23a7b9",
               "045c39154579efd667adc73a81015a797d2c8682cdfbd3c3553c4a185d481cdc50e42a0e1cbc3ca29a32a645e927f54beaed14c9dbbf8279d725f5495ca924b24d"),
     },
+
+    # Randomly generated with OpenSSL
     'ECC(PSA_ECC_FAMILY_SECP_R1)': {
         192: ("d83b57a59c51358d9c8bbb898aff507f44dd14cf16917190",
               "04e35fcbee11cec3154f80a1a61df7d7612de4f2fd70c5608d0ee3a4a1a5719471adb33966dd9b035fdb774feeba94b04c"),
@@ -58,10 +61,14 @@
         521: ("01b1b6ad07bb79e7320da59860ea28e055284f6058f279de666e06d435d2af7bda28d99fa47b7dd0963e16b0073078ee8b8a38d966a582f46d19ff95df3ad9685aae",
               "04001de142d54f69eb038ee4b7af9d3ca07736fd9cf719eb354d69879ee7f3c136fb0fbf9f08f86be5fa128ec1a051d3e6c643e85ada8ffacf3663c260bd2c844b6f5600cee8e48a9e65d09cadd89f235dee05f3b8a646be715f1f67d5b434e0ff23a1fc07ef7740193e40eeff6f3bcdfd765aa9155033524fe4f205f5444e292c4c2f6ac1"),
     },
+
+    # Randomly generated with OpenSSL
     'ECC(PSA_ECC_FAMILY_SECP_R2)': {
         160: ("00bf539a1cdda0d7f71a50a3f98aec0a2e8e4ced1e",
               "049570d541398665adb5cfa16f5af73b3196926bbd4b876bdb80f8eab20d0f540c22f4de9c140f6d7b"),
     },
+
+    # Randomly generated with OpenSSL
     'ECC(PSA_ECC_FAMILY_SECT_K1)': {
         163: ("03ebc8fcded2d6ab72ec0f75bdb4fd080481273e71",
               "0406f88f90b4b65950f06ce433afdb097e320f433dc2062b8a65db8fafd3c110f46bc45663fbf021ee7eb9"),
@@ -76,6 +83,8 @@
         571: ("005008c97b4a161c0db1bac6452c72846d57337aa92d8ecb4a66eb01d2f29555ffb61a5317225dcc8ca6917d91789e227efc0bfe9eeda7ee21998cd11c3c9885056b0e55b4f75d51",
               "04050172a7fd7adf98e4e2ed2742faa5cd12731a15fb0dbbdf75b1c3cc771a4369af6f2fa00e802735650881735759ea9c79961ded18e0daa0ac59afb1d513b5bbda9962e435f454fc020b4afe1445c2302ada07d295ec2580f8849b2dfa7f956b09b4cbe4c88d3b1c217049f75d3900d36df0fa12689256b58dd2ef784ebbeb0564600cf47a841485f8cf897a68accd5a"),
     },
+
+    # Randomly generated with OpenSSL
     'ECC(PSA_ECC_FAMILY_SECT_R1)': {
         163: ("009b05dc82d46d64a04a22e6e5ca70ca1231e68c50",
               "0400465eeb9e7258b11e33c02266bfe834b20bcb118700772796ee4704ec67651bd447e3011959a79a04cb"),
@@ -88,10 +97,14 @@
         571: ("026ac1cdf92a13a1b8d282da9725847908745138f5c6706b52d164e3675fcfbf86fc3e6ab2de732193267db029dd35a0599a94a118f480231cfc6ccca2ebfc1d8f54176e0f5656a1",
               "040708f3403ee9948114855c17572152a08f8054d486defef5f29cbffcfb7cfd9280746a1ac5f751a6ad902ec1e0525120e9be56f03437af196fbe60ee7856e3542ab2cf87880632d80290e39b1a2bd03c6bbf6225511c567bd2ff41d2325dc58346f2b60b1feee4dc8b2af2296c2dc52b153e0556b5d24152b07f690c3fa24e4d1d19efbdeb1037833a733654d2366c74"),
     },
+
+    # Randomly generated with OpenSSL
     'ECC(PSA_ECC_FAMILY_SECT_R2)': {
         163: ("0210b482a458b4822d0cb21daa96819a67c8062d34",
               "0403692601144c32a6cfa369ae20ae5d43c1c764678c037bafe80c6fd2e42b7ced96171d9c5367fd3dca6f"),
     },
+
+    # Randomly generated with OpenSSL
     'ECC(PSA_ECC_FAMILY_BRAINPOOL_P_R1)': {
         160: ("69502c4fdaf48d4fa617bdd24498b0406d0eeaac",
               "04d4b9186816358e2f9c59cf70748cb70641b22fbab65473db4b4e22a361ed7e3de7e8a8ddc4130c5c"),
@@ -108,18 +121,53 @@
         512: ("372c9778f69f726cbca3f4a268f16b4d617d10280d79a6a029cd51879fe1012934dfe5395455337df6906dc7d6d2eea4dbb2065c0228f73b3ed716480e7d71d2",
               "0438b7ec92b61c5c6c7fbc28a4ec759d48fcd4e2e374defd5c4968a54dbef7510e517886fbfc38ea39aa529359d70a7156c35d3cbac7ce776bdb251dd64bce71234424ee7049eed072f0dbc4d79996e175d557e263763ae97095c081e73e7db2e38adc3d4c9a0487b1ede876dc1fca61c902e9a1d8722b8612928f18a24845591a"),
     },
+
+    # https://www.ietf.org/archive/id/draft-lspm-cose-c509-test-vectors-00.html#name-weierstrass-ec-public-key-with-f
+    'ECC(PSA_ECC_FAMILY_FRP)': {
+        256: ("88e244ef9d8a617b35199d3ff844d6368067f0bed914ef608dc77fc6d951fe21",
+              "04378d2d28a1f6547124f2db6a42f63915bfa2f6537ae20cf0417d675fbe6603da80a4cf3f1e43633343ab3be80150ec04e9649dd62705bc055bdcda791eb25062"),
+    },
+
+    # Randomly generated with OpenSSL
     'ECC(PSA_ECC_FAMILY_MONTGOMERY)': {
         255: ("70076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c6a",
               "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a"),
         448: ("e4e49f52686f9ee3b638528f721f1596196ffd0a1cddb64c3f216f06541805cfeb1a286dc78018095cdfec050e8007b5f4908962ba20d6c1",
               "c0d3a5a2b416a573dc9909f92f134ac01323ab8f8e36804e578588ba2d09fe7c3e737f771ca112825b548a0ffded6d6a2fd09a3e77dec30e"),
     },
+
+    # https://datatracker.ietf.org/doc/html/rfc8032#section-7
     'ECC(PSA_ECC_FAMILY_TWISTED_EDWARDS)': {
         255: ("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60",
               "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a"),
         448: ("6c82a562cb808d10d632be89c8513ebf6c929f34ddfa8c9f63c9960ef6e348a3528c8a3fcc2f044e39a3fc5b94492f8f032e7549a20098f95b",
               "5fd7449b59b461fd2ce787ec616ad46a1da1342485a70e1f8a0ea75d80e96778edf124769b46c7061bd6783df1e50f6cd1fa1abeafe8256180"),
     },
+
+    # https://github.com/usnistgov/ACVP-Server/blob/v1.1.0.41/gen-val/json-files/ML-DSA-keyGen-FIPS204/internalProjection.json
+    'ML_DSA': {
+        44: ("D71361C000F9A7BC99DFB425BCB6BB27C32C36AB444FF3708B2D93B4E66D5B5B",
+             " "),
+        65: ("1BD67DC782B2958E189E315C040DD1F64C8AB232A6A170E1A7A52C33F10851B1",
+             " "),
+        87: ("F7052FBB921759CD8716773BA6355630121D6927899FDDA5768E2BC240FCCB7B",
+             " "),
+    },
+
+    # https://github.com/usnistgov/ACVP-Server/blob/v1.1.0.41/gen-val/json-files/ML-KEM-keyGen-FIPS203/internalProjection.json
+    'ML_KEM': {
+        512: ("BBA3C0F5DF044CDF4D9CAA53CA15FDE26F34EB3541555CFC54CA9C31B964D0C8" +
+              "0A64FDD51A8D91B3166C4958A94EFC3166A4F5DF680980B878DB8371B7624C96",
+              " "),
+        768: ("A2B4BCA315A6EA4600B4A316E09A2578AA1E8BCE919C8DF3A96C71C843F5B38B" +
+              "D6BF055CB7B375E3271ED131F1BA31F83FEF533A239878A71074578B891265D1",
+              " "),
+        1024: ("2B5330C4F23BFDFD5C31F050BA3B38235324BF032372FC12D04DD08920F0BD59" +
+               "0A064D6C06CEAB73E59CFCA9FF6402255A326AEF1E9CB678BF36929DAFE29A58",
+               " "),
+    },
+
+    # Randomly generated with OpenSSL
     'RSA': {
         1024: ("""
 3082025e
@@ -234,4 +282,44 @@
  0203010001
 """),
     },
+
+    # https://github.com/usnistgov/ACVP-Server/blob/v1.1.0.41/gen-val/json-files/SLH-DSA-keyGen-FIPS205/internalProjection.json
+    'SLH_DSA(PSA_SLH_FAMILY_SHA2_F)': {
+        128: ("C42BCB3B5A6F331F5CCE899253C6D9E29FF2B7EAD7A04BAB1794DB8CC659C3B4A868F1BD5DEBC12D4C9FAD66AABD0A94A868F1BD5DEBC12D4C9FAD66AABD0A94B546DF247BE4C457F3D467CDFCFABD39",
+              "A868F1BD5DEBC12D4C9FAD66AABD0A94A868F1BD5DEBC12D4C9FAD66AABD0A94B546DF247BE4C457F3D467CDFCFABD39"),
+        192: ("A021B4B9D6DEE168722BC10225E50A946642AF630C3C7C7D69E3A40BA09DF2AC165B792A07F064AC5FC28D8C99A580F4EE4823D09E79854706DAA80AE3179B5BC8C2E9409D6328A3EE4823D09E79854706DAA80AE3179B5BC8C2E9409D6328A33577FD584BC0784C559CDB2437A46F7F753C336369419ACF",
+              "EE4823D09E79854706DAA80AE3179B5BC8C2E9409D6328A3EE4823D09E79854706DAA80AE3179B5BC8C2E9409D6328A33577FD584BC0784C559CDB2437A46F7F753C336369419ACF"),
+        256: ("18523702A0FE2C9E488948B127185BAB93D3F02C3D7C23A1B379F762DE0509E56AB0D9F93540BD809D1D2E8A050440AA81E853750470E2B00C959DBD3BE40E2BD7125F5D00BA47F1FC8D4C32C2F57C444BD384D7CE770BC50DD5980C1D1264D0D7125F5D00BA47F1FC8D4C32C2F57C444BD384D7CE770BC50DD5980C1D1264D00AD5197FFCBAAFE11B1E413F26ADB1504CE1C3F5C40C1DCDA14E99FD126D5B81",
+              "D7125F5D00BA47F1FC8D4C32C2F57C444BD384D7CE770BC50DD5980C1D1264D0D7125F5D00BA47F1FC8D4C32C2F57C444BD384D7CE770BC50DD5980C1D1264D00AD5197FFCBAAFE11B1E413F26ADB1504CE1C3F5C40C1DCDA14E99FD126D5B81"),
+    },
+
+    # https://github.com/usnistgov/ACVP-Server/blob/v1.1.0.41/gen-val/json-files/SLH-DSA-keyGen-FIPS205/internalProjection.json
+    'SLH_DSA(PSA_SLH_FAMILY_SHA2_S)': {
+        128: ("173D04C938C1C36BF289C3C022D04B1463AE23C41AA546DA589774AC20B745C40D794777914C99766827F0F09CA972BE0D794777914C99766827F0F09CA972BE0162C10219D422ADBA1359E6AA65299C",
+              "0D794777914C99766827F0F09CA972BE0D794777914C99766827F0F09CA972BE0162C10219D422ADBA1359E6AA65299C"),
+        192: ("040266529C1864088925506C20A624A2B6D50CD77C1C6F0D2841150AE8157512EF34A343FFEA77FF7D9E814B45A8B41464462665F4202886206A8F632267186CA6A1CAD08A2B9A8664462665F4202886206A8F632267186CA6A1CAD08A2B9A862C6A7BC4AC4AAA84ACCEF60D529F0311274F205E8DA642C9",
+              "64462665F4202886206A8F632267186CA6A1CAD08A2B9A8664462665F4202886206A8F632267186CA6A1CAD08A2B9A862C6A7BC4AC4AAA84ACCEF60D529F0311274F205E8DA642C9"),
+        256: ("FCBF36A9807B30697BE063A5105E091B412A391DD39E1326EBA23CBD4096CA77EF4121C08DD71BE913572F1F91E57D0ACBCD5CEC28539AC275832BBAA6C11081A0B4F5549EBCADB951DC2E512C76B0620D8FB8100B4EE886EF8784780D52A254A0B4F5549EBCADB951DC2E512C76B0620D8FB8100B4EE886EF8784780D52A2543E57AB494D47068FFEE4B8244AAD6F19CDF94A2172BD134A15A6B5F298D5A80E",
+              "A0B4F5549EBCADB951DC2E512C76B0620D8FB8100B4EE886EF8784780D52A254A0B4F5549EBCADB951DC2E512C76B0620D8FB8100B4EE886EF8784780D52A2543E57AB494D47068FFEE4B8244AAD6F19CDF94A2172BD134A15A6B5F298D5A80E"),
+    },
+
+    # https://github.com/usnistgov/ACVP-Server/blob/v1.1.0.41/gen-val/json-files/SLH-DSA-keyGen-FIPS205/internalProjection.json
+    'SLH_DSA(PSA_SLH_FAMILY_SHAKE_F)': {
+        128: ("3956AB391B4D22FC907AF0740326D061AB0EB206436F2B86EBE086D77739B3E456505C229F4E7FA6B201714C7DCC9DA356505C229F4E7FA6B201714C7DCC9DA366578F1F24C3FE371C97C14CE0E79CDC",
+              "56505C229F4E7FA6B201714C7DCC9DA356505C229F4E7FA6B201714C7DCC9DA366578F1F24C3FE371C97C14CE0E79CDC"),
+        192: ("FB7A2C2C75CE6C96B5F4328E0AB300476FC6F864CB5B0B99990ECB726CA822A4E3652DD92EC0AAB7637EA41C0482AE2868DCC671E3534F81A352C275B6A25F906D2ED0FF62B8B4E368DCC671E3534F81A352C275B6A25F906D2ED0FF62B8B4E398F1A9876CB082A48E9AE2C862B289486A3925CEFC6FF4BE",
+              "68DCC671E3534F81A352C275B6A25F906D2ED0FF62B8B4E368DCC671E3534F81A352C275B6A25F906D2ED0FF62B8B4E398F1A9876CB082A48E9AE2C862B289486A3925CEFC6FF4BE"),
+        256: ("2AC9403858D186B172EDD8DF9C78A11449893681487D3AF0DAD0EC341E8ACA48AFA2771BAE6C17DD6F77B4E3808B05F56F31B8F4128DF2CCB677F0283CFB18DA559BC883105E8BA0264648B532626155F87EDB4BEDCFC12A24204D3B696D5370559BC883105E8BA0264648B532626155F87EDB4BEDCFC12A24204D3B696D53707A158FF5D30E3428183A3B3A96A0E4A341A2A16E5A6226AF374D1EFB39A35DF6",
+              "559BC883105E8BA0264648B532626155F87EDB4BEDCFC12A24204D3B696D5370559BC883105E8BA0264648B532626155F87EDB4BEDCFC12A24204D3B696D53707A158FF5D30E3428183A3B3A96A0E4A341A2A16E5A6226AF374D1EFB39A35DF6"),
+    },
+
+    # https://github.com/usnistgov/ACVP-Server/blob/v1.1.0.41/gen-val/json-files/SLH-DSA-keyGen-FIPS205/internalProjection.json
+    'SLH_DSA(PSA_SLH_FAMILY_SHAKE_S)': {
+        128: ("C151951F3811029239B74ADD24C506AFDD30363E156E6FE936EC6ED0231FEB5C529FFE86200D1F32C2B60D0CD909F190529FFE86200D1F32C2B60D0CD909F1900761F9B727AFA724B47223016BB5B2BA",
+              "529FFE86200D1F32C2B60D0CD909F190529FFE86200D1F32C2B60D0CD909F1900761F9B727AFA724B47223016BB5B2BA"),
+        192: ("8732621860E9A6E1887BE55F7AF692B98EB4C10B2599F94AD5CC9D6470D8B21136158E8B1710F1FBE03ECED37ED4AC6853FC64D46D7E1653EBBB36ED5FBC12C6E7CEF3CB756482C853FC64D46D7E1653EBBB36ED5FBC12C6E7CEF3CB756482C8C620452E864E8497E1B38A7B04449219ACD9E4393F9C88EF",
+              "53FC64D46D7E1653EBBB36ED5FBC12C6E7CEF3CB756482C853FC64D46D7E1653EBBB36ED5FBC12C6E7CEF3CB756482C8C620452E864E8497E1B38A7B04449219ACD9E4393F9C88EF"),
+        256: ("E440E39644A11A6A58E850C09C8F03C273E465237F3BEF7C58DE62281E676CEA99C199C00DB30F8499A61B5B9DC8A361725F6AE80E97037176F408C30B38844DD7B5E755B4879FDE3288A21AF3E32FBB006FD9B8BC2B180EB9B0D82C9F3157AFD7B5E755B4879FDE3288A21AF3E32FBB006FD9B8BC2B180EB9B0D82C9F3157AF02ACD6B3198EE1C9FE9AFE61FD86D1E0877AD9061980B57B178CE27191D8EB1B",
+              "D7B5E755B4879FDE3288A21AF3E32FBB006FD9B8BC2B180EB9B0D82C9F3157AFD7B5E755B4879FDE3288A21AF3E32FBB006FD9B8BC2B180EB9B0D82C9F3157AF02ACD6B3198EE1C9FE9AFE61FD86D1E0877AD9061980B57B178CE27191D8EB1B"),
+    },
 })
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/c_build_helper.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/c_build_helper.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/c_build_helper.py	2025-10-01 18:24:20.273085000 +0300
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/c_build_helper.py	2026-03-27 12:34:57.782811000 +0200
@@ -16,8 +16,7 @@
 
     def __init__(self, message):
         """Save the error massage"""
-
-        super().__init__()
+        super().__init__(message)
         self.message = message
 
 def remove_file_if_exists(filename):
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/code_wrapper/psa_buffer.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/code_wrapper/psa_buffer.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/code_wrapper/psa_buffer.py	2025-10-01 18:24:20.273746000 +0300
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/code_wrapper/psa_buffer.py	2026-03-27 12:34:57.783246500 +0200
@@ -4,9 +4,6 @@
 # Copyright The Mbed TLS Contributors
 # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
 
-from typing import List
-from .. import typing_util
-
 class BufferParameter:
     """Description of an input or output buffer parameter sequence to a PSA function."""
     #pylint: disable=too-few-public-methods
@@ -26,4 +23,3 @@
         self.buffer_name = buffer_name
         self.size_name = size_name
         self.is_output = is_output
-
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/code_wrapper/psa_test_wrapper.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/code_wrapper/psa_test_wrapper.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/code_wrapper/psa_test_wrapper.py	2025-10-01 18:24:20.273872100 +0300
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/code_wrapper/psa_test_wrapper.py	2026-03-27 12:34:57.783374000 +0200
@@ -4,18 +4,9 @@
 # Copyright The Mbed TLS Contributors
 # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
 
-import argparse
-import itertools
-import os
-from typing import Iterator, List, Collection, Optional, Tuple
-
-from .. import build_tree
-from .. import c_parsing_helper
-from .. import c_wrapper_generator
-from .. import typing_util
+from typing import List, Optional
 
-from .psa_buffer import BufferParameter
-from .psa_wrapper import PSAWrapper, PSALoggingWrapper, PSAWrapperConfiguration
+from .psa_wrapper import PSAWrapper, PSALoggingWrapper
 
 class PSATestWrapper(PSAWrapper):
     """Generate a C source file containing wrapper functions for PSA Crypto API calls."""
@@ -31,9 +22,6 @@
 class PSALoggingTestWrapper(PSATestWrapper, PSALoggingWrapper):
     """Generate a C source file containing wrapper functions that log PSA Crypto API calls."""
 
-    def __init__(self, out_h_f: str,
-                       out_c_f: str,
-                       stream: str,
-                       in_headers: Optional[List[str]] = None) -> None:
+    def __init__(self, out_h_f: str, out_c_f: str, stream: str,
+                 in_headers: Optional[List[str]] = None) -> None:
         super().__init__(out_h_f, out_c_f, stream, in_headers)
-
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/code_wrapper/psa_wrapper.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/code_wrapper/psa_wrapper.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/code_wrapper/psa_wrapper.py	2025-10-01 18:24:20.274141800 +0300
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/code_wrapper/psa_wrapper.py	2026-03-27 12:34:57.783471800 +0200
@@ -4,10 +4,9 @@
 # Copyright The Mbed TLS Contributors
 # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
 
-import argparse
 import itertools
 import os
-from typing import Any, Iterator, List, Dict, Collection, Optional, Tuple
+from typing import Iterable, Iterator, List, Optional, Tuple
 
 from .. import build_tree
 from .. import c_parsing_helper
@@ -18,9 +17,14 @@
 
 class PSAWrapperConfiguration:
     """Configuration data class for PSA Wrapper."""
+    #pylint: disable=too-few-public-methods
 
     def __init__(self) -> None:
-        self.cpp_guards = ["MBEDTLS_PSA_CRYPTO_C", "MBEDTLS_TEST_HOOKS", "!RECORD_PSA_STATUS_COVERAGE_LOG"]
+        self.cpp_guards = [
+            "MBEDTLS_PSA_CRYPTO_C",
+            "MBEDTLS_TEST_HOOKS",
+            "!RECORD_PSA_STATUS_COVERAGE_LOG",
+        ]
 
         self.skipped_functions = frozenset([
             'mbedtls_psa_external_get_random', # not a library function
@@ -98,24 +102,18 @@
             header_path = self.rel_path(header_name)
             c_parsing_helper.read_function_declarations(self.functions, header_path)
 
-    def rel_path(self, filename: str, path_list: List[str] = ['include', 'psa']) -> str:
+    def rel_path(self, filename: str, path_list: Optional[List[str]] = None) -> str:
         """Return the estimated path in relationship to the project_root.
 
            The method allows overriding the targetted sub-directory.
            Currently the default is set to project_root/include/psa."""
-        # Temporary, while Mbed TLS does not just rely on the TF-PSA-Crypto
-        # build system to build its crypto library. When it does, the first
-        # case can just be removed.
-        if build_tree.looks_like_mbedtls_root(self.project_root) and \
-           not build_tree.is_mbedtls_3_6():
-            path_list = ['tf-psa-crypto' ] + path_list
-            return os.path.join(self.project_root, *path_list, filename)
-
+        if path_list is None:
+            path_list = ['include', 'psa']
         return os.path.join(self.project_root, *path_list, filename)
 
     # Utility Methods
     @staticmethod
-    def parse_def_guards(def_list: Collection[str])-> str:
+    def parse_def_guards(def_list: Iterable[str])-> str:
         """ Create define guards.
 
             Convert an input list of into a C preprocessor
@@ -123,8 +121,8 @@
 
         output = ""
         dl = [("defined({})".format(n) if n[0] != "!" else
-                "!defined({})".format(n[1:]))
-               for n in def_list]
+               "!defined({})".format(n[1:]))
+              for n in def_list]
 
         # Split the list in chunks of 2 and add new lines
         for i in range(0, len(dl), 2):
@@ -161,31 +159,34 @@
 
         return True
 
-    def _poison_wrap(self, param : BufferParameter, poison: bool, ident_lv = 1) -> str:
+    @staticmethod
+    def _poison_wrap(param: BufferParameter, poison: bool,
+                     ident_lv: int = 1) -> str:
         """Returns a call to MBEDTLS_TEST_MEMORY_[UN]POISON.
 
            The output is prefixed with MBEDTLS_TEST_MEMORY_ followed by POISON/UNPOISON
            and the input parameter arguments (name, length)
         """
-        return "{}MBEDTLS_TEST_MEMORY_{}({}, {});\n".format((ident_lv * 4) * ' ',
-                                                            'POISON' if poison else 'UNPOISON',
-                                                             param.buffer_name, param.size_name)
+        return "{}MBEDTLS_TEST_MEMORY_{}({}, {});\n".format(
+            (ident_lv * 4) * ' ',
+            'POISON' if poison else 'UNPOISON',
+            param.buffer_name, param.size_name)
 
     def _poison_multi_write(self,
                             out: typing_util.Writable,
                             buffer_parameters: List['BufferParameter'],
                             poison: bool) -> None:
-            """Write poisoning or unpoisoning code for the buffer parameters.
+        """Write poisoning or unpoisoning code for the buffer parameters.
 
-               Write poisoning code if poison is true, unpoisoning code otherwise.
-            """
+           Write poisoning code if poison is true, unpoisoning code otherwise.
+        """
 
-            if not buffer_parameters:
-                return
-            out.write('#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)\n')
-            for param in buffer_parameters:
-                out.write(self._poison_wrap(param, poison))
-            out.write('#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */\n')
+        if not buffer_parameters:
+            return
+        out.write('#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)\n')
+        for param in buffer_parameters:
+            out.write(self._poison_wrap(param, poison))
+        out.write('#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */\n')
 
     # Override parent's methods
     def _write_function_call(self, out: typing_util.Writable,
@@ -243,7 +244,7 @@
 class PSALoggingWrapper(PSAWrapper, c_wrapper_generator.Logging):
     """Generate a C source file containing wrapper functions that log PSA Crypto API calls."""
 
-    def __init__(self,
+    def __init__(self, #pylint: disable=too-many-arguments
                  stream: str,
                  out_h_f: str,
                  out_c_f: str,
@@ -284,4 +285,3 @@
                     ['(unsigned) psa_get_key_{}({})'.format(field, var)
                      for field in ['id', 'lifetime', 'type', 'bits', 'algorithm', 'usage_flags']])
         return super()._printf_parameters(typ, var)
-
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/config_checks_generator.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/config_checks_generator.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/config_checks_generator.py	2025-10-01 18:29:09.515177500 +0300
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/config_checks_generator.py	2026-03-27 12:34:57.783685000 +0200
@@ -10,6 +10,7 @@
 import argparse
 import enum
 import os
+import posixpath
 import re
 import sys
 import textwrap
@@ -256,7 +257,9 @@
     """Generate the header files to include before and after *config.h."""
     for position in Position:
         generator = HeaderGenerator(branch_data, position)
-        yield os.path.join(directory, generator.output_file_name())
+        # Make sure to output a path with / even on Windows, so that
+        # it can be consumed by tools such as CMake.
+        yield posixpath.join(directory, generator.output_file_name())
         if not list_only:
             generator.write(directory)
 
@@ -280,7 +283,7 @@
     parser.add_argument('--list-for-cmake', action='store_true',
                         help='List generated files in CMake-friendly format and exit')
     parser.add_argument('output_directory', metavar='DIR', nargs='?',
-                        default=os.path.join(root, branch_data.header_directory),
+                        default=posixpath.join(root, branch_data.header_directory),
                         help='output file location (default: %(default)s)')
     options = parser.parse_args()
     list_only = options.list or options.list_for_cmake
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/config_history.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/config_history.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/config_history.py	2025-10-01 18:29:09.515414700 +0300
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/config_history.py	2026-03-27 12:34:57.783886400 +0200
@@ -1,4 +1,6 @@
 """Historical information about the library configuration.
+
+Note: this module is deprecated. Use config_macros.py instead.
 """
 
 ## Copyright The Mbed TLS Contributors
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/config_macros.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/config_macros.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/config_macros.py	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/config_macros.py	2026-03-27 12:34:57.784016100 +0200
@@ -0,0 +1,180 @@
+"""Information about configuration macros and derived macros."""
+
+## Copyright The Mbed TLS Contributors
+## SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+import glob
+import os
+import re
+from typing import FrozenSet, Iterable, Iterator, List
+
+from . import build_tree
+from . import generate_files_helper
+
+
+class ConfigMacros:
+    """Information about configuration macros and derived macros."""
+
+    def __init__(self, public: FrozenSet[str], adjusted: FrozenSet[str]) -> None:
+        self._public = public
+        self._internal = adjusted - public
+
+    def options(self) -> FrozenSet[str]:
+        """The set of configuration options in this product."""
+        return self._public
+
+    def internal(self) -> FrozenSet[str]:
+        """The set of internal option-like macros in this product."""
+        return self._internal
+
+    @staticmethod
+    def _load_file(filename: str) -> FrozenSet[str]:
+        """Load macro names from the given file."""
+        with open(filename, encoding='ascii') as input_:
+            return frozenset(line.strip()
+                             for line in input_)
+
+
+class Current(ConfigMacros, generate_files_helper.Generator):
+    """Information about config-like macros parsed from the source code."""
+
+    _SHADOW_FILE = 'scripts/data_files/config-options-current.txt'
+
+    _PUBLIC_CONFIG_HEADERS = [
+        'include/mbedtls/mbedtls_config.h',
+        'include/psa/crypto_config.h',
+    ]
+
+    _ADJUST_CONFIG_HEADERS = [
+        'include/**/*adjust*.h',
+        'drivers/*/include/**/*adjust*.h',
+    ]
+
+    _DEFINE_RE = re.compile(r'[/ ]*# *define  *([A-Z_a-z][0-9A-Z_a-z]*)')
+
+    def _list_files(self, patterns: Iterable[str]) -> Iterator[str]:
+        """Yield files matching the given glob patterns."""
+        for pattern in patterns:
+            yield from glob.glob(os.path.join(self._root, self._submodule,
+                                              pattern),
+                                 recursive=True)
+
+    def _search_file(self, filename: str) -> Iterator[str]:
+        """Yield macros defined in the given file."""
+        with open(filename, encoding='utf-8') as input_:
+            for line in input_:
+                m = self._DEFINE_RE.match(line)
+                if m:
+                    yield m.group(1)
+
+    def _search_files(self, patterns: Iterable[str]) -> FrozenSet[str]:
+        """Yield macros defined in files matching the given glob patterns."""
+        return frozenset(element
+                         for filename in self._list_files(patterns)
+                         for element in self._search_file(filename))
+
+    def shadow_file_path(self) -> str:
+        """The path to the option list shadow file."""
+        return os.path.join(self._root, self._submodule, self._SHADOW_FILE)
+
+    def __init__(self, submodule: str = '',
+                 shadow_missing_ok: bool = False) -> None:
+        """Look for macros defined in the given submodule's source tree.
+
+        If submodule is omitted or empty, look in the root module.
+
+        If shadow_missing_ok is true, treat a missing shadow file as
+        if it was empty. This is intended for use only when regenerating
+        the shadow file.
+        """
+        self._root = build_tree.guess_project_root()
+        self._submodule = submodule
+        shadow_file = self.shadow_file_path()
+        try:
+            public = self._load_file(shadow_file)
+        except FileNotFoundError:
+            if not shadow_missing_ok:
+                raise
+            public = frozenset()
+        adjusted = self._search_files(self._ADJUST_CONFIG_HEADERS)
+        super().__init__(public, adjusted)
+
+    def live_config_options(self) -> FrozenSet[str]:
+        """Return config options from the config file (as opposed to the shadow file)."""
+        return self._search_files(self._PUBLIC_CONFIG_HEADERS)
+
+    def is_shadow_file_up_to_date(self) -> bool:
+        """Whether the config options shadow file is up to date."""
+        live = self.live_config_options()
+        return live == self._public
+
+    def compare_shadow_file(self) -> str:
+        """Compare the option list shadow file with the live config file.
+
+        Return a string containing the names that are only found in one of
+        them, in a diff-like format: a line prefixed by ``+`` if the name
+        is missing from the shadow file, or by ``-`` if the name is only
+        in the shadow file.
+        """
+        live = self.live_config_options()
+        diff = []
+        for x in sorted(live | self._public):
+            if x not in live:
+                diff.append('+' + x + '\n')
+            elif x not in self._public:
+                diff.append('-' + x + '\n')
+        return ''.join(diff)
+
+    def update_shadow_file(self, always_update: bool) -> None:
+        """Update the shadow file from the live config file.
+
+        If always_update is false and the shadow file already has the desired
+        content, don't touch it.
+        """
+        if not always_update and self.is_shadow_file_up_to_date():
+            return
+        with open(self.shadow_file_path(), 'w') as out:
+            for name in sorted(self.live_config_options()):
+                out.write(name + '\n')
+
+    # Implement the generate_files_helper.Generator interface
+    def generator_name(self) -> str:
+        """Name as a generate_files_helper.Generator."""
+        return 'options'
+
+    def target_files(self) -> List[str]:
+        """List the (single) generated file name."""
+        return [os.path.join(self._submodule, self._SHADOW_FILE)]
+
+    def outdated_files(self) -> List[str]:
+        """List the (single) generated file name if it is out of date."""
+        if self.is_shadow_file_up_to_date():
+            return []
+        else:
+            return self.target_files()
+
+    def update(self, always: bool) -> None:
+        """Update the shadow file from the live config file."""
+        self.update_shadow_file(always)
+
+
+class History(ConfigMacros):
+    """Information about config-like macros in a previous version.
+
+    Load files created by ``framework/scripts/save_config_history.sh``.
+    """
+
+    def _load_history_file(self, basename: str) -> FrozenSet[str]:
+        """Load macro names from the given file in the history directory."""
+        filename = os.path.join(self._history_dir, basename)
+        return self._load_file(filename)
+
+    def __init__(self, project: str, version: str) -> None:
+        """Read information about the given project at the given version.
+
+        The information must be present in history files in the framework.
+        """
+        self._history_dir = os.path.join(build_tree.framework_root(), 'history')
+        public = self._load_history_file(f'config-options-{project}-{version}.txt')
+        adjusted = self._load_history_file(f'config-adjust-{project}-{version}.txt')
+        super().__init__(public, adjusted)
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/crypto_data_tests.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/crypto_data_tests.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/crypto_data_tests.py	2025-10-01 18:24:20.274708300 +0300
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/crypto_data_tests.py	2026-03-27 12:34:57.784164400 +0200
@@ -36,13 +36,14 @@
     # hashlib might not have everything, depending on the Python version and
     # the underlying OpenSSL. On Ubuntu 16.04, truncated sha512 and sha3/shake
     # are not available. On Ubuntu 22.04, md2, md4 and ripemd160 are not
-    # available.
+    # available. As of Python 3.14, Ascon is not available.
     CALCULATE = {
         'PSA_ALG_MD5': lambda data: hashlib.md5(data).hexdigest(),
         'PSA_ALG_RIPEMD160': None, #lambda data: hashlib.new('ripdemd160').hexdigest()
         'PSA_ALG_SHA_1': lambda data: hashlib.sha1(data).hexdigest(),
         'PSA_ALG_SHA_224': lambda data: hashlib.sha224(data).hexdigest(),
         'PSA_ALG_SHA_256': lambda data: hashlib.sha256(data).hexdigest(),
+        'PSA_ALG_SHA_256_192': None, #lambda data: hashlib.new('sha256').hexdigest()[:48]
         'PSA_ALG_SHA_384': lambda data: hashlib.sha384(data).hexdigest(),
         'PSA_ALG_SHA_512': lambda data: hashlib.sha512(data).hexdigest(),
         'PSA_ALG_SHA_512_224': None, #lambda data: hashlib.new('sha512_224').hexdigest()
@@ -51,7 +52,11 @@
         'PSA_ALG_SHA3_256': None, #lambda data: hashlib.sha3_256(data).hexdigest(),
         'PSA_ALG_SHA3_384': None, #lambda data: hashlib.sha3_384(data).hexdigest(),
         'PSA_ALG_SHA3_512': None, #lambda data: hashlib.sha3_512(data).hexdigest(),
+        'PSA_ALG_SHAKE128_192': None, #lambda data: hashlib.shake_128(data).hexdigest(24),
+        'PSA_ALG_SHAKE128_256': None, #lambda data: hashlib.shake_128(data).hexdigest(32),
+        'PSA_ALG_SHAKE256_256': None, #lambda data: hashlib.shake_256(data).hexdigest(32),
         'PSA_ALG_SHAKE256_512': None, #lambda data: hashlib.shake_256(data).hexdigest(64),
+        'PSA_ALG_ASCON_HASH256': None, #lambda data: ascon.ascon_hash(data),
     } #type: Dict[str, Optional[Callable[[bytes], str]]]
 
     @staticmethod
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/crypto_knowledge.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/crypto_knowledge.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/crypto_knowledge.py	2025-10-01 18:30:17.257858500 +0300
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/crypto_knowledge.py	2026-03-27 12:34:57.784284800 +0200
@@ -128,6 +128,7 @@
         return self.name.endswith('_PUBLIC_KEY')
 
     DH_KEY_SIZES = {
+        'PSA_DH_FAMILY_RFC3526': (1536, 2048, 3072, 4096, 6144, 8192),
         'PSA_DH_FAMILY_RFC7919': (2048, 3072, 4096, 6144, 8192),
     } # type: Dict[str, Tuple[int, ...]]
     ECC_KEY_SIZES = {
@@ -138,12 +139,15 @@
         'PSA_ECC_FAMILY_SECT_R1': (163, 233, 283, 409, 571),
         'PSA_ECC_FAMILY_SECT_R2': (163,),
         'PSA_ECC_FAMILY_BRAINPOOL_P_R1': (160, 192, 224, 256, 320, 384, 512),
+        'PSA_ECC_FAMILY_FRP': (256,),
         'PSA_ECC_FAMILY_MONTGOMERY': (255, 448),
         'PSA_ECC_FAMILY_TWISTED_EDWARDS': (255, 448),
     } # type: Dict[str, Tuple[int, ...]]
     KEY_TYPE_SIZES = {
         'PSA_KEY_TYPE_AES': (128, 192, 256), # exhaustive
+        'PSA_KEY_TYPE_ARC4': (8, 128, 2048), # extremes + sensible
         'PSA_KEY_TYPE_ARIA': (128, 192, 256), # exhaustive
+        'PSA_KEY_TYPE_ASCON': (128, 256), # exhaustive
         'PSA_KEY_TYPE_CAMELLIA': (128, 192, 256), # exhaustive
         'PSA_KEY_TYPE_CHACHA20': (256,), # exhaustive
         'PSA_KEY_TYPE_DERIVE': (120, 128), # sample
@@ -154,6 +158,8 @@
         'PSA_KEY_TYPE_PEPPER': (128, 256), # sample
         'PSA_KEY_TYPE_RAW_DATA': (8, 40, 128), # sample
         'PSA_KEY_TYPE_RSA_KEY_PAIR': (1024, 1536), # small sample
+        'PSA_KEY_TYPE_SM4': (128,), # exhaustive
+        'PSA_KEY_TYPE_XCHACHA20': (256,), # exhaustive
     } # type: Dict[str, Tuple[int, ...]]
     def sizes_to_test(self) -> Tuple[int, ...]:
         """Return a tuple of key sizes to test.
@@ -226,6 +232,8 @@
             if alg.head in ['CMAC', 'OFB'] and \
                self.head in ['ARIA', 'CAMELLIA']:
                 return False # not implemented in Mbed TLS
+            if alg.head == 'XTS' and self.head != 'AES':
+                return False # not implemented in Mbed TLS
             return True
         if self.head == 'CHACHA20' and alg.head == 'CHACHA20_POLY1305':
             return True
@@ -264,7 +272,7 @@
 class AlgorithmCategory(enum.Enum):
     """PSA algorithm categories."""
     # The numbers are aligned with the category bits in numerical values of
-    # algorithms.
+    # algorithms. The names match the `PSA_ALG_IS_xxx` macros.
     HASH = 2
     MAC = 3
     CIPHER = 4
@@ -274,17 +282,25 @@
     KEY_DERIVATION = 8
     KEY_AGREEMENT = 9
     PAKE = 10
+    KEY_WRAP = 11
+    KEY_ENCAPSULATION = 12
+    XOF = 13
 
     def requires_key(self) -> bool:
         """Whether operations in this category are set up with a key."""
-        return self not in {self.HASH, self.KEY_DERIVATION}
+        return self not in {
+            self.HASH,
+            self.XOF,
+            self.KEY_DERIVATION, # key passed separately from setup
+        }
 
     def is_asymmetric(self) -> bool:
         """Whether operations in this category involve asymmetric keys."""
         return self in {
             self.SIGN,
             self.ASYMMETRIC_ENCRYPTION,
-            self.KEY_AGREEMENT
+            self.KEY_AGREEMENT,
+            self.KEY_ENCAPSULATION,
         }
 
 
@@ -335,20 +351,33 @@
         return head
 
     CATEGORY_FROM_HEAD = {
+        'AES_MMO_ZIGBEE': AlgorithmCategory.HASH,
+        'ASCON_HASH': AlgorithmCategory.HASH,
         'SHA': AlgorithmCategory.HASH,
         'SHAKE256_512': AlgorithmCategory.HASH,
         'MD': AlgorithmCategory.HASH,
         'RIPEMD': AlgorithmCategory.HASH,
+        'SM3': AlgorithmCategory.HASH,
         'ANY_HASH': AlgorithmCategory.HASH,
         'HMAC': AlgorithmCategory.MAC,
         'STREAM_CIPHER': AlgorithmCategory.CIPHER,
+        'ASCON_AEAD': AlgorithmCategory.AEAD,
         'CHACHA20_POLY1305': AlgorithmCategory.AEAD,
+        'XCHACHA20_POLY1305': AlgorithmCategory.AEAD,
         'DSA': AlgorithmCategory.SIGN,
         'ECDSA': AlgorithmCategory.SIGN,
         'EDDSA': AlgorithmCategory.SIGN,
+        'HASH_ML_DSA': AlgorithmCategory.SIGN,
+        'HASH_SLH_DSA': AlgorithmCategory.SIGN,
+        'HSS': AlgorithmCategory.SIGN,
+        'LMS': AlgorithmCategory.SIGN,
+        'ML_DSA': AlgorithmCategory.SIGN,
         'PURE_EDDSA': AlgorithmCategory.SIGN,
+        'SLH_DSA': AlgorithmCategory.SIGN,
         'RSA_PSS': AlgorithmCategory.SIGN,
         'RSA_PKCS1V15_SIGN': AlgorithmCategory.SIGN,
+        'XMMS': AlgorithmCategory.SIGN,
+        'XMMS_MT': AlgorithmCategory.SIGN,
         'RSA_PKCS1V15_CRYPT': AlgorithmCategory.ASYMMETRIC_ENCRYPTION,
         'RSA_OAEP': AlgorithmCategory.ASYMMETRIC_ENCRYPTION,
         'HKDF': AlgorithmCategory.KEY_DERIVATION,
@@ -363,6 +392,13 @@
         'KEY_AGREEMENT': AlgorithmCategory.KEY_DERIVATION,
         'JPAKE': AlgorithmCategory.PAKE,
         'SPAKE2P': AlgorithmCategory.PAKE,
+        'KW': AlgorithmCategory.KEY_WRAP,
+        'KWP': AlgorithmCategory.KEY_WRAP,
+        'ECIES_SEC1': AlgorithmCategory.KEY_ENCAPSULATION,
+        'ML_KEM': AlgorithmCategory.KEY_ENCAPSULATION,
+        'ASCON_CXOF': AlgorithmCategory.XOF,
+        'ASCON_XOF': AlgorithmCategory.XOF,
+        'SHAKE': AlgorithmCategory.XOF,
     }
     for x in BLOCK_MAC_MODES:
         CATEGORY_FROM_HEAD[x] = AlgorithmCategory.MAC
@@ -453,16 +489,20 @@
         """
         return short_expression(self.expression, level=level)
 
-    HASH_LENGTH = {
+    HASH_LENGTH_BYTES = {
+        'PSA_ALG_AES_MMO_ZIGBEE': 16,
+        'PSA_ALG_MD2': 16,
+        'PSA_ALG_MD4': 16,
         'PSA_ALG_MD5': 16,
         'PSA_ALG_SHA_1': 20,
+        'PSA_ALG_SM3': 32,
     }
     HASH_LENGTH_BITS_RE = re.compile(r'([0-9]+)\Z')
     @classmethod
     def hash_length(cls, alg: str) -> int:
         """The length of the given hash algorithm, in bytes."""
-        if alg in cls.HASH_LENGTH:
-            return cls.HASH_LENGTH[alg]
+        if alg in cls.HASH_LENGTH_BYTES:
+            return cls.HASH_LENGTH_BYTES[alg]
         m = cls.HASH_LENGTH_BITS_RE.search(alg)
         if m:
             return int(m.group(1)) // 8
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/c_wrapper_generator.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/c_wrapper_generator.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/c_wrapper_generator.py	2025-10-01 18:24:20.273423400 +0300
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/c_wrapper_generator.py	2026-03-27 12:34:57.783028600 +0200
@@ -110,6 +110,17 @@
 
             ''')
 
+        if not header:
+            # On Mingw-w64, force the use of a C99-compliant printf() and friends.
+            # This is necessary on older versions of Mingw and/or Windows runtimes
+            # where snprintf does not always zero-terminate the buffer, and does
+            # not support formats such as "%zu" for size_t and "%lld" for long long.
+            prologue += strip_indentation(f'''
+                #if !defined(__USE_MINGW_ANSI_STDIO)
+                #define __USE_MINGW_ANSI_STDIO 1
+                #endif
+            ''')
+
         for include in self._INCLUDES:
             prologue += "#include {}\n".format(include)
 
@@ -359,7 +370,7 @@
         """Preprocessor symbol used as a guard against multiple inclusion."""
         # Heuristic to strip irrelevant leading directories
         filename = re.sub(r'.*include[\\/]', r'', filename)
-        return re.sub(r'[^0-9A-Za-z]', r'_', filename, re.A).upper()
+        return re.sub(r'[^0-9A-Za-z]', r'_', filename, flags=re.A).upper()
 
     def write_h_file(self, filename: str) -> None:
         """Output a header file with function wrapper declarations and macro definitions."""
@@ -403,7 +414,6 @@
 #if defined(MBEDTLS_FS_IO) && defined(MBEDTLS_TEST_HOOKS)
 #include <stdio.h>
 #include <inttypes.h>
-#include <mbedtls/debug.h> // for MBEDTLS_PRINTF_SIZET
 #include <mbedtls/platform.h> // for mbedtls_fprintf
 #endif /* defined(MBEDTLS_FS_IO) && defined(MBEDTLS_TEST_HOOKS) */
 """)
@@ -412,7 +422,7 @@
         'int': '%d',
         'long': '%ld',
         'long long': '%lld',
-        'size_t': '%"MBEDTLS_PRINTF_SIZET"',
+        'size_t': '%zu',
         'unsigned': '0x%08x',
         'unsigned int': '0x%08x',
         'unsigned long': '0x%08lx',
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/ecp.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/ecp.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/ecp.py	2025-10-01 18:24:20.275170000 +0300
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/ecp.py	2026-03-27 12:34:57.784482700 +0200
@@ -86,7 +86,9 @@
 
     @property
     def is_valid(self) -> bool:
-        return True
+        # secp192r1 support has been removed from development, but it's stil
+        # available in 3.6 branch.
+        return build_tree.is_mbedtls_3_6()
 
     def arguments(self)-> List[str]:
         args = super().arguments()
@@ -553,7 +555,9 @@
 
     @property
     def is_valid(self) -> bool:
-        return True
+        # secp192k1 support has been removed from development, but it's stil
+        # available in 3.6 branch.
+        return build_tree.is_mbedtls_3_6()
 
     def arguments(self):
         args = super().arguments()
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/generated_files.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/generated_files.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/generated_files.py	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/generated_files.py	2026-03-27 12:34:57.784859200 +0200
@@ -0,0 +1,167 @@
+"""Generic code to generate, check and list the generated files
+"""
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+import argparse
+import filecmp
+import shutil
+import subprocess
+import sys
+
+from pathlib import Path
+from typing import List, Optional
+
+class GenerationScript:
+    """
+    Representation of a script generating a configuration independent file.
+    """
+    # pylint: disable=too-few-public-methods,too-many-arguments
+    def __init__(self, script: Path, files: List[Path],
+                 output_dir_option: Optional[str] = None,
+                 output_file_option: Optional[str] = None,
+                 optional: bool = False) -> None:
+        # Path from the root of Mbed TLS or TF-PSA-Crypto of the generation script
+        self.script = script
+
+        # Executable to run the script, needed for Windows
+        if script.suffix == ".py":
+            self.exe = sys.executable
+        elif script.suffix == ".pl":
+            self.exe = "perl"
+
+        # List of the default paths from the Mbed TLS or TF-PSA-Crypto root of the
+        # files the script generates.
+        self.files = files
+
+        # Output directory script argument. Can be an empty string in case it is a
+        # positional argument.
+        self.output_dir_option = output_dir_option
+
+        # Output file script argument. Can be an empty string in case it is a
+        # positional argument.
+        self.output_file_option = output_file_option
+
+        # Optional files are skipped in --check mode if they don't exist.
+        # This normally shouldn't happen, but it can happen during transition
+        # periods where we're adding a new script or a new file, and a
+        # consuming repository hasn't been updated yet.
+        self.optional = optional
+
+def get_generation_script_files(generation_script: str) -> List[Path]:
+    """
+    Get the list of the default paths of the files that a given script
+    generates. It is assumed that the script supports the "--list" option.
+    """
+    files = []
+    if generation_script.endswith(".py"):
+        cmd = [sys.executable]
+    elif generation_script.endswith(".pl"):
+        cmd = ["perl"]
+    cmd += [generation_script, "--list"]
+
+    output = subprocess.check_output(cmd, universal_newlines=True)
+    for line in output.splitlines():
+        files.append(Path(line))
+
+    return files
+
+def get_generated_files(generation_scripts: List[GenerationScript]) -> List[Path]:
+    """
+    List the generated files in Mbed TLS or TF-PSA-Crypto. The path from root
+    is returned for each generated files.
+    """
+    files = []
+    for generation_script in generation_scripts:
+        files += generation_script.files
+
+    return files
+
+def make_generated_files(generation_scripts: List[GenerationScript]) -> None:
+    """
+    Generate the configuration independent files in their default location in
+    the Mbed TLS or TF-PSA-Crypto tree.
+    """
+    for generation_script in generation_scripts:
+        subprocess.run([generation_script.exe, str(generation_script.script)], check=True)
+
+def check_generated_files(generation_scripts: List[GenerationScript],
+                          root: Path) -> bool:
+    """
+    Check that the given root directory contains the generated files as expected/
+    generated by this script.
+    """
+    ok = True
+    for generation_script in generation_scripts:
+        for file in generation_script.files:
+            file = root / file
+            if not file.exists():
+                # If the script is just being added, allow its files not
+                # to exist. This can happen, at least, when adding a new
+                # generation script in crypto: until mbedtls is updated,
+                # the files from that script won't be present when
+                # the updated crypto is built from mbedtls development.
+                if generation_script.optional:
+                    continue
+                raise Exception(f"Expected generated file does not exist: {file}")
+            bak_file = file.with_name(file.name + ".bak")
+            if bak_file.exists():
+                bak_file.unlink()
+            file.rename(bak_file)
+
+        command = [generation_script.exe, str(generation_script.script)]
+        if generation_script.output_dir_option is not None:
+            command += [generation_script.output_dir_option,
+                        str(root / Path(generation_script.files[0].parent))]
+        elif generation_script.output_file_option is not None:
+            command += generation_script.output_file_option.split()
+            command += [str(root / Path(generation_script.files[0]))]
+        subprocess.run([item for item in command if item.strip()], check=True)
+
+        for file in generation_script.files:
+            file = root / file
+            bak_file = file.with_name(file.name + ".bak")
+            if generation_script.optional and not bak_file.exists():
+                # This file is optional and didn't exist before, so
+                # there's nothing to compare to, or clean up.
+                continue
+            if not filecmp.cmp(file, bak_file):
+                ok = False
+                ref_file = file.with_name(file.name + ".ref")
+                ref_file = root / ref_file
+                if ref_file.exists():
+                    ref_file.unlink()
+                shutil.copy(file, ref_file)
+                print(f"Generated file {file} not identical to the reference one {ref_file}.")
+            file.unlink()
+            bak_file.rename(file)
+    return ok
+
+def main(generation_scripts: List[GenerationScript]) -> int:
+    """
+    Main function of this program
+    """
+    parser = argparse.ArgumentParser()
+
+    parser.add_argument('--list', action='store_true',
+                        default=False, help='List generated files.')
+    parser.add_argument('--root', metavar='DIR',
+                        help='Root of the tree containing the generated files \
+                              to check (default: Mbed TLS or TF-PSA-Cryto root.)')
+    parser.add_argument('--check', action='store_true',
+                        default=False, help='Check the generated files in root')
+
+    args = parser.parse_args()
+
+    if args.list:
+        files = get_generated_files(generation_scripts)
+        for file in files:
+            print(str(file))
+        return 0
+    elif args.check:
+        ok = check_generated_files(generation_scripts, Path(args.root or "."))
+        return 0 if ok else 1
+    else:
+        make_generated_files(generation_scripts)
+        return 0 # Any error causes an exception
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/generate_files_helper.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/generate_files_helper.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/generate_files_helper.py	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/generate_files_helper.py	2026-03-27 12:34:57.784712300 +0200
@@ -0,0 +1,182 @@
+"""Utilities for intermediate files that are generated, but platform-independent
+and configuration-independent.
+"""
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+import argparse
+import os
+import subprocess
+import sys
+from typing import Dict, Iterable, List, Sequence, Set
+
+
+class Generator:
+    """An abstract base class for generators of intermediate files."""
+
+    def generator_name(self) -> str:
+        """A name for this generator.
+
+        Generator names must be unique and should not be identical to
+        the name of any target.
+        """
+        raise NotImplementedError
+
+    def target_files(self) -> List[str]:
+        """The list of files targeted by this generator.
+
+        File names are relative to the project root.
+        """
+        raise NotImplementedError
+
+    def outdated_files(self) -> Iterable[str]:
+        """Return the list of targets that are out of date.
+
+        This is empty after running update().
+        Missing targets are considered out of date.
+        """
+        raise NotImplementedError
+
+    def update(self, always: bool) -> None:
+        """Update the target(s) of this generator.
+
+        If always is false, avoid changing the output file if it already has
+        the desired content. If always is true, make sure to update the
+        time stamp on the output file even if it already has the desired content.
+        """
+        raise NotImplementedError
+
+
+class TestDataGenerator(Generator):
+    """A test data generator script.
+
+    Even though the test data generator scripts are written in Python, we
+    run them as a separate process, because their output depends on the
+    program name (they write sys.argv[0] in a comment in the .data file).
+    """
+
+    def __init__(self, script: str) -> None:
+        """Run the specified test generator to generate files.
+
+        Assume that the script is written in Python and has the command line
+        interface of test_data_generation.py.
+        """
+        self.script = script
+
+    def generator_name(self) -> str:
+        return os.path.basename(self.script)
+
+    def target_files(self) -> List[str]:
+        output = subprocess.check_output([sys.executable, self.script, '--list'],
+                                         encoding='utf-8')
+        return output.splitlines()
+
+    def outdated_files(self) -> List[str]:
+        output = subprocess.check_output([sys.executable, self.script, '--list-outdated'],
+                                         encoding='utf-8')
+        return output.splitlines()
+
+    def update(self, _always) -> None:
+        subprocess.check_call([sys.executable, self.script])
+
+
+def assemble(available: Iterable[Generator]) -> Dict[str, Generator]:
+    """Assemble the generators into a dictionary with both names and targets as keys."""
+    by_ident = {} #type: Dict[str, Generator]
+    for generator in available:
+        ident = generator.generator_name()
+        if ident in by_ident:
+            raise Exception(f'Generator conflict: name "{ident}" of {generator} '
+                            f'already recorded for {by_ident[ident]}')
+        by_ident[ident] = generator
+        for ident in generator.target_files():
+            if ident in by_ident:
+                raise Exception(f'Generator conflict: target "{ident}" of {generator} '
+                                f'already recorded for {by_ident[ident]}')
+            by_ident[ident] = generator
+    return by_ident
+
+def list_names(available: Iterable[Generator]) -> List[str]:
+    """Return the list of generator names."""
+    return sorted(generator.generator_name() for generator in available)
+
+def list_targets(available: Iterable[Generator]) -> List[str]:
+    """Return the list of generator targets."""
+    return sorted(target
+                  for generator in available
+                  for target in generator.target_files())
+
+def select(available: Dict[str, Generator],
+           wanted: Iterable[str]) -> List[Generator]:
+    """Select generators by name or target."""
+    wanted_names = set() #type: Set[str]
+    for ident in wanted:
+        if ident not in available:
+            raise Exception(f'No generator found for {ident}')
+        wanted_names.add(ident)
+    return [available[name] for name in sorted(wanted_names)]
+
+def main(generators: Sequence[Generator],
+         description: str) -> None:
+    #pylint: disable=too-many-branches
+    """Command line entry point.
+    """
+    parser = argparse.ArgumentParser(description=description)
+    parser.add_argument('--always-update', '-U',
+                        action='store_true',
+                        help=('Update target files unconditionally '
+                              '(overrides --update)'))
+    parser.add_argument('--list',
+                        action='store_true',
+                        help='List generator names and targets and exit')
+    parser.add_argument('--list-names',
+                        action='store_true',
+                        help='List generator names and exit')
+    parser.add_argument('--list-targets',
+                        action='store_true',
+                        help='List generator targets and exit')
+    parser.add_argument('--update', '-u',
+                        action='store_true',
+                        help='Update target files if needed')
+    parser.add_argument('--verbose', '-v',
+                        action='store_true',
+                        help='Be more verbose')
+    parser.add_argument('idents', nargs='*', metavar='NAME|TARGET',
+                        help='List of generator names or targets (all targets if empty)')
+    args = parser.parse_args()
+
+    if args.list:
+        args.list_names = True
+        args.list_targets = True
+    if args.list_names:
+        for name in list_names(generators):
+            print(name)
+    if args.list_targets:
+        for target in list_targets(generators):
+            print(target)
+    if args.list_names or args.list_targets:
+        return
+
+    if args.idents:
+        available = assemble(generators)
+        wanted = select(available, args.idents) #type: Sequence[Generator]
+    else:
+        wanted = generators
+    if args.update or args.always_update:
+        for generator in wanted:
+            if args.verbose:
+                sys.stderr.write(f'Running generator {generator.generator_name()}...\n')
+            generator.update(args.always_update)
+    else:
+        outdated = [] #type: List[str]
+        for generator in wanted:
+            if args.verbose:
+                sys.stderr.write(f'Checking targets of generator {generator.generator_name()}...\n')
+            outdated += generator.outdated_files()
+        if outdated:
+            sys.stderr.write(f'Some targets are missing or out of date.\n')
+            for target in outdated:
+                print(target)
+            sys.stderr.write(f'Run {sys.argv[0]} -u and commit the result.')
+            sys.exit(1)
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/interface_checks.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/interface_checks.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/interface_checks.py	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/interface_checks.py	2026-03-27 12:34:57.784966000 +0200
@@ -0,0 +1,679 @@
+"""This script compares the interfaces of two versions of Mbed TLS, looking
+for backward incompatibilities between two different Git revisions within
+an Mbed TLS repository. It must be run from the root of a Git working tree.
+
+### How the script works ###
+
+For the source (API) and runtime (ABI) interface compatibility, this script
+is a small wrapper around the abi-compliance-checker and abi-dumper tools,
+applying them to compare the header and library files.
+
+For the storage format, this script compares the automatically generated
+storage tests and the manual read tests, and complains if there is a
+reduction in coverage. A change in test data will be signaled as a
+coverage reduction since the old test data is no longer present. A change in
+how test data is presented will be signaled as well; this would be a false
+positive.
+
+The results of the API/ABI comparison are either formatted as HTML and stored
+at a configurable location, or are given as a brief list of problems.
+Returns 0 on success, 1 on non-compliance, and 2 if there is an error
+while running the script.
+
+### How to interpret non-compliance ###
+
+This script has relatively common false positives. In many scenarios, it only
+reports a pass if there is a strict textual match between the old version and
+the new version, and it reports problems where there is a sufficient semantic
+match but not a textual match. This section lists some common false positives.
+This is not an exhaustive list: in the end what matters is whether we are
+breaking a backward compatibility goal.
+
+**API**: the goal is that if an application works with the old version of the
+library, it can be recompiled against the new version and will still work.
+This is normally validated by comparing the declarations in `include/*/*.h`.
+A failure is a declaration that has disappeared or that now has a different
+type.
+
+  * It's ok to change or remove macros and functions that are documented as
+    for internal use only or as experimental.
+  * It's ok to rename function or macro parameters as long as the semantics
+    has not changed.
+  * It's ok to change or remove structure fields that are documented as
+    private.
+  * It's ok to add fields to a structure that already had private fields
+    or was documented as extensible.
+
+**ABI**: the goal is that if an application was built against the old version
+of the library, the same binary will work when linked against the new version.
+This is normally validated by comparing the symbols exported by `libmbed*.so`.
+A failure is a symbol that is no longer exported by the same library or that
+now has a different type.
+
+  * All ABI changes are acceptable if the library version is bumped
+    (see `scripts/bump_version.sh`).
+  * ABI changes that concern functions which are declared only inside the
+    library directory, and not in `include/*/*.h`, are acceptable only if
+    the function was only ever used inside the same library (libmbedcrypto,
+    libmbedx509, libmbedtls). As a counter example, if the old version
+    of libmbedtls calls mbedtls_foo() from libmbedcrypto, and the new version
+    of libmbedcrypto no longer has a compatible mbedtls_foo(), this does
+    require a version bump for libmbedcrypto.
+
+**Storage format**: the goal is to check that persistent keys stored by the
+old version can be read by the new version. This is normally validated by
+comparing the `*read*` test cases in `test_suite*storage_format*.data`.
+A failure is a storage read test case that is no longer present with the same
+function name and parameter list.
+
+  * It's ok if the same test data is present, but its presentation has changed,
+    for example if a test function is renamed or has different parameters.
+  * It's ok if redundant tests are removed.
+
+**Generated test coverage**: the goal is to check that automatically
+generated tests have as much coverage as before. This is normally validated
+by comparing the test cases that are automatically generated by a script.
+A failure is a generated test case that is no longer present with the same
+function name and parameter list.
+
+  * It's ok if the same test data is present, but its presentation has changed,
+    for example if a test function is renamed or has different parameters.
+  * It's ok if redundant tests are removed.
+
+"""
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+import glob
+import os
+import re
+import sys
+import traceback
+import shutil
+import subprocess
+import argparse
+import logging
+import tempfile
+import filecmp
+import fnmatch
+from types import SimpleNamespace
+
+import xml.etree.ElementTree as ET
+
+from . import build_tree
+
+
+class AbiChecker:
+    """API and ABI checker."""
+
+    def __init__(self, old_version, new_version, configuration):
+        """Instantiate the API/ABI checker.
+
+        old_version: RepoVersion containing details to compare against
+        new_version: RepoVersion containing details to check
+        configuration.report_dir: directory for output files
+        configuration.keep_all_reports: if false, delete old reports
+        configuration.brief: if true, output shorter report to stdout
+        configuration.check_abi: if true, compare ABIs
+        configuration.check_api: if true, compare APIs
+        configuration.check_storage: if true, compare storage format tests
+        configuration.skip_file: path to file containing symbols and types to skip
+        """
+        self.repo_path = build_tree.guess_project_root()
+        self.log = None
+        self.verbose = configuration.verbose
+        self._setup_logger()
+        self.report_dir = os.path.abspath(configuration.report_dir)
+        self.keep_all_reports = configuration.keep_all_reports
+        self.can_remove_report_dir = not (os.path.exists(self.report_dir) or
+                                          self.keep_all_reports)
+        self.old_version = old_version
+        self.new_version = new_version
+        self.skip_file = configuration.skip_file
+        self.check_abi = configuration.check_abi
+        self.check_api = configuration.check_api
+        if self.check_abi != self.check_api:
+            raise Exception('Checking API without ABI or vice versa is not supported')
+        self.check_storage_tests = configuration.check_storage
+        self.brief = configuration.brief
+        self.git_command = "git"
+        self.cmake_command = "cmake"
+
+    def _setup_logger(self):
+        self.log = logging.getLogger()
+        if self.verbose:
+            self.log.setLevel(logging.DEBUG)
+        else:
+            self.log.setLevel(logging.INFO)
+        self.log.addHandler(logging.StreamHandler())
+
+    @staticmethod
+    def check_abi_tools_are_installed():
+        for command in ["abi-dumper", "abi-compliance-checker"]:
+            if not shutil.which(command):
+                raise Exception("{} not installed, aborting".format(command))
+
+    def _get_clean_worktree_for_git_revision(self, version):
+        """Make a separate worktree with version.revision checked out.
+        Do not modify the current worktree."""
+        git_worktree_path = tempfile.mkdtemp()
+        if version.repository:
+            self.log.debug(
+                "Checking out git worktree for revision {} from {}".format(
+                    version.revision, version.repository
+                )
+            )
+            fetch_output = subprocess.check_output(
+                [self.git_command, "fetch",
+                 version.repository, version.revision],
+                cwd=self.repo_path,
+                stderr=subprocess.STDOUT
+            )
+            self.log.debug(fetch_output.decode("utf-8"))
+            worktree_rev = "FETCH_HEAD"
+        else:
+            self.log.debug("Checking out git worktree for revision {}".format(
+                version.revision
+            ))
+            worktree_rev = version.revision
+        worktree_output = subprocess.check_output(
+            [self.git_command, "worktree", "add", "--detach",
+             git_worktree_path, worktree_rev],
+            cwd=self.repo_path,
+            stderr=subprocess.STDOUT
+        )
+        self.log.debug(worktree_output.decode("utf-8"))
+        version.commit = subprocess.check_output(
+            [self.git_command, "rev-parse", "HEAD"],
+            cwd=git_worktree_path,
+            stderr=subprocess.STDOUT
+        ).decode("ascii").rstrip()
+        self.log.debug("Commit is {}".format(version.commit))
+        return git_worktree_path
+
+    def _update_git_submodules(self, git_worktree_path):
+        """Recursively checkout all submodules at the revision recorded in their
+           parent module"""
+        submodule_output = subprocess.check_output(
+            [self.git_command, "submodule", "foreach", "--recursive",
+             f'git worktree add --detach "{git_worktree_path}/$displaypath" HEAD'],
+            cwd=self.repo_path,
+            stderr=subprocess.STDOUT
+        )
+        self.log.debug(submodule_output.decode("utf-8"))
+
+        try:
+            # Try to update the submodules using local commits
+            # (Git will sometimes insist on fetching the remote without --no-fetch
+            # if the submodules are shallow clones)
+            update_output = subprocess.check_output(
+                [self.git_command, "submodule", "update", "--init", '--recursive', '--no-fetch'],
+                cwd=git_worktree_path,
+                stderr=subprocess.STDOUT
+            )
+        except subprocess.CalledProcessError as err:
+            self.log.debug(err.stdout.decode("utf-8"))
+
+            # Checkout with --no-fetch failed, falling back to fetching from origin
+            update_output = subprocess.check_output(
+                [self.git_command, "submodule", "update", "--init", '--recursive'],
+                cwd=git_worktree_path,
+                stderr=subprocess.STDOUT
+            )
+        self.log.debug(update_output.decode("utf-8"))
+
+    def _build_shared_libraries(self, git_worktree_path, version):
+        """Build the shared libraries in the specified worktree."""
+        build_dir = os.path.join(git_worktree_path, "build")
+        os.mkdir(build_dir)
+        configure_output = subprocess.check_output(
+            [
+                self.cmake_command, "..",
+                "-DCMAKE_BUILD_TYPE=Debug",
+                "-DENABLE_TESTING=OFF",
+                "-DENABLE_PROGRAMS=OFF",
+                "-DUSE_SHARED_MBEDTLS_LIBRARY=ON",
+                "-DUSE_STATIC_MBEDTLS_LIBRARY=OFF",
+                "-DUSE_SHARED_TF_PSA_CRYPTO_LIBRARY=ON",
+                "-DUSE_STATIC_TF_PSA_CRYPTO_LIBRARY=OFF",
+            ],
+            cwd=build_dir,
+            stderr=subprocess.STDOUT
+        )
+        self.log.debug(configure_output.decode("utf-8"))
+
+        build_output = subprocess.check_output(
+            [self.cmake_command, "--build", build_dir],
+            stderr=subprocess.STDOUT
+        )
+        self.log.debug(build_output.decode("utf-8"))
+        for root, _dirs, files in os.walk(build_dir):
+            for file in fnmatch.filter(files, "*.so"):
+                basename = os.path.splitext(file)[0]
+                path = os.path.join(root, file)
+                if basename in version.modules:
+                    if not filecmp.cmp(version.modules[basename], path):
+                        raise Exception(
+                            "The following libraries differ, but have the same name:\n"
+                            f"{version.modules[basename]}\n"
+                            f"{path}"
+                        )
+                else:
+                    version.modules[basename] = path
+
+    @staticmethod
+    def _pretty_revision(version):
+        if version.revision == version.commit:
+            return version.revision
+        else:
+            return "{} ({})".format(version.revision, version.commit)
+
+    def _get_abi_dumps_from_shared_libraries(self, version):
+        """Generate the ABI dumps for the specified git revision.
+        The shared libraries must have been built and the module paths
+        present in version.modules."""
+        for mbed_module, module_path in version.modules.items():
+            output_path = os.path.join(
+                self.report_dir, "{}-{}-{}.dump".format(
+                    mbed_module, version.revision, version.version
+                )
+            )
+            abi_dump_command = [
+                "abi-dumper",
+                module_path,
+                "-o", output_path,
+                "-lver", self._pretty_revision(version),
+            ]
+            abi_dump_output = subprocess.check_output(
+                abi_dump_command,
+                stderr=subprocess.STDOUT
+            )
+            self.log.debug(abi_dump_output.decode("utf-8"))
+            version.abi_dumps[mbed_module] = output_path
+
+    @staticmethod
+    def _normalize_storage_test_case_data(line):
+        """Eliminate cosmetic or irrelevant details in storage format test cases."""
+        line = re.sub(r'\s+', r'', line)
+        return line
+
+    def _read_storage_tests(self,
+                            directory,
+                            filename,
+                            is_generated,
+                            storage_tests):
+        """Record storage tests from the given file.
+
+        Populate the storage_tests dictionary with test cases read from
+        filename under directory.
+        """
+        at_paragraph_start = True
+        description = None
+        full_path = os.path.join(directory, filename)
+        with open(full_path) as fd:
+            for line_number, line in enumerate(fd, 1):
+                line = line.strip()
+                if not line:
+                    at_paragraph_start = True
+                    continue
+                if line.startswith('#'):
+                    continue
+                if at_paragraph_start:
+                    description = line.strip()
+                    at_paragraph_start = False
+                    continue
+                if line.startswith('depends_on:'):
+                    continue
+                # We've reached a test case data line
+                test_case_data = self._normalize_storage_test_case_data(line)
+                if not is_generated:
+                    # In manual test data, only look at read tests.
+                    function_name = test_case_data.split(':', 1)[0]
+                    if 'read' not in function_name.split('_'):
+                        continue
+                metadata = SimpleNamespace(
+                    filename=filename,
+                    line_number=line_number,
+                    description=description
+                )
+                storage_tests[test_case_data] = metadata
+
+    @staticmethod
+    def _list_generated_test_data_files(git_worktree_path):
+        """List the generated test data files."""
+        generate_psa_tests = 'framework/scripts/generate_psa_tests.py'
+        if not os.path.isfile(git_worktree_path + '/' + generate_psa_tests):
+            # The checked-out revision is from before generate_psa_tests.py
+            # was moved to the framework submodule. Use the old location.
+            generate_psa_tests = 'tests/scripts/generate_psa_tests.py'
+
+        output = subprocess.check_output(
+            [generate_psa_tests, '--list'],
+            cwd=git_worktree_path,
+        ).decode('ascii')
+        return [line for line in output.split('\n') if line]
+
+    def _get_storage_format_tests(self, version, git_worktree_path):
+        """Record the storage format tests for the specified git version.
+
+        The storage format tests are the test suite data files whose name
+        contains "storage_format".
+
+        The version must be checked out at git_worktree_path.
+
+        This function creates or updates the generated data files.
+        """
+        # Existing test data files. This may be missing some automatically
+        # generated files if they haven't been generated yet.
+        if os.path.isdir(os.path.join(git_worktree_path, 'tf-psa-crypto',
+                                      'tests', 'suites')):
+            storage_data_files = set(glob.glob(
+                'tf-psa-crypto/tests/suites/test_suite_*storage_format*.data'
+            ))
+        else:
+            storage_data_files = set(glob.glob(
+                'tests/suites/test_suite_*storage_format*.data'
+            ))
+        # Discover and (re)generate automatically generated data files.
+        to_be_generated = set()
+        for filename in self._list_generated_test_data_files(git_worktree_path):
+            if 'storage_format' in filename:
+                storage_data_files.add(filename)
+                to_be_generated.add(filename)
+
+        generate_psa_tests = 'framework/scripts/generate_psa_tests.py'
+        if not os.path.isfile(git_worktree_path + '/' + generate_psa_tests):
+            # The checked-out revision is from before generate_psa_tests.py
+            # was moved to the framework submodule. Use the old location.
+            generate_psa_tests = 'tests/scripts/generate_psa_tests.py'
+        subprocess.check_call(
+            [generate_psa_tests] + sorted(to_be_generated),
+            cwd=git_worktree_path,
+        )
+        for test_file in sorted(storage_data_files):
+            self._read_storage_tests(git_worktree_path,
+                                     test_file,
+                                     test_file in to_be_generated,
+                                     version.storage_tests)
+
+    def _cleanup_worktree(self, git_worktree_path):
+        """Remove the specified git worktree."""
+        shutil.rmtree(git_worktree_path)
+        submodule_output = subprocess.check_output(
+            [self.git_command, "submodule", "foreach", "--recursive",
+             f'git worktree remove "{git_worktree_path}/$displaypath"'],
+            cwd=self.repo_path,
+            stderr=subprocess.STDOUT
+        )
+        self.log.debug(submodule_output.decode("utf-8"))
+        worktree_output = subprocess.check_output(
+            [self.git_command, "worktree", "remove", git_worktree_path],
+            cwd=self.repo_path,
+            stderr=subprocess.STDOUT
+        )
+        self.log.debug(worktree_output.decode("utf-8"))
+
+    def _get_abi_dump_for_ref(self, version):
+        """Generate the interface information for the specified git revision."""
+        git_worktree_path = self._get_clean_worktree_for_git_revision(version)
+        self._update_git_submodules(git_worktree_path)
+        if self.check_abi:
+            self._build_shared_libraries(git_worktree_path, version)
+            self._get_abi_dumps_from_shared_libraries(version)
+        if self.check_storage_tests:
+            self._get_storage_format_tests(version, git_worktree_path)
+        self._cleanup_worktree(git_worktree_path)
+
+    def _remove_children_with_tag(self, parent, tag):
+        children = parent.getchildren()
+        for child in children:
+            if child.tag == tag:
+                parent.remove(child)
+            else:
+                self._remove_children_with_tag(child, tag)
+
+    def _remove_extra_detail_from_report(self, report_root):
+        for tag in ['test_info', 'test_results', 'problem_summary',
+                    'added_symbols', 'affected']:
+            self._remove_children_with_tag(report_root, tag)
+
+        for report in report_root:
+            for problems in report.getchildren()[:]:
+                if not problems.getchildren():
+                    report.remove(problems)
+
+    def _abi_compliance_command(self, mbed_module, output_path):
+        """Build the command to run to analyze the library mbed_module.
+        The report will be placed in output_path."""
+        abi_compliance_command = [
+            "abi-compliance-checker",
+            "-l", mbed_module,
+            "-old", self.old_version.abi_dumps[mbed_module],
+            "-new", self.new_version.abi_dumps[mbed_module],
+            "-strict",
+            "-report-path", output_path,
+        ]
+        if self.skip_file:
+            abi_compliance_command += ["-skip-symbols", self.skip_file,
+                                       "-skip-types", self.skip_file]
+        if self.brief:
+            abi_compliance_command += ["-report-format", "xml",
+                                       "-stdout"]
+        return abi_compliance_command
+
+    def _is_library_compatible(self, mbed_module, compatibility_report):
+        """Test if the library mbed_module has remained compatible.
+        Append a message regarding compatibility to compatibility_report."""
+        output_path = os.path.join(
+            self.report_dir, "{}-{}-{}.html".format(
+                mbed_module, self.old_version.revision,
+                self.new_version.revision
+            )
+        )
+        try:
+            subprocess.check_output(
+                self._abi_compliance_command(mbed_module, output_path),
+                stderr=subprocess.STDOUT
+            )
+        except subprocess.CalledProcessError as err:
+            if err.returncode != 1:
+                raise err
+            if self.brief:
+                self.log.info(
+                    "Compatibility issues found for {}".format(mbed_module)
+                )
+                report_root = ET.fromstring(err.output.decode("utf-8"))
+                self._remove_extra_detail_from_report(report_root)
+                self.log.info(ET.tostring(report_root).decode("utf-8"))
+            else:
+                self.can_remove_report_dir = False
+                compatibility_report.append(
+                    "Compatibility issues found for {}, "
+                    "for details see {}".format(mbed_module, output_path)
+                )
+            return False
+        compatibility_report.append(
+            "No compatibility issues for {}".format(mbed_module)
+        )
+        if not (self.keep_all_reports or self.brief):
+            os.remove(output_path)
+        return True
+
+    @staticmethod
+    def _is_storage_format_compatible(old_tests, new_tests,
+                                      compatibility_report):
+        """Check whether all tests present in old_tests are also in new_tests.
+
+        Append a message regarding compatibility to compatibility_report.
+        """
+        missing = frozenset(old_tests.keys()).difference(new_tests.keys())
+        for test_data in sorted(missing):
+            metadata = old_tests[test_data]
+            compatibility_report.append(
+                'Test case from {} line {} "{}" has disappeared: {}'.format(
+                    metadata.filename, metadata.line_number,
+                    metadata.description, test_data
+                )
+            )
+        compatibility_report.append(
+            'FAIL: {}/{} storage format test cases have changed or disappeared.'.format(
+                len(missing), len(old_tests)
+            ) if missing else
+            'PASS: All {} storage format test cases are preserved.'.format(
+                len(old_tests)
+            )
+        )
+        compatibility_report.append(
+            'Info: number of storage format tests cases: {} -> {}.'.format(
+                len(old_tests), len(new_tests)
+            )
+        )
+        return not missing
+
+    def get_abi_compatibility_report(self):
+        """Generate a report of the differences between the reference ABI
+        and the new ABI. ABI dumps from self.old_version and self.new_version
+        must be available."""
+        compatibility_report = ["Checking evolution from {} to {}".format(
+            self._pretty_revision(self.old_version),
+            self._pretty_revision(self.new_version)
+        )]
+        compliance_return_code = 0
+
+        if self.check_abi:
+            shared_modules = list(set(self.old_version.modules.keys()) &
+                                  set(self.new_version.modules.keys()))
+            for mbed_module in shared_modules:
+                if not self._is_library_compatible(mbed_module,
+                                                   compatibility_report):
+                    compliance_return_code = 1
+
+        if self.check_storage_tests:
+            if not self._is_storage_format_compatible(
+                    self.old_version.storage_tests,
+                    self.new_version.storage_tests,
+                    compatibility_report):
+                compliance_return_code = 1
+
+        for version in [self.old_version, self.new_version]:
+            for mbed_module, mbed_module_dump in version.abi_dumps.items():
+                os.remove(mbed_module_dump)
+        if self.can_remove_report_dir:
+            os.rmdir(self.report_dir)
+        self.log.info("\n".join(compatibility_report))
+        return compliance_return_code
+
+    def check_for_abi_changes(self):
+        """Generate a report of ABI differences
+        between self.old_rev and self.new_rev."""
+        try:
+            if self.check_api or self.check_abi:
+                self.check_abi_tools_are_installed()
+            self._get_abi_dump_for_ref(self.old_version)
+            self._get_abi_dump_for_ref(self.new_version)
+            return self.get_abi_compatibility_report()
+        except subprocess.CalledProcessError as err:
+            self.log.error(err.stdout.decode("utf-8"))
+            raise err
+
+
+def run_main():
+    try:
+        parser = argparse.ArgumentParser(
+            description=__doc__,
+            formatter_class=argparse.RawDescriptionHelpFormatter
+        )
+        parser.add_argument(
+            "-v", "--verbose", action="store_true",
+            help="set verbosity level",
+        )
+        parser.add_argument(
+            "-r", "--report-dir", type=str, default="reports",
+            help="directory where reports are stored, default is reports",
+        )
+        parser.add_argument(
+            "-k", "--keep-all-reports", action="store_true",
+            help="keep all reports, even if there are no compatibility issues",
+        )
+        parser.add_argument(
+            "-o", "--old-rev", type=str, help="revision for old version.",
+            required=True,
+        )
+        parser.add_argument(
+            "-or", "--old-repo", type=str, help="repository for old version."
+        )
+        parser.add_argument(
+            "-n", "--new-rev", type=str, help="revision for new version",
+            required=True,
+        )
+        parser.add_argument(
+            "-nr", "--new-repo", type=str, help="repository for new version."
+        )
+        parser.add_argument(
+            "-s", "--skip-file", type=str,
+            help=("path to file containing symbols and types to skip "
+                  "(typically \"-s identifiers\" after running "
+                  "\"tests/scripts/list-identifiers.sh --internal\")")
+        )
+        parser.add_argument(
+            "--check-abi",
+            action='store_true', default=True,
+            help="Perform ABI comparison (default: yes)"
+        )
+        parser.add_argument("--no-check-abi", action='store_false', dest='check_abi')
+        parser.add_argument(
+            "--check-api",
+            action='store_true', default=True,
+            help="Perform API comparison (default: yes)"
+        )
+        parser.add_argument("--no-check-api", action='store_false', dest='check_api')
+        parser.add_argument(
+            "--check-storage",
+            action='store_true', default=True,
+            help="Perform storage tests comparison (default: yes)"
+        )
+        parser.add_argument("--no-check-storage", action='store_false', dest='check_storage')
+        parser.add_argument(
+            "-b", "--brief", action="store_true",
+            help="output only the list of issues to stdout, instead of a full report",
+        )
+        abi_args = parser.parse_args()
+        if os.path.isfile(abi_args.report_dir):
+            parser.error("{} is not a directory".format(abi_args.report_dir))
+        old_version = SimpleNamespace(
+            version="old",
+            repository=abi_args.old_repo,
+            revision=abi_args.old_rev,
+            commit=None,
+            abi_dumps={},
+            storage_tests={},
+            modules={}
+        )
+        new_version = SimpleNamespace(
+            version="new",
+            repository=abi_args.new_repo,
+            revision=abi_args.new_rev,
+            commit=None,
+            abi_dumps={},
+            storage_tests={},
+            modules={}
+        )
+        configuration = SimpleNamespace(
+            verbose=abi_args.verbose,
+            report_dir=abi_args.report_dir,
+            keep_all_reports=abi_args.keep_all_reports,
+            brief=abi_args.brief,
+            check_abi=abi_args.check_abi,
+            check_api=abi_args.check_api,
+            check_storage=abi_args.check_storage,
+            skip_file=abi_args.skip_file
+        )
+        abi_check = AbiChecker(old_version, new_version, configuration)
+        return_code = abi_check.check_for_abi_changes()
+        sys.exit(return_code)
+    except Exception: # pylint: disable=broad-except
+        # Print the backtrace and exit explicitly so as to exit with
+        # status 2, not 1.
+        traceback.print_exc()
+        sys.exit(2)
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/macro_collector.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/macro_collector.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/macro_collector.py	2025-10-01 18:30:17.259058500 +0300
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/macro_collector.py	2026-03-27 12:34:57.785157000 +0200
@@ -89,8 +89,8 @@
         self.key_usage_flags = set() #type: Set[str]
         self.hash_algorithms = set() #type: Set[str]
         self.mac_algorithms = set() #type: Set[str]
-        self.ka_algorithms = set() #type: Set[str]
-        self.kdf_algorithms = set() #type: Set[str]
+        self.key_agreement_algorithms = set() #type: Set[str]
+        self.key_derivation_algorithms = set() #type: Set[str]
         self.pake_algorithms = set() #type: Set[str]
         self.aead_algorithms = set() #type: Set[str]
         self.sign_algorithms = set() #type: Set[str]
@@ -108,6 +108,8 @@
         # type. See `is_internal_name`.
         # Always false in this class, may be set to true in derived classes.
         self.include_intermediate = False
+        # Deprecated backward compatibility alias for generate_psa_constants.py.
+        self.ka_algorithms = self.key_agreement_algorithms
 
     def is_internal_name(self, name: str) -> bool:
         """Whether this is an internal macro. Internal macros will be skipped."""
@@ -125,8 +127,8 @@
         """
         self.arguments_for['hash_alg'] = sorted(self.hash_algorithms)
         self.arguments_for['mac_alg'] = sorted(self.mac_algorithms)
-        self.arguments_for['ka_alg'] = sorted(self.ka_algorithms)
-        self.arguments_for['kdf_alg'] = sorted(self.kdf_algorithms)
+        self.arguments_for['ka_alg'] = sorted(self.key_agreement_algorithms)
+        self.arguments_for['kdf_alg'] = sorted(self.key_derivation_algorithms)
         self.arguments_for['aead_alg'] = sorted(self.aead_algorithms)
         self.arguments_for['sign_alg'] = sorted(self.sign_algorithms)
         self.arguments_for['curve'] = sorted(self.ecc_curves)
@@ -258,7 +260,7 @@
         if re.match(r'MAC(?:_|\Z)', name):
             self.mac_algorithms.add(name)
         elif re.match(r'KDF(?:_|\Z)', name):
-            self.kdf_algorithms.add(name)
+            self.key_derivation_algorithms.add(name)
         elif re.search(r'0x020000[0-9A-Fa-f]{2}', expansion):
             self.hash_algorithms.add(name)
         elif re.search(r'0x03[0-9A-Fa-f]{6}', expansion):
@@ -266,9 +268,9 @@
         elif re.search(r'0x05[0-9A-Fa-f]{6}', expansion):
             self.aead_algorithms.add(name)
         elif re.search(r'0x09[0-9A-Fa-f]{2}0000', expansion):
-            self.ka_algorithms.add(name)
+            self.key_agreement_algorithms.add(name)
         elif re.search(r'0x08[0-9A-Fa-f]{6}', expansion):
-            self.kdf_algorithms.add(name)
+            self.key_derivation_algorithms.add(name)
 
     # "#define" followed by a macro name with either no parameters
     # or a single parameter and a non-empty expansion.
@@ -281,7 +283,11 @@
 
     # Macro that is a destructor, not a constructor (i.e. takes a thing as
     # an argument and analyzes it, rather than constructing a thing).
-    _destructor_name_re = re.compile(r'.*(_GET_|_HAS_|_IS_)|.*_LENGTH\Z')
+    _destructor_name_re = re.compile('|'.join([
+        r'.*(?:_GET_|_HAS_|_IS_)',
+        r'.*_LENGTH\Z',
+        r'PSA_ALG_SIGN_SUPPORTS_CONTEXT\Z',
+    ]))
 
     # Macro that converts between things, rather than building a thing from
     # scratch.
@@ -405,12 +411,15 @@
             'cipher_algorithm': [],
             'hmac_algorithm': [self.mac_algorithms, self.sign_algorithms],
             'aead_algorithm': [self.aead_algorithms],
-            'key_derivation_algorithm': [self.kdf_algorithms],
-            'key_agreement_algorithm': [self.ka_algorithms],
+            'key_derivation_algorithm': [self.key_derivation_algorithms],
+            'key_agreement_algorithm': [self.key_agreement_algorithms],
             'asymmetric_signature_algorithm': [self.sign_algorithms],
             'asymmetric_signature_wildcard': [self.algorithms],
             'asymmetric_encryption_algorithm': [],
             'pake_algorithm': [self.pake_algorithms],
+            'key_wrap_algorithm': [],
+            'key_encapsulation_algorithm': [],
+            'xof_algorithm': [],
             'other_algorithm': [],
             'lifetime': [self.lifetimes],
         } #type: Dict[str, List[Set[str]]]
@@ -451,8 +460,8 @@
         # not likely to be assigned in the near future.
         self.hash_algorithms.add('0x020000fe') # 0x020000ff is PSA_ALG_ANY_HASH
         self.mac_algorithms.add('0x03007fff')
-        self.ka_algorithms.add('0x09fc0000')
-        self.kdf_algorithms.add('0x080000ff')
+        self.key_agreement_algorithms.add('0x09fc0000')
+        self.key_derivation_algorithms.add('0x080000ff')
         self.pake_algorithms.add('0x0a0000ff')
         # For AEAD algorithms, the only variability is over the tag length,
         # and this only applies to known algorithms, so don't test an
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/psa_storage.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/psa_storage.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/psa_storage.py	2025-10-01 18:24:20.275965700 +0300
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/psa_storage.py	2026-03-27 12:34:57.785856700 +0200
@@ -51,11 +51,13 @@
                 includes.append('drivers/builtin/include')
                 includes.append('drivers/everest/include')
                 includes.append('drivers/everest/include/tf-psa-crypto/private/')
+                includes.append('drivers/pqcp/include')
             elif not build_tree.is_mbedtls_3_6():
                 includes.append('tf-psa-crypto/include')
                 includes.append('tf-psa-crypto/drivers/builtin/include')
                 includes.append('tf-psa-crypto/drivers/everest/include')
                 includes.append('tf-psa-crypto/drivers/everest/include/tf-psa-crypto/private/')
+                includes.append('tf-psa-crypto/drivers/pqcp/include')
 
         values = c_build_helper.get_c_expression_values(
             'unsigned long', '%lu',
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/psa_test_case.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/psa_test_case.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/psa_test_case.py	2025-10-01 18:24:20.276105900 +0300
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/psa_test_case.py	2026-03-27 12:34:57.785981000 +0200
@@ -47,10 +47,15 @@
 
         acc = set() #type: Set[str]
         for filename in [
-                os.path.join(include_dir, 'psa/crypto_config.h'),
-                os.path.join(include_dir, 'psa/crypto_adjust_config_synonyms.h'),
+                'psa/crypto_config.h',
+                'psa/crypto_adjust_config_synonyms.h',
+                'tf-psa-crypto/private/crypto_adjust_config_synonyms.h',
         ]:
-            read_implemented_dependencies(acc, filename)
+            path = os.path.join(build_tree.guess_project_root(),
+                                include_dir,
+                                filename)
+            if os.path.exists(path):
+                read_implemented_dependencies(acc, path)
         _implemented_dependencies = frozenset(acc)
     return [dep
             for dep in dependencies
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/test_case.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/test_case.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/test_case.py	2025-10-01 18:24:20.276266800 +0300
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/test_case.py	2026-03-27 12:34:57.786130400 +0200
@@ -127,6 +127,18 @@
         out.write(prefix + self.function + ':' +
                   ':'.join(self.arguments) + '\n')
 
+def write_data_stream(out,
+                      test_cases: Iterable[TestCase],
+                      caller: Optional[str] = None) -> None:
+    """Write the test cases to the specified output stream."""
+    if caller is None:
+        caller = os.path.basename(sys.argv[0])
+    out.write('# Automatically generated by {}. Do not edit!\n'
+              .format(caller))
+    for tc in test_cases:
+        tc.write(out)
+    out.write('\n# End of automatically generated file.\n')
+
 def write_data_file(filename: str,
                     test_cases: Iterable[TestCase],
                     caller: Optional[str] = None) -> None:
@@ -134,15 +146,9 @@
 
     If the file already exists, it is overwritten.
     """
-    if caller is None:
-        caller = os.path.basename(sys.argv[0])
     tempfile = filename + '.new'
     with open(tempfile, 'w') as out:
-        out.write('# Automatically generated by {}. Do not edit!\n'
-                  .format(caller))
-        for tc in test_cases:
-            tc.write(out)
-        out.write('\n# End of automatically generated file.\n')
+        write_data_stream(out, test_cases, caller)
     os.replace(tempfile, filename)
 
 def psa_or_3_6_feature_macro(psa_name: str,
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/test_data_generation.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/test_data_generation.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/test_data_generation.py	2025-10-01 18:24:20.276415800 +0300
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/test_data_generation.py	2026-03-27 12:34:57.786245300 +0200
@@ -11,6 +11,7 @@
 #
 
 import argparse
+import io
 import os
 import posixpath
 import re
@@ -139,6 +140,11 @@
 
 class TestGenerator:
     """Generate test cases and write to data files."""
+
+    # Note that targets whose names contain 'test_format' have their content
+    # validated by `abi_check.py`.
+    targets = {} # type: Dict[str, Callable[..., Iterable[test_case.TestCase]]]
+
     def __init__(self, options) -> None:
         self.test_suite_directory = options.directory
         # Update `targets` with an entry for each child class of BaseTarget.
@@ -163,10 +169,6 @@
         filename = self.filename_for(basename)
         test_case.write_data_file(filename, test_cases)
 
-    # Note that targets whose names contain 'test_format' have their content
-    # validated by `abi_check.py`.
-    targets = {} # type: Dict[str, Callable[..., Iterable[test_case.TestCase]]]
-
     def generate_target(self, name: str, *target_args) -> None:
         """Generate cases and write to data file for a target.
 
@@ -176,6 +178,22 @@
         test_cases = self.targets[name](*target_args)
         self.write_test_data_file(name, test_cases)
 
+    def is_up_to_date(self, target) -> bool:
+        """Check if the given target already has the expected content."""
+        filename = self.filename_for(target)
+        if not os.path.exists(filename):
+            return False
+        test_cases = self.targets[target]()
+        out = io.StringIO()
+        test_case.write_data_stream(out, test_cases)
+        out.seek(0)
+        new_content = out.read()
+        out.close()
+        with open(filename) as current_file:
+            old_content = current_file.read()
+        return new_content == old_content
+
+
 def main(args, description: str, generator_class: Type[TestGenerator] = TestGenerator):
     """Command line entry point."""
     parser = argparse.ArgumentParser(description=description)
@@ -183,6 +201,9 @@
                         help='List available targets and exit')
     parser.add_argument('--list-for-cmake', action='store_true',
                         help='Print \';\'-separated list of available targets and exit')
+    parser.add_argument('--list-outdated', action='store_true',
+                        help=('List outdated targets and exit '
+                              '(succeeds even if there are outdated or missing targets)'))
     # If specified explicitly, this option may be a path relative to the
     # current directory when the script is invoked. The default value
     # is relative to the mbedtls root, which we don't know yet. So we
@@ -221,4 +242,8 @@
     else:
         options.targets = sorted(generator.targets)
     for target in options.targets:
-        generator.generate_target(target)
+        if options.list_outdated:
+            if not generator.is_up_to_date(target):
+                print(generator.filename_for(target))
+        else:
+            generator.generate_target(target)
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/test_driver.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/test_driver.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/test_driver.py	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/test_driver.py	2026-03-27 12:34:57.786399400 +0200
@@ -0,0 +1,341 @@
+"""Library for building a TF-PSA-Crypto test driver from the built-in driver
+"""
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+#
+
+import argparse
+import re
+import shutil
+import subprocess
+
+from fnmatch import fnmatch
+from pathlib import Path
+from typing import Iterable, List, Match, Optional, Set
+
+def get_parsearg_base() -> argparse.ArgumentParser:
+    """ Get base arguments for scripts generating a TF-PSA-Crypto test driver """
+    parser = argparse.ArgumentParser(description="""\
+        Clone the built-in driver tree, rewrite header inclusions and prefix
+        exposed C identifiers.
+        """)
+
+    parser.add_argument("dst_dir", metavar="DST_DIR",
+                        help="Destination directory (relative to repository root)")
+    parser.add_argument("--driver", default="libtestdriver1", metavar="DRIVER",
+                        help="Test driver name (default: %(default)s).")
+    parser.add_argument('--list-vars-for-cmake', nargs="?", \
+                        const="__AUTO__", metavar="FILE",
+                        help="""
+        Generate a file to be included from a CMakeLists.txt and exit. The file
+        defines CMake list variables with the script's inputs/outputs files. If
+        FILE is omitted, the output name defaults to '<DRIVER>-list-vars.cmake'.
+        """)
+    return parser
+
+class TestDriverGenerator:
+    """A TF-PSA-Crypto test driver generator"""
+    def __init__(self, src_dir: Path, dst_dir: Path, driver: str, \
+                 exclude_files: Optional[Iterable[str]] = None) -> None:
+        """
+        Initialize a test driver generator.
+
+        Args:
+            src_dir (Path):
+                Path to the source directory that contains the built-in driver.
+                If this path is relative, it should be relative to the repository
+                root so that the source paths returned by `write_list_vars_for_cmake`
+                are correct.
+
+                The source directory is expected to contain:
+                - an `include` directory
+                - an `src` directory
+
+            dst_dir (Path):
+                Path to the destination directory where the rewritten tree will
+                be created. If the directory already exists, only the `include`
+                and `src` subdirectories are modified.
+
+            driver (str):
+                Name of the driver. This is used as a prefix when rewritting
+                the tree.
+
+            exclude_files (Optional[Iterable[str]]):
+                Glob patterns for the basename of the files to be excluded from
+                the source directory.
+        """
+        self.src_dir = src_dir
+        self.dst_dir = dst_dir
+        self.driver = driver
+        self.exclude_files = [] if exclude_files is None else list(exclude_files)
+
+        if not (src_dir / "include").is_dir():
+            raise RuntimeError(f'"include" directory in {src_dir} not found')
+
+        if not (src_dir / "src").is_dir():
+            raise RuntimeError(f'"src" directory in {src_dir} not found')
+
+    def write_list_vars_for_cmake(self, fname: str) -> None:
+        src_relpaths = self.__get_src_code_files()
+        with open(self.dst_dir / fname, "w") as f:
+            f.write(f"set({self.driver}_input_files\n    " + \
+                     "\n    ".join(f'"{path}"' for path in src_relpaths) + "\n)\n\n")
+            f.write(f"set({self.driver}_files\n    " + \
+                    "\n    ".join(f'"{self.__get_dst_relpath(path.relative_to(self.src_dir))}"' \
+                     for path in src_relpaths) + "\n)\n\n")
+            f.write(f"set({self.driver}_src_files\n    " + \
+                    "\n    ".join(f'"{self.__get_dst_relpath(path.relative_to(self.src_dir))}"' \
+                    for path in src_relpaths if path.suffix == ".c") + "\n)\n")
+
+    def get_identifiers_to_prefix(self, prefixes: Set[str]) -> Set[str]:
+        """
+        Get the set of identifiers that will be prefixed in the test driver code.
+
+        This method is intended to be amended by subclasses in consuming branches.
+
+        The default implementation returns the complete set of identifiers from
+        the built-in driver whose names begin with any of the `prefixes`. These
+        are the identifiers that could be renamed in the test driver before
+        adaptation.
+
+        Subclasses need to filter, transform, or otherwise adjust the set of
+        identifiers that should be renamed when generating the test driver.
+
+        Args:
+             prefixes (Set[str]):
+                 The set of identifier prefixes used by the built-in driver
+                 for the symbols it exposes to the other parts of the crypto
+                 library. All identifiers beginning with any of these
+                 prefixes are candidates for renaming in the test driver to
+                 avoid symbol clashes.
+
+        Returns:
+            Set[str]: The default set of identifiers to rename.
+        """
+        identifiers = set()
+        for file in self.__get_src_code_files():
+            identifiers.update(self.get_c_identifiers(file))
+
+        identifiers_with_prefixes = set()
+        for identifier in identifiers:
+            if any(identifier.startswith(prefix) for prefix in prefixes):
+                identifiers_with_prefixes.add(identifier)
+        return identifiers_with_prefixes
+
+    def create_test_driver_tree(self, prefixes: Set[str]) -> None:
+        """
+        Create a test driver tree from `self.src_dir` into `self.dst_dir`.
+
+        Only the `include/` and `src/` subdirectories of the source tree are
+        used, and their internal directory structure is preserved.
+
+        Only "*.h" and "*.c" files are copied. Files whose basenames match any
+        of the glob patterns in `self.exclude_files` are excluded.
+
+        The basename of all files is prefixed with `{self.driver}-`. The
+        header inclusions referencing the renamed headers are rewritten
+        accordingly.
+
+        Symbol identifiers exposed by the built-in driver are renamed by
+        prefixing them with `{self.driver}_` to avoid collisions when linking the
+        built-in driver and the test driver together in the crypto library.
+
+        Args:
+             prefixes (Set[str]):
+                 The set of identifier prefixes used by the built-in driver
+                 for the symbols it exposes to the other parts of the crypto
+                 library. All identifiers beginning with any of these
+                 prefixes are candidates for renaming in the test driver to
+                 avoid symbol clashes.
+        """
+        if (self.dst_dir / "include").exists():
+            shutil.rmtree(self.dst_dir / "include")
+
+        if (self.dst_dir / "src").exists():
+            shutil.rmtree(self.dst_dir / "src")
+
+        headers = {
+            f.name \
+            for f in self.__get_src_code_files() if f.suffix == ".h"
+        }
+        identifiers_to_prefix = self.get_identifiers_to_prefix(prefixes)
+
+        # Create the test driver tree
+        for file in self.__get_src_code_files():
+            dst = self.dst_dir / \
+                  self.__get_dst_relpath(file.relative_to(self.src_dir))
+            dst.parent.mkdir(parents=True, exist_ok=True)
+            self.__write_test_driver_file(file, dst, headers,\
+                                          identifiers_to_prefix)
+
+    @staticmethod
+    def __get_code_files(root: Path) -> List[Path]:
+        """
+        Return all "*.c" and "*.h" files found recursively under the
+        `include` and `src` subdirectories of `root`.
+        """
+        return sorted(path
+                      for directory in ('include', 'src')
+                      for path in (root / directory).rglob('*.[hc]'))
+
+    def __get_src_code_files(self) -> List[Path]:
+        """
+        Return all "*.c" and "*.h" files found recursively under the
+        `include` and `src` subdirectories of the source directory `self.src_dir`
+        excluding the files whose basename match any of the patterns in
+        `self.exclude_files`.
+        """
+        out = []
+        for file in self.__get_code_files(self.src_dir):
+            if not any(fnmatch(file.name, pattern) for pattern in self.exclude_files):
+                out.append(file)
+        return out
+
+    def __get_dst_relpath(self, src_relpath: Path) -> Path:
+        """
+        Return the path relative to `dst_dir` of the file that corresponds to the
+        file with relative path `src_relpath` in the source tree.
+
+        Same as `src_relpath` but the basename prefixed with `self.driver`
+        """
+        assert not src_relpath.is_absolute(), "src_relpath must be relative"
+
+        return src_relpath.parent / (self.driver + '-' + src_relpath.name)
+
+    @staticmethod
+    def get_c_identifiers(file: Path) -> Set[str]:
+        """
+        Extract the C identifiers present in `file` using `ctags -x`
+
+        The following C symbol kinds are included (with their `--c-kinds`
+        flags in parentheses):
+
+          - macro definitions (d)
+          - enum values (e)
+          - functions (f)
+          - enum tags (g)
+          - function prototypes (p)
+          - struct tags (s)
+          - typedefs (t)
+          - union tags (u)
+          - global variables (v)
+
+        Compatibility
+        -------------
+        The command used here has been validated with the following `ctags`
+        implementations:
+          - Exuberant Ctags 5.8
+          - Exuberant Ctags 5.9~svn20110310 (default on Ubuntu 16.04–24.04)
+          - Universal Ctags 5.9.0 (Ubuntu 24.04)
+          - Universal Ctags 6.2.0 (Ubuntu 26.04)
+
+        All of these versions support the options `-x`, `--language-force=C`,
+        and ``--c-kinds=defgpstuv`` sufficiently for the use case here.
+
+        Returns:
+            Set[str]: The set of identifiers found in `file`.
+        """
+        output = subprocess.check_output(
+            ["ctags", "-x", "--language-force=C", "--c-kinds=defgpstuv", str(file)],
+            stderr=subprocess.STDOUT,
+            universal_newlines=True,
+        )
+        identifiers = set()
+        for line in output.splitlines():
+            identifiers.add(line.split()[0])
+
+        return identifiers
+
+    def __write_test_driver_file(self, src: Path, dst: Path,
+                                 headers: Set[str],
+                                 identifiers_to_prefix: Set[str]) -> None:
+        """
+        Write a test driver file to `dst` based on the contents of `src` with
+        two transformations: rewriting of `#include` directives and identifier
+        renaming.
+
+        1. Rewrite header inclusions
+           Any `#include` directive whose header basename matches an entry of
+           `headers` is rewritten so that the basename is prefixed with
+           `{self.driver}-`. Directory components (if any) are preserved.
+
+           Example:
+               #include "mbedtls/private/aes.h"
+               becomes
+               #include "mbedtls/private/libtestdriver1-aes.h"
+
+           LIMITATION:
+               The current implementation does not correctly handle the case
+               where a built-in header and a non–built-in header share the same
+               basename. In principle, only inclusions of built-in headers
+               should be rewritten, while inclusions of non–built-in headers
+               should be left unchanged. However, the current logic only matches
+               on the basename, so both are rewritten.
+
+               For example, if both `include/psa/foo.h` (non–built-in) and
+               `drivers/builtin/include/mbedtls/foo.h` (built-in) exist, then
+               in the test driver:
+
+               - `#include <psa/foo.h>` should not be rewritten
+               - `#include <mbedtls/foo.h>` should be rewritten to
+                 `#include <mbedtls/libtestdriver1-foo.h>`
+
+               With the current basename-only matching, both inclusions are
+               rewritten, which is incorrect. No practical implications
+               currently, such same header basename case does not occur in the
+               code base.
+
+        2. Rename selected identifiers
+           Each identifier in `identifiers_to_prefix` is prefixed with
+           `self.driver`. Case is preserved: if the identifier is all-uppercase,
+           then the uppercase form of `driver` is used, the lowercase form
+           otherwise.
+
+           Examples:
+               `MBEDTLS_AES_C` becomes `LIBTESTDRIVER1_MBEDTLS_AES_C`
+               `mbedtls_sha256_init` becomes `libtestdriver1_mbedtls_sha256_init`
+
+        Args:
+            src (Path):
+                The source file to read.
+
+            dst (Path):
+                The destination file where the rewritten version is written.
+
+            headers (Set[str]):
+                Basenames of headers whose includes should be rewritten.
+
+            identifiers_to_prefix (Set[str]):
+                Identifiers that must be renamed by prefixing with `self.driver`
+                (using uppercase or lowercase depending on the identifier's casing).
+        """
+        text = src.read_text(encoding="utf-8")
+
+        include_line_re = re.compile(
+            fr'^(\s*#\s*include\s*[<"])([^>"]+)([>"])',
+            re.MULTILINE
+        )
+        def repl_header_inclusion(m: Match) -> str:
+            parts = m.group(2).split("/")
+            if parts[-1] in headers:
+                path = "/".join(parts[:-1] + [self.driver + "-" + parts[-1]])
+                return f'{m.group(1)}{path}{m.group(3)}'
+            return m.group(0)
+        intermediate_text = include_line_re.sub(repl_header_inclusion, text)
+
+        c_identifier_re = re.compile(r"\b[A-Za-z_][A-Za-z0-9_]*\b")
+        prefix_uppercased = self.driver.upper()
+        prefix_lowercased = self.driver.lower()
+
+        def repl(m: Match) -> str:
+            identifier = m.group(0)
+            if identifier in identifiers_to_prefix:
+                if identifier[0].isupper():
+                    return f"{prefix_uppercased}_{identifier}"
+                else:
+                    return f"{prefix_lowercased}_{identifier}"
+            return identifier
+
+        new_text = c_identifier_re.sub(repl, intermediate_text)
+        dst.write_text(new_text, encoding="utf-8")
diff -Nru mbedtls-3.6.5/framework/scripts/mbedtls_framework/tls_handshake_tests.py mbedtls-3.6.6/framework/scripts/mbedtls_framework/tls_handshake_tests.py
--- mbedtls-3.6.5/framework/scripts/mbedtls_framework/tls_handshake_tests.py	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/scripts/mbedtls_framework/tls_handshake_tests.py	2026-03-27 12:34:57.786492800 +0200
@@ -0,0 +1,228 @@
+"""
+Generate miscellaneous TLS test cases relating to the handshake.
+"""
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+import argparse
+import os
+import sys
+from typing import Optional
+
+from mbedtls_framework import tls_test_case
+from mbedtls_framework import typing_util
+from mbedtls_framework.tls_test_case import Side, Version
+import translate_ciphers
+
+
+# Assume that a TLS 1.2 ClientHello used in these tests will be at most
+# this many bytes long.
+TLS12_CLIENT_HELLO_ASSUMED_MAX_LENGTH = 255
+
+# Minimum handshake fragment length that Mbed TLS supports.
+TLS_HANDSHAKE_FRAGMENT_MIN_LENGTH = 4
+
+def write_tls_handshake_defragmentation_test(
+        #pylint: disable=too-many-arguments
+        out: typing_util.Writable,
+        side: Side,
+        length: Optional[int],
+        version: Optional[Version] = None,
+        cipher: Optional[str] = None,
+        etm: Optional[bool] = None, #encrypt-then-mac (only relevant for CBC)
+        tls12_client_hello_defragmentation: Optional[bool] = True,
+        variant: str = ''
+) -> None:
+    """Generate one TLS handshake defragmentation test.
+
+    :param out: file to write to.
+    :param side: which side is Mbed TLS.
+    :param length: fragment length, or None to not fragment.
+    :param version: protocol version, if forced.
+    """
+    #pylint: disable=chained-comparison,too-many-branches,too-many-statements
+
+    our_args = ''
+    their_args = ''
+
+    if length is None:
+        description = 'no fragmentation, for reference'
+    else:
+        description = 'len=' + str(length)
+    if version is not None:
+        description += ', TLS 1.' + str(version.value)
+    description = f'Handshake defragmentation on {side.name.lower()}: {description}'
+    tc = tls_test_case.TestCase(description)
+
+    if version is not None:
+        their_args += ' ' + version.openssl_option()
+        # Emit a version requirement, because we're forcing the version via
+        # OpenSSL, not via Mbed TLS, and the automatic depdendencies in
+        # ssl-opt.sh only handle forcing the version via Mbed TLS.
+        tc.requirements.append(version.requires_command())
+        if side == Side.SERVER and version == Version.TLS12 and \
+           length is not None and \
+           length <= TLS12_CLIENT_HELLO_ASSUMED_MAX_LENGTH and \
+           not tls12_client_hello_defragmentation:
+            # If Server-side ClientHello defragmentation is only supported in
+            # the TLS 1.3 message parser, not in the TLS 1.2 message parser,
+            # a TLS 1.2 fragmented ClientHello is handled properly only if it
+            # is first reassembled by the TLS 1.3 parser before to be passed to
+            # the TLS 1.2 ClientHello parser in a TLS 1.3 or TLS 1.2 version
+            # negotiation scenario.
+            # When TLS 1.3 support is disabled in the server (at compile-time
+            # or at runtime), the TLS 1.2 ClientHello parser only sees
+            # the first fragment of a fragmented ClientHello.
+            tc.requirements.append('requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3')
+            tc.description += ' with 1.3 support'
+
+    # To guarantee that the handhake messages are large enough and need to be
+    # split into fragments, the tests require certificate authentication.
+    # The party in control of the fragmentation operations is OpenSSL and
+    # will always use server5.crt (548 Bytes).
+    if length is not None and \
+       length >= TLS_HANDSHAKE_FRAGMENT_MIN_LENGTH:
+        tc.requirements.append('requires_certificate_authentication')
+        if version == Version.TLS12 and side == Side.CLIENT:
+            #The server uses an ECDSA cert, so make sure we have a compatible key exchange
+            tc.requirements.append(
+                'requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED')
+    else:
+        # This test case may run in a pure-PSK configuration. OpenSSL doesn't
+        # allow this by default with TLS 1.3.
+        their_args += ' -allow_no_dhe_kex'
+
+    if length is None:
+        forbidden_patterns = [
+            'waiting for more fragments',
+        ]
+        wanted_patterns = []
+    elif length < TLS_HANDSHAKE_FRAGMENT_MIN_LENGTH:
+        their_args += ' -split_send_frag ' + str(length)
+        tc.exit_code = 1
+        forbidden_patterns = []
+        wanted_patterns = [
+            'handshake message too short: ' + str(length),
+            'SSL - An invalid SSL record was received',
+        ]
+        if side == Side.SERVER:
+            wanted_patterns[0:0] = ['=> parse client hello']
+        elif version == Version.TLS13:
+            wanted_patterns[0:0] = ['=> ssl_tls13_process_server_hello']
+    else:
+        their_args += ' -split_send_frag ' + str(length)
+        forbidden_patterns = []
+        wanted_patterns = [
+            'reassembled record',
+            fr'initial handshake fragment: {length}, 0\.\.{length} of [0-9]\+',
+            fr'subsequent handshake fragment: [0-9]\+, {length}\.\.',
+            fr'Prepare: waiting for more handshake fragments {length}/',
+            fr'Consume: waiting for more handshake fragments {length}/',
+        ]
+
+    if cipher is not None:
+        mbedtls_cipher = translate_ciphers.translate_mbedtls(cipher)
+        if side == Side.CLIENT:
+            our_args += ' force_ciphersuite=' + mbedtls_cipher
+            if 'NULL' in cipher:
+                their_args += ' -cipher ALL@SECLEVEL=0:COMPLEMENTOFALL@SECLEVEL=0'
+        else:
+            # For TLS 1.2, when Mbed TLS is the server, we must force the
+            # cipher suite on the client side, because passing
+            # force_ciphersuite to ssl_server2 would force a TLS-1.2-only
+            # server, which does not support a fragmented ClientHello.
+            tc.requirements.append('requires_ciphersuite_enabled ' + mbedtls_cipher)
+            their_args += ' -cipher ' + translate_ciphers.translate_ossl(cipher)
+            if 'NULL' in cipher:
+                their_args += '@SECLEVEL=0'
+
+    if etm is not None:
+        if etm:
+            tc.requirements.append('requires_config_enabled MBEDTLS_SSL_ENCRYPT_THEN_MAC')
+        our_args += ' etm=' + str(int(etm))
+        (wanted_patterns if etm else forbidden_patterns)[0:0] = [
+            'using encrypt then mac',
+        ]
+
+    tc.description += variant
+
+    if side == Side.CLIENT:
+        tc.client = '$P_CLI debug_level=4' + our_args
+        tc.server = '$O_NEXT_SRV' + their_args
+        tc.wanted_client_patterns = wanted_patterns
+        tc.forbidden_client_patterns = forbidden_patterns
+    else:
+        their_args += ' -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key'
+        our_args += ' auth_mode=required'
+        tc.client = '$O_NEXT_CLI' + their_args
+        tc.server = '$P_SRV debug_level=4' + our_args
+        tc.wanted_server_patterns = wanted_patterns
+        tc.forbidden_server_patterns = forbidden_patterns
+    tc.write(out)
+
+
+CIPHERS_FOR_TLS12_HANDSHAKE_DEFRAGMENTATION = [
+    (None, 'default', None),
+    ('TLS_ECDHE_ECDSA_WITH_NULL_SHA', 'null', None),
+    ('TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256', 'ChachaPoly', None),
+    ('TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256', 'GCM', None),
+    ('TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256', 'CBC, etm=n', False),
+    ('TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256', 'CBC, etm=y', True),
+]
+
+def write_tls_handshake_defragmentation_tests(args, out: typing_util.Writable) -> None:
+    """Generate TLS handshake defragmentation tests."""
+    for side in Side.CLIENT, Side.SERVER:
+        write_tls_handshake_defragmentation_test(out, side, None)
+        for length in [512, 513, 256, 128, 64, 36, 32, 16, 13, 5, 4, 3]:
+            write_tls_handshake_defragmentation_test(out, side, length,
+                                                     Version.TLS13)
+            if length == 4:
+                for (cipher_suite, nickname, etm) in \
+                        CIPHERS_FOR_TLS12_HANDSHAKE_DEFRAGMENTATION:
+                    write_tls_handshake_defragmentation_test(
+                        out, side, length, Version.TLS12,
+                        cipher=cipher_suite, etm=etm,
+                        variant=', '+nickname,
+                        tls12_client_hello_defragmentation= \
+                            args.tls12_client_hello_defragmentation)
+            else:
+                write_tls_handshake_defragmentation_test(
+                    out, side, length, Version.TLS12,
+                    tls12_client_hello_defragmentation=
+                    args.tls12_client_hello_defragmentation)
+
+
+def write_handshake_tests(args, out: typing_util.Writable) -> None:
+    """Generate handshake tests."""
+    out.write(f"""\
+# Miscellaneous tests related to the TLS handshake layer.
+#
+# Automatically generated by {os.path.basename(sys.argv[0])}. Do not edit!
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+""")
+    write_tls_handshake_defragmentation_tests(args, out)
+    out.write("""\
+# End of automatically generated file.
+""")
+
+def main() -> None:
+    """Command line entry point."""
+    parser = argparse.ArgumentParser()
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument('-o', '--output',
+                        default='tests/opt-testcases/handshake-generated.sh',
+                        help='Output file (default: tests/opt-testcases/handshake-generated.sh)')
+    parser.add_argument('--no-tls12-client-hello-defragmentation-support',
+                        action="store_false",
+                        dest="tls12_client_hello_defragmentation",
+                        help="Whether the TLS 1.2 ClientHello defragmentation is "
+                             "fully supported or not (default: True)")
+    args = parser.parse_args()
+
+    with open(args.output, 'w') as out:
+        write_handshake_tests(args, out)
diff -Nru mbedtls-3.6.5/framework/scripts/output_env.sh mbedtls-3.6.6/framework/scripts/output_env.sh
--- mbedtls-3.6.5/framework/scripts/output_env.sh	2025-10-01 18:24:20.276897000 +0300
+++ mbedtls-3.6.6/framework/scripts/output_env.sh	2026-03-27 12:34:57.786849000 +0200
@@ -126,6 +126,9 @@
 print_version "valgrind" "--version" ""
 echo
 
+print_version "ctags" "--version" "" "head -n 1"
+echo
+
 print_version "gdb" "--version" "" "head -n 1"
 echo
 
diff -Nru mbedtls-3.6.5/framework/scripts/run_demos.py mbedtls-3.6.6/framework/scripts/run_demos.py
--- mbedtls-3.6.5/framework/scripts/run_demos.py	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/scripts/run_demos.py	2026-03-27 12:34:57.787755300 +0200
@@ -0,0 +1,65 @@
+#!/usr/bin/env python3
+"""Run the Mbed TLS demo scripts.
+"""
+import argparse
+import glob
+import subprocess
+import sys
+
+def run_demo(demo, quiet=False):
+    """Run the specified demo script. Return True if it succeeds."""
+    args = {}
+    if quiet:
+        args['stdout'] = subprocess.DEVNULL
+        args['stderr'] = subprocess.DEVNULL
+    returncode = subprocess.call([demo], **args)
+    return returncode == 0
+
+def run_demos(demos, quiet=False):
+    """Run the specified demos and print summary information about failures.
+
+    Return True if all demos passed and False if a demo fails.
+    """
+    failures = []
+    for demo in demos:
+        if not quiet:
+            print('#### {} ####'.format(demo))
+        success = run_demo(demo, quiet=quiet)
+        if not success:
+            failures.append(demo)
+            if not quiet:
+                print('{}: FAIL'.format(demo))
+        if quiet:
+            print('{}: {}'.format(demo, 'PASS' if success else 'FAIL'))
+        else:
+            print('')
+    successes = len(demos) - len(failures)
+    print('{}/{} demos passed'.format(successes, len(demos)))
+    if failures and not quiet:
+        print('Failures:', *failures)
+    return not failures
+
+def run_all_demos(quiet=False):
+    """Run all the available demos.
+
+    Return True if all demos passed and False if a demo fails.
+    """
+    mbedtls_demos = glob.glob('programs/*/*_demo.sh')
+    tf_psa_crypto_demos = glob.glob('tf-psa-crypto/programs/*/*_demo.sh')
+    all_demos = mbedtls_demos + tf_psa_crypto_demos
+    if not all_demos:
+        # Keep the message on one line. pylint: disable=line-too-long
+        raise Exception('No demos found. run_demos needs to operate from the Mbed TLS toplevel directory.')
+    return run_demos(all_demos, quiet=quiet)
+
+def main():
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument('--quiet', '-q',
+                        action='store_true',
+                        help="suppress the output of demos")
+    options = parser.parse_args()
+    success = run_all_demos(quiet=options.quiet)
+    sys.exit(0 if success else 1)
+
+if __name__ == '__main__':
+    main()
diff -Nru mbedtls-3.6.5/framework/scripts/run-metatests.sh mbedtls-3.6.6/framework/scripts/run-metatests.sh
--- mbedtls-3.6.5/framework/scripts/run-metatests.sh	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/scripts/run-metatests.sh	2026-03-27 12:34:57.787688700 +0200
@@ -0,0 +1,89 @@
+#!/bin/sh
+
+help () {
+    cat <<EOF
+Usage: $0 [OPTION] [PLATFORM]...
+Run all the metatests whose platform matches any of the given PLATFORM.
+A PLATFORM can contain shell wildcards.
+
+Expected output: a lot of scary-looking error messages, since each
+metatest is expected to report a failure. The final line should be
+"Ran N metatests, all good."
+
+If something goes wrong: the final line should be
+"Ran N metatests, X unexpected successes". Look for "Unexpected success"
+in the logs above.
+
+  -l  List the available metatests, don't run them.
+EOF
+}
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+set -e -u
+
+if [ -d programs ]; then
+    METATEST_PROGRAM=programs/test/metatest
+elif [ -d ../programs ]; then
+    METATEST_PROGRAM=../programs/test/metatest
+elif [ -d ../../programs ]; then
+    METATEST_PROGRAM=../../programs/test/metatest
+else
+    echo >&2 "$0: FATAL: programs/test/metatest not found"
+    exit 120
+fi
+
+LIST_ONLY=
+while getopts hl OPTLET; do
+    case $OPTLET in
+        h) help; exit;;
+        l) LIST_ONLY=1;;
+        \?) help >&2; exit 120;;
+    esac
+done
+shift $((OPTIND - 1))
+
+list_matches () {
+    while read name platform junk; do
+        for pattern in "$@"; do
+            case $platform in
+                $pattern) echo "$name"; break;;
+            esac
+        done
+    done
+}
+
+count=0
+errors=0
+run_metatest () {
+    ret=0
+    "$METATEST_PROGRAM" "$1" || ret=$?
+    if [ $ret -eq 0 ]; then
+        echo >&2 "$0: Unexpected success: $1"
+        errors=$((errors + 1))
+    fi
+    count=$((count + 1))
+}
+
+# Don't pipe the output of metatest so that if it fails, this script exits
+# immediately with a failure status.
+full_list=$("$METATEST_PROGRAM" list)
+matching_list=$(printf '%s\n' "$full_list" | list_matches "$@")
+
+if [ -n "$LIST_ONLY" ]; then
+    printf '%s\n' $matching_list
+    exit
+fi
+
+for name in $matching_list; do
+    run_metatest "$name"
+done
+
+if [ $errors -eq 0 ]; then
+    echo "Ran $count metatests, all good."
+    exit 0
+else
+    echo "Ran $count metatests, $errors unexpected successes."
+    exit 1
+fi
diff -Nru mbedtls-3.6.5/framework/scripts/test_config_script.py mbedtls-3.6.6/framework/scripts/test_config_script.py
--- mbedtls-3.6.5/framework/scripts/test_config_script.py	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/scripts/test_config_script.py	2026-03-27 12:34:57.788095000 +0200
@@ -0,0 +1,175 @@
+#!/usr/bin/env python3
+
+"""Test helper for the Mbed TLS configuration file tool
+
+Run config.py with various parameters and write the results to files.
+
+This is a harness to help regression testing, not a functional tester.
+Sample usage:
+
+    test_config_script.py -d old
+    ## Modify config.py and/or mbedtls_config.h ##
+    test_config_script.py -d new
+    diff -ru old new
+"""
+
+## Copyright The Mbed TLS Contributors
+## SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+##
+
+import argparse
+import glob
+import os
+import re
+import shutil
+import subprocess
+
+OUTPUT_FILE_PREFIX = 'config-'
+
+def output_file_name(directory, stem, extension):
+    return os.path.join(directory,
+                        '{}{}.{}'.format(OUTPUT_FILE_PREFIX,
+                                         stem, extension))
+
+def cleanup_directory(directory):
+    """Remove old output files."""
+    for extension in []:
+        pattern = output_file_name(directory, '*', extension)
+        filenames = glob.glob(pattern)
+        for filename in filenames:
+            os.remove(filename)
+
+def prepare_directory(directory):
+    """Create the output directory if it doesn't exist yet.
+
+    If there are old output files, remove them.
+    """
+    if os.path.exists(directory):
+        cleanup_directory(directory)
+    else:
+        os.makedirs(directory)
+
+def guess_presets_from_help(help_text):
+    """Figure out what presets the script supports.
+
+    help_text should be the output from running the script with --help.
+    """
+    # Try the output format from config.py
+    hits = re.findall(r'\{([-\w,]+)\}', help_text)
+    for hit in hits:
+        words = set(hit.split(','))
+        if 'get' in words and 'set' in words and 'unset' in words:
+            words.remove('get')
+            words.remove('set')
+            words.remove('unset')
+            return words
+    # Try the output format from config.pl
+    hits = re.findall(r'\n +([-\w]+) +- ', help_text)
+    if hits:
+        return hits
+    raise Exception("Unable to figure out supported presets. Pass the '-p' option.")
+
+def list_presets(options):
+    """Return the list of presets to test.
+
+    The list is taken from the command line if present, otherwise it is
+    extracted from running the config script with --help.
+    """
+    if options.presets:
+        return re.split(r'[ ,]+', options.presets)
+    else:
+        help_text = subprocess.run([options.script, '--help'],
+                                   check=False, # config.pl --help returns 255
+                                   stdout=subprocess.PIPE,
+                                   stderr=subprocess.STDOUT).stdout
+        return guess_presets_from_help(help_text.decode('ascii'))
+
+def run_one(options, args, stem_prefix='', input_file=None):
+    """Run the config script with the given arguments.
+
+    Take the original content from input_file if specified, defaulting
+    to options.input_file if input_file is None.
+
+    Write the following files, where xxx contains stem_prefix followed by
+    a filename-friendly encoding of args:
+    * config-xxx.h: modified file.
+    * config-xxx.out: standard output.
+    * config-xxx.err: standard output.
+    * config-xxx.status: exit code.
+
+    Return ("xxx+", "path/to/config-xxx.h") which can be used as
+    stem_prefix and input_file to call this function again with new args.
+    """
+    if input_file is None:
+        input_file = options.input_file
+    stem = stem_prefix + '-'.join(args)
+    data_filename = output_file_name(options.output_directory, stem, 'h')
+    stdout_filename = output_file_name(options.output_directory, stem, 'out')
+    stderr_filename = output_file_name(options.output_directory, stem, 'err')
+    status_filename = output_file_name(options.output_directory, stem, 'status')
+    shutil.copy(input_file, data_filename)
+    # Pass only the file basename, not the full path, to avoid getting the
+    # directory name in error messages, which would make comparisons
+    # between output directories more difficult.
+    cmd = [os.path.abspath(options.script),
+           '-f', os.path.basename(data_filename)]
+    with open(stdout_filename, 'wb') as out:
+        with open(stderr_filename, 'wb') as err:
+            status = subprocess.call(cmd + args,
+                                     cwd=options.output_directory,
+                                     stdin=subprocess.DEVNULL,
+                                     stdout=out, stderr=err)
+    with open(status_filename, 'w') as status_file:
+        status_file.write('{}\n'.format(status))
+    return stem + "+", data_filename
+
+### A list of symbols to test with.
+### This script currently tests what happens when you change a symbol from
+### having a value to not having a value or vice versa. This is not
+### necessarily useful behavior, and we may not consider it a bug if
+### config.py stops handling that case correctly.
+TEST_SYMBOLS = [
+    'CUSTOM_SYMBOL', # does not exist
+    'PSA_WANT_KEY_TYPE_AES', # set, no value
+    'MBEDTLS_MPI_MAX_SIZE', # unset, has a value
+    'MBEDTLS_NO_UDBL_DIVISION', # unset, in "System support"
+    'MBEDTLS_PLATFORM_ZEROIZE_ALT', # unset, in "Customisation configuration options"
+]
+
+def run_all(options):
+    """Run all the command lines to test."""
+    presets = list_presets(options)
+    for preset in presets:
+        run_one(options, [preset])
+    for symbol in TEST_SYMBOLS:
+        run_one(options, ['get', symbol])
+        (stem, filename) = run_one(options, ['set', symbol])
+        run_one(options, ['get', symbol], stem_prefix=stem, input_file=filename)
+        run_one(options, ['--force', 'set', symbol])
+        (stem, filename) = run_one(options, ['set', symbol, 'value'])
+        run_one(options, ['get', symbol], stem_prefix=stem, input_file=filename)
+        run_one(options, ['--force', 'set', symbol, 'value'])
+        run_one(options, ['unset', symbol])
+
+def main():
+    """Command line entry point."""
+    parser = argparse.ArgumentParser(description=__doc__,
+                                     formatter_class=argparse.RawDescriptionHelpFormatter)
+    parser.add_argument('-d', metavar='DIR',
+                        dest='output_directory', required=True,
+                        help="""Output directory.""")
+    parser.add_argument('-f', metavar='FILE',
+                        dest='input_file', default='include/mbedtls/mbedtls_config.h',
+                        help="""Config file (default: %(default)s).""")
+    parser.add_argument('-p', metavar='PRESET,...',
+                        dest='presets',
+                        help="""Presets to test (default: guessed from --help).""")
+    parser.add_argument('-s', metavar='FILE',
+                        dest='script', default='scripts/config.py',
+                        help="""Configuration script (default: %(default)s).""")
+    options = parser.parse_args()
+    prepare_directory(options.output_directory)
+    run_all(options)
+
+if __name__ == '__main__':
+    main()
diff -Nru mbedtls-3.6.5/framework/scripts/test_psa_constant_names.py mbedtls-3.6.6/framework/scripts/test_psa_constant_names.py
--- mbedtls-3.6.5/framework/scripts/test_psa_constant_names.py	2025-10-01 18:24:20.278531000 +0300
+++ mbedtls-3.6.6/framework/scripts/test_psa_constant_names.py	2026-03-27 12:34:57.788516500 +0200
@@ -175,6 +175,7 @@
                                                       'tf-psa-crypto/drivers/everest/include',
                                                       'tf-psa-crypto/drivers/everest/include/' +
                                                       'tf-psa-crypto/private',
+                                                      'tf-psa-crypto/drivers/pqcp/include',
                                                       'include'],
                             help='Directory for header files')
     parser.add_argument('--keep-c',
diff -Nru mbedtls-3.6.5/framework/tests/include/test/arguments.h mbedtls-3.6.6/framework/tests/include/test/arguments.h
--- mbedtls-3.6.5/framework/tests/include/test/arguments.h	2025-10-01 18:24:20.280033000 +0300
+++ mbedtls-3.6.6/framework/tests/include/test/arguments.h	2026-03-27 12:34:57.789934600 +0200
@@ -14,7 +14,7 @@
 #ifndef TEST_ARGUMENTS_H
 #define TEST_ARGUMENTS_H
 
-#include "mbedtls/build_info.h"
+#include "build_info.h"
 #include <stdint.h>
 #include <stdlib.h>
 
diff -Nru mbedtls-3.6.5/framework/tests/include/test/asn1_helpers.h mbedtls-3.6.6/framework/tests/include/test/asn1_helpers.h
--- mbedtls-3.6.5/framework/tests/include/test/asn1_helpers.h	2025-10-01 18:24:20.280132500 +0300
+++ mbedtls-3.6.6/framework/tests/include/test/asn1_helpers.h	2026-03-27 12:34:57.790014300 +0200
@@ -8,6 +8,7 @@
 #ifndef ASN1_HELPERS_H
 #define ASN1_HELPERS_H
 
+#include "build_info.h"
 #include "test/helpers.h"
 
 /** Skip past an INTEGER in an ASN.1 buffer.
diff -Nru mbedtls-3.6.5/framework/tests/include/test/bignum_codepath_check.h mbedtls-3.6.6/framework/tests/include/test/bignum_codepath_check.h
--- mbedtls-3.6.5/framework/tests/include/test/bignum_codepath_check.h	2025-10-01 18:24:20.280257700 +0300
+++ mbedtls-3.6.6/framework/tests/include/test/bignum_codepath_check.h	2026-03-27 12:34:57.790099100 +0200
@@ -17,6 +17,8 @@
 #ifndef BIGNUM_CODEPATH_CHECK_H
 #define BIGNUM_CODEPATH_CHECK_H
 
+#include "build_info.h"
+
 #include "bignum_core.h"
 
 #if defined(MBEDTLS_TEST_HOOKS) && !defined(MBEDTLS_THREADING_C)
diff -Nru mbedtls-3.6.5/framework/tests/include/test/bignum_helpers.h mbedtls-3.6.6/framework/tests/include/test/bignum_helpers.h
--- mbedtls-3.6.5/framework/tests/include/test/bignum_helpers.h	2025-10-01 18:24:20.280368300 +0300
+++ mbedtls-3.6.6/framework/tests/include/test/bignum_helpers.h	2026-03-27 12:34:57.790182400 +0200
@@ -13,7 +13,7 @@
 #ifndef TEST_BIGNUM_HELPERS_H
 #define TEST_BIGNUM_HELPERS_H
 
-#include <mbedtls/build_info.h>
+#include "build_info.h"
 
 #if defined(MBEDTLS_BIGNUM_C)
 
diff -Nru mbedtls-3.6.5/framework/tests/include/test/build_info.h mbedtls-3.6.6/framework/tests/include/test/build_info.h
--- mbedtls-3.6.5/framework/tests/include/test/build_info.h	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/tests/include/test/build_info.h	2026-03-27 12:34:57.790268700 +0200
@@ -0,0 +1,24 @@
+/**
+ * \file test/build_info.h
+ *
+ * \brief Common things for all Mbed TLS and TF-PSA-Crypto test headers.
+ *
+ * Include this header first in all headers in `include/test/`.
+ */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef TEST_BUILD_INFO_H
+#define TEST_BUILD_INFO_H
+
+#include <mbedtls/build_info.h>
+
+/* Most fields of publicly available structs are private and are wrapped with
+ * MBEDTLS_PRIVATE macro. This define allows tests to access the private fields
+ * directly (without using the MBEDTLS_PRIVATE wrapper). */
+#define MBEDTLS_ALLOW_PRIVATE_ACCESS
+
+#endif /* TEST_BUILD_INFO_H */
diff -Nru mbedtls-3.6.5/framework/tests/include/test/constant_flow.h mbedtls-3.6.6/framework/tests/include/test/constant_flow.h
--- mbedtls-3.6.5/framework/tests/include/test/constant_flow.h	2025-10-01 18:24:20.280477500 +0300
+++ mbedtls-3.6.6/framework/tests/include/test/constant_flow.h	2026-03-27 12:34:57.790337800 +0200
@@ -12,7 +12,7 @@
 #ifndef TEST_CONSTANT_FLOW_H
 #define TEST_CONSTANT_FLOW_H
 
-#include "mbedtls/build_info.h"
+#include "build_info.h"
 
 /*
  * This file defines the two macros
diff -Nru mbedtls-3.6.5/framework/tests/include/test/drivers/test_driver_common.h mbedtls-3.6.6/framework/tests/include/test/drivers/test_driver_common.h
--- mbedtls-3.6.5/framework/tests/include/test/drivers/test_driver_common.h	2025-10-01 18:24:20.282044600 +0300
+++ mbedtls-3.6.6/framework/tests/include/test/drivers/test_driver_common.h	2026-03-27 12:34:57.791691500 +0200
@@ -25,4 +25,66 @@
 
 /* *INDENT-ON* */
 
+/*
+ * In the libtestdriver1 library used in Mbed TLS 3.6 and 4.0 for driver
+ * dispatch testing, the PSA core code is cloned and all identifiers starting
+ * with MBEDTLS_, PSA_, mbedtls_, or psa_ are prefixed with `libtestdriver1_`.
+ * As a result, libtestdriver1 drivers use, for example,
+ * `libtestdriver1_psa_key_attributes_t` instead of `psa_key_attributes_t`.
+ *
+ * With the generated test drivers introduced in TF-PSA-Crypto between 1.0
+ * and 1.1, only the modules under `drivers/builtin` are cloned, not the PSA
+ * core. The generated test drivers therefore do not use prefixed PSA core
+ * identifiers. For example, they use the `psa_key_attributes_t` type, just
+ * like the built-in drivers.
+ *
+ * To make driver dispatch work in both cases, we define certain
+ * `libtestdriver1_xyz` identifiers as aliases of the corresponding `xyz`
+ * identifiers in the latter case.
+ */
+#if defined(TF_PSA_CRYPTO_TEST_LIBTESTDRIVER1)
+typedef psa_key_attributes_t libtestdriver1_psa_key_attributes_t;
+typedef psa_crypto_driver_pake_inputs_t libtestdriver1_psa_crypto_driver_pake_inputs_t;
+typedef psa_crypto_driver_pake_step_t libtestdriver1_psa_crypto_driver_pake_step_t;
+#endif
+
+/*
+ * The LIBTESTDRIVER1_PSA_DRIVER_INTERNAL_HEADER(basename) macro expands to
+ * the path of the internal header `basename` of a libtestdriver1 test driver.
+ *
+ * The internal headers the macro is dedicated to are the `psa_crypto_xyz.h`
+ * headers located in `library` in 3.6, in `tf-psa-crypto/drivers/builtin/src`
+ * in 4.x and in`drivers/builtin/src` in TF-PSA-Crypto.
+ *
+ * - In Mbed TLS 3.6 and 4.x, when the libtestdriver1 library is built, its code
+ *   is located in the `libtestdriver1` directory at the root of the project.
+ *   The header path is relative to the repository root and therefore of the
+ *   form:
+ *     - Mbed TLS 3.6: `libtestdriver1/library/xyz`
+ *     - Mbed TLS 4.x: `libtestdriver1/tf-psa-crypto/drivers/builtin/src/xyz`
+ *
+ * - In TF-PSA-Crypto, the libtestdriver1 library code is located in
+ *   `drivers/libtestdriver1`. The header path is relative to
+ *   `drivers/libtestdriver1/include` and has the form:
+ *     `../src/libtestdriver1-xyz`
+ *
+ * Uncrustify is not happy with the macros, temporarily disable it.
+ *
+ * *INDENT-OFF*
+ */
+#if defined(TF_PSA_CRYPTO_TEST_LIBTESTDRIVER1)
+#define LIBTESTDRIVER1_PSA_DRIVER_INTERNAL_HEADER(basename) \
+    <../src/libtestdriver1-basename>
+#else
+#if MBEDTLS_VERSION_MAJOR < 4
+#define LIBTESTDRIVER1_PSA_DRIVER_INTERNAL_HEADER(basename) \
+    <libtestdriver1/library/basename>
+#else
+#define LIBTESTDRIVER1_PSA_DRIVER_INTERNAL_HEADER(basename) \
+    <libtestdriver1/tf-psa-crypto/drivers/builtin/src/basename>
+#endif
+#endif
+
+/* *INDENT-ON* */
+
 #endif /* test_driver_common.h */
diff -Nru mbedtls-3.6.5/framework/tests/include/test/drivers/test_driver.h mbedtls-3.6.6/framework/tests/include/test/drivers/test_driver.h
--- mbedtls-3.6.5/framework/tests/include/test/drivers/test_driver.h	2025-10-01 18:24:20.281929000 +0300
+++ mbedtls-3.6.6/framework/tests/include/test/drivers/test_driver.h	2026-03-27 12:34:57.791606200 +0200
@@ -27,6 +27,7 @@
 #include "test/drivers/asymmetric_encryption.h"
 #include "test/drivers/key_agreement.h"
 #include "test/drivers/pake.h"
+#include "test/drivers/xof.h"
 
 #endif /* PSA_CRYPTO_DRIVER_TEST */
 #endif /* PSA_CRYPTO_TEST_DRIVER_H */
diff -Nru mbedtls-3.6.5/framework/tests/include/test/drivers/xof.h mbedtls-3.6.6/framework/tests/include/test/drivers/xof.h
--- mbedtls-3.6.5/framework/tests/include/test/drivers/xof.h	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/tests/include/test/drivers/xof.h	2026-03-27 12:34:57.791780200 +0200
@@ -0,0 +1,63 @@
+/*
+ * Test driver for xof driver entry points.
+ */
+/*  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef PSA_CRYPTO_TEST_DRIVERS_XOF_H
+#define PSA_CRYPTO_TEST_DRIVERS_XOF_H
+
+#include "mbedtls/build_info.h"
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include "test_driver_common.h"
+
+#include <psa/crypto_driver_common.h>
+
+/* The type  mbedtls_transparent_test_driver_xof_operation_t is only
+ * defined since XOF support was added in TF-PSA-Crypto 1.1.0. */
+#if defined(PSA_ALG_CATEGORY_XOF)
+
+typedef struct {
+    /* If not PSA_SUCCESS, return this error code instead of processing the
+     * function call. */
+    psa_status_t forced_status;
+    /* Count the amount of times xof driver entry points are called. */
+    unsigned long hits;
+    /* Status returned by the last xof driver entry point call. */
+    psa_status_t driver_status;
+} mbedtls_test_driver_xof_hooks_t;
+
+#define MBEDTLS_TEST_DRIVER_XOF_INIT { 0, 0, 0 }
+static inline mbedtls_test_driver_xof_hooks_t
+mbedtls_test_driver_xof_hooks_init(void)
+{
+    const mbedtls_test_driver_xof_hooks_t v = MBEDTLS_TEST_DRIVER_XOF_INIT;
+    return v;
+}
+
+extern mbedtls_test_driver_xof_hooks_t mbedtls_test_driver_xof_hooks;
+
+psa_status_t mbedtls_test_transparent_xof_setup(
+    mbedtls_transparent_test_driver_xof_operation_t *operation,
+    psa_algorithm_t alg);
+
+psa_status_t mbedtls_test_transparent_xof_set_context(
+    mbedtls_transparent_test_driver_xof_operation_t *operation,
+    const uint8_t *context, size_t context_length);
+
+psa_status_t mbedtls_test_transparent_xof_update(
+    mbedtls_transparent_test_driver_xof_operation_t *operation,
+    const uint8_t *input, size_t input_length);
+
+psa_status_t mbedtls_test_transparent_xof_output(
+    mbedtls_transparent_test_driver_xof_operation_t *operation,
+    uint8_t *output, size_t output_length);
+
+psa_status_t mbedtls_test_transparent_xof_abort(
+    mbedtls_transparent_test_driver_xof_operation_t *operation);
+
+#endif /* PSA_ALG_CATEGORY_XOF */
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_TEST_DRIVERS_XOF_H */
diff -Nru mbedtls-3.6.5/framework/tests/include/test/fake_external_rng_for_test.h mbedtls-3.6.6/framework/tests/include/test/fake_external_rng_for_test.h
--- mbedtls-3.6.5/framework/tests/include/test/fake_external_rng_for_test.h	2025-10-01 18:24:20.282156500 +0300
+++ mbedtls-3.6.6/framework/tests/include/test/fake_external_rng_for_test.h	2026-03-27 12:34:57.791863200 +0200
@@ -10,7 +10,7 @@
 #ifndef FAKE_EXTERNAL_RNG_FOR_TEST_H
 #define FAKE_EXTERNAL_RNG_FOR_TEST_H
 
-#include "mbedtls/build_info.h"
+#include "build_info.h"
 
 #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
 /** Enable the insecure implementation of mbedtls_psa_external_get_random().
diff -Nru mbedtls-3.6.5/framework/tests/include/test/fork_helpers.h mbedtls-3.6.6/framework/tests/include/test/fork_helpers.h
--- mbedtls-3.6.5/framework/tests/include/test/fork_helpers.h	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/tests/include/test/fork_helpers.h	2026-03-27 12:34:57.792076000 +0200
@@ -0,0 +1,61 @@
+/** Helper functions for testing with subprocesses.
+ */
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef TEST_FORK_HELPERS_H
+#define TEST_FORK_HELPERS_H
+
+#include "test/helpers.h"
+
+/** Type of a function to run in a child process.
+ *
+ * The function can mark the test case as failed by calling
+ * mbedtls_test_fail(). This information will be reported to the parent.
+ *
+ * \param param         Parameter passed to the callback.
+ * \param[out] output   Buffer for data to pass to the parent.
+ *                      This data is ignored if the test case is marked
+ *                      as failed.
+ * \param output_size   Size of \p output in bytes.
+ * \param[out] output_length    Number of bytes written to \p output, to be
+ *                              passed to the parent. The default is \c 0.
+ */
+typedef void mbedtls_test_fork_child_callback_t(
+    void *param,
+    unsigned char *output, size_t output_size, size_t *output_length);
+
+/* Fork a child process and wait for it to collect some data.
+ *
+ * This is similar to backquotes or `$(...)` in a shell.
+ *
+ * This function blocks until the child exits.
+ *
+ * If the child marks the test as failed or skipped, the child's test
+ * information (test result and failure location) is propagated to the
+ * parent.
+ *
+ * \note Memory leak detection is disabled in the child.
+ *
+ * \param child_callback        Callback function to run in the child.
+ * \param param                 Parameter to pass to the callback function.
+ * \param[out] child_output     On success, data retrieved from the child.
+ *                              Note that the data is only available if the
+ *                              child did not mark the test case as failed
+ *                              or skipped.
+ * \param child_output_size     Size of \p child_output in bytes.
+ * \param[out] child_output_length  On success, the number of bytes collected
+ *                                  from the child in \c child_output.
+ *
+ * \return \c 0 on success.
+ *         A nonzero value if the test case is marked as failed or skipped.
+ */
+int mbedtls_test_fork_run_child(
+    mbedtls_test_fork_child_callback_t *child_callback,
+    void *param,
+    unsigned char *child_output, size_t child_output_size,
+    size_t *child_output_length);
+
+#endif /* TEST_FORK_HELPERS_H */
diff -Nru mbedtls-3.6.5/framework/tests/include/test/helpers.h mbedtls-3.6.6/framework/tests/include/test/helpers.h
--- mbedtls-3.6.5/framework/tests/include/test/helpers.h	2025-10-01 18:24:20.282310500 +0300
+++ mbedtls-3.6.6/framework/tests/include/test/helpers.h	2026-03-27 12:34:57.792359600 +0200
@@ -13,12 +13,7 @@
 #ifndef TEST_HELPERS_H
 #define TEST_HELPERS_H
 
-/* Most fields of publicly available structs are private and are wrapped with
- * MBEDTLS_PRIVATE macro. This define allows tests to access the private fields
- * directly (without using the MBEDTLS_PRIVATE wrapper). */
-#define MBEDTLS_ALLOW_PRIVATE_ACCESS
-
-#include "mbedtls/build_info.h"
+#include "build_info.h"
 
 #if defined(__SANITIZE_ADDRESS__) /* gcc -fsanitize=address */
 #  define MBEDTLS_TEST_HAVE_ASAN
@@ -152,6 +147,25 @@
  */
 void mbedtls_test_get_line2(char *line);
 
+/**
+ * \brief           Get a copy of the test result information.
+ *
+ * \param[out] out  On output, contains a copy of the current test info.
+ */
+void mbedtls_test_info_save(mbedtls_test_info_t *out);
+
+/**
+ * \brief           Overwrite the test result information.
+ *                  This is intended for some unusual scenarios.
+ *                  You probably shouldn't use this in a test function.
+ *
+ * \param[in] replacement
+ *                  The test info to use instead of the current one.
+ *                  The function copies the data, so the pointer does
+ *                  not need to be valid after this function returns.
+ */
+void mbedtls_test_info_overwrite(const mbedtls_test_info_t *replacement);
+
 #if defined(MBEDTLS_TEST_MUTEX_USAGE)
 /**
  * \brief           Get the current mutex usage error message
@@ -241,6 +255,19 @@
 void mbedtls_test_fail(const char *test, int line_no, const char *filename);
 
 /**
+ * \brief           Record the current test case as a failure
+ *                  and show the value of errno.
+ *
+ *                  This function is usually called via #TEST_ASSERT_ERRNO.
+ *
+ * \param test      Description of the failure or assertion that failed. This
+ *                  MUST be a string literal.
+ * \param line_no   Line number where the failure originated.
+ * \param filename  Filename where the failure originated.
+ */
+void mbedtls_test_fail_errno(const char *test, int line_no, const char *filename);
+
+/**
  * \brief           Record the current test case as skipped.
  *
  *                  This function can be called directly however it is usually
diff -Nru mbedtls-3.6.5/framework/tests/include/test/macros.h mbedtls-3.6.6/framework/tests/include/test/macros.h
--- mbedtls-3.6.5/framework/tests/include/test/macros.h	2025-10-01 18:24:20.282423000 +0300
+++ mbedtls-3.6.6/framework/tests/include/test/macros.h	2026-03-27 12:34:57.792442600 +0200
@@ -12,7 +12,7 @@
 #ifndef TEST_MACROS_H
 #define TEST_MACROS_H
 
-#include "mbedtls/build_info.h"
+#include "build_info.h"
 
 #include <stdlib.h>
 
@@ -54,6 +54,21 @@
         }                                                    \
     } while (0)
 
+/** \brief Evaluate an integer expression. If the value is 0 (i.e. false),
+ *         mark the test case as failed and display errno.
+ *
+ * This is intended for functions that follow the Unix API convention of
+ * returning a particular value (often -1) and setting errno on failure,
+ * e.g. `TEST_ASSERT_ERRNO(open(...) != -1)`.
+ */
+#define TEST_ASSERT_ERRNO(expr)                                         \
+    do {                                                                \
+        if (!(expr)) {                                                  \
+            mbedtls_test_fail_errno(#expr, __LINE__, __FILE__);         \
+            goto exit;                                                  \
+        }                                                               \
+    } while (0)
+
 /** This macro asserts fails the test with given output message.
  *
  * \param   MESSAGE The message to be outputed on assertion
diff -Nru mbedtls-3.6.5/framework/tests/include/test/memory.h mbedtls-3.6.6/framework/tests/include/test/memory.h
--- mbedtls-3.6.5/framework/tests/include/test/memory.h	2025-10-01 18:24:20.282527400 +0300
+++ mbedtls-3.6.6/framework/tests/include/test/memory.h	2026-03-27 12:34:57.792520300 +0200
@@ -12,7 +12,8 @@
 #ifndef TEST_MEMORY_H
 #define TEST_MEMORY_H
 
-#include "mbedtls/build_info.h"
+#include "build_info.h"
+
 #include "mbedtls/platform.h"
 #include "test/helpers.h"
 
diff -Nru mbedtls-3.6.5/framework/tests/include/test/pk_helpers.h mbedtls-3.6.6/framework/tests/include/test/pk_helpers.h
--- mbedtls-3.6.5/framework/tests/include/test/pk_helpers.h	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/tests/include/test/pk_helpers.h	2026-03-27 12:34:57.792650000 +0200
@@ -0,0 +1,96 @@
+/*
+ * Helper functions for PK.
+ * This is only for TF-PSA-Crypto 1.0 and above.
+ */
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef PK_HELPERS_H
+#define PK_HELPERS_H
+
+#include "build_info.h"
+
+#if defined(MBEDTLS_PK_C)
+
+#include <psa/crypto.h>
+#include <mbedtls/pk.h>
+
+/* 'pk_context_populate_method_t' is only used in 'mbedtls_pk_helpers_populate_context'
+ * which takes a PSA key ID to populate the PK context. The idea is to use that
+ * function after calling 'mbedtls_pk_helpers_make_psa_key_from_predefined' to
+ * retrieve a PSA key ID. Adding support for parsing doesn't fit well with the
+ * current prototype of 'mbedtls_pk_helpers_populate_context'.
+ * What is needed to add parsing in the list below is a new function which acts
+ * as a combination between 'mbedtls_pk_helpers_make_psa_key_from_predefined' and
+ * 'mbedtls_pk_helpers_populate_context', i.e. it takes a key type, key bits and
+ * population method as input and it returns a PK context.
+ */
+typedef enum {
+    TEST_PK_WRAP_PSA,
+    TEST_PK_COPY_FROM_PSA,
+    TEST_PK_COPY_PUBLIC_FROM_PSA,
+} pk_context_populate_method_t;
+
+/**
+ * Get predefined key pair/public key data for the requested key.
+ *
+ * If the specified key type or bit length does not exist in the list of known
+ * predefined keys, an assertion failure will be generated.
+ *
+ * The output format is compatible with PSA API, so they key can be imported
+ * with psa_import_key().
+ *
+ * \param key_type   PSA key type for the key being requested.
+ * \param key_bits   Bit length for the PSA key being requested.
+ * \param output     Pointer which on exit will point to the key material that has
+ *                   been requested by "key_type" and "key_bits".
+ * \param output_len Length of the key material being pointed to from "output".
+ *
+ * \return           0 on success; MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE if the required
+ *                   key is not the in list of known ones.
+ */
+int mbedtls_pk_helpers_get_predefined_key_data(psa_key_type_t key_type, psa_key_bits_t key_bits,
+                                               const uint8_t **output, size_t *output_len);
+
+/**
+ * Create a PSA key using prefined key data.
+ *
+ * Predefined key data is used to create the key and the choice of predefined
+ * key material is based on the combination of "key_type" and "key_bits".
+ *
+ * \param key_type    Type of key to be created. For the time being only RSA and
+ *                    EC key types are supported.
+ * \param key_bits    Length of the key (in bits).
+ * \param alg         Algorithm to be associated with the key.
+ * \param alg2        Enrollment alogrithm to be associated with the key.
+ * \param usage_flags Usage flags to be associated with the key.
+ *
+ * \return            On success the key ID of the created PSA key.
+ *                    On failure 0 is returned and the test is marked as failed.
+ */
+mbedtls_svc_key_id_t mbedtls_pk_helpers_make_psa_key_from_predefined(psa_key_type_t key_type,
+                                                                     psa_key_bits_t key_bits,
+                                                                     psa_algorithm_t alg,
+                                                                     psa_algorithm_t alg2,
+                                                                     psa_key_usage_t usage_flags);
+
+/**
+ * Populate the given PK context using "key_id" and the desired "method".
+ *
+ * \param pk     The PK context to be populated; it must have been initialized.
+ * \param key_id The PSA key ID to be used to populate the PK context.
+ * \param method The desired method for populating the PK context. See
+ *               "pk_context_populate_method_t" for available options.
+ *
+ * \return       0 on success.
+ *               In case of failure -1 is returned and the test case is marked
+ *               as failed.
+ */
+int mbedtls_pk_helpers_populate_context(mbedtls_pk_context *pk, mbedtls_svc_key_id_t key_id,
+                                        pk_context_populate_method_t method);
+
+#endif /* MBEDTLS_PK_C */
+
+#endif /* PK_HELPERS_H */
diff -Nru mbedtls-3.6.5/framework/tests/include/test/psa_crypto_helpers.h mbedtls-3.6.6/framework/tests/include/test/psa_crypto_helpers.h
--- mbedtls-3.6.5/framework/tests/include/test/psa_crypto_helpers.h	2025-10-01 18:24:20.282641200 +0300
+++ mbedtls-3.6.6/framework/tests/include/test/psa_crypto_helpers.h	2026-03-27 12:34:57.792750400 +0200
@@ -9,6 +9,7 @@
 #ifndef PSA_CRYPTO_HELPERS_H
 #define PSA_CRYPTO_HELPERS_H
 
+#include "build_info.h"
 #include "test/helpers.h"
 
 #if (MBEDTLS_VERSION_MAJOR < 4 && defined(MBEDTLS_PSA_CRYPTO_C)) || \
diff -Nru mbedtls-3.6.5/framework/tests/include/test/psa_exercise_key.h mbedtls-3.6.6/framework/tests/include/test/psa_exercise_key.h
--- mbedtls-3.6.5/framework/tests/include/test/psa_exercise_key.h	2025-10-01 18:24:20.282785700 +0300
+++ mbedtls-3.6.6/framework/tests/include/test/psa_exercise_key.h	2026-03-27 12:34:57.792841400 +0200
@@ -9,6 +9,7 @@
 #ifndef PSA_EXERCISE_KEY_H
 #define PSA_EXERCISE_KEY_H
 
+#include "build_info.h"
 #include "test/helpers.h"
 #include "test/psa_crypto_helpers.h"
 
diff -Nru mbedtls-3.6.5/framework/tests/include/test/psa_helpers.h mbedtls-3.6.6/framework/tests/include/test/psa_helpers.h
--- mbedtls-3.6.5/framework/tests/include/test/psa_helpers.h	2025-10-01 18:24:20.282890000 +0300
+++ mbedtls-3.6.6/framework/tests/include/test/psa_helpers.h	2026-03-27 12:34:57.792914900 +0200
@@ -9,6 +9,8 @@
 #ifndef PSA_HELPERS_H
 #define PSA_HELPERS_H
 
+#include "build_info.h"
+
 #if defined(MBEDTLS_PSA_CRYPTO_SPM)
 #include "spm/psa_defs.h"
 #endif
diff -Nru mbedtls-3.6.5/framework/tests/include/test/psa_memory_poisoning_wrappers.h mbedtls-3.6.6/framework/tests/include/test/psa_memory_poisoning_wrappers.h
--- mbedtls-3.6.5/framework/tests/include/test/psa_memory_poisoning_wrappers.h	2025-10-01 18:24:20.282985400 +0300
+++ mbedtls-3.6.6/framework/tests/include/test/psa_memory_poisoning_wrappers.h	2026-03-27 12:34:57.792990200 +0200
@@ -15,6 +15,8 @@
 #ifndef PSA_MEMORY_POISONING_WRAPPERS_H
 #define PSA_MEMORY_POISONING_WRAPPERS_H
 
+#include "build_info.h"
+
 #include "psa/crypto.h"
 
 #include "test/memory.h"
diff -Nru mbedtls-3.6.5/framework/tests/include/test/random.h mbedtls-3.6.6/framework/tests/include/test/random.h
--- mbedtls-3.6.5/framework/tests/include/test/random.h	2025-10-01 18:24:20.283083700 +0300
+++ mbedtls-3.6.6/framework/tests/include/test/random.h	2026-03-27 12:34:57.793071700 +0200
@@ -13,7 +13,7 @@
 #ifndef TEST_RANDOM_H
 #define TEST_RANDOM_H
 
-#include "mbedtls/build_info.h"
+#include "build_info.h"
 
 #include <stddef.h>
 #include <stdint.h>
diff -Nru mbedtls-3.6.5/framework/tests/include/test/threading_helpers.h mbedtls-3.6.6/framework/tests/include/test/threading_helpers.h
--- mbedtls-3.6.5/framework/tests/include/test/threading_helpers.h	2025-10-01 18:24:20.283232500 +0300
+++ mbedtls-3.6.6/framework/tests/include/test/threading_helpers.h	2026-03-27 12:34:57.793146600 +0200
@@ -13,18 +13,12 @@
 #ifndef THREADING_HELPERS_H
 #define THREADING_HELPERS_H
 
-#include "mbedtls/private_access.h"
-#include "mbedtls/build_info.h"
+#include "build_info.h"
 
 #if defined MBEDTLS_THREADING_C
 
 #include <mbedtls/threading.h>
 
-/* Most fields of publicly available structs are private and are wrapped with
- * MBEDTLS_PRIVATE macro. This define allows tests to access the private fields
- * directly (without using the MBEDTLS_PRIVATE wrapper). */
-#define MBEDTLS_ALLOW_PRIVATE_ACCESS
-
 /* Error in thread management */
 #define MBEDTLS_ERR_THREADING_THREAD_ERROR                 -0x001F
 
diff -Nru mbedtls-3.6.5/framework/tests/programs/metatest.c mbedtls-3.6.6/framework/tests/programs/metatest.c
--- mbedtls-3.6.5/framework/tests/programs/metatest.c	2025-10-01 18:24:20.283528000 +0300
+++ mbedtls-3.6.6/framework/tests/programs/metatest.c	2026-03-27 12:34:57.793398100 +0200
@@ -16,7 +16,7 @@
  * Asan or Valgrind to detect memory leaks. This is reflected by the
  * "platform" associated with each meta-test.
  *
- * Use the companion script `tests/scripts/run-metatests.sh` to run all
+ * Use the companion script `framework/scripts/run-metatests.sh` to run all
  * the meta-tests for a given platform and validate that they trigger a
  * detected failure as expected.
  */
@@ -26,6 +26,14 @@
  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  */
 
+/* On Mingw-w64, force the use of a C99-compliant printf() and friends.
+ * This is necessary on older versions of Mingw and/or Windows runtimes
+ * where snprintf does not always zero-terminate the buffer, and does
+ * not support formats such as "%zu" for size_t and "%lld" for long long.
+ */
+#if !defined(__USE_MINGW_ANSI_STDIO)
+#define __USE_MINGW_ANSI_STDIO 1
+#endif
 
 #include <mbedtls/debug.h>
 #include <mbedtls/platform.h>
@@ -200,10 +208,7 @@
     size_t start = 0, offset = 0, count = 0;
     char direction = 'r';
     if (sscanf(name,
-               "%*[^0-9]%" MBEDTLS_PRINTF_SIZET
-               "%*[^0-9]%" MBEDTLS_PRINTF_SIZET
-               "%*[^0-9]%" MBEDTLS_PRINTF_SIZET
-               "_%c",
+               "%*[^0-9]%zu%*[^0-9]%zu%*[^0-9]%zu_%c",
                &start, &offset, &count, &direction) != 4) {
         mbedtls_fprintf(stderr, "%s: Bad name format: %s\n", __func__, name);
         return;
@@ -217,22 +222,19 @@
 
     if (start > sizeof(aligned.buf)) {
         mbedtls_fprintf(stderr,
-                        "%s: start=%" MBEDTLS_PRINTF_SIZET
-                        " > size=%" MBEDTLS_PRINTF_SIZET,
+                        "%s: start=%zu > size=%zu",
                         __func__, start, sizeof(aligned.buf));
         return;
     }
     if (start + count > sizeof(aligned.buf)) {
         mbedtls_fprintf(stderr,
-                        "%s: start+count=%" MBEDTLS_PRINTF_SIZET
-                        " > size=%" MBEDTLS_PRINTF_SIZET,
+                        "%s: start+count=%zu > size=%zu",
                         __func__, start + count, sizeof(aligned.buf));
         return;
     }
     if (offset >= count) {
         mbedtls_fprintf(stderr,
-                        "%s: offset=%" MBEDTLS_PRINTF_SIZET
-                        " >= count=%" MBEDTLS_PRINTF_SIZET,
+                        "%s: offset=%zu >= count=%zu",
                         __func__, offset, count);
         return;
     }
diff -Nru mbedtls-3.6.5/framework/tests/src/asn1_helpers.c mbedtls-3.6.6/framework/tests/src/asn1_helpers.c
--- mbedtls-3.6.5/framework/tests/src/asn1_helpers.c	2025-10-01 18:24:20.284328000 +0300
+++ mbedtls-3.6.6/framework/tests/src/asn1_helpers.c	2026-03-27 12:34:57.794057000 +0200
@@ -8,6 +8,7 @@
  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  */
 
+#include "test_common.h"
 #include <test/helpers.h>
 #include <test/macros.h>
 
diff -Nru mbedtls-3.6.5/framework/tests/src/bignum_codepath_check.c mbedtls-3.6.6/framework/tests/src/bignum_codepath_check.c
--- mbedtls-3.6.5/framework/tests/src/bignum_codepath_check.c	2025-10-01 18:24:20.284413600 +0300
+++ mbedtls-3.6.6/framework/tests/src/bignum_codepath_check.c	2026-03-27 12:34:57.794140300 +0200
@@ -5,6 +5,7 @@
  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  */
 
+#include "test_common.h"
 #include "test/bignum_codepath_check.h"
 #include "bignum_core_invasive.h"
 
diff -Nru mbedtls-3.6.5/framework/tests/src/bignum_helpers.c mbedtls-3.6.6/framework/tests/src/bignum_helpers.c
--- mbedtls-3.6.5/framework/tests/src/bignum_helpers.c	2025-10-11 23:43:14.514709700 +0300
+++ mbedtls-3.6.6/framework/tests/src/bignum_helpers.c	2026-03-27 12:34:57.794275800 +0200
@@ -10,7 +10,8 @@
  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  */
 
-#define MBEDTLS_ALLOW_PRIVATE_ACCESS
+#include "test_common.h"
+
 #include <test/bignum_helpers.h>
 
 #if defined(MBEDTLS_BIGNUM_C)
diff -Nru mbedtls-3.6.5/framework/tests/src/drivers/hash.c mbedtls-3.6.6/framework/tests/src/drivers/hash.c
--- mbedtls-3.6.5/framework/tests/src/drivers/hash.c	2025-10-01 18:24:20.284788000 +0300
+++ mbedtls-3.6.6/framework/tests/src/drivers/hash.c	2026-03-27 12:34:57.794446000 +0200
@@ -13,11 +13,7 @@
 #include "test/drivers/hash.h"
 
 #if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
-#if MBEDTLS_VERSION_MAJOR < 4
-#include "libtestdriver1/library/psa_crypto_hash.h"
-#else
-#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_hash.h"
-#endif
+#include LIBTESTDRIVER1_PSA_DRIVER_INTERNAL_HEADER(psa_crypto_hash.h)
 #endif
 
 mbedtls_test_driver_hash_hooks_t
diff -Nru mbedtls-3.6.5/framework/tests/src/drivers/test_driver_aead.c mbedtls-3.6.6/framework/tests/src/drivers/test_driver_aead.c
--- mbedtls-3.6.5/framework/tests/src/drivers/test_driver_aead.c	2025-10-01 18:24:20.285014000 +0300
+++ mbedtls-3.6.6/framework/tests/src/drivers/test_driver_aead.c	2026-03-27 12:34:57.794612600 +0200
@@ -16,11 +16,7 @@
 #include "mbedtls/constant_time.h"
 
 #if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
-#if MBEDTLS_VERSION_MAJOR < 4
-#include "libtestdriver1/library/psa_crypto_aead.h"
-#else
-#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_aead.h"
-#endif
+#include LIBTESTDRIVER1_PSA_DRIVER_INTERNAL_HEADER(psa_crypto_aead.h)
 #endif
 
 mbedtls_test_driver_aead_hooks_t
diff -Nru mbedtls-3.6.5/framework/tests/src/drivers/test_driver_asymmetric_encryption.c mbedtls-3.6.6/framework/tests/src/drivers/test_driver_asymmetric_encryption.c
--- mbedtls-3.6.5/framework/tests/src/drivers/test_driver_asymmetric_encryption.c	2025-10-01 18:24:20.285180800 +0300
+++ mbedtls-3.6.6/framework/tests/src/drivers/test_driver_asymmetric_encryption.c	2026-03-27 12:34:57.794782900 +0200
@@ -22,11 +22,7 @@
 #include "test/drivers/key_management.h"
 
 #if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
-#if MBEDTLS_VERSION_MAJOR < 4
-#include "libtestdriver1/library/psa_crypto_rsa.h"
-#else
-#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_rsa.h"
-#endif
+#include LIBTESTDRIVER1_PSA_DRIVER_INTERNAL_HEADER(psa_crypto_rsa.h)
 #endif
 
 #define PSA_RSA_KEY_PAIR_MAX_SIZE \
diff -Nru mbedtls-3.6.5/framework/tests/src/drivers/test_driver_cipher.c mbedtls-3.6.6/framework/tests/src/drivers/test_driver_cipher.c
--- mbedtls-3.6.5/framework/tests/src/drivers/test_driver_cipher.c	2025-10-01 18:24:20.285319600 +0300
+++ mbedtls-3.6.6/framework/tests/src/drivers/test_driver_cipher.c	2026-03-27 12:34:57.794884000 +0200
@@ -24,11 +24,7 @@
 #include "test/random.h"
 
 #if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
-#if MBEDTLS_VERSION_MAJOR < 4
-#include "libtestdriver1/library/psa_crypto_cipher.h"
-#else
-#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_cipher.h"
-#endif
+#include LIBTESTDRIVER1_PSA_DRIVER_INTERNAL_HEADER(psa_crypto_cipher.h)
 #endif
 
 #include <string.h>
diff -Nru mbedtls-3.6.5/framework/tests/src/drivers/test_driver_key_agreement.c mbedtls-3.6.6/framework/tests/src/drivers/test_driver_key_agreement.c
--- mbedtls-3.6.5/framework/tests/src/drivers/test_driver_key_agreement.c	2025-10-01 18:24:20.285452100 +0300
+++ mbedtls-3.6.6/framework/tests/src/drivers/test_driver_key_agreement.c	2026-03-27 12:34:57.795018400 +0200
@@ -20,16 +20,16 @@
 #include <string.h>
 
 #if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
+#include LIBTESTDRIVER1_PSA_DRIVER_INTERNAL_HEADER(psa_crypto_ecp.h)
+#include LIBTESTDRIVER1_PSA_DRIVER_INTERNAL_HEADER(psa_crypto_ffdh.h)
+#if !defined(TF_PSA_CRYPTO_TEST_LIBTESTDRIVER1)
 #if MBEDTLS_VERSION_MAJOR < 4
 #include "libtestdriver1/include/psa/crypto.h"
-#include "libtestdriver1/library/psa_crypto_ecp.h"
-#include "libtestdriver1/library/psa_crypto_ffdh.h"
 #else
 #include "libtestdriver1/tf-psa-crypto/include/psa/crypto.h"
-#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_ecp.h"
-#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_ffdh.h"
 #endif
 #endif
+#endif /* MBEDTLS_TEST_LIBTESTDRIVER1 */
 
 mbedtls_test_driver_key_agreement_hooks_t
     mbedtls_test_driver_key_agreement_hooks = MBEDTLS_TEST_DRIVER_KEY_AGREEMENT_INIT;
diff -Nru mbedtls-3.6.5/framework/tests/src/drivers/test_driver_key_management.c mbedtls-3.6.6/framework/tests/src/drivers/test_driver_key_management.c
--- mbedtls-3.6.5/framework/tests/src/drivers/test_driver_key_management.c	2025-10-01 18:24:20.285535000 +0300
+++ mbedtls-3.6.6/framework/tests/src/drivers/test_driver_key_management.c	2026-03-27 12:34:57.795105500 +0200
@@ -21,24 +21,16 @@
 #include "mbedtls/ecp.h"
 #endif
 
-#include "mbedtls/error.h"
-
 #include "test/drivers/key_management.h"
 #include "test/drivers/test_driver.h"
 
 #include "test/random.h"
 
 #if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
-#if MBEDTLS_VERSION_MAJOR < 4
-#include "libtestdriver1/library/psa_crypto_ecp.h"
-#include "libtestdriver1/library/psa_crypto_rsa.h"
-#include "libtestdriver1/library/psa_crypto_ffdh.h"
-#else
-#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_ecp.h"
-#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_rsa.h"
-#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_ffdh.h"
-#endif
-#endif
+#include LIBTESTDRIVER1_PSA_DRIVER_INTERNAL_HEADER(psa_crypto_ecp.h)
+#include LIBTESTDRIVER1_PSA_DRIVER_INTERNAL_HEADER(psa_crypto_rsa.h)
+#include LIBTESTDRIVER1_PSA_DRIVER_INTERNAL_HEADER(psa_crypto_ffdh.h)
+#endif /* MBEDTLS_TEST_LIBTESTDRIVER1 */
 
 #include <string.h>
 
@@ -68,7 +60,8 @@
 {
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
 
-#if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
+#if !defined(TF_PSA_CRYPTO_TEST_LIBTESTDRIVER1) && \
+    defined(MBEDTLS_TEST_LIBTESTDRIVER1)
     status = libtestdriver1_psa_crypto_init();
     if (status != PSA_SUCCESS) {
         return status;
@@ -81,7 +74,8 @@
 
 void mbedtls_test_transparent_free(void)
 {
-#if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
+#if !defined(TF_PSA_CRYPTO_TEST_LIBTESTDRIVER1) && \
+    defined(MBEDTLS_TEST_LIBTESTDRIVER1)
     libtestdriver1_mbedtls_psa_crypto_free();
 #endif
 
diff -Nru mbedtls-3.6.5/framework/tests/src/drivers/test_driver_mac.c mbedtls-3.6.6/framework/tests/src/drivers/test_driver_mac.c
--- mbedtls-3.6.5/framework/tests/src/drivers/test_driver_mac.c	2025-10-01 18:24:20.285724200 +0300
+++ mbedtls-3.6.6/framework/tests/src/drivers/test_driver_mac.c	2026-03-27 12:34:57.795321200 +0200
@@ -13,11 +13,7 @@
 #include "test/drivers/mac.h"
 
 #if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
-#if MBEDTLS_VERSION_MAJOR < 4
-#include "libtestdriver1/library/psa_crypto_mac.h"
-#else
-#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_mac.h"
-#endif
+#include LIBTESTDRIVER1_PSA_DRIVER_INTERNAL_HEADER(psa_crypto_mac.h)
 #endif
 
 mbedtls_test_driver_mac_hooks_t mbedtls_test_driver_mac_hooks =
diff -Nru mbedtls-3.6.5/framework/tests/src/drivers/test_driver_pake.c mbedtls-3.6.6/framework/tests/src/drivers/test_driver_pake.c
--- mbedtls-3.6.5/framework/tests/src/drivers/test_driver_pake.c	2025-10-01 18:24:20.285882200 +0300
+++ mbedtls-3.6.6/framework/tests/src/drivers/test_driver_pake.c	2026-03-27 12:34:57.795466700 +0200
@@ -14,11 +14,7 @@
 #include "string.h"
 
 #if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
-#if MBEDTLS_VERSION_MAJOR < 4
-#include "libtestdriver1/library/psa_crypto_pake.h"
-#else
-#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_pake.h"
-#endif
+#include LIBTESTDRIVER1_PSA_DRIVER_INTERNAL_HEADER(psa_crypto_pake.h)
 #endif
 
 mbedtls_test_driver_pake_hooks_t mbedtls_test_driver_pake_hooks =
diff -Nru mbedtls-3.6.5/framework/tests/src/drivers/test_driver_signature.c mbedtls-3.6.6/framework/tests/src/drivers/test_driver_signature.c
--- mbedtls-3.6.5/framework/tests/src/drivers/test_driver_signature.c	2025-10-01 18:24:20.286036300 +0300
+++ mbedtls-3.6.6/framework/tests/src/drivers/test_driver_signature.c	2026-03-27 12:34:57.795593000 +0200
@@ -24,7 +24,6 @@
 
 #include "test/drivers/hash.h"
 #include "test/drivers/signature.h"
-#include "test/drivers/hash.h"
 
 #if !defined(MBEDTLS_VERSION_MAJOR) || MBEDTLS_VERSION_MAJOR >= 4
 #include "mbedtls/private/ecdsa.h"
@@ -35,15 +34,9 @@
 #include "test/random.h"
 
 #if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
-#if MBEDTLS_VERSION_MAJOR < 4
-#include "libtestdriver1/library/psa_crypto_ecp.h"
-#include "libtestdriver1/library/psa_crypto_hash.h"
-#include "libtestdriver1/library/psa_crypto_rsa.h"
-#else
-#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_ecp.h"
-#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_hash.h"
-#include "libtestdriver1/tf-psa-crypto/drivers/builtin/src/psa_crypto_rsa.h"
-#endif
+#include LIBTESTDRIVER1_PSA_DRIVER_INTERNAL_HEADER(psa_crypto_ecp.h)
+#include LIBTESTDRIVER1_PSA_DRIVER_INTERNAL_HEADER(psa_crypto_hash.h)
+#include LIBTESTDRIVER1_PSA_DRIVER_INTERNAL_HEADER(psa_crypto_rsa.h)
 #endif
 
 #include <string.h>
@@ -53,7 +46,7 @@
 mbedtls_test_driver_signature_hooks_t
     mbedtls_test_driver_signature_verify_hooks = MBEDTLS_TEST_DRIVER_SIGNATURE_INIT;
 
-psa_status_t sign_hash(
+static psa_status_t sign_hash(
     const psa_key_attributes_t *attributes,
     const uint8_t *key_buffer,
     size_t key_buffer_size,
@@ -121,7 +114,7 @@
     return PSA_ERROR_NOT_SUPPORTED;
 }
 
-psa_status_t verify_hash(
+static psa_status_t verify_hash(
     const psa_key_attributes_t *attributes,
     const uint8_t *key_buffer,
     size_t key_buffer_size,
diff -Nru mbedtls-3.6.5/framework/tests/src/drivers/xof.c mbedtls-3.6.6/framework/tests/src/drivers/xof.c
--- mbedtls-3.6.5/framework/tests/src/drivers/xof.c	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/tests/src/drivers/xof.c	2026-03-27 12:34:57.795782000 +0200
@@ -0,0 +1,163 @@
+/*
+ * Test driver for xof entry points.
+ */
+/*  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include <test/helpers.h>
+
+#if defined(PSA_ALG_CATEGORY_XOF) && defined(PSA_CRYPTO_DRIVER_TEST)
+
+#include "psa_crypto_xof.h"
+
+#include "test/drivers/xof.h"
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
+#include LIBTESTDRIVER1_PSA_DRIVER_INTERNAL_HEADER(psa_crypto_xof.h)
+#endif
+
+mbedtls_test_driver_xof_hooks_t
+    mbedtls_test_driver_xof_hooks = MBEDTLS_TEST_DRIVER_XOF_INIT;
+
+psa_status_t mbedtls_test_transparent_xof_setup(
+    mbedtls_transparent_test_driver_xof_operation_t *operation,
+    psa_algorithm_t alg)
+{
+    mbedtls_test_driver_xof_hooks.hits++;
+
+    if (mbedtls_test_driver_xof_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_xof_hooks.driver_status =
+            mbedtls_test_driver_xof_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_XOF)
+        mbedtls_test_driver_xof_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_xof_setup(operation, alg);
+#elif defined(MBEDTLS_PSA_BUILTIN_XOF)
+        mbedtls_test_driver_xof_hooks.driver_status =
+            mbedtls_psa_xof_setup(operation, alg);
+#else
+        (void) operation;
+        (void) alg;
+        mbedtls_test_driver_xof_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_xof_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_xof_set_context(
+    mbedtls_transparent_test_driver_xof_operation_t *operation,
+    const uint8_t *context, size_t context_length)
+{
+    mbedtls_test_driver_xof_hooks.hits++;
+
+    if (mbedtls_test_driver_xof_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_xof_hooks.driver_status =
+            mbedtls_test_driver_xof_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_XOF)
+        mbedtls_test_driver_xof_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_xof_set_context(
+                operation, context, context_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_XOF)
+        mbedtls_test_driver_xof_hooks.driver_status =
+            mbedtls_psa_xof_set_context(operation, context, context_length);
+#else
+        (void) operation;
+        (void) context;
+        (void) context_length;
+        mbedtls_test_driver_xof_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_xof_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_xof_update(
+    mbedtls_transparent_test_driver_xof_operation_t *operation,
+    const uint8_t *input,
+    size_t input_length)
+{
+    mbedtls_test_driver_xof_hooks.hits++;
+
+    if (mbedtls_test_driver_xof_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_xof_hooks.driver_status =
+            mbedtls_test_driver_xof_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_XOF)
+        mbedtls_test_driver_xof_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_xof_update(
+                operation, input, input_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_XOF)
+        mbedtls_test_driver_xof_hooks.driver_status =
+            mbedtls_psa_xof_update(operation, input, input_length);
+#else
+        (void) operation;
+        (void) input;
+        (void) input_length;
+        mbedtls_test_driver_xof_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_xof_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_xof_output(
+    mbedtls_transparent_test_driver_xof_operation_t *operation,
+    uint8_t *output, size_t output_length)
+{
+    mbedtls_test_driver_xof_hooks.hits++;
+
+    if (mbedtls_test_driver_xof_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_xof_hooks.driver_status =
+            mbedtls_test_driver_xof_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_XOF)
+        mbedtls_test_driver_xof_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_xof_output(
+                operation, output, output_length);
+#elif defined(MBEDTLS_PSA_BUILTIN_XOF)
+        mbedtls_test_driver_xof_hooks.driver_status =
+            mbedtls_psa_xof_output(operation, output, output_length);
+#else
+        (void) operation;
+        (void) output;
+        (void) output_length;
+        mbedtls_test_driver_xof_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_xof_hooks.driver_status;
+}
+
+psa_status_t mbedtls_test_transparent_xof_abort(
+    mbedtls_transparent_test_driver_xof_operation_t *operation)
+{
+    mbedtls_test_driver_xof_hooks.hits++;
+
+    if (mbedtls_test_driver_xof_hooks.forced_status != PSA_SUCCESS) {
+        mbedtls_test_driver_xof_hooks.driver_status =
+            mbedtls_test_driver_xof_hooks.forced_status;
+    } else {
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+        defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_XOF)
+        mbedtls_test_driver_xof_hooks.driver_status =
+            libtestdriver1_mbedtls_psa_xof_abort(operation);
+#elif defined(MBEDTLS_PSA_BUILTIN_XOF)
+        mbedtls_test_driver_xof_hooks.driver_status =
+            mbedtls_psa_xof_abort(operation);
+#else
+        (void) operation;
+        mbedtls_test_driver_xof_hooks.driver_status = PSA_ERROR_NOT_SUPPORTED;
+#endif
+    }
+
+    return mbedtls_test_driver_xof_hooks.driver_status;
+}
+
+#endif /* PSA_CRYPTO_DRIVER_TEST && defined(PSA_ALG_CATEGORY_XOF) */
diff -Nru mbedtls-3.6.5/framework/tests/src/fake_external_rng_for_test.c mbedtls-3.6.6/framework/tests/src/fake_external_rng_for_test.c
--- mbedtls-3.6.5/framework/tests/src/fake_external_rng_for_test.c	2025-10-01 18:29:09.517337300 +0300
+++ mbedtls-3.6.6/framework/tests/src/fake_external_rng_for_test.c	2026-03-27 12:34:57.795961900 +0200
@@ -13,6 +13,8 @@
  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  */
 
+#include "test_common.h"
+
 #include <test/fake_external_rng_for_test.h>
 
 #if defined(MBEDTLS_PSA_DRIVER_GET_ENTROPY)
diff -Nru mbedtls-3.6.5/framework/tests/src/fork_helpers.c mbedtls-3.6.6/framework/tests/src/fork_helpers.c
--- mbedtls-3.6.5/framework/tests/src/fork_helpers.c	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/tests/src/fork_helpers.c	2026-03-27 12:34:57.796220300 +0200
@@ -0,0 +1,244 @@
+/** \file fork_helpers.c
+ *
+ * \brief Helper functions for testing with subprocesses.
+ */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "test_common.h"
+#include <test/helpers.h>
+#include <test/macros.h>
+
+#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE)
+
+#include <test/fork_helpers.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+/** Child exit code for mbedtls_test_fork_run_child().
+ */
+typedef enum {
+    /** Reporting of the child output or the child test result through
+     * the pipe succeeded.
+     *
+     * The content sent on the pipe has the following format:
+     * - [1 byte] #mbedtls_test_result_t \c test_result
+     * - Case \c test_result:
+     *     - If \c test_result == #MBEDTLS_TEST_RESULT_SUCCESS:
+     *       the output from the child body function.
+     *     - Otherwise:
+     *       the child failure (or skip) information, a direct write of
+     *       a #mbedtls_test_result_t structure.
+     */
+    CHILD_EXIT_CODE_OK = 0,
+    /** Something went wrong, e.g. a write error on the pipe. */
+    CHILD_EXIT_CODE_REPORTING_FAILED = 122,
+} child_exit_code_t;
+
+static int env_contains_substring(const char *name, const char *substring)
+{
+    const char *value = getenv(name);
+    if (value == NULL) {
+        return 0;
+    } else {
+        return strstr(value, substring) != NULL;
+    }
+}
+
+static int probably_running_under_valgrind(void)
+{
+    if (env_contains_substring("LD_PRELOAD", "/vgpreload_")) {
+        return 1;
+    }
+    if (env_contains_substring("DYLD_INSERT_LIBRARIES", "/vgpreload_")) {
+        return 1;
+    }
+    return 0;
+}
+
+#if defined(__GNUC__)
+__attribute__((__noreturn__))
+#endif
+static void run_child(
+    int write_fd,
+    mbedtls_test_fork_child_callback_t *child_callback,
+    void *param,
+    unsigned char *buf, size_t size)
+{
+    /* If something goes wrong while trying to report what happened
+     * in the child, exit with a nonzero status. */
+    int child_exit_code = CHILD_EXIT_CODE_REPORTING_FAILED;
+    /* We'll use stdio to write to the pipe, so we don't have to
+     * manage EINTR and such. */
+    FILE *file = fdopen(write_fd, "a");
+    size_t length = 0;
+
+    if (file == NULL) {
+        /* There's no way we can report anything other than the exit code.
+         * So we might as well quit without even running the child callback. */
+        goto write_done;
+    }
+
+    child_callback(param, buf, size, &length);
+    TEST_LE_U(length, size);
+
+    /* Label called `exit`: this is where TEST_ASSERT() and friends jump to. */
+exit:
+    ; // label followed by a declaration is not portable C
+    char result_char = mbedtls_test_get_result();
+    if (fputc(result_char, file) == EOF) {
+        goto write_done;
+    }
+    if (result_char == MBEDTLS_TEST_RESULT_SUCCESS) {
+        if (fwrite(buf, length, 1, file) != 1) {
+            goto write_done;
+        }
+    } else {
+        mbedtls_test_info_t test_info;
+        mbedtls_test_info_save(&test_info);
+        if (fwrite(&test_info, sizeof(test_info), 1, file) != 1) {
+            goto write_done;
+        }
+    }
+    if (fflush(file) != 0) {
+        goto write_done;
+    }
+    child_exit_code = CHILD_EXIT_CODE_OK;
+
+    /* Label for `_exit()` call: this is where we jump to if the failure
+     * reporting fails. */
+write_done:
+    /* We must call _exit(), not exit(), because the child must not run the
+     * things that normally run at exit.
+     *
+     * - Do not flush any stdio buffers! Any unflushed buffers are inherited
+     *   from our parent, and if we flushed them, we'd get duplicate output
+     *   since the parent would also write the same buffer content.
+     * - Do not run atexit hooks, e.g. leak detection code from sanitizers
+     *   such as ASan. The child leaks any number of resources which are
+     *   inherited from the parent but not used in the child. It's the
+     *   parent's job to check for resource leaks.
+     *   (We deliberately do not clean up in the child. One reason is that
+     *   we try to minimize what happens in the child, because it's difficult
+     *   to debug. Another reason is that we must not cause external effects
+     *   such as destroying a PSA persistent key.)
+     */
+    if (probably_running_under_valgrind()) {
+        /* Valgrind overloads _exit(), and this makes it do weird things,
+         * including an lseek() call to rewind the pointer on the file
+         * description for the `.datax` file, causing the same test cases
+         * to run again (or parse errors, depending on the exact amount
+         * of rewinding).
+         *
+         * Valgrind doesn't overload execve() and friends. So instead of
+         * _exit(), execute a shell command that returns the same status.
+         */
+        char cmd[20];
+        snprintf(cmd, sizeof(cmd), "exit %d", child_exit_code);
+        execlp("sh", "sh", "-c", cmd, NULL);
+    }
+    _exit(child_exit_code);
+}
+
+int mbedtls_test_fork_run_child(
+    mbedtls_test_fork_child_callback_t *child_callback,
+    void *param,
+    unsigned char *child_output, size_t child_output_size,
+    size_t *child_output_length)
+{
+    *child_output_length = 0;
+
+    int ret = -1;
+    pid_t pid = -1;
+    int pipe_fd[2] = { -1, -1 };
+
+    /* Set up a pipe. The child will write to pipe_fd[1], and the
+     * parent will read from pipe_fd[0]. */
+    TEST_ASSERT_ERRNO(pipe(pipe_fd) != -1);
+
+    pid = fork();
+    TEST_ASSERT_ERRNO(pid != -1);
+
+    if (pid == 0) {
+        /* The child code */
+        close(pipe_fd[0]);
+        run_child(pipe_fd[1], child_callback, param,
+                  child_output, child_output_size);
+        /* Unreachable */
+    }
+    /* Beyond this point, we're in the parent (original) process. */
+
+    close(pipe_fd[1]);
+    pipe_fd[1] = -1;
+
+    unsigned char result_char;
+    struct {
+        mbedtls_test_info_t child_test_info;
+        unsigned char excess;
+    } reading_on_failure;
+    /* Normally, the child should give us a 1-byte result, then either
+     * the child body's output or a test info. */
+    ssize_t n = read(pipe_fd[0], &result_char, 1);
+    TEST_EQUAL(n, 1);
+
+    /* Tentatively read what we were promised. Don't commit to anything
+     * until we have the child's exit status. */
+    size_t bytes_read = 0;
+    if (result_char == MBEDTLS_TEST_RESULT_SUCCESS) {
+        do {
+            n = read(pipe_fd[0],
+                     child_output + bytes_read,
+                     child_output_size - bytes_read);
+            if (n > 0) {
+                bytes_read += n;
+            }
+        } while (n > 0 && bytes_read < child_output_size);
+        TEST_ASSERT_ERRNO(n != -1);
+    } else {
+        do {
+            n = read(pipe_fd[0],
+                     (unsigned char *) &reading_on_failure + bytes_read,
+                     sizeof(reading_on_failure) - bytes_read);
+            if (n > 0) {
+                bytes_read += n;
+            }
+        } while (n > 0 && bytes_read < sizeof(reading_on_failure));
+        TEST_ASSERT_ERRNO(n != -1);
+        /* Check that the child wrote the amount of data that what we expect. */
+        TEST_EQUAL(bytes_read, sizeof(reading_on_failure.child_test_info));
+    }
+
+    /* Close the pipe. If we left it open, there could be a deadlock if the
+     * child tried to write more than it should, while the parent is just
+     * waiting for the child to exit. */
+    close(pipe_fd[0]);
+    pipe_fd[0] = -1;
+
+    int wstatus;
+    TEST_ASSERT_ERRNO(waitpid(pid, &wstatus, 0) == pid);
+    if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == CHILD_EXIT_CODE_OK) {
+        if (result_char == MBEDTLS_TEST_RESULT_SUCCESS) {
+            *child_output_length = bytes_read;
+            ret = 0;
+        } else {
+            mbedtls_test_info_overwrite(&reading_on_failure.child_test_info);
+        }
+    } else {
+        /* Weird status, just report it. */
+        TEST_EQUAL(wstatus, 0);
+    }
+
+exit:
+    close(pipe_fd[0]);
+    close(pipe_fd[1]);
+    return ret;
+}
+
+#endif /* MBEDTLS_PLATFORM_IS_UNIXLIKE */
diff -Nru mbedtls-3.6.5/framework/tests/src/helpers.c mbedtls-3.6.6/framework/tests/src/helpers.c
--- mbedtls-3.6.5/framework/tests/src/helpers.c	2025-10-01 18:24:20.286286400 +0300
+++ mbedtls-3.6.6/framework/tests/src/helpers.c	2026-03-27 12:34:57.796432700 +0200
@@ -3,9 +3,12 @@
  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  */
 
+#include "test_common.h"
+
 #include <test/constant_flow.h>
 #include <test/helpers.h>
 #include <test/macros.h>
+#include <errno.h>
 #include <string.h>
 
 #if defined(MBEDTLS_PSA_INJECT_ENTROPY)
@@ -457,6 +460,28 @@
 #endif /* MBEDTLS_THREADING_C */
 }
 
+void mbedtls_test_info_save(mbedtls_test_info_t *out)
+{
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+    memcpy(out, &mbedtls_test_info, sizeof(mbedtls_test_info));
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+}
+
+void mbedtls_test_info_overwrite(const mbedtls_test_info_t *replacement)
+{
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+    memcpy(&mbedtls_test_info, replacement, sizeof(mbedtls_test_info));
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+}
+
 int mbedtls_test_equal(const char *test, int line_no, const char *filename,
                        unsigned long long value1, unsigned long long value2)
 {
@@ -571,6 +596,31 @@
     return 0;
 }
 
+void mbedtls_test_fail_errno(const char *test,
+                             int line_no, const char *filename)
+{
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    /* Don't use accessor, we already hold mutex. */
+    if (mbedtls_test_info.result != MBEDTLS_TEST_RESULT_FAILED) {
+        /* If we've already recorded the test as having failed then don't
+         * overwrite any previous information about the failure. */
+
+        char buf[MBEDTLS_TEST_LINE_LENGTH];
+        mbedtls_test_fail_internal(test, line_no, filename);
+        (void) mbedtls_snprintf(buf, sizeof(buf),
+                                "errno = %d (%s)",
+                                errno, strerror(errno));
+        mbedtls_test_set_line1_internal(buf);
+    }
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+}
+
 int mbedtls_test_unhexify(unsigned char *obuf,
                           size_t obufmax,
                           const char *ibuf,
diff -Nru mbedtls-3.6.5/framework/tests/src/pk_helpers.c mbedtls-3.6.6/framework/tests/src/pk_helpers.c
--- mbedtls-3.6.5/framework/tests/src/pk_helpers.c	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/tests/src/pk_helpers.c	2026-03-27 12:34:57.796570300 +0200
@@ -0,0 +1,137 @@
+/*
+ * Helper functions for PK.
+ * This is only for TF-PSA-Crypto 1.0 and above.
+ */
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "test_common.h"
+#include <test/macros.h>
+#include <test/helpers.h>
+#include <test/pk_helpers.h>
+#include <test/psa_helpers.h>
+#include <test/test_keys.h>
+#include <mbedtls/pk.h>
+#include "psa_util_internal.h"
+
+/* Functions like mbedtls_pk_wrap_psa() are only available in tf-psa-crypto and
+ * not in 3.6 LTS branch, so we need a guard for this. */
+#if TF_PSA_CRYPTO_VERSION_MAJOR >= 1
+
+#if defined(MBEDTLS_PK_C)
+
+typedef struct {
+    psa_key_type_t key_type;
+    psa_key_bits_t key_bits;
+    const uint8_t *key;
+    size_t key_len;
+} mbedtls_pk_helpers_predefined_key_t;
+
+#define EC_KEY(family_type, bits, array_base_name)                   \
+    { PSA_KEY_TYPE_ECC_KEY_PAIR(family_type), bits,                  \
+      array_base_name ## _priv, sizeof(array_base_name ## _priv) },  \
+    { PSA_KEY_TYPE_ECC_PUBLIC_KEY(family_type), bits,                \
+      array_base_name ## _pub, sizeof(array_base_name ## _pub) }
+
+#define RSA_KEY(bits, array_base_name)                               \
+    { PSA_KEY_TYPE_RSA_KEY_PAIR, bits,                               \
+      array_base_name ## _priv, sizeof(array_base_name ## _priv) },  \
+    { PSA_KEY_TYPE_RSA_PUBLIC_KEY, bits,                             \
+      array_base_name ## _pub, sizeof(array_base_name ## _pub) }
+
+static mbedtls_pk_helpers_predefined_key_t predefined_keys_psa[] = {
+    EC_KEY(PSA_ECC_FAMILY_BRAINPOOL_P_R1, 256, test_ec_bp256r1),
+    EC_KEY(PSA_ECC_FAMILY_BRAINPOOL_P_R1, 384, test_ec_bp384r1),
+    EC_KEY(PSA_ECC_FAMILY_BRAINPOOL_P_R1, 512, test_ec_bp512r1),
+
+    EC_KEY(PSA_ECC_FAMILY_MONTGOMERY, 255, test_ec_curve25519),
+    EC_KEY(PSA_ECC_FAMILY_MONTGOMERY, 448, test_ec_curve448),
+
+    EC_KEY(PSA_ECC_FAMILY_SECP_K1, 256, test_ec_secp256k1),
+
+    EC_KEY(PSA_ECC_FAMILY_SECP_R1, 256, test_ec_secp256r1),
+    EC_KEY(PSA_ECC_FAMILY_SECP_R1, 384, test_ec_secp384r1),
+    EC_KEY(PSA_ECC_FAMILY_SECP_R1, 521, test_ec_secp521r1),
+
+    RSA_KEY(1024, test_rsa_1024),
+    RSA_KEY(1026, test_rsa_1026),
+    RSA_KEY(1028, test_rsa_1028),
+    RSA_KEY(1030, test_rsa_1030),
+    RSA_KEY(1536, test_rsa_1536),
+    RSA_KEY(2048, test_rsa_2048),
+    RSA_KEY(4096, test_rsa_4096),
+};
+
+int mbedtls_pk_helpers_get_predefined_key_data(psa_key_type_t key_type, psa_key_bits_t key_bits,
+                                               const uint8_t **output, size_t *output_len)
+{
+    for (size_t i = 0; i < ARRAY_LENGTH(predefined_keys_psa); i++) {
+        if ((key_type == predefined_keys_psa[i].key_type) &&
+            (key_bits == predefined_keys_psa[i].key_bits)) {
+            *output = predefined_keys_psa[i].key;
+            *output_len = predefined_keys_psa[i].key_len;
+            return 0;
+        }
+    }
+
+    *output = NULL;
+    *output_len = 0;
+    TEST_FAIL("Predefined key not available");
+
+exit:
+    return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
+}
+
+mbedtls_svc_key_id_t mbedtls_pk_helpers_make_psa_key_from_predefined(psa_key_type_t key_type,
+                                                                     psa_key_bits_t key_bits,
+                                                                     psa_algorithm_t alg,
+                                                                     psa_algorithm_t alg2,
+                                                                     psa_key_usage_t usage_flags)
+{
+    mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
+    psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT;
+    const uint8_t *key = NULL;
+    size_t key_len = 0;
+
+    mbedtls_pk_helpers_get_predefined_key_data(key_type, key_bits, &key, &key_len);
+
+    psa_set_key_type(&attr, key_type);
+    psa_set_key_usage_flags(&attr, usage_flags);
+    psa_set_key_algorithm(&attr, alg);
+    psa_set_key_enrollment_algorithm(&attr, alg2);
+    PSA_ASSERT(psa_import_key(&attr, key, key_len, &key_id));
+
+exit:
+    return key_id;
+}
+
+int mbedtls_pk_helpers_populate_context(mbedtls_pk_context *pk, mbedtls_svc_key_id_t key_id,
+                                        pk_context_populate_method_t method)
+{
+    int ret = -1;
+
+    switch (method) {
+        case TEST_PK_WRAP_PSA:
+            TEST_EQUAL(mbedtls_pk_wrap_psa(pk, key_id), 0);
+            break;
+        case TEST_PK_COPY_FROM_PSA:
+            TEST_EQUAL(mbedtls_pk_copy_from_psa(key_id, pk), 0);
+            break;
+        case TEST_PK_COPY_PUBLIC_FROM_PSA:
+            TEST_EQUAL(mbedtls_pk_copy_public_from_psa(key_id, pk), 0);
+            break;
+        default:
+            TEST_FAIL("Unknown population method");
+    }
+
+    ret = 0;
+
+exit:
+    return ret;
+}
+
+#endif /* MBEDTLS_PK_C */
+
+#endif /* !TF_PSA_CRYPTO_VERSION_MAJOR */
diff -Nru mbedtls-3.6.5/framework/tests/src/psa_crypto_helpers.c mbedtls-3.6.6/framework/tests/src/psa_crypto_helpers.c
--- mbedtls-3.6.5/framework/tests/src/psa_crypto_helpers.c	2025-10-01 18:24:20.286515000 +0300
+++ mbedtls-3.6.6/framework/tests/src/psa_crypto_helpers.c	2026-03-27 12:34:57.796656400 +0200
@@ -8,6 +8,7 @@
  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  */
 
+#include "test_common.h"
 #include <test/helpers.h>
 #include <test/macros.h>
 #include <psa_crypto_slot_management.h>
diff -Nru mbedtls-3.6.5/framework/tests/src/psa_crypto_stubs.c mbedtls-3.6.6/framework/tests/src/psa_crypto_stubs.c
--- mbedtls-3.6.5/framework/tests/src/psa_crypto_stubs.c	2025-10-01 18:24:20.286625600 +0300
+++ mbedtls-3.6.6/framework/tests/src/psa_crypto_stubs.c	2026-03-27 12:34:57.796737700 +0200
@@ -9,6 +9,7 @@
  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  */
 
+#include "test_common.h"
 #include <psa/crypto.h>
 
 #if defined(MBEDTLS_PSA_CRYPTO_CLIENT) && !defined(MBEDTLS_PSA_CRYPTO_C)
diff -Nru mbedtls-3.6.5/framework/tests/src/psa_exercise_key.c mbedtls-3.6.6/framework/tests/src/psa_exercise_key.c
--- mbedtls-3.6.5/framework/tests/src/psa_exercise_key.c	2025-10-01 18:24:20.286774900 +0300
+++ mbedtls-3.6.6/framework/tests/src/psa_exercise_key.c	2026-03-27 12:34:57.796864700 +0200
@@ -7,6 +7,7 @@
  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  */
 
+#include "test_common.h"
 #include <test/helpers.h>
 #include <test/macros.h>
 #include <test/psa_exercise_key.h>
@@ -37,6 +38,15 @@
 #include <rsa_internal.h>
 #endif
 
+#if defined(__IAR_SYSTEMS_ICC__)
+/* Suppress a very overeager warning from IAR: it dislikes a forward goto
+ * that bypasses the initialization of a variable, even if that variable
+ * is not used after the jump. (This is perfectly valid C; it would only
+ * be invalid C if jumping into a block from outside that block.)
+ */
+#pragma diag_suppress=Pe546 // transfer of control bypasses initialization
+#endif
+
 #if defined(MBEDTLS_PSA_CRYPTO_SE_C)
 static int lifetime_is_dynamic_secure_element(psa_key_lifetime_t lifetime)
 {
diff -Nru mbedtls-3.6.5/framework/tests/src/psa_memory_poisoning_wrappers.c mbedtls-3.6.6/framework/tests/src/psa_memory_poisoning_wrappers.c
--- mbedtls-3.6.5/framework/tests/src/psa_memory_poisoning_wrappers.c	2025-10-01 18:24:20.286905000 +0300
+++ mbedtls-3.6.6/framework/tests/src/psa_memory_poisoning_wrappers.c	2026-03-27 12:34:57.796948400 +0200
@@ -4,6 +4,8 @@
  *  Copyright The Mbed TLS Contributors
  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  */
+#include "test_common.h"
+
 #include <test/memory.h>
 #include <test/psa_memory_poisoning_wrappers.h>
 
diff -Nru mbedtls-3.6.5/framework/tests/src/random.c mbedtls-3.6.6/framework/tests/src/random.c
--- mbedtls-3.6.5/framework/tests/src/random.c	2025-10-01 18:24:20.287027600 +0300
+++ mbedtls-3.6.6/framework/tests/src/random.c	2026-03-27 12:34:57.797031200 +0200
@@ -19,6 +19,7 @@
 #define _BSD_SOURCE 1
 #endif
 
+#include "test_common.h"
 #include <test/macros.h>
 #include <test/random.h>
 #include <string.h>
diff -Nru mbedtls-3.6.5/framework/tests/src/test_common.h mbedtls-3.6.6/framework/tests/src/test_common.h
--- mbedtls-3.6.5/framework/tests/src/test_common.h	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/tests/src/test_common.h	2026-03-27 12:34:57.797209000 +0200
@@ -0,0 +1,55 @@
+/**
+ * \file test_common.h
+ *
+ * \brief Common things for all Mbed TLS and TF-PSA-Crypto test code.
+ *
+ * Include this header first in all test C files.
+ */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef TEST_TEST_COMMON_H
+#define TEST_TEST_COMMON_H
+
+#if !defined(_POSIX_C_SOURCE)
+/* For standards-compliant access to
+ * clock_gettime(), gmtime_r(), ...
+ */
+#define _POSIX_C_SOURCE 200112L
+#endif
+
+/* With GNU libc, define all the things, even when compiling with -pedantic. */
+#if !defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
+
+/* On Mingw-w64, force the use of a C99-compliant printf() and friends.
+ * This is necessary on older versions of Mingw and/or Windows runtimes
+ * where snprintf does not always zero-terminate the buffer, and does
+ * not support formats such as "%zu" for size_t and "%lld" for long long.
+ */
+#if !defined(__USE_MINGW_ANSI_STDIO)
+#define __USE_MINGW_ANSI_STDIO 1
+#endif
+
+#if defined(__IAR_SYSTEMS_ICC__)
+/* With IAR, enable support for ::FILE functions in stdio.h.
+ */
+#define _DLIB_FILE_DESCRIPTOR 1
+#endif
+
+/* Make sure we have the library configuration, and anything else that
+ * is deemed necessary in test headers. */
+#include <test/build_info.h>
+
+/* Give test code access to internal macros of the library. */
+#if defined(TF_PSA_CRYPTO_VERSION_NUMBER)
+#include "tf_psa_crypto_common.h"
+#else
+#include "common.h"
+#endif
+
+#endif /* TEST_TEST_COMMON_H */
diff -Nru mbedtls-3.6.5/framework/tests/src/test_memory.c mbedtls-3.6.6/framework/tests/src/test_memory.c
--- mbedtls-3.6.5/framework/tests/src/test_memory.c	2025-10-01 18:24:20.287149000 +0300
+++ mbedtls-3.6.6/framework/tests/src/test_memory.c	2026-03-27 12:34:57.797344400 +0200
@@ -9,6 +9,7 @@
  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  */
 
+#include "test_common.h"
 #include <test/helpers.h>
 #include <test/macros.h>
 #include <test/memory.h>
diff -Nru mbedtls-3.6.5/framework/tests/src/threading_helpers.c mbedtls-3.6.6/framework/tests/src/threading_helpers.c
--- mbedtls-3.6.5/framework/tests/src/threading_helpers.c	2025-10-01 18:24:20.287305000 +0300
+++ mbedtls-3.6.6/framework/tests/src/threading_helpers.c	2026-03-27 12:34:57.797485600 +0200
@@ -5,6 +5,7 @@
  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  */
 
+#include "test_common.h"
 #include <test/helpers.h>
 #include <test/threading_helpers.h>
 #include <test/macros.h>
diff -Nru mbedtls-3.6.5/framework/util/generate_mldsa_tests.py mbedtls-3.6.6/framework/util/generate_mldsa_tests.py
--- mbedtls-3.6.5/framework/util/generate_mldsa_tests.py	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/util/generate_mldsa_tests.py	2026-03-27 12:34:57.797696400 +0200
@@ -0,0 +1,206 @@
+#!/usr/bin/env python3
+"""Generate ML-DSA test cases.
+"""
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+import sys
+from typing import Iterable, List, Optional
+
+# pip install dilithium-py
+import dilithium_py.ml_dsa #type: ignore
+
+import scripts_path # pylint: disable=unused-import
+from mbedtls_framework import test_case
+from mbedtls_framework import test_data_generation
+
+# ML_DSA instances for pure ML-DSA
+PURE = {
+    #44: dilithium_py.ml_dsa.ML_DSA_44,
+    #65: dilithium_py.ml_dsa.ML_DSA_65,
+    87: dilithium_py.ml_dsa.ML_DSA_87,
+}
+
+# ML_DSA instances for HashML-DSA
+HASH = {
+    #44: dilithium_py.ml_dsa.HASH_ML_DSA_44_WITH_SHA512,
+    #65: dilithium_py.ml_dsa.HASH_ML_DSA_65_WITH_SHA512,
+    87: dilithium_py.ml_dsa.HASH_ML_DSA_87_WITH_SHA512,
+}
+
+# Seeds (i.e. private keys) to test with.
+SEEDS = [
+    b'There was once upon a time a ...',
+    b'\x00' * 32,
+]
+
+class Key:
+    """An MLDSA key pair."""
+    #pylint: disable=too-few-public-methods
+
+    def __init__(self, kl: int, seed: bytes) -> None:
+        self.kl = kl #pylint: disable=invalid-name
+        self.seed = seed
+        self.public, self.secret = PURE[kl]._keygen_internal(seed)
+
+    def sign_message(self, message: bytes, deterministic: bool) -> bytes:
+        PURE[self.kl].set_drbg_seed(bytes(48))
+        return PURE[self.kl].sign(self.secret, message,
+                                  deterministic=deterministic)
+
+# Key pairs to test with.
+KEYS = {kl: [Key(kl, seed) for seed in SEEDS]
+        for kl in sorted(PURE.keys())}
+
+# Input messages to test with.
+MESSAGES = [
+    (b'This is a test', ''),
+    (b'', 'empty message'),
+    (b'\x00', '"\\x00"'),
+    (b'\x01', '"\\x01"'),
+    (b'ACBDEFGHIJ' * 100, '1000B'),
+]
+
+
+class API:
+    """Abstract base class for the interface of the test functions."""
+
+    @classmethod
+    def function(cls, func: str, kl: int) -> str:
+        raise NotImplementedError
+
+    @classmethod
+    def metadata_arguments(cls,
+                           kl: int,
+                           pair: bool,
+                           deterministic: Optional[bool]) -> List[str]:
+        raise NotImplementedError
+
+    @classmethod
+    def final_arguments(cls) -> List[str]:
+        return []
+
+    @classmethod
+    def secret_is_seed(cls) -> bool:
+        return True
+
+
+class PQCPAPI(API):
+    """Test mldsa-native entry points."""
+
+    @classmethod
+    def function(cls, func: str, kl: int) -> str:
+        return f'{func}_{kl}'
+
+    @classmethod
+    def metadata_arguments(cls,
+                           _kl: int,
+                           _pair: bool,
+                           _deterministic: Optional[bool]) -> List[str]:
+        return []
+
+    @classmethod
+    def secret_is_seed(cls) -> bool:
+        return False
+
+
+def one_mldsa_key_pair_from_seed(key: Key,
+                                 descr: str) -> test_case.TestCase:
+    """Construct one test case for mldsa-native keypair_internal()."""
+    tc = test_case.TestCase()
+    tc.set_function(f'key_pair_from_seed_{key.kl}')
+    tc.set_dependencies([f'TF_PSA_CRYPTO_PQCP_MLDSA_{key.kl}_ENABLED'])
+    tc.set_arguments([
+        test_case.hex_string(key.seed),
+        test_case.hex_string(key.secret),
+        test_case.hex_string(key.public),
+    ])
+    tc.set_description(f'MLDSA-{key.kl} key pair from seed {descr}')
+    return tc
+
+def gen_pqcp_key_management(kl: int) -> Iterable[test_case.TestCase]:
+    """Generate test cases for mldsa-native keypair_internal()."""
+    for i, key in enumerate(KEYS[kl], 1):
+        yield one_mldsa_key_pair_from_seed(key, f'key#{i}')
+
+def one_mldsa_sign_deterministic_pure(api: API,
+                                      key: Key,
+                                      message: bytes,
+                                      descr: str) -> test_case.TestCase:
+    """Construct one test case for deterministic signature."""
+    signature = key.sign_message(message, deterministic=True)
+    tc = test_case.TestCase()
+    tc.set_function(api.function('sign_deterministic_pure', key.kl))
+    tc.set_dependencies([f'TF_PSA_CRYPTO_PQCP_MLDSA_{key.kl}_ENABLED'])
+    tc.set_arguments(api.metadata_arguments(key.kl, True, True) + [
+        test_case.hex_string(key.seed if api.secret_is_seed() else key.secret),
+        test_case.hex_string(message),
+        test_case.hex_string(signature),
+    ] + api.final_arguments())
+    tc.set_description(f'MLDSA-{key.kl} sign deterministic {descr}')
+    return tc
+
+def one_mldsa_verify_pure(api: API,
+                          key: Key,
+                          message: bytes,
+                          deterministic: bool,
+                          descr: str) -> test_case.TestCase:
+    """Construct one test case for verification.
+
+    When deterministic is true, the test case is a deterministic signature.
+    When deterministic is false, the test case is some other valid signature.
+    """
+    signature = key.sign_message(message, deterministic=deterministic)
+    tc = test_case.TestCase()
+    tc.set_function(api.function('verify_pure', key.kl))
+    tc.set_dependencies([f'TF_PSA_CRYPTO_PQCP_MLDSA_{key.kl}_ENABLED'])
+    tc.set_arguments(api.metadata_arguments(key.kl, False, True) + [
+        test_case.hex_string(key.public),
+        test_case.hex_string(message),
+        test_case.hex_string(signature),
+    ] + api.final_arguments())
+    variant = "deterministic" if deterministic else "randomized"
+    tc.set_description(f'MLDSA-{key.kl} verify {variant} {descr}')
+    return tc
+
+def gen_mldsa_pure(api: API, kl: int) -> Iterable[test_case.TestCase]:
+    """Generate all test cases for pure ML-DSA signature and verification."""
+    for i, key in enumerate(KEYS[kl], 1):
+        yield one_mldsa_sign_deterministic_pure(api, key, MESSAGES[0][0],
+                                                f'key#{i}')
+    for message, descr in MESSAGES[1:]:
+        yield one_mldsa_sign_deterministic_pure(api, KEYS[kl][0], message,
+                                                f'key#1 {descr}')
+    for i, key in enumerate(KEYS[kl], 1):
+        yield one_mldsa_verify_pure(api, key, MESSAGES[0][0], True,
+                                    f'key#{i}')
+    for message, descr in MESSAGES[1:]:
+        yield one_mldsa_verify_pure(api, KEYS[kl][0], message, True,
+                                    f'key#1 {descr}')
+    for i, key in enumerate(KEYS[kl], 1):
+        yield one_mldsa_verify_pure(api, key, MESSAGES[0][0], False,
+                                    f'key#{i}')
+    for message, descr in MESSAGES[1:]:
+        yield one_mldsa_verify_pure(api, KEYS[kl][0], message, False,
+                                    f'key#1 {descr}')
+
+def gen_pqcp_mldsa_all() -> Iterable[test_case.TestCase]:
+    """Generate all test cases for mldsa-native."""
+    api = PQCPAPI()
+    for kl in sorted(KEYS.keys()):
+        yield from gen_pqcp_key_management(kl)
+        yield from gen_mldsa_pure(api, kl)
+
+class MLDSATestGenerator(test_data_generation.TestGenerator):
+    """Generate test cases for ML-DSA."""
+
+    def __init__(self, settings) -> None:
+        self.targets = {
+            'test_suite_pqcp_mldsa.dilithium_py': gen_pqcp_mldsa_all,
+        }
+        super().__init__(settings)
+
+
+if __name__ == '__main__':
+    test_data_generation.main(sys.argv[1:], __doc__, MLDSATestGenerator)
diff -Nru mbedtls-3.6.5/framework/util/requirements.txt mbedtls-3.6.6/framework/util/requirements.txt
--- mbedtls-3.6.5/framework/util/requirements.txt	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/util/requirements.txt	2026-03-27 12:34:57.797772600 +0200
@@ -0,0 +1,5 @@
+# Python module requirements for maintainer utilities
+
+# For generate_mldsa_tests.py
+pycryptodome
+dilithium-py >= 1.3.0; python_version >= "3.9"
diff -Nru mbedtls-3.6.5/framework/util/scripts_path.py mbedtls-3.6.6/framework/util/scripts_path.py
--- mbedtls-3.6.5/framework/util/scripts_path.py	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/framework/util/scripts_path.py	2026-03-27 12:34:57.797852500 +0200
@@ -0,0 +1,18 @@
+"""Add our Python library directory to the module search path.
+
+Usage:
+
+    import scripts_path # pylint: disable=unused-import
+    from mbedtls_framework import ...
+"""
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+#
+
+import os
+import sys
+
+sys.path.append(os.path.join(os.path.dirname(__file__),
+                             os.path.pardir,
+                             'scripts'))
diff -Nru mbedtls-3.6.5/include/CMakeLists.txt mbedtls-3.6.6/include/CMakeLists.txt
--- mbedtls-3.6.5/include/CMakeLists.txt	2025-10-14 19:12:36.856436300 +0300
+++ mbedtls-3.6.6/include/CMakeLists.txt	2026-03-27 19:00:27.530611500 +0200
@@ -6,11 +6,11 @@
     file(GLOB psa_headers "psa/*.h")
 
     install(FILES ${headers}
-        DESTINATION include/mbedtls
+        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mbedtls
         PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
 
     install(FILES ${psa_headers}
-        DESTINATION include/psa
+        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/psa
         PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
 
 endif(INSTALL_MBEDTLS_HEADERS)
diff -Nru mbedtls-3.6.5/include/mbedtls/asn1write.h mbedtls-3.6.6/include/mbedtls/asn1write.h
--- mbedtls-3.6.5/include/mbedtls/asn1write.h	2025-10-14 19:12:36.857833100 +0300
+++ mbedtls-3.6.6/include/mbedtls/asn1write.h	2026-03-27 19:00:27.531493400 +0200
@@ -381,10 +381,10 @@
                                                        const unsigned char *val,
                                                        size_t val_len);
 
+#endif /* MBEDTLS_ASN1_WRITE_C */
+
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* MBEDTLS_ASN1_WRITE_C */
-
 #endif /* MBEDTLS_ASN1_WRITE_H */
diff -Nru mbedtls-3.6.5/include/mbedtls/build_info.h mbedtls-3.6.6/include/mbedtls/build_info.h
--- mbedtls-3.6.5/include/mbedtls/build_info.h	2025-10-14 19:12:36.859993200 +0300
+++ mbedtls-3.6.6/include/mbedtls/build_info.h	2026-03-27 19:00:27.533633000 +0200
@@ -26,16 +26,16 @@
  */
 #define MBEDTLS_VERSION_MAJOR  3
 #define MBEDTLS_VERSION_MINOR  6
-#define MBEDTLS_VERSION_PATCH  5
+#define MBEDTLS_VERSION_PATCH  6
 
 /**
  * The single version number has the following structure:
  *    MMNNPP00
  *    Major version | Minor version | Patch version
  */
-#define MBEDTLS_VERSION_NUMBER         0x03060500
-#define MBEDTLS_VERSION_STRING         "3.6.5"
-#define MBEDTLS_VERSION_STRING_FULL    "Mbed TLS 3.6.5"
+#define MBEDTLS_VERSION_NUMBER         0x03060600
+#define MBEDTLS_VERSION_STRING         "3.6.6"
+#define MBEDTLS_VERSION_STRING_FULL    "Mbed TLS 3.6.6"
 
 /* Macros for build-time platform detection */
 
diff -Nru mbedtls-3.6.5/include/mbedtls/config_adjust_legacy_crypto.h mbedtls-3.6.6/include/mbedtls/config_adjust_legacy_crypto.h
--- mbedtls-3.6.5/include/mbedtls/config_adjust_legacy_crypto.h	2025-10-14 19:12:36.862520000 +0300
+++ mbedtls-3.6.6/include/mbedtls/config_adjust_legacy_crypto.h	2026-03-27 19:00:27.535348400 +0200
@@ -48,6 +48,49 @@
 #endif
 #endif /* _MINGW32__ || (_MSC_VER && (_MSC_VER <= 1900)) */
 
+/* The number of "true" entropy sources (excluding NV seed).
+ * This must be consistent with mbedtls_entropy_init() in entropy.c.
+ */
+/* Define auxiliary macros, because in standard C, defined(xxx) is only
+ * allowed directly on an #if or #elif line, not in recursive expansion. */
+#if defined(MBEDTLS_NO_PLATFORM_ENTROPY)
+#define MBEDTLS_PLATFORM_ENTROPY_ENABLED 0
+#else
+#define MBEDTLS_PLATFORM_ENTROPY_ENABLED 1
+#endif
+#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
+#define MBEDTLS_ENTROPY_HARDWARE_ALT_DEFINED 1
+#else
+#define MBEDTLS_ENTROPY_HARDWARE_ALT_DEFINED 0
+#endif
+
+#define MBEDTLS_ENTROPY_TRUE_SOURCES ( \
+        MBEDTLS_ENTROPY_HARDWARE_ALT_DEFINED + \
+        MBEDTLS_PLATFORM_ENTROPY_ENABLED + \
+        0)
+
+/* Whether there is at least one entropy source for the entropy module.
+ *
+ * Note that when MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG is enabled, the entropy
+ * module is unused and the configuration will typically not include any
+ * entropy source, so this macro will typically remain undefined.
+ */
+#if defined(MBEDTLS_ENTROPY_NV_SEED)
+#define MBEDTLS_ENTROPY_HAVE_SOURCES (MBEDTLS_ENTROPY_TRUE_SOURCES + 1)
+#elif MBEDTLS_ENTROPY_TRUE_SOURCES != 0
+#define MBEDTLS_ENTROPY_HAVE_SOURCES MBEDTLS_ENTROPY_TRUE_SOURCES
+#else
+#undef MBEDTLS_ENTROPY_HAVE_SOURCES
+#endif
+
+/* Test function dependencies can only check with defined(),
+ * not other preprocessor expressions. */
+#if MBEDTLS_ENTROPY_TRUE_SOURCES > 0
+#define MBEDTLS_ENTROPY_HAVE_TRUE_SOURCES
+#else
+#undef MBEDTLS_ENTROPY_HAVE_TRUE_SOURCES
+#endif
+
 /* If MBEDTLS_PSA_CRYPTO_C is defined, make sure MBEDTLS_PSA_CRYPTO_CLIENT
  * is defined as well to include all PSA code.
  */
diff -Nru mbedtls-3.6.5/include/mbedtls/ctr_drbg.h mbedtls-3.6.6/include/mbedtls/ctr_drbg.h
--- mbedtls-3.6.5/include/mbedtls/ctr_drbg.h	2025-10-14 19:12:36.864071100 +0300
+++ mbedtls-3.6.6/include/mbedtls/ctr_drbg.h	2026-03-27 19:00:27.536519800 +0200
@@ -186,8 +186,7 @@
     unsigned char MBEDTLS_PRIVATE(counter)[16];  /*!< The counter (V). */
     int MBEDTLS_PRIVATE(reseed_counter);         /*!< The reseed counter.
                                                   * This is the number of requests that have
-                                                  * been made since the last (re)seeding,
-                                                  * minus one.
+                                                  * been made since the last (re)seeding.
                                                   * Before the initial seeding, this field
                                                   * contains the amount of entropy in bytes
                                                   * to use as a nonce for the initial seeding,
diff -Nru mbedtls-3.6.5/include/mbedtls/debug.h mbedtls-3.6.6/include/mbedtls/debug.h
--- mbedtls-3.6.5/include/mbedtls/debug.h	2025-10-14 19:12:36.864617800 +0300
+++ mbedtls-3.6.6/include/mbedtls/debug.h	2026-03-27 19:00:27.536721700 +0200
@@ -111,7 +111,7 @@
 #if defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER < 1900)
    #include <inttypes.h>
    #define MBEDTLS_PRINTF_SIZET     PRIuPTR
-   #define MBEDTLS_PRINTF_LONGLONG  "I64d"
+   #define MBEDTLS_PRINTF_LONGLONG  PRId64
 #else \
     /* defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER < 1900) */
    #define MBEDTLS_PRINTF_SIZET     "zu"
diff -Nru mbedtls-3.6.5/include/mbedtls/ecdh.h mbedtls-3.6.6/include/mbedtls/ecdh.h
--- mbedtls-3.6.5/include/mbedtls/ecdh.h	2025-10-14 19:12:36.865654000 +0300
+++ mbedtls-3.6.6/include/mbedtls/ecdh.h	2026-03-27 19:00:27.537408000 +0200
@@ -6,7 +6,7 @@
  * The Elliptic Curve Diffie-Hellman (ECDH) protocol is an anonymous
  * key agreement protocol allowing two parties to establish a shared
  * secret over an insecure channel. Each party must have an
- * elliptic-curve public–private key pair.
+ * elliptic-curve public private key pair.
  *
  * For more information, see <em>NIST SP 800-56A Rev. 2: Recommendation for
  * Pair-Wise Key Establishment Schemes Using Discrete Logarithm
diff -Nru mbedtls-3.6.5/include/mbedtls/mbedtls_config.h mbedtls-3.6.6/include/mbedtls/mbedtls_config.h
--- mbedtls-3.6.5/include/mbedtls/mbedtls_config.h	2025-10-14 19:12:36.868876500 +0300
+++ mbedtls-3.6.6/include/mbedtls/mbedtls_config.h	2026-03-27 19:00:27.539453500 +0200
@@ -1204,6 +1204,20 @@
  * This is useful if your platform does not support
  * standards like the /dev/urandom or Windows CryptoAPI.
  *
+ * If you enable this macro, you will probably need to enable
+ * #MBEDTLS_ENTROPY_HARDWARE_ALT and provide a function
+ * mbedtls_hardware_poll().
+ *
+ * \note The default platform entropy function supports the following
+ *       sources:
+ *       - getrandom() on Linux (if syscall() is available at compile time);
+ *       - getrandom() on FreeBSD and DragonFlyBSD (if available at compile
+ *         time);
+ *       - `sysctl(KERN_ARND)` on FreeBSD and NetBSD;
+ *       - #MBEDTLS_PLATFORM_DEV_RANDOM on Unix-like platforms
+ *         (unless one of the above is used);
+ *       - BCryptGenRandom() on Windows.
+ *
  * Uncomment this macro to disable the built-in platform entropy functions.
  */
 //#define MBEDTLS_NO_PLATFORM_ENTROPY
@@ -4140,6 +4154,37 @@
 //#define MBEDTLS_PLATFORM_MS_TIME_TYPE_MACRO   int64_t //#define MBEDTLS_PLATFORM_MS_TIME_TYPE_MACRO   int64_t /**< Default milliseconds time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled. It must be signed, and at least 64 bits. If it is changed from the default, MBEDTLS_PRINTF_MS_TIME must be updated to match.*/
 //#define MBEDTLS_PRINTF_MS_TIME    PRId64 /**< Default fmt for printf. That's avoid compiler warning if mbedtls_ms_time_t is redefined */
 
+/** \def MBEDTLS_PLATFORM_DEV_RANDOM
+ *
+ * Path to a special file that returns cryptographic-quality random bytes
+ * when read. This is used by the default platform entropy source on
+ * non-Windows platforms unless a dedicated system call is available
+ * (see #MBEDTLS_NO_PLATFORM_ENTROPY).
+ *
+ * The default value is `/dev/random`, which is suitable on most platforms
+ * other than Linux. On Linux, either `/dev/random` or `/dev/urandom`
+ * may be the right choice, depending on the circumstances:
+ *
+ * - If possible, the library will use the getrandom() system call,
+ *   which is preferable, and #MBEDTLS_PLATFORM_DEV_RANDOM is not used.
+ * - If there is a dedicated hardware entropy source (e.g. RDRAND on x86
+ *   processors), then both `/dev/random` and `/dev/urandom` are fine.
+ * - `/dev/random` is always secure. However, with kernels older than 5.6,
+ *   `/dev/random` often blocks unnecessarily if there is no dedicated
+ *   hardware entropy source.
+ * - `/dev/urandom` never blocks. However, it may return predictable data
+ *   if it is used early after the kernel boots, especially on embedded
+ *   devices without an interactive user.
+ *
+ * Thus you should change the value to `/dev/urandom` if your application
+ * definitely won't be used on a device running Linux without a dedicated
+ * entropy source early during or after boot.
+ *
+ * This is the default value of ::mbedtls_platform_dev_random, which
+ * can be changed at run time.
+ */
+//#define MBEDTLS_PLATFORM_DEV_RANDOM "/dev/random"
+
 /** \def MBEDTLS_CHECK_RETURN
  *
  * This macro is used at the beginning of the declaration of a function
diff -Nru mbedtls-3.6.5/include/mbedtls/pk.h mbedtls-3.6.6/include/mbedtls/pk.h
--- mbedtls-3.6.5/include/mbedtls/pk.h	2025-10-14 19:12:36.872660400 +0300
+++ mbedtls-3.6.6/include/mbedtls/pk.h	2026-03-27 19:00:27.542005500 +0200
@@ -218,8 +218,11 @@
  * \brief           Public key container
  */
 typedef struct mbedtls_pk_context {
-    const mbedtls_pk_info_t *MBEDTLS_PRIVATE(pk_info);    /**< Public key information         */
-    void *MBEDTLS_PRIVATE(pk_ctx);                        /**< Underlying public key context  */
+    /** Method table */
+    const mbedtls_pk_info_t *MBEDTLS_PRIVATE(pk_info);
+    /** Underlying type-specific key context */
+    void *MBEDTLS_PRIVATE(pk_ctx);
+
     /* The following field is used to store the ID of a private key in the
      * following cases:
      * - opaque key when MBEDTLS_USE_PSA_CRYPTO is defined
@@ -838,7 +841,7 @@
  *                  length up to the hash length), depending on the padding mode
  *                  in the underlying RSA context. For a pk object constructed
  *                  by parsing, this is PKCS#1 v1.5 by default. Use
- *                  mbedtls_pk_verify_ext() to explicitly select a different
+ *                  mbedtls_pk_sign_ext() to explicitly select a different
  *                  algorithm.
  *
  * \return          0 on success, or a specific error code.
diff -Nru mbedtls-3.6.5/include/mbedtls/platform.h mbedtls-3.6.6/include/mbedtls/platform.h
--- mbedtls-3.6.5/include/mbedtls/platform.h	2025-10-14 19:12:36.873770000 +0300
+++ mbedtls-3.6.6/include/mbedtls/platform.h	2026-03-27 19:00:27.542651400 +0200
@@ -385,6 +385,37 @@
 #define MBEDTLS_EXIT_FAILURE 1
 #endif
 
+#if defined(MBEDTLS_ENTROPY_C) && \
+    !defined(MBEDTLS_NO_PLATFORM_ENTROPY) && \
+    !(defined(_WIN32) && !defined(EFIX64) && !defined(EFI32))
+/* Platforms where MBEDTLS_PLATFORM_DEV_RANDOM is used
+ * unless a dedicated system call is available both at
+ * compile time and at run time. */
+#define MBEDTLS_PLATFORM_HAVE_DEV_RANDOM
+#endif
+
+#if !defined(MBEDTLS_PLATFORM_DEV_RANDOM)
+#define MBEDTLS_PLATFORM_DEV_RANDOM "/dev/random"
+#endif
+
+/* Arrange for mbedtls_platform_dev_random to always be visible to
+ * Doxygen, because it's linked from the documentation of
+ * MBEDTLS_PLATFORM_DEV_RANDOM and that documentation can be visible
+ * even in configurations where it isn't used. */
+#if defined(MBEDTLS_PLATFORM_HAVE_DEV_RANDOM) || defined(__DOXYGEN__)
+/**
+ * Path to a special file that returns cryptographic-quality random bytes
+ * when read.
+ *
+ * This variable is only declared on platforms where it is used.
+ * It is available when the macro `MBEDTLS_PLATFORM_HAVE_DEV_RANDOM` is defined.
+ *
+ * The default value is #MBEDTLS_PLATFORM_DEV_RANDOM.
+ * See the documentation of this option for guidance.
+ */
+extern const char *mbedtls_platform_dev_random;
+#endif
+
 /*
  * The function pointers for reading from and writing a seed file to
  * Non-Volatile storage (NV) in a platform-independent way
diff -Nru mbedtls-3.6.5/include/mbedtls/ssl.h mbedtls-3.6.6/include/mbedtls/ssl.h
--- mbedtls-3.6.5/include/mbedtls/ssl.h	2025-10-14 19:12:36.877379400 +0300
+++ mbedtls-3.6.6/include/mbedtls/ssl.h	2026-03-27 19:00:27.545340800 +0200
@@ -3357,6 +3357,27 @@
  *                 On server, this can be used for alternative implementations
  *                 of session cache or session tickets.
  *
+ * \warning        The serialized data contains highly sensitive material,
+ *                 including a resumption key (TLS 1.3) or the master secret
+ *                 (TLS 1.2) from which the session's traffic keys are derived.
+ *
+ *                 The serialized data is not cryptographically protected.
+ *                 It is the responsibility of the user of the
+ *                 mbedtls_ssl_session_save() and
+ *                 mbedtls_ssl_session_load() APIs to ensure both its
+ *                 confidentiality and integrity while stored or transported.
+ *
+ *                 A breach of confidentiality could result in full compromise
+ *                 of the associated TLS session, including loss of
+ *                 confidentiality and integrity of past and future
+ *                 application data protected under that session.
+ *
+ *                 A breach of integrity may allow modification of the
+ *                 serialized data prior to restoration. As it represents
+ *                 trusted internal context, tampering could potentially result
+ *                 in arbitrary code execution or other severe compromise of
+ *                 the hosting process.
+ *
  * \warning        If a peer certificate chain is associated with the session,
  *                 the serialized state will only contain the peer's
  *                 end-entity certificate and the result of the chain
@@ -3395,6 +3416,19 @@
  *
  * \see            mbedtls_ssl_session_load()
  *
+ * \warning        The serialized data contains highly sensitive material,
+ *                 including a resumption key (TLS 1.3) or the master secret
+ *                 (TLS 1.2) from which the session's traffic keys are derived.
+ *
+ *                 The serialized data is not cryptographically protected.
+ *                 It is the responsibility of the user of the
+ *                 mbedtls_ssl_session_save() and
+ *                 mbedtls_ssl_session_load() APIs to ensure both its
+ *                 confidentiality and integrity while stored or transported.
+ *
+ *                 See the mbedtls_ssl_session_load() documentation for
+ *                 additional information.
+ *
  * \param session  The session structure to be saved.
  * \param buf      The buffer to write the serialized data to. It must be a
  *                 writeable buffer of at least \p buf_len bytes, or may be \c
@@ -5084,13 +5118,6 @@
  *                 supported with some limitations (those limitations do
  *                 not apply to DTLS, where defragmentation is fully
  *                 supported):
- *                 - On an Mbed TLS server that only accepts TLS 1.2,
- *                   the initial ClientHello message must not be fragmented.
- *                   A TLS 1.2 ClientHello may be fragmented if the server
- *                   also accepts TLS 1.3 connections (meaning
- *                   that #MBEDTLS_SSL_PROTO_TLS1_3 enabled, and the
- *                   accepted versions have not been restricted with
- *                   mbedtls_ssl_conf_max_tls_version() or the like).
  *                 - The first fragment of a handshake message must be
  *                   at least 4 bytes long.
  *                 - Non-handshake records must not be interleaved between
@@ -5577,6 +5604,19 @@
  *
  * \see            mbedtls_ssl_context_load()
  *
+ * \warning        The serialized data contains highly sensitive material,
+ *                 including the master secret from which the session's traffic
+ *                 keys are derived.
+ *
+ *                 The serialized data is not cryptographically protected.
+ *                 It is the responsibility of the user of the
+ *                 mbedtls_ssl_context_save() and
+ *                 mbedtls_ssl_context_load() APIs to ensure both its
+ *                 confidentiality and integrity while stored or transported.
+ *
+ *                 See the mbedtls_ssl_context_load() documentation for
+ *                 additional information.
+ *
  * \note           The serialized data only contains the data that is
  *                 necessary to resume the connection: negotiated protocol
  *                 options, session identifier, keys, etc.
@@ -5643,6 +5683,27 @@
  *                 more than one context would cause severe security failures
  *                 including but not limited to loss of confidentiality.
  *
+ * \warning        The serialized data contains highly sensitive material,
+ *                 including the master secret from which the session's traffic
+ *                 keys are derived.
+ *
+ *                 The serialized data is not cryptographically protected.
+ *                 It is the responsibility of the user of the
+ *                 mbedtls_ssl_context_save() and
+ *                 mbedtls_ssl_context_load() APIs to ensure both its
+ *                 confidentiality and integrity while stored or transported.
+ *
+ *                 A breach of confidentiality could result in full compromise
+ *                 of the associated TLS session, including loss of
+ *                 confidentiality and integrity of past and future
+ *                 application data protected under that session.
+ *
+ *                 A breach of integrity may allow modification of the
+ *                 serialized data prior to restoration. As it represents
+ *                 trusted internal context, tampering could potentially result
+ *                 in arbitrary code execution or other severe compromise of
+ *                 the hosting process.
+ *
  * \note           Before calling this function, the SSL context must be
  *                 prepared in one of the two following ways. The first way is
  *                 to take a context freshly initialised with
diff -Nru mbedtls-3.6.5/include/psa/crypto_extra.h mbedtls-3.6.6/include/psa/crypto_extra.h
--- mbedtls-3.6.5/include/psa/crypto_extra.h	2025-10-14 19:12:36.886370700 +0300
+++ mbedtls-3.6.6/include/psa/crypto_extra.h	2026-03-27 19:00:27.550212400 +0200
@@ -33,13 +33,32 @@
 #endif
 
 /* If the size of static key slots is not explicitly defined by the user, then
- * set it to the maximum between PSA_EXPORT_KEY_PAIR_OR_PUBLIC_MAX_SIZE and
- * PSA_CIPHER_MAX_KEY_LENGTH.
- * See mbedtls_config.h for the definition. */
+ * try to guess it based on some of the most common the key types enabled in the build.
+ * See mbedtls_config.h for the definition of MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE. */
 #if !defined(MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE)
-#define MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE  \
-    ((PSA_EXPORT_KEY_PAIR_OR_PUBLIC_MAX_SIZE > PSA_CIPHER_MAX_KEY_LENGTH) ? \
-     PSA_EXPORT_KEY_PAIR_OR_PUBLIC_MAX_SIZE : PSA_CIPHER_MAX_KEY_LENGTH)
+
+#define MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE 1
+
+#if PSA_EXPORT_ASYMMETRIC_KEY_MAX_SIZE > MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE
+#undef MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE
+#define MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE PSA_EXPORT_ASYMMETRIC_KEY_MAX_SIZE
+#endif
+
+/* This covers ciphers, AEADs and CMAC. */
+#if PSA_CIPHER_MAX_KEY_LENGTH > MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE
+#undef MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE
+#define MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE PSA_CIPHER_MAX_KEY_LENGTH
+#endif
+
+/* For HMAC, it's typical but not mandatory to use a key size that is equal to
+ * the hash size. */
+#if defined(PSA_WANT_ALG_HMAC)
+#if PSA_HASH_MAX_SIZE > MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE
+#undef MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE
+#define MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE PSA_HASH_MAX_SIZE
+#endif
+#endif /* PSA_WANT_ALG_HMAC */
+
 #endif /* !MBEDTLS_PSA_STATIC_KEY_SLOT_BUFFER_SIZE*/
 
 /** \addtogroup attributes
@@ -434,7 +453,7 @@
 /**@}*/
 
 
-/** \defgroup psa_external_rng External random generator
+/** \defgroup psa_rng Random generator
  * @{
  */
 
@@ -483,6 +502,155 @@
     uint8_t *output, size_t output_size, size_t *output_length);
 #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
 
+/** Force an immediate reseed of the PSA random generator.
+ *
+ * The entropy source(s) are the ones configured at compile time.
+ *
+ * The random generator is always seeded automatically before use, and
+ * it is reseeded as needed based on the configured policy, so most
+ * applications do not need to call this function.
+ *
+ * The main reason to call this function is in scenarios where the process
+ * state is cloned (i.e. duplicated) while the random generator is active.
+ * In such scenarios, you must call this function in every clone of
+ * the original process before performing any cryptographic operation
+ * that uses randomness. (Note that any operation that uses a private or
+ * secret key may use randomness internally even if the result is not
+ * randomized, but hashing and signature verification are ok.) For example:
+ *
+ * - If the process is part of a live virtual machine that is cloned,
+ *   call this function after cloning so that the new instance has a
+ *   distinct random generator state.
+ * - If the process is part of a hibernated image that may be resumed
+ *   multiple times, call this function after resuming so that each
+ *   resumed instance has a distinct random generator state.
+ * - If the process is cloned through the fork() system call, the
+ *   child process should call this function before using the random
+ *   generator.
+ *
+ * An additional consideration applies in configurations where there is no
+ * actual entropy source, only a nonvolatile seed (i.e.
+ * #MBEDTLS_ENTROPY_NV_SEED is enabled, #MBEDTLS_NO_PLATFORM_ENTROPY is
+ * enabled and #MBEDTLS_ENTROPY_HARDWARE_ALT is disabled).
+ * In such configurations, simply calling psa_random_reseed() in multiple
+ * cloned processes would result in the same random generator state in
+ * all the clones. To avoid this, in such configurations, you must pass
+ * a unique \p perso string in every clone.
+ *
+ * \note  This function has no effect when the compilation option
+ *        #MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG is enabled.
+ *
+ * \note  In client-server builds, this function may not be available
+ *        from clients, since the decision to reseed is generally based
+ *        on the server state.
+ *
+ * \note  If the entropy source fails, the random generator remains usable:
+ *        subsequent calls to generate random data will succeed until
+ *        the random generator itself decides to reseed. If you want to
+ *        force a reseed, either treat the failure as a fatal error,
+ *        or call psa_random_deplete() instead of this function (or in
+ *        addition).
+ *
+ * \param[in] perso     A personalization string, i.e. a byte string to
+ *                      inject into the random generator state in addition
+ *                      to entropy obtained from the normal source(s).
+ *                      In most cases, it is fine for \c perso to be
+ *                      empty. The main use case for a personalization
+ *                      string is when the random generator state is cloned,
+ *                      as described above, and there is no actual entropy
+ *                      source.
+ * \param perso_size    Length of \c perso in bytes.
+ *
+ * \retval #PSA_SUCCESS
+ *         The reseed succeeded.
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The PSA random generator is not active.
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ *         PSA uses an external random generator because the compilation
+ *         option #MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG is enabled. This
+ *         configuration does not support explicit reseeding.
+ * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY
+ *         The entropy source failed.
+ */
+psa_status_t psa_random_reseed(const uint8_t *perso, size_t perso_size);
+
+/** Force a reseed of the PSA random generator the next time it is used.
+ *
+ * The entropy source(s) are the ones configured at compile time.
+ *
+ * The random generator is always seeded automatically before use, and
+ * it is reseeded as needed based on the configured policy, so most
+ * applications do not need to call this function.
+ *
+ * This function has a similar purpose as psa_random_reseed(),
+ * but the reseed will happen the next time the random generator is used.
+ * The advantage of this function is that it does not fail unless the
+ * system is in an unintended state, so it can be used in contexts where
+ * propagating errors is difficult.
+ *
+ * \note This function has no effect when #MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+ *       is enabled.
+ *
+ * \note If prediction resistance is enabled (either explicitly, or because
+ *       the reseed interval is set to 1), calling this function is
+ *       unnecessary since the random generator will always reseed anyway.
+ *
+ * \retval #PSA_SUCCESS
+ *         The reseed succeeded.
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The PSA random generator is not active.
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ *         PSA uses an external random generator because the compilation
+ *         option #MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG is enabled. This
+ *         configuration does not support explicit reseeding.
+ */
+psa_status_t psa_random_deplete(void);
+
+/** Enable or disable prediction resistance in the PSA random generator.
+ *
+ * When prediction resistance is enabled, the random generator
+ * injects extra entropy before each request regardless of its size.
+ * As a consequence, a temporary compromise of the random generator
+ * state does not, by itself, compromise future steps.
+ * Furthermore, duplicating the random generator state (because the
+ * running application instance is cloned) is safe since it will
+ * not lead to identical random generator outputs in the clones.
+ *
+ * When prediction resistance is disabled, the random generator injects
+ * extra entropy periodically only as determined by
+ * #MBEDTLS_CTR_DRBG_RESEED_INTERVAL if #MBEDTLS_CTR_DRBG_C
+ * is enabled, or #MBEDTLS_HMAC_DRBG_RESEED_INTERVAL otherwise.
+ *
+ * Prediction resistance is disabled by default, although setting
+ * #MBEDTLS_CTR_DRBG_RESEED_INTERVAL or #MBEDTLS_HMAC_DRBG_RESEED_INTERVAL
+ * to \c 1 satisfies the prediction resistance property even when the
+ * option is disabled.
+ *
+ * \note This function has no effect when #MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+ *       is enabled.
+ *
+ * \note Prediction resistance cannot be enabled when the only entropy source
+ *       is a nonvolatile seed, since prediction resistance is effectively
+ *       impossible to achieve without actual entropy.
+ *
+ * \param enabled   \c 1 to enable prediction resistance.
+ *                  \c 0 to disable prediction resistance.
+ *
+ * \retval #PSA_SUCCESS
+ *         The PSA random generator is active, and prediction resistance
+ *         has been changed to the desired option.
+ * \retval #PSA_ERROR_BAD_STATE
+ *         The PSA random generator is not active.
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ *         \p enabled is not valid.
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ *         PSA uses an external random generator because the compilation
+ *         option #MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG is enabled.
+ *         Or, the random generator only has a nonvolatile seed but no entropy
+ *         source, and prediction resistance has been requested.
+ */
+psa_status_t psa_random_set_prediction_resistance(unsigned enabled);
+
 /**@}*/
 
 /** \defgroup psa_builtin_keys Built-in keys
diff -Nru mbedtls-3.6.5/include/psa/crypto_sizes.h mbedtls-3.6.6/include/psa/crypto_sizes.h
--- mbedtls-3.6.5/include/psa/crypto_sizes.h	2025-10-14 19:12:36.888776000 +0300
+++ mbedtls-3.6.6/include/psa/crypto_sizes.h	2026-03-27 19:00:27.551015900 +0200
@@ -912,15 +912,11 @@
  *         If the parameters are not valid, the return value is unspecified.
  */
 #define PSA_EXPORT_KEY_OUTPUT_SIZE(key_type, key_bits)                                              \
-    (PSA_KEY_TYPE_IS_UNSTRUCTURED(key_type) ? PSA_BITS_TO_BYTES(key_bits) :                         \
-     PSA_KEY_TYPE_IS_DH(key_type) ? PSA_BITS_TO_BYTES(key_bits) :                                   \
-     (key_type) == PSA_KEY_TYPE_RSA_KEY_PAIR ? PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(key_bits) :     \
+    ((key_type) == PSA_KEY_TYPE_RSA_KEY_PAIR ? PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(key_bits) :     \
      (key_type) == PSA_KEY_TYPE_RSA_PUBLIC_KEY ? PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(key_bits) : \
-     (key_type) == PSA_KEY_TYPE_DSA_KEY_PAIR ? PSA_KEY_EXPORT_DSA_KEY_PAIR_MAX_SIZE(key_bits) :     \
-     (key_type) == PSA_KEY_TYPE_DSA_PUBLIC_KEY ? PSA_KEY_EXPORT_DSA_PUBLIC_KEY_MAX_SIZE(key_bits) : \
      PSA_KEY_TYPE_IS_ECC_KEY_PAIR(key_type) ? PSA_KEY_EXPORT_ECC_KEY_PAIR_MAX_SIZE(key_bits) :      \
      PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(key_type) ? PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits) :  \
-     0u)
+     PSA_BITS_TO_BYTES(key_bits)) /*unstructured; FFDH public or private*/
 
 /** Sufficient output buffer size for psa_export_public_key().
  *
@@ -1038,10 +1034,16 @@
     PSA_KEY_EXPORT_FFDH_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_FFDH_MAX_KEY_BITS)
 #endif
 
-#define PSA_EXPORT_KEY_PAIR_OR_PUBLIC_MAX_SIZE \
+/* This is the name that was standardized in PSA Crypto v1.3 */
+#define PSA_EXPORT_ASYMMETRIC_KEY_MAX_SIZE \
     ((PSA_EXPORT_KEY_PAIR_MAX_SIZE > PSA_EXPORT_PUBLIC_KEY_MAX_SIZE) ? \
      PSA_EXPORT_KEY_PAIR_MAX_SIZE : PSA_EXPORT_PUBLIC_KEY_MAX_SIZE)
 
+/* This is our old custom name from before it was in the spec,
+ * keep it around in case users were relying on it. */
+#define PSA_EXPORT_KEY_PAIR_OR_PUBLIC_MAX_SIZE \
+    PSA_EXPORT_ASYMMETRIC_KEY_MAX_SIZE
+
 /** Sufficient output buffer size for psa_raw_key_agreement().
  *
  * This macro returns a compile-time constant if its arguments are
diff -Nru mbedtls-3.6.5/library/aesce.c mbedtls-3.6.6/library/aesce.c
--- mbedtls-3.6.5/library/aesce.c	2025-10-14 19:12:36.892524700 +0300
+++ mbedtls-3.6.6/library/aesce.c	2026-03-27 19:00:27.553899000 +0200
@@ -16,15 +16,16 @@
 #endif
 
 #if defined(MBEDTLS_AESCE_ARCH_IS_ARMV8_A) && !defined(__ARM_FEATURE_CRYPTO)
-/* TODO: Re-consider above after https://reviews.llvm.org/D131064 merged.
- *
- * The intrinsic declaration are guarded by predefined ACLE macros in clang:
+/* The intrinsic declaration are guarded by predefined ACLE macros in clang:
  * these are normally only enabled by the -march option on the command line.
  * By defining the macros ourselves we gain access to those declarations without
  * requiring -march on the command line.
  *
  * `arm_neon.h` is included by common.h, so we put these defines
- * at the top of this file, before any includes.
+ * at the top of this file, before any includes. This is necessary with
+ * Clang <=15.x. With Clang 16.0 and above, these macro definitions are
+ * no longer required, but they're harmless. See
+ * https://reviews.llvm.org/D131064
  */
 #define __ARM_FEATURE_CRYPTO 1
 /* See: https://arm-software.github.io/acle/main/acle.html#cryptographic-extensions
@@ -38,11 +39,12 @@
 
 #endif /* defined(__clang__) &&  (__clang_major__ >= 4) */
 
-#include <string.h>
 #include "common.h"
 
 #if defined(MBEDTLS_AESCE_C)
 
+#include <string.h>
+
 #include "aesce.h"
 
 #if defined(MBEDTLS_AESCE_HAVE_CODE)
@@ -86,7 +88,11 @@
 #           define MBEDTLS_POP_TARGET_PRAGMA
 #       endif
 #   elif defined(__clang__)
-#       pragma clang attribute push (__attribute__((target("aes"))), apply_to=function)
+#       if __clang_major__ < 7
+#           pragma clang attribute push (__attribute__((target("crypto"))), apply_to=function)
+#       else
+#           pragma clang attribute push (__attribute__((target("aes"))), apply_to=function)
+#       endif
 #       define MBEDTLS_POP_TARGET_PRAGMA
 #   elif defined(__GNUC__)
 #       pragma GCC push_options
diff -Nru mbedtls-3.6.5/library/alignment.h mbedtls-3.6.6/library/alignment.h
--- mbedtls-3.6.5/library/alignment.h	2025-10-14 19:12:36.893766600 +0300
+++ mbedtls-3.6.6/library/alignment.h	2026-03-27 19:00:27.555654000 +0200
@@ -15,6 +15,7 @@
 #include <string.h>
 #include <stdlib.h>
 
+#if !defined(MBEDTLS_ALIGNMENT_DISABLE_EFFICENT_UNALIGNED_ACCESS)  //no-check-names
 /*
  * Define MBEDTLS_EFFICIENT_UNALIGNED_ACCESS for architectures where unaligned memory
  * accesses are known to be efficient.
@@ -35,7 +36,9 @@
  * device memory).
  */
 #define MBEDTLS_EFFICIENT_UNALIGNED_ACCESS
-#endif
+#endif /* __ARM_FEATURE_UNALIGNED || MBEDTLS_ARCH_IS_X86 || MBEDTLS_ARCH_IS_X64 ||
+        * MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64 */
+#endif /* MBEDTLS_ALIGNMENT_DISABLE_EFFICENT_UNALIGNED_ACCESS */ //no-check-names
 
 #if defined(__IAR_SYSTEMS_ICC__) && \
     (defined(MBEDTLS_ARCH_IS_ARM64) || defined(MBEDTLS_ARCH_IS_ARM32) \
@@ -85,13 +88,13 @@
  #define UINT_UNALIGNED_STRUCT
 typedef struct {
     uint16_t x;
-} __attribute__((packed)) mbedtls_uint16_unaligned_t;
+} __attribute__((packed, may_alias)) mbedtls_uint16_unaligned_t;
 typedef struct {
     uint32_t x;
-} __attribute__((packed)) mbedtls_uint32_unaligned_t;
+} __attribute__((packed, may_alias)) mbedtls_uint32_unaligned_t;
 typedef struct {
     uint64_t x;
-} __attribute__((packed)) mbedtls_uint64_unaligned_t;
+} __attribute__((packed, may_alias)) mbedtls_uint64_unaligned_t;
  #endif
 
 /*
@@ -277,15 +280,15 @@
 /*
  * Detect GCC built-in byteswap routines
  */
-#if defined(__GNUC__) && defined(__GNUC_PREREQ)
-#if __GNUC_PREREQ(4, 8)
+#if defined(__GNUC__)
+#if MBEDTLS_GCC_VERSION >= 40800
 #define MBEDTLS_BSWAP16 __builtin_bswap16
-#endif /* __GNUC_PREREQ(4,8) */
-#if __GNUC_PREREQ(4, 3)
+#endif
+#if MBEDTLS_GCC_VERSION >= 40300
 #define MBEDTLS_BSWAP32 __builtin_bswap32
 #define MBEDTLS_BSWAP64 __builtin_bswap64
-#endif /* __GNUC_PREREQ(4,3) */
-#endif /* defined(__GNUC__) && defined(__GNUC_PREREQ) */
+#endif
+#endif /* defined(__GNUC__) */
 
 /*
  * Detect Clang built-in byteswap routines
diff -Nru mbedtls-3.6.5/library/base64.c mbedtls-3.6.6/library/base64.c
--- mbedtls-3.6.5/library/base64.c	2025-10-14 19:12:36.894929200 +0300
+++ mbedtls-3.6.6/library/base64.c	2026-03-27 19:00:27.556563400 +0200
@@ -5,8 +5,6 @@
  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  */
 
-#include <limits.h>
-
 #include "common.h"
 
 #if defined(MBEDTLS_BASE64_C)
@@ -16,6 +14,7 @@
 #include "constant_time_internal.h"
 #include "mbedtls/error.h"
 
+#include <limits.h>
 #include <stdint.h>
 
 #if defined(MBEDTLS_SELF_TEST)
diff -Nru mbedtls-3.6.5/library/ccm.c mbedtls-3.6.6/library/ccm.c
--- mbedtls-3.6.5/library/ccm.c	2025-10-14 19:12:36.898882900 +0300
+++ mbedtls-3.6.6/library/ccm.c	2026-03-27 19:00:27.559717400 +0200
@@ -177,6 +177,7 @@
             ctx->plaintext_len = 0;
             return 0;
         } else {
+            ctx->state |= CCM_STATE__ERROR;
             return MBEDTLS_ERR_CCM_BAD_INPUT;
         }
     }
@@ -480,6 +481,14 @@
         return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     }
 
+    if (!(ctx->state & CCM_STATE__STARTED)) {
+        return MBEDTLS_ERR_CCM_BAD_INPUT;
+    }
+
+    if (!(ctx->state & CCM_STATE__LENGTHS_SET)) {
+        return MBEDTLS_ERR_CCM_BAD_INPUT;
+    }
+
     if (ctx->add_len > 0 && !(ctx->state & CCM_STATE__AUTH_DATA_FINISHED)) {
         return MBEDTLS_ERR_CCM_BAD_INPUT;
     }
@@ -488,6 +497,10 @@
         return MBEDTLS_ERR_CCM_BAD_INPUT;
     }
 
+    if (tag_len != ctx->tag_len) {
+        return MBEDTLS_ERR_CCM_BAD_INPUT;
+    }
+
     /*
      * Authentication: reset counter and crypt/mask internal tag
      */
diff -Nru mbedtls-3.6.5/library/check_crypto_config.h mbedtls-3.6.6/library/check_crypto_config.h
--- mbedtls-3.6.5/library/check_crypto_config.h	2025-10-14 19:12:36.900047300 +0300
+++ mbedtls-3.6.6/library/check_crypto_config.h	2026-03-27 19:00:27.560100600 +0200
@@ -128,11 +128,6 @@
 #error "PSA_WANT_KEY_TYPE_DH_KEY_PAIR_DERIVE defined, but feature is not supported"
 #endif
 
-#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && defined(MBEDTLS_USE_PSA_CRYPTO) && \
-    !(defined(PSA_WANT_ALG_SHA_1) || defined(PSA_WANT_ALG_SHA_256) || defined(PSA_WANT_ALG_SHA_512))
-#error "MBEDTLS_SSL_PROTO_TLS1_2 defined, but not all prerequisites"
-#endif
-
 #if defined(PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS) && \
     !defined(PSA_WANT_ALG_SHA_256)
 #error "PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS defined, but not all prerequisites"
diff -Nru mbedtls-3.6.5/library/CMakeLists.txt mbedtls-3.6.6/library/CMakeLists.txt
--- mbedtls-3.6.5/library/CMakeLists.txt	2025-10-14 19:12:36.891071000 +0300
+++ mbedtls-3.6.6/library/CMakeLists.txt	2026-03-27 19:00:27.552934400 +0200
@@ -76,6 +76,7 @@
     psa_crypto_mac.c
     psa_crypto_pake.c
     psa_crypto_rsa.c
+    psa_crypto_random.c
     psa_crypto_se.c
     psa_crypto_slot_management.c
     psa_crypto_storage.c
@@ -313,7 +314,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.5 SOVERSION 16)
+    set_target_properties(${mbedcrypto_target} PROPERTIES VERSION 3.6.6 SOVERSION 16)
     target_link_libraries(${mbedcrypto_target} PUBLIC ${libs})
 
     if(TARGET ${everest_target})
@@ -325,11 +326,11 @@
     endif()
 
     add_library(${mbedx509_target} SHARED ${src_x509})
-    set_target_properties(${mbedx509_target} PROPERTIES VERSION 3.6.5 SOVERSION 7)
+    set_target_properties(${mbedx509_target} PROPERTIES VERSION 3.6.6 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.5 SOVERSION 21)
+    set_target_properties(${mbedtls_target} PROPERTIES VERSION 3.6.6 SOVERSION 21)
     target_link_libraries(${mbedtls_target} PUBLIC ${libs} ${mbedx509_target})
 
     if(GEN_FILES)
@@ -349,7 +350,7 @@
     # of /library (which currently means: under /3rdparty).
     target_include_directories(${target}
         PUBLIC $<BUILD_INTERFACE:${MBEDTLS_DIR}/include/>
-               $<INSTALL_INTERFACE:include/>
+               $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
         PRIVATE ${MBEDTLS_DIR}/library/
                 # Needed to include psa_crypto_driver_wrappers.h
                 ${CMAKE_CURRENT_BINARY_DIR})
diff -Nru mbedtls-3.6.5/library/common.h mbedtls-3.6.6/library/common.h
--- mbedtls-3.6.5/library/common.h	2025-10-14 19:12:36.901656600 +0300
+++ mbedtls-3.6.6/library/common.h	2026-03-27 19:00:27.561397600 +0200
@@ -27,6 +27,24 @@
 #define MBEDTLS_HAVE_NEON_INTRINSICS
 #endif
 
+/* Decide whether we're built for a Unix-like platform.
+ */
+#if defined(MBEDTLS_TEST_PLATFORM_IS_NOT_UNIXLIKE) //no-check-names
+/* We may be building on a Unix-like platform, but for test purposes,
+ * do not try to use Unix features. */
+#elif defined(_WIN32)
+/* If Windows platform interfaces are available, we use them, even if
+ * a Unix-like might also to be available. */
+/* defined(_WIN32) ==> we can include <windows.h> */
+#elif defined(unix) || defined(__unix) || defined(__unix__) ||    \
+    (defined(__APPLE__) && defined(__MACH__)) ||                  \
+    defined(__HAIKU__) ||                                         \
+    defined(__midipix__) ||                                       \
+    /* Add other Unix-like platform indicators here ^^^^ */ 0
+/* defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) ==> we can include <unistd.h> */
+#define MBEDTLS_PLATFORM_IS_UNIXLIKE
+#endif
+
 /** Helper to define a function as static except when building invasive tests.
  *
  * If a function is only used inside its own source file and should be
@@ -99,6 +117,13 @@
  * fall back to the unsafe implementation. */
 #define ARRAY_LENGTH(array) ARRAY_LENGTH_UNSAFE(array)
 #endif
+
+#if defined(__has_builtin)
+#define MBEDTLS_HAS_BUILTIN(x) __has_builtin(x)
+#else
+#define MBEDTLS_HAS_BUILTIN(x) 0
+#endif
+
 /** Allow library to access its structs' private members.
  *
  * Although structs defined in header files are publicly available,
@@ -208,6 +233,11 @@
         return;
     }
 #endif
+#if defined(MBEDTLS_COMPILER_IS_GCC) && MBEDTLS_HAS_BUILTIN(__builtin_constant_p)
+    if (__builtin_constant_p(n) && n % 16 == 0) {
+        return;
+    }
+#endif
 #elif defined(MBEDTLS_ARCH_IS_X64) || defined(MBEDTLS_ARCH_IS_ARM64)
     /* This codepath probably only makes sense on architectures with 64-bit registers */
     for (; (i + 8) <= n; i += 8) {
@@ -219,6 +249,11 @@
         return;
     }
 #endif
+#if defined(MBEDTLS_COMPILER_IS_GCC) && MBEDTLS_HAS_BUILTIN(__builtin_constant_p)
+    if (__builtin_constant_p(n) && n % 8 == 0) {
+        return;
+    }
+#endif
 #else
     for (; (i + 4) <= n; i += 4) {
         uint32_t x = mbedtls_get_unaligned_uint32(a + i) ^ mbedtls_get_unaligned_uint32(b + i);
@@ -229,6 +264,11 @@
         return;
     }
 #endif
+#if defined(MBEDTLS_COMPILER_IS_GCC) && MBEDTLS_HAS_BUILTIN(__builtin_constant_p)
+    if (__builtin_constant_p(n) && n % 4 == 0) {
+        return;
+    }
+#endif
 #endif
 #endif
     for (; i < n; i++) {
@@ -367,12 +407,6 @@
     struct ISO_C_does_not_allow_extra_semicolon_outside_of_a_function
 #endif
 
-#if defined(__has_builtin)
-#define MBEDTLS_HAS_BUILTIN(x) __has_builtin(x)
-#else
-#define MBEDTLS_HAS_BUILTIN(x) 0
-#endif
-
 /* Define compiler branch hints */
 #if MBEDTLS_HAS_BUILTIN(__builtin_expect)
 #define MBEDTLS_LIKELY(x)       __builtin_expect(!!(x), 1)
diff -Nru mbedtls-3.6.5/library/constant_time.c mbedtls-3.6.6/library/constant_time.c
--- mbedtls-3.6.5/library/constant_time.c	2025-10-14 19:12:36.901869000 +0300
+++ mbedtls-3.6.6/library/constant_time.c	2026-03-27 19:00:27.561490300 +0200
@@ -10,15 +10,14 @@
  * might be translated to branches by some compilers on some platforms.
  */
 
-#include <stdint.h>
-#include <limits.h>
-
 #include "common.h"
 #include "constant_time_internal.h"
 #include "mbedtls/constant_time.h"
 #include "mbedtls/error.h"
 #include "mbedtls/platform_util.h"
 
+#include <limits.h>
+#include <stdint.h>
 #include <string.h>
 
 #if !defined(MBEDTLS_CT_ASM)
diff -Nru mbedtls-3.6.5/library/ctr_drbg.c mbedtls-3.6.6/library/ctr_drbg.c
--- mbedtls-3.6.5/library/ctr_drbg.c	2025-10-14 19:12:36.902589800 +0300
+++ mbedtls-3.6.6/library/ctr_drbg.c	2026-03-27 19:00:27.562441300 +0200
@@ -494,7 +494,7 @@
     if ((ret = ctr_drbg_update_internal(ctx, seed)) != 0) {
         goto exit;
     }
-    ctx->reseed_counter = 1;
+    ctx->reseed_counter = 0;
 
 exit:
     mbedtls_platform_zeroize(seed, sizeof(seed));
@@ -629,7 +629,7 @@
 
     memset(locals.add_input, 0, MBEDTLS_CTR_DRBG_SEEDLEN);
 
-    if (ctx->reseed_counter > ctx->reseed_interval ||
+    if (ctx->reseed_counter >= ctx->reseed_interval ||
         ctx->prediction_resistance) {
         if ((ret = mbedtls_ctr_drbg_reseed(ctx, additional, add_len)) != 0) {
             return ret;
diff -Nru mbedtls-3.6.5/library/debug.c mbedtls-3.6.6/library/debug.c
--- mbedtls-3.6.5/library/debug.c	2025-10-14 19:12:36.903538500 +0300
+++ mbedtls-3.6.6/library/debug.c	2026-03-27 19:00:27.562623500 +0200
@@ -21,6 +21,16 @@
 /* DEBUG_BUF_SIZE must be at least 2 */
 #define DEBUG_BUF_SIZE      512
 
+int mbedtls_debug_snprintf(char *dest, size_t maxlen,
+                           const char *format, ...)
+{
+    va_list argp;
+    va_start(argp, format);
+    int ret = mbedtls_vsnprintf(dest, maxlen, format, argp);
+    va_end(argp);
+    return ret;
+}
+
 static int debug_threshold = 0;
 
 void mbedtls_debug_set_threshold(int threshold)
diff -Nru mbedtls-3.6.5/library/debug_internal.h mbedtls-3.6.6/library/debug_internal.h
--- mbedtls-3.6.5/library/debug_internal.h	2025-10-14 19:12:36.903840500 +0300
+++ mbedtls-3.6.6/library/debug_internal.h	2026-03-27 19:00:27.562801100 +0200
@@ -12,6 +12,19 @@
 
 #include "mbedtls/debug.h"
 
+/* This should be equivalent to mbedtls_snprintf(). But it might not be due
+ * to platform shenanigans. For example, Mbed TLS and TF-PSA-Crypto could
+ * have inconsistent platform definitions. On Mingw, some code might
+ * be built with a different setting of __USE_MINGW_ANSI_STDIO, resulting
+ * in an old non-C99 printf being used somewhere.
+ *
+ * Our library assumes that mbedtls_snprintf() and other printf functions
+ * are consistent throughout. This function is not an official API and
+ * is not meant to be used inside the library. It is provided to help
+ * debugging printf inconsistencies issues. If you need it, good luck!
+ */
+int mbedtls_debug_snprintf(char *dest, size_t maxlen,
+                           const char *format, ...) MBEDTLS_PRINTF_ATTRIBUTE(3, 4);
 /**
  * \brief    Print a message to the debug output. This function is always used
  *          through the MBEDTLS_SSL_DEBUG_MSG() macro, which supplies the ssl
diff -Nru mbedtls-3.6.5/library/entropy_poll.c mbedtls-3.6.6/library/entropy_poll.c
--- mbedtls-3.6.5/library/entropy_poll.c	2025-10-14 19:12:36.908689700 +0300
+++ mbedtls-3.6.6/library/entropy_poll.c	2026-03-27 19:00:27.566627000 +0200
@@ -147,6 +147,8 @@
 
 #include <stdio.h>
 
+const char *mbedtls_platform_dev_random = MBEDTLS_PLATFORM_DEV_RANDOM;
+
 int mbedtls_platform_entropy_poll(void *data,
                                   unsigned char *output, size_t len, size_t *olen)
 {
@@ -180,7 +182,7 @@
 
     *olen = 0;
 
-    file = fopen("/dev/urandom", "rb");
+    file = fopen(mbedtls_platform_dev_random, "rb");
     if (file == NULL) {
         return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
     }
diff -Nru mbedtls-3.6.5/library/hmac_drbg.c mbedtls-3.6.6/library/hmac_drbg.c
--- mbedtls-3.6.5/library/hmac_drbg.c	2025-10-14 19:12:36.909986300 +0300
+++ mbedtls-3.6.6/library/hmac_drbg.c	2026-03-27 19:00:27.568148000 +0200
@@ -196,7 +196,7 @@
     }
 
     /* 3. Reset reseed_counter */
-    ctx->reseed_counter = 1;
+    ctx->reseed_counter = 0;
 
 exit:
     /* 4. Done */
@@ -326,7 +326,7 @@
     /* 1. (aka VII and IX) Check reseed counter and PR */
     if (ctx->f_entropy != NULL && /* For no-reseeding instances */
         (ctx->prediction_resistance == MBEDTLS_HMAC_DRBG_PR_ON ||
-         ctx->reseed_counter > ctx->reseed_interval)) {
+         ctx->reseed_counter >= ctx->reseed_interval)) {
         if ((ret = mbedtls_hmac_drbg_reseed(ctx, additional, add_len)) != 0) {
             return ret;
         }
diff -Nru mbedtls-3.6.5/library/Makefile mbedtls-3.6.6/library/Makefile
--- mbedtls-3.6.5/library/Makefile	2025-10-14 19:12:36.891729400 +0300
+++ mbedtls-3.6.6/library/Makefile	2026-03-27 19:00:27.553402700 +0200
@@ -167,6 +167,7 @@
 	     psa_crypto_hash.o \
 	     psa_crypto_mac.o \
 	     psa_crypto_pake.o \
+	     psa_crypto_random.o \
 	     psa_crypto_rsa.o \
 	     psa_crypto_se.o \
 	     psa_crypto_slot_management.o \
diff -Nru mbedtls-3.6.5/library/net_sockets.c mbedtls-3.6.6/library/net_sockets.c
--- mbedtls-3.6.5/library/net_sockets.c	2025-10-14 19:12:36.913169000 +0300
+++ mbedtls-3.6.6/library/net_sockets.c	2026-03-27 19:00:27.570571400 +0200
@@ -19,9 +19,7 @@
 
 #if defined(MBEDTLS_NET_C)
 
-#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \
-    !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \
-    !defined(__HAIKU__) && !defined(__midipix__)
+#if !defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) && !defined(_WIN32)
 #error "This module only works on Unix and Windows, see MBEDTLS_NET_C in mbedtls_config.h"
 #endif
 
diff -Nru mbedtls-3.6.5/library/pk.c mbedtls-3.6.6/library/pk.c
--- mbedtls-3.6.5/library/pk.c	2025-10-14 19:12:36.914935400 +0300
+++ mbedtls-3.6.6/library/pk.c	2026-03-27 19:00:27.572038000 +0200
@@ -35,6 +35,31 @@
 #include <limits.h>
 #include <stdint.h>
 
+#if !defined(PK_EXPORT_KEYS_ON_THE_STACK)
+#include "mbedtls/platform.h" // for calloc/free
+#endif
+
+#if defined(MBEDTLS_PSA_CRYPTO_CLIENT)
+#define MBEDTLS_PK_MAX_EC_PUBKEY_RAW_LEN \
+    PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_ECC_MAX_CURVE_BITS)
+
+#define MBEDTLS_PK_MAX_RSA_PUBKEY_RAW_LEN \
+    PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_RSA_MAX_KEY_BITS)
+
+#define MBEDTLS_PK_MAX_PUBKEY_RAW_LEN 0
+#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) && \
+    MBEDTLS_PK_MAX_EC_PUBKEY_RAW_LEN > MBEDTLS_PK_MAX_PUBKEY_RAW_LEN
+#undef MBEDTLS_PK_MAX_PUBKEY_RAW_LEN
+#define MBEDTLS_PK_MAX_PUBKEY_RAW_LEN MBEDTLS_PK_MAX_EC_PUBKEY_RAW_LEN
+#endif
+#if (defined(MBEDTLS_RSA_C) || \
+    (defined(MBEDTLS_USE_PSA_CRYPTO) && defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY))) && \
+    MBEDTLS_PK_MAX_RSA_PUBKEY_RAW_LEN > MBEDTLS_PK_MAX_PUBKEY_RAW_LEN
+#undef MBEDTLS_PK_MAX_PUBKEY_RAW_LEN
+#define MBEDTLS_PK_MAX_PUBKEY_RAW_LEN MBEDTLS_PK_MAX_RSA_PUBKEY_RAW_LEN
+#endif
+#endif /* MBEDTLS_PSA_CRYPTO_CLIENT */
+
 /*
  * Initialise a mbedtls_pk_context
  */
@@ -586,19 +611,44 @@
 
 #if defined(MBEDTLS_PK_USE_PSA_EC_DATA) || defined(MBEDTLS_USE_PSA_CRYPTO)
 static psa_status_t export_import_into_psa(mbedtls_svc_key_id_t old_key_id,
+                                           psa_key_type_t old_type, size_t old_bits,
                                            const psa_key_attributes_t *attributes,
                                            mbedtls_svc_key_id_t *new_key_id)
 {
-    unsigned char key_buffer[PSA_EXPORT_KEY_PAIR_MAX_SIZE];
+#if !defined(PK_EXPORT_KEYS_ON_THE_STACK)
+    unsigned char *key_buffer = NULL;
+    size_t key_buffer_size = 0;
+#else
+    unsigned char key_buffer[PK_EXPORT_KEY_STACK_BUFFER_SIZE];
+    const size_t key_buffer_size = sizeof(key_buffer);
+#endif
     size_t key_length = 0;
+
+    /* We are exporting from a PK object, so we know key type is valid for PK */
+#if !defined(PK_EXPORT_KEYS_ON_THE_STACK)
+    key_buffer_size = PSA_EXPORT_KEY_OUTPUT_SIZE(old_type, old_bits);
+    key_buffer = mbedtls_calloc(1, key_buffer_size);
+    if (key_buffer == NULL) {
+        return MBEDTLS_ERR_PK_ALLOC_FAILED;
+    }
+#else
+    (void) old_type;
+    (void) old_bits;
+#endif
+
     psa_status_t status = psa_export_key(old_key_id,
-                                         key_buffer, sizeof(key_buffer),
+                                         key_buffer, key_buffer_size,
                                          &key_length);
     if (status != PSA_SUCCESS) {
-        return status;
+        goto cleanup;
     }
     status = psa_import_key(attributes, key_buffer, key_length, new_key_id);
     mbedtls_platform_zeroize(key_buffer, key_length);
+
+cleanup:
+#if !defined(PK_EXPORT_KEYS_ON_THE_STACK)
+    mbedtls_free(key_buffer);
+#endif
     return status;
 }
 
@@ -628,11 +678,13 @@
             return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
         }
         psa_key_type_t old_type = psa_get_key_type(&old_attributes);
+        size_t old_bits = psa_get_key_bits(&old_attributes);
         psa_reset_key_attributes(&old_attributes);
         if (old_type != psa_get_key_type(attributes)) {
             return MBEDTLS_ERR_PK_TYPE_MISMATCH;
         }
-        status = export_import_into_psa(old_key_id, attributes, new_key_id);
+        status = export_import_into_psa(old_key_id, old_type, old_bits,
+                                        attributes, new_key_id);
     }
     return PSA_PK_TO_MBEDTLS_ERR(status);
 }
@@ -649,20 +701,25 @@
             if (psa_get_key_type(attributes) != PSA_KEY_TYPE_RSA_KEY_PAIR) {
                 return MBEDTLS_ERR_PK_TYPE_MISMATCH;
             }
-            unsigned char key_buffer[
-                PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(PSA_VENDOR_RSA_MAX_KEY_BITS)];
-            unsigned char *const key_end = key_buffer + sizeof(key_buffer);
+            size_t key_bits = psa_get_key_bits(attributes);
+            size_t key_buffer_size = PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(key_bits);
+            unsigned char *key_buffer = mbedtls_calloc(1, key_buffer_size);
+            if (key_buffer == NULL) {
+                return MBEDTLS_ERR_PK_ALLOC_FAILED;
+            }
+            unsigned char *const key_end = key_buffer + key_buffer_size;
             unsigned char *key_data = key_end;
             int ret = mbedtls_rsa_write_key(mbedtls_pk_rsa(*pk),
                                             key_buffer, &key_data);
             if (ret < 0) {
-                return ret;
+                goto cleanup_rsa;
             }
             size_t key_length = key_end - key_data;
             ret = PSA_PK_TO_MBEDTLS_ERR(psa_import_key(attributes,
                                                        key_data, key_length,
                                                        key_id));
-            mbedtls_platform_zeroize(key_data, key_length);
+cleanup_rsa:
+            mbedtls_zeroize_and_free(key_buffer, key_buffer_size);
             return ret;
         }
 #endif /* MBEDTLS_RSA_C */
@@ -741,7 +798,7 @@
 #if defined(MBEDTLS_RSA_C) ||                                           \
     (defined(MBEDTLS_PK_HAVE_ECC_KEYS) && !defined(MBEDTLS_PK_USE_PSA_EC_DATA)) || \
     defined(MBEDTLS_USE_PSA_CRYPTO)
-    unsigned char key_buffer[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
+    unsigned char key_buffer[MBEDTLS_PK_MAX_PUBKEY_RAW_LEN];
 #endif
     unsigned char *key_data = NULL;
     size_t key_length = 0;
@@ -857,6 +914,21 @@
     }
 }
 
+static int is_valid_for_pk(psa_key_type_t key_type)
+{
+#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
+    if (PSA_KEY_TYPE_IS_ECC(key_type)) {
+        return 1;
+    }
+#endif
+#if defined(MBEDTLS_RSA_C)
+    if (PSA_KEY_TYPE_IS_RSA(key_type)) {
+        return 1;
+    }
+#endif
+    return 0;
+}
+
 static int copy_from_psa(mbedtls_svc_key_id_t key_id,
                          mbedtls_pk_context *pk,
                          int public_only)
@@ -865,8 +937,13 @@
     psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
     psa_key_type_t key_type;
     size_t key_bits;
-    /* Use a buffer size large enough to contain either a key pair or public key. */
-    unsigned char exp_key[PSA_EXPORT_KEY_PAIR_OR_PUBLIC_MAX_SIZE];
+#if !defined(PK_EXPORT_KEYS_ON_THE_STACK)
+    unsigned char *exp_key = NULL;
+    size_t exp_key_size = 0;
+#else
+    unsigned char exp_key[PK_EXPORT_KEY_STACK_BUFFER_SIZE];
+    const size_t exp_key_size = sizeof(exp_key);
+#endif
     size_t exp_key_len;
     int ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA;
 
@@ -879,10 +956,28 @@
         return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
     }
 
+    key_type = psa_get_key_type(&key_attr);
+    if (!is_valid_for_pk(key_type)) {
+        return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+    }
+
     if (public_only) {
-        status = psa_export_public_key(key_id, exp_key, sizeof(exp_key), &exp_key_len);
+        key_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(key_type);
+    }
+    key_bits = psa_get_key_bits(&key_attr);
+
+#if !defined(PK_EXPORT_KEYS_ON_THE_STACK)
+    exp_key_size = PSA_EXPORT_KEY_OUTPUT_SIZE(key_type, key_bits);
+    exp_key = mbedtls_calloc(1, exp_key_size);
+    if (exp_key == NULL) {
+        return MBEDTLS_ERR_PK_ALLOC_FAILED;
+    }
+#endif
+
+    if (public_only) {
+        status = psa_export_public_key(key_id, exp_key, exp_key_size, &exp_key_len);
     } else {
-        status = psa_export_key(key_id, exp_key, sizeof(exp_key), &exp_key_len);
+        status = psa_export_key(key_id, exp_key, exp_key_size, &exp_key_len);
     }
     if (status != PSA_SUCCESS) {
         ret = PSA_PK_TO_MBEDTLS_ERR(status);
@@ -964,12 +1059,16 @@
 #endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
     {
         (void) key_bits;
-        return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+        ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA;
+        goto exit;
     }
 
 exit:
+    mbedtls_platform_zeroize(exp_key, exp_key_size);
+#if !defined(PK_EXPORT_KEYS_ON_THE_STACK)
+    mbedtls_free(exp_key);
+#endif
     psa_reset_key_attributes(&key_attr);
-    mbedtls_platform_zeroize(exp_key, sizeof(exp_key));
 
     return ret;
 }
@@ -1146,7 +1245,7 @@
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     if (pss_opts->mgf1_hash_id == md_alg) {
-        unsigned char buf[MBEDTLS_PK_RSA_PUB_DER_MAX_BYTES];
+        unsigned char buf[PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_RSA_MAX_KEY_BITS)];
         unsigned char *p;
         int key_len;
         size_t signature_length;
diff -Nru mbedtls-3.6.5/library/pk_internal.h mbedtls-3.6.6/library/pk_internal.h
--- mbedtls-3.6.5/library/pk_internal.h	2025-10-14 19:12:36.915778000 +0300
+++ mbedtls-3.6.6/library/pk_internal.h	2026-03-27 19:00:27.572516000 +0200
@@ -44,6 +44,40 @@
 #define PEM_BEGIN_ENCRYPTED_PRIVATE_KEY_PKCS8 "-----BEGIN ENCRYPTED PRIVATE KEY-----"
 #define PEM_END_ENCRYPTED_PRIVATE_KEY_PKCS8   "-----END ENCRYPTED PRIVATE KEY-----"
 
+/*
+ * We're trying to statisfy two kinds of users:
+ * - those who don't want to use the heap;
+ * - those who can't afford large stack buffers.
+ *
+ * The current compromise is that if ECC is the only key type supported in PK,
+ * then we export keys on the stack, and otherwise we use the heap.
+ *
+ * RSA can either be used directly or indirectly via opaque keys if enabled.
+ * (RSA_ALT is not relevant here as we can't export from such contexts.)
+ */
+#if !defined(MBEDTLS_RSA_C) && \
+    !(defined(MBEDTLS_USE_PSA_CRYPTO) && defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY))
+#define PK_EXPORT_KEYS_ON_THE_STACK
+#endif
+
+#if defined(PK_EXPORT_KEYS_ON_THE_STACK)
+/* We know for ECC, pubkey are longer than privkeys, but double check.
+ * Also, take the maximum size of legacy and PSA, as PSA might be disabled. */
+#define PK_EXPORT_KEY_STACK_BUFFER_SIZE  MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH
+#if PK_EXPORT_KEY_STACK_BUFFER_SIZE < MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH
+#undef PK_EXPORT_KEY_STACK_BUFFER_SIZE
+#define PK_EXPORT_KEY_STACK_BUFFER_SIZE  MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH
+#endif
+#if PK_EXPORT_KEY_STACK_BUFFER_SIZE < MBEDTLS_ECP_MAX_BYTES
+#undef PK_EXPORT_KEY_STACK_BUFFER_SIZE
+#define PK_EXPORT_KEY_STACK_BUFFER_SIZE  MBEDTLS_ECP_MAX_BYTES
+#endif
+#if PK_EXPORT_KEY_STACK_BUFFER_SIZE < MBEDTLS_ECP_MAX_PT_LEN
+#undef PK_EXPORT_KEY_STACK_BUFFER_SIZE
+#define PK_EXPORT_KEY_STACK_BUFFER_SIZE  MBEDTLS_ECP_MAX_PT_LEN
+#endif
+#endif
+
 #if defined(MBEDTLS_PK_HAVE_ECC_KEYS) && !defined(MBEDTLS_PK_USE_PSA_EC_DATA)
 /**
  * Public function mbedtls_pk_ec() can be used to get direct access to the
diff -Nru mbedtls-3.6.5/library/pk_wrap.c mbedtls-3.6.6/library/pk_wrap.c
--- mbedtls-3.6.5/library/pk_wrap.c	2025-10-14 19:12:36.916180400 +0300
+++ mbedtls-3.6.6/library/pk_wrap.c	2026-03-27 19:00:27.572652000 +0200
@@ -72,7 +72,7 @@
     mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
     psa_status_t status;
     int key_len;
-    unsigned char buf[MBEDTLS_PK_RSA_PUB_DER_MAX_BYTES];
+    unsigned char buf[PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_RSA_MAX_KEY_BITS)];
     unsigned char *p = buf + sizeof(buf);
     psa_algorithm_t psa_alg_md;
     size_t rsa_len = mbedtls_rsa_get_len(rsa);
@@ -288,9 +288,6 @@
     psa_algorithm_t psa_md_alg, decrypt_alg;
     psa_status_t status;
     int key_len;
-    unsigned char buf[MBEDTLS_PK_RSA_PRV_DER_MAX_BYTES];
-    unsigned char *p = buf + sizeof(buf);
-
     ((void) f_rng);
     ((void) p_rng);
 
@@ -298,6 +295,13 @@
         return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
     }
 
+    const size_t key_bits = mbedtls_pk_get_bitlen(pk);
+    /* mbedtls_rsa_write_key() uses the same format as PSA export, which
+     * actually calls it under the hood, so we can use the PSA size macro. */
+    const size_t buf_size = PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE(key_bits);
+    unsigned char *buf = mbedtls_calloc(1, buf_size);
+
+    unsigned char *p = buf + buf_size;
     key_len = mbedtls_rsa_write_key(rsa, buf, &p);
     if (key_len <= 0) {
         return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
@@ -314,7 +318,7 @@
     psa_set_key_algorithm(&attributes, decrypt_alg);
 
     status = psa_import_key(&attributes,
-                            buf + sizeof(buf) - key_len, key_len,
+                            buf + buf_size - key_len, key_len,
                             &key_id);
     if (status != PSA_SUCCESS) {
         ret = PSA_PK_TO_MBEDTLS_ERR(status);
@@ -333,7 +337,7 @@
     ret = 0;
 
 cleanup:
-    mbedtls_platform_zeroize(buf, sizeof(buf));
+    mbedtls_zeroize_and_free(buf, buf_size);
     status = psa_destroy_key(key_id);
     if (ret == 0 && status != PSA_SUCCESS) {
         ret = PSA_PK_TO_MBEDTLS_ERR(status);
@@ -371,7 +375,7 @@
     psa_algorithm_t psa_md_alg, psa_encrypt_alg;
     psa_status_t status;
     int key_len;
-    unsigned char buf[MBEDTLS_PK_RSA_PUB_DER_MAX_BYTES];
+    unsigned char buf[PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(PSA_VENDOR_RSA_MAX_KEY_BITS)];
     unsigned char *p = buf + sizeof(buf);
 
     ((void) f_rng);
@@ -1336,7 +1340,6 @@
                               int (*f_rng)(void *, unsigned char *, size_t),
                               void *p_rng)
 {
-    unsigned char sig[MBEDTLS_MPI_MAX_SIZE];
     unsigned char hash[32];
     size_t sig_len = 0;
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -1345,21 +1348,29 @@
         return MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
     }
 
+    size_t sig_size = (rsa_get_bitlen(pub) + 7) / 8;
+    unsigned char *sig = mbedtls_calloc(1, sig_size);
+    if (sig == NULL) {
+        return MBEDTLS_ERR_PK_ALLOC_FAILED;
+    }
+
     memset(hash, 0x2a, sizeof(hash));
 
     if ((ret = rsa_alt_sign_wrap(prv, MBEDTLS_MD_NONE,
                                  hash, sizeof(hash),
-                                 sig, sizeof(sig), &sig_len,
+                                 sig, sig_size, &sig_len,
                                  f_rng, p_rng)) != 0) {
-        return ret;
+        goto cleanup;
     }
 
     if (rsa_verify_wrap(pub, MBEDTLS_MD_NONE,
                         hash, sizeof(hash), sig, sig_len) != 0) {
-        return MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
+        ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED;
     }
 
-    return 0;
+cleanup:
+    mbedtls_zeroize_and_free(sig, sig_size);
+    return ret;
 }
 #endif /* MBEDTLS_RSA_C */
 
diff -Nru mbedtls-3.6.5/library/pkwrite.c mbedtls-3.6.6/library/pkwrite.c
--- mbedtls-3.6.5/library/pkwrite.c	2025-10-14 19:12:36.918826000 +0300
+++ mbedtls-3.6.6/library/pkwrite.c	2026-03-27 19:00:27.573871000 +0200
@@ -45,10 +45,10 @@
 /* Helpers for properly sizing buffers aimed at holding public keys or
  * key-pairs based on build symbols. */
 #if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
-#define PK_MAX_EC_PUBLIC_KEY_SIZE       PSA_EXPORT_PUBLIC_KEY_MAX_SIZE
+#define PK_MAX_EC_PUBLIC_KEY_SIZE       MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH
 #define PK_MAX_EC_KEY_PAIR_SIZE         MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH
 #elif defined(MBEDTLS_USE_PSA_CRYPTO)
-#define PK_MAX_EC_PUBLIC_KEY_SIZE       PSA_EXPORT_PUBLIC_KEY_MAX_SIZE
+#define PK_MAX_EC_PUBLIC_KEY_SIZE       MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH
 #define PK_MAX_EC_KEY_PAIR_SIZE         MBEDTLS_PSA_MAX_EC_KEY_PAIR_LENGTH
 #else
 #define PK_MAX_EC_PUBLIC_KEY_SIZE       MBEDTLS_ECP_MAX_PT_LEN
@@ -64,22 +64,24 @@
 {
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) {
-        uint8_t tmp[PSA_EXPORT_KEY_PAIR_MAX_SIZE];
-        size_t tmp_len = 0;
+        psa_status_t status;
+        size_t buf_size = (size_t) (*p - buf);
+        size_t key_len = 0;
 
-        if (psa_export_key(pk->priv_id, tmp, sizeof(tmp), &tmp_len) != PSA_SUCCESS) {
-            return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
-        }
-        /* Ensure there's enough space in the provided buffer before copying data into it. */
-        if (tmp_len > (size_t) (*p - buf)) {
-            mbedtls_platform_zeroize(tmp, sizeof(tmp));
+        status = psa_export_key(pk->priv_id, buf, buf_size, &key_len);
+        if (status == PSA_ERROR_BUFFER_TOO_SMALL) {
             return MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
+        } else if (status != PSA_SUCCESS) {
+            return PSA_PK_RSA_TO_MBEDTLS_ERR(status);
         }
-        *p -= tmp_len;
-        memcpy(*p, tmp, tmp_len);
-        mbedtls_platform_zeroize(tmp, sizeof(tmp));
 
-        return (int) tmp_len;
+        /* We wrote to the beginning of the buffer while
+         * we were supposed to write to its end. */
+        *p -= key_len;
+        memmove(*p, buf, key_len);
+        mbedtls_platform_zeroize(buf, *p - buf);
+
+        return (int) key_len;
     }
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
     return mbedtls_rsa_write_key(mbedtls_pk_rsa(*pk), buf, p);
diff -Nru mbedtls-3.6.5/library/platform_util.c mbedtls-3.6.6/library/platform_util.c
--- mbedtls-3.6.5/library/platform_util.c	2025-10-14 19:12:36.920012500 +0300
+++ mbedtls-3.6.6/library/platform_util.c	2026-03-27 19:00:27.574441200 +0200
@@ -147,12 +147,9 @@
 
 #if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT)
 #include <time.h>
-#if !defined(_WIN32) && (defined(unix) || \
-    defined(__unix) || defined(__unix__) || (defined(__APPLE__) && \
-    defined(__MACH__)) || defined(__midipix__))
+#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE)
 #include <unistd.h>
-#endif /* !_WIN32 && (unix || __unix || __unix__ ||
-        * (__APPLE__ && __MACH__) || __midipix__) */
+#endif
 
 #if !((defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L) ||     \
     (defined(_POSIX_THREAD_SAFE_FUNCTIONS) &&                     \
@@ -218,12 +215,10 @@
 #if defined(MBEDTLS_HAVE_TIME) && !defined(MBEDTLS_PLATFORM_MS_TIME_ALT)
 
 #include <time.h>
-#if !defined(_WIN32) && \
-    (defined(unix) || defined(__unix) || defined(__unix__) || \
-    (defined(__APPLE__) && defined(__MACH__)) || defined(__HAIKU__) || defined(__midipix__))
+#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE)
 #include <unistd.h>
-#endif \
-    /* !_WIN32 && (unix || __unix || __unix__ || (__APPLE__ && __MACH__) || __HAIKU__ || __midipix__) */
+#endif
+
 #if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 199309L) || defined(__HAIKU__)
 mbedtls_ms_time_t mbedtls_ms_time(void)
 {
diff -Nru mbedtls-3.6.5/library/psa_crypto_aead.c mbedtls-3.6.6/library/psa_crypto_aead.c
--- mbedtls-3.6.5/library/psa_crypto_aead.c	2025-10-14 19:12:36.926311000 +0300
+++ mbedtls-3.6.6/library/psa_crypto_aead.c	2026-03-27 19:00:27.575295000 +0200
@@ -310,9 +310,6 @@
 exit:
     mbedtls_psa_aead_abort(&operation);
 
-    if (status == PSA_SUCCESS) {
-        *plaintext_length = ciphertext_length - operation.tag_length;
-    }
     return status;
 }
 
diff -Nru mbedtls-3.6.5/library/psa_crypto.c mbedtls-3.6.6/library/psa_crypto.c
--- mbedtls-3.6.5/library/psa_crypto.c	2025-10-14 19:12:36.925314000 +0300
+++ mbedtls-3.6.6/library/psa_crypto.c	2026-03-27 19:00:27.575132100 +0200
@@ -37,6 +37,7 @@
  * stored keys. */
 #include "psa_crypto_storage.h"
 
+#include "psa_crypto_random.h"
 #include "psa_crypto_random_impl.h"
 
 #include <stdlib.h>
@@ -4412,25 +4413,8 @@
     return PSA_SUCCESS;
 
 #else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
-
-    while (output_size > 0) {
-        int ret = MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED;
-        size_t request_size =
-            (output_size > MBEDTLS_PSA_RANDOM_MAX_REQUEST ?
-             MBEDTLS_PSA_RANDOM_MAX_REQUEST :
-             output_size);
-#if defined(MBEDTLS_CTR_DRBG_C)
-        ret = mbedtls_ctr_drbg_random(&global_data.rng.drbg, output, request_size);
-#elif defined(MBEDTLS_HMAC_DRBG_C)
-        ret = mbedtls_hmac_drbg_random(&global_data.rng.drbg, output, request_size);
-#endif /* !MBEDTLS_CTR_DRBG_C && !MBEDTLS_HMAC_DRBG_C */
-        if (ret != 0) {
-            return mbedtls_to_psa_error(ret);
-        }
-        output_size -= request_size;
-        output += request_size;
-    }
-    return PSA_SUCCESS;
+    return psa_random_internal_generate(&global_data.rng,
+                                        output, output_size);
 #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
 }
 
@@ -5523,6 +5507,10 @@
 
 static psa_status_t psa_aead_final_checks(const psa_aead_operation_t *operation)
 {
+    if (operation->alg == PSA_ALG_CCM && !operation->lengths_set) {
+        return PSA_ERROR_BAD_STATE;
+    }
+
     if (operation->id == 0 || !operation->nonce_set) {
         return PSA_ERROR_BAD_STATE;
     }
@@ -7923,10 +7911,8 @@
      * for the output size. The PSA specification only guarantees that this
      * function works if output_size >= PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE(...),
      * but it might be nice to allow smaller buffers if the output fits.
-     * At the time of writing this comment, with only ECDH implemented,
-     * PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE() is exact so the point is moot.
-     * If FFDH is implemented, PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE() can easily
-     * be exact for it as well. */
+     * At the time of writing this comment, for both FFDH and ECDH,
+     * PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE() is exact so the point is moot. */
     expected_length =
         PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE(slot->attr.type, slot->attr.bits);
     if (output_size < expected_length) {
@@ -7986,28 +7972,7 @@
 #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
     memset(rng, 0, sizeof(*rng));
 #else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
-
-    /* Set default configuration if
-     * mbedtls_psa_crypto_configure_entropy_sources() hasn't been called. */
-    if (rng->entropy_init == NULL) {
-        rng->entropy_init = mbedtls_entropy_init;
-    }
-    if (rng->entropy_free == NULL) {
-        rng->entropy_free = mbedtls_entropy_free;
-    }
-
-    rng->entropy_init(&rng->entropy);
-#if defined(MBEDTLS_PSA_INJECT_ENTROPY) && \
-    defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES)
-    /* The PSA entropy injection feature depends on using NV seed as an entropy
-     * source. Add NV seed as an entropy source for PSA entropy injection. */
-    mbedtls_entropy_add_source(&rng->entropy,
-                               mbedtls_nv_seed_poll, NULL,
-                               MBEDTLS_ENTROPY_BLOCK_SIZE,
-                               MBEDTLS_ENTROPY_SOURCE_STRONG);
-#endif
-
-    mbedtls_psa_drbg_init(&rng->drbg);
+    psa_random_internal_init(rng);
 #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
 }
 
@@ -8021,8 +7986,7 @@
 #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
     memset(rng, 0, sizeof(*rng));
 #else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
-    mbedtls_psa_drbg_free(&rng->drbg);
-    rng->entropy_free(&rng->entropy);
+    psa_random_internal_free(rng);
 #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
 }
 
@@ -8035,13 +7999,87 @@
     (void) rng;
     return PSA_SUCCESS;
 #else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
-    const unsigned char drbg_seed[] = "PSA";
-    int ret = mbedtls_psa_drbg_seed(&rng->drbg, &rng->entropy,
-                                    drbg_seed, sizeof(drbg_seed) - 1);
+    return psa_random_internal_seed(rng);
+#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+}
+
+psa_status_t psa_random_reseed(const uint8_t *perso, size_t perso_size)
+{
+    GUARD_MODULE_INITIALIZED;
+#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+    (void) perso;
+    (void) perso_size;
+    return PSA_ERROR_NOT_SUPPORTED;
+#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+#if defined(MBEDTLS_THREADING_C)
+    if (mbedtls_mutex_lock(&mbedtls_threading_psa_rngdata_mutex) != 0) {
+        return PSA_ERROR_SERVICE_FAILURE;
+    }
+#endif /* defined(MBEDTLS_THREADING_C) */
+    int ret = mbedtls_psa_drbg_reseed(&global_data.rng.drbg,
+                                      perso, perso_size);
+#if defined(MBEDTLS_THREADING_C)
+    mbedtls_mutex_unlock(&mbedtls_threading_psa_rngdata_mutex);
+#endif /* defined(MBEDTLS_THREADING_C) */
     return mbedtls_to_psa_error(ret);
 #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
 }
 
+psa_status_t psa_random_deplete(void)
+{
+    GUARD_MODULE_INITIALIZED;
+#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+    return PSA_ERROR_NOT_SUPPORTED;
+#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+#if defined(MBEDTLS_THREADING_C)
+    if (mbedtls_mutex_lock(&mbedtls_threading_psa_rngdata_mutex) != 0) {
+        return PSA_ERROR_SERVICE_FAILURE;
+    }
+#endif /* defined(MBEDTLS_THREADING_C) */
+    mbedtls_psa_drbg_deplete(&global_data.rng.drbg);
+#if defined(MBEDTLS_THREADING_C)
+    mbedtls_mutex_unlock(&mbedtls_threading_psa_rngdata_mutex);
+#endif /* defined(MBEDTLS_THREADING_C) */
+    return PSA_SUCCESS;
+#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+}
+
+psa_status_t psa_random_set_prediction_resistance(unsigned enabled)
+{
+    GUARD_MODULE_INITIALIZED;
+
+#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+    (void) enabled;
+    return PSA_ERROR_NOT_SUPPORTED;
+#else /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+
+    if (enabled != 0 && enabled != 1) {
+        return PSA_ERROR_INVALID_ARGUMENT;
+    }
+
+#if MBEDTLS_ENTROPY_TRUE_SOURCES > 0
+#if defined(MBEDTLS_THREADING_C)
+    if (mbedtls_mutex_lock(&mbedtls_threading_psa_rngdata_mutex) != 0) {
+        return PSA_ERROR_SERVICE_FAILURE;
+    }
+#endif /* defined(MBEDTLS_THREADING_C) */
+    mbedtls_psa_drbg_set_prediction_resistance(&global_data.rng.drbg, enabled);
+#if defined(MBEDTLS_THREADING_C)
+    mbedtls_mutex_unlock(&mbedtls_threading_psa_rngdata_mutex);
+#endif /* defined(MBEDTLS_THREADING_C) */
+    return PSA_SUCCESS;
+
+#else /* MBEDTLS_ENTROPY_TRUE_SOURCES > 0 */
+    if (enabled) {
+        return PSA_ERROR_NOT_SUPPORTED;
+    } else {
+        return PSA_SUCCESS;
+    }
+
+#endif /* MBEDTLS_ENTROPY_TRUE_SOURCES > 0 */
+#endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+}
+
 psa_status_t psa_generate_random(uint8_t *output_external,
                                  size_t output_size)
 {
diff -Nru mbedtls-3.6.5/library/psa_crypto_ffdh.c mbedtls-3.6.6/library/psa_crypto_ffdh.c
--- mbedtls-3.6.5/library/psa_crypto_ffdh.c	2025-10-14 19:12:36.930708200 +0300
+++ mbedtls-3.6.6/library/psa_crypto_ffdh.c	2026-03-27 19:00:27.578571300 +0200
@@ -168,6 +168,10 @@
     mbedtls_mpi_init(&X); mbedtls_mpi_init(&P);
 
     size_t key_len = PSA_BITS_TO_BYTES(attributes->bits);
+    if (key_len > data_size) {
+        status = PSA_ERROR_BUFFER_TOO_SMALL;
+        goto cleanup;
+    }
 
     status = mbedtls_psa_ffdh_set_prime_generator(key_len, &P, &G);
 
@@ -266,35 +270,71 @@
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
-    mbedtls_mpi P, G, X, GY, K;
-    const size_t calculated_shared_secret_size = peer_key_length;
+    mbedtls_mpi P, X, GY, K;
+    const size_t calculated_shared_secret_size = key_buffer_size;
 
-    if (peer_key_length != key_buffer_size ||
-        calculated_shared_secret_size > shared_secret_size) {
+    if (!PSA_KEY_TYPE_IS_DH_KEY_PAIR(psa_get_key_type(attributes))) {
         return PSA_ERROR_INVALID_ARGUMENT;
     }
 
-    if (!PSA_KEY_TYPE_IS_DH_KEY_PAIR(psa_get_key_type(attributes))) {
+    if (peer_key_length != key_buffer_size) {
         return PSA_ERROR_INVALID_ARGUMENT;
     }
 
-    mbedtls_mpi_init(&P); mbedtls_mpi_init(&G);
+    /* This has been checked by the core, but keep a local check too. */
+    if (calculated_shared_secret_size > shared_secret_size) {
+        return PSA_ERROR_BUFFER_TOO_SMALL;
+    }
+
+    mbedtls_mpi_init(&P);
     mbedtls_mpi_init(&X); mbedtls_mpi_init(&GY);
     mbedtls_mpi_init(&K);
 
     status = mbedtls_psa_ffdh_set_prime_generator(
-        PSA_BITS_TO_BYTES(attributes->bits), &P, &G);
+        PSA_BITS_TO_BYTES(attributes->bits), &P, NULL);
 
     if (status != PSA_SUCCESS) {
         goto cleanup;
     }
 
-    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&X, key_buffer,
-                                            key_buffer_size));
-
     MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&GY, peer_key,
                                             peer_key_length));
 
+    /* RFC 7919 5.1: validate the peer's public key: 1 < GY < P-1
+     *
+     * This check is sufficient to ensure GY is not of low order, because we're
+     * using a safe prime (that is, q = (p-1) / 2 is also prime), so the only
+     * group elements of low order are 1 and p-1. (Obviously we also want to
+     * exclude 0 that is not a group element, and values >= p as they are not
+     * residues mod p.)
+     *
+     * Note: we know we're using a safe prime because the only FFDH groups
+     * defined by the PSA spec are from RFC 7919 (since version 1.0) and RFC
+     * 3525 (since v1.4, not yet supported in tf-psa-crypto as of writing this
+     * comment), which both use safe primes.
+     *
+     * Note: NIST SP 800-56Ar3 5.7.1.1 (2) has the check on the shared secret,
+     * but checking before is equivalent (unless our secret key is exactly
+     * (p-1)/2, which has negligible probability and can't be influenced by the
+     * adversary). Checking before is cleaner in terms of side channel analysis,
+     * as we haven't loaded our secret yet, so no worries about branches.
+     *
+     * Use X as a temporary, since we haven't loaded it yet.
+     */
+    MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&X, &P, 1)); // x = p - 1
+    if (mbedtls_mpi_cmp_mpi(&GY, &X) >= 0) {
+        status = PSA_ERROR_INVALID_ARGUMENT;
+        goto cleanup;
+    }
+    MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&X, 1)); // x = 1
+    if (mbedtls_mpi_cmp_mpi(&GY, &X) <= 0) {
+        status = PSA_ERROR_INVALID_ARGUMENT;
+        goto cleanup;
+    }
+
+    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&X, key_buffer,
+                                            key_buffer_size));
+
     /* Calculate shared secret public key: K = G^(XY) mod P = GY^X mod P */
     MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&K, &GY, &X, &P, NULL));
 
@@ -306,7 +346,7 @@
     ret = 0;
 
 cleanup:
-    mbedtls_mpi_free(&P); mbedtls_mpi_free(&G);
+    mbedtls_mpi_free(&P);
     mbedtls_mpi_free(&X); mbedtls_mpi_free(&GY);
     mbedtls_mpi_free(&K);
 
diff -Nru mbedtls-3.6.5/library/psa_crypto_random.c mbedtls-3.6.6/library/psa_crypto_random.c
--- mbedtls-3.6.5/library/psa_crypto_random.c	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/library/psa_crypto_random.c	2026-03-27 19:00:27.581370600 +0200
@@ -0,0 +1,181 @@
+/*
+ *  PSA crypto random generator.
+ */
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#include "common.h"
+
+#if defined(MBEDTLS_PSA_CRYPTO_C) && !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+
+#include "psa_crypto_core.h"
+#include "psa_crypto_random.h"
+#include "psa_crypto_random_impl.h"
+#include "threading_internal.h"
+
+#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
+#include "entropy_poll.h"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE)
+/* For getpid(), for fork protection */
+#include <unistd.h>
+#if defined(MBEDTLS_HAVE_TIME)
+#include <mbedtls/platform_time.h>
+#else
+/* For gettimeofday(), for fork protection without actual entropy */
+#include <sys/time.h>
+#endif
+#endif
+
+void psa_random_internal_init(mbedtls_psa_random_context_t *rng)
+{
+    /* Set default configuration if
+     * mbedtls_psa_crypto_configure_entropy_sources() hasn't been called. */
+    if (rng->entropy_init == NULL) {
+        rng->entropy_init = mbedtls_entropy_init;
+    }
+    if (rng->entropy_free == NULL) {
+        rng->entropy_free = mbedtls_entropy_free;
+    }
+
+    rng->entropy_init(&rng->entropy);
+#if defined(MBEDTLS_PSA_INJECT_ENTROPY) && \
+    defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES)
+    /* The PSA entropy injection feature depends on using NV seed as an entropy
+     * source. Add NV seed as an entropy source for PSA entropy injection. */
+    mbedtls_entropy_add_source(&rng->entropy,
+                               mbedtls_nv_seed_poll, NULL,
+                               MBEDTLS_ENTROPY_BLOCK_SIZE,
+                               MBEDTLS_ENTROPY_SOURCE_STRONG);
+#endif
+
+    mbedtls_psa_drbg_init(&rng->drbg);
+}
+
+void psa_random_internal_free(mbedtls_psa_random_context_t *rng)
+{
+    mbedtls_psa_drbg_free(&rng->drbg);
+    rng->entropy_free(&rng->entropy);
+}
+psa_status_t psa_random_internal_seed(mbedtls_psa_random_context_t *rng)
+{
+    const unsigned char drbg_seed[] = "PSA";
+    int ret = mbedtls_psa_drbg_seed(&rng->drbg, &rng->entropy,
+                                    drbg_seed, sizeof(drbg_seed) - 1);
+#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE)
+    rng->pid = getpid();
+#endif
+    return mbedtls_to_psa_error(ret);
+}
+
+#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE)
+static psa_status_t psa_random_internal_reseed_child(
+    mbedtls_psa_random_context_t *rng,
+    intmax_t pid)
+{
+    /* Reseeding from actual entropy gives the child a unique RNG state
+     * which the parent process cannot predict, and wipes the
+     * parent's RNG state from the child.
+     *
+     * However, in some library configurations, there is no actual
+     * entropy source, only a nonvolatile seed (MBEDTLS_ENTROPY_NV_SEED
+     * enabled and no actual entropy source enabled). In such a
+     * configuration, the reseed operation is deterministic and
+     * always injects the same content, so with the DRBG reseed
+     * process alone, for example, two child processes forked in
+     * close sequence would end up with the same RNG state.
+
+     * To avoid this, we use a personalization string that has a high
+     * likelihood of being unique. This way, the child has a unique state.
+     * The parent can predict the child's RNG state until the next time
+     * it reseeds or generates some random output, but that's
+     * unavoidable in the absence of actual entropy.
+     */
+    struct {
+        /* Using the PID mostly guarantees that each child gets a
+         * unique state. */
+        /* Use intmax_t, not pid_t, because some Unix-like platforms
+         * don't define pid_t, or more likely nowadays they define
+         * pid_t but only with certain platform macros which might not
+         * be the exact ones we use. In practice, this only costs
+         * a couple of instructions to pass and compare two words
+         * rather than one.
+         */
+        intmax_t pid;
+        /* In case an old child had died and its PID is reused for
+         * a new child of the same process, also include the time. */
+#if defined(MBEDTLS_HAVE_TIME)
+        mbedtls_ms_time_t now;
+#else
+        struct timeval now;
+#endif
+    } perso;
+    memset(&perso, 0, sizeof(perso));
+    perso.pid = pid;
+#if defined(MBEDTLS_HAVE_TIME)
+    perso.now = mbedtls_ms_time();
+#else
+    /* We don't have mbedtls_ms_time(), but the platform has getpid().
+     * Use gettimeofday(), which is a classic Unix function. Modern POSIX
+     * has stopped requiring gettimeofday() (in favor of clock_gettime()),
+     * but this is fallback code for restricted configurations, so it's
+     * more likely to be used on embedded platforms that only have a subset
+     * of Unix APIs and are more likely to have the classic gettimeofday(). */
+    if (gettimeofday(&perso.now, NULL) == -1) {
+        return PSA_ERROR_INSUFFICIENT_ENTROPY;
+    }
+#endif
+    int ret = mbedtls_psa_drbg_reseed(&rng->drbg,
+                                      (unsigned char *) &perso, sizeof(perso));
+    return mbedtls_to_psa_error(ret);
+}
+#endif /* MBEDTLS_PLATFORM_IS_UNIXLIKE */
+
+psa_status_t psa_random_internal_generate(
+    mbedtls_psa_random_context_t *rng,
+    uint8_t *output, size_t output_size)
+{
+#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE)
+    intmax_t pid = getpid();
+    if (pid != rng->pid) {
+        /* This is a (grand...)child of the original process, but
+         * we inherited the RNG state from our parent. We must reseed! */
+#if defined(MBEDTLS_THREADING_C)
+        mbedtls_mutex_lock(&mbedtls_threading_psa_rngdata_mutex);
+#endif /* defined(MBEDTLS_THREADING_C) */
+        psa_status_t status = psa_random_internal_reseed_child(rng, pid);
+        if (status == PSA_SUCCESS) {
+            rng->pid = pid;
+        }
+#if defined(MBEDTLS_THREADING_C)
+        mbedtls_mutex_unlock(&mbedtls_threading_psa_rngdata_mutex);
+#endif /* defined(MBEDTLS_THREADING_C) */
+        if (status != PSA_SUCCESS) {
+            return status;
+        }
+    }
+#endif /* MBEDTLS_PLATFORM_IS_UNIXLIKE */
+
+    while (output_size > 0) {
+        size_t request_size =
+            (output_size > MBEDTLS_PSA_RANDOM_MAX_REQUEST ?
+             MBEDTLS_PSA_RANDOM_MAX_REQUEST :
+             output_size);
+#if defined(MBEDTLS_CTR_DRBG_C)
+        int ret = mbedtls_ctr_drbg_random(&rng->drbg, output, request_size);
+#elif defined(MBEDTLS_HMAC_DRBG_C)
+        int ret = mbedtls_hmac_drbg_random(&rng->drbg, output, request_size);
+#endif /* !MBEDTLS_CTR_DRBG_C && !MBEDTLS_HMAC_DRBG_C */
+        if (ret != 0) {
+            return mbedtls_to_psa_error(ret);
+        }
+        output_size -= request_size;
+        output += request_size;
+    }
+    return PSA_SUCCESS;
+}
+
+#endif /* MBEDTLS_PSA_CRYPTO_C && !MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
diff -Nru mbedtls-3.6.5/library/psa_crypto_random.h mbedtls-3.6.6/library/psa_crypto_random.h
--- mbedtls-3.6.5/library/psa_crypto_random.h	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/library/psa_crypto_random.h	2026-03-27 19:00:27.581451200 +0200
@@ -0,0 +1,72 @@
+/*
+ *  PSA crypto random generator internal functions.
+ */
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef PSA_CRYPTO_RANDOM_H
+#define PSA_CRYPTO_RANDOM_H
+
+#include "common.h"
+
+#if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+
+#include <psa/crypto.h>
+#include "psa_crypto_random_impl.h"
+
+/** Initialize the PSA random generator.
+ *
+ * \param[out] rng      The random generator context to initialize.
+ */
+void psa_random_internal_init(mbedtls_psa_random_context_t *rng);
+
+/** Deinitialize the PSA random generator.
+ *
+ * \param[in,out] rng   The random generator context to deinitialize.
+ */
+void psa_random_internal_free(mbedtls_psa_random_context_t *rng);
+
+/** Seed the PSA random generator.
+ *
+ * \note This function is not thread-safe.
+ *
+ * \param[in,out] rng   The random generator context to seed.
+ *
+ * \retval #PSA_SUCCESS
+ *         Success.
+ * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY
+ *         The entropy source failed.
+ */
+psa_status_t psa_random_internal_seed(mbedtls_psa_random_context_t *rng);
+
+/**
+ * \brief Generate random bytes. Like psa_generate_random(), but for use
+ *        inside the library.
+ *
+ * This function is thread-safe.
+ *
+ * \warning This function **can** fail! Callers MUST check the return status
+ *          and MUST NOT use the content of the output buffer if the return
+ *          status is not #PSA_SUCCESS.
+ *
+ * \param[in,out] rng       The random generator context to seed.
+ * \param[out] output       Output buffer for the generated data.
+ * \param output_size       Number of bytes to generate and output.
+ *
+ * \retval #PSA_SUCCESS
+ *         Success.
+ * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY
+ *         The random generator needed to reseed, and the entropy
+ *         source failed.
+ * \retval #PSA_ERROR_HARDWARE_FAILURE
+ *         A hardware accelerator failed.
+ */
+psa_status_t psa_random_internal_generate(
+    mbedtls_psa_random_context_t *rng,
+    uint8_t *output, size_t output_size);
+
+#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */
+
+#endif /* PSA_CRYPTO_RANDOM_H */
diff -Nru mbedtls-3.6.5/library/psa_crypto_random_impl.h mbedtls-3.6.6/library/psa_crypto_random_impl.h
--- mbedtls-3.6.5/library/psa_crypto_random_impl.h	2025-10-14 19:12:36.933508600 +0300
+++ mbedtls-3.6.6/library/psa_crypto_random_impl.h	2026-03-27 19:00:27.581852700 +0200
@@ -70,6 +70,23 @@
     void (* entropy_free)(mbedtls_entropy_context *ctx);
     mbedtls_entropy_context entropy;
     mbedtls_psa_drbg_context_t drbg;
+#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE)
+    /* Fork protection: normally pid = getpid(). If the value changes,
+     * we are in a (grand)*child of the original process, so reseed
+     * the RNG to ensure that the child and the original process have
+     * distinct RNG states. See psa_random_internal_generate().
+     *
+     * The type is intmax_t, not pid_t, for portability reasons:
+     * pid_t is defined in `unistd.h`, but on some platforms, it may
+     * only be defined if a certain compatibility level is requested
+     * by defining a macro such as _POSIX_C_SOURCE or _XOPEN_SOURCE.
+     * The macro needs to be defined before any system header, which
+     * may be hard to do in some C files that include this header
+     * (e.g. test suites). So we sidestep this complication, at the
+     * cost of possibly a few more instructions to compare pid values.
+     */
+    intmax_t pid;
+#endif
 } mbedtls_psa_random_context_t;
 
 /** Initialize the PSA DRBG.
@@ -100,6 +117,8 @@
 
 /** Seed the PSA DRBG.
  *
+ * \param drbg_ctx      The DRBG context to seed.
+ *                      It must be initialized but not active.
  * \param entropy       An entropy context to read the seed from.
  * \param custom        The personalization string.
  *                      This can be \c NULL, in which case the personalization
@@ -121,6 +140,61 @@
 #endif
 }
 
+/** Reseed the PSA DRBG.
+ *
+ * \param drbg_ctx      The DRBG context to reseed.
+ *                      It must be active.
+ * \param additional    Additional data to inject.
+ * \param len           The length of \p additional in bytes.
+ *                      This can be 0 to simply reseed from the entropy source.
+ *
+ * \return              \c 0 on success.
+ * \return              An Mbed TLS error code (\c MBEDTLS_ERR_xxx) on failure.
+ */
+static inline int mbedtls_psa_drbg_reseed(mbedtls_psa_drbg_context_t *drbg_ctx,
+                                          const unsigned char *additional,
+                                          size_t len)
+{
+#if defined(MBEDTLS_CTR_DRBG_C)
+    return mbedtls_ctr_drbg_reseed(drbg_ctx, additional, len);
+#elif defined(MBEDTLS_HMAC_DRBG_C)
+    return mbedtls_hmac_drbg_reseed(drbg_ctx, additional, len);
+#endif
+}
+
+/** Deplete the PSA DRBG, i.e. cause it to reseed the next time it is used.
+ *
+ * \note This function is not thread-safe.
+ *
+ * \param drbg_ctx      The DRBG context to deplete.
+ *                      It must be active.
+ */
+static inline void mbedtls_psa_drbg_deplete(mbedtls_psa_drbg_context_t *drbg_ctx)
+{
+    drbg_ctx->reseed_counter = drbg_ctx->reseed_interval;
+}
+
+#if MBEDTLS_ENTROPY_TRUE_SOURCES > 0
+/** Set prediction resistance in the PSA DRBG.
+ *
+ * \note This function is not thread-safe.
+ *
+ * \param drbg_ctx      The DRBG context to reconfigure.
+ *                      It must be active.
+ * \param enabled       \c 1 to enable, or \c 0 to disable.
+ */
+static inline void mbedtls_psa_drbg_set_prediction_resistance(
+    mbedtls_psa_drbg_context_t *drbg_ctx,
+    unsigned enabled)
+{
+#if defined(MBEDTLS_CTR_DRBG_C)
+    mbedtls_ctr_drbg_set_prediction_resistance(drbg_ctx, enabled);
+#elif defined(MBEDTLS_HMAC_DRBG_C)
+    mbedtls_hmac_drbg_set_prediction_resistance(drbg_ctx, enabled);
+#endif
+}
+#endif /* MBEDTLS_ENTROPY_TRUE_SOURCES > 0 */
+
 #endif /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
 
 #endif /* PSA_CRYPTO_RANDOM_IMPL_H */
diff -Nru mbedtls-3.6.5/library/psa_crypto_slot_management.c mbedtls-3.6.6/library/psa_crypto_slot_management.c
--- mbedtls-3.6.5/library/psa_crypto_slot_management.c	2025-10-14 19:12:36.935118000 +0300
+++ mbedtls-3.6.6/library/psa_crypto_slot_management.c	2026-03-27 19:00:27.582763700 +0200
@@ -684,6 +684,12 @@
     psa_status_t status = PSA_SUCCESS;
     uint8_t *key_data = NULL;
     size_t key_data_length = 0;
+    psa_key_id_t key_id = MBEDTLS_SVC_KEY_ID_GET_KEY_ID(slot->attr.id);
+
+    /* Do not try to load a persistent key whose ID is in the volatile range. */
+    if ((key_id >= PSA_KEY_ID_VOLATILE_MIN) && (key_id <= PSA_KEY_ID_VOLATILE_MAX)) {
+        return PSA_ERROR_DOES_NOT_EXIST;
+    }
 
     status = psa_load_persistent_key(&slot->attr,
                                      &key_data, &key_data_length);
diff -Nru mbedtls-3.6.5/library/rsa_alt_helpers.c mbedtls-3.6.6/library/rsa_alt_helpers.c
--- mbedtls-3.6.5/library/rsa_alt_helpers.c	2025-10-14 19:12:36.937463800 +0300
+++ mbedtls-3.6.6/library/rsa_alt_helpers.c	2026-03-27 19:00:27.584295000 +0200
@@ -188,7 +188,7 @@
     int ret = 0;
     mbedtls_mpi K, L;
 
-    if (D == NULL || mbedtls_mpi_cmp_int(D, 0) != 0) {
+    if (D == NULL) {
         return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
     }
 
diff -Nru mbedtls-3.6.5/library/rsa.c mbedtls-3.6.6/library/rsa.c
--- mbedtls-3.6.5/library/rsa.c	2025-10-14 19:12:36.936987600 +0300
+++ mbedtls-3.6.6/library/rsa.c	2026-03-27 19:00:27.584156300 +0200
@@ -1101,7 +1101,6 @@
          * if it exists (FIPS 186-4 §B.3.1 criterion 2(a)) */
         ret = mbedtls_rsa_deduce_private_exponent(&ctx->P, &ctx->Q, &ctx->E, &ctx->D);
         if (ret == MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
-            mbedtls_mpi_lset(&ctx->D, 0); /* needed for the next call */
             continue;
         }
         if (ret != 0) {
@@ -1268,6 +1267,117 @@
     return 0;
 }
 
+#if !defined(MBEDTLS_RSA_NO_CRT)
+/*
+ * Compute T such that T = TP mod P and T = TQ mod Q.
+ * (This is the Chinese Remainder Theorem - CRT.)
+ */
+static int rsa_apply_crt(mbedtls_mpi *T,
+                         const mbedtls_mpi *TP,
+                         const mbedtls_mpi *TQ,
+                         const mbedtls_rsa_context *ctx)
+{
+    int ret;
+
+    /*
+     * Set T = ((TP - TQ) * (Q^-1 mod P) mod P) * Q + TQ
+     *
+     * That way we have both:
+     * mod P: T = (TP - TQ) * (Q^-1 * Q) + TQ = (TP - TQ) * 1 + TQ = TP
+     * mod Q: T = (...) * Q + TQ = TQ
+     */
+    MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(T, TP, TQ));        // T = TP - TQ
+    MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(T, T, &ctx->QP));   // T *= Q^-1 mod P
+    MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(T, T, &ctx->P));    // T %= P
+    MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(T, T, &ctx->Q));    // T *= Q
+    MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(T, T, TQ));         // T += TQ
+
+cleanup:
+    return ret;
+}
+#endif
+
+/* Generate random A and B such that A^-1 = B mod N */
+static int rsa_gen_rand_with_inverse(const mbedtls_rsa_context *ctx,
+                                     mbedtls_mpi *A,
+                                     mbedtls_mpi *B,
+                                     int (*f_rng)(void *, unsigned char *, size_t),
+                                     void *p_rng)
+{
+#if defined(MBEDTLS_RSA_NO_CRT)
+    int ret;
+    mbedtls_mpi G;
+
+    mbedtls_mpi_init(&G);
+
+    MBEDTLS_MPI_CHK(mbedtls_mpi_random(A, 1, &ctx->N, f_rng, p_rng));
+    MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(&G, B, A, &ctx->N));
+
+    if (mbedtls_mpi_cmp_int(&G, 1) != 0) {
+        /* This happens if we're unlucky enough to draw a multiple of P or Q,
+         * or if (at least) one of them is not a prime, and we drew a multiple
+         * of one of its factors. */
+        ret = MBEDTLS_ERR_RSA_RNG_FAILED;
+        goto cleanup;
+    }
+
+cleanup:
+    mbedtls_mpi_free(&G);
+
+    return ret;
+#else
+    int ret;
+    mbedtls_mpi Ap, Aq, Bp, Bq, G;
+
+    mbedtls_mpi_init(&Ap); mbedtls_mpi_init(&Aq);
+    mbedtls_mpi_init(&Bp); mbedtls_mpi_init(&Bq);
+    mbedtls_mpi_init(&G);
+
+    /*
+     * Instead of generating A, B = A^-1 (mod N) directly, generate one Ap, Bp
+     * pair (mod P) and one pair (mod Q) and use Chinese Remainder Theorem to
+     * construct an A and B from those.
+     *
+     * This works because the CRT correspondence is a ring isomorphism between
+     * Z/NZ (integers mod N) and Z/PZ x Z/QZ (pairs of integers mod P and Q):
+     * - it is a bijection (one-to-one correspondence);
+     * - doing a ring operation (modular +, -, *, ^-1 when possible) on one side is
+     *   the same as doing it on the other side.
+     * So, drawing uniformly at random an invertible A mod N is the same as
+     * drawing uniformly at random pairs of invertible Ap mod P, Aq mod Q.
+     */
+
+    /* Generate Ap in [1, P) and compute Bp = Ap^-1 mod P */
+    MBEDTLS_MPI_CHK(mbedtls_mpi_random(&Ap, 1, &ctx->P, f_rng, p_rng));
+    MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(&G, &Bp, &Ap, &ctx->P));
+    if (mbedtls_mpi_cmp_int(&G, 1) != 0) {
+        /* This can only happen if P was not a prime. */
+        ret = MBEDTLS_ERR_RSA_RNG_FAILED;
+        goto cleanup;
+    }
+
+    /* Generate Aq in [1, Q) and compute Bq = Aq^-1 mod Q */
+    MBEDTLS_MPI_CHK(mbedtls_mpi_random(&Aq, 1, &ctx->Q, f_rng, p_rng));
+    MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(&G, &Bq, &Aq, &ctx->Q));
+    if (mbedtls_mpi_cmp_int(&G, 1) != 0) {
+        /* This can only happen if Q was not a prime. */
+        ret = MBEDTLS_ERR_RSA_RNG_FAILED;
+        goto cleanup;
+    }
+
+    /* Reconstruct A and B */
+    MBEDTLS_MPI_CHK(rsa_apply_crt(A, &Ap, &Aq, ctx));
+    MBEDTLS_MPI_CHK(rsa_apply_crt(B, &Bp, &Bq, ctx));
+
+cleanup:
+    mbedtls_mpi_free(&Ap); mbedtls_mpi_free(&Aq);
+    mbedtls_mpi_free(&Bp); mbedtls_mpi_free(&Bq);
+    mbedtls_mpi_free(&G);
+
+    return ret;
+#endif
+}
+
 /*
  * Generate or update blinding values, see section 10 of:
  *  KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA,
@@ -1277,10 +1387,7 @@
 static int rsa_prepare_blinding(mbedtls_rsa_context *ctx,
                                 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
 {
-    int ret, count = 0;
-    mbedtls_mpi R;
-
-    mbedtls_mpi_init(&R);
+    int ret;
 
     if (ctx->Vf.p != NULL) {
         /* We already have blinding values, just update them by squaring */
@@ -1288,30 +1395,17 @@
         MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->Vi, &ctx->Vi, &ctx->N));
         MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&ctx->Vf, &ctx->Vf, &ctx->Vf));
         MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&ctx->Vf, &ctx->Vf, &ctx->N));
-
         goto cleanup;
     }
 
     /* Unblinding value: Vf = random number, invertible mod N */
-    mbedtls_mpi_lset(&R, 0);
-    do {
-        if (count++ > 10) {
-            ret = MBEDTLS_ERR_RSA_RNG_FAILED;
-            goto cleanup;
-        }
-
-        MBEDTLS_MPI_CHK(mbedtls_mpi_random(&ctx->Vf, 1, &ctx->N, f_rng, p_rng));
-        MBEDTLS_MPI_CHK(mbedtls_mpi_gcd_modinv_odd(&R, &ctx->Vi, &ctx->Vf, &ctx->N));
-    } while (mbedtls_mpi_cmp_int(&R, 1) != 0);
+    MBEDTLS_MPI_CHK(rsa_gen_rand_with_inverse(ctx, &ctx->Vf, &ctx->Vi, f_rng, p_rng));
 
     /* Blinding value: Vi = Vf^(-e) mod N
      * (Vi already contains Vf^-1 at this point) */
     MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&ctx->Vi, &ctx->Vi, &ctx->E, &ctx->N, &ctx->RN));
 
-
 cleanup:
-    mbedtls_mpi_free(&R);
-
     return ret;
 }
 
@@ -1511,19 +1605,7 @@
 
     MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&TP, &T, &DP_blind, &ctx->P, &ctx->RP));
     MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&TQ, &T, &DQ_blind, &ctx->Q, &ctx->RQ));
-
-    /*
-     * T = (TP - TQ) * (Q^-1 mod P) mod P
-     */
-    MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&T, &TP, &TQ));
-    MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&TP, &T, &ctx->QP));
-    MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&T, &TP, &ctx->P));
-
-    /*
-     * T = TQ + T * Q
-     */
-    MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&TP, &T, &ctx->Q));
-    MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&T, &TQ, &TP));
+    MBEDTLS_MPI_CHK(rsa_apply_crt(&T, &TP, &TQ, ctx));
 #endif /* MBEDTLS_RSA_NO_CRT */
 
     /* Verify the result to prevent glitching attacks. */
diff -Nru mbedtls-3.6.5/library/sha256.c mbedtls-3.6.6/library/sha256.c
--- mbedtls-3.6.5/library/sha256.c	2025-10-14 19:12:36.938674000 +0300
+++ mbedtls-3.6.6/library/sha256.c	2026-03-27 19:00:27.584950000 +0200
@@ -10,6 +10,11 @@
  *  http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
  */
 
+/* Ensure that SIG_SETMASK is defined when -std=c99 is used. */
+#if !defined(_GNU_SOURCE)
+#define _GNU_SOURCE
+#endif
+
 #if defined(__clang__) &&  (__clang_major__ >= 4)
 
 /* Ideally, we would simply use MBEDTLS_ARCH_IS_ARMV8_A in the following #if,
@@ -21,15 +26,18 @@
 #endif
 
 #if defined(MBEDTLS_SHA256_ARCH_IS_ARMV8_A) && !defined(__ARM_FEATURE_CRYPTO)
-/* TODO: Re-consider above after https://reviews.llvm.org/D131064 merged.
- *
+/*
  * The intrinsic declaration are guarded by predefined ACLE macros in clang:
  * these are normally only enabled by the -march option on the command line.
  * By defining the macros ourselves we gain access to those declarations without
  * requiring -march on the command line.
  *
  * `arm_neon.h` is included by common.h, so we put these defines
- * at the top of this file, before any includes.
+ * at the top of this file, before any includes but after the intrinsic
+ * declaration. This is necessary with
+ * Clang <=15.x. With Clang 16.0 and above, these macro definitions are
+ * no longer required, but they're harmless. See
+ * https://reviews.llvm.org/D131064
  */
 #define __ARM_FEATURE_CRYPTO 1
 /* See: https://arm-software.github.io/acle/main/acle.html#cryptographic-extensions
@@ -43,11 +51,6 @@
 
 #endif /* defined(__clang__) &&  (__clang_major__ >= 4) */
 
-/* Ensure that SIG_SETMASK is defined when -std=c99 is used. */
-#if !defined(_GNU_SOURCE)
-#define _GNU_SOURCE
-#endif
-
 #include "common.h"
 
 #if defined(MBEDTLS_SHA256_C) || defined(MBEDTLS_SHA224_C)
diff -Nru mbedtls-3.6.5/library/sha512.c mbedtls-3.6.6/library/sha512.c
--- mbedtls-3.6.5/library/sha512.c	2025-10-14 19:12:36.939272000 +0300
+++ mbedtls-3.6.6/library/sha512.c	2026-03-27 19:00:27.585364600 +0200
@@ -12,15 +12,18 @@
 
 #if defined(__aarch64__) && !defined(__ARM_FEATURE_SHA512) && \
     defined(__clang__) && __clang_major__ >= 7
-/* TODO: Re-consider above after https://reviews.llvm.org/D131064 merged.
- *
+/*
  * The intrinsic declaration are guarded by predefined ACLE macros in clang:
  * these are normally only enabled by the -march option on the command line.
  * By defining the macros ourselves we gain access to those declarations without
  * requiring -march on the command line.
  *
  * `arm_neon.h` is included by common.h, so we put these defines
- * at the top of this file, before any includes.
+ * at the top of this file, before any includes but after the intrinsic
+ * declaration. This is necessary with
+ * Clang <=15.x. With Clang 16.0 and above, these macro definitions are
+ * no longer required, but they're harmless. See
+ * https://reviews.llvm.org/D131064
  */
 #define __ARM_FEATURE_SHA512 1
 #define MBEDTLS_ENABLE_ARM_SHA3_EXTENSIONS_COMPILER_FLAG
diff -Nru mbedtls-3.6.5/library/ssl_debug_helpers.h mbedtls-3.6.6/library/ssl_debug_helpers.h
--- mbedtls-3.6.5/library/ssl_debug_helpers.h	2025-10-14 19:12:36.941942500 +0300
+++ mbedtls-3.6.6/library/ssl_debug_helpers.h	2026-03-27 19:00:27.587410000 +0200
@@ -38,6 +38,8 @@
 
 const char *mbedtls_ssl_get_extension_name(unsigned int extension_type);
 
+const char *mbedtls_ssl_get_hs_msg_name(int hs_msg_type);
+
 void mbedtls_ssl_print_extensions(const mbedtls_ssl_context *ssl,
                                   int level, const char *file, int line,
                                   int hs_msg_type, uint32_t extensions_mask,
diff -Nru mbedtls-3.6.5/library/ssl_misc.h mbedtls-3.6.6/library/ssl_misc.h
--- mbedtls-3.6.5/library/ssl_misc.h	2025-10-14 19:12:36.942909700 +0300
+++ mbedtls-3.6.6/library/ssl_misc.h	2026-03-27 19:00:27.588500300 +0200
@@ -1351,14 +1351,14 @@
                                                    mbedtls_ssl_states state)
 {
     MBEDTLS_SSL_DEBUG_MSG(3, ("handshake state: %d (%s) -> %d (%s)",
-                              ssl->state, mbedtls_ssl_states_str(ssl->state),
+                              ssl->state, mbedtls_ssl_states_str((mbedtls_ssl_states) ssl->state),
                               (int) state, mbedtls_ssl_states_str(state)));
     ssl->state = (int) state;
 }
 
 static inline void mbedtls_ssl_handshake_increment_state(mbedtls_ssl_context *ssl)
 {
-    mbedtls_ssl_handshake_set_state(ssl, ssl->state + 1);
+    mbedtls_ssl_handshake_set_state(ssl, (mbedtls_ssl_states) (ssl->state + 1));
 }
 
 MBEDTLS_CHECK_RETURN_CRITICAL
diff -Nru mbedtls-3.6.5/library/ssl_msg.c mbedtls-3.6.6/library/ssl_msg.c
--- mbedtls-3.6.5/library/ssl_msg.c	2025-10-14 19:12:36.943813000 +0300
+++ mbedtls-3.6.6/library/ssl_msg.c	2026-03-27 19:00:27.589213100 +0200
@@ -19,6 +19,7 @@
 #include "mbedtls/ssl.h"
 #include "ssl_misc.h"
 #include "debug_internal.h"
+#include "ssl_debug_helpers.h"
 #include "mbedtls/error.h"
 #include "mbedtls/platform_util.h"
 #include "mbedtls/version.h"
@@ -321,7 +322,7 @@
                              size_t buflen)
 {
     int ret = 0;
-    MBEDTLS_SSL_DEBUG_MSG(1, ("=> mbedtls_ssl_check_record"));
+    MBEDTLS_SSL_DEBUG_MSG(3, ("=> mbedtls_ssl_check_record"));
     MBEDTLS_SSL_DEBUG_BUF(3, "record buffer", buf, buflen);
 
     /* We don't support record checking in TLS because
@@ -363,7 +364,7 @@
         ret = MBEDTLS_ERR_SSL_UNEXPECTED_RECORD;
     }
 
-    MBEDTLS_SSL_DEBUG_MSG(1, ("<= mbedtls_ssl_check_record"));
+    MBEDTLS_SSL_DEBUG_MSG(3, ("<= mbedtls_ssl_check_record"));
     return ret;
 }
 
@@ -375,6 +376,7 @@
 /* Forward declarations for functions related to message buffering. */
 static void ssl_buffering_free_slot(mbedtls_ssl_context *ssl,
                                     uint8_t slot);
+static void ssl_buffering_shift_slots(mbedtls_ssl_context *ssl, unsigned shift);
 static void ssl_free_buffered_record(mbedtls_ssl_context *ssl);
 MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_load_buffered_message(mbedtls_ssl_context *ssl);
@@ -2618,7 +2620,8 @@
                               max_hs_frag_len : rem_len;
 
             if (frag_off == 0 && cur_hs_frag_len != hs_len) {
-                MBEDTLS_SSL_DEBUG_MSG(2, ("fragmenting handshake message (%u > %u)",
+                MBEDTLS_SSL_DEBUG_MSG(2, ("fragmenting %s handshake message (%u > %u)",
+                                          mbedtls_ssl_get_hs_msg_name(cur->p[0]),
                                           (unsigned) cur_hs_frag_len,
                                           (unsigned) max_hs_frag_len));
             }
@@ -3259,6 +3262,54 @@
             return MBEDTLS_ERR_SSL_INVALID_RECORD;
         }
 
+        if (ssl->in_msg[0] == MBEDTLS_SSL_HS_CLIENT_HELLO &&
+            ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER) {
+            if (ssl->state == MBEDTLS_SSL_CLIENT_HELLO
+#if defined(MBEDTLS_SSL_RENEGOTIATION)
+                && ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE
+#endif
+                ) {
+                /*
+                 * When establishing the connection, the client may go through
+                 * a series of ClientHello and HelloVerifyRequest requests and
+                 * responses. The server intentionally does not keep trace of
+                 * these initial round trips: minimum allocated ressources as
+                 * long as the reachability of the client has not been
+                 * confirmed. When receiving the "first ClientHello" from
+                 * server perspective, we may thus need to adapt the next
+                 * expected `message_seq` for the incoming and outgoing
+                 * handshake messages.
+                 */
+                if ((ssl->handshake->in_msg_seq == 0) && (recv_msg_seq > 0)) {
+                    MBEDTLS_SSL_DEBUG_MSG(3, ("shift slots by %u", recv_msg_seq));
+                    ssl_buffering_shift_slots(ssl, recv_msg_seq);
+                    ssl->handshake->in_msg_seq = recv_msg_seq;
+                    ssl->handshake->out_msg_seq = recv_msg_seq;
+                }
+
+                /* Epoch should be 0 for initial handshakes */
+                if (ssl->in_ctr[0] != 0 || ssl->in_ctr[1] != 0) {
+                    MBEDTLS_SSL_DEBUG_MSG(1, ("bad client hello message"));
+                    return MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER;
+                }
+
+                memcpy(&ssl->cur_out_ctr[2], ssl->in_ctr + 2,
+                       sizeof(ssl->cur_out_ctr) - 2);
+
+            } else if (mbedtls_ssl_is_handshake_over(ssl) == 1) {
+                /* In case of a post-handshake ClientHello that initiates a
+                 * renegotiation check that the handshake message sequence
+                 * number is zero.
+                 */
+                if (recv_msg_seq != 0) {
+                    MBEDTLS_SSL_DEBUG_MSG(1, ("bad client hello message_seq: "
+                                              "%u (expected 0)",
+                                              recv_msg_seq));
+                    return MBEDTLS_ERR_SSL_DECODE_ERROR;
+                }
+            }
+        }
+
         if (ssl->handshake != NULL &&
             ((mbedtls_ssl_is_handshake_over(ssl) == 0 &&
               recv_msg_seq != ssl->handshake->in_msg_seq) ||
@@ -3427,28 +3478,10 @@
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
     if (ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
         ssl->handshake != NULL) {
-        unsigned offset;
-        mbedtls_ssl_hs_buffer *hs_buf;
 
         /* Increment handshake sequence number */
         hs->in_msg_seq++;
-
-        /*
-         * Clear up handshake buffering and reassembly structure.
-         */
-
-        /* Free first entry */
-        ssl_buffering_free_slot(ssl, 0);
-
-        /* Shift all other entries */
-        for (offset = 0, hs_buf = &hs->buffering.hs[0];
-             offset + 1 < MBEDTLS_SSL_MAX_BUFFERED_HS;
-             offset++, hs_buf++) {
-            *hs_buf = *(hs_buf + 1);
-        }
-
-        /* Create a fresh last entry */
-        memset(hs_buf, 0, sizeof(mbedtls_ssl_hs_buffer));
+        ssl_buffering_shift_slots(ssl, 1);
     }
 #endif
     return 0;
@@ -3865,7 +3898,7 @@
                               (
                                   "datagram of length %u too small to hold DTLS record header of length %u",
                                   (unsigned) len,
-                                  (unsigned) (rec_hdr_len_len + rec_hdr_len_len)));
+                                  (unsigned) (rec_hdr_len_offset + rec_hdr_len_len)));
         return MBEDTLS_ERR_SSL_INVALID_RECORD;
     }
 
@@ -4449,7 +4482,9 @@
             return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
         }
 
-        MBEDTLS_SSL_DEBUG_MSG(2, ("Next handshake message has been buffered - load"));
+        MBEDTLS_SSL_DEBUG_MSG(2, ("%s handshake message has been buffered%s",
+                                  mbedtls_ssl_get_hs_msg_name(hs_buf->data[0]),
+                                  hs_buf->is_fragmented ? " and reassembled" : ""));
         MBEDTLS_SSL_DEBUG_BUF(3, "Buffered handshake message (incl. header)",
                               hs_buf->data, msg_len + 12);
 
@@ -4995,6 +5030,31 @@
                 ret = MBEDTLS_ERR_SSL_UNEXPECTED_RECORD;
             }
 
+#if defined(MBEDTLS_SSL_SRV_C)
+            /*
+             * In DTLS, invalid records are usually ignored because it is easy
+             * for an attacker to inject UDP datagrams, and we do not want such
+             * packets to disrupt the entire connection.
+             *
+             * However, when expecting the ClientHello, we reject invalid or
+             * unexpected records. This avoids waiting for further records
+             * before receiving at least one valid message. Such records could
+             * be leftover messages from a previous connection, accidental
+             * input, or part of a DoS attempt.
+             *
+             * Since no valid message has been received yet, immediately
+             * closing the connection does not result in any loss.
+             */
+            if ((ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER) &&
+                (ssl->state == MBEDTLS_SSL_CLIENT_HELLO)
+#if defined(MBEDTLS_SSL_RENEGOTIATION)
+                && (ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE)
+#endif
+                ) {
+                return ret;
+            }
+#endif /* MBEDTLS_SSL_SRV_C */
+
             if (ret == MBEDTLS_ERR_SSL_UNEXPECTED_RECORD) {
 #if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C)
                 /* Reset in pointers to default state for TLS/DTLS records,
@@ -5133,14 +5193,9 @@
     /* The record content type may change during decryption,
      * so re-read it. */
     ssl->in_msgtype = rec.type;
-    /* Also update the input buffer, because unfortunately
-     * the server-side ssl_parse_client_hello() reparses the
-     * record header when receiving a ClientHello initiating
-     * a renegotiation. */
-    ssl->in_hdr[0] = rec.type;
+
     ssl->in_msg    = rec.buf + rec.data_offset;
     ssl->in_msglen = rec.data_len;
-    MBEDTLS_PUT_UINT16_BE(rec.data_len, ssl->in_len, 0);
 
     return 0;
 }
@@ -5826,6 +5881,11 @@
             ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_PENDING;
         }
 #endif
+
+        /* Keep the ClientHello message for ssl_parse_client_hello() */
+        if (ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER) {
+            ssl->keep_current_message = 1;
+        }
         ret = mbedtls_ssl_start_renegotiation(ssl);
         if (ret != MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO &&
             ret != 0) {
@@ -6423,6 +6483,42 @@
     }
 }
 
+/*
+ * Shift the buffering slots to the left by `shift` positions.
+ * After the operation, slot i contains the previous slot i + shift.
+ */
+static void ssl_buffering_shift_slots(mbedtls_ssl_context *ssl,
+                                      unsigned shift)
+{
+    mbedtls_ssl_handshake_params * const hs = ssl->handshake;
+    unsigned offset;
+
+    if (shift == 0) {
+        return;
+    }
+
+    if (shift >= MBEDTLS_SSL_MAX_BUFFERED_HS) {
+        shift = MBEDTLS_SSL_MAX_BUFFERED_HS;
+    }
+
+    /* Free discarded entries */
+    for (offset = 0; offset < shift; offset++) {
+        ssl_buffering_free_slot(ssl, offset);
+    }
+
+    /* Shift remaining entries left */
+    for (offset = 0; offset + shift < MBEDTLS_SSL_MAX_BUFFERED_HS; offset++) {
+        hs->buffering.hs[offset] = hs->buffering.hs[offset + shift];
+    }
+
+    /* Reset the remaining entries at the end. Some may already have been
+     * cleared by the loop freeing the discarded entries, but resetting all
+     * of them is simpler and avoids tracking which ones were already handled.
+     */
+    for (; offset < MBEDTLS_SSL_MAX_BUFFERED_HS; offset++) {
+        memset(&hs->buffering.hs[offset], 0, sizeof(hs->buffering.hs[offset]));
+    }
+}
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
 
 /*
diff -Nru mbedtls-3.6.5/library/ssl_tls12_client.c mbedtls-3.6.6/library/ssl_tls12_client.c
--- mbedtls-3.6.5/library/ssl_tls12_client.c	2025-10-14 19:12:36.946297000 +0300
+++ mbedtls-3.6.6/library/ssl_tls12_client.c	2026-03-27 19:00:27.590912600 +0200
@@ -2078,6 +2078,46 @@
 #endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) ||
           MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */
 
+#if defined(MBEDTLS_KEY_EXCHANGE_WITH_SERVER_SIGNATURE_ENABLED)
+MBEDTLS_CHECK_RETURN_CRITICAL
+static int ssl_parse_signature_algorithm(mbedtls_ssl_context *ssl,
+                                         uint16_t sig_alg,
+                                         mbedtls_md_type_t *md_alg,
+                                         mbedtls_pk_type_t *pk_alg)
+{
+    if (mbedtls_ssl_get_pk_type_and_md_alg_from_sig_alg(sig_alg, pk_alg, md_alg) != 0) {
+        MBEDTLS_SSL_DEBUG_MSG(1,
+                              ("Server used unsupported value in SigAlg extension 0x%04x",
+                               sig_alg));
+        return MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER;
+    }
+
+    /*
+     * mbedtls_ssl_get_pk_sigalg_and_md_alg_from_sig_alg() understands sig_alg code points across
+     * TLS versions. Make sure that the received sig_alg extension is valid in TLS 1.2.
+     */
+    if (!mbedtls_ssl_sig_alg_is_supported(ssl, sig_alg)) {
+        MBEDTLS_SSL_DEBUG_MSG(1,
+                              ("Server used unsupported value in SigAlg extension 0x%04x",
+                               sig_alg));
+        return MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER;
+    }
+
+    /*
+     * Check if the signature algorithm is acceptable
+     */
+    if (!mbedtls_ssl_sig_alg_is_offered(ssl, sig_alg)) {
+        MBEDTLS_SSL_DEBUG_MSG(1, ("Server used SigAlg value 0x%04x that was not offered", sig_alg));
+        return MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER;
+    }
+
+    MBEDTLS_SSL_DEBUG_MSG(2, ("Server used SignatureAlgorithm %d", sig_alg & 0x00FF));
+    MBEDTLS_SSL_DEBUG_MSG(2, ("Server used HashAlgorithm %d", sig_alg >> 8));
+
+    return 0;
+}
+#endif /* MBEDTLS_KEY_EXCHANGE_WITH_SERVER_SIGNATURE_ENABLED) */
+
 MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_server_key_exchange(mbedtls_ssl_context *ssl)
 {
@@ -2300,7 +2340,6 @@
         unsigned char *params = ssl->in_msg + mbedtls_ssl_hs_hdr_len(ssl);
         size_t params_len = (size_t) (p - params);
         void *rs_ctx = NULL;
-        uint16_t sig_alg;
 
         mbedtls_pk_context *peer_pk;
 
@@ -2319,11 +2358,8 @@
          * Handle the digitally-signed structure
          */
         MBEDTLS_SSL_CHK_BUF_READ_PTR(p, end, 2);
-        sig_alg = MBEDTLS_GET_UINT16_BE(p, 0);
-        if (mbedtls_ssl_get_pk_type_and_md_alg_from_sig_alg(
-                sig_alg, &pk_alg, &md_alg) != 0 &&
-            !mbedtls_ssl_sig_alg_is_offered(ssl, sig_alg) &&
-            !mbedtls_ssl_sig_alg_is_supported(ssl, sig_alg)) {
+        uint16_t sig_alg = MBEDTLS_GET_UINT16_BE(p, 0);
+        if (ssl_parse_signature_algorithm(ssl, sig_alg, &md_alg, &pk_alg) != 0) {
             MBEDTLS_SSL_DEBUG_MSG(1,
                                   ("bad server key exchange message"));
             mbedtls_ssl_send_alert_message(
@@ -2764,7 +2800,7 @@
 
         header_len = 4;
 
-        MBEDTLS_SSL_DEBUG_MSG(1, ("Perform PSA-based ECDH computation."));
+        MBEDTLS_SSL_DEBUG_MSG(3, ("Perform PSA-based ECDH computation."));
 
         /*
          * Generate EC private key for ECDHE exchange.
@@ -2936,7 +2972,7 @@
 
         header_len += ssl->conf->psk_identity_len;
 
-        MBEDTLS_SSL_DEBUG_MSG(1, ("Perform PSA-based ECDH computation."));
+        MBEDTLS_SSL_DEBUG_MSG(3, ("Perform PSA-based ECDH computation."));
 
         /*
          * Generate EC private key for ECDHE exchange.
diff -Nru mbedtls-3.6.5/library/ssl_tls12_server.c mbedtls-3.6.6/library/ssl_tls12_server.c
--- mbedtls-3.6.5/library/ssl_tls12_server.c	2025-10-14 19:12:36.947482000 +0300
+++ mbedtls-3.6.6/library/ssl_tls12_server.c	2026-03-27 19:00:27.591469800 +0200
@@ -912,132 +912,70 @@
 
     MBEDTLS_SSL_DEBUG_MSG(2, ("=> parse client hello"));
 
-    int renegotiating;
-
-#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
-read_record_header:
-#endif
     /*
-     * If renegotiating, then the input was read with mbedtls_ssl_read_record(),
-     * otherwise read it ourselves manually in order to support SSLv2
-     * ClientHello, which doesn't use the same record layer format.
-     * Otherwise in a scenario of TLS 1.3/TLS 1.2 version negotiation, the
-     * ClientHello has been already fully fetched by the TLS 1.3 code and the
-     * flag ssl->keep_current_message is raised.
+     * Fetch the expected ClientHello handshake message. Do not ask
+     * mbedtls_ssl_read_record() to update the handshake digest, because the
+     * ClientHello may already have been read in ssl_tls13_process_client_hello()
+     * or as a post-handshake message (renegotiation). In those cases we need
+     * to update the digest ourselves, and it is simpler to do so
+     * unconditionally than to track whether it is needed.
      */
-    renegotiating = 0;
-#if defined(MBEDTLS_SSL_RENEGOTIATION)
-    renegotiating = (ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE);
-#endif
-    if (!renegotiating && !ssl->keep_current_message) {
-        if ((ret = mbedtls_ssl_fetch_input(ssl, 5)) != 0) {
-            /* No alert on a read error. */
-            MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_fetch_input", ret);
-            return ret;
-        }
-    }
-
-    buf = ssl->in_hdr;
-
-    MBEDTLS_SSL_DEBUG_BUF(4, "record header", buf, mbedtls_ssl_in_hdr_len(ssl));
+    if ((ret = mbedtls_ssl_read_record(ssl, 0)) != 0) {
+        MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_read_record ", ret);
 
-    /*
-     * TLS Client Hello
-     *
-     * Record layer:
-     *     0  .   0   message type
-     *     1  .   2   protocol version
-     *     3  .   11  DTLS: epoch + record sequence number
-     *     3  .   4   message length
-     */
-    MBEDTLS_SSL_DEBUG_MSG(3, ("client hello, message type: %d",
-                              buf[0]));
-
-    if (buf[0] != MBEDTLS_SSL_MSG_HANDSHAKE) {
-        MBEDTLS_SSL_DEBUG_MSG(1, ("bad client hello message"));
-        return MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE;
-    }
-
-    MBEDTLS_SSL_DEBUG_MSG(3, ("client hello, message len.: %d",
-                              MBEDTLS_GET_UINT16_BE(ssl->in_len, 0)));
-
-    MBEDTLS_SSL_DEBUG_MSG(3, ("client hello, protocol version: [%d:%d]",
-                              buf[1], buf[2]));
-
-    /* For DTLS if this is the initial handshake, remember the client sequence
-     * number to use it in our next message (RFC 6347 4.2.1) */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if (ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM
+        /*
+         * In the case of an alert message corresponding to the termination of
+         * a previous connection, `ssl_parse_record_header()` and then
+         * `mbedtls_ssl_read_record()` may return
+         * MBEDTLS_ERR_SSL_UNEXPECTED_RECORD because of a non zero epoch.
+         *
+         * Historically, the library has returned
+         * MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE in this situation.
+         * The sample program dtls_server.c relies on this behavior
+         * (see
+         * https://github.com/Mbed-TLS/mbedtls/blob/d5e35a376bee23fad0b17f2e3e94a32ce4017c64/programs/ssl/dtls_server.c#L295),
+         * and user applications may rely on it as well.
+         *
+         * For compatibility, map MBEDTLS_ERR_SSL_UNEXPECTED_RECORD
+         * to MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE here.
+         *
+         * MBEDTLS_ERR_SSL_UNEXPECTED_RECORD does not appear to be
+         * used to detect a specific error condition, so this mapping
+         * should not remove any meaningful distinction.
+         */
+        if ((ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM)
 #if defined(MBEDTLS_SSL_RENEGOTIATION)
-        && ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE
+            && (ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE)
 #endif
-        ) {
-        /* Epoch should be 0 for initial handshakes */
-        if (ssl->in_ctr[0] != 0 || ssl->in_ctr[1] != 0) {
-            MBEDTLS_SSL_DEBUG_MSG(1, ("bad client hello message"));
-            return MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER;
-        }
-
-        memcpy(&ssl->cur_out_ctr[2], ssl->in_ctr + 2,
-               sizeof(ssl->cur_out_ctr) - 2);
-
-#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
-        if (mbedtls_ssl_dtls_replay_check(ssl) != 0) {
-            MBEDTLS_SSL_DEBUG_MSG(1, ("replayed record, discarding"));
-            ssl->next_record_offset = 0;
-            ssl->in_left = 0;
-            goto read_record_header;
+            ) {
+            if (ret == MBEDTLS_ERR_SSL_UNEXPECTED_RECORD) {
+                MBEDTLS_SSL_DEBUG_MSG(1, ("mapping UNEXPECTED_RECORD to UNEXPECTED_MESSAGE"));
+                ret = MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE;
+            }
         }
-
-        /* No MAC to check yet, so we can update right now */
-        mbedtls_ssl_dtls_replay_update(ssl);
-#endif
-    }
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
 
-    msg_len = MBEDTLS_GET_UINT16_BE(ssl->in_len, 0);
-
-#if defined(MBEDTLS_SSL_RENEGOTIATION)
-    if (ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE) {
-        /* Set by mbedtls_ssl_read_record() */
-        msg_len = ssl->in_hslen;
-    } else
-#endif
-    {
-        if (ssl->keep_current_message) {
-            ssl->keep_current_message = 0;
-        } else {
-            if (msg_len > MBEDTLS_SSL_IN_CONTENT_LEN) {
-                MBEDTLS_SSL_DEBUG_MSG(1, ("bad client hello message"));
-                return MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER;
-            }
-
-            if ((ret = mbedtls_ssl_fetch_input(ssl,
-                                               mbedtls_ssl_in_hdr_len(ssl) + msg_len)) != 0) {
-                MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_fetch_input", ret);
-                return ret;
-            }
-
-            /* Done reading this record, get ready for the next one */
-#if defined(MBEDTLS_SSL_PROTO_DTLS)
-            if (ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
-                ssl->next_record_offset = msg_len + mbedtls_ssl_in_hdr_len(ssl);
-            } else
-#endif
-            ssl->in_left = 0;
-        }
+        return ret;
     }
 
-    buf = ssl->in_msg;
-
-    MBEDTLS_SSL_DEBUG_BUF(4, "record contents", buf, msg_len);
-
-    ret = ssl->handshake->update_checksum(ssl, buf, msg_len);
+    /*
+     * Update the handshake checksum.
+     *
+     * Note that the checksum must be updated before parsing the extensions
+     * because ssl_parse_session_ticket_ext() may decrypt the ticket in place
+     * and therefore modify the ClientHello message. This occurs when using
+     * the Mbed TLS ssl_ticket.c implementation.
+     */
+    ret = mbedtls_ssl_update_handshake_status(ssl);
     if (0 != ret) {
-        MBEDTLS_SSL_DEBUG_RET(1, ("update_checksum"), ret);
+        MBEDTLS_SSL_DEBUG_RET(1, ("mbedtls_ssl_update_handshake_status"), ret);
         return ret;
     }
 
+    buf = ssl->in_msg;
+    msg_len = ssl->in_hslen;
+
     /*
      * Handshake layer:
      *     0  .   0   handshake type
@@ -1046,64 +984,12 @@
      *     6  .   8   DTLS only: fragment offset
      *     9  .  11   DTLS only: fragment length
      */
-    if (msg_len < mbedtls_ssl_hs_hdr_len(ssl)) {
-        MBEDTLS_SSL_DEBUG_MSG(1, ("bad client hello message"));
-        return MBEDTLS_ERR_SSL_DECODE_ERROR;
-    }
-
-    MBEDTLS_SSL_DEBUG_MSG(3, ("client hello v3, handshake type: %d", buf[0]));
-
-    if (buf[0] != MBEDTLS_SSL_HS_CLIENT_HELLO) {
+    if ((ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE) ||
+        (buf[0] != MBEDTLS_SSL_HS_CLIENT_HELLO)) {
         MBEDTLS_SSL_DEBUG_MSG(1, ("bad client hello message"));
         return MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE;
     }
 
-#if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if (ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
-        /*
-         * Copy the client's handshake message_seq on initial handshakes,
-         * check sequence number on renego.
-         */
-#if defined(MBEDTLS_SSL_RENEGOTIATION)
-        if (ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS) {
-            /* This couldn't be done in ssl_prepare_handshake_record() */
-            unsigned int cli_msg_seq = (unsigned int) MBEDTLS_GET_UINT16_BE(ssl->in_msg, 4);
-            if (cli_msg_seq != ssl->handshake->in_msg_seq) {
-                MBEDTLS_SSL_DEBUG_MSG(1, ("bad client hello message_seq: "
-                                          "%u (expected %u)", cli_msg_seq,
-                                          ssl->handshake->in_msg_seq));
-                return MBEDTLS_ERR_SSL_DECODE_ERROR;
-            }
-
-            ssl->handshake->in_msg_seq++;
-        } else
-#endif
-        {
-            unsigned int cli_msg_seq = (unsigned int) MBEDTLS_GET_UINT16_BE(ssl->in_msg, 4);
-            ssl->handshake->out_msg_seq = cli_msg_seq;
-            ssl->handshake->in_msg_seq  = cli_msg_seq + 1;
-        }
-        {
-            /*
-             * For now we don't support fragmentation, so make sure
-             * fragment_offset == 0 and fragment_length == length
-             */
-            size_t fragment_offset, fragment_length, length;
-            fragment_offset = MBEDTLS_GET_UINT24_BE(ssl->in_msg, 6);
-            fragment_length = MBEDTLS_GET_UINT24_BE(ssl->in_msg, 9);
-            length = MBEDTLS_GET_UINT24_BE(ssl->in_msg, 1);
-            MBEDTLS_SSL_DEBUG_MSG(
-                4, ("fragment_offset=%u fragment_length=%u length=%u",
-                    (unsigned) fragment_offset, (unsigned) fragment_length,
-                    (unsigned) length));
-            if (fragment_offset != 0 || length != fragment_length) {
-                MBEDTLS_SSL_DEBUG_MSG(1, ("ClientHello fragmentation not supported"));
-                return MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
-            }
-        }
-    }
-#endif /* MBEDTLS_SSL_PROTO_DTLS */
-
     buf += mbedtls_ssl_hs_hdr_len(ssl);
     msg_len -= mbedtls_ssl_hs_hdr_len(ssl);
 
@@ -1433,7 +1319,11 @@
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
             case MBEDTLS_TLS_EXT_SESSION_TICKET:
                 MBEDTLS_SSL_DEBUG_MSG(3, ("found session ticket extension"));
-
+                /*
+                 * If the Mbed TLS ssl_ticket.c implementation is used, the
+                 * ticket is decrypted in place. This modifies the ClientHello
+                 * message in the input buffer.
+                 */
                 ret = ssl_parse_session_ticket_ext(ssl, ext + 4, ext_size);
                 if (ret != 0) {
                     return ret;
@@ -2982,7 +2872,7 @@
         psa_key_type_t key_type = PSA_KEY_TYPE_NONE;
         size_t ec_bits = 0;
 
-        MBEDTLS_SSL_DEBUG_MSG(1, ("Perform PSA-based ECDH computation."));
+        MBEDTLS_SSL_DEBUG_MSG(3, ("Perform PSA-based ECDH computation."));
 
         /* Convert EC's TLS ID to PSA key type. */
         if (mbedtls_ssl_get_psa_curve_info_from_tls_id(*curr_tls_id,
diff -Nru mbedtls-3.6.5/library/ssl_tls13_client.c mbedtls-3.6.6/library/ssl_tls13_client.c
--- mbedtls-3.6.5/library/ssl_tls13_client.c	2025-10-14 19:12:36.948281800 +0300
+++ mbedtls-3.6.6/library/ssl_tls13_client.c	2026-03-27 19:00:27.592316400 +0200
@@ -2270,6 +2270,9 @@
 #if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED)
     if (mbedtls_ssl_tls13_key_exchange_mode_with_psk(ssl)) {
         mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_SERVER_FINISHED);
+
+        /* Since we're not using a certificate, set verify_result to success */
+        ssl->session_negotiate->verify_result = 0;
     } else {
         mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_CERTIFICATE_REQUEST);
     }
diff -Nru mbedtls-3.6.5/library/ssl_tls13_server.c mbedtls-3.6.6/library/ssl_tls13_server.c
--- mbedtls-3.6.5/library/ssl_tls13_server.c	2025-10-14 19:12:36.950044600 +0300
+++ mbedtls-3.6.6/library/ssl_tls13_server.c	2026-03-27 19:00:27.594703700 +0200
@@ -1776,6 +1776,11 @@
         return MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER;
     }
 
+    if (handshake->key_exchange_mode !=
+        MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK) {
+        hrr_required = (no_usable_share_for_key_agreement != 0);
+    }
+
 #if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_PSK_ENABLED)
     if (handshake->key_exchange_mode &
         MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ALL) {
@@ -1786,17 +1791,12 @@
                                   ((unsigned) psk.ciphersuite_info->id),
                                   psk.ciphersuite_info->name));
 
-        if (psk.type == MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION) {
+        if (psk.type == MBEDTLS_SSL_TLS1_3_PSK_RESUMPTION && (!hrr_required)) {
             handshake->resume = 1;
         }
     }
 #endif
 
-    if (handshake->key_exchange_mode !=
-        MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK) {
-        hrr_required = (no_usable_share_for_key_agreement != 0);
-    }
-
     mbedtls_ssl_optimize_checksum(ssl, handshake->ciphersuite_info);
 
     return hrr_required ? SSL_CLIENT_HELLO_HRR_REQUIRED : SSL_CLIENT_HELLO_OK;
@@ -1969,6 +1969,9 @@
 
     /*
      * Version 1.2 of the protocol has to be used for the handshake.
+     * If we have sent an HRR, then the second ClientHello is inconsistent
+     * with the first one and we abort the handshake with an `illegal_parameter`
+     * fatal alert.
      * If TLS 1.2 is not supported, abort the handshake. Otherwise, set the
      * ssl->keep_current_message flag for the ClientHello to be kept and parsed
      * as a TLS 1.2 ClientHello. We also change ssl->tls_version to
@@ -1976,7 +1979,12 @@
      * will dispatch to the TLS 1.2 state machine.
      */
     if (SSL_CLIENT_HELLO_TLS1_2 == parse_client_hello_ret) {
-        /* Check if server supports TLS 1.2 */
+        if (ssl->handshake->hello_retry_request_flag) {
+            MBEDTLS_SSL_DEBUG_MSG(1, ("Non compliant 2nd ClientHello, TLS 1.2 version"));
+            MBEDTLS_SSL_PEND_FATAL_ALERT(MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER,
+                                         MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER);
+            return MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER;
+        }
         if (!mbedtls_ssl_conf_is_tls12_enabled(ssl->conf)) {
             MBEDTLS_SSL_DEBUG_MSG(
                 1, ("TLS 1.2 not supported."));
@@ -2637,6 +2645,9 @@
 #if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED)
     if (mbedtls_ssl_tls13_key_exchange_mode_with_psk(ssl)) {
         mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_SERVER_FINISHED);
+
+        /* Since we're not using a certificate, set verify_result to success */
+        ssl->session_negotiate->verify_result = 0;
     } else {
         mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_CERTIFICATE_REQUEST);
     }
diff -Nru mbedtls-3.6.5/library/ssl_tls.c mbedtls-3.6.6/library/ssl_tls.c
--- mbedtls-3.6.5/library/ssl_tls.c	2025-10-14 19:12:36.945095800 +0300
+++ mbedtls-3.6.6/library/ssl_tls.c	2026-03-27 19:00:27.590506800 +0200
@@ -685,7 +685,7 @@
         mbedtls_ssl_get_extension_id(extension_type)];
 }
 
-static const char *ssl_tls13_get_hs_msg_name(int hs_msg_type)
+const char *mbedtls_ssl_get_hs_msg_name(int hs_msg_type)
 {
     switch (hs_msg_type) {
         case MBEDTLS_SSL_HS_CLIENT_HELLO:
@@ -700,8 +700,16 @@
             return "EncryptedExtensions";
         case MBEDTLS_SSL_HS_CERTIFICATE:
             return "Certificate";
+        case MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE:
+            return "ServerKeyExchange";
         case MBEDTLS_SSL_HS_CERTIFICATE_REQUEST:
             return "CertificateRequest";
+        case MBEDTLS_SSL_HS_CERTIFICATE_VERIFY:
+            return "CertificateVerify";
+        case MBEDTLS_SSL_HS_CLIENT_KEY_EXCHANGE:
+            return "ClientKeyExchange";
+        case MBEDTLS_SSL_HS_FINISHED:
+            return "Finished";
     }
     return "Unknown";
 }
@@ -716,7 +724,7 @@
         mbedtls_debug_print_msg(
             ssl, level, file, line,
             "%s: %s(%u) extension %s %s.",
-            ssl_tls13_get_hs_msg_name(hs_msg_type),
+            mbedtls_ssl_get_hs_msg_name(hs_msg_type),
             mbedtls_ssl_get_extension_name(extension_type),
             extension_type,
             extra_msg0, extra_msg1);
@@ -727,7 +735,7 @@
     if (extra_msg) {
         mbedtls_debug_print_msg(
             ssl, level, file, line,
-            "%s: %s(%u) extension %s.", ssl_tls13_get_hs_msg_name(hs_msg_type),
+            "%s: %s(%u) extension %s.", mbedtls_ssl_get_hs_msg_name(hs_msg_type),
             mbedtls_ssl_get_extension_name(extension_type), extension_type,
             extra_msg);
         return;
@@ -735,7 +743,7 @@
 
     mbedtls_debug_print_msg(
         ssl, level, file, line,
-        "%s: %s(%u) extension.", ssl_tls13_get_hs_msg_name(hs_msg_type),
+        "%s: %s(%u) extension.", mbedtls_ssl_get_hs_msg_name(hs_msg_type),
         mbedtls_ssl_get_extension_name(extension_type), extension_type);
 }
 
@@ -1048,6 +1056,8 @@
 void mbedtls_ssl_session_init(mbedtls_ssl_session *session)
 {
     memset(session, 0, sizeof(mbedtls_ssl_session));
+    /* Set verify_result to -1u to indicate 'result not available'. */
+    session->verify_result = 0xFFFFFFFF;
 }
 
 MBEDTLS_CHECK_RETURN_CRITICAL
@@ -3278,13 +3288,6 @@
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
 size_t mbedtls_ssl_get_current_mtu(const mbedtls_ssl_context *ssl)
 {
-    /* Return unlimited mtu for client hello messages to avoid fragmentation. */
-    if (ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT &&
-        (ssl->state == MBEDTLS_SSL_CLIENT_HELLO ||
-         ssl->state == MBEDTLS_SSL_SERVER_HELLO)) {
-        return 0;
-    }
-
     if (ssl->handshake == NULL || ssl->handshake->mtu == 0) {
         return ssl->mtu;
     }
@@ -5003,6 +5006,9 @@
 #endif
 
     mbedtls_platform_zeroize(session, sizeof(mbedtls_ssl_session));
+
+    /* Set verify_result to -1u to indicate 'result not available'. */
+    session->verify_result = 0xFFFFFFFF;
 }
 
 #if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
@@ -7929,6 +7935,7 @@
         ssl->handshake->ciphersuite_info;
 
     if (!mbedtls_ssl_ciphersuite_uses_srv_cert(ciphersuite_info)) {
+        ssl->session_negotiate->verify_result = 0;
         return SSL_CERTIFICATE_SKIP;
     }
 
@@ -9873,6 +9880,7 @@
                                    void *rs_ctx)
 {
     if (authmode == MBEDTLS_SSL_VERIFY_NONE) {
+        ssl->session_negotiate->verify_result = 0;
         return 0;
     }
 
@@ -10121,7 +10129,7 @@
                                                     const size_t context_len)
 {
     const psa_algorithm_t psa_hash_alg = mbedtls_md_psa_alg_from_type(hash_alg);
-    const size_t hash_len = PSA_HASH_LENGTH(hash_alg);
+    const size_t hash_len = PSA_HASH_LENGTH(psa_hash_alg);
     const unsigned char *secret = ssl->session->app_secrets.exporter_master_secret;
 
     /* The length of the label must be at most 249 bytes to fit into the HkdfLabel
diff -Nru mbedtls-3.6.5/library/threading.c mbedtls-3.6.6/library/threading.c
--- mbedtls-3.6.5/library/threading.c	2025-10-14 19:12:36.950206800 +0300
+++ mbedtls-3.6.6/library/threading.c	2026-03-27 19:00:27.594854800 +0200
@@ -21,9 +21,7 @@
 
 #if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT)
 
-#if !defined(_WIN32) && (defined(unix) || \
-    defined(__unix) || defined(__unix__) || (defined(__APPLE__) && \
-    defined(__MACH__)))
+#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE)
 #include <unistd.h>
 #endif /* !_WIN32 && (unix || __unix || __unix__ ||
         * (__APPLE__ && __MACH__)) */
diff -Nru mbedtls-3.6.5/library/timing.c mbedtls-3.6.6/library/timing.c
--- mbedtls-3.6.5/library/timing.c	2025-10-14 19:12:36.950724000 +0300
+++ mbedtls-3.6.6/library/timing.c	2026-03-27 19:00:27.595067000 +0200
@@ -13,9 +13,7 @@
 
 #if !defined(MBEDTLS_TIMING_ALT)
 
-#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \
-    !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \
-    !defined(__HAIKU__) && !defined(__midipix__)
+#if !defined(_WIN32) && !defined(MBEDTLS_PLATFORM_IS_UNIXLIKE)
 #error "This module only works on Unix and Windows, see MBEDTLS_TIMING_C in mbedtls_config.h"
 #endif
 
diff -Nru mbedtls-3.6.5/library/x509_create.c mbedtls-3.6.6/library/x509_create.c
--- mbedtls-3.6.5/library/x509_create.c	2025-10-14 19:12:36.952343700 +0300
+++ mbedtls-3.6.6/library/x509_create.c	2026-03-27 19:00:27.596668000 +0200
@@ -310,6 +310,9 @@
             } else {
                 oid.len = strlen(attr_descr->oid);
                 oid.p = mbedtls_calloc(1, oid.len);
+                if (oid.p == NULL) {
+                    return MBEDTLS_ERR_X509_ALLOC_FAILED;
+                }
                 memcpy(oid.p, attr_descr->oid, oid.len);
                 numericoid = 0;
             }
diff -Nru mbedtls-3.6.5/library/x509_crt.c mbedtls-3.6.6/library/x509_crt.c
--- mbedtls-3.6.5/library/x509_crt.c	2025-10-14 19:12:36.953579400 +0300
+++ mbedtls-3.6.6/library/x509_crt.c	2026-03-27 19:00:27.597741800 +0200
@@ -2748,22 +2748,25 @@
             if (*p == '\0') {
                 break;
             } else if (*p == '.') {
-                /* Don't accept IPv4 too early or late */
-                if ((nonzero_groups == 0 && zero_group_start == -1) ||
+                /* Don't accept IPv4 too early or late:
+                 * - The first 6 nonzero groups must be 16 bit pieces of address delimited by ':'
+                 * - This might be fully or partially represented with compressed syntax (a zero
+                 *   group "::")
+                 */
+                if ((nonzero_groups < 6 && zero_group_start == -1) ||
                     nonzero_groups >= 7) {
                     break;
                 }
 
-                /* Walk back to prior ':', then parse as IPv4-mapped */
-                int steps = 4;
+                /* Walk back to prior ':', then parse as IPv4-mapped.
+                 * At this point nonzero_groups == 6 or zero_group_start >= 0. Either way we have a
+                 * ':' before the current position and still inside the buffer. Thus it is safe to
+                 * search back for that ':' without any further checks.
+                 */
                 do {
                     p--;
-                    steps--;
-                } while (*p != ':' && steps > 0);
+                } while (*p != ':');
 
-                if (*p != ':') {
-                    break;
-                }
                 p++;
                 nonzero_groups--;
                 if (x509_inet_pton_ipv4((const char *) p,
diff -Nru mbedtls-3.6.5/Makefile mbedtls-3.6.6/Makefile
--- mbedtls-3.6.5/Makefile	2025-10-14 19:12:36.754199000 +0300
+++ mbedtls-3.6.6/Makefile	2026-03-27 19:00:27.518883200 +0200
@@ -193,9 +193,9 @@
 # 2. Run the relevant tests for the part of the code you're interested in.
 #    For the reference coverage measurement, see
 #    tests/scripts/basic-build-test.sh
-# 3. Run scripts/lcov.sh to generate an HTML report.
+# 3. Run framework/scripts/lcov.sh to generate an HTML report.
 lcov:
-	scripts/lcov.sh
+	framework/scripts/lcov.sh
 
 apidoc:
 	mkdir -p apidoc
diff -Nru mbedtls-3.6.5/programs/Makefile mbedtls-3.6.6/programs/Makefile
--- mbedtls-3.6.5/programs/Makefile	2025-10-14 19:12:36.957340700 +0300
+++ mbedtls-3.6.6/programs/Makefile	2026-03-27 19:00:27.599738000 +0200
@@ -125,7 +125,7 @@
 ssl-opt: $(patsubst %,%$(EXEXT),$(SSL_OPT_APPS))
 .PHONY: ssl-opt
 
-fuzz: ${MBEDTLS_TEST_OBJS}
+fuzz: ${MBEDLIBS} ${MBEDTLS_TEST_OBJS}
 	$(MAKE) -C fuzz
 
 ${MBEDTLS_TEST_OBJS}:
diff -Nru mbedtls-3.6.5/programs/README.md mbedtls-3.6.6/programs/README.md
--- mbedtls-3.6.5/programs/README.md	2025-10-14 19:12:36.957599400 +0300
+++ mbedtls-3.6.6/programs/README.md	2026-03-27 19:00:27.599905700 +0200
@@ -3,6 +3,8 @@
 
 This subdirectory mostly contains sample programs that illustrate specific features of the library, as well as a few test and support programs.
 
+We try to ensure that the sample programs are good examples of how to use Mbed TLS but we make no hard guarantees about their security. They should not be used in production unless they have been separately tested and thoroughly audited for security. Note that this means vulnerabilities in the sample programs are out of the scope of our usual security process and will be fixed in public.
+
 ## Symmetric cryptography (AES) examples
 
 * [`aes/crypt_and_hash.c`](aes/crypt_and_hash.c): file encryption and authentication, demonstrating the generic cipher interface and the generic hash interface.
diff -Nru mbedtls-3.6.5/programs/ssl/ssl_server2.c mbedtls-3.6.6/programs/ssl/ssl_server2.c
--- mbedtls-3.6.5/programs/ssl/ssl_server2.c	2025-10-14 19:12:36.977109200 +0300
+++ mbedtls-3.6.6/programs/ssl/ssl_server2.c	2026-03-27 19:00:27.611049400 +0200
@@ -3592,6 +3592,7 @@
      * 5. Verify the client certificate
      */
     mbedtls_printf("  . Verifying peer X.509 certificate...");
+    fflush(stdout);
 
     if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0) {
         char vrfy_buf[512];
@@ -3609,6 +3610,7 @@
         char crt_buf[512];
 
         mbedtls_printf("  . Peer certificate information    ...\n");
+        fflush(stdout);
         mbedtls_x509_crt_info(crt_buf, sizeof(crt_buf), "      ",
                               mbedtls_ssl_get_peer_cert(&ssl));
         mbedtls_printf("%s\n", crt_buf);
@@ -4061,6 +4063,7 @@
         size_t buf_len;
 
         mbedtls_printf("  . Serializing live connection...");
+        fflush(stdout);
 
         ret = mbedtls_ssl_context_save(&ssl, NULL, 0, &buf_len);
         if (ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL) {
@@ -4095,6 +4098,7 @@
             size_t b64_len;
 
             mbedtls_printf("  . Save serialized context to a file... ");
+            fflush(stdout);
 
             mbedtls_base64_encode(NULL, 0, &b64_len, context_buf, buf_len);
 
@@ -4143,6 +4147,7 @@
         if (opt.serialize == 1) {
             /* nothing to do here, done by context_save() already */
             mbedtls_printf("  . Context has been reset... ok\n");
+            fflush(stdout);
         }
 
         /*
@@ -4155,6 +4160,7 @@
          */
         if (opt.serialize == 2) {
             mbedtls_printf("  . Freeing and reinitializing context...");
+            fflush(stdout);
 
             mbedtls_ssl_free(&ssl);
 
@@ -4191,6 +4197,7 @@
         }
 
         mbedtls_printf("  . Deserializing connection...");
+        fflush(stdout);
 
         if ((ret = mbedtls_ssl_context_load(&ssl, context_buf,
                                             buf_len)) != 0) {
@@ -4220,6 +4227,7 @@
      */
 close_notify:
     mbedtls_printf("  . Closing the connection...");
+    fflush(stdout);
 
     /* No error checking, the connection might be closed already */
     do {
diff -Nru mbedtls-3.6.5/programs/test/query_config.c mbedtls-3.6.6/programs/test/query_config.c
--- mbedtls-3.6.5/programs/test/query_config.c	2025-10-14 19:12:36.981411200 +0300
+++ mbedtls-3.6.6/programs/test/query_config.c	2026-03-27 19:00:27.613521300 +0200
@@ -2668,6 +2668,14 @@
     }
 #endif /* MBEDTLS_PRINTF_MS_TIME */
 
+#if defined(MBEDTLS_PLATFORM_DEV_RANDOM)
+    if( strcmp( "MBEDTLS_PLATFORM_DEV_RANDOM", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_DEV_RANDOM );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_DEV_RANDOM */
+
 #if defined(MBEDTLS_CHECK_RETURN)
     if( strcmp( "MBEDTLS_CHECK_RETURN", config ) == 0 )
     {
@@ -4834,6 +4842,10 @@
     OUTPUT_MACRO_NAME_VALUE(MBEDTLS_PRINTF_MS_TIME);
 #endif /* MBEDTLS_PRINTF_MS_TIME */
 
+#if defined(MBEDTLS_PLATFORM_DEV_RANDOM)
+    OUTPUT_MACRO_NAME_VALUE(MBEDTLS_PLATFORM_DEV_RANDOM);
+#endif /* MBEDTLS_PLATFORM_DEV_RANDOM */
+
 #if defined(MBEDTLS_CHECK_RETURN)
     OUTPUT_MACRO_NAME_VALUE(MBEDTLS_CHECK_RETURN);
 #endif /* MBEDTLS_CHECK_RETURN */
diff -Nru mbedtls-3.6.5/scripts/abi_check.py mbedtls-3.6.6/scripts/abi_check.py
--- mbedtls-3.6.5/scripts/abi_check.py	2025-10-14 19:12:36.987432000 +0300
+++ mbedtls-3.6.6/scripts/abi_check.py	2026-03-27 12:30:26.950314500 +0200
@@ -1,699 +1,16 @@
 #!/usr/bin/env python3
-"""This script compares the interfaces of two versions of Mbed TLS, looking
-for backward incompatibilities between two different Git revisions within
-an Mbed TLS repository. It must be run from the root of a Git working tree.
-
-### How the script works ###
-
-For the source (API) and runtime (ABI) interface compatibility, this script
-is a small wrapper around the abi-compliance-checker and abi-dumper tools,
-applying them to compare the header and library files.
-
-For the storage format, this script compares the automatically generated
-storage tests and the manual read tests, and complains if there is a
-reduction in coverage. A change in test data will be signaled as a
-coverage reduction since the old test data is no longer present. A change in
-how test data is presented will be signaled as well; this would be a false
-positive.
-
-The results of the API/ABI comparison are either formatted as HTML and stored
-at a configurable location, or are given as a brief list of problems.
-Returns 0 on success, 1 on non-compliance, and 2 if there is an error
-while running the script.
-
-### How to interpret non-compliance ###
-
-This script has relatively common false positives. In many scenarios, it only
-reports a pass if there is a strict textual match between the old version and
-the new version, and it reports problems where there is a sufficient semantic
-match but not a textual match. This section lists some common false positives.
-This is not an exhaustive list: in the end what matters is whether we are
-breaking a backward compatibility goal.
-
-**API**: the goal is that if an application works with the old version of the
-library, it can be recompiled against the new version and will still work.
-This is normally validated by comparing the declarations in `include/*/*.h`.
-A failure is a declaration that has disappeared or that now has a different
-type.
-
-  * It's ok to change or remove macros and functions that are documented as
-    for internal use only or as experimental.
-  * It's ok to rename function or macro parameters as long as the semantics
-    has not changed.
-  * It's ok to change or remove structure fields that are documented as
-    private.
-  * It's ok to add fields to a structure that already had private fields
-    or was documented as extensible.
-
-**ABI**: the goal is that if an application was built against the old version
-of the library, the same binary will work when linked against the new version.
-This is normally validated by comparing the symbols exported by `libmbed*.so`.
-A failure is a symbol that is no longer exported by the same library or that
-now has a different type.
-
-  * All ABI changes are acceptable if the library version is bumped
-    (see `scripts/bump_version.sh`).
-  * ABI changes that concern functions which are declared only inside the
-    library directory, and not in `include/*/*.h`, are acceptable only if
-    the function was only ever used inside the same library (libmbedcrypto,
-    libmbedx509, libmbedtls). As a counter example, if the old version
-    of libmbedtls calls mbedtls_foo() from libmbedcrypto, and the new version
-    of libmbedcrypto no longer has a compatible mbedtls_foo(), this does
-    require a version bump for libmbedcrypto.
-
-**Storage format**: the goal is to check that persistent keys stored by the
-old version can be read by the new version. This is normally validated by
-comparing the `*read*` test cases in `test_suite*storage_format*.data`.
-A failure is a storage read test case that is no longer present with the same
-function name and parameter list.
-
-  * It's ok if the same test data is present, but its presentation has changed,
-    for example if a test function is renamed or has different parameters.
-  * It's ok if redundant tests are removed.
-
-**Generated test coverage**: the goal is to check that automatically
-generated tests have as much coverage as before. This is normally validated
-by comparing the test cases that are automatically generated by a script.
-A failure is a generated test case that is no longer present with the same
-function name and parameter list.
-
-  * It's ok if the same test data is present, but its presentation has changed,
-    for example if a test function is renamed or has different parameters.
-  * It's ok if redundant tests are removed.
+"""Bridge script
+See framework/scripts/mbedtls_framework/interface_checks.py for detailed documentation.
 
+This is a convenient place to encode any branch-specific information we might want to add
+in the future.
 """
 
 # Copyright The Mbed TLS Contributors
 # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
 
-import glob
-import os
-import re
-import sys
-import traceback
-import shutil
-import subprocess
-import argparse
-import logging
-import tempfile
-import fnmatch
-from types import SimpleNamespace
-
-import xml.etree.ElementTree as ET
-
 import framework_scripts_path # pylint: disable=unused-import
-from mbedtls_framework import build_tree
-
-
-class AbiChecker:
-    """API and ABI checker."""
-
-    def __init__(self, old_version, new_version, configuration):
-        """Instantiate the API/ABI checker.
-
-        old_version: RepoVersion containing details to compare against
-        new_version: RepoVersion containing details to check
-        configuration.report_dir: directory for output files
-        configuration.keep_all_reports: if false, delete old reports
-        configuration.brief: if true, output shorter report to stdout
-        configuration.check_abi: if true, compare ABIs
-        configuration.check_api: if true, compare APIs
-        configuration.check_storage: if true, compare storage format tests
-        configuration.skip_file: path to file containing symbols and types to skip
-        """
-        self.repo_path = "."
-        self.log = None
-        self.verbose = configuration.verbose
-        self._setup_logger()
-        self.report_dir = os.path.abspath(configuration.report_dir)
-        self.keep_all_reports = configuration.keep_all_reports
-        self.can_remove_report_dir = not (os.path.exists(self.report_dir) or
-                                          self.keep_all_reports)
-        self.old_version = old_version
-        self.new_version = new_version
-        self.skip_file = configuration.skip_file
-        self.check_abi = configuration.check_abi
-        self.check_api = configuration.check_api
-        if self.check_abi != self.check_api:
-            raise Exception('Checking API without ABI or vice versa is not supported')
-        self.check_storage_tests = configuration.check_storage
-        self.brief = configuration.brief
-        self.git_command = "git"
-        self.make_command = "make"
-
-    def _setup_logger(self):
-        self.log = logging.getLogger()
-        if self.verbose:
-            self.log.setLevel(logging.DEBUG)
-        else:
-            self.log.setLevel(logging.INFO)
-        self.log.addHandler(logging.StreamHandler())
-
-    @staticmethod
-    def check_abi_tools_are_installed():
-        for command in ["abi-dumper", "abi-compliance-checker"]:
-            if not shutil.which(command):
-                raise Exception("{} not installed, aborting".format(command))
-
-    def _get_clean_worktree_for_git_revision(self, version):
-        """Make a separate worktree with version.revision checked out.
-        Do not modify the current worktree."""
-        git_worktree_path = tempfile.mkdtemp()
-        if version.repository:
-            self.log.debug(
-                "Checking out git worktree for revision {} from {}".format(
-                    version.revision, version.repository
-                )
-            )
-            fetch_output = subprocess.check_output(
-                [self.git_command, "fetch",
-                 version.repository, version.revision],
-                cwd=self.repo_path,
-                stderr=subprocess.STDOUT
-            )
-            self.log.debug(fetch_output.decode("utf-8"))
-            worktree_rev = "FETCH_HEAD"
-        else:
-            self.log.debug("Checking out git worktree for revision {}".format(
-                version.revision
-            ))
-            worktree_rev = version.revision
-        worktree_output = subprocess.check_output(
-            [self.git_command, "worktree", "add", "--detach",
-             git_worktree_path, worktree_rev],
-            cwd=self.repo_path,
-            stderr=subprocess.STDOUT
-        )
-        self.log.debug(worktree_output.decode("utf-8"))
-        version.commit = subprocess.check_output(
-            [self.git_command, "rev-parse", "HEAD"],
-            cwd=git_worktree_path,
-            stderr=subprocess.STDOUT
-        ).decode("ascii").rstrip()
-        self.log.debug("Commit is {}".format(version.commit))
-        return git_worktree_path
-
-    def _update_git_submodules(self, git_worktree_path, version):
-        """If the crypto submodule is present, initialize it.
-        if version.crypto_revision exists, update it to that revision,
-        otherwise update it to the default revision"""
-        submodule_output = subprocess.check_output(
-            [self.git_command, "submodule", "foreach", "--recursive",
-             f'git worktree add --detach "{git_worktree_path}/$displaypath" HEAD'],
-            cwd=self.repo_path,
-            stderr=subprocess.STDOUT
-        )
-        self.log.debug(submodule_output.decode("utf-8"))
-
-        try:
-            # Try to update the submodules using local commits
-            # (Git will sometimes insist on fetching the remote without --no-fetch
-            # if the submodules are shallow clones)
-            update_output = subprocess.check_output(
-                [self.git_command, "submodule", "update", "--init", '--recursive', '--no-fetch'],
-                cwd=git_worktree_path,
-                stderr=subprocess.STDOUT
-            )
-        except subprocess.CalledProcessError as err:
-            self.log.debug(err.stdout.decode("utf-8"))
-
-            # Checkout with --no-fetch failed, falling back to fetching from origin
-            update_output = subprocess.check_output(
-                [self.git_command, "submodule", "update", "--init", '--recursive'],
-                cwd=git_worktree_path,
-                stderr=subprocess.STDOUT
-            )
-        self.log.debug(update_output.decode("utf-8"))
-        if not (os.path.exists(os.path.join(git_worktree_path, "crypto"))
-                and version.crypto_revision):
-            return
-
-        if version.crypto_repository:
-            fetch_output = subprocess.check_output(
-                [self.git_command, "fetch", version.crypto_repository,
-                 version.crypto_revision],
-                cwd=os.path.join(git_worktree_path, "crypto"),
-                stderr=subprocess.STDOUT
-            )
-            self.log.debug(fetch_output.decode("utf-8"))
-            crypto_rev = "FETCH_HEAD"
-        else:
-            crypto_rev = version.crypto_revision
-
-        checkout_output = subprocess.check_output(
-            [self.git_command, "checkout", crypto_rev],
-            cwd=os.path.join(git_worktree_path, "crypto"),
-            stderr=subprocess.STDOUT
-        )
-        self.log.debug(checkout_output.decode("utf-8"))
-
-    def _build_shared_libraries(self, git_worktree_path, version):
-        """Build the shared libraries in the specified worktree."""
-        my_environment = os.environ.copy()
-        my_environment["CFLAGS"] = "-g -Og"
-        my_environment["SHARED"] = "1"
-        if os.path.exists(os.path.join(git_worktree_path, "crypto")):
-            my_environment["USE_CRYPTO_SUBMODULE"] = "1"
-        make_output = subprocess.check_output(
-            [self.make_command, "lib"],
-            env=my_environment,
-            cwd=git_worktree_path,
-            stderr=subprocess.STDOUT
-        )
-        self.log.debug(make_output.decode("utf-8"))
-        for root, _dirs, files in os.walk(git_worktree_path):
-            for file in fnmatch.filter(files, "*.so"):
-                version.modules[os.path.splitext(file)[0]] = (
-                    os.path.join(root, file)
-                )
-
-    @staticmethod
-    def _pretty_revision(version):
-        if version.revision == version.commit:
-            return version.revision
-        else:
-            return "{} ({})".format(version.revision, version.commit)
-
-    def _get_abi_dumps_from_shared_libraries(self, version):
-        """Generate the ABI dumps for the specified git revision.
-        The shared libraries must have been built and the module paths
-        present in version.modules."""
-        for mbed_module, module_path in version.modules.items():
-            output_path = os.path.join(
-                self.report_dir, "{}-{}-{}.dump".format(
-                    mbed_module, version.revision, version.version
-                )
-            )
-            abi_dump_command = [
-                "abi-dumper",
-                module_path,
-                "-o", output_path,
-                "-lver", self._pretty_revision(version),
-            ]
-            abi_dump_output = subprocess.check_output(
-                abi_dump_command,
-                stderr=subprocess.STDOUT
-            )
-            self.log.debug(abi_dump_output.decode("utf-8"))
-            version.abi_dumps[mbed_module] = output_path
-
-    @staticmethod
-    def _normalize_storage_test_case_data(line):
-        """Eliminate cosmetic or irrelevant details in storage format test cases."""
-        line = re.sub(r'\s+', r'', line)
-        return line
-
-    def _read_storage_tests(self,
-                            directory,
-                            filename,
-                            is_generated,
-                            storage_tests):
-        """Record storage tests from the given file.
-
-        Populate the storage_tests dictionary with test cases read from
-        filename under directory.
-        """
-        at_paragraph_start = True
-        description = None
-        full_path = os.path.join(directory, filename)
-        with open(full_path) as fd:
-            for line_number, line in enumerate(fd, 1):
-                line = line.strip()
-                if not line:
-                    at_paragraph_start = True
-                    continue
-                if line.startswith('#'):
-                    continue
-                if at_paragraph_start:
-                    description = line.strip()
-                    at_paragraph_start = False
-                    continue
-                if line.startswith('depends_on:'):
-                    continue
-                # We've reached a test case data line
-                test_case_data = self._normalize_storage_test_case_data(line)
-                if not is_generated:
-                    # In manual test data, only look at read tests.
-                    function_name = test_case_data.split(':', 1)[0]
-                    if 'read' not in function_name.split('_'):
-                        continue
-                metadata = SimpleNamespace(
-                    filename=filename,
-                    line_number=line_number,
-                    description=description
-                )
-                storage_tests[test_case_data] = metadata
-
-    @staticmethod
-    def _list_generated_test_data_files(git_worktree_path):
-        """List the generated test data files."""
-        generate_psa_tests = 'framework/scripts/generate_psa_tests.py'
-        if not os.path.isfile(git_worktree_path + '/' + generate_psa_tests):
-            # The checked-out revision is from before generate_psa_tests.py
-            # was moved to the framework submodule. Use the old location.
-            generate_psa_tests = 'tests/scripts/generate_psa_tests.py'
-
-        output = subprocess.check_output(
-            [generate_psa_tests, '--list'],
-            cwd=git_worktree_path,
-        ).decode('ascii')
-        return [line for line in output.split('\n') if line]
-
-    def _get_storage_format_tests(self, version, git_worktree_path):
-        """Record the storage format tests for the specified git version.
-
-        The storage format tests are the test suite data files whose name
-        contains "storage_format".
-
-        The version must be checked out at git_worktree_path.
-
-        This function creates or updates the generated data files.
-        """
-        # Existing test data files. This may be missing some automatically
-        # generated files if they haven't been generated yet.
-        storage_data_files = set(glob.glob(
-            'tests/suites/test_suite_*storage_format*.data'
-        ))
-        # Discover and (re)generate automatically generated data files.
-        to_be_generated = set()
-        for filename in self._list_generated_test_data_files(git_worktree_path):
-            if 'storage_format' in filename:
-                storage_data_files.add(filename)
-                to_be_generated.add(filename)
-
-        generate_psa_tests = 'framework/scripts/generate_psa_tests.py'
-        if not os.path.isfile(git_worktree_path + '/' + generate_psa_tests):
-            # The checked-out revision is from before generate_psa_tests.py
-            # was moved to the framework submodule. Use the old location.
-            generate_psa_tests = 'tests/scripts/generate_psa_tests.py'
-        subprocess.check_call(
-            [generate_psa_tests] + sorted(to_be_generated),
-            cwd=git_worktree_path,
-        )
-        for test_file in sorted(storage_data_files):
-            self._read_storage_tests(git_worktree_path,
-                                     test_file,
-                                     test_file in to_be_generated,
-                                     version.storage_tests)
-
-    def _cleanup_worktree(self, git_worktree_path):
-        """Remove the specified git worktree."""
-        shutil.rmtree(git_worktree_path)
-        submodule_output = subprocess.check_output(
-            [self.git_command, "submodule", "foreach", "--recursive",
-             f'git worktree remove "{git_worktree_path}/$displaypath"'],
-            cwd=self.repo_path,
-            stderr=subprocess.STDOUT
-        )
-        self.log.debug(submodule_output.decode("utf-8"))
-        worktree_output = subprocess.check_output(
-            [self.git_command, "worktree", "remove", git_worktree_path],
-            cwd=self.repo_path,
-            stderr=subprocess.STDOUT
-        )
-        self.log.debug(worktree_output.decode("utf-8"))
-
-    def _get_abi_dump_for_ref(self, version):
-        """Generate the interface information for the specified git revision."""
-        git_worktree_path = self._get_clean_worktree_for_git_revision(version)
-        self._update_git_submodules(git_worktree_path, version)
-        if self.check_abi:
-            self._build_shared_libraries(git_worktree_path, version)
-            self._get_abi_dumps_from_shared_libraries(version)
-        if self.check_storage_tests:
-            self._get_storage_format_tests(version, git_worktree_path)
-        self._cleanup_worktree(git_worktree_path)
-
-    def _remove_children_with_tag(self, parent, tag):
-        children = parent.getchildren()
-        for child in children:
-            if child.tag == tag:
-                parent.remove(child)
-            else:
-                self._remove_children_with_tag(child, tag)
-
-    def _remove_extra_detail_from_report(self, report_root):
-        for tag in ['test_info', 'test_results', 'problem_summary',
-                    'added_symbols', 'affected']:
-            self._remove_children_with_tag(report_root, tag)
-
-        for report in report_root:
-            for problems in report.getchildren()[:]:
-                if not problems.getchildren():
-                    report.remove(problems)
-
-    def _abi_compliance_command(self, mbed_module, output_path):
-        """Build the command to run to analyze the library mbed_module.
-        The report will be placed in output_path."""
-        abi_compliance_command = [
-            "abi-compliance-checker",
-            "-l", mbed_module,
-            "-old", self.old_version.abi_dumps[mbed_module],
-            "-new", self.new_version.abi_dumps[mbed_module],
-            "-strict",
-            "-report-path", output_path,
-        ]
-        if self.skip_file:
-            abi_compliance_command += ["-skip-symbols", self.skip_file,
-                                       "-skip-types", self.skip_file]
-        if self.brief:
-            abi_compliance_command += ["-report-format", "xml",
-                                       "-stdout"]
-        return abi_compliance_command
-
-    def _is_library_compatible(self, mbed_module, compatibility_report):
-        """Test if the library mbed_module has remained compatible.
-        Append a message regarding compatibility to compatibility_report."""
-        output_path = os.path.join(
-            self.report_dir, "{}-{}-{}.html".format(
-                mbed_module, self.old_version.revision,
-                self.new_version.revision
-            )
-        )
-        try:
-            subprocess.check_output(
-                self._abi_compliance_command(mbed_module, output_path),
-                stderr=subprocess.STDOUT
-            )
-        except subprocess.CalledProcessError as err:
-            if err.returncode != 1:
-                raise err
-            if self.brief:
-                self.log.info(
-                    "Compatibility issues found for {}".format(mbed_module)
-                )
-                report_root = ET.fromstring(err.output.decode("utf-8"))
-                self._remove_extra_detail_from_report(report_root)
-                self.log.info(ET.tostring(report_root).decode("utf-8"))
-            else:
-                self.can_remove_report_dir = False
-                compatibility_report.append(
-                    "Compatibility issues found for {}, "
-                    "for details see {}".format(mbed_module, output_path)
-                )
-            return False
-        compatibility_report.append(
-            "No compatibility issues for {}".format(mbed_module)
-        )
-        if not (self.keep_all_reports or self.brief):
-            os.remove(output_path)
-        return True
-
-    @staticmethod
-    def _is_storage_format_compatible(old_tests, new_tests,
-                                      compatibility_report):
-        """Check whether all tests present in old_tests are also in new_tests.
-
-        Append a message regarding compatibility to compatibility_report.
-        """
-        missing = frozenset(old_tests.keys()).difference(new_tests.keys())
-        for test_data in sorted(missing):
-            metadata = old_tests[test_data]
-            compatibility_report.append(
-                'Test case from {} line {} "{}" has disappeared: {}'.format(
-                    metadata.filename, metadata.line_number,
-                    metadata.description, test_data
-                )
-            )
-        compatibility_report.append(
-            'FAIL: {}/{} storage format test cases have changed or disappeared.'.format(
-                len(missing), len(old_tests)
-            ) if missing else
-            'PASS: All {} storage format test cases are preserved.'.format(
-                len(old_tests)
-            )
-        )
-        compatibility_report.append(
-            'Info: number of storage format tests cases: {} -> {}.'.format(
-                len(old_tests), len(new_tests)
-            )
-        )
-        return not missing
-
-    def get_abi_compatibility_report(self):
-        """Generate a report of the differences between the reference ABI
-        and the new ABI. ABI dumps from self.old_version and self.new_version
-        must be available."""
-        compatibility_report = ["Checking evolution from {} to {}".format(
-            self._pretty_revision(self.old_version),
-            self._pretty_revision(self.new_version)
-        )]
-        compliance_return_code = 0
-
-        if self.check_abi:
-            shared_modules = list(set(self.old_version.modules.keys()) &
-                                  set(self.new_version.modules.keys()))
-            for mbed_module in shared_modules:
-                if not self._is_library_compatible(mbed_module,
-                                                   compatibility_report):
-                    compliance_return_code = 1
-
-        if self.check_storage_tests:
-            if not self._is_storage_format_compatible(
-                    self.old_version.storage_tests,
-                    self.new_version.storage_tests,
-                    compatibility_report):
-                compliance_return_code = 1
-
-        for version in [self.old_version, self.new_version]:
-            for mbed_module, mbed_module_dump in version.abi_dumps.items():
-                os.remove(mbed_module_dump)
-        if self.can_remove_report_dir:
-            os.rmdir(self.report_dir)
-        self.log.info("\n".join(compatibility_report))
-        return compliance_return_code
-
-    def check_for_abi_changes(self):
-        """Generate a report of ABI differences
-        between self.old_rev and self.new_rev."""
-        build_tree.check_repo_path()
-        if self.check_api or self.check_abi:
-            self.check_abi_tools_are_installed()
-        self._get_abi_dump_for_ref(self.old_version)
-        self._get_abi_dump_for_ref(self.new_version)
-        return self.get_abi_compatibility_report()
-
-
-def run_main():
-    try:
-        parser = argparse.ArgumentParser(
-            description=__doc__
-        )
-        parser.add_argument(
-            "-v", "--verbose", action="store_true",
-            help="set verbosity level",
-        )
-        parser.add_argument(
-            "-r", "--report-dir", type=str, default="reports",
-            help="directory where reports are stored, default is reports",
-        )
-        parser.add_argument(
-            "-k", "--keep-all-reports", action="store_true",
-            help="keep all reports, even if there are no compatibility issues",
-        )
-        parser.add_argument(
-            "-o", "--old-rev", type=str, help="revision for old version.",
-            required=True,
-        )
-        parser.add_argument(
-            "-or", "--old-repo", type=str, help="repository for old version."
-        )
-        parser.add_argument(
-            "-oc", "--old-crypto-rev", type=str,
-            help="revision for old crypto submodule."
-        )
-        parser.add_argument(
-            "-ocr", "--old-crypto-repo", type=str,
-            help="repository for old crypto submodule."
-        )
-        parser.add_argument(
-            "-n", "--new-rev", type=str, help="revision for new version",
-            required=True,
-        )
-        parser.add_argument(
-            "-nr", "--new-repo", type=str, help="repository for new version."
-        )
-        parser.add_argument(
-            "-nc", "--new-crypto-rev", type=str,
-            help="revision for new crypto version"
-        )
-        parser.add_argument(
-            "-ncr", "--new-crypto-repo", type=str,
-            help="repository for new crypto submodule."
-        )
-        parser.add_argument(
-            "-s", "--skip-file", type=str,
-            help=("path to file containing symbols and types to skip "
-                  "(typically \"-s identifiers\" after running "
-                  "\"tests/scripts/list-identifiers.sh --internal\")")
-        )
-        parser.add_argument(
-            "--check-abi",
-            action='store_true', default=True,
-            help="Perform ABI comparison (default: yes)"
-        )
-        parser.add_argument("--no-check-abi", action='store_false', dest='check_abi')
-        parser.add_argument(
-            "--check-api",
-            action='store_true', default=True,
-            help="Perform API comparison (default: yes)"
-        )
-        parser.add_argument("--no-check-api", action='store_false', dest='check_api')
-        parser.add_argument(
-            "--check-storage",
-            action='store_true', default=True,
-            help="Perform storage tests comparison (default: yes)"
-        )
-        parser.add_argument("--no-check-storage", action='store_false', dest='check_storage')
-        parser.add_argument(
-            "-b", "--brief", action="store_true",
-            help="output only the list of issues to stdout, instead of a full report",
-        )
-        abi_args = parser.parse_args()
-        if os.path.isfile(abi_args.report_dir):
-            print("Error: {} is not a directory".format(abi_args.report_dir))
-            parser.exit()
-        old_version = SimpleNamespace(
-            version="old",
-            repository=abi_args.old_repo,
-            revision=abi_args.old_rev,
-            commit=None,
-            crypto_repository=abi_args.old_crypto_repo,
-            crypto_revision=abi_args.old_crypto_rev,
-            abi_dumps={},
-            storage_tests={},
-            modules={}
-        )
-        new_version = SimpleNamespace(
-            version="new",
-            repository=abi_args.new_repo,
-            revision=abi_args.new_rev,
-            commit=None,
-            crypto_repository=abi_args.new_crypto_repo,
-            crypto_revision=abi_args.new_crypto_rev,
-            abi_dumps={},
-            storage_tests={},
-            modules={}
-        )
-        configuration = SimpleNamespace(
-            verbose=abi_args.verbose,
-            report_dir=abi_args.report_dir,
-            keep_all_reports=abi_args.keep_all_reports,
-            brief=abi_args.brief,
-            check_abi=abi_args.check_abi,
-            check_api=abi_args.check_api,
-            check_storage=abi_args.check_storage,
-            skip_file=abi_args.skip_file
-        )
-        abi_check = AbiChecker(old_version, new_version, configuration)
-        return_code = abi_check.check_for_abi_changes()
-        sys.exit(return_code)
-    except Exception: # pylint: disable=broad-except
-        # Print the backtrace and exit explicitly so as to exit with
-        # status 2, not 1.
-        traceback.print_exc()
-        sys.exit(2)
-
+from mbedtls_framework import interface_checks
 
 if __name__ == "__main__":
-    run_main()
+    interface_checks.run_main()
diff -Nru mbedtls-3.6.5/scripts/bump_version.sh mbedtls-3.6.6/scripts/bump_version.sh
--- mbedtls-3.6.5/scripts/bump_version.sh	2025-10-14 19:12:36.987955800 +0300
+++ mbedtls-3.6.6/scripts/bump_version.sh	2026-03-27 19:00:27.616186100 +0200
@@ -15,7 +15,6 @@
 set -e
 
 VERSION=""
-SOVERSION=""
 
 # Parse arguments
 #
@@ -52,7 +51,7 @@
       echo -e "  --so-x509 <version>\tSO version to bump libmbedx509 to."
       echo -e "  --so-tls <version>\tSO version to bump libmbedtls to."
       echo -e "  -v|--verbose\t\tVerbose."
-      exit 1
+      exit 0
       ;;
     *)
       # print error
diff -Nru mbedtls-3.6.5/scripts/common.make mbedtls-3.6.6/scripts/common.make
--- mbedtls-3.6.5/scripts/common.make	2025-10-14 19:12:36.989243700 +0300
+++ mbedtls-3.6.6/scripts/common.make	2026-03-27 19:00:27.616629800 +0200
@@ -117,7 +117,7 @@
 default: all
 
 $(MBEDLIBS):
-	$(MAKE) -C $(MBEDTLS_PATH)/library
+	$(MAKE) -C $(MBEDTLS_PATH)/library $(@F)
 
 neat: clean
 ifndef WINDOWS
diff -Nru mbedtls-3.6.5/scripts/generate_tls_handshake_tests.py mbedtls-3.6.6/scripts/generate_tls_handshake_tests.py
--- mbedtls-3.6.5/scripts/generate_tls_handshake_tests.py	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/scripts/generate_tls_handshake_tests.py	2026-03-27 12:30:26.953384200 +0200
@@ -0,0 +1,14 @@
+#!/usr/bin/env python3
+"""
+Generate miscellaneous TLS test cases relating to the handshake.
+"""
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+import framework_scripts_path # pylint: disable=unused-import
+
+from mbedtls_framework import tls_handshake_tests
+
+if __name__ == '__main__':
+    tls_handshake_tests.main()
diff -Nru mbedtls-3.6.5/scripts/lcov.sh mbedtls-3.6.6/scripts/lcov.sh
--- mbedtls-3.6.5/scripts/lcov.sh	2025-10-14 19:12:37.002198000 +0300
+++ mbedtls-3.6.6/scripts/lcov.sh	1970-01-01 02:00:00.000000000 +0200
@@ -1,87 +0,0 @@
-#!/bin/sh
-
-help () {
-    cat <<EOF
-Usage: $0 [-r]
-Collect coverage statistics of library code into an HTML report.
-
-General instructions:
-1. Build the library with CFLAGS="--coverage -O0 -g3" and link the test
-   programs with LDFLAGS="--coverage".
-   This can be an out-of-tree build.
-   For example (in-tree):
-        make CFLAGS="--coverage -O0 -g3" LDFLAGS="--coverage"
-   Or (out-of-tree):
-        mkdir build-coverage && cd build-coverage &&
-        cmake -D CMAKE_BUILD_TYPE=Coverage .. && make
-2. Run whatever tests you want.
-3. Run this script from the parent of the directory containing the library
-   object files and coverage statistics files.
-4. Browse the coverage report in Coverage/index.html.
-5. After rework, run "$0 -r", then re-test and run "$0" to get a fresh report.
-
-Options
-  -r    Reset traces. Run this before re-testing to get fresh measurements.
-EOF
-}
-
-# Copyright The Mbed TLS Contributors
-# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
-
-# This script must be invoked from the project's root.
-
-set -eu
-
-. framework/scripts/project_detection.sh
-
-# Collect stats and build a HTML report.
-lcov_library_report () {
-    rm -rf Coverage
-    mkdir Coverage Coverage/tmp
-    # Pass absolute paths as lcov output files. This works around a bug
-    # whereby lcov tries to create the output file in the root directory
-    # if it has emitted a warning. A fix was released in lcov 1.13 in 2016.
-    # Ubuntu 16.04 is affected, 18.04 and above are not.
-    # https://github.com/linux-test-project/lcov/commit/632c25a0d1f5e4d2f4fd5b28ce7c8b86d388c91f
-    COVTMP=$PWD/Coverage/tmp
-    lcov --capture --initial --directory $library_dir -o "$COVTMP/files.info"
-    lcov --rc lcov_branch_coverage=1 --capture --directory $library_dir -o "$COVTMP/tests.info"
-    lcov --rc lcov_branch_coverage=1 --add-tracefile "$COVTMP/files.info" --add-tracefile "$COVTMP/tests.info" -o "$COVTMP/all.info"
-    lcov --rc lcov_branch_coverage=1 --remove "$COVTMP/all.info" -o "$COVTMP/final.info" '*.h'
-    gendesc tests/Descriptions.txt -o "$COVTMP/descriptions"
-    genhtml --title "$title" --description-file "$COVTMP/descriptions" --keep-descriptions --legend --branch-coverage -o Coverage "$COVTMP/final.info"
-    rm -f "$COVTMP/"*.info "$COVTMP/descriptions"
-    echo "Coverage report in: Coverage/index.html"
-}
-
-# Reset the traces to 0.
-lcov_reset_traces () {
-    # Location with plain make
-    rm -f $library_dir/*.gcda
-    # Location with CMake
-    rm -f $library_dir/CMakeFiles/*.dir/*.gcda
-}
-
-if [ $# -gt 0 ] && [ "$1" = "--help" ]; then
-    help
-    exit
-fi
-
-if in_mbedtls_repo; then
-    library_dir='library'
-    title='Mbed TLS'
-else
-    library_dir='core'
-    title='TF-PSA-Crypto'
-fi
-
-main=lcov_library_report
-while getopts r OPTLET; do
-    case $OPTLET in
-        r) main=lcov_reset_traces;;
-        *) help 2>&1; exit 120;;
-    esac
-done
-shift $((OPTIND - 1))
-
-"$main" "$@"
diff -Nru mbedtls-3.6.5/scripts/make_generated_files.bat mbedtls-3.6.6/scripts/make_generated_files.bat
--- mbedtls-3.6.5/scripts/make_generated_files.bat	2025-10-14 19:12:37.003144700 +0300
+++ mbedtls-3.6.6/scripts/make_generated_files.bat	2026-03-27 19:00:27.619804600 +0200
@@ -23,9 +23,10 @@
 python framework\scripts\generate_config_tests.py || exit /b 1
 python framework\scripts\generate_ecp_tests.py || exit /b 1
 python framework\scripts\generate_psa_tests.py || exit /b 1
+python framework\scripts\generate_psa_wrappers.py || exit /b 1
 python framework\scripts\generate_test_keys.py --output tests\include\test\test_keys.h || exit /b 1
 python framework\scripts\generate_test_cert_macros.py --output tests\include\test\test_certs.h || exit /b 1
-python framework\scripts\generate_tls_handshake_tests.py || exit /b 1
+python scripts\generate_tls_handshake_tests.py || exit /b 1
 python framework\scripts\generate_tls13_compat_tests.py || exit /b 1
 
 @rem @@@@ Build @@@@
diff -Nru mbedtls-3.6.5/scripts/prepare_release.sh mbedtls-3.6.6/scripts/prepare_release.sh
--- mbedtls-3.6.5/scripts/prepare_release.sh	2025-10-14 19:02:36.196918700 +0300
+++ mbedtls-3.6.6/scripts/prepare_release.sh	2026-03-27 19:00:27.620225200 +0200
@@ -1,70 +1,39 @@
 #!/bin/bash
-
-print_usage()
-{
-    cat <<EOF
-Usage: $0 [OPTION]...
-Prepare the source tree for a release.
-
-Options:
-  -u    Prepare for development (undo the release preparation)
-EOF
-}
-
 # Copyright The Mbed TLS Contributors
 # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
 
-set -eu
-
-if [ $# -ne 0 ] && [ "$1" = "--help" ]; then
-    print_usage
-    exit
-fi
-
-unrelease= # if non-empty, we're in undo-release mode
-while getopts u OPTLET; do
-    case $OPTLET in
-        u) unrelease=1;;
-        \?)
-            echo 1>&2 "$0: unknown option: -$OPTLET"
-            echo 1>&2 "Try '$0 --help' for more information."
-            exit 3;;
-    esac
-done
-
+# prepare_release.sh — Prepare the source tree for a release.
+#
+# This script switches the repo into “release” mode:
+#   - Updates all tracked `.gitignore` files to stop
+#     ignoring the automatically-generated files.
+#   - Sets the CMake option `GEN_FILES` to OFF to explicitely disable
+#     recreating the automatically-generated files.
+#.  - The script will recursively update the tf-psa-crypto files too.
 
 
-#### .gitignore processing ####
+set -eu
 
-GITIGNORES=$(find . -name ".gitignore")
-for GITIGNORE in $GITIGNORES; do
-    if [ -n "$unrelease" ]; then
-        sed -i '/###START_COMMENTED_GENERATED_FILES###/,/###END_COMMENTED_GENERATED_FILES###/s/^#//' $GITIGNORE
-        sed -i 's/###START_COMMENTED_GENERATED_FILES###/###START_GENERATED_FILES###/' $GITIGNORE
-        sed -i 's/###END_COMMENTED_GENERATED_FILES###/###END_GENERATED_FILES###/' $GITIGNORE
+# Portable inline sed. Helper function that will automatically pre-pend
+# an empty string as the backup suffix (required by macOS sed).
+psed() {
+    # macOS sed does not offer a version
+    if sed --version >/dev/null 2>&1; then
+        sed -i "$@"
+    # macOS/BSD sed
     else
-        sed -i '/###START_GENERATED_FILES###/,/###END_GENERATED_FILES###/s/^/#/' $GITIGNORE
-        sed -i 's/###START_GENERATED_FILES###/###START_COMMENTED_GENERATED_FILES###/' $GITIGNORE
-        sed -i 's/###END_GENERATED_FILES###/###END_COMMENTED_GENERATED_FILES###/' $GITIGNORE
+        sed -i '' "$@"
     fi
-done
-
+}
 
+#### .gitignore processing ####
+for GITIGNORE in $(git ls-files --recurse-submodules -- '*.gitignore'); do
+        psed '/###START_GENERATED_FILES###/,/###END_GENERATED_FILES###/s/^/#/' "$GITIGNORE"
+        psed 's/###START_GENERATED_FILES###/###START_COMMENTED_GENERATED_FILES###/' "$GITIGNORE"
+        psed 's/###END_GENERATED_FILES###/###END_COMMENTED_GENERATED_FILES###/' "$GITIGNORE"
+done
 
 #### Build scripts ####
+psed 's/^\(GEN_FILES[ ?:]*=\)\([^#]*\)/\1/' Makefile */Makefile
+psed '/[Oo][Ff][Ff] in development/! s/^\( *option *( *GEN_FILES  *"[^"]*"  *\)\([A-Za-z0-9][A-Za-z0-9]*\)/\1OFF/' CMakeLists.txt
 
-# GEN_FILES defaults on (non-empty) in development, off (empty) in releases
-if [ -n "$unrelease" ]; then
-    r=' yes'
-else
-    r=''
-fi
-sed -i 's/^\(GEN_FILES[ ?:]*=\)\([^#]*\)/\1'"$r/" Makefile */Makefile
-
-# GEN_FILES defaults on in development, off in releases
-if [ -n "$unrelease" ]; then
-    r='ON'
-else
-    r='OFF'
-fi
-sed -i '/[Oo][Ff][Ff] in development/! s/^\( *option *( *GEN_FILES  *"[^"]*"  *\)\([A-Za-z0-9][A-Za-z0-9]*\)/\1'"$r/" CMakeLists.txt
diff -Nru mbedtls-3.6.5/SECURITY.md mbedtls-3.6.6/SECURITY.md
--- mbedtls-3.6.5/SECURITY.md	2025-10-14 19:12:36.755461500 +0300
+++ mbedtls-3.6.6/SECURITY.md	2026-03-27 19:00:27.519637600 +0200
@@ -145,21 +145,25 @@
 The Everest variant is only used when `MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED`
 configuration option is defined. This option is off by default.
 
-#### Formatting of X.509 certificates and certificate signing requests
+#### Formatting of X509 data
+
+This section discusses limitations in how X.509 objects are processed. This
+applies to certificates, certificate signing requests (CSRs) and certificate
+revocation lists (CRLs).
 
-When parsing X.509 certificates and certificate signing requests (CSRs),
 Mbed TLS does not check that they are strictly compliant with X.509 and other
-relevant standards. In the case of signed certificates, the signing party is
-assumed to have performed this validation (and the certificate is trusted to
-be correctly formatted as long as the signature is correct).
-Similarly, CSRs are implicitly trusted by Mbed TLS to be standards-compliant.
+relevant standards. In the case of signed certificates and signed CRLs, the
+signing party is assumed to have performed this validation (and the certificate
+or CRL is trusted to be correctly formatted as long as the signature is
+correct).  Similarly, CSRs are implicitly trusted by Mbed TLS to be
+standards-compliant.
 
-**Warning!** Mbed TLS must not be used to sign untrusted CSRs unless extra
-validation is performed separately to ensure that they are compliant to the
-relevant specifications. This makes Mbed TLS on its own unsuitable for use in
-a Certificate Authority (CA).
+**Warning!** Mbed TLS must not be used to sign untrusted CSRs or CRLs unless
+extra validation is performed separately to ensure that they are compliant to
+the relevant specifications. This makes Mbed TLS on its own unsuitable for use
+in a Certificate Authority (CA).
 
 However, Mbed TLS aims to protect against memory corruption and other
-undefined behavior when parsing certificates and CSRs. If a CSR or signed
+undefined behavior when parsing certificates, CSRs and CRLs. If a CSR or signed
 certificate causes undefined behavior when it is parsed by Mbed TLS, that
 is considered a security vulnerability.
diff -Nru mbedtls-3.6.5/tests/CMakeLists.txt mbedtls-3.6.6/tests/CMakeLists.txt
--- mbedtls-3.6.5/tests/CMakeLists.txt	2025-10-14 19:12:37.006312600 +0300
+++ mbedtls-3.6.6/tests/CMakeLists.txt	2026-03-27 19:00:27.620926400 +0200
@@ -132,10 +132,10 @@
             ${CMAKE_CURRENT_SOURCE_DIR}/..
         COMMAND
             "${MBEDTLS_PYTHON_EXECUTABLE}"
-            "${CMAKE_CURRENT_SOURCE_DIR}/../framework/scripts/generate_tls_handshake_tests.py"
+            "${PROJECT_SOURCE_DIR}/scripts/generate_tls_handshake_tests.py"
         DEPENDS
             ${CMAKE_CURRENT_SOURCE_DIR}/../framework/scripts/mbedtls_framework/tls_test_case.py
-            ${CMAKE_CURRENT_SOURCE_DIR}/../framework/scripts/generate_tls_handshake_tests.py
+            ${PROJECT_SOURCE_DIR}/scripts/generate_tls_handshake_tests.py
     )
     add_custom_target(handshake-generated.sh
         DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/opt-testcases/handshake-generated.sh)
diff -Nru mbedtls-3.6.5/tests/.gitignore mbedtls-3.6.6/tests/.gitignore
--- mbedtls-3.6.5/tests/.gitignore	2025-10-14 19:12:37.006066000 +0300
+++ mbedtls-3.6.6/tests/.gitignore	2026-03-27 19:00:27.620698000 +0200
@@ -20,11 +20,13 @@
 ## Generated source files
 #/opt-testcases/handshake-generated.sh
 #/opt-testcases/tls13-compat.sh
+#/src/psa_test_wrappers.c
 #/suites/*.generated.data
 #/suites/test_suite_config.mbedtls_boolean.data
 #/suites/test_suite_config.psa_boolean.data
 #/suites/test_suite_psa_crypto_storage_format.v[0-9]*.data
 #/suites/test_suite_psa_crypto_storage_format.current.data
+#/include/test/psa_test_wrappers.h
 #/include/test/test_keys.h
 #/include/test/test_certs.h
 ####END_COMMENTED_GENERATED_FILES###
diff -Nru mbedtls-3.6.5/tests/include/test/psa_test_wrappers.h mbedtls-3.6.6/tests/include/test/psa_test_wrappers.h
--- mbedtls-3.6.5/tests/include/test/psa_test_wrappers.h	2025-10-14 19:12:37.013145700 +0300
+++ mbedtls-3.6.6/tests/include/test/psa_test_wrappers.h	2026-03-27 19:00:27.624751800 +0200
@@ -681,6 +681,21 @@
 #define psa_purge_key(arg0_key) \
     mbedtls_test_wrap_psa_purge_key(arg0_key)
 
+psa_status_t mbedtls_test_wrap_psa_random_deplete(void);
+#define psa_random_deplete() \
+    mbedtls_test_wrap_psa_random_deplete()
+
+psa_status_t mbedtls_test_wrap_psa_random_reseed(
+    const uint8_t *arg0_perso,
+    size_t arg1_perso_size);
+#define psa_random_reseed(arg0_perso, arg1_perso_size) \
+    mbedtls_test_wrap_psa_random_reseed(arg0_perso, arg1_perso_size)
+
+psa_status_t mbedtls_test_wrap_psa_random_set_prediction_resistance(
+    unsigned arg0_enabled);
+#define psa_random_set_prediction_resistance(arg0_enabled) \
+    mbedtls_test_wrap_psa_random_set_prediction_resistance(arg0_enabled)
+
 psa_status_t mbedtls_test_wrap_psa_raw_key_agreement(
     psa_algorithm_t arg0_alg,
     mbedtls_svc_key_id_t arg1_private_key,
diff -Nru mbedtls-3.6.5/tests/include/test/ssl_helpers.h mbedtls-3.6.6/tests/include/test/ssl_helpers.h
--- mbedtls-3.6.5/tests/include/test/ssl_helpers.h	2025-10-14 19:12:37.013382200 +0300
+++ mbedtls-3.6.6/tests/include/test/ssl_helpers.h	2026-03-27 19:00:27.625038400 +0200
@@ -71,6 +71,39 @@
     defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)
 #define MBEDTLS_CAN_HANDLE_RSA_TEST_KEY
 #endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && \
+    defined(MBEDTLS_ECP_HAVE_SECP384R1) && \
+    defined(MBEDTLS_MD_CAN_SHA384)
+#define MBEDTLS_CAN_HANDLE_ECDSA_TEST_KEY
+#endif
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && \
+    defined(MBEDTLS_ECP_HAVE_SECP256R1) && \
+    defined(MBEDTLS_MD_CAN_SHA256)
+#define MBEDTLS_CAN_HANDLE_ECDSA_CLIENT_TEST_KEY
+#endif
+
+#if defined(MBEDTLS_ECP_HAVE_CURVE25519)  || \
+    defined(MBEDTLS_ECP_HAVE_SECP256R1)   || \
+    defined(MBEDTLS_ECP_HAVE_SECP384R1)   || \
+    defined(MBEDTLS_ECP_HAVE_CURVE448)    || \
+    defined(MBEDTLS_ECP_HAVE_SECP521R1)   || \
+    defined(MBEDTLS_ECP_HAVE_BP256R1)     || \
+    defined(MBEDTLS_ECP_HAVE_BP384R1)     || \
+    defined(MBEDTLS_ECP_HAVE_BP512R1)
+#define MBEDTLS_TEST_HAS_DEFAULT_EC_GROUP
+#endif
+
+/*
+ * To use the test keys we need PSA_WANT_ALG_SHA_256. Some test cases need an additional hash that
+ * is configured by default (see mbedtls_ssl_config_defaults()), but it doesn't matter which one.
+ */
+#if defined(MBEDTLS_MD_CAN_SHA512)   || \
+    defined(MBEDTLS_MD_CAN_SHA384)
+#define MBEDTLS_TEST_HAS_ADDITIONAL_HASH
+#endif
+
 enum {
 #define MBEDTLS_SSL_TLS1_3_LABEL(name, string)          \
     tls13_label_ ## name,
diff -Nru mbedtls-3.6.5/tests/include/test/test_certs.h mbedtls-3.6.6/tests/include/test/test_certs.h
--- mbedtls-3.6.5/tests/include/test/test_certs.h	2025-10-14 19:12:37.013609600 +0300
+++ mbedtls-3.6.6/tests/include/test/test_certs.h	2026-03-27 19:00:27.625651100 +0200
@@ -8,8 +8,8 @@
 /* THIS FILE is generated by `framework/scripts/generate_test_cert_macros.py` */
 /* *INDENT-OFF* */
 
-/* This is taken from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/test-ca2.crt. */
-/* BEGIN FILE string macro TEST_CA_CRT_EC_PEM /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/test-ca2.crt */
+/* This is taken from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/test-ca2.crt. */
+/* BEGIN FILE string macro TEST_CA_CRT_EC_PEM /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/test-ca2.crt */
 #define TEST_CA_CRT_EC_PEM                                                     \
     "-----BEGIN CERTIFICATE-----\r\n"                                          \
     "MIICBzCCAYugAwIBAgIJAMFD4n5iQ8zoMAwGCCqGSM49BAMCBQAwPjELMAkGA1UE\r\n"     \
@@ -26,8 +26,8 @@
     "-----END CERTIFICATE-----\r\n"
 /* END FILE */
 
-/* This is generated from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/test-ca2.crt.der. */
-/* BEGIN FILE binary macro TEST_CA_CRT_EC_DER /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/test-ca2.crt.der */
+/* This is generated from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/test-ca2.crt.der. */
+/* BEGIN FILE binary macro TEST_CA_CRT_EC_DER /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/test-ca2.crt.der */
 #define TEST_CA_CRT_EC_DER {                                                    \
         0x30, 0x82, 0x02, 0x07, 0x30, 0x82, 0x01, 0x8b, 0xa0, 0x03, 0x02, 0x01, \
         0x02, 0x02, 0x09, 0x00, 0xc1, 0x43, 0xe2, 0x7e, 0x62, 0x43, 0xcc, 0xe8, \
@@ -76,8 +76,8 @@
 }
 /* END FILE */
 
-/* This is taken from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/test-ca2.key.enc. */
-/* BEGIN FILE string macro TEST_CA_KEY_EC_PEM /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/test-ca2.key.enc */
+/* This is taken from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/test-ca2.key.enc. */
+/* BEGIN FILE string macro TEST_CA_KEY_EC_PEM /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/test-ca2.key.enc */
 #define TEST_CA_KEY_EC_PEM                                                     \
     "-----BEGIN EC PRIVATE KEY-----\r\n"                                       \
     "Proc-Type: 4,ENCRYPTED\r\n"                                               \
@@ -92,8 +92,8 @@
 
 #define TEST_CA_PWD_EC_PEM "PolarSSLTest"
 
-/* This is generated from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/test-ca2.key.der. */
-/* BEGIN FILE binary macro TEST_CA_KEY_EC_DER /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/test-ca2.key.der */
+/* This is generated from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/test-ca2.key.der. */
+/* BEGIN FILE binary macro TEST_CA_KEY_EC_DER /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/test-ca2.key.der */
 #define TEST_CA_KEY_EC_DER {                                                    \
         0x30, 0x81, 0xa4, 0x02, 0x01, 0x01, 0x04, 0x30, 0x83, 0xd9, 0x15, 0x0e, \
         0xa0, 0x71, 0xf0, 0x57, 0x10, 0x33, 0xa3, 0x38, 0xb8, 0x86, 0xc1, 0xa6, \
@@ -112,8 +112,8 @@
 }
 /* END FILE */
 
-/* This is taken from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/test-ca-sha256.crt. */
-/* BEGIN FILE string macro TEST_CA_CRT_RSA_SHA256_PEM /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/test-ca-sha256.crt */
+/* This is taken from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/test-ca-sha256.crt. */
+/* BEGIN FILE string macro TEST_CA_CRT_RSA_SHA256_PEM /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/test-ca-sha256.crt */
 #define TEST_CA_CRT_RSA_SHA256_PEM                                             \
     "-----BEGIN CERTIFICATE-----\r\n"                                          \
     "MIIDQTCCAimgAwIBAgIBAzANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER\r\n"     \
@@ -137,8 +137,8 @@
     "-----END CERTIFICATE-----\r\n"
 /* END FILE */
 
-/* This is generated from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/test-ca-sha256.crt.der. */
-/* BEGIN FILE binary macro TEST_CA_CRT_RSA_SHA256_DER /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/test-ca-sha256.crt.der */
+/* This is generated from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/test-ca-sha256.crt.der. */
+/* BEGIN FILE binary macro TEST_CA_CRT_RSA_SHA256_DER /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/test-ca-sha256.crt.der */
 #define TEST_CA_CRT_RSA_SHA256_DER {                                            \
         0x30, 0x82, 0x03, 0x41, 0x30, 0x82, 0x02, 0x29, 0xa0, 0x03, 0x02, 0x01, \
         0x02, 0x02, 0x01, 0x03, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, \
@@ -213,8 +213,8 @@
 }
 /* END FILE */
 
-/* This is taken from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/test-ca-sha1.crt. */
-/* BEGIN FILE string macro TEST_CA_CRT_RSA_SHA1_PEM /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/test-ca-sha1.crt */
+/* This is taken from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/test-ca-sha1.crt. */
+/* BEGIN FILE string macro TEST_CA_CRT_RSA_SHA1_PEM /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/test-ca-sha1.crt */
 #define TEST_CA_CRT_RSA_SHA1_PEM                                               \
     "-----BEGIN CERTIFICATE-----\r\n"                                          \
     "MIIDQTCCAimgAwIBAgIBAzANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n"     \
@@ -238,8 +238,8 @@
     "-----END CERTIFICATE-----\r\n"
 /* END FILE */
 
-/* This is generated from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/test-ca-sha1.crt.der. */
-/* BEGIN FILE binary macro TEST_CA_CRT_RSA_SHA1_DER /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/test-ca-sha1.crt.der */
+/* This is generated from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/test-ca-sha1.crt.der. */
+/* BEGIN FILE binary macro TEST_CA_CRT_RSA_SHA1_DER /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/test-ca-sha1.crt.der */
 #define TEST_CA_CRT_RSA_SHA1_DER {                                              \
         0x30, 0x82, 0x03, 0x41, 0x30, 0x82, 0x02, 0x29, 0xa0, 0x03, 0x02, 0x01, \
         0x02, 0x02, 0x01, 0x03, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, \
@@ -314,8 +314,8 @@
 }
 /* END FILE */
 
-/* This is taken from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/test-ca.key. */
-/* BEGIN FILE string macro TEST_CA_KEY_RSA_PEM /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/test-ca.key */
+/* This is taken from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/test-ca.key. */
+/* BEGIN FILE string macro TEST_CA_KEY_RSA_PEM /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/test-ca.key */
 #define TEST_CA_KEY_RSA_PEM                                                    \
     "-----BEGIN RSA PRIVATE KEY-----\r\n"                                      \
     "Proc-Type: 4,ENCRYPTED\r\n"                                               \
@@ -351,8 +351,8 @@
 
 #define TEST_CA_PWD_RSA_PEM "PolarSSLTest"
 
-/* This is generated from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/test-ca.key.der. */
-/* BEGIN FILE binary macro TEST_CA_KEY_RSA_DER /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/test-ca.key.der */
+/* This is generated from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/test-ca.key.der. */
+/* BEGIN FILE binary macro TEST_CA_KEY_RSA_DER /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/test-ca.key.der */
 #define TEST_CA_KEY_RSA_DER {                                                   \
         0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, \
         0xc0, 0xdf, 0x37, 0xfc, 0x17, 0xbb, 0xe0, 0x96, 0x9d, 0x3f, 0x86, 0xde, \
@@ -457,8 +457,8 @@
 }
 /* END FILE */
 
-/* This is taken from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/server5.crt. */
-/* BEGIN FILE string macro TEST_SRV_CRT_EC_PEM /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/server5.crt */
+/* This is taken from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/server5.crt. */
+/* BEGIN FILE string macro TEST_SRV_CRT_EC_PEM /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/server5.crt */
 #define TEST_SRV_CRT_EC_PEM                                                    \
     "-----BEGIN CERTIFICATE-----\r\n"                                          \
     "MIICIDCCAaWgAwIBAgIBCTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G\r\n"     \
@@ -476,8 +476,8 @@
     "-----END CERTIFICATE-----\r\n"
 /* END FILE */
 
-/* This is generated from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/server5.crt.der. */
-/* BEGIN FILE binary macro TEST_SRV_CRT_EC_DER /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/server5.crt.der */
+/* This is generated from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/server5.crt.der. */
+/* BEGIN FILE binary macro TEST_SRV_CRT_EC_DER /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/server5.crt.der */
 #define TEST_SRV_CRT_EC_DER {                                                   \
         0x30, 0x82, 0x02, 0x20, 0x30, 0x82, 0x01, 0xa5, 0xa0, 0x03, 0x02, 0x01, \
         0x02, 0x02, 0x01, 0x09, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, \
@@ -528,8 +528,8 @@
 }
 /* END FILE */
 
-/* This is taken from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/server5.key. */
-/* BEGIN FILE string macro TEST_SRV_KEY_EC_PEM /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/server5.key */
+/* This is taken from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/server5.key. */
+/* BEGIN FILE string macro TEST_SRV_KEY_EC_PEM /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/server5.key */
 #define TEST_SRV_KEY_EC_PEM                                                    \
     "-----BEGIN EC PRIVATE KEY-----\r\n"                                       \
     "MHcCAQEEIPEqEyB2AnCoPL/9U/YDHvdqXYbIogTywwyp6/UfDw6noAoGCCqGSM49\r\n"     \
@@ -538,8 +538,8 @@
     "-----END EC PRIVATE KEY-----\r\n"
 /* END FILE */
 
-/* This is generated from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/server5.key.der. */
-/* BEGIN FILE binary macro TEST_SRV_KEY_EC_DER /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/server5.key.der */
+/* This is generated from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/server5.key.der. */
+/* BEGIN FILE binary macro TEST_SRV_KEY_EC_DER /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/server5.key.der */
 #define TEST_SRV_KEY_EC_DER {                                                   \
         0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0xf1, 0x2a, 0x13, 0x20, 0x76, \
         0x02, 0x70, 0xa8, 0x3c, 0xbf, 0xfd, 0x53, 0xf6, 0x03, 0x1e, 0xf7, 0x6a, \
@@ -555,8 +555,8 @@
 }
 /* END FILE */
 
-/* This is taken from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/server2-sha256.crt. */
-/* BEGIN FILE string macro TEST_SRV_CRT_RSA_SHA256_PEM /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/server2-sha256.crt */
+/* This is taken from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/server2-sha256.crt. */
+/* BEGIN FILE string macro TEST_SRV_CRT_RSA_SHA256_PEM /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/server2-sha256.crt */
 #define TEST_SRV_CRT_RSA_SHA256_PEM                                            \
     "-----BEGIN CERTIFICATE-----\r\n"                                          \
     "MIIDNzCCAh+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER\r\n"     \
@@ -580,8 +580,8 @@
     "-----END CERTIFICATE-----\r\n"
 /* END FILE */
 
-/* This is generated from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/server2-sha256.crt.der. */
-/* BEGIN FILE binary macro TEST_SRV_CRT_RSA_SHA256_DER /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/server2-sha256.crt.der */
+/* This is generated from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/server2-sha256.crt.der. */
+/* BEGIN FILE binary macro TEST_SRV_CRT_RSA_SHA256_DER /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/server2-sha256.crt.der */
 #define TEST_SRV_CRT_RSA_SHA256_DER {                                           \
         0x30, 0x82, 0x03, 0x37, 0x30, 0x82, 0x02, 0x1f, 0xa0, 0x03, 0x02, 0x01, \
         0x02, 0x02, 0x01, 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, \
@@ -655,8 +655,8 @@
 }
 /* END FILE */
 
-/* This is taken from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/server2.crt. */
-/* BEGIN FILE string macro TEST_SRV_CRT_RSA_SHA1_PEM /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/server2.crt */
+/* This is taken from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/server2.crt. */
+/* BEGIN FILE string macro TEST_SRV_CRT_RSA_SHA1_PEM /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/server2.crt */
 #define TEST_SRV_CRT_RSA_SHA1_PEM                                              \
     "-----BEGIN CERTIFICATE-----\r\n"                                          \
     "MIIDNzCCAh+gAwIBAgIBAjANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n"     \
@@ -680,8 +680,8 @@
     "-----END CERTIFICATE-----\r\n"
 /* END FILE */
 
-/* This is generated from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/server2.crt.der. */
-/* BEGIN FILE binary macro TEST_SRV_CRT_RSA_SHA1_DER /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/server2.crt.der */
+/* This is generated from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/server2.crt.der. */
+/* BEGIN FILE binary macro TEST_SRV_CRT_RSA_SHA1_DER /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/server2.crt.der */
 #define TEST_SRV_CRT_RSA_SHA1_DER {                                             \
         0x30, 0x82, 0x03, 0x37, 0x30, 0x82, 0x02, 0x1f, 0xa0, 0x03, 0x02, 0x01, \
         0x02, 0x02, 0x01, 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, \
@@ -755,8 +755,8 @@
 }
 /* END FILE */
 
-/* This is taken from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/server2.key. */
-/* BEGIN FILE string macro TEST_SRV_KEY_RSA_PEM /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/server2.key */
+/* This is taken from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/server2.key. */
+/* BEGIN FILE string macro TEST_SRV_KEY_RSA_PEM /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/server2.key */
 #define TEST_SRV_KEY_RSA_PEM                                                   \
     "-----BEGIN RSA PRIVATE KEY-----\r\n"                                      \
     "MIIEpAIBAAKCAQEAwU2j3efNHdEE10lyuJmsDnjkOjxKzzoTFtBa5M2jAIin7h5r\r\n"     \
@@ -787,8 +787,8 @@
     "-----END RSA PRIVATE KEY-----\r\n"
 /* END FILE */
 
-/* This is generated from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/server2.key.der. */
-/* BEGIN FILE binary macro TEST_SRV_KEY_RSA_DER /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/server2.key.der */
+/* This is generated from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/server2.key.der. */
+/* BEGIN FILE binary macro TEST_SRV_KEY_RSA_DER /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/server2.key.der */
 #define TEST_SRV_KEY_RSA_DER {                                                  \
         0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, \
         0xc1, 0x4d, 0xa3, 0xdd, 0xe7, 0xcd, 0x1d, 0xd1, 0x04, 0xd7, 0x49, 0x72, \
@@ -893,8 +893,8 @@
 }
 /* END FILE */
 
-/* This is taken from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/cli2.crt. */
-/* BEGIN FILE string macro TEST_CLI_CRT_EC_PEM /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/cli2.crt */
+/* This is taken from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/cli2.crt. */
+/* BEGIN FILE string macro TEST_CLI_CRT_EC_PEM /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/cli2.crt */
 #define TEST_CLI_CRT_EC_PEM                                                    \
     "-----BEGIN CERTIFICATE-----\r\n"                                          \
     "MIIB3zCCAWOgAwIBAgIBDTAMBggqhkjOPQQDAgUAMD4xCzAJBgNVBAYTAk5MMREw\r\n"     \
@@ -911,8 +911,8 @@
     "-----END CERTIFICATE-----\r\n"
 /* END FILE */
 
-/* This is generated from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/cli2.crt.der. */
-/* BEGIN FILE binary macro TEST_CLI_CRT_EC_DER /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/cli2.crt.der */
+/* This is generated from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/cli2.crt.der. */
+/* BEGIN FILE binary macro TEST_CLI_CRT_EC_DER /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/cli2.crt.der */
 #define TEST_CLI_CRT_EC_DER {                                                   \
         0x30, 0x82, 0x01, 0xdf, 0x30, 0x82, 0x01, 0x63, 0xa0, 0x03, 0x02, 0x01, \
         0x02, 0x02, 0x01, 0x0d, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, \
@@ -958,8 +958,8 @@
 }
 /* END FILE */
 
-/* This is taken from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/cli2.key. */
-/* BEGIN FILE string macro TEST_CLI_KEY_EC_PEM /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/cli2.key */
+/* This is taken from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/cli2.key. */
+/* BEGIN FILE string macro TEST_CLI_KEY_EC_PEM /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/cli2.key */
 #define TEST_CLI_KEY_EC_PEM                                                    \
     "-----BEGIN EC PRIVATE KEY-----\r\n"                                       \
     "MHcCAQEEIPb3hmTxZ3/mZI3vyk7p3U3wBf+WIop6hDhkFzJhmLcqoAoGCCqGSM49\r\n"     \
@@ -968,8 +968,8 @@
     "-----END EC PRIVATE KEY-----\r\n"
 /* END FILE */
 
-/* This is generated from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/cli2.key.der. */
-/* BEGIN FILE binary macro TEST_CLI_KEY_EC_DER /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/cli2.key.der */
+/* This is generated from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/cli2.key.der. */
+/* BEGIN FILE binary macro TEST_CLI_KEY_EC_DER /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/cli2.key.der */
 #define TEST_CLI_KEY_EC_DER {                                                   \
         0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0xf6, 0xf7, 0x86, 0x64, 0xf1, \
         0x67, 0x7f, 0xe6, 0x64, 0x8d, 0xef, 0xca, 0x4e, 0xe9, 0xdd, 0x4d, 0xf0, \
@@ -985,8 +985,8 @@
 }
 /* END FILE */
 
-/* This is taken from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/cli-rsa-sha256.crt. */
-/* BEGIN FILE string macro TEST_CLI_CRT_RSA_PEM /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/cli-rsa-sha256.crt */
+/* This is taken from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/cli-rsa-sha256.crt. */
+/* BEGIN FILE string macro TEST_CLI_CRT_RSA_PEM /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/cli-rsa-sha256.crt */
 #define TEST_CLI_CRT_RSA_PEM                                                   \
     "-----BEGIN CERTIFICATE-----\r\n"                                          \
     "MIIDPzCCAiegAwIBAgIBBDANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER\r\n"     \
@@ -1010,8 +1010,8 @@
     "-----END CERTIFICATE-----\r\n"
 /* END FILE */
 
-/* This is generated from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/cli-rsa-sha256.crt.der. */
-/* BEGIN FILE binary macro TEST_CLI_CRT_RSA_DER /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/cli-rsa-sha256.crt.der */
+/* This is generated from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/cli-rsa-sha256.crt.der. */
+/* BEGIN FILE binary macro TEST_CLI_CRT_RSA_DER /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/cli-rsa-sha256.crt.der */
 #define TEST_CLI_CRT_RSA_DER {                                                  \
         0x30, 0x82, 0x03, 0x3f, 0x30, 0x82, 0x02, 0x27, 0xa0, 0x03, 0x02, 0x01, \
         0x02, 0x02, 0x01, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, \
@@ -1086,8 +1086,8 @@
 }
 /* END FILE */
 
-/* This is taken from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/cli-rsa.key. */
-/* BEGIN FILE string macro TEST_CLI_KEY_RSA_PEM /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/cli-rsa.key */
+/* This is taken from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/cli-rsa.key. */
+/* BEGIN FILE string macro TEST_CLI_KEY_RSA_PEM /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/cli-rsa.key */
 #define TEST_CLI_KEY_RSA_PEM                                                   \
     "-----BEGIN RSA PRIVATE KEY-----\r\n"                                      \
     "MIIEpAIBAAKCAQEAyHTEzLn5tXnpRdkUYLB9u5Pyax6fM60Nj4o8VmXl3ETZzGaF\r\n"     \
@@ -1118,8 +1118,8 @@
     "-----END RSA PRIVATE KEY-----\r\n"
 /* END FILE */
 
-/* This is generated from /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/cli-rsa.key.der. */
-/* BEGIN FILE binary macro TEST_CLI_KEY_RSA_DER /Users/mingal01/dev/git/release/mbedtls-restricted/framework/data_files/cli-rsa.key.der */
+/* This is generated from /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/cli-rsa.key.der. */
+/* BEGIN FILE binary macro TEST_CLI_KEY_RSA_DER /Users/mingal01/dev/git/release/manual-release-4.1.0/framework/data_files/cli-rsa.key.der */
 #define TEST_CLI_KEY_RSA_DER {                                                  \
         0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, \
         0xc8, 0x74, 0xc4, 0xcc, 0xb9, 0xf9, 0xb5, 0x79, 0xe9, 0x45, 0xd9, 0x14, \
diff -Nru mbedtls-3.6.5/tests/include/test/test_keys.h mbedtls-3.6.6/tests/include/test/test_keys.h
--- mbedtls-3.6.5/tests/include/test/test_keys.h	2025-10-14 19:12:37.013897400 +0300
+++ mbedtls-3.6.6/tests/include/test/test_keys.h	2026-03-27 19:00:27.626360400 +0200
@@ -3,11 +3,23 @@
  * Please do not edit it manually.
  *********************************************************************************/
 
-const unsigned char test_ec_bp256r1_priv[] = {
+#ifndef TEST_TEST_KEYS_H
+#define TEST_TEST_KEYS_H
+
+#if TF_PSA_CRYPTO_VERSION_MAJOR >= 1
+#include <tf_psa_crypto_common.h>
+#include <mbedtls/private/ecp.h>
+#else
+#include <common.h>
+#include <mbedtls/ecp.h>
+#endif
+
+
+static const unsigned char test_ec_bp256r1_priv[] = {
     0x21, 0x61, 0xd6, 0xf2, 0xdb, 0x76, 0x52, 0x6f, 0xa6, 0x2c, 0x16, 0xf3, 0x56, 0xa8, 0x0f, 0x01,
     0xf3, 0x2f, 0x77, 0x67, 0x84, 0xb3, 0x6a, 0xa9, 0x97, 0x99, 0xa8, 0xb7, 0x66, 0x20, 0x80, 0xff,
 };
-const unsigned char test_ec_bp256r1_pub[] = {
+static const unsigned char test_ec_bp256r1_pub[] = {
     0x04, 0x76, 0x8c, 0x8c, 0xae, 0x4a, 0xbc, 0xa6, 0x30, 0x6d, 0xb0, 0xed, 0x81, 0xb0, 0xc4, 0xa6,
     0x21, 0x5c, 0x37, 0x80, 0x66, 0xec, 0x6d, 0x61, 0x6c, 0x14, 0x6e, 0x13, 0xf1, 0xc7, 0xdf, 0x80,
     0x9b, 0x96, 0xab, 0x69, 0x11, 0xc2, 0x7d, 0x8a, 0x02, 0x33, 0x9f, 0x09, 0x26, 0x84, 0x0e, 0x55,
@@ -15,12 +27,12 @@
     0x1d,
 };
 
-const unsigned char test_ec_bp384r1_priv[] = {
+static const unsigned char test_ec_bp384r1_priv[] = {
     0x3d, 0xd9, 0x2e, 0x75, 0x0d, 0x90, 0xd7, 0xd3, 0x9f, 0xc1, 0x88, 0x5c, 0xd8, 0xad, 0x12, 0xea,
     0x94, 0x41, 0xf2, 0x2b, 0x93, 0x34, 0xb4, 0xd9, 0x65, 0x20, 0x2a, 0xdb, 0x14, 0x48, 0xce, 0x24,
     0xc5, 0x80, 0x8a, 0x85, 0xdd, 0x9a, 0xfc, 0x22, 0x9a, 0xf0, 0xa3, 0x12, 0x4f, 0x75, 0x5b, 0xcb,
 };
-const unsigned char test_ec_bp384r1_pub[] = {
+static const unsigned char test_ec_bp384r1_pub[] = {
     0x04, 0x71, 0x9f, 0x9d, 0x09, 0x3a, 0x62, 0x7e, 0x0d, 0x35, 0x03, 0x85, 0xc6, 0x61, 0xce, 0xbf,
     0x00, 0xc6, 0x19, 0x23, 0x56, 0x6f, 0xe9, 0x00, 0x6a, 0x31, 0x07, 0xaf, 0x1d, 0x87, 0x1b, 0xc6,
     0xbb, 0x68, 0x98, 0x5f, 0xd7, 0x22, 0xea, 0x32, 0xbe, 0x31, 0x6f, 0x8e, 0x78, 0x3b, 0x7c, 0xd1,
@@ -30,13 +42,13 @@
     0x6a,
 };
 
-const unsigned char test_ec_bp512r1_priv[] = {
+static const unsigned char test_ec_bp512r1_priv[] = {
     0x37, 0x2c, 0x97, 0x78, 0xf6, 0x9f, 0x72, 0x6c, 0xbc, 0xa3, 0xf4, 0xa2, 0x68, 0xf1, 0x6b, 0x4d,
     0x61, 0x7d, 0x10, 0x28, 0x0d, 0x79, 0xa6, 0xa0, 0x29, 0xcd, 0x51, 0x87, 0x9f, 0xe1, 0x01, 0x29,
     0x34, 0xdf, 0xe5, 0x39, 0x54, 0x55, 0x33, 0x7d, 0xf6, 0x90, 0x6d, 0xc7, 0xd6, 0xd2, 0xee, 0xa4,
     0xdb, 0xb2, 0x06, 0x5c, 0x02, 0x28, 0xf7, 0x3b, 0x3e, 0xd7, 0x16, 0x48, 0x0e, 0x7d, 0x71, 0xd2,
 };
-const unsigned char test_ec_bp512r1_pub[] = {
+static const unsigned char test_ec_bp512r1_pub[] = {
     0x04, 0x38, 0xb7, 0xec, 0x92, 0xb6, 0x1c, 0x5c, 0x6c, 0x7f, 0xbc, 0x28, 0xa4, 0xec, 0x75, 0x9d,
     0x48, 0xfc, 0xd4, 0xe2, 0xe3, 0x74, 0xde, 0xfd, 0x5c, 0x49, 0x68, 0xa5, 0x4d, 0xbe, 0xf7, 0x51,
     0x0e, 0x51, 0x78, 0x86, 0xfb, 0xfc, 0x38, 0xea, 0x39, 0xaa, 0x52, 0x93, 0x59, 0xd7, 0x0a, 0x71,
@@ -48,44 +60,44 @@
     0x1a,
 };
 
-const unsigned char test_ec_curve25519_priv[] = {
+static const unsigned char test_ec_curve25519_priv[] = {
     0x70, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1, 0x72, 0x51, 0xb2, 0x66, 0x45,
     0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a, 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x6a,
 };
-const unsigned char test_ec_curve25519_pub[] = {
+static const unsigned char test_ec_curve25519_pub[] = {
     0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, 0x74, 0x8b, 0x7d, 0xdc, 0xb4, 0x3e, 0xf7, 0x5a,
     0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38, 0x1a, 0xf4, 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a,
 };
 
-const unsigned char test_ec_curve448_priv[] = {
+static const unsigned char test_ec_curve448_priv[] = {
     0xe4, 0xe4, 0x9f, 0x52, 0x68, 0x6f, 0x9e, 0xe3, 0xb6, 0x38, 0x52, 0x8f, 0x72, 0x1f, 0x15, 0x96,
     0x19, 0x6f, 0xfd, 0x0a, 0x1c, 0xdd, 0xb6, 0x4c, 0x3f, 0x21, 0x6f, 0x06, 0x54, 0x18, 0x05, 0xcf,
     0xeb, 0x1a, 0x28, 0x6d, 0xc7, 0x80, 0x18, 0x09, 0x5c, 0xdf, 0xec, 0x05, 0x0e, 0x80, 0x07, 0xb5,
     0xf4, 0x90, 0x89, 0x62, 0xba, 0x20, 0xd6, 0xc1,
 };
-const unsigned char test_ec_curve448_pub[] = {
+static const unsigned char test_ec_curve448_pub[] = {
     0xc0, 0xd3, 0xa5, 0xa2, 0xb4, 0x16, 0xa5, 0x73, 0xdc, 0x99, 0x09, 0xf9, 0x2f, 0x13, 0x4a, 0xc0,
     0x13, 0x23, 0xab, 0x8f, 0x8e, 0x36, 0x80, 0x4e, 0x57, 0x85, 0x88, 0xba, 0x2d, 0x09, 0xfe, 0x7c,
     0x3e, 0x73, 0x7f, 0x77, 0x1c, 0xa1, 0x12, 0x82, 0x5b, 0x54, 0x8a, 0x0f, 0xfd, 0xed, 0x6d, 0x6a,
     0x2f, 0xd0, 0x9a, 0x3e, 0x77, 0xde, 0xc3, 0x0e,
 };
 
-const unsigned char test_ec_secp192k1_priv[] = {
+static const unsigned char test_ec_secp192k1_priv[] = {
     0x29, 0x7a, 0xc1, 0x72, 0x2c, 0xca, 0xc7, 0x58, 0x9e, 0xcb, 0x24, 0x0d, 0xc7, 0x19, 0x84, 0x25,
     0x38, 0xca, 0x97, 0x4b, 0xeb, 0x79, 0xf2, 0x28,
 };
-const unsigned char test_ec_secp192k1_pub[] = {
+static const unsigned char test_ec_secp192k1_pub[] = {
     0x04, 0x26, 0xb7, 0xbb, 0x38, 0xda, 0x64, 0x9a, 0xc2, 0x13, 0x8f, 0xc0, 0x50, 0xc6, 0x54, 0x8b,
     0x32, 0x55, 0x3d, 0xab, 0x68, 0xaf, 0xeb, 0xc3, 0x61, 0x05, 0xd3, 0x25, 0xb7, 0x55, 0x38, 0xc1,
     0x23, 0x23, 0xcb, 0x07, 0x64, 0x78, 0x9e, 0xcb, 0x99, 0x26, 0x71, 0xbe, 0xb2, 0xb6, 0xbe, 0xf2,
     0xf5,
 };
 
-const unsigned char test_ec_secp256k1_priv[] = {
+static const unsigned char test_ec_secp256k1_priv[] = {
     0x7f, 0xa0, 0x6f, 0xa0, 0x2d, 0x0e, 0x91, 0x1b, 0x9a, 0x47, 0xfd, 0xc1, 0x7d, 0x2d, 0x96, 0x2c,
     0xa0, 0x1e, 0x2f, 0x31, 0xd6, 0x0c, 0x62, 0x12, 0xd0, 0xed, 0x7e, 0x3b, 0xba, 0x23, 0xa7, 0xb9,
 };
-const unsigned char test_ec_secp256k1_pub[] = {
+static const unsigned char test_ec_secp256k1_pub[] = {
     0x04, 0x5c, 0x39, 0x15, 0x45, 0x79, 0xef, 0xd6, 0x67, 0xad, 0xc7, 0x3a, 0x81, 0x01, 0x5a, 0x79,
     0x7d, 0x2c, 0x86, 0x82, 0xcd, 0xfb, 0xd3, 0xc3, 0x55, 0x3c, 0x4a, 0x18, 0x5d, 0x48, 0x1c, 0xdc,
     0x50, 0xe4, 0x2a, 0x0e, 0x1c, 0xbc, 0x3c, 0xa2, 0x9a, 0x32, 0xa6, 0x45, 0xe9, 0x27, 0xf5, 0x4b,
@@ -93,33 +105,33 @@
     0x4d,
 };
 
-const unsigned char test_ec_secp192r1_priv[] = {
+static const unsigned char test_ec_secp192r1_priv[] = {
     0xd8, 0x3b, 0x57, 0xa5, 0x9c, 0x51, 0x35, 0x8d, 0x9c, 0x8b, 0xbb, 0x89, 0x8a, 0xff, 0x50, 0x7f,
     0x44, 0xdd, 0x14, 0xcf, 0x16, 0x91, 0x71, 0x90,
 };
-const unsigned char test_ec_secp192r1_pub[] = {
+static const unsigned char test_ec_secp192r1_pub[] = {
     0x04, 0xe3, 0x5f, 0xcb, 0xee, 0x11, 0xce, 0xc3, 0x15, 0x4f, 0x80, 0xa1, 0xa6, 0x1d, 0xf7, 0xd7,
     0x61, 0x2d, 0xe4, 0xf2, 0xfd, 0x70, 0xc5, 0x60, 0x8d, 0x0e, 0xe3, 0xa4, 0xa1, 0xa5, 0x71, 0x94,
     0x71, 0xad, 0xb3, 0x39, 0x66, 0xdd, 0x9b, 0x03, 0x5f, 0xdb, 0x77, 0x4f, 0xee, 0xba, 0x94, 0xb0,
     0x4c,
 };
 
-const unsigned char test_ec_secp224r1_priv[] = {
+static const unsigned char test_ec_secp224r1_priv[] = {
     0x87, 0x2f, 0x20, 0x3b, 0x3a, 0xd3, 0x5b, 0x7f, 0x2e, 0xcc, 0x80, 0x3c, 0x3a, 0x0e, 0x1e, 0x0b,
     0x1e, 0xd6, 0x1c, 0xc1, 0xaf, 0xe7, 0x1b, 0x18, 0x9c, 0xd4, 0xc9, 0x95,
 };
-const unsigned char test_ec_secp224r1_pub[] = {
+static const unsigned char test_ec_secp224r1_pub[] = {
     0x04, 0x6f, 0x00, 0xea, 0xda, 0xa9, 0x49, 0xfe, 0xe3, 0xe9, 0xe1, 0xc7, 0xfa, 0x12, 0x47, 0xee,
     0xce, 0xc8, 0x6a, 0x0d, 0xce, 0x46, 0x41, 0x8b, 0x9b, 0xd3, 0x11, 0x7b, 0x98, 0x1d, 0x4b, 0xd0,
     0xae, 0x7a, 0x99, 0x0d, 0xe9, 0x12, 0xf9, 0xd0, 0x60, 0xd6, 0xcb, 0x53, 0x1a, 0x42, 0xd2, 0x2e,
     0x39, 0x4a, 0xc2, 0x9e, 0x81, 0x80, 0x4b, 0xf1, 0x60,
 };
 
-const unsigned char test_ec_secp256r1_priv[] = {
+static const unsigned char test_ec_secp256r1_priv[] = {
     0x49, 0xc9, 0xa8, 0xc1, 0x8c, 0x4b, 0x88, 0x56, 0x38, 0xc4, 0x31, 0xcf, 0x1d, 0xf1, 0xc9, 0x94,
     0x13, 0x16, 0x09, 0xb5, 0x80, 0xd4, 0xfd, 0x43, 0xa0, 0xca, 0xb1, 0x7d, 0xb2, 0xf1, 0x3e, 0xee,
 };
-const unsigned char test_ec_secp256r1_pub[] = {
+static const unsigned char test_ec_secp256r1_pub[] = {
     0x04, 0x77, 0x72, 0x65, 0x6f, 0x81, 0x4b, 0x39, 0x92, 0x79, 0xd5, 0xe1, 0xf1, 0x78, 0x1f, 0xac,
     0x6f, 0x09, 0x9a, 0x3c, 0x5c, 0xa1, 0xb0, 0xe3, 0x53, 0x51, 0x83, 0x4b, 0x08, 0xb6, 0x5e, 0x0b,
     0x57, 0x25, 0x90, 0xcd, 0xaf, 0x8f, 0x76, 0x93, 0x61, 0xbc, 0xf3, 0x4a, 0xcf, 0xc1, 0x1e, 0x5e,
@@ -127,12 +139,12 @@
     0x45,
 };
 
-const unsigned char test_ec_secp384r1_priv[] = {
+static const unsigned char test_ec_secp384r1_priv[] = {
     0x3f, 0x5d, 0x8d, 0x9b, 0xe2, 0x80, 0xb5, 0x69, 0x6c, 0xc5, 0xcc, 0x9f, 0x94, 0xcf, 0x8a, 0xf7,
     0xe6, 0xb6, 0x1d, 0xd6, 0x59, 0x2b, 0x2a, 0xb2, 0xb3, 0xa4, 0xc6, 0x07, 0x45, 0x04, 0x17, 0xec,
     0x32, 0x7d, 0xcd, 0xca, 0xed, 0x7c, 0x10, 0x05, 0x3d, 0x71, 0x9a, 0x05, 0x74, 0xf0, 0xa7, 0x6a,
 };
-const unsigned char test_ec_secp384r1_pub[] = {
+static const unsigned char test_ec_secp384r1_pub[] = {
     0x04, 0xd9, 0xc6, 0x62, 0xb5, 0x0b, 0xa2, 0x9c, 0xa4, 0x79, 0x90, 0x45, 0x0e, 0x04, 0x3a, 0xea,
     0xf4, 0xf0, 0xc6, 0x9b, 0x15, 0x67, 0x6d, 0x11, 0x2f, 0x62, 0x2a, 0x71, 0xc9, 0x30, 0x59, 0xaf,
     0x99, 0x96, 0x91, 0xc5, 0x68, 0x0d, 0x2b, 0x44, 0xd1, 0x11, 0x57, 0x9d, 0xb1, 0x2f, 0x4a, 0x41,
@@ -142,14 +154,14 @@
     0x47,
 };
 
-const unsigned char test_ec_secp521r1_priv[] = {
+static const unsigned char test_ec_secp521r1_priv[] = {
     0x01, 0xb1, 0xb6, 0xad, 0x07, 0xbb, 0x79, 0xe7, 0x32, 0x0d, 0xa5, 0x98, 0x60, 0xea, 0x28, 0xe0,
     0x55, 0x28, 0x4f, 0x60, 0x58, 0xf2, 0x79, 0xde, 0x66, 0x6e, 0x06, 0xd4, 0x35, 0xd2, 0xaf, 0x7b,
     0xda, 0x28, 0xd9, 0x9f, 0xa4, 0x7b, 0x7d, 0xd0, 0x96, 0x3e, 0x16, 0xb0, 0x07, 0x30, 0x78, 0xee,
     0x8b, 0x8a, 0x38, 0xd9, 0x66, 0xa5, 0x82, 0xf4, 0x6d, 0x19, 0xff, 0x95, 0xdf, 0x3a, 0xd9, 0x68,
     0x5a, 0xae,
 };
-const unsigned char test_ec_secp521r1_pub[] = {
+static const unsigned char test_ec_secp521r1_pub[] = {
     0x04, 0x00, 0x1d, 0xe1, 0x42, 0xd5, 0x4f, 0x69, 0xeb, 0x03, 0x8e, 0xe4, 0xb7, 0xaf, 0x9d, 0x3c,
     0xa0, 0x77, 0x36, 0xfd, 0x9c, 0xf7, 0x19, 0xeb, 0x35, 0x4d, 0x69, 0x87, 0x9e, 0xe7, 0xf3, 0xc1,
     0x36, 0xfb, 0x0f, 0xbf, 0x9f, 0x08, 0xf8, 0x6b, 0xe5, 0xfa, 0x12, 0x8e, 0xc1, 0xa0, 0x51, 0xd3,
@@ -161,7 +173,643 @@
     0x2c, 0x4c, 0x2f, 0x6a, 0xc1,
 };
 
-const unsigned char test_rsa_1024_priv[] = {
+static const unsigned char test_mldsa_44_priv[] = {
+    0xd7, 0x13, 0x61, 0xc0, 0x00, 0xf9, 0xa7, 0xbc, 0x99, 0xdf, 0xb4, 0x25, 0xbc, 0xb6, 0xbb, 0x27,
+    0xc3, 0x2c, 0x36, 0xab, 0x44, 0x4f, 0xf3, 0x70, 0x8b, 0x2d, 0x93, 0xb4, 0xe6, 0x6d, 0x5b, 0x5b,
+};
+static const unsigned char test_mldsa_44_pub[] = {
+    0xb8, 0x45, 0xfa, 0x28, 0x81, 0x40, 0x7a, 0x59, 0x18, 0x30, 0x71, 0x62, 0x9b, 0x08, 0x22, 0x31,
+    0x28, 0x11, 0x60, 0x14, 0xfb, 0x58, 0xff, 0x6b, 0xb4, 0xc8, 0xc9, 0xfe, 0x19, 0xcf, 0x5b, 0x0b,
+    0xd7, 0x7b, 0x16, 0x64, 0x8a, 0x34, 0x4f, 0xfe, 0x48, 0x6b, 0xc3, 0xe3, 0xcb, 0x5f, 0xab, 0x9a,
+    0xbc, 0x4c, 0xc2, 0xf1, 0xc3, 0x49, 0x01, 0x69, 0x2b, 0xec, 0x5d, 0x29, 0x0d, 0x81, 0x5a, 0x6c,
+    0xdf, 0x7e, 0x97, 0x10, 0xa3, 0x38, 0x82, 0x47, 0xa7, 0xe0, 0x37, 0x16, 0x15, 0x50, 0x7a, 0x57,
+    0x2c, 0x98, 0x35, 0xe6, 0x73, 0x7b, 0xf3, 0x0b, 0x92, 0xa7, 0x96, 0xff, 0xf3, 0xa1, 0x0a, 0x73,
+    0x0c, 0x7b, 0x55, 0x09, 0x24, 0xeb, 0x1f, 0xb6, 0xd5, 0x61, 0x95, 0xf0, 0x2d, 0xe6, 0xd3, 0x74,
+    0x6f, 0x9f, 0x33, 0x0b, 0xeb, 0xe9, 0x90, 0xc9, 0x0c, 0x4d, 0x67, 0x6a, 0xd4, 0x15, 0xf4, 0x26,
+    0x8d, 0x2d, 0x6b, 0x54, 0x8a, 0x8b, 0xcd, 0xf2, 0x7f, 0xdd, 0x46, 0x7e, 0x67, 0x49, 0xc0, 0xf8,
+    0x7b, 0x71, 0xe8, 0x5c, 0x27, 0x97, 0x69, 0x47, 0x72, 0xbb, 0xa8, 0x8d, 0x4f, 0x1a, 0xc0, 0x6c,
+    0x7c, 0x0e, 0x91, 0x78, 0x64, 0x72, 0xcd, 0x76, 0x35, 0x37, 0x08, 0xd6, 0xbb, 0xc5, 0xc2, 0x8e,
+    0x9d, 0xb8, 0x91, 0xc3, 0x94, 0x0e, 0x87, 0x90, 0x52, 0xd3, 0x0c, 0x8f, 0xd1, 0x09, 0x65, 0xcb,
+    0xb8, 0xee, 0x1b, 0xd7, 0x9b, 0x06, 0x0d, 0x37, 0xfb, 0x83, 0x90, 0x98, 0x55, 0x2a, 0xab, 0xdd,
+    0x3a, 0x57, 0xab, 0x1c, 0x6a, 0x82, 0xb0, 0x91, 0x1d, 0x1c, 0xf1, 0x48, 0x65, 0x4a, 0xa5, 0x61,
+    0x3b, 0x07, 0x01, 0x4b, 0x21, 0xe4, 0xa1, 0x18, 0x2b, 0x4a, 0x55, 0x01, 0x67, 0x1d, 0x11, 0x2f,
+    0x59, 0x75, 0xfb, 0x0c, 0x8a, 0x2a, 0xc4, 0x5d, 0x57, 0x5d, 0xc4, 0x2f, 0x48, 0x97, 0x7f, 0xf3,
+    0x7f, 0xff, 0x42, 0x1d, 0xb2, 0x7c, 0x45, 0xe7, 0x9f, 0x8a, 0x94, 0x72, 0x00, 0x70, 0x23, 0xdf,
+    0x0b, 0x64, 0x20, 0x5c, 0xd9, 0xf5, 0x7c, 0x02, 0xce, 0x9d, 0x1f, 0x61, 0xf2, 0xae, 0x24, 0xf7,
+    0x13, 0x9f, 0x56, 0x41, 0x98, 0x4e, 0xe8, 0xdf, 0x78, 0x3b, 0x9e, 0xa4, 0x3e, 0x99, 0x7c, 0x6e,
+    0x19, 0xd0, 0x9e, 0x06, 0x2a, 0xfc, 0xa5, 0x6e, 0x4f, 0x76, 0xaa, 0xab, 0x8f, 0x66, 0x60, 0x0f,
+    0xc7, 0x8f, 0x6a, 0xb4, 0xf6, 0x78, 0x56, 0x90, 0xd1, 0x85, 0x81, 0x6e, 0xe3, 0x5a, 0x93, 0x94,
+    0x58, 0xb6, 0x03, 0x24, 0xee, 0xfc, 0x60, 0xe6, 0x4b, 0x11, 0xfa, 0x0d, 0x20, 0x31, 0x7a, 0xcb,
+    0x6c, 0xb2, 0x9a, 0xa0, 0x3c, 0x77, 0x5f, 0x15, 0x16, 0x72, 0x95, 0x26, 0x89, 0xfa, 0x4f, 0x8f,
+    0x83, 0x83, 0x29, 0xcb, 0x9e, 0x6d, 0xc9, 0x94, 0x5b, 0x6c, 0x7a, 0xde, 0x4e, 0x7b, 0x66, 0x35,
+    0x78, 0xf8, 0x7d, 0x39, 0x35, 0xf2, 0xa1, 0x52, 0x20, 0x97, 0xad, 0x50, 0x42, 0xa0, 0xd9, 0x90,
+    0xa6, 0x28, 0x51, 0x0b, 0x61, 0x03, 0xcb, 0x24, 0x2c, 0xd8, 0xa3, 0xaf, 0xc1, 0xa5, 0xad, 0xa5,
+    0x23, 0x31, 0xf4, 0xdf, 0x46, 0x1b, 0xc1, 0xda, 0x51, 0xd1, 0xd2, 0x24, 0x09, 0x4e, 0x7a, 0xbe,
+    0xd3, 0xd8, 0x7d, 0x98, 0xf0, 0xd8, 0x17, 0x08, 0x47, 0x80, 0xee, 0x80, 0x37, 0x0f, 0x39, 0x76,
+    0x31, 0xec, 0xb7, 0x5d, 0x42, 0x64, 0xb6, 0xb5, 0xe2, 0xe6, 0x6c, 0x05, 0x86, 0xb5, 0xfb, 0x74,
+    0x35, 0x16, 0x39, 0x91, 0x65, 0x83, 0x7a, 0x0f, 0xdf, 0xf7, 0xc6, 0x13, 0x4f, 0x03, 0x3b, 0xfa,
+    0x69, 0xc1, 0xb2, 0x41, 0x69, 0x65, 0xc6, 0xe5, 0x78, 0x59, 0x2f, 0x40, 0xe2, 0x58, 0xcb, 0x6d,
+    0xfb, 0x29, 0xfb, 0x8e, 0x0f, 0x54, 0x35, 0x5b, 0x6e, 0x24, 0xa6, 0x5f, 0x67, 0xab, 0xae, 0x31,
+    0x93, 0xd0, 0x07, 0x11, 0x5c, 0xc0, 0xb9, 0xff, 0x94, 0xcb, 0x91, 0x1a, 0x93, 0xb1, 0xa7, 0x6c,
+    0x0e, 0x76, 0x62, 0xf5, 0xe2, 0xb2, 0x01, 0x39, 0xe0, 0x15, 0x9e, 0xd9, 0x29, 0xcb, 0x93, 0x2d,
+    0x48, 0x95, 0xf8, 0x9a, 0x02, 0xe5, 0x5c, 0x59, 0xdf, 0x2d, 0xbb, 0x8f, 0x6e, 0x5d, 0xd7, 0xd5,
+    0xb1, 0xf3, 0xce, 0xc3, 0x7b, 0x4a, 0x91, 0x66, 0xb3, 0x81, 0xc5, 0x44, 0x0e, 0x23, 0xe6, 0x73,
+    0x68, 0xcd, 0xe0, 0xa2, 0x9d, 0x59, 0xaa, 0x05, 0xa3, 0xc9, 0xbe, 0x24, 0xa4, 0xdc, 0x8d, 0xd7,
+    0x5b, 0xe3, 0x0e, 0x82, 0xbc, 0x63, 0x5d, 0x36, 0xaa, 0xc6, 0x6d, 0xe8, 0x80, 0xc6, 0x70, 0x1a,
+    0x98, 0x7d, 0x7e, 0x05, 0xf0, 0xf2, 0xff, 0x28, 0x78, 0x28, 0xbe, 0xc3, 0x05, 0x95, 0x08, 0x9d,
+    0x8a, 0xb9, 0xaa, 0x39, 0x0e, 0xd7, 0x19, 0xca, 0xa6, 0xe5, 0x76, 0xcd, 0xbb, 0xe9, 0xb1, 0x84,
+    0xa3, 0x22, 0xe5, 0xe2, 0xda, 0xbb, 0x69, 0xc2, 0x3c, 0xc6, 0x96, 0xd5, 0x4f, 0xc3, 0x2f, 0xf5,
+    0x70, 0x01, 0xb6, 0xb6, 0x4e, 0x2a, 0x83, 0x7f, 0x30, 0x62, 0xd8, 0x5a, 0xeb, 0x50, 0xb3, 0x51,
+    0x0f, 0x7e, 0xdf, 0xc3, 0x4d, 0xf3, 0x8e, 0x08, 0x3d, 0x4d, 0x9b, 0x94, 0xff, 0xab, 0x0d, 0xe1,
+    0x5d, 0x73, 0xd9, 0xaf, 0x30, 0xb9, 0xf3, 0x1c, 0xc4, 0xf4, 0x1c, 0x9c, 0x24, 0xf2, 0xd6, 0x18,
+    0xb2, 0xa7, 0xc3, 0xc4, 0xbd, 0xfb, 0x74, 0x5d, 0x52, 0xd3, 0xeb, 0x54, 0x58, 0x9c, 0x8b, 0xda,
+    0x8a, 0xc0, 0x5d, 0xad, 0x14, 0xec, 0x74, 0x45, 0x05, 0x57, 0x5a, 0x09, 0x88, 0xee, 0xc6, 0x51,
+    0xc1, 0x71, 0x54, 0x39, 0xfd, 0xfb, 0x29, 0x92, 0x33, 0x80, 0xa4, 0x3c, 0x1a, 0x66, 0xa8, 0x6c,
+    0x98, 0x2a, 0x84, 0x1f, 0x11, 0x82, 0x0a, 0x6a, 0x0e, 0x1e, 0x2f, 0x2f, 0xff, 0x51, 0x08, 0xec,
+    0xae, 0x51, 0xa6, 0xaa, 0xbc, 0x9b, 0x94, 0x92, 0x26, 0xd2, 0x28, 0xff, 0x84, 0xc4, 0xe5, 0xe5,
+    0xd6, 0x31, 0x14, 0xd8, 0x03, 0x59, 0xc4, 0x93, 0x1e, 0x61, 0x2d, 0xce, 0xd1, 0x83, 0x8b, 0x7d,
+    0x06, 0x6a, 0xc9, 0x18, 0x2c, 0xec, 0xfa, 0x22, 0x3a, 0x21, 0xa4, 0xc8, 0xe1, 0x55, 0xae, 0xfa,
+    0x78, 0x03, 0x73, 0xbc, 0xc1, 0x50, 0x98, 0xae, 0xe4, 0x0c, 0x03, 0x3a, 0xf2, 0x2f, 0x8e, 0x7c,
+    0x67, 0xa0, 0xd2, 0x52, 0x6d, 0xa7, 0x47, 0x5e, 0x83, 0x03, 0x08, 0xc0, 0x4a, 0xed, 0x9d, 0x32,
+    0xbc, 0xcc, 0x72, 0xe7, 0x19, 0xee, 0x70, 0xa8, 0xd1, 0x3f, 0x09, 0xac, 0x11, 0xe2, 0x6e, 0xa2,
+    0x37, 0xd5, 0xcc, 0x8f, 0x98, 0xb5, 0xae, 0x0e, 0x54, 0xf9, 0x33, 0xbd, 0x05, 0x07, 0x94, 0x2e,
+    0xd9, 0x00, 0xd0, 0x56, 0xfd, 0x32, 0xf8, 0xe6, 0xe8, 0x17, 0x77, 0x91, 0x2f, 0xd4, 0x82, 0x74,
+    0x60, 0x29, 0xb7, 0x1c, 0xce, 0x3b, 0xa6, 0x9b, 0x8f, 0xc2, 0xd0, 0x3e, 0xb4, 0x41, 0x02, 0x7c,
+    0x38, 0x7b, 0xc2, 0xf9, 0x50, 0x31, 0xa0, 0xae, 0x70, 0x52, 0x21, 0x5e, 0xb2, 0x4b, 0x9e, 0xa8,
+    0xfb, 0x0a, 0x96, 0x1b, 0x0f, 0x80, 0xbf, 0xa8, 0x0d, 0x0d, 0x62, 0x57, 0xc1, 0xc2, 0x2b, 0x50,
+    0x8c, 0x5d, 0x31, 0xb9, 0x7f, 0xcd, 0xfe, 0x1d, 0x17, 0x66, 0xe8, 0xa9, 0xc8, 0x77, 0x19, 0x32,
+    0xdd, 0x59, 0x8a, 0xdb, 0x7e, 0x71, 0x77, 0x43, 0xf4, 0x5f, 0xc5, 0x71, 0xf2, 0x1e, 0x4a, 0x51,
+    0x62, 0x49, 0xf8, 0x1d, 0x74, 0x7f, 0x15, 0x32, 0x97, 0x90, 0xf0, 0xf7, 0x0a, 0x0b, 0x8e, 0x46,
+    0x1a, 0x4e, 0xdf, 0x50, 0x50, 0x4a, 0xf0, 0x3f, 0x30, 0xdd, 0xf8, 0xa8, 0x81, 0x8e, 0x38, 0x76,
+    0x1e, 0x16, 0x81, 0xd6, 0xdd, 0xef, 0x0b, 0x1d, 0xd3, 0x26, 0xb2, 0xec, 0x22, 0x8c, 0xe4, 0x85,
+    0x70, 0xf2, 0x85, 0xb4, 0x9d, 0x29, 0xd7, 0xc2, 0xef, 0x37, 0x86, 0x6d, 0x54, 0x46, 0xdf, 0x82,
+    0xb8, 0xe4, 0x3b, 0x34, 0xcb, 0x24, 0x89, 0x62, 0xa2, 0x1a, 0x9a, 0x39, 0x46, 0x15, 0x97, 0x40,
+    0xf8, 0xae, 0xe8, 0xe6, 0xa1, 0x6a, 0x4e, 0xb2, 0xb4, 0x2d, 0x14, 0x3f, 0xe2, 0x61, 0x2e, 0x05,
+    0xef, 0x4b, 0x5e, 0x64, 0x6d, 0x81, 0x32, 0x48, 0x44, 0x45, 0x56, 0xa2, 0xa8, 0xbf, 0x92, 0xce,
+    0x10, 0xba, 0xde, 0xcb, 0x6b, 0x8a, 0x40, 0xb0, 0x80, 0xdd, 0x42, 0xd5, 0x33, 0x46, 0xfe, 0xfc,
+    0xc4, 0xb9, 0xb4, 0x0b, 0x1e, 0x49, 0x98, 0x99, 0x1e, 0xc7, 0x53, 0xc9, 0x5a, 0xa2, 0xf2, 0xa5,
+    0x06, 0xf3, 0x11, 0xe7, 0x10, 0xb0, 0xf1, 0xd3, 0x6c, 0x1d, 0xca, 0x66, 0x44, 0xee, 0x6d, 0x1d,
+    0x4a, 0xe9, 0xce, 0xa5, 0x66, 0x6e, 0xf4, 0xb3, 0xe8, 0x88, 0xdb, 0xdb, 0xb9, 0x5a, 0x77, 0xec,
+    0xfe, 0x1e, 0x8b, 0x47, 0x7d, 0xe7, 0xcb, 0x07, 0x63, 0x9d, 0x68, 0x2d, 0x53, 0x02, 0x0e, 0xc1,
+    0x4e, 0xa6, 0xc7, 0xdd, 0x7e, 0x71, 0x53, 0x89, 0xd1, 0x09, 0x38, 0x42, 0x9f, 0xab, 0x8a, 0x06,
+    0x8a, 0x14, 0x66, 0xa4, 0xcd, 0x89, 0x13, 0x59, 0xf8, 0x07, 0x4e, 0x0f, 0x5a, 0x14, 0x2a, 0xdd,
+    0x73, 0x1b, 0x87, 0x87, 0x8d, 0x98, 0x5e, 0x4f, 0xa6, 0xec, 0xb3, 0xb7, 0x3d, 0x29, 0x85, 0x53,
+    0x41, 0x82, 0x73, 0xe9, 0x50, 0x3a, 0xa8, 0x40, 0x92, 0xc0, 0x80, 0xe5, 0xf2, 0x90, 0x2f, 0x90,
+    0xf5, 0xc5, 0x99, 0x44, 0xd2, 0x4c, 0xa0, 0x27, 0x1d, 0x11, 0xd0, 0xd6, 0x73, 0x46, 0x06, 0xd0,
+    0x39, 0x55, 0x0a, 0x37, 0xfc, 0xa2, 0xb7, 0x35, 0x85, 0x0e, 0x63, 0xf5, 0x40, 0xf2, 0xf0, 0x6b,
+    0x79, 0x14, 0x4b, 0x5c, 0x4e, 0xd2, 0xc7, 0x00, 0xbb, 0x51, 0xc3, 0x3d, 0x26, 0x5b, 0x3d, 0x03,
+    0x73, 0x89, 0xc9, 0x9e, 0xfd, 0x59, 0x76, 0x42, 0xd8, 0x29, 0xdb, 0x1e, 0xb5, 0x86, 0x43, 0xcf,
+    0xcd, 0x07, 0xf4, 0xde, 0xc6, 0x0b, 0x8f, 0x72, 0x7d, 0x97, 0xbd, 0x7c, 0x4b, 0x59, 0xbd, 0xa1,
+};
+
+static const unsigned char test_mldsa_65_priv[] = {
+    0x1b, 0xd6, 0x7d, 0xc7, 0x82, 0xb2, 0x95, 0x8e, 0x18, 0x9e, 0x31, 0x5c, 0x04, 0x0d, 0xd1, 0xf6,
+    0x4c, 0x8a, 0xb2, 0x32, 0xa6, 0xa1, 0x70, 0xe1, 0xa7, 0xa5, 0x2c, 0x33, 0xf1, 0x08, 0x51, 0xb1,
+};
+static const unsigned char test_mldsa_65_pub[] = {
+    0x43, 0xad, 0x65, 0x60, 0xd3, 0xbb, 0x68, 0x46, 0x67, 0xa5, 0x59, 0xee, 0x6e, 0xc7, 0xc8, 0x16,
+    0x02, 0x0e, 0x5b, 0x65, 0x67, 0x1f, 0x27, 0x0f, 0x23, 0x53, 0xa8, 0xc9, 0x12, 0xb6, 0xc2, 0x6b,
+    0x0d, 0xb0, 0xc2, 0xcf, 0x42, 0xdc, 0x74, 0x7b, 0x10, 0xaa, 0x3e, 0xbd, 0xd5, 0x73, 0xb3, 0x00,
+    0xee, 0xa4, 0x6c, 0x42, 0x00, 0xb2, 0x10, 0x09, 0x4f, 0x95, 0x12, 0x11, 0x9a, 0x6b, 0xb8, 0x37,
+    0x24, 0x27, 0x62, 0xb2, 0xce, 0x94, 0xc2, 0x46, 0x72, 0x78, 0x50, 0x0e, 0xe7, 0xb1, 0x39, 0xbe,
+    0xd9, 0x06, 0x67, 0x66, 0x63, 0x35, 0x5b, 0x81, 0x3a, 0x9a, 0xd9, 0xd3, 0xdb, 0x70, 0xf7, 0xaf,
+    0x2d, 0x78, 0x50, 0x40, 0xbf, 0xd5, 0x12, 0x08, 0xbd, 0x3d, 0x2c, 0xfb, 0x09, 0xea, 0xf7, 0xce,
+    0xdf, 0x77, 0xd1, 0xb5, 0x9d, 0xa7, 0x5f, 0x77, 0x28, 0xf1, 0x20, 0xc1, 0x18, 0x98, 0xd9, 0xec,
+    0x2c, 0xb2, 0x2c, 0x73, 0xeb, 0x8f, 0x94, 0x36, 0xff, 0x60, 0x52, 0x4b, 0x56, 0xee, 0x6b, 0x41,
+    0x30, 0x30, 0xeb, 0x7d, 0xd1, 0x07, 0x74, 0x26, 0x14, 0x52, 0xcd, 0x8c, 0x5a, 0xde, 0x75, 0xd1,
+    0x96, 0x76, 0x28, 0x07, 0x8c, 0xda, 0x77, 0xe2, 0xb1, 0xaf, 0xb8, 0x3b, 0x9f, 0x07, 0xf6, 0x93,
+    0x9d, 0x37, 0xff, 0x54, 0xd5, 0xe1, 0x0e, 0xd1, 0x7f, 0xf8, 0xa3, 0xc2, 0x15, 0x46, 0xa8, 0x9f,
+    0x51, 0x45, 0x76, 0xae, 0x78, 0x0d, 0xe8, 0x76, 0x1c, 0x4f, 0x2e, 0xa2, 0x88, 0x28, 0xc6, 0x9e,
+    0x38, 0xc7, 0x30, 0xac, 0xaa, 0x4c, 0xc8, 0xdc, 0x7d, 0xf6, 0x3b, 0xa4, 0xc1, 0x52, 0x55, 0x10,
+    0xfa, 0xe2, 0xc8, 0xe1, 0xb0, 0x18, 0x12, 0x35, 0x8b, 0xc5, 0xdf, 0xc0, 0x1e, 0x95, 0x52, 0x94,
+    0xa5, 0xdf, 0xdd, 0x1c, 0xff, 0x05, 0x19, 0xe2, 0x0b, 0x8f, 0x74, 0xfe, 0x18, 0x85, 0x4d, 0x80,
+    0xc8, 0x60, 0x51, 0xaa, 0x5c, 0xc2, 0xfc, 0x1d, 0xb0, 0x78, 0xbc, 0x78, 0x5b, 0xf4, 0xba, 0xd6,
+    0x83, 0x2b, 0x8c, 0x26, 0x91, 0x56, 0x50, 0x9b, 0x33, 0x20, 0x38, 0xb4, 0xc3, 0x71, 0x9d, 0xc4,
+    0x98, 0x14, 0xfc, 0x6b, 0x6a, 0xd5, 0x36, 0x0e, 0x94, 0x5a, 0xff, 0xf4, 0xd4, 0xac, 0x23, 0x5f,
+    0x56, 0xc7, 0xf7, 0xa9, 0xa8, 0x72, 0xb5, 0x18, 0xc1, 0xf0, 0xd4, 0x81, 0x84, 0xda, 0x0e, 0xb3,
+    0x18, 0xf7, 0x4e, 0xb8, 0x4c, 0x4f, 0x32, 0x4a, 0x2b, 0xd0, 0x37, 0x04, 0xd2, 0xe2, 0xa5, 0x9f,
+    0x64, 0xa8, 0x85, 0x4c, 0x7a, 0xef, 0xb2, 0xd3, 0x53, 0x0e, 0x20, 0xc8, 0xae, 0x8a, 0x48, 0x7e,
+    0x6c, 0xbe, 0xda, 0x64, 0x5b, 0xd8, 0x6a, 0x5a, 0x83, 0xe7, 0x7a, 0x6a, 0x22, 0x88, 0x8e, 0xd8,
+    0xe4, 0x3a, 0x7f, 0x48, 0x04, 0xc2, 0xde, 0x18, 0x7f, 0x1a, 0xcb, 0xa3, 0xcf, 0x55, 0xcf, 0x99,
+    0x41, 0x2a, 0x7a, 0x59, 0xcf, 0x77, 0xa4, 0xa9, 0x77, 0x72, 0x4a, 0x72, 0x68, 0x6f, 0xdf, 0x7f,
+    0xc6, 0x44, 0x92, 0xa5, 0xcb, 0x75, 0x92, 0x1a, 0xd0, 0x14, 0xeb, 0x72, 0x7e, 0xda, 0x1d, 0xfa,
+    0x7b, 0xd7, 0xac, 0xe5, 0x2f, 0xe2, 0x92, 0x32, 0x2f, 0x0b, 0xe0, 0xb0, 0x04, 0xdc, 0xe4, 0x4b,
+    0xea, 0xa2, 0x0f, 0xf0, 0x6a, 0x76, 0x91, 0xdc, 0x36, 0x40, 0x53, 0x61, 0xf9, 0x24, 0x0d, 0xdf,
+    0x2f, 0xd1, 0xa5, 0xec, 0x42, 0x2e, 0xd6, 0x39, 0x50, 0x5a, 0xb8, 0xe1, 0x37, 0xb9, 0x71, 0xd5,
+    0x72, 0x9b, 0x11, 0xe8, 0x4c, 0x04, 0x02, 0x47, 0x42, 0x4a, 0x51, 0xdd, 0xdb, 0xdb, 0xc4, 0x3a,
+    0xf2, 0x61, 0xd0, 0x38, 0xb0, 0xcd, 0x70, 0xd5, 0xbf, 0x44, 0x25, 0x2a, 0x37, 0x86, 0xa2, 0x6a,
+    0xf3, 0xfc, 0xd4, 0xec, 0x10, 0x0e, 0x5c, 0xdd, 0xe0, 0x19, 0xf1, 0x7b, 0xe6, 0xa6, 0x4f, 0x82,
+    0x0c, 0x3f, 0x62, 0x2f, 0x78, 0xd4, 0xf5, 0x6a, 0x98, 0x41, 0x22, 0xd6, 0xfa, 0x2d, 0x43, 0x8d,
+    0x54, 0x8d, 0xd8, 0x7b, 0x90, 0x95, 0xf1, 0xff, 0x02, 0x43, 0x78, 0x54, 0xe2, 0x41, 0x9a, 0x03,
+    0x16, 0xc3, 0x3e, 0xaf, 0xfa, 0x01, 0x61, 0x73, 0x7e, 0x47, 0x6a, 0x9e, 0x70, 0x7c, 0xc4, 0x0e,
+    0x78, 0x68, 0x6d, 0x6a, 0x04, 0x3d, 0xde, 0x96, 0x2b, 0x31, 0x9b, 0xe2, 0xbf, 0x9f, 0x7a, 0x1e,
+    0xff, 0x9e, 0xde, 0xfd, 0x1b, 0x4c, 0xd0, 0x71, 0x31, 0x49, 0x4c, 0x08, 0x40, 0x83, 0xbf, 0x76,
+    0x18, 0x1e, 0x3e, 0xb1, 0x39, 0x99, 0x29, 0x31, 0x44, 0x73, 0xa7, 0x5e, 0x19, 0x9a, 0xc9, 0xd5,
+    0x44, 0x4d, 0xb0, 0xce, 0xc0, 0x7e, 0x62, 0x5e, 0xc7, 0x0c, 0x68, 0x64, 0x09, 0x39, 0x61, 0x95,
+    0x09, 0x87, 0xfb, 0x1e, 0x96, 0xdc, 0xb7, 0xe0, 0x01, 0x20, 0x98, 0x65, 0xd6, 0x6d, 0x82, 0x9c,
+    0xd2, 0xe2, 0xb2, 0x40, 0x81, 0x8c, 0xac, 0xe0, 0x03, 0xc9, 0xcc, 0x74, 0xdc, 0xe5, 0x15, 0x1c,
+    0x65, 0xe5, 0x9a, 0xc1, 0xef, 0x6d, 0x49, 0x5b, 0x0c, 0x71, 0x7b, 0x44, 0x12, 0xc7, 0x0b, 0x50,
+    0xcf, 0x44, 0xf4, 0x4e, 0x64, 0x87, 0x88, 0xf4, 0x6b, 0xaf, 0x6f, 0x8a, 0xf3, 0x36, 0x1f, 0x0e,
+    0x4b, 0x61, 0x19, 0xed, 0xf6, 0x37, 0x4d, 0xa5, 0x96, 0x45, 0x31, 0x69, 0xb9, 0x35, 0xe1, 0xa3,
+    0xb8, 0x75, 0xa6, 0xc1, 0xb9, 0xfe, 0x38, 0x4a, 0xf9, 0x61, 0x86, 0x05, 0x14, 0xe8, 0xcf, 0x29,
+    0x1d, 0x86, 0x50, 0xd7, 0x53, 0x0d, 0xb4, 0x2a, 0x46, 0x79, 0x06, 0x49, 0xb5, 0xd8, 0x13, 0x4a,
+    0xae, 0xc3, 0x3a, 0x41, 0xf0, 0xab, 0x42, 0x96, 0xae, 0x26, 0x20, 0x32, 0x91, 0xf1, 0xc2, 0xbb,
+    0x52, 0x76, 0xac, 0x30, 0x52, 0x69, 0x77, 0x8e, 0x7f, 0x2a, 0x4b, 0xac, 0x15, 0xb5, 0xa3, 0x1a,
+    0x6b, 0x6b, 0x76, 0x34, 0x25, 0x96, 0xd3, 0x9c, 0x7f, 0xd3, 0xd1, 0xc5, 0x18, 0x68, 0x93, 0x72,
+    0xeb, 0xd2, 0x0b, 0x66, 0x7b, 0xe5, 0xee, 0x2e, 0xd1, 0x1b, 0xc1, 0x07, 0xa7, 0x60, 0x0e, 0xda,
+    0x1b, 0xe7, 0xa5, 0xdc, 0x05, 0xbb, 0x9f, 0x16, 0xd2, 0xb8, 0xbb, 0x1c, 0x7d, 0x8d, 0x10, 0x05,
+    0x02, 0x07, 0x53, 0x0b, 0xff, 0xda, 0xae, 0x7b, 0x11, 0xe0, 0x61, 0x57, 0x26, 0xf2, 0xe9, 0x9c,
+    0xe9, 0x9d, 0x6c, 0xa6, 0x04, 0x8f, 0x9d, 0x61, 0xb1, 0x4f, 0x72, 0x65, 0x47, 0x3e, 0xc2, 0xd0,
+    0x29, 0x89, 0x77, 0x2b, 0x3d, 0x7e, 0x21, 0x2a, 0xa6, 0x8d, 0x89, 0x37, 0x4c, 0x6c, 0xaf, 0x7a,
+    0xb1, 0x60, 0xc6, 0xc5, 0xe0, 0x95, 0x02, 0x04, 0x9c, 0x3d, 0x03, 0x73, 0x8d, 0x70, 0x04, 0x57,
+    0xf7, 0x06, 0x34, 0x1d, 0xde, 0xaf, 0xc6, 0xca, 0x73, 0x9e, 0xcf, 0xb4, 0xf1, 0x93, 0xea, 0x6b,
+    0x38, 0x5b, 0x03, 0x5e, 0xea, 0x0f, 0x7b, 0xfd, 0x61, 0xfa, 0x77, 0x6a, 0xf3, 0x2a, 0xed, 0x63,
+    0x66, 0xe6, 0xc0, 0x64, 0x2d, 0x1a, 0x01, 0x75, 0x9f, 0xa6, 0xbd, 0xd2, 0x95, 0xf7, 0xd1, 0x8c,
+    0xa6, 0xda, 0x1d, 0x48, 0x56, 0x3e, 0xee, 0x40, 0x3f, 0x2f, 0x8b, 0xcb, 0x6a, 0x60, 0x32, 0x6c,
+    0x48, 0x1f, 0x12, 0xf8, 0x18, 0x0b, 0x2b, 0x81, 0x17, 0xad, 0xe6, 0x1c, 0x7e, 0x29, 0xf5, 0x25,
+    0x42, 0x07, 0xc5, 0xd4, 0x65, 0x7b, 0x82, 0xbe, 0x4e, 0xba, 0x43, 0x67, 0x52, 0xec, 0x7d, 0xa0,
+    0x62, 0x7f, 0xce, 0xd8, 0x30, 0xc1, 0x5f, 0x10, 0xfb, 0x8d, 0x3c, 0xd9, 0x0b, 0x45, 0x05, 0xfa,
+    0x32, 0x5b, 0x54, 0xd9, 0x54, 0xc5, 0xb6, 0x30, 0x1d, 0xa7, 0x2b, 0x26, 0x2b, 0x22, 0x6e, 0xab,
+    0x2e, 0x4e, 0xe8, 0x82, 0x26, 0xcc, 0x60, 0x6b, 0x97, 0x73, 0x62, 0x60, 0xec, 0xb6, 0xd8, 0xf7,
+    0x4a, 0x04, 0x40, 0xaf, 0xd5, 0xd7, 0x51, 0xa9, 0x08, 0x73, 0xff, 0xf0, 0x0c, 0x8d, 0x3e, 0x9c,
+    0xa0, 0x97, 0x5f, 0x30, 0x3f, 0x7a, 0xc2, 0x63, 0xb8, 0xff, 0x49, 0x6c, 0x6c, 0x8f, 0xd2, 0x2e,
+    0x8e, 0xf7, 0xb5, 0x87, 0xba, 0xb5, 0x0a, 0x7d, 0xad, 0x99, 0xbd, 0x55, 0xd3, 0xb7, 0x96, 0x85,
+    0x84, 0xf1, 0xfb, 0x21, 0x25, 0x5e, 0xe2, 0x2d, 0xb5, 0x6a, 0xf6, 0x03, 0x4f, 0x3f, 0x13, 0xe6,
+    0x59, 0x16, 0x1a, 0x57, 0xca, 0x8c, 0x9f, 0x2e, 0x87, 0xca, 0x96, 0xbd, 0x71, 0x00, 0xfc, 0xef,
+    0x8f, 0x74, 0xa8, 0xc6, 0xa1, 0xc9, 0x2e, 0x2e, 0xff, 0x74, 0xe2, 0xf5, 0xfa, 0xe5, 0x12, 0xc0,
+    0x9d, 0x26, 0xe0, 0xf3, 0x98, 0x5d, 0x88, 0x24, 0x01, 0xef, 0xc5, 0x47, 0x27, 0xbb, 0xc0, 0xf4,
+    0xe1, 0x11, 0x07, 0x71, 0xa1, 0x06, 0x89, 0x86, 0x92, 0xd0, 0xc5, 0xa6, 0x99, 0x7c, 0xa7, 0x42,
+    0x84, 0x6f, 0xa4, 0xd4, 0x9e, 0x8a, 0xbd, 0xf1, 0x23, 0xd9, 0x27, 0x43, 0xe9, 0x94, 0x9b, 0xeb,
+    0x6e, 0x46, 0xb9, 0x65, 0x5e, 0xe6, 0x98, 0xc2, 0x3d, 0x74, 0x99, 0x1c, 0x96, 0x06, 0x7d, 0xef,
+    0x06, 0xea, 0xcb, 0x98, 0x1a, 0xd4, 0xa7, 0xa5, 0xed, 0x91, 0xea, 0xcf, 0x05, 0xd3, 0x74, 0xc7,
+    0x4c, 0x44, 0x3f, 0x3f, 0xba, 0xd3, 0x63, 0xb2, 0x45, 0x0a, 0x1a, 0x47, 0xaa, 0xf2, 0x95, 0x4d,
+    0x36, 0xe5, 0x3b, 0x06, 0x34, 0x51, 0x39, 0x13, 0x8d, 0x38, 0xb9, 0x41, 0x29, 0x89, 0x82, 0xee,
+    0xa8, 0x44, 0x00, 0xc4, 0xdc, 0xc3, 0x8f, 0x51, 0x27, 0x95, 0x19, 0x06, 0xee, 0x3e, 0x40, 0xf7,
+    0x5a, 0x5d, 0xfe, 0x09, 0xfc, 0xe9, 0xbb, 0x01, 0x43, 0xa5, 0xd5, 0xad, 0xc3, 0xc4, 0x02, 0xf2,
+    0x3a, 0x75, 0xa4, 0x23, 0xab, 0x98, 0x39, 0x2c, 0xa3, 0xa4, 0xd5, 0xd2, 0x3d, 0x3b, 0xcd, 0x56,
+    0xff, 0x22, 0xc9, 0x61, 0x2a, 0x5d, 0x2c, 0x22, 0x3c, 0x70, 0x79, 0x95, 0x8c, 0xd0, 0x51, 0x75,
+    0xaa, 0x74, 0xdd, 0xd2, 0x1b, 0x42, 0x05, 0x1c, 0xdb, 0xdc, 0x14, 0x04, 0x8c, 0xb4, 0x3c, 0xb2,
+    0xf6, 0x53, 0x5e, 0x2c, 0xa9, 0xf5, 0xb8, 0x70, 0x52, 0xf6, 0x33, 0x97, 0x6f, 0x47, 0x95, 0xcb,
+    0xa6, 0x9d, 0x39, 0xf2, 0x48, 0x1c, 0xfb, 0x9d, 0x21, 0x0c, 0x9b, 0x0e, 0x9e, 0xfd, 0x94, 0x1a,
+    0xc8, 0x75, 0xa9, 0xa6, 0xc3, 0xe8, 0x39, 0xec, 0x54, 0xf5, 0x55, 0x85, 0x72, 0x1d, 0xe4, 0x18,
+    0x15, 0xdd, 0xfc, 0x05, 0xe8, 0xa5, 0x8c, 0x97, 0xe2, 0xfa, 0x52, 0x98, 0x41, 0x35, 0xaa, 0xb0,
+    0x93, 0x10, 0x94, 0xff, 0x84, 0x00, 0xca, 0xb0, 0x43, 0xc2, 0xa5, 0xe6, 0x3c, 0x29, 0x42, 0xb7,
+    0xd3, 0x69, 0x88, 0xc4, 0xed, 0x9b, 0x73, 0xc1, 0x1d, 0x91, 0x3e, 0x75, 0x8a, 0xdf, 0x94, 0x29,
+    0x1a, 0x42, 0x74, 0x3e, 0x4f, 0xb0, 0x4c, 0x27, 0x1e, 0xd5, 0x80, 0x7e, 0xa0, 0x32, 0x71, 0xea,
+    0x66, 0x56, 0xcf, 0x96, 0x7a, 0xb2, 0x59, 0x55, 0x88, 0xb5, 0x5f, 0x82, 0xaf, 0x2d, 0x07, 0xad,
+    0xff, 0xcc, 0xf8, 0x59, 0xab, 0xa7, 0x0b, 0x17, 0x07, 0xb7, 0x22, 0xda, 0x1f, 0xf3, 0x93, 0xcc,
+    0x5b, 0xbc, 0xc0, 0x20, 0x14, 0xc0, 0xd4, 0x50, 0x06, 0x55, 0x57, 0x79, 0x46, 0xdb, 0x5f, 0x95,
+    0xef, 0x1e, 0x76, 0x57, 0xdc, 0x98, 0x40, 0x2e, 0x5c, 0xb0, 0x48, 0xdc, 0xb3, 0x72, 0xc9, 0x27,
+    0x7f, 0xda, 0x4d, 0x8f, 0x3a, 0x30, 0xc9, 0x53, 0x82, 0x24, 0x74, 0xce, 0xed, 0xa6, 0x70, 0xd5,
+    0xe6, 0x80, 0x02, 0x92, 0x59, 0x26, 0x0d, 0x91, 0xf8, 0x73, 0x7c, 0xf7, 0x57, 0x26, 0x51, 0xfb,
+    0x28, 0xa7, 0xdf, 0x46, 0xf6, 0x71, 0x67, 0x9b, 0xdd, 0x50, 0x76, 0x96, 0xb0, 0x21, 0xc2, 0xc7,
+    0xf4, 0x30, 0x0f, 0x30, 0x98, 0xff, 0x94, 0x60, 0x58, 0x2d, 0xb5, 0x8e, 0x12, 0x2c, 0x58, 0x51,
+    0x85, 0xbc, 0xd0, 0x91, 0xe7, 0xac, 0xcb, 0x60, 0x8f, 0x7e, 0x0c, 0x35, 0x58, 0x62, 0x74, 0x84,
+    0x52, 0x9a, 0x66, 0x2c, 0x05, 0x28, 0xd4, 0x19, 0x24, 0x8b, 0x65, 0x65, 0xd3, 0x2e, 0xcc, 0x78,
+    0xf7, 0x89, 0x1d, 0xb5, 0xbb, 0x19, 0x84, 0xcd, 0xe8, 0x9c, 0x1a, 0xf2, 0x5f, 0x09, 0x27, 0x20,
+    0x5e, 0x73, 0x4a, 0x7d, 0xfe, 0xb9, 0xae, 0xe9, 0x4f, 0x23, 0xf2, 0xfd, 0x11, 0xfb, 0x53, 0xec,
+    0x76, 0x8f, 0x6b, 0x82, 0x68, 0xe0, 0x0e, 0x40, 0x54, 0xcd, 0x12, 0xed, 0xe4, 0x83, 0x2b, 0x07,
+    0xa2, 0x54, 0xa4, 0xe2, 0x24, 0x18, 0x54, 0xe8, 0xff, 0x2a, 0xe1, 0xe1, 0xb2, 0x48, 0xf9, 0xeb,
+    0x1c, 0x77, 0x58, 0x1c, 0xa2, 0xa2, 0xef, 0x2d, 0x4c, 0x91, 0x71, 0x17, 0x7a, 0x1e, 0x04, 0x0f,
+    0x9d, 0x4a, 0xd8, 0xd0, 0xd0, 0xc6, 0xcd, 0x14, 0xfc, 0xd1, 0x3b, 0x23, 0x37, 0x94, 0xe5, 0x17,
+    0x04, 0xb6, 0x89, 0x0c, 0x56, 0xbc, 0xe1, 0xb8, 0xcd, 0x1c, 0x9e, 0xae, 0x6d, 0x59, 0xac, 0xd9,
+    0x1e, 0xb6, 0x7b, 0x3a, 0x61, 0x8d, 0x65, 0xf0, 0xf9, 0x4e, 0x54, 0x58, 0x27, 0x1e, 0x14, 0xdc,
+    0x6f, 0x65, 0x30, 0xad, 0x0e, 0xe8, 0xb2, 0xb2, 0xf0, 0xce, 0xc1, 0x46, 0x12, 0xe5, 0x63, 0x33,
+    0x8e, 0x24, 0x16, 0x02, 0xb9, 0x97, 0xec, 0x4e, 0x62, 0xc8, 0x39, 0x42, 0xc7, 0xf1, 0x8d, 0xad,
+    0x68, 0x41, 0xb1, 0x34, 0x8c, 0xab, 0x99, 0xa7, 0x8f, 0x59, 0x8f, 0xe7, 0x8a, 0x20, 0x20, 0x5d,
+    0x88, 0xd8, 0x26, 0xd2, 0xe1, 0x63, 0xf6, 0xb6, 0x28, 0xb2, 0x66, 0xc1, 0x87, 0xb4, 0x27, 0xf2,
+    0x53, 0x00, 0x0e, 0x4e, 0xf9, 0x9f, 0xec, 0x04, 0x94, 0xa9, 0x7d, 0x9b, 0x42, 0xe3, 0x7e, 0xe6,
+    0x13, 0x76, 0x7d, 0x26, 0x51, 0xfb, 0x7c, 0xb2, 0xb9, 0xe9, 0x95, 0x78, 0xce, 0x2d, 0x78, 0xb9,
+    0xc9, 0x77, 0x7c, 0x95, 0x4d, 0xbd, 0x1d, 0x7b, 0xe8, 0xb5, 0x68, 0xf8, 0x8a, 0xb4, 0x2d, 0xdf,
+    0xd2, 0x93, 0xbe, 0x28, 0x74, 0x71, 0x03, 0xb0, 0x52, 0xad, 0x81, 0xd8, 0xf6, 0x25, 0x4e, 0x42,
+    0x68, 0x02, 0x51, 0x65, 0x00, 0x11, 0x1a, 0xdf, 0x0a, 0x8f, 0x27, 0xae, 0x7c, 0x55, 0xd3, 0xd5,
+    0xdb, 0x86, 0x27, 0x8f, 0xaf, 0x58, 0xb6, 0x8a, 0x26, 0xd1, 0x2b, 0x28, 0x01, 0xac, 0x28, 0xed,
+    0xa8, 0x7a, 0xa5, 0xd6, 0x92, 0xed, 0xa9, 0xbe, 0x08, 0xf7, 0xcc, 0x3e, 0x78, 0x51, 0x72, 0x99,
+    0xa3, 0xfd, 0x9c, 0xe2, 0xa0, 0xa8, 0x93, 0xe1, 0x2d, 0x71, 0x06, 0x2a, 0xe2, 0x51, 0x4c, 0x46,
+    0x5d, 0x39, 0x9f, 0x16, 0x5e, 0x4d, 0x2f, 0x71, 0xd1, 0x91, 0x3d, 0x8b, 0x95, 0x39, 0x66, 0x81,
+    0x48, 0x64, 0x32, 0xb0, 0x90, 0xf0, 0xcc, 0xe8, 0x6a, 0xa8, 0x4b, 0x66, 0x1f, 0xf2, 0x2d, 0x4a,
+    0x56, 0x03, 0x5e, 0x82, 0x1a, 0x1c, 0xe3, 0x0f, 0x33, 0xaf, 0xeb, 0x6c, 0x7b, 0x8f, 0xa9, 0xce,
+};
+
+static const unsigned char test_mldsa_87_priv[] = {
+    0xf7, 0x05, 0x2f, 0xbb, 0x92, 0x17, 0x59, 0xcd, 0x87, 0x16, 0x77, 0x3b, 0xa6, 0x35, 0x56, 0x30,
+    0x12, 0x1d, 0x69, 0x27, 0x89, 0x9f, 0xdd, 0xa5, 0x76, 0x8e, 0x2b, 0xc2, 0x40, 0xfc, 0xcb, 0x7b,
+};
+static const unsigned char test_mldsa_87_pub[] = {
+    0x18, 0xdf, 0xf3, 0x92, 0xde, 0xf5, 0x75, 0x6e, 0xa2, 0x35, 0x19, 0xa2, 0x40, 0xe6, 0xb5, 0xcd,
+    0xcf, 0x91, 0x2d, 0x89, 0xcd, 0x94, 0xde, 0xc9, 0xdc, 0x71, 0xe5, 0x3f, 0x8c, 0xdf, 0x37, 0xd9,
+    0x6c, 0xaf, 0xf7, 0xeb, 0x6f, 0x18, 0x2b, 0x85, 0xbe, 0xc2, 0xf5, 0x34, 0xdc, 0xb9, 0x18, 0xab,
+    0xe8, 0x42, 0x8e, 0x34, 0x1d, 0xed, 0xf6, 0xdb, 0x71, 0xb4, 0xb8, 0x05, 0x76, 0x7b, 0x6c, 0x9f,
+    0xda, 0xe2, 0x94, 0xbe, 0x70, 0x82, 0xd3, 0x5f, 0xb6, 0x8c, 0x92, 0x65, 0x00, 0xf2, 0x87, 0x60,
+    0x2a, 0xdd, 0x34, 0xc3, 0xf9, 0x5e, 0x2d, 0x63, 0xb4, 0x89, 0x12, 0xaa, 0x47, 0x6a, 0x4e, 0xca,
+    0x07, 0x6e, 0xb0, 0x40, 0xb2, 0x60, 0x30, 0x3e, 0x41, 0x2d, 0xb2, 0x61, 0xf1, 0xd4, 0x74, 0x1e,
+    0x74, 0x22, 0x75, 0xfd, 0xe4, 0x21, 0x56, 0x12, 0x0b, 0x8b, 0xd6, 0xfe, 0x6c, 0xf4, 0xfd, 0x54,
+    0xeb, 0x22, 0x71, 0xf8, 0x46, 0x6c, 0x73, 0xb2, 0x0a, 0x7b, 0x23, 0x0c, 0xaa, 0xf7, 0x3c, 0x55,
+    0xb4, 0xf3, 0x51, 0xd4, 0xe9, 0x3a, 0x06, 0x94, 0x0a, 0x4d, 0x42, 0x77, 0xdc, 0x02, 0x54, 0xae,
+    0x82, 0x51, 0x45, 0xc2, 0xe4, 0xa0, 0x6b, 0xd3, 0x3d, 0x82, 0x24, 0x46, 0xa0, 0xdb, 0x08, 0xe0,
+    0xd1, 0x33, 0x5c, 0xb0, 0xbf, 0xb5, 0x70, 0x94, 0xce, 0x81, 0xad, 0x2b, 0x15, 0xe1, 0xf0, 0xd5,
+    0x2b, 0x8e, 0x54, 0x81, 0x70, 0xa8, 0xb4, 0x4f, 0xf9, 0xf2, 0xb8, 0x0a, 0xc8, 0x86, 0x08, 0xdf,
+    0xd8, 0x94, 0x89, 0xc1, 0x14, 0xee, 0x7c, 0x88, 0xb5, 0x2e, 0xd2, 0xaa, 0xe5, 0x72, 0x0f, 0x46,
+    0xc2, 0x32, 0x65, 0xc6, 0x7a, 0x24, 0xcb, 0xaa, 0x3c, 0xfe, 0x13, 0x58, 0xda, 0xad, 0x57, 0xd3,
+    0x4c, 0xea, 0x19, 0xb7, 0x4a, 0xaf, 0x88, 0xfa, 0xf6, 0xb1, 0x92, 0x50, 0xed, 0xb3, 0xb6, 0x6c,
+    0x6d, 0x27, 0x2f, 0xa0, 0x5f, 0x89, 0x6a, 0x47, 0x63, 0xa1, 0xd6, 0x0a, 0x5b, 0x85, 0x9b, 0x21,
+    0x45, 0x96, 0xa6, 0x71, 0xa5, 0x83, 0x2e, 0x02, 0x18, 0xc8, 0x08, 0xd2, 0x2f, 0xe2, 0xdf, 0x4a,
+    0xf8, 0x50, 0xc6, 0x38, 0xb8, 0x1a, 0x68, 0x2e, 0x68, 0x79, 0x3f, 0x3f, 0x1c, 0xa8, 0xa5, 0x26,
+    0x1d, 0x71, 0x04, 0xab, 0x34, 0x05, 0x56, 0xd6, 0x6f, 0x40, 0xd5, 0x93, 0x0a, 0xd6, 0x69, 0x94,
+    0x7e, 0x48, 0x4c, 0xb9, 0x65, 0x40, 0x3f, 0xf5, 0xe5, 0x7b, 0x93, 0x5b, 0xa2, 0x9d, 0xb5, 0xb9,
+    0x7f, 0xff, 0xf1, 0x64, 0xe9, 0x50, 0x88, 0x16, 0xe2, 0xcd, 0x81, 0x1b, 0x8a, 0xaa, 0x76, 0x83,
+    0x21, 0xfa, 0xca, 0xe3, 0xce, 0x2b, 0x2a, 0x9c, 0xff, 0xb2, 0xe4, 0xf1, 0xcb, 0x68, 0xca, 0xe2,
+    0xfd, 0x67, 0x2c, 0x31, 0x4d, 0x32, 0x7d, 0xcd, 0xf4, 0x6a, 0x91, 0xf2, 0x39, 0x29, 0xba, 0x32,
+    0x7a, 0xe8, 0xa8, 0x64, 0x6f, 0xd2, 0x02, 0x29, 0xfc, 0x5d, 0x85, 0x14, 0x94, 0x84, 0xbc, 0xc4,
+    0x73, 0xf5, 0x2d, 0x5b, 0xe9, 0xa0, 0xeb, 0xc5, 0x7e, 0x2e, 0x25, 0x2e, 0xc8, 0x95, 0xdc, 0xba,
+    0x1c, 0xd3, 0x95, 0x84, 0xcd, 0x7f, 0xc1, 0x4e, 0x96, 0x20, 0x1d, 0x90, 0x87, 0x42, 0x11, 0x55,
+    0x5c, 0x4b, 0xff, 0xd9, 0xf9, 0x06, 0x87, 0x6f, 0x3e, 0x11, 0x2c, 0xcd, 0xe0, 0x09, 0x14, 0xe3,
+    0xe4, 0x60, 0xd8, 0xe9, 0x5f, 0xdf, 0x0c, 0x65, 0xf7, 0x0c, 0x23, 0x25, 0xa1, 0xb0, 0x77, 0xdb,
+    0x3c, 0xcd, 0x64, 0xf1, 0xbe, 0xd8, 0x63, 0xa8, 0xe8, 0x2f, 0xc1, 0x22, 0x74, 0x61, 0x61, 0x69,
+    0x6c, 0xe0, 0xa3, 0x0c, 0x03, 0xe9, 0x92, 0x96, 0xdd, 0x5e, 0xd0, 0x31, 0xba, 0x79, 0x20, 0xcc,
+    0x15, 0xba, 0x35, 0x70, 0xba, 0xc1, 0xbd, 0xfe, 0x00, 0xaa, 0x60, 0xa3, 0xaf, 0xeb, 0x73, 0xfd,
+    0xfa, 0xce, 0xcf, 0x9b, 0xe1, 0xa9, 0xe1, 0x18, 0xbd, 0x64, 0x5a, 0x82, 0x1c, 0xfc, 0x3e, 0x80,
+    0xc2, 0x84, 0xca, 0x1c, 0x1e, 0xe1, 0xf7, 0xb5, 0xeb, 0xac, 0x2d, 0xac, 0xfc, 0x39, 0xd4, 0x86,
+    0xf2, 0x09, 0xf5, 0x80, 0x81, 0x81, 0x12, 0x7e, 0xc0, 0x12, 0xa4, 0x86, 0xc5, 0x21, 0xa4, 0x78,
+    0xf4, 0x78, 0xe6, 0x1b, 0x43, 0xe2, 0x8e, 0xbf, 0x5c, 0x94, 0xe4, 0xe2, 0x98, 0x27, 0xe3, 0x33,
+    0x84, 0xd3, 0x3b, 0xf6, 0xf9, 0x5e, 0x32, 0xd8, 0x24, 0xe2, 0x8d, 0x3e, 0xea, 0xd4, 0xa0, 0x73,
+    0x6c, 0xa1, 0x4c, 0x21, 0x81, 0x86, 0x65, 0xa2, 0xb7, 0x1f, 0xec, 0x36, 0xe4, 0x9f, 0xc5, 0xca,
+    0xf0, 0x58, 0xd2, 0x9c, 0x3b, 0xef, 0x04, 0x03, 0xaa, 0xa6, 0xb2, 0x8a, 0x23, 0xd9, 0x66, 0x3f,
+    0xfa, 0x8b, 0xd3, 0x66, 0x59, 0xbf, 0x2f, 0xa4, 0x35, 0x6b, 0xfa, 0x22, 0xcf, 0xd4, 0x9e, 0xe0,
+    0x45, 0x7b, 0x17, 0xbc, 0x9a, 0x67, 0xc4, 0xd6, 0x53, 0xba, 0xec, 0x1e, 0x34, 0x57, 0x51, 0xc6,
+    0x20, 0x8e, 0x5e, 0xf0, 0xad, 0xff, 0x63, 0x80, 0x44, 0xcf, 0x67, 0xab, 0xce, 0xc0, 0xb8, 0x8f,
+    0xec, 0xe6, 0xfc, 0xb0, 0x4e, 0x10, 0x16, 0x40, 0x8a, 0x70, 0xfb, 0x73, 0x4a, 0x13, 0xe1, 0x47,
+    0x14, 0xe9, 0x6a, 0xaf, 0x18, 0x21, 0x5a, 0x48, 0x31, 0xdc, 0x00, 0x9b, 0x73, 0x43, 0x83, 0x9c,
+    0x72, 0x8c, 0x9b, 0x9d, 0xab, 0xd9, 0x6f, 0x47, 0x2b, 0x3f, 0xbf, 0xf3, 0xdb, 0x4f, 0x27, 0xd8,
+    0x2e, 0xdf, 0x01, 0x47, 0x07, 0xdf, 0xd7, 0xc7, 0xe4, 0x12, 0xf7, 0x60, 0x63, 0x7d, 0xd0, 0x7c,
+    0xed, 0xff, 0xe1, 0xaa, 0x67, 0x3b, 0x8a, 0xfb, 0x6c, 0xfb, 0xc1, 0xdd, 0xa4, 0x45, 0x68, 0x63,
+    0x54, 0x53, 0x36, 0xcf, 0x22, 0x2d, 0x84, 0x33, 0x61, 0xb1, 0xec, 0x85, 0x0e, 0x20, 0x03, 0xb4,
+    0x10, 0x66, 0xa7, 0xfb, 0x79, 0x92, 0x56, 0x65, 0x3a, 0x8f, 0x46, 0x78, 0x3e, 0x4e, 0x55, 0xb6,
+    0xaa, 0xa0, 0x7b, 0x87, 0xdf, 0xc5, 0x49, 0x32, 0xa0, 0xc6, 0x4f, 0x15, 0x43, 0xa9, 0x91, 0x25,
+    0x77, 0xbf, 0x61, 0x50, 0x2d, 0x3b, 0xef, 0xff, 0x90, 0xde, 0x16, 0xb4, 0x56, 0xa4, 0x91, 0x49,
+    0xf7, 0xf0, 0xbb, 0xf4, 0xf0, 0xa3, 0x77, 0x18, 0xaa, 0x99, 0xfa, 0x48, 0x03, 0xa4, 0xa2, 0x0e,
+    0x4d, 0xc8, 0xcb, 0x39, 0x8b, 0xfc, 0x47, 0xce, 0x13, 0xda, 0xe1, 0x75, 0xb7, 0x8a, 0x6a, 0x5b,
+    0xa1, 0x82, 0x00, 0xd3, 0x5e, 0x77, 0x5a, 0x55, 0x59, 0x6e, 0x1b, 0xc0, 0xe8, 0x3f, 0x87, 0x86,
+    0x12, 0xda, 0xf3, 0xba, 0x51, 0xf0, 0xe8, 0x44, 0xaa, 0x1b, 0x5d, 0xfc, 0x85, 0x85, 0xd6, 0x93,
+    0x80, 0x0d, 0x20, 0x59, 0xc9, 0xe9, 0xb6, 0x13, 0x5e, 0x09, 0x4a, 0x9a, 0xe2, 0xae, 0x06, 0xa0,
+    0x0c, 0x43, 0xfc, 0xbe, 0x43, 0xab, 0x22, 0xa3, 0x44, 0xc6, 0xdf, 0x8c, 0x55, 0xc9, 0xbf, 0x1e,
+    0xf9, 0x9f, 0x97, 0xf6, 0xe2, 0x9a, 0x1f, 0xd0, 0xaa, 0xe7, 0xd2, 0xd1, 0x03, 0x1b, 0x57, 0x8f,
+    0xcf, 0x10, 0xe8, 0xc8, 0x31, 0xdf, 0x2d, 0x53, 0x75, 0x60, 0xb2, 0x74, 0xd4, 0xbb, 0x30, 0x5a,
+    0xa2, 0x99, 0xba, 0x64, 0xef, 0x16, 0x20, 0x83, 0xc2, 0x03, 0x41, 0xe8, 0x19, 0x16, 0xf0, 0x65,
+    0xa4, 0x83, 0xdc, 0xb9, 0xaf, 0x74, 0xac, 0x78, 0xbf, 0xc4, 0xd1, 0x9c, 0x4c, 0x42, 0xb2, 0x26,
+    0x88, 0xb1, 0x71, 0xed, 0x10, 0xab, 0xc4, 0x30, 0x09, 0xe3, 0x9e, 0x12, 0x1a, 0xfe, 0x25, 0xcb,
+    0xd1, 0x6f, 0x92, 0x9d, 0x9e, 0xb1, 0x64, 0xe0, 0xb3, 0x6f, 0x17, 0xc2, 0x86, 0xe5, 0x98, 0x7d,
+    0x80, 0xb4, 0x3a, 0x59, 0x06, 0xe3, 0x31, 0x5d, 0xd3, 0xbc, 0xbf, 0x4e, 0x52, 0x6f, 0xba, 0x9e,
+    0xf5, 0x10, 0x68, 0x37, 0x58, 0x82, 0x56, 0xe2, 0xa8, 0xf0, 0x69, 0x41, 0x1a, 0x8c, 0xbb, 0x7f,
+    0xb7, 0x10, 0x9c, 0x8e, 0x15, 0x2f, 0x81, 0xdd, 0xe2, 0x30, 0x4a, 0x11, 0xac, 0x54, 0xeb, 0xea,
+    0x1a, 0x1e, 0xb3, 0xaa, 0xa2, 0x03, 0x11, 0xfb, 0x72, 0xff, 0x9c, 0x8c, 0xb2, 0x30, 0xb4, 0x53,
+    0x48, 0xb8, 0xb0, 0x31, 0xa8, 0x1f, 0x68, 0xc2, 0xaa, 0xb8, 0x4e, 0x5f, 0x6f, 0x97, 0x70, 0x38,
+    0xbd, 0xfe, 0xdf, 0xef, 0x57, 0xe4, 0xfb, 0xfb, 0xdf, 0x30, 0xb8, 0x04, 0xed, 0x8f, 0x3a, 0xbe,
+    0xc9, 0x1e, 0xeb, 0x25, 0x2e, 0xbe, 0xc5, 0x23, 0x11, 0xc4, 0x8e, 0xa0, 0xf5, 0x9c, 0x36, 0xef,
+    0x01, 0xa1, 0x38, 0xe8, 0x6f, 0x74, 0x0c, 0x97, 0x22, 0x85, 0xd8, 0xa7, 0xfe, 0x9b, 0x81, 0x7e,
+    0x3e, 0x58, 0xa0, 0x1f, 0x5f, 0xe6, 0x0c, 0xda, 0x12, 0x47, 0xc3, 0x51, 0xad, 0x0a, 0xca, 0xa7,
+    0x65, 0x35, 0x1f, 0xc5, 0x80, 0xa8, 0x73, 0xe8, 0xab, 0xaa, 0x72, 0x86, 0x88, 0xff, 0x7c, 0x04,
+    0x48, 0x27, 0xd6, 0x00, 0xaa, 0xd3, 0x57, 0x8f, 0x6e, 0x48, 0x69, 0xfd, 0x2e, 0x2f, 0x75, 0xec,
+    0xf3, 0x8d, 0x57, 0x7e, 0x4e, 0x20, 0x11, 0xb1, 0xca, 0x14, 0xbb, 0x44, 0x8f, 0x53, 0x59, 0x6c,
+    0x5a, 0xb7, 0xe4, 0x0c, 0x42, 0xfd, 0x34, 0xf1, 0x47, 0x00, 0x2e, 0xbc, 0x57, 0x65, 0xfb, 0x5a,
+    0xe3, 0xdf, 0x9a, 0x09, 0x43, 0x36, 0xf8, 0x5c, 0xa4, 0x75, 0xff, 0xcf, 0x43, 0xb7, 0xa9, 0x98,
+    0xef, 0xc9, 0x49, 0x9d, 0x86, 0x36, 0x37, 0x5b, 0xfe, 0xab, 0x91, 0x68, 0x8b, 0x06, 0x32, 0x63,
+    0x6b, 0x69, 0x2e, 0x39, 0xad, 0x0b, 0xda, 0xbb, 0x58, 0x51, 0x33, 0x4c, 0x7a, 0xd9, 0x43, 0x96,
+    0xa1, 0x08, 0x17, 0x28, 0x4f, 0xce, 0xf3, 0x43, 0x6c, 0x93, 0x73, 0x1f, 0x92, 0xf7, 0x02, 0x1b,
+    0x27, 0x2d, 0x6b, 0x8a, 0x63, 0x1f, 0x25, 0x18, 0x60, 0xe1, 0x61, 0x67, 0x4b, 0xde, 0x79, 0xb2,
+    0x45, 0xd8, 0x6e, 0x9c, 0x9c, 0xd9, 0x94, 0x7a, 0xea, 0xcd, 0x1a, 0x2a, 0xc7, 0xb3, 0x19, 0xfe,
+    0xce, 0x34, 0x11, 0xc8, 0xc2, 0x71, 0x44, 0x27, 0x4d, 0x33, 0xce, 0xa8, 0xd1, 0xb9, 0xf2, 0x24,
+    0x11, 0xec, 0xe8, 0x25, 0x12, 0xa3, 0xab, 0xd3, 0x2d, 0x31, 0xc6, 0x78, 0x02, 0x55, 0x54, 0x15,
+    0x7f, 0x30, 0x9e, 0xad, 0x33, 0x00, 0x36, 0x0f, 0x3e, 0xe2, 0xb8, 0x73, 0xe1, 0x0a, 0xce, 0x3c,
+    0xdc, 0x36, 0xf1, 0x75, 0x49, 0x7f, 0x09, 0x5e, 0x49, 0x6e, 0xa8, 0x1e, 0x34, 0xc2, 0xc7, 0x36,
+    0x9b, 0x57, 0x22, 0x25, 0x97, 0x35, 0xe0, 0xec, 0xfe, 0x68, 0x4e, 0x87, 0x5b, 0x71, 0xc4, 0x82,
+    0x8d, 0x2a, 0x46, 0x3a, 0x27, 0x9c, 0x25, 0x52, 0x01, 0x96, 0x96, 0x82, 0x9a, 0xa6, 0x4b, 0xed,
+    0x7f, 0x4c, 0x8e, 0x24, 0x42, 0x10, 0x09, 0x01, 0x23, 0x04, 0x69, 0xa9, 0xab, 0xaa, 0xc4, 0x43,
+    0x06, 0x9b, 0x30, 0x53, 0x64, 0x05, 0xcc, 0x3c, 0x25, 0xa1, 0x19, 0x00, 0xda, 0xf7, 0x3d, 0x59,
+    0x8a, 0x13, 0x1e, 0x32, 0x9c, 0xa3, 0x5e, 0x6e, 0x7d, 0x80, 0x71, 0xdd, 0xc0, 0xa5, 0x39, 0xed,
+    0x9d, 0x7a, 0x4b, 0xbc, 0xd5, 0x12, 0x59, 0x5a, 0x93, 0x10, 0x86, 0x12, 0x8e, 0xe9, 0x38, 0x7c,
+    0x90, 0x46, 0x39, 0xdf, 0xe3, 0x80, 0x08, 0x0b, 0xcf, 0x56, 0x43, 0x8f, 0x70, 0x4f, 0x72, 0x8e,
+    0xc5, 0xfb, 0xc1, 0xd5, 0x43, 0xff, 0xe7, 0xb7, 0x6e, 0xb9, 0x49, 0x7d, 0x2f, 0xe9, 0x12, 0x43,
+    0x08, 0xcc, 0xd8, 0x29, 0x39, 0xb6, 0x6d, 0x47, 0x8e, 0x12, 0x3d, 0xab, 0x08, 0x14, 0x3b, 0xae,
+    0xc3, 0x69, 0x85, 0xb3, 0x74, 0xc5, 0xfc, 0x88, 0xf5, 0xb4, 0x1c, 0xa1, 0xab, 0x21, 0x79, 0x58,
+    0x3d, 0xe2, 0x26, 0xbc, 0xfe, 0x1b, 0xa0, 0x7f, 0x82, 0xaa, 0x38, 0x81, 0x1f, 0x38, 0x9a, 0x87,
+    0xdf, 0x71, 0x48, 0x81, 0xb5, 0x1e, 0xaf, 0x2c, 0x62, 0xe2, 0xd7, 0x7d, 0xe2, 0x4a, 0x59, 0xeb,
+    0x79, 0x35, 0x88, 0x43, 0x48, 0xa3, 0xa6, 0x1b, 0x75, 0x93, 0x8a, 0xa5, 0xe7, 0xfd, 0xb5, 0xc1,
+    0xcf, 0xfd, 0x03, 0x0e, 0xf4, 0x1a, 0x18, 0xaf, 0x91, 0xcf, 0x96, 0xd5, 0x5b, 0x23, 0x94, 0x99,
+    0x82, 0x6b, 0x39, 0x24, 0xf3, 0x1f, 0x7c, 0x7b, 0xbf, 0x74, 0x66, 0xc5, 0xf6, 0x9d, 0xbf, 0x67,
+    0xeb, 0x34, 0x4d, 0xde, 0x8e, 0x72, 0x46, 0x61, 0x0f, 0x1b, 0x73, 0x8f, 0xf7, 0x1d, 0x14, 0xda,
+    0x35, 0xb5, 0x2d, 0x86, 0x95, 0xcb, 0xe8, 0xfa, 0x33, 0x4f, 0x92, 0x43, 0x1a, 0x62, 0x9f, 0x00,
+    0x4a, 0xc4, 0xfb, 0xa9, 0x40, 0x0f, 0x24, 0x65, 0x03, 0x0f, 0x19, 0xca, 0xe0, 0xd3, 0x4e, 0xcd,
+    0x48, 0x5b, 0x14, 0x35, 0x21, 0x97, 0x0d, 0x3f, 0xb8, 0x0d, 0xcf, 0x36, 0xb1, 0xeb, 0x36, 0x94,
+    0x94, 0x6d, 0xd5, 0x7c, 0x20, 0x16, 0xe0, 0x56, 0x48, 0x75, 0x18, 0xa3, 0x03, 0x4e, 0x7c, 0x38,
+    0x7a, 0xff, 0x01, 0x32, 0x0b, 0xad, 0xc4, 0x60, 0xf6, 0xed, 0xca, 0x10, 0x98, 0xd0, 0x7a, 0x52,
+    0xa6, 0x7a, 0x73, 0xb3, 0xec, 0x39, 0x8a, 0x54, 0xab, 0x4f, 0xa8, 0xf0, 0x86, 0x2d, 0xc2, 0x3d,
+    0x69, 0x45, 0x78, 0x19, 0x43, 0xa0, 0x65, 0x1f, 0x3a, 0x03, 0x15, 0xec, 0x73, 0x49, 0xc3, 0x3a,
+    0x22, 0x93, 0x75, 0x12, 0x47, 0x4f, 0x10, 0x42, 0xd5, 0xce, 0xa6, 0x9f, 0x3a, 0x18, 0x8c, 0xe1,
+    0x0e, 0x39, 0x5e, 0x19, 0xc8, 0xa1, 0x92, 0x1e, 0x18, 0x6b, 0xc9, 0x1b, 0xa8, 0xbe, 0xa8, 0x77,
+    0x53, 0xc1, 0x56, 0x99, 0x49, 0x12, 0x96, 0xaf, 0x4d, 0xac, 0xd2, 0xd2, 0x11, 0xb3, 0xe9, 0x8a,
+    0x2c, 0xc4, 0x03, 0xf3, 0x54, 0x5a, 0x2c, 0xed, 0x56, 0x54, 0x00, 0x36, 0x4f, 0xa1, 0xf8, 0x6f,
+    0x2b, 0xf6, 0x06, 0x7a, 0x51, 0x5f, 0x2e, 0x3a, 0xb1, 0xf2, 0xdf, 0x93, 0x4f, 0x7c, 0x5e, 0x12,
+    0x68, 0x5c, 0x7d, 0x87, 0x64, 0x4d, 0xca, 0x48, 0xe6, 0xa0, 0xdd, 0x27, 0x2e, 0x97, 0x9c, 0xf3,
+    0x5e, 0x4a, 0x08, 0x29, 0xa4, 0x94, 0xec, 0x77, 0x9a, 0x9f, 0x7e, 0xef, 0x8c, 0x39, 0xfc, 0x2e,
+    0xb1, 0x01, 0xca, 0xbb, 0xda, 0x7c, 0x1e, 0xab, 0xde, 0xa9, 0x2a, 0x81, 0x8b, 0x62, 0x8d, 0x26,
+    0x5b, 0xbe, 0x4e, 0x08, 0xae, 0x11, 0x57, 0x93, 0x59, 0x68, 0x35, 0x3a, 0xdc, 0x6b, 0x87, 0xcd,
+    0x0d, 0x7c, 0xd2, 0xf9, 0xf7, 0x24, 0xcd, 0xf1, 0xfa, 0xb5, 0xa6, 0xcf, 0x0b, 0x14, 0x5d, 0x55,
+    0x98, 0x59, 0xf0, 0x5f, 0x54, 0x47, 0x7b, 0x54, 0x3d, 0x2a, 0x6b, 0xcb, 0xc2, 0x7c, 0x46, 0x09,
+    0x61, 0xa7, 0xfe, 0xf9, 0xf8, 0xa3, 0xf6, 0x61, 0xb8, 0xbb, 0x58, 0x17, 0x17, 0xce, 0xf4, 0x23,
+    0x42, 0xe4, 0xaa, 0x7d, 0x11, 0xa7, 0xcf, 0x2b, 0xfc, 0x7c, 0x0f, 0x13, 0xdc, 0xc1, 0x8f, 0x5d,
+    0x22, 0x22, 0x93, 0x5c, 0xd9, 0xe2, 0x6a, 0x28, 0xed, 0xb1, 0x3e, 0x2c, 0x34, 0xc4, 0x96, 0xb2,
+    0xd1, 0x24, 0x7a, 0x3d, 0xc7, 0xaa, 0xbb, 0x91, 0x9d, 0x23, 0x04, 0x55, 0x45, 0x66, 0x67, 0x57,
+    0x77, 0x5f, 0xad, 0x49, 0x68, 0x4e, 0xce, 0x44, 0x4c, 0x8b, 0x0a, 0x8a, 0xf1, 0xe1, 0xfd, 0xd1,
+    0x7e, 0xbe, 0xe6, 0x27, 0x04, 0x82, 0x32, 0x7c, 0xab, 0x00, 0xc3, 0x82, 0x52, 0x60, 0x28, 0xa4,
+    0x8d, 0x77, 0x03, 0x9a, 0x31, 0x47, 0x78, 0x9d, 0x32, 0x6f, 0xf4, 0x07, 0x93, 0x7b, 0x6f, 0x39,
+    0x36, 0x41, 0xbd, 0x67, 0x27, 0xf1, 0x0a, 0xfa, 0x6f, 0x52, 0x22, 0xc5, 0x02, 0xc4, 0x20, 0x35,
+    0x5c, 0xd1, 0xfd, 0x88, 0x60, 0xc6, 0xf2, 0x44, 0x59, 0xe3, 0x0f, 0xd8, 0xdb, 0x3b, 0xc0, 0x83,
+    0x03, 0x40, 0xe2, 0xbb, 0x4a, 0x70, 0x7d, 0xec, 0x0e, 0xf6, 0xff, 0x40, 0x09, 0x08, 0x85, 0x47,
+    0x4d, 0x36, 0x18, 0x88, 0x57, 0x3a, 0xb3, 0xcb, 0x9a, 0x17, 0xd3, 0xcb, 0xf8, 0x95, 0x76, 0x4f,
+    0x20, 0x2e, 0x74, 0x36, 0x9d, 0x20, 0x70, 0x55, 0xa8, 0xf4, 0xd2, 0x26, 0x2c, 0x31, 0x7e, 0x9b,
+    0x45, 0xcf, 0xab, 0xb3, 0x4a, 0x9f, 0xee, 0xc0, 0x31, 0x93, 0xd5, 0x02, 0xa9, 0x58, 0x9b, 0x6b,
+    0x01, 0x0c, 0xa2, 0xf4, 0x29, 0xfb, 0xf4, 0x37, 0x74, 0x00, 0xbe, 0xa0, 0x71, 0x42, 0x8c, 0xea,
+    0x42, 0xa3, 0xf2, 0xc0, 0xb0, 0x81, 0x73, 0xf2, 0x79, 0xee, 0x12, 0x92, 0xac, 0xea, 0x8a, 0x5c,
+    0x67, 0xf8, 0xea, 0x66, 0x92, 0xcb, 0x31, 0x2e, 0xf6, 0x66, 0x91, 0x7e, 0x01, 0xe7, 0x31, 0xb9,
+    0x43, 0xdb, 0x00, 0x2f, 0x9a, 0x89, 0xa3, 0x70, 0x99, 0xea, 0xe6, 0xc1, 0x43, 0x7b, 0xf2, 0x2d,
+    0x5e, 0xd8, 0x25, 0x74, 0xb6, 0xa9, 0x26, 0x5c, 0x6a, 0x51, 0xe4, 0xb0, 0x12, 0xb0, 0x46, 0x8b,
+    0x83, 0x39, 0xea, 0x53, 0xc0, 0x21, 0xb6, 0x70, 0xde, 0xf4, 0xec, 0x4d, 0x95, 0x5e, 0x9f, 0x09,
+    0x25, 0x0e, 0xf1, 0x79, 0x65, 0x4c, 0xc9, 0x89, 0x7c, 0x68, 0x5f, 0xde, 0x21, 0xa4, 0xb5, 0xa5,
+    0x1f, 0xf2, 0xa0, 0xf4, 0x1c, 0x6f, 0xaf, 0x96, 0x6e, 0xa2, 0xd6, 0xbc, 0xf3, 0x2b, 0x65, 0x4c,
+    0xa1, 0xfa, 0x0c, 0xd0, 0xdf, 0x62, 0xc7, 0x8b, 0x64, 0x11, 0x15, 0x15, 0x09, 0xb0, 0x19, 0xe6,
+    0x9e, 0x12, 0x4b, 0x0c, 0x07, 0x9c, 0xdf, 0x61, 0xed, 0x4e, 0x53, 0x4c, 0xdd, 0xc0, 0xa6, 0x02,
+    0x25, 0x11, 0x73, 0x12, 0xe2, 0x66, 0x96, 0x31, 0xe3, 0x53, 0xad, 0xc1, 0x89, 0x0f, 0x1e, 0x54,
+    0xa0, 0x92, 0x2e, 0x34, 0x0e, 0x86, 0x1f, 0xc6, 0xc5, 0x10, 0x37, 0x13, 0x30, 0x02, 0xeb, 0x21,
+    0x84, 0x5e, 0xac, 0xa1, 0x5a, 0xe9, 0x68, 0xe2, 0x64, 0x18, 0xb8, 0xd5, 0xa8, 0x88, 0x81, 0xd7,
+    0xb0, 0x19, 0x06, 0x86, 0x20, 0x62, 0xa8, 0x70, 0x8d, 0x1e, 0x8c, 0x10, 0xf1, 0x87, 0xc7, 0x6d,
+    0xe7, 0x8c, 0xc9, 0xfa, 0xf6, 0xd2, 0x10, 0xdc, 0x44, 0x79, 0xf3, 0xa1, 0xd2, 0x16, 0x47, 0x7d,
+    0x1a, 0x1b, 0x51, 0x79, 0x60, 0x02, 0xe5, 0x72, 0xd0, 0x1e, 0x76, 0x35, 0x80, 0xcd, 0x94, 0x25,
+    0x13, 0x8c, 0x1a, 0xee, 0x52, 0xd8, 0x47, 0x46, 0x6d, 0xd4, 0xfa, 0xfc, 0xb5, 0x9c, 0x7e, 0x57,
+    0x41, 0x5e, 0x84, 0x3e, 0xa7, 0x6b, 0xac, 0x9b, 0x4f, 0x3b, 0x2a, 0x80, 0x59, 0x7f, 0x98, 0x62,
+    0x22, 0xd3, 0x85, 0xb9, 0x9b, 0xc9, 0xf5, 0x99, 0xc5, 0xbf, 0xf0, 0x63, 0x82, 0x75, 0x48, 0x52,
+    0x38, 0xde, 0x69, 0x45, 0xf5, 0x34, 0xef, 0x4c, 0xc1, 0x3e, 0x97, 0x37, 0x9a, 0xd8, 0x93, 0x50,
+    0x56, 0x04, 0x54, 0x30, 0xa6, 0x9b, 0x78, 0x5a, 0x78, 0x78, 0xcc, 0x42, 0x5a, 0xac, 0xc8, 0x7c,
+    0x8a, 0xb3, 0x5c, 0x5a, 0xc7, 0xdd, 0x32, 0xea, 0xc3, 0x10, 0x80, 0xae, 0x99, 0xb0, 0x57, 0x4e,
+    0xa5, 0x6a, 0x2b, 0x82, 0x60, 0x59, 0x4e, 0xe3, 0x9b, 0x90, 0xc9, 0x53, 0x6c, 0x2c, 0x4f, 0x22,
+    0xdb, 0x40, 0xea, 0x71, 0x95, 0x3a, 0x30, 0xc7, 0x2c, 0x75, 0xdb, 0x52, 0x61, 0xc3, 0x75, 0xd3,
+    0xe4, 0x50, 0xba, 0x74, 0x1f, 0xd4, 0xed, 0xf0, 0xc0, 0xa0, 0xef, 0xc9, 0xd6, 0x9c, 0x7f, 0xda,
+    0xba, 0xe4, 0x73, 0xda, 0x78, 0x57, 0x57, 0x6d, 0xe9, 0x11, 0x2d, 0x60, 0xe1, 0x2a, 0xe3, 0x64,
+    0x6f, 0x94, 0x61, 0xa7, 0x03, 0x2c, 0x84, 0x4c, 0x41, 0xa3, 0x00, 0x74, 0x87, 0x4c, 0xe3, 0xab,
+    0xc7, 0x50, 0x5d, 0xe1, 0x5a, 0x16, 0x69, 0x8d, 0xa0, 0xfb, 0xc0, 0xd2, 0xad, 0x86, 0xd6, 0x4a,
+    0x8f, 0xd7, 0x68, 0x61, 0x9e, 0xe0, 0x73, 0xed, 0xa6, 0x89, 0xe2, 0x43, 0x0d, 0x9e, 0xcf, 0x3c,
+};
+
+static const unsigned char test_mlkem_512_priv[] = {
+    0xbb, 0xa3, 0xc0, 0xf5, 0xdf, 0x04, 0x4c, 0xdf, 0x4d, 0x9c, 0xaa, 0x53, 0xca, 0x15, 0xfd, 0xe2,
+    0x6f, 0x34, 0xeb, 0x35, 0x41, 0x55, 0x5c, 0xfc, 0x54, 0xca, 0x9c, 0x31, 0xb9, 0x64, 0xd0, 0xc8,
+    0x0a, 0x64, 0xfd, 0xd5, 0x1a, 0x8d, 0x91, 0xb3, 0x16, 0x6c, 0x49, 0x58, 0xa9, 0x4e, 0xfc, 0x31,
+    0x66, 0xa4, 0xf5, 0xdf, 0x68, 0x09, 0x80, 0xb8, 0x78, 0xdb, 0x83, 0x71, 0xb7, 0x62, 0x4c, 0x96,
+};
+static const unsigned char test_mlkem_512_pub[] = {
+    0x1c, 0xab, 0x32, 0xbe, 0x74, 0x9c, 0xa7, 0x61, 0x24, 0xee, 0x19, 0x90, 0x7b, 0x9c, 0xcb, 0x7f,
+    0xd3, 0x0f, 0x8b, 0x2c, 0x38, 0xdc, 0x97, 0x0e, 0x81, 0xf9, 0x95, 0x6c, 0x97, 0xa8, 0xbd, 0x3c,
+    0x6e, 0x37, 0xb0, 0x7c, 0x29, 0xe6, 0x0b, 0xb2, 0xb7, 0x5c, 0x52, 0x58, 0xb5, 0x72, 0x62, 0x6a,
+    0x85, 0x9a, 0xba, 0x89, 0xdb, 0x3a, 0xab, 0xc5, 0x71, 0x42, 0x46, 0x18, 0xb2, 0x63, 0x10, 0x27,
+    0x8b, 0x8e, 0xc4, 0xe7, 0x6e, 0xd0, 0x7a, 0x10, 0xb8, 0x64, 0xaa, 0xbf, 0x37, 0xbf, 0xc9, 0xf3,
+    0x64, 0x73, 0x10, 0x50, 0x63, 0x14, 0x21, 0xbf, 0xcb, 0x1c, 0x3b, 0x91, 0x53, 0xd4, 0x31, 0x6a,
+    0x95, 0x08, 0x91, 0x97, 0xa0, 0x27, 0xab, 0x80, 0xb3, 0x9c, 0x36, 0x2c, 0xe6, 0xd9, 0x7e, 0xff,
+    0x42, 0x22, 0x44, 0xfb, 0x81, 0xaa, 0xf6, 0x73, 0x54, 0xf0, 0x38, 0x94, 0xcc, 0x25, 0xb2, 0x70,
+    0x79, 0x39, 0xa4, 0xa0, 0x6d, 0x30, 0x2c, 0x59, 0xd1, 0x06, 0xeb, 0x74, 0x36, 0x78, 0xda, 0xa3,
+    0xf1, 0xd1, 0xc3, 0xf4, 0x6b, 0x03, 0xf0, 0xda, 0xa0, 0x64, 0x18, 0x35, 0xa5, 0x48, 0x36, 0x31,
+    0x80, 0x74, 0x4e, 0x6b, 0x62, 0x35, 0xb8, 0x4d, 0xb9, 0xa4, 0x62, 0x82, 0x79, 0xa6, 0xef, 0x72,
+    0x31, 0x49, 0x92, 0x08, 0xe6, 0x57, 0xa3, 0xf9, 0xbb, 0x6e, 0x3f, 0x78, 0x26, 0x06, 0xb7, 0x9f,
+    0xc9, 0xa3, 0x87, 0x23, 0x57, 0x6f, 0xa8, 0x08, 0x98, 0xe8, 0xa6, 0x88, 0x7d, 0x94, 0xc3, 0xed,
+    0x77, 0x4e, 0x46, 0xa8, 0x6c, 0xfe, 0x70, 0x5b, 0x34, 0xc6, 0xb5, 0x53, 0x58, 0x65, 0x32, 0x9c,
+    0x5a, 0x4a, 0x82, 0x0f, 0x91, 0x14, 0xce, 0x9a, 0x9c, 0x68, 0x49, 0x5c, 0x72, 0x63, 0x68, 0xb9,
+    0xe0, 0x73, 0xcb, 0xbe, 0x62, 0x7a, 0x7d, 0xe4, 0x19, 0xf7, 0xf7, 0xb4, 0xad, 0x22, 0x15, 0x76,
+    0xf9, 0x1f, 0xb1, 0xe6, 0x6c, 0xff, 0x96, 0x51, 0xbd, 0x6c, 0x25, 0xe3, 0xcc, 0x9c, 0xa4, 0x9a,
+    0x57, 0x0c, 0xf0, 0x41, 0xe4, 0x57, 0x65, 0x80, 0x72, 0xb6, 0x84, 0xe7, 0x14, 0xbd, 0x6a, 0x86,
+    0xb3, 0xd0, 0x5c, 0x75, 0x97, 0xa7, 0x29, 0xe1, 0x2e, 0x51, 0x2c, 0x8d, 0x7e, 0x5b, 0x5c, 0x27,
+    0x04, 0x9e, 0xfb, 0x0a, 0xc0, 0xe0, 0x85, 0xb1, 0xb8, 0x83, 0x47, 0xbf, 0xd3, 0x14, 0xb4, 0xe4,
+    0xab, 0x4b, 0x88, 0x75, 0xa4, 0x89, 0xad, 0xb8, 0xc9, 0xae, 0x28, 0x00, 0x8b, 0xad, 0x36, 0xaa,
+    0xad, 0x24, 0x68, 0x35, 0x63, 0xbf, 0xaf, 0x19, 0xbd, 0xa8, 0x67, 0x7a, 0xb7, 0xba, 0xc7, 0xe3,
+    0x3c, 0x30, 0x87, 0xb8, 0x4a, 0x45, 0x24, 0x6a, 0x2a, 0xb1, 0xae, 0xf3, 0x97, 0x75, 0x0d, 0x38,
+    0x6a, 0xcd, 0xac, 0x63, 0xc8, 0x75, 0x06, 0x16, 0x6a, 0x0f, 0xae, 0x18, 0x77, 0x3f, 0x53, 0x0e,
+    0x74, 0x54, 0x5d, 0x54, 0xbc, 0x67, 0x0d, 0xd7, 0x35, 0x3b, 0x75, 0xb1, 0x63, 0x73, 0xcb, 0x8a,
+    0x62, 0x69, 0xaf, 0x37, 0x09, 0x7e, 0xe1, 0xb1, 0x64, 0x04, 0x58, 0x15, 0x31, 0x32, 0xad, 0x80,
+    0xab, 0x64, 0xf7, 0xa5, 0x99, 0xb8, 0x67, 0x0e, 0x30, 0x12, 0x05, 0x04, 0x3c, 0x13, 0x6c, 0x56,
+    0xca, 0x5a, 0x06, 0xdb, 0xfa, 0xba, 0x32, 0x04, 0x67, 0x1c, 0x1b, 0x23, 0x7b, 0x18, 0x82, 0x45,
+    0x55, 0xb5, 0xdd, 0xb2, 0x06, 0xa7, 0x4a, 0xce, 0x63, 0x70, 0x05, 0xb3, 0x63, 0x23, 0x83, 0x78,
+    0xbd, 0xa5, 0xe1, 0x98, 0xad, 0x69, 0xb8, 0x5c, 0xbb, 0x39, 0x9e, 0x8b, 0x07, 0xcb, 0x89, 0x9f,
+    0x9e, 0x93, 0xcf, 0x6c, 0xf6, 0x2f, 0xca, 0xfc, 0x9e, 0x4d, 0x77, 0x36, 0x3c, 0xa2, 0x14, 0x9e,
+    0x92, 0x19, 0x7f, 0x21, 0x33, 0x22, 0x37, 0x99, 0xc1, 0x82, 0xcf, 0x5f, 0x18, 0x2e, 0xcd, 0x35,
+    0xb5, 0xfd, 0xfc, 0xbf, 0x0a, 0x93, 0xa1, 0x35, 0x01, 0x98, 0xf2, 0xf2, 0x44, 0xf3, 0x21, 0x6b,
+    0x44, 0x2a, 0x22, 0xfd, 0xdb, 0x2f, 0x4f, 0x3b, 0xb8, 0xcb, 0xf0, 0x16, 0x8d, 0x02, 0x20, 0xaa,
+    0x72, 0x5a, 0x0e, 0x28, 0x7d, 0xf0, 0x80, 0x79, 0xa1, 0xdb, 0xb8, 0x74, 0x7c, 0x02, 0xf0, 0xc2,
+    0xc8, 0x29, 0x75, 0x9a, 0x5d, 0x95, 0xb6, 0x23, 0x75, 0x22, 0xe7, 0xf7, 0x1a, 0xb5, 0x66, 0x93,
+    0x90, 0x37, 0x7e, 0x03, 0xa9, 0x3a, 0xb7, 0xfc, 0x7e, 0x9f, 0xd6, 0xbb, 0x59, 0xc1, 0xb9, 0xb8,
+    0xcc, 0x96, 0x61, 0x41, 0xb0, 0xba, 0x67, 0x96, 0xe6, 0x68, 0x29, 0xd6, 0xa4, 0x03, 0xb1, 0xf5,
+    0x81, 0x6c, 0x85, 0x57, 0xee, 0x88, 0x41, 0x03, 0x1b, 0x2e, 0xd6, 0xc6, 0xcc, 0xfe, 0x8a, 0x55,
+    0xb3, 0x9b, 0x92, 0x73, 0xf8, 0xba, 0x05, 0x0b, 0x1b, 0x32, 0x8c, 0x7b, 0x9a, 0x23, 0x8a, 0x7b,
+    0x83, 0x24, 0xf1, 0x6a, 0x7a, 0x47, 0x4c, 0x0b, 0x57, 0x21, 0xb9, 0xc8, 0x24, 0x65, 0x31, 0xe1,
+    0x92, 0x08, 0x83, 0x83, 0x56, 0xf3, 0x33, 0x77, 0x68, 0xbc, 0xb3, 0x39, 0x7b, 0x4e, 0x01, 0xcc,
+    0x26, 0x17, 0x5b, 0x67, 0xa6, 0x6d, 0xfc, 0xd1, 0x1f, 0x07, 0xb2, 0x95, 0xc2, 0x0a, 0xb4, 0x84,
+    0xa6, 0x0e, 0x7d, 0x08, 0x6d, 0xb3, 0x9b, 0x83, 0x01, 0x84, 0x5b, 0x65, 0x4a, 0x48, 0x44, 0x62,
+    0x50, 0x8f, 0xa7, 0x85, 0x06, 0x35, 0x7b, 0xbb, 0xf4, 0x2d, 0xba, 0xc1, 0x57, 0xbc, 0xa7, 0x76,
+    0x9c, 0x09, 0x9a, 0x0b, 0x18, 0x94, 0xd4, 0xa1, 0x72, 0x56, 0xf5, 0x04, 0xeb, 0xe5, 0x0b, 0xe2,
+    0x84, 0x65, 0x6f, 0x65, 0x38, 0x45, 0xa2, 0x6b, 0x00, 0x85, 0x6d, 0x76, 0xa8, 0xa5, 0xa1, 0x66,
+    0xcd, 0x09, 0xd0, 0x47, 0x05, 0x26, 0x1e, 0xba, 0xfa, 0x20, 0x68, 0x7a, 0x10, 0x68, 0xd9, 0xb9,
+    0xe2, 0x83, 0x26, 0x84, 0x8b, 0x67, 0xa0, 0xa3, 0x99, 0x4d, 0x2d, 0xba, 0x4b, 0x7a, 0x8f, 0x62,
+    0x3b, 0x90, 0x1e, 0x17, 0xcb, 0xee, 0x61, 0x08, 0x47, 0xa2, 0x90, 0x33, 0x01, 0xc5, 0x82, 0x87,
+};
+
+static const unsigned char test_mlkem_768_priv[] = {
+    0xa2, 0xb4, 0xbc, 0xa3, 0x15, 0xa6, 0xea, 0x46, 0x00, 0xb4, 0xa3, 0x16, 0xe0, 0x9a, 0x25, 0x78,
+    0xaa, 0x1e, 0x8b, 0xce, 0x91, 0x9c, 0x8d, 0xf3, 0xa9, 0x6c, 0x71, 0xc8, 0x43, 0xf5, 0xb3, 0x8b,
+    0xd6, 0xbf, 0x05, 0x5c, 0xb7, 0xb3, 0x75, 0xe3, 0x27, 0x1e, 0xd1, 0x31, 0xf1, 0xba, 0x31, 0xf8,
+    0x3f, 0xef, 0x53, 0x3a, 0x23, 0x98, 0x78, 0xa7, 0x10, 0x74, 0x57, 0x8b, 0x89, 0x12, 0x65, 0xd1,
+};
+static const unsigned char test_mlkem_768_pub[] = {
+    0x52, 0x19, 0xc4, 0xcc, 0x17, 0xc3, 0x5a, 0x82, 0x8f, 0x3e, 0x21, 0xb2, 0xab, 0x74, 0x96, 0x80,
+    0x5c, 0x99, 0xee, 0x04, 0x1f, 0xca, 0x01, 0x58, 0xa3, 0x31, 0x4f, 0x07, 0xd0, 0x53, 0xf3, 0x64,
+    0xc8, 0x87, 0xa6, 0x82, 0x59, 0x58, 0xa6, 0x25, 0x96, 0x5d, 0x48, 0x85, 0xc2, 0xcb, 0x35, 0x5e,
+    0x83, 0xa3, 0xc1, 0xbb, 0xb1, 0x54, 0x46, 0xf8, 0x91, 0xd2, 0xd2, 0x4f, 0x14, 0x56, 0x32, 0xcf,
+    0x06, 0xa5, 0xee, 0x1a, 0x27, 0x8c, 0xd3, 0x06, 0x4a, 0x79, 0xad, 0x53, 0x19, 0x38, 0x53, 0xe4,
+    0xce, 0xa6, 0x54, 0x44, 0x8a, 0x42, 0x97, 0xce, 0xa3, 0xc9, 0xe8, 0x75, 0x61, 0x62, 0x96, 0x80,
+    0xf5, 0x88, 0x95, 0x3b, 0x85, 0x80, 0x74, 0x29, 0x2e, 0xd3, 0x1c, 0x20, 0xdd, 0xd9, 0x83, 0xe8,
+    0x05, 0xd0, 0x7b, 0xb9, 0xcf, 0xad, 0xd8, 0x23, 0xc7, 0x90, 0x0b, 0x60, 0x42, 0x86, 0xc0, 0x18,
+    0x47, 0x38, 0xca, 0x04, 0xe0, 0xda, 0x82, 0x89, 0x54, 0x0e, 0x32, 0x96, 0x05, 0xef, 0xaa, 0x59,
+    0x60, 0xaa, 0xc0, 0xfd, 0x07, 0x60, 0x00, 0x6c, 0x1f, 0x19, 0x93, 0x42, 0x6c, 0xc7, 0xbe, 0xa2,
+    0x2b, 0xcb, 0xb3, 0xcc, 0x02, 0xe0, 0x99, 0xb8, 0x28, 0xe8, 0x2f, 0x94, 0x04, 0x5d, 0xfa, 0xcb,
+    0x1d, 0x9f, 0xb3, 0x15, 0x58, 0x2b, 0x20, 0xd1, 0xb4, 0x14, 0x76, 0xfc, 0x43, 0xac, 0x46, 0x80,
+    0x64, 0x72, 0x59, 0xfe, 0x9b, 0x51, 0x37, 0x12, 0x23, 0x44, 0x6c, 0x82, 0xe0, 0xbb, 0xae, 0xa1,
+    0x32, 0x91, 0x3e, 0x2b, 0x96, 0xea, 0x11, 0x95, 0x0c, 0x45, 0x0f, 0x25, 0x85, 0x4e, 0xe4, 0xfa,
+    0x49, 0x21, 0x19, 0x3c, 0x8f, 0x1c, 0x66, 0xd6, 0x1b, 0x82, 0x65, 0xc7, 0x07, 0x2b, 0x04, 0x6f,
+    0x0c, 0x53, 0x21, 0x41, 0xd5, 0x1d, 0x99, 0x19, 0xc8, 0x07, 0x33, 0xc1, 0xbd, 0x3c, 0x5a, 0x6d,
+    0x77, 0xcc, 0xb3, 0xa1, 0x93, 0x8c, 0x95, 0xc1, 0xe4, 0xe8, 0x66, 0xd1, 0xd6, 0x5c, 0x78, 0x29,
+    0x7b, 0x3b, 0x32, 0xca, 0x3c, 0x41, 0x43, 0xe6, 0xa2, 0x15, 0xc6, 0x09, 0xa3, 0x6a, 0x1b, 0x13,
+    0xba, 0xa1, 0x79, 0x81, 0xd4, 0x2b, 0x7f, 0xf4, 0xc7, 0x15, 0xac, 0x80, 0x6d, 0xc4, 0x91, 0x56,
+    0x00, 0x32, 0xa5, 0xa2, 0xbb, 0x30, 0xe4, 0x76, 0xa2, 0x66, 0xc6, 0xe4, 0xa4, 0xa0, 0x65, 0xd9,
+    0x69, 0x8d, 0xb0, 0x81, 0x32, 0x60, 0x81, 0x36, 0x08, 0x26, 0x89, 0xb1, 0xb6, 0x48, 0xb4, 0x90,
+    0x63, 0xc9, 0x83, 0x24, 0x70, 0x6a, 0x43, 0x87, 0x65, 0x07, 0xfc, 0x69, 0x08, 0x93, 0x90, 0x0f,
+    0x81, 0x66, 0xe1, 0xd5, 0x2a, 0xdc, 0xc4, 0x48, 0x48, 0xd8, 0x64, 0xb8, 0xba, 0x09, 0x33, 0xb3,
+    0x2d, 0xaa, 0x63, 0x43, 0x5f, 0x11, 0x06, 0x59, 0x15, 0xc5, 0xd5, 0xd8, 0x79, 0xed, 0xcc, 0x13,
+    0x6f, 0xa8, 0x51, 0x5b, 0x02, 0x60, 0xb9, 0x53, 0x6c, 0x31, 0x61, 0x20, 0xb4, 0x90, 0x49, 0x21,
+    0x80, 0x55, 0x21, 0xc0, 0x23, 0x2d, 0xa1, 0x26, 0xe2, 0xa9, 0xc5, 0x32, 0x39, 0x76, 0xab, 0xc7,
+    0x3b, 0x5a, 0xb8, 0x92, 0xe5, 0x9b, 0x01, 0xa1, 0x94, 0xb6, 0x44, 0x6c, 0x1b, 0x73, 0x21, 0x7f,
+    0xbb, 0xa8, 0x55, 0xac, 0x88, 0x7a, 0xfa, 0x58, 0xa8, 0xf1, 0x5a, 0x76, 0x8e, 0xf9, 0x68, 0xd7,
+    0x75, 0x26, 0x7e, 0x05, 0x01, 0x50, 0xc7, 0xa8, 0x23, 0x7c, 0x10, 0x24, 0xf9, 0x42, 0x1c, 0x21,
+    0x0d, 0x97, 0x90, 0x7b, 0x2a, 0x14, 0x47, 0x36, 0xe3, 0xb5, 0x8e, 0x01, 0xc4, 0x89, 0x47, 0xb1,
+    0xc6, 0x26, 0x55, 0xe3, 0x80, 0x25, 0x64, 0x91, 0xce, 0xbe, 0x40, 0x0f, 0x52, 0x49, 0x3d, 0x90,
+    0x33, 0xa2, 0x9d, 0x6c, 0x9a, 0xe8, 0x0b, 0x33, 0xe8, 0xc3, 0x85, 0x84, 0xb3, 0x0a, 0x31, 0xa3,
+    0x7b, 0x15, 0xe8, 0x5f, 0x5e, 0x82, 0xb7, 0x31, 0x57, 0x40, 0x8a, 0x53, 0x99, 0xa9, 0x57, 0x19,
+    0x0c, 0xba, 0x90, 0x5f, 0x17, 0x13, 0xc9, 0xac, 0xa5, 0x3a, 0xa3, 0x29, 0x23, 0xca, 0xcb, 0x82,
+    0x69, 0x43, 0x6a, 0x56, 0xbc, 0x02, 0x93, 0x21, 0x89, 0xc7, 0x13, 0x9d, 0x84, 0x63, 0xd0, 0xdc,
+    0x54, 0x06, 0x21, 0x87, 0x5e, 0x9a, 0x7d, 0xfe, 0xf0, 0x20, 0xe7, 0xe8, 0x36, 0x96, 0xc7, 0x61,
+    0x2b, 0xc2, 0xa7, 0xde, 0x71, 0x48, 0xd7, 0x07, 0x5c, 0x31, 0xf2, 0x57, 0x76, 0x63, 0x01, 0xfa,
+    0x5a, 0x06, 0xe0, 0x05, 0x82, 0xdc, 0xe1, 0x5c, 0x6f, 0xb3, 0x19, 0x5a, 0xf4, 0x30, 0x78, 0xd7,
+    0x9b, 0x11, 0x0b, 0x5d, 0xc0, 0x78, 0x9b, 0xe3, 0xa3, 0x21, 0x32, 0x73, 0x7f, 0xeb, 0x24, 0x7d,
+    0xf8, 0xd2, 0x21, 0x6f, 0x27, 0x2c, 0x3d, 0x5b, 0xa7, 0x00, 0xc5, 0x2e, 0xd7, 0xe3, 0xa2, 0x79,
+    0x5c, 0xcf, 0xe3, 0x07, 0x2c, 0xd1, 0xd1, 0xb5, 0x33, 0x93, 0x9a, 0xc5, 0x8a, 0x06, 0x5a, 0x8a,
+    0x9f, 0xe8, 0x54, 0x41, 0xed, 0x29, 0x1d, 0x43, 0x86, 0x9e, 0x25, 0x30, 0x77, 0x37, 0xa5, 0x15,
+    0x5a, 0x09, 0x5c, 0x50, 0x56, 0xa2, 0x04, 0x32, 0x6f, 0x94, 0x4a, 0x9f, 0xc8, 0xf7, 0x03, 0x5c,
+    0x93, 0x1a, 0x61, 0x03, 0x3c, 0xc2, 0xdb, 0x6e, 0xce, 0xc0, 0x8a, 0xae, 0x00, 0x45, 0xa6, 0x54,
+    0x20, 0x80, 0xc1, 0xa7, 0xbb, 0xd6, 0x99, 0x90, 0x2a, 0x2e, 0xcb, 0xe3, 0xa1, 0xf9, 0xaa, 0x95,
+    0xfc, 0x62, 0x22, 0xc6, 0xc6, 0xab, 0x7b, 0xf9, 0x6e, 0xdb, 0x34, 0x50, 0xe0, 0x29, 0xb0, 0xce,
+    0x10, 0x4d, 0xbb, 0xfa, 0x0a, 0x49, 0xb8, 0x04, 0x4e, 0xe1, 0xbb, 0x63, 0xb3, 0x3b, 0xcf, 0xaa,
+    0x8a, 0x6a, 0x45, 0x01, 0x94, 0xcc, 0x57, 0x7d, 0x49, 0x0a, 0x54, 0x9b, 0x6c, 0x42, 0xd6, 0x81,
+    0x6f, 0x44, 0x4a, 0xae, 0x8b, 0x8a, 0x4f, 0x62, 0xaf, 0xfd, 0x17, 0x66, 0x4e, 0x95, 0x7e, 0x2b,
+    0xa2, 0x45, 0xa8, 0x64, 0xba, 0xb8, 0xd2, 0x8e, 0x82, 0xca, 0xb9, 0xfa, 0xc3, 0xbc, 0xd7, 0x07,
+    0xaa, 0xc1, 0x9a, 0x5e, 0xe5, 0x8a, 0x39, 0x25, 0xdc, 0x70, 0x59, 0xba, 0x1b, 0x9e, 0x7a, 0x79,
+    0x8e, 0xc9, 0x87, 0xe1, 0x92, 0x43, 0x42, 0xc5, 0x4e, 0x5d, 0x93, 0x5a, 0x66, 0x99, 0xb6, 0xd9,
+    0xaa, 0x78, 0xe4, 0x73, 0x8b, 0x0c, 0xec, 0x6c, 0x57, 0xd8, 0x22, 0x8c, 0x86, 0x88, 0x1a, 0x14,
+    0xa3, 0xb5, 0x70, 0x65, 0xbb, 0xe5, 0x65, 0x3b, 0xd9, 0x2b, 0x5b, 0xd5, 0xa9, 0x88, 0x8b, 0x1b,
+    0x1e, 0x9b, 0x01, 0x7e, 0xca, 0x1a, 0x78, 0x8c, 0xbc, 0x3a, 0x28, 0x3a, 0x9f, 0x7b, 0x00, 0xd3,
+    0xf5, 0x5b, 0x13, 0x8c, 0xa2, 0x6c, 0x33, 0xcd, 0x2c, 0xa3, 0xba, 0x63, 0x2a, 0x07, 0x35, 0x59,
+    0x61, 0x62, 0xaa, 0x6c, 0x9d, 0x10, 0x96, 0x8f, 0x53, 0x30, 0x5d, 0x35, 0xce, 0xc4, 0x39, 0x5c,
+    0xa0, 0x48, 0x9f, 0xf6, 0x31, 0xa3, 0xef, 0x66, 0x12, 0x64, 0xa2, 0x2a, 0xcb, 0x53, 0x5d, 0xcc,
+    0x13, 0x13, 0xcd, 0x69, 0x17, 0xbf, 0xe3, 0xb5, 0xb8, 0xfc, 0x3b, 0x80, 0x16, 0xca, 0x0d, 0xfb,
+    0x15, 0x16, 0x23, 0xc9, 0x2f, 0x95, 0x70, 0x1d, 0xcc, 0x41, 0x40, 0x45, 0x9b, 0x52, 0xeb, 0x79,
+    0x6f, 0xda, 0x60, 0xfb, 0x42, 0x96, 0x51, 0x05, 0x2d, 0x2c, 0x16, 0xb5, 0x50, 0xfa, 0x03, 0x5c,
+    0xc1, 0x37, 0x4c, 0x87, 0xa4, 0x39, 0x07, 0x77, 0x13, 0x76, 0x9c, 0x72, 0x8b, 0x76, 0x6b, 0xc7,
+    0x5a, 0x60, 0x9b, 0x70, 0xbb, 0xc1, 0x4a, 0xf8, 0x4a, 0x3c, 0x70, 0x51, 0x9c, 0x32, 0x11, 0xac,
+    0xad, 0x58, 0xbf, 0x7c, 0x14, 0xc1, 0x5f, 0x1a, 0xa8, 0x6f, 0xcc, 0x1d, 0xf5, 0x55, 0x80, 0xa2,
+    0xf9, 0xbb, 0xbc, 0x31, 0xb6, 0xb0, 0xea, 0xab, 0x37, 0x94, 0x81, 0xce, 0x99, 0x66, 0xf7, 0xfa,
+    0x64, 0x87, 0xc6, 0x11, 0xba, 0x5b, 0x3e, 0x8f, 0x83, 0x07, 0xfa, 0x35, 0xcd, 0x52, 0x48, 0xc8,
+    0xab, 0x35, 0x1b, 0x63, 0xab, 0xc4, 0xba, 0x00, 0x58, 0x71, 0xa9, 0x77, 0x51, 0xf0, 0x1e, 0x51,
+    0x43, 0x30, 0x2c, 0x75, 0x7a, 0x65, 0xe4, 0x11, 0xaf, 0x7b, 0x26, 0xf2, 0x20, 0x76, 0xc7, 0xa1,
+    0xcf, 0x7e, 0x2b, 0x00, 0x55, 0xe8, 0x0d, 0x71, 0x16, 0xca, 0x2b, 0x30, 0x56, 0xbf, 0x87, 0x54,
+    0xbc, 0xfa, 0x90, 0x95, 0xd0, 0xce, 0x99, 0x71, 0x5c, 0xc4, 0x51, 0x2f, 0x10, 0x12, 0x5c, 0x5a,
+    0x50, 0x0d, 0xab, 0xb7, 0xc1, 0x1f, 0x5b, 0x04, 0x08, 0x37, 0x79, 0x00, 0x62, 0x1b, 0xe8, 0x51,
+    0xb7, 0xa3, 0x60, 0x25, 0x76, 0x65, 0x0b, 0x84, 0x19, 0x17, 0x49, 0xf3, 0x0a, 0xc6, 0x35, 0xa9,
+    0xe2, 0x21, 0x24, 0x00, 0x76, 0x9d, 0xe8, 0xe1, 0x91, 0x5f, 0x26, 0xba, 0x19, 0x8a, 0xf8, 0xe5,
+    0x3d, 0xac, 0xb5, 0x98, 0x71, 0x17, 0x38, 0xda, 0x8c, 0x58, 0x3a, 0x38, 0x8e, 0x02, 0x7a, 0x59,
+};
+
+static const unsigned char test_mlkem_1024_priv[] = {
+    0x2b, 0x53, 0x30, 0xc4, 0xf2, 0x3b, 0xfd, 0xfd, 0x5c, 0x31, 0xf0, 0x50, 0xba, 0x3b, 0x38, 0x23,
+    0x53, 0x24, 0xbf, 0x03, 0x23, 0x72, 0xfc, 0x12, 0xd0, 0x4d, 0xd0, 0x89, 0x20, 0xf0, 0xbd, 0x59,
+    0x0a, 0x06, 0x4d, 0x6c, 0x06, 0xce, 0xab, 0x73, 0xe5, 0x9c, 0xfc, 0xa9, 0xff, 0x64, 0x02, 0x25,
+    0x5a, 0x32, 0x6a, 0xef, 0x1e, 0x9c, 0xb6, 0x78, 0xbf, 0x36, 0x92, 0x9d, 0xaf, 0xe2, 0x9a, 0x58,
+};
+static const unsigned char test_mlkem_1024_pub[] = {
+    0xb2, 0x41, 0x74, 0xa5, 0xb0, 0x0d, 0xbf, 0x52, 0x0c, 0xb9, 0xe3, 0x78, 0x3d, 0x48, 0x2e, 0x03,
+    0xca, 0x31, 0x66, 0xd4, 0x0d, 0x08, 0x2a, 0x7b, 0xab, 0x66, 0x48, 0x45, 0xb6, 0x17, 0xad, 0xd9,
+    0x8c, 0x07, 0xc6, 0xa3, 0xc3, 0x20, 0x4f, 0x81, 0x20, 0x35, 0x68, 0x3a, 0x1d, 0x4f, 0x10, 0xac,
+    0x1d, 0xe7, 0x64, 0x70, 0x6c, 0xce, 0x96, 0xd7, 0x58, 0x32, 0xa4, 0x62, 0xa8, 0xb1, 0xb8, 0x2c,
+    0xf4, 0x71, 0xcb, 0xf8, 0x08, 0xa2, 0x65, 0x08, 0xd9, 0xfa, 0xa5, 0x43, 0xf2, 0xcd, 0x98, 0x03,
+    0x77, 0xd6, 0xf7, 0x94, 0x36, 0x79, 0x38, 0x06, 0x4b, 0x6d, 0xd3, 0x88, 0xc5, 0x29, 0x75, 0x69,
+    0x63, 0xb1, 0x2c, 0xa5, 0x94, 0xb3, 0x06, 0xab, 0x3f, 0x0e, 0xbb, 0xb6, 0xed, 0x47, 0x60, 0x1a,
+    0xec, 0x10, 0x74, 0xa2, 0xb0, 0xd1, 0xb4, 0x17, 0x17, 0xf8, 0xc6, 0x95, 0xf1, 0x74, 0xef, 0x73,
+    0x40, 0x52, 0x07, 0x7e, 0x53, 0xdc, 0x9f, 0x47, 0x31, 0x6b, 0x66, 0x08, 0xb7, 0xed, 0xb5, 0x4e,
+    0xa3, 0x63, 0x1a, 0x36, 0xbb, 0x8d, 0x84, 0x2c, 0xaf, 0x27, 0x36, 0x7c, 0x15, 0xc1, 0x8d, 0xdb,
+    0xa7, 0xaf, 0xe6, 0x2a, 0xa5, 0x72, 0x13, 0x33, 0x84, 0xcb, 0x87, 0x25, 0x55, 0x94, 0x8a, 0x16,
+    0x5f, 0x20, 0x4c, 0x2c, 0xb4, 0x50, 0x3c, 0x9d, 0x8a, 0xce, 0x5f, 0x52, 0x17, 0x19, 0x4a, 0x67,
+    0xeb, 0xd2, 0xa7, 0x2f, 0x99, 0x56, 0x2f, 0x98, 0xb2, 0xb7, 0x73, 0xb6, 0x96, 0x5c, 0x07, 0x1b,
+    0xf1, 0x1d, 0xee, 0xd3, 0x95, 0xbc, 0x15, 0x3e, 0xd6, 0x96, 0x74, 0x92, 0xd8, 0x8d, 0x5e, 0xf3,
+    0x2d, 0x05, 0xe0, 0x08, 0xb7, 0x95, 0x8a, 0x2f, 0x36, 0xb9, 0xdb, 0x06, 0xcc, 0xdc, 0x52, 0xa6,
+    0x26, 0x41, 0x79, 0x66, 0xb1, 0x9c, 0x50, 0x79, 0xa9, 0x89, 0x2b, 0xa4, 0x26, 0xa0, 0x36, 0x2f,
+    0xb1, 0x8e, 0x7e, 0xc0, 0x7f, 0xfd, 0xc0, 0xc5, 0xdb, 0xe2, 0x64, 0xde, 0xec, 0x41, 0xbc, 0x83,
+    0xa5, 0x73, 0x59, 0x9a, 0x25, 0xa8, 0x90, 0x9b, 0x24, 0x76, 0x68, 0x23, 0x36, 0xce, 0xc9, 0xa3,
+    0x96, 0x20, 0x1a, 0x00, 0x0a, 0x9c, 0x1b, 0xe7, 0x92, 0xd9, 0x98, 0x8f, 0xbc, 0x03, 0xc2, 0x48,
+    0x55, 0xc1, 0xb2, 0x42, 0xae, 0x27, 0xa1, 0x27, 0xcd, 0x36, 0x41, 0x5c, 0xfb, 0x0d, 0x98, 0xcc,
+    0xbb, 0x9b, 0xd8, 0x3a, 0xf5, 0x98, 0x8d, 0x74, 0x37, 0x73, 0xac, 0xea, 0x42, 0x01, 0xac, 0x93,
+    0x5e, 0x7c, 0xcc, 0x46, 0xe9, 0x2d, 0x8e, 0x84, 0xa9, 0xd7, 0x0c, 0xc6, 0x26, 0x96, 0x54, 0x29,
+    0x45, 0x09, 0x80, 0xe0, 0x78, 0x2e, 0xe1, 0x1c, 0xd9, 0x11, 0x69, 0xce, 0x94, 0xbf, 0x89, 0xc1,
+    0x4e, 0xc1, 0x0b, 0x90, 0x0e, 0xb4, 0xb7, 0x71, 0x29, 0xa8, 0x59, 0x03, 0x9a, 0xd1, 0x25, 0x3e,
+    0x56, 0x57, 0xb2, 0x61, 0xe9, 0x85, 0x5b, 0xc4, 0xb0, 0xf5, 0x04, 0xc4, 0x78, 0xd5, 0x8f, 0x4a,
+    0x38, 0x82, 0x15, 0xa0, 0x71, 0x51, 0x68, 0x10, 0x95, 0x26, 0xc2, 0xda, 0xc5, 0x55, 0x00, 0x7c,
+    0x66, 0xe1, 0x0b, 0x79, 0xeb, 0x92, 0x47, 0x1a, 0xcc, 0x9a, 0x64, 0x08, 0x05, 0xbd, 0x94, 0x7e,
+    0xea, 0x45, 0xb6, 0x6a, 0x2c, 0x02, 0xd5, 0xb7, 0xc9, 0x02, 0x99, 0x45, 0xb5, 0x81, 0x66, 0x6d,
+    0x47, 0x0c, 0xd2, 0x65, 0x4e, 0xb5, 0x1c, 0x33, 0x04, 0xac, 0x52, 0xcb, 0x11, 0x38, 0x2b, 0x86,
+    0x28, 0x55, 0x3b, 0x63, 0x74, 0x2c, 0x41, 0xb2, 0x93, 0x46, 0x7b, 0x75, 0x4d, 0xf8, 0xf5, 0x2a,
+    0x7b, 0x9a, 0x5e, 0xf2, 0x35, 0x9b, 0xf3, 0x40, 0x25, 0xa9, 0x31, 0x8d, 0xf9, 0x2b, 0x14, 0x71,
+    0xec, 0x52, 0x9e, 0x89, 0x58, 0x14, 0x99, 0x9c, 0x55, 0x13, 0x56, 0xec, 0xc9, 0xca, 0x94, 0x56,
+    0x41, 0x06, 0x7b, 0x16, 0xac, 0x04, 0xb4, 0x16, 0x9c, 0xc2, 0xf8, 0xa3, 0xb9, 0xa0, 0x05, 0x04,
+    0x7a, 0xc1, 0xaa, 0x4d, 0xf2, 0x7f, 0xf2, 0x84, 0xc7, 0xab, 0x19, 0xa8, 0x00, 0x62, 0x9b, 0x5a,
+    0x85, 0xb0, 0x68, 0x34, 0x62, 0x3a, 0xc0, 0x18, 0xd2, 0xe4, 0xca, 0x1c, 0xa1, 0x97, 0xd7, 0xb4,
+    0x58, 0xc1, 0x85, 0xbe, 0x0b, 0xa9, 0xb4, 0x70, 0x38, 0x11, 0xf8, 0x62, 0x8d, 0x13, 0xb6, 0x90,
+    0x60, 0x25, 0x44, 0xbd, 0x69, 0xaf, 0xae, 0x21, 0x5f, 0x5b, 0xdb, 0x51, 0x31, 0x5c, 0xb5, 0x70,
+    0xd4, 0x8d, 0x8b, 0x55, 0x12, 0x0d, 0x50, 0x56, 0x0e, 0x59, 0x59, 0x4c, 0x8b, 0x56, 0x03, 0xfb,
+    0xcc, 0x7e, 0x48, 0x4e, 0xaf, 0x59, 0x10, 0x70, 0x86, 0x5f, 0xad, 0xd4, 0x95, 0xc4, 0xd6, 0x7b,
+    0xfc, 0x67, 0xcf, 0x1c, 0xb9, 0x4a, 0xcd, 0x50, 0xc8, 0x97, 0x0a, 0x22, 0x6c, 0x0b, 0xc0, 0xff,
+    0xa1, 0x86, 0xbd, 0xc5, 0x1d, 0xd2, 0x35, 0xac, 0x8d, 0x08, 0x5f, 0x34, 0x83, 0x74, 0xc8, 0x8c,
+    0x62, 0x06, 0xe1, 0x47, 0x23, 0x31, 0x04, 0x30, 0x69, 0x16, 0xe3, 0x06, 0x35, 0xf0, 0xab, 0x1b,
+    0x95, 0x66, 0x44, 0xe0, 0x2a, 0x4e, 0xe2, 0xbc, 0xc3, 0x24, 0x60, 0x88, 0xd3, 0xd5, 0x70, 0xa6,
+    0x17, 0xa6, 0x31, 0x50, 0xb3, 0x2b, 0xd5, 0x0d, 0xaa, 0x55, 0x5d, 0xd6, 0xbb, 0x8b, 0x6d, 0x34,
+    0xc0, 0xcb, 0xa8, 0x3a, 0x41, 0xc2, 0x3b, 0x48, 0xb3, 0x97, 0x08, 0xd7, 0x57, 0x8d, 0x33, 0xc5,
+    0xa6, 0x0a, 0xa2, 0x84, 0x30, 0xcb, 0x10, 0xba, 0x26, 0x4d, 0x15, 0x8a, 0xbf, 0xf3, 0x01, 0xa0,
+    0x07, 0x32, 0xbd, 0x95, 0x53, 0x91, 0x90, 0x43, 0x6a, 0xd0, 0x2f, 0x89, 0x31, 0x5c, 0xe9, 0x21,
+    0x49, 0x9c, 0x04, 0x30, 0x5d, 0x81, 0xcf, 0xb7, 0x99, 0x7a, 0xba, 0x4b, 0x2d, 0x65, 0x63, 0x9a,
+    0x34, 0x90, 0x1b, 0x67, 0x97, 0x2c, 0x9a, 0x23, 0x55, 0xb5, 0xa1, 0x0e, 0x91, 0xf9, 0x55, 0xe0,
+    0xa9, 0x5f, 0xf3, 0x3a, 0x21, 0xfa, 0x4a, 0x8b, 0x8e, 0x01, 0x8e, 0xa6, 0xe4, 0x3f, 0x34, 0x46,
+    0x2d, 0xaf, 0x95, 0xa2, 0x9d, 0xcc, 0x71, 0x9c, 0x2b, 0x7e, 0xea, 0xe5, 0x03, 0x50, 0x49, 0x70,
+    0x06, 0xf6, 0xac, 0x53, 0xd2, 0x8f, 0xcb, 0xf9, 0x08, 0x45, 0xb0, 0x2a, 0x88, 0x46, 0xc5, 0x8d,
+    0x64, 0x94, 0xc0, 0xc6, 0x03, 0x28, 0x34, 0x76, 0xaf, 0x12, 0x17, 0x67, 0xa9, 0x60, 0x0c, 0x83,
+    0xa9, 0xe9, 0x2b, 0x8d, 0x7b, 0x19, 0xc2, 0x68, 0x0b, 0x19, 0x48, 0x04, 0x4b, 0x80, 0x7c, 0x9e,
+    0xa7, 0xec, 0x94, 0xbe, 0x30, 0xcf, 0x3a, 0xea, 0x67, 0x6d, 0x16, 0x15, 0x9f, 0xa3, 0xbc, 0x97,
+    0xc0, 0x55, 0xed, 0x0a, 0x43, 0x9a, 0xf5, 0xc2, 0xf0, 0x85, 0xbc, 0x06, 0x80, 0xa5, 0xde, 0xd6,
+    0x82, 0x08, 0x43, 0xc3, 0xd3, 0xf6, 0x51, 0x38, 0xe5, 0xac, 0xe4, 0x8c, 0x7a, 0x0c, 0x11, 0x03,
+    0x71, 0x61, 0x67, 0x48, 0x26, 0x08, 0x4f, 0xd9, 0xba, 0x31, 0x13, 0x22, 0x3f, 0x18, 0x56, 0x4a,
+    0x9b, 0x8d, 0xd9, 0x84, 0x72, 0xd1, 0x83, 0x7a, 0xb8, 0x5b, 0x66, 0xe2, 0xc2, 0x63, 0x8a, 0x4a,
+    0x8d, 0x9d, 0xd6, 0xc3, 0x61, 0xba, 0x6b, 0x86, 0x62, 0x9f, 0xed, 0x9b, 0x6e, 0x76, 0xdc, 0x75,
+    0xb2, 0x58, 0x90, 0x8b, 0x75, 0x01, 0x17, 0xe8, 0xa4, 0x76, 0x3a, 0x1c, 0x0c, 0x0b, 0xbe, 0x5e,
+    0x26, 0x16, 0xc5, 0xd5, 0x5b, 0x60, 0x72, 0x03, 0x71, 0xf0, 0x6d, 0x63, 0x89, 0x30, 0x61, 0xfa,
+    0x6b, 0x3c, 0x76, 0xa6, 0x00, 0x17, 0x9b, 0x52, 0xf0, 0xc3, 0x19, 0xf4, 0x7a, 0x10, 0x18, 0x9a,
+    0x0f, 0x56, 0x6a, 0x72, 0x92, 0xc4, 0x0c, 0xd9, 0x98, 0x0c, 0x01, 0x12, 0xf2, 0x65, 0x66, 0x0c,
+    0x3b, 0x4f, 0x60, 0x73, 0x6a, 0x96, 0x93, 0x45, 0x4a, 0x7b, 0x86, 0x1f, 0x83, 0x4d, 0x35, 0xb8,
+    0x38, 0xf8, 0xa6, 0x47, 0x77, 0x16, 0x30, 0xbc, 0xbc, 0x1f, 0x23, 0xf6, 0xaa, 0x88, 0x7c, 0xb6,
+    0xcb, 0xd5, 0x82, 0xcc, 0x22, 0x40, 0xcd, 0xba, 0x86, 0x41, 0x67, 0x50, 0x6a, 0x43, 0xc4, 0x34,
+    0xc2, 0x7e, 0xad, 0x75, 0x44, 0x84, 0xd2, 0x32, 0xa8, 0x3b, 0xc4, 0x0c, 0x22, 0x18, 0x30, 0x68,
+    0x16, 0x03, 0x0a, 0x20, 0x76, 0x5a, 0x54, 0x70, 0x21, 0x7e, 0x5b, 0x2c, 0x90, 0x84, 0x63, 0x44,
+    0xcd, 0x8b, 0xc2, 0xc4, 0x98, 0xb7, 0x70, 0xe8, 0x3c, 0xd1, 0x95, 0x9d, 0xc1, 0x52, 0xbc, 0xcb,
+    0x4a, 0xce, 0xab, 0x36, 0xab, 0xf7, 0xf3, 0x61, 0x8c, 0x12, 0x47, 0xf5, 0xdb, 0x20, 0x13, 0x10,
+    0xc0, 0xa1, 0xe5, 0x74, 0xfa, 0x54, 0x7c, 0x39, 0x8c, 0xc5, 0xa4, 0x4a, 0xc2, 0x36, 0x85, 0xb6,
+    0x4d, 0x07, 0xb8, 0xf6, 0x61, 0x40, 0x16, 0xc4, 0x27, 0x1b, 0x71, 0xc6, 0x50, 0xa8, 0xb5, 0x20,
+    0xa5, 0xaf, 0xa0, 0x8b, 0xa0, 0x4e, 0xe5, 0x16, 0x46, 0xb8, 0xa7, 0xfb, 0x65, 0x2d, 0x3a, 0xf5,
+    0x7a, 0x40, 0x10, 0x55, 0x8f, 0x85, 0x6f, 0xac, 0xc9, 0x91, 0x1e, 0x09, 0xb3, 0x32, 0xc5, 0x87,
+    0x0e, 0xdb, 0x61, 0xe8, 0xe8, 0x50, 0xbb, 0x19, 0x49, 0xae, 0x57, 0x55, 0xc1, 0xfb, 0xa2, 0xcc,
+    0x47, 0x20, 0x73, 0x02, 0x9f, 0xd6, 0x54, 0x2b, 0xcd, 0xa7, 0x1b, 0x79, 0x52, 0xbc, 0xf8, 0x11,
+    0x60, 0x8f, 0x2a, 0x88, 0x29, 0x1a, 0x04, 0xf2, 0x66, 0x4b, 0xb1, 0x11, 0x2e, 0x27, 0xb1, 0x23,
+    0x5b, 0x16, 0xc1, 0x92, 0x03, 0x21, 0x4e, 0x79, 0x14, 0x5a, 0x31, 0x8c, 0x51, 0x10, 0x15, 0x2d,
+    0xa3, 0x6b, 0xb2, 0x1a, 0xca, 0x73, 0x80, 0x11, 0x85, 0xd6, 0xb8, 0xb1, 0xf6, 0xa3, 0x44, 0xb3,
+    0x3b, 0x3e, 0x55, 0x0f, 0xb5, 0xdc, 0x29, 0xbc, 0xd1, 0x98, 0x46, 0xe8, 0x40, 0x74, 0xbb, 0xc8,
+    0xf7, 0x58, 0x0c, 0xd3, 0x47, 0xb5, 0x2f, 0x12, 0xa7, 0xd1, 0x61, 0x6c, 0x55, 0xa2, 0xcd, 0x1f,
+    0x5c, 0x4a, 0xa8, 0x67, 0x02, 0xdd, 0x53, 0x0f, 0xa0, 0x5a, 0x64, 0x13, 0x02, 0xa1, 0x61, 0x27,
+    0x46, 0x8e, 0x85, 0x52, 0x2e, 0x56, 0x75, 0x70, 0xb6, 0x5f, 0xc3, 0xf8, 0x34, 0xd8, 0x5a, 0x20,
+    0x97, 0x3a, 0x0e, 0xb2, 0xb2, 0x10, 0xd5, 0x81, 0x2c, 0xfd, 0xfb, 0x88, 0x1c, 0xc3, 0xaa, 0x06,
+    0xab, 0x4c, 0xb7, 0x7b, 0xba, 0x7c, 0xdc, 0x6b, 0xce, 0xe5, 0x3c, 0x02, 0x0b, 0x33, 0x43, 0xb9,
+    0xbd, 0x9a, 0x82, 0x98, 0xad, 0x20, 0x55, 0xee, 0x1a, 0x60, 0x70, 0x84, 0x91, 0x40, 0xa8, 0x62,
+    0x88, 0x72, 0x18, 0x15, 0xc7, 0x97, 0x34, 0x77, 0x3f, 0x40, 0x97, 0xcf, 0x47, 0x41, 0xcc, 0x96,
+    0x35, 0xa3, 0x0c, 0x81, 0x00, 0xb2, 0x07, 0x33, 0xd3, 0x98, 0x0b, 0x35, 0x03, 0x93, 0xfa, 0xac,
+    0x4c, 0xd0, 0xe6, 0x6e, 0x47, 0x37, 0xc6, 0x81, 0xdb, 0xbc, 0xc8, 0xd7, 0x95, 0x3f, 0xa7, 0x74,
+    0x54, 0xc4, 0x22, 0xad, 0x87, 0x0e, 0x27, 0x8b, 0x11, 0x21, 0xc3, 0x3c, 0x82, 0x73, 0x37, 0x0e,
+    0x5b, 0x68, 0x6a, 0x6a, 0xab, 0x17, 0xfc, 0xa3, 0xb6, 0x7a, 0x30, 0x40, 0xd6, 0x49, 0x12, 0x41,
+    0xbf, 0x5e, 0x30, 0x72, 0xfb, 0xdc, 0x1e, 0x42, 0x24, 0x13, 0xfa, 0x5b, 0x4e, 0x9e, 0xe9, 0x1e,
+    0xb3, 0xc9, 0x36, 0xe2, 0x1a, 0x5c, 0x78, 0x56, 0x94, 0x2f, 0x44, 0xa5, 0x56, 0x70, 0xa6, 0x88,
+    0xa6, 0x9e, 0x91, 0xa9, 0xa8, 0x0b, 0xf4, 0x09, 0x4c, 0x30, 0x1d, 0xf7, 0x05, 0x33, 0x4d, 0xac,
+    0xb0, 0xcd, 0x92, 0x94, 0x73, 0x82, 0x9f, 0x34, 0xf3, 0x79, 0x47, 0xd2, 0x2b, 0x55, 0xc0, 0x62,
+    0xf4, 0xcc, 0xf7, 0x03, 0xee, 0x3c, 0x1c, 0xc0, 0xba, 0x73, 0x16, 0xdd, 0x65, 0x8e, 0x6b, 0x6e,
+    0x08, 0x15, 0xf8, 0xfc, 0x9a, 0x70, 0xb1, 0xbb, 0xa3, 0x25, 0xec, 0x32, 0xe2, 0x93, 0x09, 0x16,
+};
+
+static const unsigned char test_rsa_1024_priv[] = {
     0x30, 0x82, 0x02, 0x5e, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xaf, 0x05, 0x7d, 0x39, 0x6e,
     0xe8, 0x4f, 0xb7, 0x5f, 0xdb, 0xb5, 0xc2, 0xb1, 0x3c, 0x7f, 0xe5, 0xa6, 0x54, 0xaa, 0x8a, 0xa2,
     0x47, 0x0b, 0x54, 0x1e, 0xe1, 0xfe, 0xb0, 0xb1, 0x2d, 0x25, 0xc7, 0x97, 0x11, 0x53, 0x12, 0x49,
@@ -202,7 +850,7 @@
     0xba, 0xf2, 0x5b, 0xe5, 0x73, 0x8a, 0xae, 0x59, 0xbb, 0xfe, 0x1c, 0x99, 0x77, 0x81, 0x44, 0x7a,
     0x2b, 0x24,
 };
-const unsigned char test_rsa_1024_pub[] = {
+static const unsigned char test_rsa_1024_pub[] = {
     0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xaf, 0x05, 0x7d, 0x39, 0x6e, 0xe8, 0x4f, 0xb7, 0x5f,
     0xdb, 0xb5, 0xc2, 0xb1, 0x3c, 0x7f, 0xe5, 0xa6, 0x54, 0xaa, 0x8a, 0xa2, 0x47, 0x0b, 0x54, 0x1e,
     0xe1, 0xfe, 0xb0, 0xb1, 0x2d, 0x25, 0xc7, 0x97, 0x11, 0x53, 0x12, 0x49, 0xe1, 0x12, 0x96, 0x28,
@@ -214,7 +862,7 @@
     0x69, 0x0e, 0xf7, 0x98, 0x5f, 0x6b, 0xc3, 0x02, 0x03, 0x01, 0x00, 0x01,
 };
 
-const unsigned char test_rsa_1026_priv[] = {
+static const unsigned char test_rsa_1026_priv[] = {
     0x30, 0x82, 0x02, 0x5e, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x02, 0xd0, 0x96, 0x61, 0xfc, 0x74,
     0x22, 0x4b, 0xa7, 0xbe, 0x79, 0x07, 0xab, 0xef, 0x4f, 0x5e, 0x8b, 0xcc, 0x26, 0x4a, 0x80, 0x2c,
     0x97, 0x8f, 0x7e, 0xaa, 0x58, 0x55, 0xad, 0xa0, 0x54, 0x36, 0xd7, 0x5d, 0xb7, 0x68, 0xd2, 0x0f,
@@ -255,7 +903,7 @@
     0x08, 0x1e, 0x24, 0x0b, 0x6a, 0xe4, 0xe2, 0x71, 0x48, 0x87, 0xdd, 0x78, 0xda, 0xda, 0xeb, 0x0b,
     0x92, 0x16,
 };
-const unsigned char test_rsa_1026_pub[] = {
+static const unsigned char test_rsa_1026_pub[] = {
     0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x02, 0xd0, 0x96, 0x61, 0xfc, 0x74, 0x22, 0x4b, 0xa7, 0xbe,
     0x79, 0x07, 0xab, 0xef, 0x4f, 0x5e, 0x8b, 0xcc, 0x26, 0x4a, 0x80, 0x2c, 0x97, 0x8f, 0x7e, 0xaa,
     0x58, 0x55, 0xad, 0xa0, 0x54, 0x36, 0xd7, 0x5d, 0xb7, 0x68, 0xd2, 0x0f, 0x68, 0x59, 0x5d, 0xbc,
@@ -267,7 +915,7 @@
     0xe4, 0x6f, 0x74, 0x8a, 0x66, 0xd6, 0xef, 0x02, 0x03, 0x01, 0x00, 0x01,
 };
 
-const unsigned char test_rsa_1028_priv[] = {
+static const unsigned char test_rsa_1028_priv[] = {
     0x30, 0x82, 0x02, 0x5e, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x0e, 0x62, 0xa7, 0x6f, 0x0e, 0x0b,
     0x59, 0x68, 0x3a, 0x7e, 0xbf, 0x7c, 0xbf, 0xd3, 0x7b, 0x1d, 0x17, 0x81, 0xd8, 0xf1, 0xb9, 0x00,
     0x60, 0x4b, 0x50, 0x7f, 0x0f, 0x04, 0xc7, 0x2a, 0x3d, 0x34, 0x0d, 0x06, 0x7b, 0xcd, 0x53, 0xbe,
@@ -308,7 +956,7 @@
     0x25, 0x03, 0x1b, 0x8d, 0x37, 0x9f, 0x38, 0x9d, 0xe2, 0x77, 0xa9, 0xa0, 0x13, 0x76, 0x51, 0xdf,
     0x54, 0x8a,
 };
-const unsigned char test_rsa_1028_pub[] = {
+static const unsigned char test_rsa_1028_pub[] = {
     0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x0e, 0x62, 0xa7, 0x6f, 0x0e, 0x0b, 0x59, 0x68, 0x3a, 0x7e,
     0xbf, 0x7c, 0xbf, 0xd3, 0x7b, 0x1d, 0x17, 0x81, 0xd8, 0xf1, 0xb9, 0x00, 0x60, 0x4b, 0x50, 0x7f,
     0x0f, 0x04, 0xc7, 0x2a, 0x3d, 0x34, 0x0d, 0x06, 0x7b, 0xcd, 0x53, 0xbe, 0xa3, 0xca, 0xff, 0x4e,
@@ -320,7 +968,7 @@
     0x46, 0x2d, 0xde, 0x18, 0x23, 0x7c, 0xf5, 0x02, 0x03, 0x01, 0x00, 0x01,
 };
 
-const unsigned char test_rsa_1030_priv[] = {
+static const unsigned char test_rsa_1030_priv[] = {
     0x30, 0x82, 0x02, 0x5f, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x2b, 0x7c, 0xd1, 0x97, 0xf5, 0x79,
     0x6d, 0x1f, 0x8e, 0x57, 0x6b, 0x2b, 0x37, 0x72, 0x3f, 0xd9, 0x21, 0x08, 0x14, 0xef, 0x1c, 0x19,
     0x95, 0xf9, 0x89, 0x9d, 0x50, 0x05, 0x8f, 0x37, 0x9d, 0x23, 0x9c, 0x66, 0x87, 0x8e, 0x92, 0x2f,
@@ -361,7 +1009,7 @@
     0x32, 0x6a, 0x21, 0x42, 0xfc, 0xa4, 0x54, 0xbb, 0xd3, 0x8d, 0x6d, 0xbc, 0x6c, 0xaa, 0x7a, 0xc3,
     0x35, 0xa1, 0x7c,
 };
-const unsigned char test_rsa_1030_pub[] = {
+static const unsigned char test_rsa_1030_pub[] = {
     0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x2b, 0x7c, 0xd1, 0x97, 0xf5, 0x79, 0x6d, 0x1f, 0x8e, 0x57,
     0x6b, 0x2b, 0x37, 0x72, 0x3f, 0xd9, 0x21, 0x08, 0x14, 0xef, 0x1c, 0x19, 0x95, 0xf9, 0x89, 0x9d,
     0x50, 0x05, 0x8f, 0x37, 0x9d, 0x23, 0x9c, 0x66, 0x87, 0x8e, 0x92, 0x2f, 0x34, 0xc6, 0xae, 0x36,
@@ -373,7 +1021,7 @@
     0x88, 0xef, 0x65, 0x64, 0x08, 0xbd, 0x89, 0x02, 0x03, 0x01, 0x00, 0x01,
 };
 
-const unsigned char test_rsa_1536_priv[] = {
+static const unsigned char test_rsa_1536_priv[] = {
     0x30, 0x82, 0x03, 0x7b, 0x02, 0x01, 0x00, 0x02, 0x81, 0xc1, 0x00, 0xc8, 0x70, 0xfe, 0xb6, 0xca,
     0x6b, 0x1d, 0x2b, 0xd9, 0xf2, 0xdd, 0x99, 0xe2, 0x0f, 0x1f, 0xe2, 0xd7, 0xe5, 0x19, 0x2d, 0xe6,
     0x62, 0x22, 0x9d, 0xbe, 0x16, 0x2b, 0xd1, 0xba, 0x66, 0x33, 0x6a, 0x71, 0x82, 0x90, 0x3c, 0xa0,
@@ -431,7 +1079,7 @@
     0x8a, 0xc2, 0x71, 0x0c, 0xb5, 0x87, 0x8b, 0x59, 0x2f, 0xfe, 0xb1, 0xf4, 0xf0, 0xa1, 0x85, 0x3e,
     0x4e, 0x8d, 0x1d, 0x05, 0x61, 0xb6, 0xef, 0xcc, 0x83, 0x1a, 0x29, 0x6c, 0xf7, 0xee, 0xaf,
 };
-const unsigned char test_rsa_1536_pub[] = {
+static const unsigned char test_rsa_1536_pub[] = {
     0x30, 0x81, 0xc9, 0x02, 0x81, 0xc1, 0x00, 0xc8, 0x70, 0xfe, 0xb6, 0xca, 0x6b, 0x1d, 0x2b, 0xd9,
     0xf2, 0xdd, 0x99, 0xe2, 0x0f, 0x1f, 0xe2, 0xd7, 0xe5, 0x19, 0x2d, 0xe6, 0x62, 0x22, 0x9d, 0xbe,
     0x16, 0x2b, 0xd1, 0xba, 0x66, 0x33, 0x6a, 0x71, 0x82, 0x90, 0x3c, 0xa0, 0xb7, 0x27, 0x96, 0xcd,
@@ -447,7 +1095,7 @@
     0xa3, 0xf5, 0xef, 0xdf, 0x6d, 0xcc, 0x35, 0x02, 0x03, 0x01, 0x00, 0x01,
 };
 
-const unsigned char test_rsa_2048_priv[] = {
+static const unsigned char test_rsa_2048_priv[] = {
     0x30, 0x82, 0x04, 0xa3, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xf7, 0xbb, 0x6b, 0x8e,
     0xab, 0x40, 0x49, 0x1c, 0xd6, 0x44, 0x55, 0xec, 0x04, 0xd4, 0xed, 0x8d, 0xb5, 0x05, 0x1a, 0x97,
     0x38, 0xfc, 0x7a, 0xf7, 0x3f, 0xf3, 0xb0, 0x97, 0x51, 0x1c, 0xce, 0x40, 0xaa, 0xf7, 0x65, 0x37,
@@ -524,7 +1172,7 @@
     0xbf, 0x08, 0x75, 0x2d, 0x40, 0xa8, 0x41, 0x9d, 0xe7, 0x1b, 0x01, 0xd4, 0x92, 0x7e, 0x27, 0xc1,
     0x07, 0x9c, 0xaa, 0xda, 0x05, 0x68, 0xb1,
 };
-const unsigned char test_rsa_2048_pub[] = {
+static const unsigned char test_rsa_2048_pub[] = {
     0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xf7, 0xbb, 0x6b, 0x8e, 0xab, 0x40, 0x49,
     0x1c, 0xd6, 0x44, 0x55, 0xec, 0x04, 0xd4, 0xed, 0x8d, 0xb5, 0x05, 0x1a, 0x97, 0x38, 0xfc, 0x7a,
     0xf7, 0x3f, 0xf3, 0xb0, 0x97, 0x51, 0x1c, 0xce, 0x40, 0xaa, 0xf7, 0x65, 0x37, 0xb1, 0x35, 0x35,
@@ -544,7 +1192,7 @@
     0x76, 0xce, 0xbe, 0xaf, 0x14, 0xcb, 0x22, 0xc1, 0xed, 0x02, 0x03, 0x01, 0x00, 0x01,
 };
 
-const unsigned char test_rsa_4096_priv[] = {
+static const unsigned char test_rsa_4096_priv[] = {
     0x30, 0x82, 0x09, 0x29, 0x02, 0x01, 0x00, 0x02, 0x82, 0x02, 0x01, 0x00, 0xcc, 0x87, 0x25, 0xf6,
     0xb3, 0x8d, 0x5d, 0x01, 0xae, 0xeb, 0x07, 0xd3, 0x6e, 0x03, 0xde, 0x4d, 0x31, 0xa0, 0x26, 0x1c,
     0xe7, 0x4f, 0xe1, 0x1a, 0x89, 0x5e, 0xcf, 0xd1, 0x3d, 0x16, 0x8a, 0xee, 0x93, 0x2a, 0xf1, 0x35,
@@ -693,7 +1341,7 @@
     0x2f, 0x20, 0xc0, 0x05, 0xa2, 0x51, 0x9e, 0x3a, 0x87, 0x41, 0x46, 0x49, 0x5d, 0x7a, 0xac, 0xf3,
     0x41, 0x6a, 0x42, 0x2e, 0x56, 0x09, 0x86, 0xf2, 0x2f, 0x39, 0x45, 0x6e, 0x7f,
 };
-const unsigned char test_rsa_4096_pub[] = {
+static const unsigned char test_rsa_4096_pub[] = {
     0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xcc, 0x87, 0x25, 0xf6, 0xb3, 0x8d, 0x5d,
     0x01, 0xae, 0xeb, 0x07, 0xd3, 0x6e, 0x03, 0xde, 0x4d, 0x31, 0xa0, 0x26, 0x1c, 0xe7, 0x4f, 0xe1,
     0x1a, 0x89, 0x5e, 0xcf, 0xd1, 0x3d, 0x16, 0x8a, 0xee, 0x93, 0x2a, 0xf1, 0x35, 0xff, 0xbb, 0x84,
@@ -729,6 +1377,214 @@
     0x74, 0xb2, 0x60, 0x2d, 0x88, 0x85, 0x37, 0x48, 0x2d, 0x02, 0x03, 0x01, 0x00, 0x01,
 };
 
+static const unsigned char test_slhdsa_sha2f_128_priv[] = {
+    0xc4, 0x2b, 0xcb, 0x3b, 0x5a, 0x6f, 0x33, 0x1f, 0x5c, 0xce, 0x89, 0x92, 0x53, 0xc6, 0xd9, 0xe2,
+    0x9f, 0xf2, 0xb7, 0xea, 0xd7, 0xa0, 0x4b, 0xab, 0x17, 0x94, 0xdb, 0x8c, 0xc6, 0x59, 0xc3, 0xb4,
+    0xa8, 0x68, 0xf1, 0xbd, 0x5d, 0xeb, 0xc1, 0x2d, 0x4c, 0x9f, 0xad, 0x66, 0xaa, 0xbd, 0x0a, 0x94,
+    0xa8, 0x68, 0xf1, 0xbd, 0x5d, 0xeb, 0xc1, 0x2d, 0x4c, 0x9f, 0xad, 0x66, 0xaa, 0xbd, 0x0a, 0x94,
+    0xb5, 0x46, 0xdf, 0x24, 0x7b, 0xe4, 0xc4, 0x57, 0xf3, 0xd4, 0x67, 0xcd, 0xfc, 0xfa, 0xbd, 0x39,
+};
+static const unsigned char test_slhdsa_sha2f_128_pub[] = {
+    0xa8, 0x68, 0xf1, 0xbd, 0x5d, 0xeb, 0xc1, 0x2d, 0x4c, 0x9f, 0xad, 0x66, 0xaa, 0xbd, 0x0a, 0x94,
+    0xa8, 0x68, 0xf1, 0xbd, 0x5d, 0xeb, 0xc1, 0x2d, 0x4c, 0x9f, 0xad, 0x66, 0xaa, 0xbd, 0x0a, 0x94,
+    0xb5, 0x46, 0xdf, 0x24, 0x7b, 0xe4, 0xc4, 0x57, 0xf3, 0xd4, 0x67, 0xcd, 0xfc, 0xfa, 0xbd, 0x39,
+};
+
+static const unsigned char test_slhdsa_sha2f_192_priv[] = {
+    0xa0, 0x21, 0xb4, 0xb9, 0xd6, 0xde, 0xe1, 0x68, 0x72, 0x2b, 0xc1, 0x02, 0x25, 0xe5, 0x0a, 0x94,
+    0x66, 0x42, 0xaf, 0x63, 0x0c, 0x3c, 0x7c, 0x7d, 0x69, 0xe3, 0xa4, 0x0b, 0xa0, 0x9d, 0xf2, 0xac,
+    0x16, 0x5b, 0x79, 0x2a, 0x07, 0xf0, 0x64, 0xac, 0x5f, 0xc2, 0x8d, 0x8c, 0x99, 0xa5, 0x80, 0xf4,
+    0xee, 0x48, 0x23, 0xd0, 0x9e, 0x79, 0x85, 0x47, 0x06, 0xda, 0xa8, 0x0a, 0xe3, 0x17, 0x9b, 0x5b,
+    0xc8, 0xc2, 0xe9, 0x40, 0x9d, 0x63, 0x28, 0xa3, 0xee, 0x48, 0x23, 0xd0, 0x9e, 0x79, 0x85, 0x47,
+    0x06, 0xda, 0xa8, 0x0a, 0xe3, 0x17, 0x9b, 0x5b, 0xc8, 0xc2, 0xe9, 0x40, 0x9d, 0x63, 0x28, 0xa3,
+    0x35, 0x77, 0xfd, 0x58, 0x4b, 0xc0, 0x78, 0x4c, 0x55, 0x9c, 0xdb, 0x24, 0x37, 0xa4, 0x6f, 0x7f,
+    0x75, 0x3c, 0x33, 0x63, 0x69, 0x41, 0x9a, 0xcf,
+};
+static const unsigned char test_slhdsa_sha2f_192_pub[] = {
+    0xee, 0x48, 0x23, 0xd0, 0x9e, 0x79, 0x85, 0x47, 0x06, 0xda, 0xa8, 0x0a, 0xe3, 0x17, 0x9b, 0x5b,
+    0xc8, 0xc2, 0xe9, 0x40, 0x9d, 0x63, 0x28, 0xa3, 0xee, 0x48, 0x23, 0xd0, 0x9e, 0x79, 0x85, 0x47,
+    0x06, 0xda, 0xa8, 0x0a, 0xe3, 0x17, 0x9b, 0x5b, 0xc8, 0xc2, 0xe9, 0x40, 0x9d, 0x63, 0x28, 0xa3,
+    0x35, 0x77, 0xfd, 0x58, 0x4b, 0xc0, 0x78, 0x4c, 0x55, 0x9c, 0xdb, 0x24, 0x37, 0xa4, 0x6f, 0x7f,
+    0x75, 0x3c, 0x33, 0x63, 0x69, 0x41, 0x9a, 0xcf,
+};
+
+static const unsigned char test_slhdsa_sha2f_256_priv[] = {
+    0x18, 0x52, 0x37, 0x02, 0xa0, 0xfe, 0x2c, 0x9e, 0x48, 0x89, 0x48, 0xb1, 0x27, 0x18, 0x5b, 0xab,
+    0x93, 0xd3, 0xf0, 0x2c, 0x3d, 0x7c, 0x23, 0xa1, 0xb3, 0x79, 0xf7, 0x62, 0xde, 0x05, 0x09, 0xe5,
+    0x6a, 0xb0, 0xd9, 0xf9, 0x35, 0x40, 0xbd, 0x80, 0x9d, 0x1d, 0x2e, 0x8a, 0x05, 0x04, 0x40, 0xaa,
+    0x81, 0xe8, 0x53, 0x75, 0x04, 0x70, 0xe2, 0xb0, 0x0c, 0x95, 0x9d, 0xbd, 0x3b, 0xe4, 0x0e, 0x2b,
+    0xd7, 0x12, 0x5f, 0x5d, 0x00, 0xba, 0x47, 0xf1, 0xfc, 0x8d, 0x4c, 0x32, 0xc2, 0xf5, 0x7c, 0x44,
+    0x4b, 0xd3, 0x84, 0xd7, 0xce, 0x77, 0x0b, 0xc5, 0x0d, 0xd5, 0x98, 0x0c, 0x1d, 0x12, 0x64, 0xd0,
+    0xd7, 0x12, 0x5f, 0x5d, 0x00, 0xba, 0x47, 0xf1, 0xfc, 0x8d, 0x4c, 0x32, 0xc2, 0xf5, 0x7c, 0x44,
+    0x4b, 0xd3, 0x84, 0xd7, 0xce, 0x77, 0x0b, 0xc5, 0x0d, 0xd5, 0x98, 0x0c, 0x1d, 0x12, 0x64, 0xd0,
+    0x0a, 0xd5, 0x19, 0x7f, 0xfc, 0xba, 0xaf, 0xe1, 0x1b, 0x1e, 0x41, 0x3f, 0x26, 0xad, 0xb1, 0x50,
+    0x4c, 0xe1, 0xc3, 0xf5, 0xc4, 0x0c, 0x1d, 0xcd, 0xa1, 0x4e, 0x99, 0xfd, 0x12, 0x6d, 0x5b, 0x81,
+};
+static const unsigned char test_slhdsa_sha2f_256_pub[] = {
+    0xd7, 0x12, 0x5f, 0x5d, 0x00, 0xba, 0x47, 0xf1, 0xfc, 0x8d, 0x4c, 0x32, 0xc2, 0xf5, 0x7c, 0x44,
+    0x4b, 0xd3, 0x84, 0xd7, 0xce, 0x77, 0x0b, 0xc5, 0x0d, 0xd5, 0x98, 0x0c, 0x1d, 0x12, 0x64, 0xd0,
+    0xd7, 0x12, 0x5f, 0x5d, 0x00, 0xba, 0x47, 0xf1, 0xfc, 0x8d, 0x4c, 0x32, 0xc2, 0xf5, 0x7c, 0x44,
+    0x4b, 0xd3, 0x84, 0xd7, 0xce, 0x77, 0x0b, 0xc5, 0x0d, 0xd5, 0x98, 0x0c, 0x1d, 0x12, 0x64, 0xd0,
+    0x0a, 0xd5, 0x19, 0x7f, 0xfc, 0xba, 0xaf, 0xe1, 0x1b, 0x1e, 0x41, 0x3f, 0x26, 0xad, 0xb1, 0x50,
+    0x4c, 0xe1, 0xc3, 0xf5, 0xc4, 0x0c, 0x1d, 0xcd, 0xa1, 0x4e, 0x99, 0xfd, 0x12, 0x6d, 0x5b, 0x81,
+};
+
+static const unsigned char test_slhdsa_sha2s_128_priv[] = {
+    0x17, 0x3d, 0x04, 0xc9, 0x38, 0xc1, 0xc3, 0x6b, 0xf2, 0x89, 0xc3, 0xc0, 0x22, 0xd0, 0x4b, 0x14,
+    0x63, 0xae, 0x23, 0xc4, 0x1a, 0xa5, 0x46, 0xda, 0x58, 0x97, 0x74, 0xac, 0x20, 0xb7, 0x45, 0xc4,
+    0x0d, 0x79, 0x47, 0x77, 0x91, 0x4c, 0x99, 0x76, 0x68, 0x27, 0xf0, 0xf0, 0x9c, 0xa9, 0x72, 0xbe,
+    0x0d, 0x79, 0x47, 0x77, 0x91, 0x4c, 0x99, 0x76, 0x68, 0x27, 0xf0, 0xf0, 0x9c, 0xa9, 0x72, 0xbe,
+    0x01, 0x62, 0xc1, 0x02, 0x19, 0xd4, 0x22, 0xad, 0xba, 0x13, 0x59, 0xe6, 0xaa, 0x65, 0x29, 0x9c,
+};
+static const unsigned char test_slhdsa_sha2s_128_pub[] = {
+    0x0d, 0x79, 0x47, 0x77, 0x91, 0x4c, 0x99, 0x76, 0x68, 0x27, 0xf0, 0xf0, 0x9c, 0xa9, 0x72, 0xbe,
+    0x0d, 0x79, 0x47, 0x77, 0x91, 0x4c, 0x99, 0x76, 0x68, 0x27, 0xf0, 0xf0, 0x9c, 0xa9, 0x72, 0xbe,
+    0x01, 0x62, 0xc1, 0x02, 0x19, 0xd4, 0x22, 0xad, 0xba, 0x13, 0x59, 0xe6, 0xaa, 0x65, 0x29, 0x9c,
+};
+
+static const unsigned char test_slhdsa_sha2s_192_priv[] = {
+    0x04, 0x02, 0x66, 0x52, 0x9c, 0x18, 0x64, 0x08, 0x89, 0x25, 0x50, 0x6c, 0x20, 0xa6, 0x24, 0xa2,
+    0xb6, 0xd5, 0x0c, 0xd7, 0x7c, 0x1c, 0x6f, 0x0d, 0x28, 0x41, 0x15, 0x0a, 0xe8, 0x15, 0x75, 0x12,
+    0xef, 0x34, 0xa3, 0x43, 0xff, 0xea, 0x77, 0xff, 0x7d, 0x9e, 0x81, 0x4b, 0x45, 0xa8, 0xb4, 0x14,
+    0x64, 0x46, 0x26, 0x65, 0xf4, 0x20, 0x28, 0x86, 0x20, 0x6a, 0x8f, 0x63, 0x22, 0x67, 0x18, 0x6c,
+    0xa6, 0xa1, 0xca, 0xd0, 0x8a, 0x2b, 0x9a, 0x86, 0x64, 0x46, 0x26, 0x65, 0xf4, 0x20, 0x28, 0x86,
+    0x20, 0x6a, 0x8f, 0x63, 0x22, 0x67, 0x18, 0x6c, 0xa6, 0xa1, 0xca, 0xd0, 0x8a, 0x2b, 0x9a, 0x86,
+    0x2c, 0x6a, 0x7b, 0xc4, 0xac, 0x4a, 0xaa, 0x84, 0xac, 0xce, 0xf6, 0x0d, 0x52, 0x9f, 0x03, 0x11,
+    0x27, 0x4f, 0x20, 0x5e, 0x8d, 0xa6, 0x42, 0xc9,
+};
+static const unsigned char test_slhdsa_sha2s_192_pub[] = {
+    0x64, 0x46, 0x26, 0x65, 0xf4, 0x20, 0x28, 0x86, 0x20, 0x6a, 0x8f, 0x63, 0x22, 0x67, 0x18, 0x6c,
+    0xa6, 0xa1, 0xca, 0xd0, 0x8a, 0x2b, 0x9a, 0x86, 0x64, 0x46, 0x26, 0x65, 0xf4, 0x20, 0x28, 0x86,
+    0x20, 0x6a, 0x8f, 0x63, 0x22, 0x67, 0x18, 0x6c, 0xa6, 0xa1, 0xca, 0xd0, 0x8a, 0x2b, 0x9a, 0x86,
+    0x2c, 0x6a, 0x7b, 0xc4, 0xac, 0x4a, 0xaa, 0x84, 0xac, 0xce, 0xf6, 0x0d, 0x52, 0x9f, 0x03, 0x11,
+    0x27, 0x4f, 0x20, 0x5e, 0x8d, 0xa6, 0x42, 0xc9,
+};
+
+static const unsigned char test_slhdsa_sha2s_256_priv[] = {
+    0xfc, 0xbf, 0x36, 0xa9, 0x80, 0x7b, 0x30, 0x69, 0x7b, 0xe0, 0x63, 0xa5, 0x10, 0x5e, 0x09, 0x1b,
+    0x41, 0x2a, 0x39, 0x1d, 0xd3, 0x9e, 0x13, 0x26, 0xeb, 0xa2, 0x3c, 0xbd, 0x40, 0x96, 0xca, 0x77,
+    0xef, 0x41, 0x21, 0xc0, 0x8d, 0xd7, 0x1b, 0xe9, 0x13, 0x57, 0x2f, 0x1f, 0x91, 0xe5, 0x7d, 0x0a,
+    0xcb, 0xcd, 0x5c, 0xec, 0x28, 0x53, 0x9a, 0xc2, 0x75, 0x83, 0x2b, 0xba, 0xa6, 0xc1, 0x10, 0x81,
+    0xa0, 0xb4, 0xf5, 0x54, 0x9e, 0xbc, 0xad, 0xb9, 0x51, 0xdc, 0x2e, 0x51, 0x2c, 0x76, 0xb0, 0x62,
+    0x0d, 0x8f, 0xb8, 0x10, 0x0b, 0x4e, 0xe8, 0x86, 0xef, 0x87, 0x84, 0x78, 0x0d, 0x52, 0xa2, 0x54,
+    0xa0, 0xb4, 0xf5, 0x54, 0x9e, 0xbc, 0xad, 0xb9, 0x51, 0xdc, 0x2e, 0x51, 0x2c, 0x76, 0xb0, 0x62,
+    0x0d, 0x8f, 0xb8, 0x10, 0x0b, 0x4e, 0xe8, 0x86, 0xef, 0x87, 0x84, 0x78, 0x0d, 0x52, 0xa2, 0x54,
+    0x3e, 0x57, 0xab, 0x49, 0x4d, 0x47, 0x06, 0x8f, 0xfe, 0xe4, 0xb8, 0x24, 0x4a, 0xad, 0x6f, 0x19,
+    0xcd, 0xf9, 0x4a, 0x21, 0x72, 0xbd, 0x13, 0x4a, 0x15, 0xa6, 0xb5, 0xf2, 0x98, 0xd5, 0xa8, 0x0e,
+};
+static const unsigned char test_slhdsa_sha2s_256_pub[] = {
+    0xa0, 0xb4, 0xf5, 0x54, 0x9e, 0xbc, 0xad, 0xb9, 0x51, 0xdc, 0x2e, 0x51, 0x2c, 0x76, 0xb0, 0x62,
+    0x0d, 0x8f, 0xb8, 0x10, 0x0b, 0x4e, 0xe8, 0x86, 0xef, 0x87, 0x84, 0x78, 0x0d, 0x52, 0xa2, 0x54,
+    0xa0, 0xb4, 0xf5, 0x54, 0x9e, 0xbc, 0xad, 0xb9, 0x51, 0xdc, 0x2e, 0x51, 0x2c, 0x76, 0xb0, 0x62,
+    0x0d, 0x8f, 0xb8, 0x10, 0x0b, 0x4e, 0xe8, 0x86, 0xef, 0x87, 0x84, 0x78, 0x0d, 0x52, 0xa2, 0x54,
+    0x3e, 0x57, 0xab, 0x49, 0x4d, 0x47, 0x06, 0x8f, 0xfe, 0xe4, 0xb8, 0x24, 0x4a, 0xad, 0x6f, 0x19,
+    0xcd, 0xf9, 0x4a, 0x21, 0x72, 0xbd, 0x13, 0x4a, 0x15, 0xa6, 0xb5, 0xf2, 0x98, 0xd5, 0xa8, 0x0e,
+};
+
+static const unsigned char test_slhdsa_shakef_128_priv[] = {
+    0x39, 0x56, 0xab, 0x39, 0x1b, 0x4d, 0x22, 0xfc, 0x90, 0x7a, 0xf0, 0x74, 0x03, 0x26, 0xd0, 0x61,
+    0xab, 0x0e, 0xb2, 0x06, 0x43, 0x6f, 0x2b, 0x86, 0xeb, 0xe0, 0x86, 0xd7, 0x77, 0x39, 0xb3, 0xe4,
+    0x56, 0x50, 0x5c, 0x22, 0x9f, 0x4e, 0x7f, 0xa6, 0xb2, 0x01, 0x71, 0x4c, 0x7d, 0xcc, 0x9d, 0xa3,
+    0x56, 0x50, 0x5c, 0x22, 0x9f, 0x4e, 0x7f, 0xa6, 0xb2, 0x01, 0x71, 0x4c, 0x7d, 0xcc, 0x9d, 0xa3,
+    0x66, 0x57, 0x8f, 0x1f, 0x24, 0xc3, 0xfe, 0x37, 0x1c, 0x97, 0xc1, 0x4c, 0xe0, 0xe7, 0x9c, 0xdc,
+};
+static const unsigned char test_slhdsa_shakef_128_pub[] = {
+    0x56, 0x50, 0x5c, 0x22, 0x9f, 0x4e, 0x7f, 0xa6, 0xb2, 0x01, 0x71, 0x4c, 0x7d, 0xcc, 0x9d, 0xa3,
+    0x56, 0x50, 0x5c, 0x22, 0x9f, 0x4e, 0x7f, 0xa6, 0xb2, 0x01, 0x71, 0x4c, 0x7d, 0xcc, 0x9d, 0xa3,
+    0x66, 0x57, 0x8f, 0x1f, 0x24, 0xc3, 0xfe, 0x37, 0x1c, 0x97, 0xc1, 0x4c, 0xe0, 0xe7, 0x9c, 0xdc,
+};
+
+static const unsigned char test_slhdsa_shakef_192_priv[] = {
+    0xfb, 0x7a, 0x2c, 0x2c, 0x75, 0xce, 0x6c, 0x96, 0xb5, 0xf4, 0x32, 0x8e, 0x0a, 0xb3, 0x00, 0x47,
+    0x6f, 0xc6, 0xf8, 0x64, 0xcb, 0x5b, 0x0b, 0x99, 0x99, 0x0e, 0xcb, 0x72, 0x6c, 0xa8, 0x22, 0xa4,
+    0xe3, 0x65, 0x2d, 0xd9, 0x2e, 0xc0, 0xaa, 0xb7, 0x63, 0x7e, 0xa4, 0x1c, 0x04, 0x82, 0xae, 0x28,
+    0x68, 0xdc, 0xc6, 0x71, 0xe3, 0x53, 0x4f, 0x81, 0xa3, 0x52, 0xc2, 0x75, 0xb6, 0xa2, 0x5f, 0x90,
+    0x6d, 0x2e, 0xd0, 0xff, 0x62, 0xb8, 0xb4, 0xe3, 0x68, 0xdc, 0xc6, 0x71, 0xe3, 0x53, 0x4f, 0x81,
+    0xa3, 0x52, 0xc2, 0x75, 0xb6, 0xa2, 0x5f, 0x90, 0x6d, 0x2e, 0xd0, 0xff, 0x62, 0xb8, 0xb4, 0xe3,
+    0x98, 0xf1, 0xa9, 0x87, 0x6c, 0xb0, 0x82, 0xa4, 0x8e, 0x9a, 0xe2, 0xc8, 0x62, 0xb2, 0x89, 0x48,
+    0x6a, 0x39, 0x25, 0xce, 0xfc, 0x6f, 0xf4, 0xbe,
+};
+static const unsigned char test_slhdsa_shakef_192_pub[] = {
+    0x68, 0xdc, 0xc6, 0x71, 0xe3, 0x53, 0x4f, 0x81, 0xa3, 0x52, 0xc2, 0x75, 0xb6, 0xa2, 0x5f, 0x90,
+    0x6d, 0x2e, 0xd0, 0xff, 0x62, 0xb8, 0xb4, 0xe3, 0x68, 0xdc, 0xc6, 0x71, 0xe3, 0x53, 0x4f, 0x81,
+    0xa3, 0x52, 0xc2, 0x75, 0xb6, 0xa2, 0x5f, 0x90, 0x6d, 0x2e, 0xd0, 0xff, 0x62, 0xb8, 0xb4, 0xe3,
+    0x98, 0xf1, 0xa9, 0x87, 0x6c, 0xb0, 0x82, 0xa4, 0x8e, 0x9a, 0xe2, 0xc8, 0x62, 0xb2, 0x89, 0x48,
+    0x6a, 0x39, 0x25, 0xce, 0xfc, 0x6f, 0xf4, 0xbe,
+};
+
+static const unsigned char test_slhdsa_shakef_256_priv[] = {
+    0x2a, 0xc9, 0x40, 0x38, 0x58, 0xd1, 0x86, 0xb1, 0x72, 0xed, 0xd8, 0xdf, 0x9c, 0x78, 0xa1, 0x14,
+    0x49, 0x89, 0x36, 0x81, 0x48, 0x7d, 0x3a, 0xf0, 0xda, 0xd0, 0xec, 0x34, 0x1e, 0x8a, 0xca, 0x48,
+    0xaf, 0xa2, 0x77, 0x1b, 0xae, 0x6c, 0x17, 0xdd, 0x6f, 0x77, 0xb4, 0xe3, 0x80, 0x8b, 0x05, 0xf5,
+    0x6f, 0x31, 0xb8, 0xf4, 0x12, 0x8d, 0xf2, 0xcc, 0xb6, 0x77, 0xf0, 0x28, 0x3c, 0xfb, 0x18, 0xda,
+    0x55, 0x9b, 0xc8, 0x83, 0x10, 0x5e, 0x8b, 0xa0, 0x26, 0x46, 0x48, 0xb5, 0x32, 0x62, 0x61, 0x55,
+    0xf8, 0x7e, 0xdb, 0x4b, 0xed, 0xcf, 0xc1, 0x2a, 0x24, 0x20, 0x4d, 0x3b, 0x69, 0x6d, 0x53, 0x70,
+    0x55, 0x9b, 0xc8, 0x83, 0x10, 0x5e, 0x8b, 0xa0, 0x26, 0x46, 0x48, 0xb5, 0x32, 0x62, 0x61, 0x55,
+    0xf8, 0x7e, 0xdb, 0x4b, 0xed, 0xcf, 0xc1, 0x2a, 0x24, 0x20, 0x4d, 0x3b, 0x69, 0x6d, 0x53, 0x70,
+    0x7a, 0x15, 0x8f, 0xf5, 0xd3, 0x0e, 0x34, 0x28, 0x18, 0x3a, 0x3b, 0x3a, 0x96, 0xa0, 0xe4, 0xa3,
+    0x41, 0xa2, 0xa1, 0x6e, 0x5a, 0x62, 0x26, 0xaf, 0x37, 0x4d, 0x1e, 0xfb, 0x39, 0xa3, 0x5d, 0xf6,
+};
+static const unsigned char test_slhdsa_shakef_256_pub[] = {
+    0x55, 0x9b, 0xc8, 0x83, 0x10, 0x5e, 0x8b, 0xa0, 0x26, 0x46, 0x48, 0xb5, 0x32, 0x62, 0x61, 0x55,
+    0xf8, 0x7e, 0xdb, 0x4b, 0xed, 0xcf, 0xc1, 0x2a, 0x24, 0x20, 0x4d, 0x3b, 0x69, 0x6d, 0x53, 0x70,
+    0x55, 0x9b, 0xc8, 0x83, 0x10, 0x5e, 0x8b, 0xa0, 0x26, 0x46, 0x48, 0xb5, 0x32, 0x62, 0x61, 0x55,
+    0xf8, 0x7e, 0xdb, 0x4b, 0xed, 0xcf, 0xc1, 0x2a, 0x24, 0x20, 0x4d, 0x3b, 0x69, 0x6d, 0x53, 0x70,
+    0x7a, 0x15, 0x8f, 0xf5, 0xd3, 0x0e, 0x34, 0x28, 0x18, 0x3a, 0x3b, 0x3a, 0x96, 0xa0, 0xe4, 0xa3,
+    0x41, 0xa2, 0xa1, 0x6e, 0x5a, 0x62, 0x26, 0xaf, 0x37, 0x4d, 0x1e, 0xfb, 0x39, 0xa3, 0x5d, 0xf6,
+};
+
+static const unsigned char test_slhdsa_shakes_128_priv[] = {
+    0xc1, 0x51, 0x95, 0x1f, 0x38, 0x11, 0x02, 0x92, 0x39, 0xb7, 0x4a, 0xdd, 0x24, 0xc5, 0x06, 0xaf,
+    0xdd, 0x30, 0x36, 0x3e, 0x15, 0x6e, 0x6f, 0xe9, 0x36, 0xec, 0x6e, 0xd0, 0x23, 0x1f, 0xeb, 0x5c,
+    0x52, 0x9f, 0xfe, 0x86, 0x20, 0x0d, 0x1f, 0x32, 0xc2, 0xb6, 0x0d, 0x0c, 0xd9, 0x09, 0xf1, 0x90,
+    0x52, 0x9f, 0xfe, 0x86, 0x20, 0x0d, 0x1f, 0x32, 0xc2, 0xb6, 0x0d, 0x0c, 0xd9, 0x09, 0xf1, 0x90,
+    0x07, 0x61, 0xf9, 0xb7, 0x27, 0xaf, 0xa7, 0x24, 0xb4, 0x72, 0x23, 0x01, 0x6b, 0xb5, 0xb2, 0xba,
+};
+static const unsigned char test_slhdsa_shakes_128_pub[] = {
+    0x52, 0x9f, 0xfe, 0x86, 0x20, 0x0d, 0x1f, 0x32, 0xc2, 0xb6, 0x0d, 0x0c, 0xd9, 0x09, 0xf1, 0x90,
+    0x52, 0x9f, 0xfe, 0x86, 0x20, 0x0d, 0x1f, 0x32, 0xc2, 0xb6, 0x0d, 0x0c, 0xd9, 0x09, 0xf1, 0x90,
+    0x07, 0x61, 0xf9, 0xb7, 0x27, 0xaf, 0xa7, 0x24, 0xb4, 0x72, 0x23, 0x01, 0x6b, 0xb5, 0xb2, 0xba,
+};
+
+static const unsigned char test_slhdsa_shakes_192_priv[] = {
+    0x87, 0x32, 0x62, 0x18, 0x60, 0xe9, 0xa6, 0xe1, 0x88, 0x7b, 0xe5, 0x5f, 0x7a, 0xf6, 0x92, 0xb9,
+    0x8e, 0xb4, 0xc1, 0x0b, 0x25, 0x99, 0xf9, 0x4a, 0xd5, 0xcc, 0x9d, 0x64, 0x70, 0xd8, 0xb2, 0x11,
+    0x36, 0x15, 0x8e, 0x8b, 0x17, 0x10, 0xf1, 0xfb, 0xe0, 0x3e, 0xce, 0xd3, 0x7e, 0xd4, 0xac, 0x68,
+    0x53, 0xfc, 0x64, 0xd4, 0x6d, 0x7e, 0x16, 0x53, 0xeb, 0xbb, 0x36, 0xed, 0x5f, 0xbc, 0x12, 0xc6,
+    0xe7, 0xce, 0xf3, 0xcb, 0x75, 0x64, 0x82, 0xc8, 0x53, 0xfc, 0x64, 0xd4, 0x6d, 0x7e, 0x16, 0x53,
+    0xeb, 0xbb, 0x36, 0xed, 0x5f, 0xbc, 0x12, 0xc6, 0xe7, 0xce, 0xf3, 0xcb, 0x75, 0x64, 0x82, 0xc8,
+    0xc6, 0x20, 0x45, 0x2e, 0x86, 0x4e, 0x84, 0x97, 0xe1, 0xb3, 0x8a, 0x7b, 0x04, 0x44, 0x92, 0x19,
+    0xac, 0xd9, 0xe4, 0x39, 0x3f, 0x9c, 0x88, 0xef,
+};
+static const unsigned char test_slhdsa_shakes_192_pub[] = {
+    0x53, 0xfc, 0x64, 0xd4, 0x6d, 0x7e, 0x16, 0x53, 0xeb, 0xbb, 0x36, 0xed, 0x5f, 0xbc, 0x12, 0xc6,
+    0xe7, 0xce, 0xf3, 0xcb, 0x75, 0x64, 0x82, 0xc8, 0x53, 0xfc, 0x64, 0xd4, 0x6d, 0x7e, 0x16, 0x53,
+    0xeb, 0xbb, 0x36, 0xed, 0x5f, 0xbc, 0x12, 0xc6, 0xe7, 0xce, 0xf3, 0xcb, 0x75, 0x64, 0x82, 0xc8,
+    0xc6, 0x20, 0x45, 0x2e, 0x86, 0x4e, 0x84, 0x97, 0xe1, 0xb3, 0x8a, 0x7b, 0x04, 0x44, 0x92, 0x19,
+    0xac, 0xd9, 0xe4, 0x39, 0x3f, 0x9c, 0x88, 0xef,
+};
+
+static const unsigned char test_slhdsa_shakes_256_priv[] = {
+    0xe4, 0x40, 0xe3, 0x96, 0x44, 0xa1, 0x1a, 0x6a, 0x58, 0xe8, 0x50, 0xc0, 0x9c, 0x8f, 0x03, 0xc2,
+    0x73, 0xe4, 0x65, 0x23, 0x7f, 0x3b, 0xef, 0x7c, 0x58, 0xde, 0x62, 0x28, 0x1e, 0x67, 0x6c, 0xea,
+    0x99, 0xc1, 0x99, 0xc0, 0x0d, 0xb3, 0x0f, 0x84, 0x99, 0xa6, 0x1b, 0x5b, 0x9d, 0xc8, 0xa3, 0x61,
+    0x72, 0x5f, 0x6a, 0xe8, 0x0e, 0x97, 0x03, 0x71, 0x76, 0xf4, 0x08, 0xc3, 0x0b, 0x38, 0x84, 0x4d,
+    0xd7, 0xb5, 0xe7, 0x55, 0xb4, 0x87, 0x9f, 0xde, 0x32, 0x88, 0xa2, 0x1a, 0xf3, 0xe3, 0x2f, 0xbb,
+    0x00, 0x6f, 0xd9, 0xb8, 0xbc, 0x2b, 0x18, 0x0e, 0xb9, 0xb0, 0xd8, 0x2c, 0x9f, 0x31, 0x57, 0xaf,
+    0xd7, 0xb5, 0xe7, 0x55, 0xb4, 0x87, 0x9f, 0xde, 0x32, 0x88, 0xa2, 0x1a, 0xf3, 0xe3, 0x2f, 0xbb,
+    0x00, 0x6f, 0xd9, 0xb8, 0xbc, 0x2b, 0x18, 0x0e, 0xb9, 0xb0, 0xd8, 0x2c, 0x9f, 0x31, 0x57, 0xaf,
+    0x02, 0xac, 0xd6, 0xb3, 0x19, 0x8e, 0xe1, 0xc9, 0xfe, 0x9a, 0xfe, 0x61, 0xfd, 0x86, 0xd1, 0xe0,
+    0x87, 0x7a, 0xd9, 0x06, 0x19, 0x80, 0xb5, 0x7b, 0x17, 0x8c, 0xe2, 0x71, 0x91, 0xd8, 0xeb, 0x1b,
+};
+static const unsigned char test_slhdsa_shakes_256_pub[] = {
+    0xd7, 0xb5, 0xe7, 0x55, 0xb4, 0x87, 0x9f, 0xde, 0x32, 0x88, 0xa2, 0x1a, 0xf3, 0xe3, 0x2f, 0xbb,
+    0x00, 0x6f, 0xd9, 0xb8, 0xbc, 0x2b, 0x18, 0x0e, 0xb9, 0xb0, 0xd8, 0x2c, 0x9f, 0x31, 0x57, 0xaf,
+    0xd7, 0xb5, 0xe7, 0x55, 0xb4, 0x87, 0x9f, 0xde, 0x32, 0x88, 0xa2, 0x1a, 0xf3, 0xe3, 0x2f, 0xbb,
+    0x00, 0x6f, 0xd9, 0xb8, 0xbc, 0x2b, 0x18, 0x0e, 0xb9, 0xb0, 0xd8, 0x2c, 0x9f, 0x31, 0x57, 0xaf,
+    0x02, 0xac, 0xd6, 0xb3, 0x19, 0x8e, 0xe1, 0xc9, 0xfe, 0x9a, 0xfe, 0x61, 0xfd, 0x86, 0xd1, 0xe0,
+    0x87, 0x7a, 0xd9, 0x06, 0x19, 0x80, 0xb5, 0x7b, 0x17, 0x8c, 0xe2, 0x71, 0x91, 0xd8, 0xeb, 0x1b,
+};
+
 struct predefined_key_element {
     int group_id;  // EC group ID; 0 for RSA keys
     int keybits;  // bits size of RSA key; 0 for EC keys
@@ -738,7 +1594,7 @@
     size_t pub_key_len;
 };
 
-struct predefined_key_element predefined_keys[] = {
+MBEDTLS_MAYBE_UNUSED static struct predefined_key_element predefined_keys[] = {
     { MBEDTLS_ECP_DP_BP256R1, 0,
       test_ec_bp256r1_priv, sizeof(test_ec_bp256r1_priv),
       test_ec_bp256r1_pub, sizeof(test_ec_bp256r1_pub) },
@@ -775,6 +1631,24 @@
     { MBEDTLS_ECP_DP_SECP521R1, 0,
       test_ec_secp521r1_priv, sizeof(test_ec_secp521r1_priv),
       test_ec_secp521r1_pub, sizeof(test_ec_secp521r1_pub) },
+    { 0, 44,
+      test_mldsa_44_priv, sizeof(test_mldsa_44_priv),
+      test_mldsa_44_pub, sizeof(test_mldsa_44_pub) },
+    { 0, 65,
+      test_mldsa_65_priv, sizeof(test_mldsa_65_priv),
+      test_mldsa_65_pub, sizeof(test_mldsa_65_pub) },
+    { 0, 87,
+      test_mldsa_87_priv, sizeof(test_mldsa_87_priv),
+      test_mldsa_87_pub, sizeof(test_mldsa_87_pub) },
+    { 0, 512,
+      test_mlkem_512_priv, sizeof(test_mlkem_512_priv),
+      test_mlkem_512_pub, sizeof(test_mlkem_512_pub) },
+    { 0, 768,
+      test_mlkem_768_priv, sizeof(test_mlkem_768_priv),
+      test_mlkem_768_pub, sizeof(test_mlkem_768_pub) },
+    { 0, 1024,
+      test_mlkem_1024_priv, sizeof(test_mlkem_1024_priv),
+      test_mlkem_1024_pub, sizeof(test_mlkem_1024_pub) },
     { 0, 1024,
       test_rsa_1024_priv, sizeof(test_rsa_1024_priv),
       test_rsa_1024_pub, sizeof(test_rsa_1024_pub) },
@@ -796,6 +1670,44 @@
     { 0, 4096,
       test_rsa_4096_priv, sizeof(test_rsa_4096_priv),
       test_rsa_4096_pub, sizeof(test_rsa_4096_pub) },
+    { 0, 128,
+      test_slhdsa_sha2f_128_priv, sizeof(test_slhdsa_sha2f_128_priv),
+      test_slhdsa_sha2f_128_pub, sizeof(test_slhdsa_sha2f_128_pub) },
+    { 0, 192,
+      test_slhdsa_sha2f_192_priv, sizeof(test_slhdsa_sha2f_192_priv),
+      test_slhdsa_sha2f_192_pub, sizeof(test_slhdsa_sha2f_192_pub) },
+    { 0, 256,
+      test_slhdsa_sha2f_256_priv, sizeof(test_slhdsa_sha2f_256_priv),
+      test_slhdsa_sha2f_256_pub, sizeof(test_slhdsa_sha2f_256_pub) },
+    { 0, 128,
+      test_slhdsa_sha2s_128_priv, sizeof(test_slhdsa_sha2s_128_priv),
+      test_slhdsa_sha2s_128_pub, sizeof(test_slhdsa_sha2s_128_pub) },
+    { 0, 192,
+      test_slhdsa_sha2s_192_priv, sizeof(test_slhdsa_sha2s_192_priv),
+      test_slhdsa_sha2s_192_pub, sizeof(test_slhdsa_sha2s_192_pub) },
+    { 0, 256,
+      test_slhdsa_sha2s_256_priv, sizeof(test_slhdsa_sha2s_256_priv),
+      test_slhdsa_sha2s_256_pub, sizeof(test_slhdsa_sha2s_256_pub) },
+    { 0, 128,
+      test_slhdsa_shakef_128_priv, sizeof(test_slhdsa_shakef_128_priv),
+      test_slhdsa_shakef_128_pub, sizeof(test_slhdsa_shakef_128_pub) },
+    { 0, 192,
+      test_slhdsa_shakef_192_priv, sizeof(test_slhdsa_shakef_192_priv),
+      test_slhdsa_shakef_192_pub, sizeof(test_slhdsa_shakef_192_pub) },
+    { 0, 256,
+      test_slhdsa_shakef_256_priv, sizeof(test_slhdsa_shakef_256_priv),
+      test_slhdsa_shakef_256_pub, sizeof(test_slhdsa_shakef_256_pub) },
+    { 0, 128,
+      test_slhdsa_shakes_128_priv, sizeof(test_slhdsa_shakes_128_priv),
+      test_slhdsa_shakes_128_pub, sizeof(test_slhdsa_shakes_128_pub) },
+    { 0, 192,
+      test_slhdsa_shakes_192_priv, sizeof(test_slhdsa_shakes_192_priv),
+      test_slhdsa_shakes_192_pub, sizeof(test_slhdsa_shakes_192_pub) },
+    { 0, 256,
+      test_slhdsa_shakes_256_priv, sizeof(test_slhdsa_shakes_256_priv),
+      test_slhdsa_shakes_256_pub, sizeof(test_slhdsa_shakes_256_pub) },
 };
 
+#endif /* TEST_TEST_KEYS_H */
+
 /* End of generated file */
diff -Nru mbedtls-3.6.5/tests/Makefile mbedtls-3.6.6/tests/Makefile
--- mbedtls-3.6.5/tests/Makefile	2025-10-14 19:12:37.006826600 +0300
+++ mbedtls-3.6.6/tests/Makefile	2026-03-27 19:00:27.621093800 +0200
@@ -54,14 +54,15 @@
 
 GENERATED_FILES = $(GENERATED_DATA_FILES)
 GENERATED_FILES += include/test/test_keys.h include/test/test_certs.h
+GENERATED_FILES += include/test/psa_test_wrappers.h src/psa_test_wrappers.c
 
 # Generated files needed to (fully) run ssl-opt.sh
 .PHONY: ssl-opt
 
 opt-testcases/handshake-generated.sh: ../framework/scripts/mbedtls_framework/tls_test_case.py
-opt-testcases/handshake-generated.sh: ../framework/scripts/generate_tls_handshake_tests.py
+opt-testcases/handshake-generated.sh: ../scripts/generate_tls_handshake_tests.py
 	echo "  Gen   $@"
-	$(PYTHON) ../framework/scripts/generate_tls_handshake_tests.py -o $@
+	$(PYTHON) ../scripts/generate_tls_handshake_tests.py -o $@
 GENERATED_FILES += opt-testcases/handshake-generated.sh
 ssl-opt: opt-testcases/handshake-generated.sh
 
@@ -164,6 +165,10 @@
 
 mbedtls_test: $(MBEDTLS_TEST_OBJS)
 
+include/test/psa_test_wrappers.h src/psa_test_wrappers.c: ../framework/scripts/generate_psa_wrappers.py
+	echo "  Gen   $@"
+	cd .. && $(PYTHON) framework/scripts/generate_psa_wrappers.py
+
 include/test/test_certs.h: ../framework/scripts/generate_test_cert_macros.py \
 				  $($(PYTHON) ../framework/scripts/generate_test_cert_macros.py --list-dependencies)
 	echo "  Gen   $@"
@@ -180,6 +185,7 @@
 # therefore the wildcard enumeration above doesn't include it.
 TEST_OBJS_DEPS += ../framework/tests/include/test/instrument_record_status.h
 endif
+TEST_OBJS_DEPS += include/test/psa_test_wrappers.h
 TEST_OBJS_DEPS += include/test/test_certs.h include/test/test_keys.h
 
 # Rule to compile common test C files in framework
diff -Nru mbedtls-3.6.5/tests/opt-testcases/handshake-generated.sh mbedtls-3.6.6/tests/opt-testcases/handshake-generated.sh
--- mbedtls-3.6.5/tests/opt-testcases/handshake-generated.sh	2025-10-14 19:12:37.014465300 +0300
+++ mbedtls-3.6.6/tests/opt-testcases/handshake-generated.sh	2026-03-27 19:00:27.626645800 +0200
@@ -462,9 +462,8 @@
             -s "Consume: waiting for more handshake fragments 128/"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_certificate_authentication
-run_test    "Handshake defragmentation on server: len=128, TLS 1.2 with 1.3 support" \
+run_test    "Handshake defragmentation on server: len=128, TLS 1.2" \
             "$P_SRV debug_level=4 auth_mode=required" \
             "$O_NEXT_CLI -tls1_2 -split_send_frag 128 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
             0 \
@@ -487,9 +486,8 @@
             -s "Consume: waiting for more handshake fragments 64/"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_certificate_authentication
-run_test    "Handshake defragmentation on server: len=64, TLS 1.2 with 1.3 support" \
+run_test    "Handshake defragmentation on server: len=64, TLS 1.2" \
             "$P_SRV debug_level=4 auth_mode=required" \
             "$O_NEXT_CLI -tls1_2 -split_send_frag 64 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
             0 \
@@ -512,9 +510,8 @@
             -s "Consume: waiting for more handshake fragments 36/"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_certificate_authentication
-run_test    "Handshake defragmentation on server: len=36, TLS 1.2 with 1.3 support" \
+run_test    "Handshake defragmentation on server: len=36, TLS 1.2" \
             "$P_SRV debug_level=4 auth_mode=required" \
             "$O_NEXT_CLI -tls1_2 -split_send_frag 36 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
             0 \
@@ -537,9 +534,8 @@
             -s "Consume: waiting for more handshake fragments 32/"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_certificate_authentication
-run_test    "Handshake defragmentation on server: len=32, TLS 1.2 with 1.3 support" \
+run_test    "Handshake defragmentation on server: len=32, TLS 1.2" \
             "$P_SRV debug_level=4 auth_mode=required" \
             "$O_NEXT_CLI -tls1_2 -split_send_frag 32 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
             0 \
@@ -562,9 +558,8 @@
             -s "Consume: waiting for more handshake fragments 16/"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_certificate_authentication
-run_test    "Handshake defragmentation on server: len=16, TLS 1.2 with 1.3 support" \
+run_test    "Handshake defragmentation on server: len=16, TLS 1.2" \
             "$P_SRV debug_level=4 auth_mode=required" \
             "$O_NEXT_CLI -tls1_2 -split_send_frag 16 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
             0 \
@@ -587,9 +582,8 @@
             -s "Consume: waiting for more handshake fragments 13/"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_certificate_authentication
-run_test    "Handshake defragmentation on server: len=13, TLS 1.2 with 1.3 support" \
+run_test    "Handshake defragmentation on server: len=13, TLS 1.2" \
             "$P_SRV debug_level=4 auth_mode=required" \
             "$O_NEXT_CLI -tls1_2 -split_send_frag 13 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
             0 \
@@ -612,9 +606,8 @@
             -s "Consume: waiting for more handshake fragments 5/"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_certificate_authentication
-run_test    "Handshake defragmentation on server: len=5, TLS 1.2 with 1.3 support" \
+run_test    "Handshake defragmentation on server: len=5, TLS 1.2" \
             "$P_SRV debug_level=4 auth_mode=required" \
             "$O_NEXT_CLI -tls1_2 -split_send_frag 5 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
             0 \
@@ -637,9 +630,8 @@
             -s "Consume: waiting for more handshake fragments 4/"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_certificate_authentication
-run_test    "Handshake defragmentation on server: len=4, TLS 1.2 with 1.3 support, default" \
+run_test    "Handshake defragmentation on server: len=4, TLS 1.2, default" \
             "$P_SRV debug_level=4 auth_mode=required" \
             "$O_NEXT_CLI -tls1_2 -split_send_frag 4 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
             0 \
@@ -650,10 +642,9 @@
             -s "Consume: waiting for more handshake fragments 4/"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_certificate_authentication
 requires_ciphersuite_enabled TLS-ECDHE-ECDSA-WITH-NULL-SHA
-run_test    "Handshake defragmentation on server: len=4, TLS 1.2 with 1.3 support, null" \
+run_test    "Handshake defragmentation on server: len=4, TLS 1.2, null" \
             "$P_SRV debug_level=4 auth_mode=required" \
             "$O_NEXT_CLI -tls1_2 -split_send_frag 4 -cipher ECDHE-ECDSA-NULL-SHA@SECLEVEL=0 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
             0 \
@@ -664,10 +655,9 @@
             -s "Consume: waiting for more handshake fragments 4/"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_certificate_authentication
 requires_ciphersuite_enabled TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256
-run_test    "Handshake defragmentation on server: len=4, TLS 1.2 with 1.3 support, ChachaPoly" \
+run_test    "Handshake defragmentation on server: len=4, TLS 1.2, ChachaPoly" \
             "$P_SRV debug_level=4 auth_mode=required" \
             "$O_NEXT_CLI -tls1_2 -split_send_frag 4 -cipher ECDHE-ECDSA-CHACHA20-POLY1305 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
             0 \
@@ -678,10 +668,9 @@
             -s "Consume: waiting for more handshake fragments 4/"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_certificate_authentication
 requires_ciphersuite_enabled TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256
-run_test    "Handshake defragmentation on server: len=4, TLS 1.2 with 1.3 support, GCM" \
+run_test    "Handshake defragmentation on server: len=4, TLS 1.2, GCM" \
             "$P_SRV debug_level=4 auth_mode=required" \
             "$O_NEXT_CLI -tls1_2 -split_send_frag 4 -cipher ECDHE-ECDSA-AES128-GCM-SHA256 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
             0 \
@@ -692,10 +681,9 @@
             -s "Consume: waiting for more handshake fragments 4/"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_certificate_authentication
 requires_ciphersuite_enabled TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256
-run_test    "Handshake defragmentation on server: len=4, TLS 1.2 with 1.3 support, CBC, etm=n" \
+run_test    "Handshake defragmentation on server: len=4, TLS 1.2, CBC, etm=n" \
             "$P_SRV debug_level=4 etm=0 auth_mode=required" \
             "$O_NEXT_CLI -tls1_2 -split_send_frag 4 -cipher ECDHE-ECDSA-AES128-SHA256 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
             0 \
@@ -707,11 +695,10 @@
             -S "using encrypt then mac"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_certificate_authentication
 requires_ciphersuite_enabled TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256
 requires_config_enabled MBEDTLS_SSL_ENCRYPT_THEN_MAC
-run_test    "Handshake defragmentation on server: len=4, TLS 1.2 with 1.3 support, CBC, etm=y" \
+run_test    "Handshake defragmentation on server: len=4, TLS 1.2, CBC, etm=y" \
             "$P_SRV debug_level=4 etm=1 auth_mode=required" \
             "$O_NEXT_CLI -tls1_2 -split_send_frag 4 -cipher ECDHE-ECDSA-AES128-SHA256 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
             0 \
@@ -727,17 +714,16 @@
             "$P_SRV debug_level=4 auth_mode=required" \
             "$O_NEXT_CLI -tls1_3 -allow_no_dhe_kex -split_send_frag 3 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
             1 \
-            -s "<= parse client hello" \
+            -s "=> parse client hello" \
             -s "handshake message too short: 3" \
             -s "SSL - An invalid SSL record was received"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
-run_test    "Handshake defragmentation on server: len=3, TLS 1.2 with 1.3 support" \
+run_test    "Handshake defragmentation on server: len=3, TLS 1.2" \
             "$P_SRV debug_level=4 auth_mode=required" \
             "$O_NEXT_CLI -tls1_2 -allow_no_dhe_kex -split_send_frag 3 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
             1 \
-            -s "<= parse client hello" \
+            -s "=> parse client hello" \
             -s "handshake message too short: 3" \
             -s "SSL - An invalid SSL record was received"
 
diff -Nru mbedtls-3.6.5/tests/scripts/analyze_outcomes.py mbedtls-3.6.6/tests/scripts/analyze_outcomes.py
--- mbedtls-3.6.5/tests/scripts/analyze_outcomes.py	2025-10-14 19:12:37.017895500 +0300
+++ mbedtls-3.6.6/tests/scripts/analyze_outcomes.py	2026-03-27 19:00:27.629263200 +0200
@@ -43,7 +43,7 @@
             'DTLS cookie: enabled, IPv6',
             # Disabled due to OpenSSL bug.
             # https://github.com/openssl/openssl/issues/18887
-            'DTLS fragmenting: 3d, openssl client, DTLS 1.2',
+            'DTLS fragmenting: 3d, MTU=512, openssl client, DTLS 1.2',
             # We don't run ssl-opt.sh with Valgrind on the CI because
             # it's extremely slow. We don't intend to change this.
             'DTLS fragmenting: proxy MTU: auto-reduction (with valgrind)',
@@ -53,6 +53,15 @@
             # https://github.com/Mbed-TLS/mbedtls/issues/9581
             'Opaque key for server authentication: invalid key: decrypt with ECC key, no async',
             'Opaque key for server authentication: invalid key: ecdh with RSA key, no async',
+            # The following test fails intermittently on the CI with a frequency
+            # that significantly impacts CI throughput. They are thus disabled
+            # for the time being. See
+            # https://github.com/Mbed-TLS/mbedtls/issues/10652 for more
+            # information.
+            'DTLS proxy: 3d, openssl client, fragmentation',
+            'DTLS proxy: 3d, openssl client, fragmentation, nbio',
+            'DTLS proxy: 3d, gnutls client, fragmentation',
+            'DTLS proxy: 3d, gnutls client, fragmentation, nbio=2',
         ],
         'test_suite_config.mbedtls_boolean': [
             # We never test with CBC/PKCS5/PKCS12 enabled but
diff -Nru mbedtls-3.6.5/tests/scripts/check-generated-files.sh mbedtls-3.6.6/tests/scripts/check-generated-files.sh
--- mbedtls-3.6.5/tests/scripts/check-generated-files.sh	2025-10-14 19:12:37.018468900 +0300
+++ mbedtls-3.6.6/tests/scripts/check-generated-files.sh	2026-03-27 19:00:27.629558000 +0200
@@ -126,6 +126,7 @@
 check framework/scripts/generate_config_tests.py $(framework/scripts/generate_config_tests.py --list)
 check framework/scripts/generate_ecp_tests.py $(framework/scripts/generate_ecp_tests.py --list)
 check framework/scripts/generate_psa_tests.py $(framework/scripts/generate_psa_tests.py --list)
+check framework/scripts/generate_psa_wrappers.py tests/include/test/psa_test_wrappers.h tests/src/psa_test_wrappers.c
 check framework/scripts/generate_test_keys.py tests/include/test/test_keys.h
 check scripts/generate_driver_wrappers.py $library_dir/psa_crypto_driver_wrappers.h $library_dir/psa_crypto_driver_wrappers_no_static.c
 
@@ -135,7 +136,7 @@
     check scripts/generate_query_config.pl programs/test/query_config.c
     check scripts/generate_features.pl library/version_features.c
     check framework/scripts/generate_ssl_debug_helpers.py library/ssl_debug_helpers_generated.c
-    check framework/scripts/generate_tls_handshake_tests.py tests/opt-testcases/handshake-generated.sh
+    check scripts/generate_tls_handshake_tests.py tests/opt-testcases/handshake-generated.sh
     check framework/scripts/generate_tls13_compat_tests.py tests/opt-testcases/tls13-compat.sh
     check framework/scripts/generate_test_cert_macros.py tests/include/test/test_certs.h
     # generate_visualc_files enumerates source files (library/*.c). It doesn't
@@ -143,8 +144,3 @@
     # the step that creates or updates these files.
     check scripts/generate_visualc_files.pl visualc/VS2017
 fi
-
-# Generated files that are present in the repository even in the development
-# branch. (This is intended to be temporary, until the generator scripts are
-# fully reviewed and the build scripts support a generated header file.)
-check framework/scripts/generate_psa_wrappers.py tests/include/test/psa_test_wrappers.h tests/src/psa_test_wrappers.c
diff -Nru mbedtls-3.6.5/tests/scripts/components-basic-checks.sh mbedtls-3.6.6/tests/scripts/components-basic-checks.sh
--- mbedtls-3.6.5/tests/scripts/components-basic-checks.sh	2025-10-14 19:12:37.018925700 +0300
+++ mbedtls-3.6.6/tests/scripts/components-basic-checks.sh	2026-03-27 19:00:27.629856300 +0200
@@ -91,7 +91,7 @@
     grep 'depends_on' \
         tests/suites/test_suite_psa*.data tests/suites/test_suite_psa*.function |
         grep -Eo '!?MBEDTLS_[^: ]*' |
-        grep -v -e MBEDTLS_PSA_ -e MBEDTLS_TEST_ |
+        grep -v -e MBEDTLS_ENTROPY_HAVE_ -e MBEDTLS_PLATFORM -e MBEDTLS_PSA_ -e MBEDTLS_TEST_ |
         sort -u > $found
 
     # Expected ones with justification - keep in sorted order by ASCII table!
diff -Nru mbedtls-3.6.5/tests/scripts/components-compiler.sh mbedtls-3.6.6/tests/scripts/components-compiler.sh
--- mbedtls-3.6.5/tests/scripts/components-compiler.sh	2025-10-14 19:12:37.019670700 +0300
+++ mbedtls-3.6.6/tests/scripts/components-compiler.sh	2026-03-27 19:00:27.630311700 +0200
@@ -172,3 +172,45 @@
         done
     done
 }
+
+# This originated from an issue (https://github.com/Mbed-TLS/TF-PSA-Crypto/issues/665) found
+# in GCM when the library is built with GCC "10.0 <= version <= 14.2" on platforms other than
+# x86 and ARM64.
+component_test_tf_psa_crypto_optimized_alignment() {
+    msg "build: verify alignment with O3 optimizations in GCC"
+
+    # Disable optimizations for x86 (and ARM64) so that alignment related problems in
+    # "alignment.h" can be tested also on standard PC.
+    scripts/config.py unset MBEDTLS_AESNI_C
+    scripts/config.py unset MBEDTLS_AESCE_C
+
+    # "-O3" is the optimization level that causes issues: the compiler tries to
+    # optimize operations order and if memory dependencies are not respected
+    # (as it happens in issue tf-psa-crypto#665) this completely messes up results.
+    EXTRA_C_FLAGS="-O3"
+    # Forcedly ignore "MBEDTLS_EFFICIENT_UNALIGNED_ACCESS" on x86 so that we
+    # can test the problematic case, i.e. the case where uint64 integers are
+    # accessed through "mbedtls_uint64_unaligned_t" structs.
+    EXTRA_C_FLAGS="$EXTRA_C_FLAGS -DMBEDTLS_ALIGNMENT_DISABLE_EFFICENT_UNALIGNED_ACCESS"
+    # Adding '-g3' flag doesn't affect testing, BUT it allows to dump the generated
+    # assembly code for "gcm.o" module for inspection. To do this use the
+    # following command:
+    # > objdump -S --disassemble out_of_source_build/drivers/builtin/CMakeFiles/builtin.dir/src/gcm.c.o > gcm.s
+    # A file named "gcm.s" will be generated containing a mix of C and corresponding
+    # assembly code.
+    EXTRA_C_FLAGS="$EXTRA_C_FLAGS -g3"
+
+    make CC=gcc CFLAGS="$EXTRA_C_FLAGS"
+
+    msg "test: verify alignment with O3 optimizations in GCC"
+    make test
+}
+
+support_test_tf_psa_crypto_optimized_alignment() {
+    case $(gcc -dumpfullversion 2>/dev/null) in
+        ""|?.*) false;; # too old
+        10.*|11.*|12.*|13.*) true;;
+        14.[012].*) true;;
+        *) false;; # too recent
+    esac
+}
diff -Nru mbedtls-3.6.5/tests/scripts/components-configuration-crypto.sh mbedtls-3.6.6/tests/scripts/components-configuration-crypto.sh
--- mbedtls-3.6.5/tests/scripts/components-configuration-crypto.sh	2025-10-14 19:12:37.020917200 +0300
+++ mbedtls-3.6.6/tests/scripts/components-configuration-crypto.sh	2026-03-27 19:00:27.630796000 +0200
@@ -882,7 +882,7 @@
 component_build_crypto_baremetal () {
   msg "build: make, crypto only, baremetal config"
   scripts/config.py crypto_baremetal
-  make CFLAGS="-O1 -Werror -I$PWD/framework/tests/include/baremetal-override/"
+  make CFLAGS="-O1 -Werror -I$PWD/framework/tests/include/baremetal-override/ -DMBEDTLS_TEST_PLATFORM_IS_NOT_UNIXLIKE"
   are_empty_libraries library/libmbedx509.* library/libmbedtls.*
 }
 
diff -Nru mbedtls-3.6.5/tests/scripts/components-configuration.sh mbedtls-3.6.6/tests/scripts/components-configuration.sh
--- mbedtls-3.6.5/tests/scripts/components-configuration.sh	2025-10-14 19:12:37.022583500 +0300
+++ mbedtls-3.6.6/tests/scripts/components-configuration.sh	2026-03-27 19:00:27.631736800 +0200
@@ -222,7 +222,7 @@
 component_build_baremetal () {
   msg "build: make, baremetal config"
   scripts/config.py baremetal
-  make CFLAGS="-O1 -Werror -I$PWD/framework/tests/include/baremetal-override/"
+  make CFLAGS="-O1 -Werror -I$PWD/framework/tests/include/baremetal-override/ -DMBEDTLS_TEST_PLATFORM_IS_NOT_UNIXLIKE"
 }
 
 support_build_baremetal () {
diff -Nru mbedtls-3.6.5/tests/scripts/components-configuration-tls.sh mbedtls-3.6.6/tests/scripts/components-configuration-tls.sh
--- mbedtls-3.6.5/tests/scripts/components-configuration-tls.sh	2025-10-14 19:12:37.021608400 +0300
+++ mbedtls-3.6.6/tests/scripts/components-configuration-tls.sh	2026-03-27 19:00:27.631241000 +0200
@@ -419,6 +419,7 @@
     cp configs/config-ccm-psk-dtls1_2.h "$CONFIG_H"
     scripts/config.py set MBEDTLS_PSA_CRYPTO_C
     scripts/config.py set MBEDTLS_USE_PSA_CRYPTO
+    scripts/config.py set MBEDTLS_HAVE_TIME
     # test-ref-configs works by overwriting mbedtls_config.h; this makes cmake
     # want to re-generate generated files that depend on it, quite correctly.
     # However this doesn't work as the generation script expects a specific
diff -Nru mbedtls-3.6.5/tests/scripts/components-configuration-x509.sh mbedtls-3.6.6/tests/scripts/components-configuration-x509.sh
--- mbedtls-3.6.5/tests/scripts/components-configuration-x509.sh	2025-10-14 19:12:37.021912800 +0300
+++ mbedtls-3.6.6/tests/scripts/components-configuration-x509.sh	2026-03-27 19:00:27.631381800 +0200
@@ -28,7 +28,8 @@
 
     # MBEDTLS_TEST_HOOKS required for x509_crt_parse_cn_inet_pton
     scripts/config.py set MBEDTLS_TEST_HOOKS
-    make CFLAGS="-DMBEDTLS_TEST_SW_INET_PTON"
+    CC=$ASAN_CC CFLAGS="-DMBEDTLS_TEST_SW_INET_PTON" cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
     msg "test: default plus MBEDTLS_TEST_SW_INET_PTON"
     make test
diff -Nru mbedtls-3.6.5/tests/src/certs.c mbedtls-3.6.6/tests/src/certs.c
--- mbedtls-3.6.5/tests/src/certs.c	2025-10-14 19:12:37.026333000 +0300
+++ mbedtls-3.6.6/tests/src/certs.c	2026-03-27 19:00:27.634058200 +0200
@@ -440,7 +440,7 @@
     mbedtls_test_ca_crt_rsa_sha1_der,
 #endif /* MBEDTLS_MD_CAN_SHA1 */
 #endif /* MBEDTLS_RSA_C */
-#if defined(MBEDTLS_PK_CAN_ECDSA_SOME)
+#if defined(MBEDTLS_PK_CAN_ECDSA_SOME) && defined(MBEDTLS_ECP_HAVE_SECP384R1)
     mbedtls_test_ca_crt_ec_der,
 #endif /* MBEDTLS_PK_CAN_ECDSA_SOME */
     NULL
@@ -455,7 +455,7 @@
     sizeof(mbedtls_test_ca_crt_rsa_sha1_der),
 #endif /* MBEDTLS_MD_CAN_SHA1 */
 #endif /* MBEDTLS_RSA_C */
-#if defined(MBEDTLS_PK_CAN_ECDSA_SOME)
+#if defined(MBEDTLS_PK_CAN_ECDSA_SOME) && defined(MBEDTLS_ECP_HAVE_SECP384R1)
     sizeof(mbedtls_test_ca_crt_ec_der),
 #endif /* MBEDTLS_PK_CAN_ECDSA_SOME */
     0
diff -Nru mbedtls-3.6.5/tests/src/psa_test_wrappers.c mbedtls-3.6.6/tests/src/psa_test_wrappers.c
--- mbedtls-3.6.5/tests/src/psa_test_wrappers.c	2025-10-14 19:12:37.026501700 +0300
+++ mbedtls-3.6.6/tests/src/psa_test_wrappers.c	2026-03-27 19:00:27.634488000 +0200
@@ -4,6 +4,10 @@
  * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  */
 
+#if !defined(__USE_MINGW_ANSI_STDIO)
+#define __USE_MINGW_ANSI_STDIO 1
+#endif
+
 #include <mbedtls/build_info.h>
 
 #if defined(MBEDTLS_PSA_CRYPTO_C) && defined(MBEDTLS_TEST_HOOKS) && \
@@ -1194,6 +1198,36 @@
     return status;
 }
 
+/* Wrapper for psa_random_deplete */
+psa_status_t mbedtls_test_wrap_psa_random_deplete(void)
+{
+    psa_status_t status = (psa_random_deplete)();
+    return status;
+}
+
+/* Wrapper for psa_random_reseed */
+psa_status_t mbedtls_test_wrap_psa_random_reseed(
+    const uint8_t *arg0_perso,
+    size_t arg1_perso_size)
+{
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_POISON(arg0_perso, arg1_perso_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    psa_status_t status = (psa_random_reseed)(arg0_perso, arg1_perso_size);
+#if !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS)
+    MBEDTLS_TEST_MEMORY_UNPOISON(arg0_perso, arg1_perso_size);
+#endif /* !defined(MBEDTLS_PSA_ASSUME_EXCLUSIVE_BUFFERS) */
+    return status;
+}
+
+/* Wrapper for psa_random_set_prediction_resistance */
+psa_status_t mbedtls_test_wrap_psa_random_set_prediction_resistance(
+    unsigned arg0_enabled)
+{
+    psa_status_t status = (psa_random_set_prediction_resistance)(arg0_enabled);
+    return status;
+}
+
 /* Wrapper for psa_raw_key_agreement */
 psa_status_t mbedtls_test_wrap_psa_raw_key_agreement(
     psa_algorithm_t arg0_alg,
diff -Nru mbedtls-3.6.5/tests/src/test_helpers/ssl_helpers.c mbedtls-3.6.6/tests/src/test_helpers/ssl_helpers.c
--- mbedtls-3.6.5/tests/src/test_helpers/ssl_helpers.c	2025-10-14 19:12:37.027106300 +0300
+++ mbedtls-3.6.6/tests/src/test_helpers/ssl_helpers.c	2026-03-27 19:00:27.634699600 +0200
@@ -97,8 +97,10 @@
     mbedtls_test_handshake_test_options *opts)
 {
 #if defined(MBEDTLS_SSL_CACHE_C)
-    mbedtls_ssl_cache_free(opts->cache);
-    mbedtls_free(opts->cache);
+    if (opts->cache != NULL) {
+        mbedtls_ssl_cache_free(opts->cache);
+        mbedtls_free(opts->cache);
+    }
 #else
     (void) opts;
 #endif
diff -Nru mbedtls-3.6.5/tests/ssl-opt.sh mbedtls-3.6.6/tests/ssl-opt.sh
--- mbedtls-3.6.5/tests/ssl-opt.sh	2025-10-14 19:12:37.028161300 +0300
+++ mbedtls-3.6.6/tests/ssl-opt.sh	2026-03-27 19:00:27.635764600 +0200
@@ -10925,6 +10925,7 @@
             "$P_CLI dtls=1 debug_level=2" \
             0 \
             -c "found fragmented DTLS handshake message" \
+            -c "Certificate handshake message has been buffered and reassembled" \
             -C "error"
 
 requires_gnutls
@@ -10934,25 +10935,30 @@
             "$P_CLI dtls=1 debug_level=2" \
             0 \
             -c "found fragmented DTLS handshake message" \
+            -c "Certificate handshake message has been buffered and reassembled" \
+            -c "ServerKeyExchange handshake message has been buffered and reassembled" \
             -C "error"
 
 requires_gnutls
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 run_test    "DTLS reassembly: more fragmentation, nbio (gnutls server)" \
-            "$G_SRV -u --mtu 128" \
+            "$G_SRV -u --mtu 109" \
             "$P_CLI dtls=1 nbio=2 debug_level=2" \
             0 \
             -c "found fragmented DTLS handshake message" \
+            -c "Certificate handshake message has been buffered and reassembled" \
+            -c "ServerKeyExchange handshake message has been buffered and reassembled" \
             -C "error"
 
 requires_gnutls
 requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 run_test    "DTLS reassembly: fragmentation, renego (gnutls server)" \
-            "$G_SRV -u --mtu 256" \
+            "$G_SRV -u --mtu 241" \
             "$P_CLI debug_level=3 dtls=1 renegotiation=1 renegotiate=1" \
             0 \
             -c "found fragmented DTLS handshake message" \
+            -c "Certificate handshake message has been buffered and reassembled" \
             -c "client hello, adding renegotiation extension" \
             -c "found renegotiation extension" \
             -c "=> renegotiate" \
@@ -10968,6 +10974,7 @@
             "$P_CLI debug_level=3 nbio=2 dtls=1 renegotiation=1 renegotiate=1" \
             0 \
             -c "found fragmented DTLS handshake message" \
+            -c "Certificate handshake message has been buffered and reassembled" \
             -c "client hello, adding renegotiation extension" \
             -c "found renegotiation extension" \
             -c "=> renegotiate" \
@@ -10975,6 +10982,52 @@
             -C "error" \
             -s "Extra-header:"
 
+requires_gnutls
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test    "DTLS reassembly: no fragmentation (gnutls client)" \
+            "$P_SRV debug_level=2 dtls=1" \
+            "$G_NEXT_CLI -u --mtu 2048 --insecure 127.0.0.1" \
+            0 \
+            -S "found fragmented DTLS handshake message" \
+            -s "HTTP/1.0 200 OK"
+
+requires_gnutls
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test    "DTLS reassembly: some fragmentation (gnutls client)" \
+            "$P_SRV debug_level=2 dtls=1 auth_mode=required" \
+            "$G_NEXT_CLI -u --mtu 211 --insecure 127.0.0.1 --x509certfile $DATA_FILES_PATH/server5.crt --x509keyfile $DATA_FILES_PATH/server5.key" \
+            0 \
+            -s "found fragmented DTLS handshake message" \
+            -s "Certificate handshake message has been buffered and reassembled" \
+            -s "HTTP/1.0 200 OK"
+
+# Set the MTU to 128 bytes. The minimum size of a DTLS 1.2 record
+# containing a ClientHello handshake message is 69 bytes, without any cookie,
+# ciphersuite, or extension. With an MTU of 128 bytes, the ClientHello handshake
+# message is therefore very likely to be fragmented, regardless of the
+# GnuTLS client version. For example, the ClientHello sent by the GnuTLS 3.7.2
+# client is 206 bytes in this test.
+requires_gnutls
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test    "DTLS reassembly: more fragmentation (gnutls client)" \
+            "$P_SRV debug_level=2 dtls=1" \
+            "$G_NEXT_CLI -u --mtu 103 --insecure 127.0.0.1" \
+            0 \
+            -s "ClientHello handshake message has been buffered and reassembled" \
+            -s "HTTP/1.0 200 OK"
+
+requires_gnutls
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test    "DTLS reassembly: more fragmentation, nbio (gnutls client)" \
+            "$P_SRV debug_level=2 dtls=1 nbio=2" \
+            "$G_NEXT_CLI -u --mtu 103 --insecure 127.0.0.1" \
+            0 \
+            -s "ClientHello handshake message has been buffered and reassembled" \
+            -s "HTTP/1.0 200 OK"
+
+# No fragmentation and renegotiation tests with GnuTLS client as the feature
+# does not work properly.
+
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 run_test    "DTLS reassembly: no fragmentation (openssl server)" \
             "$O_SRV -dtls -mtu 2048" \
@@ -10983,29 +11036,59 @@
             -C "found fragmented DTLS handshake message" \
             -C "error"
 
+# Minimum possible MTU for OpenSSL server: 256 bytes.
+# We expect the server Certificate handshake to be fragmented and verify that
+# this is the case. Depending on the configuration, other handshake messages may
+# also be fragmented.
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-run_test    "DTLS reassembly: some fragmentation (openssl server)" \
+run_test    "DTLS reassembly: fragmentation (openssl server)" \
             "$O_SRV -dtls -mtu 256" \
             "$P_CLI dtls=1 debug_level=2" \
             0 \
             -c "found fragmented DTLS handshake message" \
+            -c "Certificate handshake message has been buffered and reassembled" \
             -C "error"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-run_test    "DTLS reassembly: more fragmentation (openssl server)" \
-            "$O_SRV -dtls -mtu 256" \
-            "$P_CLI dtls=1 debug_level=2" \
+run_test    "DTLS reassembly: fragmentation, nbio (openssl server)" \
+            "$O_SRV -dtls -mtu 273" \
+            "$P_CLI dtls=1 nbio=2 debug_level=2" \
             0 \
             -c "found fragmented DTLS handshake message" \
+            -c "Certificate handshake message has been buffered and reassembled" \
             -C "error"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-run_test    "DTLS reassembly: fragmentation, nbio (openssl server)" \
-            "$O_SRV -dtls -mtu 256" \
-            "$P_CLI dtls=1 nbio=2 debug_level=2" \
+run_test    "DTLS reassembly: no fragmentation (openssl client)" \
+            "$P_SRV debug_level=2 dtls=1 auth_mode=required" \
+            "$O_NEXT_CLI -dtls -mtu 2048 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
             0 \
-            -c "found fragmented DTLS handshake message" \
-            -C "error"
+            -S "found fragmented DTLS handshake message" \
+            -s "HTTP/1.0 200 OK"
+
+# Minimum possible MTU for OpenSSL server: 256 bytes.
+# We expect the client Certificate handshake message to be fragmented and
+# verify that this is the case. With OpenSSL 3.0.13, the ClientHello handshake
+# message is 224 bytes and also fragmented. However, it may not hold across
+# OpenSSL version updates. Therefore, we do not verify that the ClientHello is
+# reassembled by the server.
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test    "DTLS reassembly: some fragmentation (openssl client)" \
+            "$P_SRV debug_level=2 dtls=1 auth_mode=required" \
+            "$O_NEXT_CLI -dtls -mtu 256 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
+            0 \
+            -s "found fragmented DTLS handshake message" \
+            -s "Certificate handshake message has been buffered and reassembled" \
+            -s "HTTP/1.0 200 OK"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test    "DTLS reassembly: fragmentation, nbio (openssl client)" \
+            "$P_SRV debug_level=2 dtls=1 auth_mode=required nbio=2" \
+            "$O_NEXT_CLI -dtls -mtu 269 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
+            0 \
+            -s "found fragmented DTLS handshake message" \
+            -s "Certificate handshake message has been buffered and reassembled" \
+            -s "HTTP/1.0 200 OK"
 
 # Tests for sending fragmented handshake messages with DTLS
 #
@@ -11248,20 +11331,20 @@
 
 requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 requires_config_enabled MBEDTLS_RSA_C
-requires_max_content_len 2048
+requires_max_content_len 1038
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-run_test    "DTLS fragmenting: both (MTU=1024)" \
-            -p "$P_PXY mtu=1024" \
+run_test    "DTLS fragmenting: both (MTU=1038)" \
+            -p "$P_PXY mtu=1038" \
             "$P_SRV dtls=1 debug_level=2 auth_mode=required \
              crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
              key_file=$DATA_FILES_PATH/server7.key \
              hs_timeout=2500-60000 \
-             mtu=1024" \
+             mtu=1038" \
             "$P_CLI dtls=1 debug_level=2 \
              crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
              key_file=$DATA_FILES_PATH/server8.key \
              hs_timeout=2500-60000 \
-             mtu=1024" \
+             mtu=1038" \
             0 \
             -s "found fragmented DTLS handshake message" \
             -c "found fragmented DTLS handshake message" \
@@ -11271,23 +11354,103 @@
 requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 requires_config_enabled MBEDTLS_RSA_C
 requires_hash_alg SHA_256
-requires_max_content_len 2048
-run_test    "DTLS fragmenting: both (MTU=512)" \
-            -p "$P_PXY mtu=512" \
+requires_max_content_len 509
+run_test    "DTLS fragmenting: both (MTU=509)" \
+            -p "$P_PXY mtu=509" \
             "$P_SRV dtls=1 debug_level=2 auth_mode=required \
              crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
              key_file=$DATA_FILES_PATH/server7.key \
              hs_timeout=2500-60000 \
-             mtu=512" \
+             mtu=509" \
             "$P_CLI dtls=1 debug_level=2 \
              crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
              key_file=$DATA_FILES_PATH/server8.key \
              force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \
              hs_timeout=2500-60000 \
-             mtu=512" \
+             mtu=509" \
+            0 \
+            -s "found fragmented DTLS handshake message" \
+            -c "found fragmented DTLS handshake message" \
+            -C "error"
+
+# Depending on the ciphersuite selected to encrypt the application data, the
+# maximum application data payload per record may be small with an MTU of 128.
+# For example, with TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384, this maximum is
+# 35 bytes. We therefore reduce the size of the client request and the server
+# response in this test and the two following tests.
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_max_content_len 128
+run_test    "DTLS fragmenting: both (MTU=128)" \
+            -p "$P_PXY mtu=128" \
+            "$P_SRV dtls=1 debug_level=5 auth_mode=required \
+             crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
+             key_file=$DATA_FILES_PATH/server7.key \
+             response_size=8 \
+             hs_timeout=2500-60000 \
+             mtu=128" \
+            "$P_CLI dtls=1 debug_level=2 \
+             crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
+             key_file=$DATA_FILES_PATH/server8.key \
+             request_size=8 \
+             hs_timeout=2500-60000 \
+             mtu=128" \
             0 \
             -s "found fragmented DTLS handshake message" \
+            -s "fragmenting Certificate handshake message" \
             -c "found fragmented DTLS handshake message" \
+            -c "fragmenting ClientHello handshake message" \
+            -c "fragmenting Certificate handshake message" \
+            -c "fragmenting CertificateVerify handshake message" \
+            -C "error"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_max_content_len 2048
+run_test    "DTLS fragmenting: both (MTU=107)" \
+            -p "$P_PXY mtu=107" \
+            "$P_SRV dtls=1 debug_level=5 auth_mode=required \
+             crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
+             key_file=$DATA_FILES_PATH/server7.key \
+             response_size=8 \
+             hs_timeout=2500-60000 \
+             mtu=107" \
+            "$P_CLI dtls=1 debug_level=2 \
+             crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
+             key_file=$DATA_FILES_PATH/server8.key \
+             request_size=8 \
+             hs_timeout=2500-60000 \
+             mtu=107" \
+            0 \
+            -s "found fragmented DTLS handshake message" \
+            -s "fragmenting Certificate handshake message" \
+            -c "found fragmented DTLS handshake message" \
+            -c "fragmenting ClientHello handshake message" \
+            -c "fragmenting Certificate handshake message" \
+            -c "fragmenting CertificateVerify handshake message" \
+            -C "error"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_max_content_len 2048
+run_test    "DTLS fragmenting: both (MTU=133)" \
+            -p "$P_PXY mtu=133" \
+            "$P_SRV dtls=1 debug_level=5 auth_mode=required \
+             crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
+             key_file=$DATA_FILES_PATH/server7.key \
+             response_size=8 \
+             hs_timeout=2500-60000 \
+             mtu=133" \
+            "$P_CLI dtls=1 debug_level=2 \
+             crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
+             key_file=$DATA_FILES_PATH/server8.key \
+             request_size=8 \
+             hs_timeout=2500-60000 \
+             mtu=133" \
+            0 \
+            -s "found fragmented DTLS handshake message" \
+            -s "fragmenting Certificate handshake message" \
+            -c "found fragmented DTLS handshake message" \
+            -c "fragmenting ClientHello handshake message" \
+            -c "fragmenting Certificate handshake message" \
+            -c "fragmenting CertificateVerify handshake message" \
             -C "error"
 
 # Test for automatic MTU reduction on repeated resend.
@@ -11343,7 +11506,7 @@
 not_with_valgrind # spurious autoreduction due to timeout
 requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 requires_config_enabled MBEDTLS_RSA_C
-requires_max_content_len 2048
+requires_max_content_len 1024
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 run_test    "DTLS fragmenting: proxy MTU, simple handshake (MTU=1024)" \
             -p "$P_PXY mtu=1024" \
@@ -11370,7 +11533,7 @@
 not_with_valgrind # spurious autoreduction due to timeout
 requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 requires_config_enabled MBEDTLS_RSA_C
-requires_max_content_len 2048
+requires_max_content_len 512
 run_test    "DTLS fragmenting: proxy MTU, simple handshake (MTU=512)" \
             -p "$P_PXY mtu=512" \
             "$P_SRV dtls=1 debug_level=2 auth_mode=required \
@@ -11393,7 +11556,7 @@
 not_with_valgrind # spurious autoreduction due to timeout
 requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 requires_config_enabled MBEDTLS_RSA_C
-requires_max_content_len 2048
+requires_max_content_len 1024
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 run_test    "DTLS fragmenting: proxy MTU, simple handshake, nbio (MTU=1024)" \
             -p "$P_PXY mtu=1024" \
@@ -11417,7 +11580,7 @@
 not_with_valgrind # spurious autoreduction due to timeout
 requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 requires_config_enabled MBEDTLS_RSA_C
-requires_max_content_len 2048
+requires_max_content_len 512
 run_test    "DTLS fragmenting: proxy MTU, simple handshake, nbio (MTU=512)" \
             -p "$P_PXY mtu=512" \
             "$P_SRV dtls=1 debug_level=2 auth_mode=required \
@@ -11450,7 +11613,7 @@
 not_with_valgrind # spurious autoreduction due to timeout
 requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 requires_config_enabled MBEDTLS_RSA_C
-requires_max_content_len 2048
+requires_max_content_len 1450
 run_test    "DTLS fragmenting: proxy MTU, resumed handshake" \
             -p "$P_PXY mtu=1450" \
             "$P_SRV dtls=1 debug_level=2 auth_mode=required \
@@ -11477,7 +11640,7 @@
 requires_config_enabled MBEDTLS_RSA_C
 requires_hash_alg SHA_256
 requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
-requires_max_content_len 2048
+requires_max_content_len 512
 run_test    "DTLS fragmenting: proxy MTU, ChachaPoly renego" \
             -p "$P_PXY mtu=512" \
             "$P_SRV dtls=1 debug_level=2 auth_mode=required \
@@ -11506,7 +11669,7 @@
 requires_config_enabled MBEDTLS_RSA_C
 requires_hash_alg SHA_256
 requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
-requires_max_content_len 2048
+requires_max_content_len 512
 run_test    "DTLS fragmenting: proxy MTU, AES-GCM renego" \
             -p "$P_PXY mtu=512" \
             "$P_SRV dtls=1 debug_level=2 auth_mode=required \
@@ -11535,7 +11698,7 @@
 requires_config_enabled MBEDTLS_RSA_C
 requires_hash_alg SHA_256
 requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
-requires_max_content_len 2048
+requires_max_content_len 1024
 run_test    "DTLS fragmenting: proxy MTU, AES-CCM renego" \
             -p "$P_PXY mtu=1024" \
             "$P_SRV dtls=1 debug_level=2 auth_mode=required \
@@ -11565,7 +11728,7 @@
 requires_hash_alg SHA_256
 requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
 requires_config_enabled MBEDTLS_SSL_ENCRYPT_THEN_MAC
-requires_max_content_len 2048
+requires_max_content_len 1024
 run_test    "DTLS fragmenting: proxy MTU, AES-CBC EtM renego" \
             -p "$P_PXY mtu=1024" \
             "$P_SRV dtls=1 debug_level=2 auth_mode=required \
@@ -11594,7 +11757,7 @@
 requires_config_enabled MBEDTLS_RSA_C
 requires_hash_alg SHA_256
 requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
-requires_max_content_len 2048
+requires_max_content_len 1024
 run_test    "DTLS fragmenting: proxy MTU, AES-CBC non-EtM renego" \
             -p "$P_PXY mtu=1024" \
             "$P_SRV dtls=1 debug_level=2 auth_mode=required \
@@ -11620,7 +11783,7 @@
 requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 requires_config_enabled MBEDTLS_RSA_C
 client_needs_more_time 2
-requires_max_content_len 2048
+requires_max_content_len 512
 run_test    "DTLS fragmenting: proxy MTU + 3d" \
             -p "$P_PXY mtu=512 drop=8 delay=8 duplicate=8" \
             "$P_SRV dgram_packing=0 dtls=1 debug_level=2 auth_mode=required \
@@ -11641,7 +11804,7 @@
 requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 requires_config_enabled MBEDTLS_RSA_C
 client_needs_more_time 2
-requires_max_content_len 2048
+requires_max_content_len 512
 run_test    "DTLS fragmenting: proxy MTU + 3d, nbio" \
             -p "$P_PXY mtu=512 drop=8 delay=8 duplicate=8" \
             "$P_SRV dtls=1 debug_level=2 auth_mode=required \
@@ -11666,14 +11829,30 @@
 requires_config_enabled MBEDTLS_RSA_C
 requires_gnutls
 requires_max_content_len 2048
-run_test    "DTLS fragmenting: gnutls server, DTLS 1.2" \
+run_test    "DTLS fragmenting: MTU=501, gnutls server, DTLS 1.2" \
             "$G_SRV -u" \
             "$P_CLI dtls=1 debug_level=2 \
              crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
              key_file=$DATA_FILES_PATH/server8.key \
-             mtu=512 force_version=dtls12" \
+             mtu=501 force_version=dtls12" \
+            0 \
+            -c "fragmenting Certificate handshake message" \
+            -C "error"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_gnutls
+requires_max_content_len 2048
+run_test    "DTLS fragmenting: MTU=110, gnutls server, DTLS 1.2" \
+            "$G_NEXT_SRV -u" \
+            "$P_CLI dtls=1 debug_level=2 \
+             crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
+             key_file=$DATA_FILES_PATH/server8.key \
+             request_size=35 \
+             mtu=110 force_version=dtls12" \
             0 \
-            -c "fragmenting handshake message" \
+            -c "fragmenting ClientHello handshake message" \
+            -c "fragmenting Certificate handshake message" \
             -C "error"
 
 # We use --insecure for the GnuTLS client because it expects
@@ -11688,39 +11867,84 @@
 requires_gnutls
 requires_not_i686
 requires_max_content_len 2048
-run_test    "DTLS fragmenting: gnutls client, DTLS 1.2" \
+run_test    "DTLS fragmenting: MTU=536, gnutls client, DTLS 1.2" \
             "$P_SRV dtls=1 debug_level=2 \
              crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
              key_file=$DATA_FILES_PATH/server7.key \
-             mtu=512 force_version=dtls12" \
+             mtu=536 force_version=dtls12" \
+            "$G_CLI -u --insecure 127.0.0.1" \
+            0 \
+            -s "fragmenting Certificate handshake message"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_gnutls
+requires_not_i686
+requires_max_content_len 2048
+run_test    "DTLS fragmenting: MTU=149, gnutls client, DTLS 1.2" \
+            "$P_SRV dtls=1 debug_level=2 \
+             crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
+             key_file=$DATA_FILES_PATH/server7.key \
+             mtu=149 force_version=dtls12" \
             "$G_CLI -u --insecure 127.0.0.1" \
             0 \
-            -s "fragmenting handshake message"
+            -s "fragmenting Certificate handshake message"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 requires_config_enabled MBEDTLS_RSA_C
 requires_max_content_len 2048
-run_test    "DTLS fragmenting: openssl server, DTLS 1.2" \
+run_test    "DTLS fragmenting: MTU=525, openssl server, DTLS 1.2" \
             "$O_SRV -dtls1_2 -verify 10" \
             "$P_CLI dtls=1 debug_level=2 \
              crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
              key_file=$DATA_FILES_PATH/server8.key \
-             mtu=512 force_version=dtls12" \
+             mtu=525 force_version=dtls12" \
             0 \
-            -c "fragmenting handshake message" \
+            -c "fragmenting Certificate handshake message" \
             -C "error"
 
+# Depending on the ciphersuite selected to encrypt the application data, the
+# maximum application data payload per record may be small with an MTU of 128.
+# For example, with TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384, this maximum is
+# 35 bytes. We therefore reduce the size of the client request in this test.
 requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 requires_config_enabled MBEDTLS_RSA_C
 requires_max_content_len 2048
-run_test    "DTLS fragmenting: openssl client, DTLS 1.2" \
+run_test    "DTLS fragmenting: MTU=130, openssl server, DTLS 1.2" \
+            "$O_NEXT_SRV -dtls1_2 -verify 10" \
+            "$P_CLI dtls=1 debug_level=2 \
+             crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
+             key_file=$DATA_FILES_PATH/server8.key \
+             request_size=8 \
+             mtu=130 force_version=dtls12" \
+            0 \
+            -c "fragmenting ClientHello handshake message" \
+            -c "fragmenting Certificate handshake message" \
+            -C "error"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_max_content_len 2048
+run_test    "DTLS fragmenting: MTU=512, openssl client, DTLS 1.2" \
             "$P_SRV dtls=1 debug_level=2 \
              crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
              key_file=$DATA_FILES_PATH/server7.key \
              mtu=512 force_version=dtls12" \
             "$O_CLI -dtls1_2" \
             0 \
-            -s "fragmenting handshake message"
+            -s "fragmenting Certificate handshake message"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_max_content_len 2048
+run_test    "DTLS fragmenting: MTU=131, openssl client, DTLS 1.2" \
+            "$P_SRV dtls=1 debug_level=2 \
+             crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
+             key_file=$DATA_FILES_PATH/server7.key \
+             mtu=131 force_version=dtls12" \
+            "$O_CLI -dtls1_2" \
+            0 \
+            -s "fragmenting Certificate handshake message"
 
 # interop tests for DTLS fragmentating with unreliable connection
 #
@@ -11731,15 +11955,33 @@
 requires_config_enabled MBEDTLS_RSA_C
 client_needs_more_time 4
 requires_max_content_len 2048
-run_test    "DTLS fragmenting: 3d, gnutls server, DTLS 1.2" \
+run_test    "DTLS fragmenting: 3d, MTU=434, gnutls server, DTLS 1.2" \
             -p "$P_PXY drop=8 delay=8 duplicate=8" \
             "$G_NEXT_SRV -u" \
             "$P_CLI dgram_packing=0 dtls=1 debug_level=2 \
              crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
              key_file=$DATA_FILES_PATH/server8.key \
-             hs_timeout=250-60000 mtu=512 force_version=dtls12" \
+             hs_timeout=250-60000 mtu=434 force_version=dtls12" \
             0 \
-            -c "fragmenting handshake message" \
+            -c "fragmenting Certificate handshake message" \
+            -C "error"
+
+requires_gnutls_next
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+client_needs_more_time 6
+requires_max_content_len 2048
+run_test    "DTLS fragmenting: 3d, MTU=103, gnutls server, DTLS 1.2" \
+            -p "$P_PXY drop=8 delay=8 duplicate=8" \
+            "$G_NEXT_SRV -u" \
+            "$P_CLI dgram_packing=0 dtls=1 debug_level=2 \
+             crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
+             key_file=$DATA_FILES_PATH/server8.key \
+             request_size=35 \
+             hs_timeout=250-60000 mtu=103 force_version=dtls12" \
+            0 \
+            -c "fragmenting ClientHello handshake message" \
+            -c "fragmenting Certificate handshake message" \
             -C "error"
 
 requires_gnutls_next
@@ -11747,15 +11989,30 @@
 requires_config_enabled MBEDTLS_RSA_C
 client_needs_more_time 4
 requires_max_content_len 2048
-run_test    "DTLS fragmenting: 3d, gnutls client, DTLS 1.2" \
+run_test    "DTLS fragmenting: 3d, MTU=614, gnutls client, DTLS 1.2" \
             -p "$P_PXY drop=8 delay=8 duplicate=8" \
             "$P_SRV dtls=1 debug_level=2 \
              crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
              key_file=$DATA_FILES_PATH/server7.key \
-             hs_timeout=250-60000 mtu=512 force_version=dtls12" \
+             hs_timeout=250-60000 mtu=614 force_version=dtls12" \
+           "$G_NEXT_CLI -u --insecure 127.0.0.1" \
+            0 \
+            -s "fragmenting Certificate handshake message"
+
+requires_gnutls_next
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+client_needs_more_time 4
+requires_max_content_len 2048
+run_test    "DTLS fragmenting: 3d, MTU=116, gnutls client, DTLS 1.2" \
+            -p "$P_PXY drop=8 delay=8 duplicate=8" \
+            "$P_SRV dtls=1 debug_level=2 \
+             crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
+             key_file=$DATA_FILES_PATH/server7.key \
+             hs_timeout=250-60000 mtu=116 force_version=dtls12" \
            "$G_NEXT_CLI -u --insecure 127.0.0.1" \
             0 \
-            -s "fragmenting handshake message"
+            -s "fragmenting Certificate handshake message"
 
 ## The test below requires 1.1.1a or higher version of openssl, otherwise
 ## it might trigger a bug due to openssl server (https://github.com/openssl/openssl/issues/6902)
@@ -11764,15 +12021,37 @@
 requires_config_enabled MBEDTLS_RSA_C
 client_needs_more_time 4
 requires_max_content_len 2048
-run_test    "DTLS fragmenting: 3d, openssl server, DTLS 1.2" \
+run_test    "DTLS fragmenting: 3d, MTU=541, openssl server, DTLS 1.2" \
             -p "$P_PXY drop=8 delay=8 duplicate=8" \
             "$O_NEXT_SRV -dtls1_2 -verify 10" \
             "$P_CLI dtls=1 debug_level=2 \
              crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
              key_file=$DATA_FILES_PATH/server8.key \
-             hs_timeout=250-60000 mtu=512 force_version=dtls12" \
+             hs_timeout=250-60000 mtu=541 force_version=dtls12" \
+            0 \
+            -c "fragmenting Certificate handshake message" \
+            -C "error"
+
+# Depending on the ciphersuite selected to encrypt the application data, the
+# maximum application data payload per record may be small with an MTU of 128.
+# For example, with TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384, this maximum is
+# 35 bytes. We therefore reduce the size of the client request in this test.
+requires_openssl_next
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+client_needs_more_time 4
+requires_max_content_len 2048
+run_test    "DTLS fragmenting: 3d, MTU=108, openssl server, DTLS 1.2" \
+            -p "$P_PXY drop=8 delay=8 duplicate=8" \
+            "$O_NEXT_SRV -dtls1_2 -verify 10" \
+            "$P_CLI dtls=1 debug_level=2 \
+             crt_file=$DATA_FILES_PATH/server8_int-ca2.crt \
+             key_file=$DATA_FILES_PATH/server8.key \
+             request_size=8 \
+             hs_timeout=250-60000 mtu=108 force_version=dtls12" \
             0 \
-            -c "fragmenting handshake message" \
+            -c "fragmenting ClientHello handshake message" \
+            -c "fragmenting Certificate handshake message" \
             -C "error"
 
 ## the test below will time out with certain seed.
@@ -11782,7 +12061,7 @@
 requires_config_enabled MBEDTLS_RSA_C
 client_needs_more_time 4
 requires_max_content_len 2048
-run_test    "DTLS fragmenting: 3d, openssl client, DTLS 1.2" \
+run_test    "DTLS fragmenting: 3d, MTU=512, openssl client, DTLS 1.2" \
             -p "$P_PXY drop=8 delay=8 duplicate=8" \
             "$P_SRV dtls=1 debug_level=2 \
              crt_file=$DATA_FILES_PATH/server7_int-ca.crt \
@@ -11790,7 +12069,7 @@
              hs_timeout=250-60000 mtu=512 force_version=dtls12" \
             "$O_CLI -dtls1_2" \
             0 \
-            -s "fragmenting handshake message"
+            -s "fragmenting Certificate handshake message"
 
 # Tests for DTLS-SRTP (RFC 5764)
 requires_config_enabled MBEDTLS_SSL_DTLS_SRTP
@@ -12507,9 +12786,9 @@
             hs_timeout=2500-60000" \
             0 \
             -c "Buffering HS message" \
-            -c "Next handshake message has been buffered - load"\
+            -c "Certificate handshake message has been buffered$"\
             -S "Buffering HS message" \
-            -S "Next handshake message has been buffered - load"\
+            -S "handshake message has been buffered"\
             -C "Injecting buffered CCS message" \
             -C "Remember CCS message" \
             -S "Injecting buffered CCS message" \
@@ -12527,9 +12806,9 @@
             -c "Buffering HS message" \
             -c "found fragmented DTLS handshake message"\
             -c "Next handshake message 1 not or only partially buffered" \
-            -c "Next handshake message has been buffered - load"\
+            -c "Certificate handshake message has been buffered and reassembled"\
             -S "Buffering HS message" \
-            -S "Next handshake message has been buffered - load"\
+            -S "handshake message has been buffered" \
             -C "Injecting buffered CCS message" \
             -C "Remember CCS message" \
             -S "Injecting buffered CCS message" \
@@ -12550,10 +12829,11 @@
             hs_timeout=2500-60000" \
             0 \
             -c "Buffering HS message" \
-            -c "Next handshake message has been buffered - load"\
+            -c "Certificate handshake message has been buffered and reassembled"\
+            -c "ServerKeyExchange handshake message has been buffered$"\
             -C "attempt to make space by freeing buffered messages" \
             -S "Buffering HS message" \
-            -S "Next handshake message has been buffered - load"\
+            -S "handshake message has been buffered" \
             -C "Injecting buffered CCS message" \
             -C "Remember CCS message" \
             -S "Injecting buffered CCS message" \
@@ -12577,7 +12857,7 @@
             -c "attempt to make space by freeing buffered future messages" \
             -c "Enough space available after freeing buffered HS messages" \
             -S "Buffering HS message" \
-            -S "Next handshake message has been buffered - load"\
+            -S "handshake message has been buffered" \
             -C "Injecting buffered CCS message" \
             -C "Remember CCS message" \
             -S "Injecting buffered CCS message" \
@@ -12593,9 +12873,9 @@
             hs_timeout=2500-60000" \
             0 \
             -C "Buffering HS message" \
-            -C "Next handshake message has been buffered - load"\
+            -C "handshake message has been buffered" \
             -s "Buffering HS message" \
-            -s "Next handshake message has been buffered - load" \
+            -s "ClientKeyExchange handshake message has been buffered$" \
             -C "Injecting buffered CCS message" \
             -C "Remember CCS message" \
             -S "Injecting buffered CCS message" \
@@ -12612,9 +12892,9 @@
             hs_timeout=2500-60000" \
             0 \
             -C "Buffering HS message" \
-            -C "Next handshake message has been buffered - load"\
+            -C "handshake message has been buffered" \
             -S "Buffering HS message" \
-            -S "Next handshake message has been buffered - load" \
+            -S "handshake message has been buffered" \
             -c "Injecting buffered CCS message" \
             -c "Remember CCS message" \
             -S "Injecting buffered CCS message" \
@@ -12630,9 +12910,9 @@
             hs_timeout=2500-60000" \
             0 \
             -C "Buffering HS message" \
-            -C "Next handshake message has been buffered - load"\
+            -C "handshake message has been buffered" \
             -S "Buffering HS message" \
-            -S "Next handshake message has been buffered - load" \
+            -S "handshake message has been buffered" \
             -C "Injecting buffered CCS message" \
             -C "Remember CCS message" \
             -s "Injecting buffered CCS message" \
@@ -12868,10 +13148,11 @@
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 run_test    "DTLS proxy: 3d, openssl server, fragmentation" \
             -p "$P_PXY drop=5 delay=5 duplicate=5 protect_hvr=1" \
-            "$O_NEXT_SRV -dtls1_2 -mtu 768" \
-            "$P_CLI dgram_packing=0 dtls=1 hs_timeout=500-60000 tickets=0" \
+            "$O_NEXT_SRV -dtls1_2 -mtu 277" \
+            "$P_CLI dgram_packing=0 dtls=1 debug_level=2 hs_timeout=500-60000 tickets=0" \
             0 \
-            -c "HTTP/1.0 200 OK"
+            -c "HTTP/1.0 200 OK" \
+            -c "Certificate handshake message has been buffered and reassembled"
 
 requires_openssl_next
 client_needs_more_time 8
@@ -12879,10 +13160,56 @@
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 run_test    "DTLS proxy: 3d, openssl server, fragmentation, nbio" \
             -p "$P_PXY drop=5 delay=5 duplicate=5 protect_hvr=1" \
-            "$O_NEXT_SRV -dtls1_2 -mtu 768" \
-            "$P_CLI dgram_packing=0 dtls=1 hs_timeout=500-60000 nbio=2 tickets=0" \
+            "$O_NEXT_SRV -dtls1_2 -mtu 268" \
+            "$P_CLI dgram_packing=0 dtls=1 debug_level=2 hs_timeout=500-60000 nbio=2 tickets=0" \
             0 \
-            -c "HTTP/1.0 200 OK"
+            -c "HTTP/1.0 200 OK" \
+            -c "Certificate handshake message has been buffered and reassembled"
+
+requires_openssl_next
+client_needs_more_time 6
+not_with_valgrind # risk of non-mbedtls peer timing out
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test    "DTLS proxy: 3d, openssl client" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$P_SRV dgram_packing=0 dtls=1 hs_timeout=500-60000 tickets=0" \
+            "$O_NEXT_CLI -dtls1_2 -mtu 2048" \
+            0 \
+            -s "HTTP/1.0 200 OK"
+
+# The following test fails intermittently on the CI with a frequency that
+# significantly impacts CI throughput. Disable it for the time being.
+# See https://github.com/Mbed-TLS/mbedtls/issues/10652 for more information.
+skip_next_test
+requires_openssl_next
+client_needs_more_time 8
+not_with_valgrind # risk of non-mbedtls peer timing out
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test    "DTLS proxy: 3d, openssl client, fragmentation" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$P_SRV debug_level=2 dgram_packing=0 auth_mode=required dtls=1 hs_timeout=500-60000 tickets=0" \
+            "$O_NEXT_CLI -dtls1_2 -mtu 260 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
+            0 \
+            -s "HTTP/1.0 200 OK" \
+            -s "found fragmented DTLS handshake message" \
+            -s "Certificate handshake message has been buffered and reassembled"
+
+# The following test fails intermittently on the CI with a frequency that
+# significantly impacts CI throughput. Disable it for the time being.
+# See https://github.com/Mbed-TLS/mbedtls/issues/10652 for more information.
+skip_next_test
+requires_openssl_next
+client_needs_more_time 8
+not_with_valgrind # risk of non-mbedtls peer timing out
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test    "DTLS proxy: 3d, openssl client, fragmentation, nbio" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$P_SRV debug_level=2 dgram_packing=0 auth_mode=required dtls=1 hs_timeout=500-60000 nbio=2 tickets=0" \
+            "$O_NEXT_CLI -dtls1_2 -mtu 259 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
+            0 \
+            -s "HTTP/1.0 200 OK" \
+            -s "found fragmented DTLS handshake message" \
+            -s "Certificate handshake message has been buffered and reassembled"
 
 requires_gnutls
 client_needs_more_time 6
@@ -12902,11 +13229,12 @@
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 run_test    "DTLS proxy: 3d, gnutls server, fragmentation" \
             -p "$P_PXY drop=5 delay=5 duplicate=5" \
-            "$G_NEXT_SRV -u --mtu 512" \
-            "$P_CLI dgram_packing=0 dtls=1 hs_timeout=500-60000" \
+            "$G_NEXT_SRV -u --mtu 499" \
+            "$P_CLI dgram_packing=0 dtls=1 debug_level=2 hs_timeout=500-60000" \
             0 \
             -s "Extra-header:" \
-            -c "Extra-header:"
+            -c "Extra-header:" \
+            -c "Certificate handshake message has been buffered and reassembled"
 
 requires_gnutls_next
 client_needs_more_time 8
@@ -12914,11 +13242,62 @@
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 run_test    "DTLS proxy: 3d, gnutls server, fragmentation, nbio" \
             -p "$P_PXY drop=5 delay=5 duplicate=5" \
-            "$G_NEXT_SRV -u --mtu 512" \
-            "$P_CLI dgram_packing=0 dtls=1 hs_timeout=500-60000 nbio=2" \
+            "$G_NEXT_SRV -u --mtu 528" \
+            "$P_CLI dgram_packing=0 dtls=1 debug_level=2 hs_timeout=500-60000 nbio=2" \
             0 \
             -s "Extra-header:" \
-            -c "Extra-header:"
+            -c "Extra-header:" \
+            -c "Certificate handshake message has been buffered and reassembled"
+
+requires_gnutls
+client_needs_more_time 6
+not_with_valgrind # risk of non-mbedtls peer timing out
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test    "DTLS proxy: 3d, gnutls client" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$P_SRV dgram_packing=0 dtls=1" \
+            "$G_NEXT_CLI -u --mtu 2048 --insecure 127.0.0.1" \
+            0 \
+            -s "HTTP/1.0 200 OK"
+
+# Set the MTU to 131 bytes. The ClientHello is not guaranteed to be surely
+# fragmented but it is very likely. For example, the ClientHello sent by the
+# GnuTLS 3.7.2 client is 206 bytes in this test. We expect ClientHello
+# fragmentation to remain the case across GnuTLS version updates. Avoid using a
+# smaller MTU, as the smaller the MTU, the more likely the handshake is to fail
+# in this very unreliable connection emulation.
+
+# The following test fails intermittently on the CI with a frequency that
+# significantly impacts CI throughput. Disable it for the time being.
+# See https://github.com/Mbed-TLS/mbedtls/issues/10652 for more information.
+skip_next_test
+requires_gnutls
+client_needs_more_time 8
+not_with_valgrind # risk of non-mbedtls peer timing out
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test    "DTLS proxy: 3d, gnutls client, fragmentation" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$P_SRV dgram_packing=0 dtls=1 debug_level=2" \
+            "$G_NEXT_CLI -u --mtu 131 --insecure 127.0.0.1" \
+            0 \
+            -s "HTTP/1.0 200 OK" \
+            -s "ClientHello handshake message has been buffered and reassembled"
+
+# The following test fails intermittently on the CI with a frequency that
+# significantly impacts CI throughput. Disable it for the time being.
+# See https://github.com/Mbed-TLS/mbedtls/issues/10652 for more information.
+skip_next_test
+requires_gnutls
+client_needs_more_time 8
+not_with_valgrind # risk of non-mbedtls peer timing out
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test    "DTLS proxy: 3d, gnutls client, fragmentation, nbio=2" \
+            -p "$P_PXY drop=5 delay=5 duplicate=5" \
+            "$P_SRV dgram_packing=0 dtls=1  debug_level=2 nbio=2" \
+            "$G_NEXT_CLI -u --mtu 135 --insecure 127.0.0.1" \
+            0 \
+            -s "HTTP/1.0 200 OK" \
+            -s "ClientHello handshake message has been buffered and reassembled"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 run_test    "export keys functionality" \
@@ -14793,16 +15172,6 @@
 
 # Most test cases are in opt-testcases/handshake-generated.sh
 
-requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-requires_certificate_authentication
-run_test    "Handshake defragmentation on server: len=32, TLS 1.2 ClientHello (unsupported)" \
-            "$P_SRV debug_level=4 force_version=tls12 auth_mode=required" \
-            "$O_NEXT_CLI -tls1_2 -split_send_frag 32 -cert $DATA_FILES_PATH/server5.crt -key $DATA_FILES_PATH/server5.key" \
-            1 \
-            -s "The SSL configuration is tls12 only" \
-            -s "bad client hello message" \
-            -s "SSL - A message could not be parsed due to a syntactic error"
-
 # Test server-side buffer resizing with fragmented handshake on TLS1.2
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
@@ -14853,7 +15222,6 @@
             -s "Consume: waiting for more handshake fragments 256/" \
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
 run_test    "Handshake defragmentation on server: len=128, client-initiated renegotiation" \
             "$P_SRV debug_level=4 exchanges=2 renegotiation=1 auth_mode=required" \
@@ -14870,7 +15238,6 @@
             -s "Consume: waiting for more handshake fragments 128/" \
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
 run_test    "Handshake defragmentation on server: len=4, client-initiated renegotiation" \
             "$P_SRV debug_level=4 exchanges=2 renegotiation=1 auth_mode=required" \
@@ -14887,7 +15254,6 @@
             -s "Consume: waiting for more handshake fragments 4/" \
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
 requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
 run_test    "Handshake defragmentation on server: len=4, client-initiated server-rejected renegotiation" \
             "$P_SRV debug_level=4 exchanges=2 renegotiation=0 auth_mode=required" \
diff -Nru mbedtls-3.6.5/tests/suites/host_test.function mbedtls-3.6.6/tests/suites/host_test.function
--- mbedtls-3.6.5/tests/suites/host_test.function	2025-10-14 19:12:37.028993100 +0300
+++ mbedtls-3.6.6/tests/suites/host_test.function	2026-03-27 19:00:27.636060000 +0200
@@ -275,7 +275,12 @@
  * \return      0 for success else 1
  */
 #if defined(__GNUC__)
+#  if defined(__dietlibc__)
+/* __noinline__ is a macro in dietlibc... */
+__attribute__((noinline))
+#  else
 __attribute__((__noinline__))
+#  endif
 #endif
 static int test_snprintf(size_t n, const char *ref_buf, int ref_ret)
 {
diff -Nru mbedtls-3.6.5/tests/suites/main_test.function mbedtls-3.6.6/tests/suites/main_test.function
--- mbedtls-3.6.5/tests/suites/main_test.function	2025-10-14 19:12:37.029244200 +0300
+++ mbedtls-3.6.6/tests/suites/main_test.function	2026-03-27 19:00:27.636150800 +0200
@@ -23,6 +23,17 @@
 #endif
 #endif
 
+#if defined(__FreeBSD__)
+/* On FreeBSD as of 14.3, no value of _POSIX_C_SOURCE is enough for
+ * gettimeofday(), you need _XOPEN_SOURCE (any value).
+ * Furthermore, setting _XOPEN_SOURCE to 500 removes support for long long
+ * in libc, so you need at least 600 for e.g. strtoull().
+ */
+#if !defined(_XOPEN_SOURCE)
+#define _XOPEN_SOURCE 600
+#endif
+#endif
+
 #include "mbedtls/build_info.h"
 
 /* Test code may use deprecated identifiers only if the preprocessor symbol
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_ccm.data mbedtls-3.6.6/tests/suites/test_suite_ccm.data
--- mbedtls-3.6.5/tests/suites/test_suite_ccm.data	2025-10-14 19:12:37.045104500 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_ccm.data	2026-03-27 19:00:27.646350000 +0200
@@ -1746,6 +1746,72 @@
 depends_on:MBEDTLS_CCM_GCM_CAN_AES
 mbedtls_ccm_instant_finish:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_STAR_DECRYPT:"54caf96ef6d448734700aadab50faf7a":"a3803e752ae849c910d8da36af"
 
+CCM finish check-boundary encrypt tag_len=8, finish_tag_len=32
+depends_on:MBEDTLS_CCM_GCM_CAN_AES
+mbedtls_ccm_finish_boundary:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_ENCRYPT:8:32:MBEDTLS_ERR_CCM_BAD_INPUT
+
+CCM finish check-boundary encrypt tag_len=8, finish_tag_len=8
+depends_on:MBEDTLS_CCM_GCM_CAN_AES
+mbedtls_ccm_finish_boundary:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_ENCRYPT:8:8:0
+
+CCM finish check-boundary decrypt tag_len=8, finish_tag_len=32
+depends_on:MBEDTLS_CCM_GCM_CAN_AES
+mbedtls_ccm_finish_boundary:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_DECRYPT:8:32:MBEDTLS_ERR_CCM_BAD_INPUT
+
+CCM finish check-boundary decrypt tag_len=8, finish_tag_len=8
+depends_on:MBEDTLS_CCM_GCM_CAN_AES
+mbedtls_ccm_finish_boundary:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_DECRYPT:8:8:0
+
+CCM finish check-boundary encrypt tag_len=0, finish_tag_len=0
+depends_on:MBEDTLS_CCM_GCM_CAN_AES
+mbedtls_ccm_finish_boundary:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_ENCRYPT:0:0:MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
+
+CCM finish check-boundary decrypt tag_len=0, finish_tag_len=0
+depends_on:MBEDTLS_CCM_GCM_CAN_AES
+mbedtls_ccm_finish_boundary:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_DECRYPT:0:0:MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
+
+# CCM finish boundary matrix (encrypt)
+CCM finish check-boundary encrypt tag_len=16, finish_tag_len=16
+depends_on:MBEDTLS_CCM_GCM_CAN_AES
+mbedtls_ccm_finish_boundary:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_ENCRYPT:16:16:0
+
+CCM finish check-boundary encrypt tag_len=8, finish_tag_len=16
+depends_on:MBEDTLS_CCM_GCM_CAN_AES
+mbedtls_ccm_finish_boundary:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_ENCRYPT:8:16:MBEDTLS_ERR_CCM_BAD_INPUT
+
+CCM finish check-boundary encrypt tag_len=16, finish_tag_len=17
+depends_on:MBEDTLS_CCM_GCM_CAN_AES
+mbedtls_ccm_finish_boundary:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_ENCRYPT:16:17:MBEDTLS_ERR_CCM_BAD_INPUT
+
+CCM finish check-boundary encrypt tag_len=16, finish_tag_len=4000
+depends_on:MBEDTLS_CCM_GCM_CAN_AES
+mbedtls_ccm_finish_boundary:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_ENCRYPT:16:4000:MBEDTLS_ERR_CCM_BAD_INPUT
+
+CCM finish check-boundary encrypt tag_len=16, finish_tag_len=8
+depends_on:MBEDTLS_CCM_GCM_CAN_AES
+mbedtls_ccm_finish_boundary:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_ENCRYPT:16:8:MBEDTLS_ERR_CCM_BAD_INPUT
+
+# CCM finish boundary matrix (decrypt)
+CCM finish check-boundary decrypt tag_len=16, finish_tag_len=16
+depends_on:MBEDTLS_CCM_GCM_CAN_AES
+mbedtls_ccm_finish_boundary:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_DECRYPT:16:16:0
+
+CCM finish check-boundary decrypt tag_len=8, finish_tag_len=16
+depends_on:MBEDTLS_CCM_GCM_CAN_AES
+mbedtls_ccm_finish_boundary:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_DECRYPT:8:16:MBEDTLS_ERR_CCM_BAD_INPUT
+
+CCM finish check-boundary decrypt tag_len=16, finish_tag_len=17
+depends_on:MBEDTLS_CCM_GCM_CAN_AES
+mbedtls_ccm_finish_boundary:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_DECRYPT:16:17:MBEDTLS_ERR_CCM_BAD_INPUT
+
+CCM finish check-boundary decrypt tag_len=16, finish_tag_len=4000
+depends_on:MBEDTLS_CCM_GCM_CAN_AES
+mbedtls_ccm_finish_boundary:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_DECRYPT:16:4000:MBEDTLS_ERR_CCM_BAD_INPUT
+
+CCM finish check-boundary decrypt tag_len=16, finish_tag_len=8
+depends_on:MBEDTLS_CCM_GCM_CAN_AES
+mbedtls_ccm_finish_boundary:MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_DECRYPT:16:8:MBEDTLS_ERR_CCM_BAD_INPUT
+
 CCM pass unexpected auth data, NIST VPT AES-128 #14 (P=13, N=13, A=32, T=16)
 depends_on:MBEDTLS_CCM_GCM_CAN_AES
 mbedtls_ccm_unexpected_ad::MBEDTLS_CIPHER_ID_AES:MBEDTLS_CCM_ENCRYPT:"d32088d50df9aba14d9022c870a0cb85":"e16c69861efc206e85aab1255e":"0eff7d7bcceb873c3203a8df74f4e91b04bd607ec11202f96cfeb99f5bcdb7aa"
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_ccm.function mbedtls-3.6.6/tests/suites/test_suite_ccm.function
--- mbedtls-3.6.5/tests/suites/test_suite_ccm.function	2025-10-14 19:12:37.045282600 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_ccm.function	2026-03-27 19:00:27.646475000 +0200
@@ -1,5 +1,6 @@
 /* BEGIN_HEADER */
 #include "mbedtls/ccm.h"
+#include "mbedtls/error.h"
 
 /* Use the multipart interface to process the encrypted data in two parts
  * and check that the output matches the expected output.
@@ -905,4 +906,48 @@
     mbedtls_ccm_free(&ctx);
     BLOCK_CIPHER_PSA_DONE();
 }
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mbedtls_ccm_finish_boundary(int cipher_id, int mode,
+                                 int start_tag_len, int finish_tag_len,
+                                 int expected_finish_ret)
+{
+    unsigned char key[16];
+    unsigned char iv[13];
+    /* Test does not rely on data/iv.Using Arbitrary values */
+    memset(key, 42, sizeof(key));
+    memset(iv, 11, sizeof(iv));
+
+    mbedtls_ccm_context ctx;
+    unsigned char *tag = NULL;
+
+    mbedtls_ccm_init(&ctx);
+
+    BLOCK_CIPHER_PSA_INIT();
+    TEST_EQUAL(mbedtls_ccm_setkey(&ctx, cipher_id, key, sizeof(key) * 8), 0);
+
+
+    /* For non-CCM* with tag_len=0, validate the mbedtls_ccm_set_lengths path
+     * when ccm_calculate_first_block_if_ready() fails. */
+    if (start_tag_len == 0) {
+        TEST_EQUAL(0, mbedtls_ccm_set_lengths(&ctx, 0, 0, (size_t) start_tag_len));
+        TEST_EQUAL(MBEDTLS_ERR_CCM_BAD_INPUT,
+                   mbedtls_ccm_starts(&ctx, mode, iv, sizeof(iv)));
+
+        /* Use the caller-provided tag length during setup, then finish with a
+         * different tag length to exercise boundary handling/API compliance */
+    } else {
+        TEST_EQUAL(0, mbedtls_ccm_starts(&ctx, mode, iv, sizeof(iv)));
+        TEST_EQUAL(0, mbedtls_ccm_set_lengths(&ctx, 0, 0, (size_t) start_tag_len));
+    }
+
+    TEST_CALLOC(tag, finish_tag_len);
+    TEST_EQUAL(expected_finish_ret,
+               mbedtls_ccm_finish(&ctx, tag, finish_tag_len));
+exit:
+    mbedtls_free(tag);
+    mbedtls_ccm_free(&ctx);
+    BLOCK_CIPHER_PSA_DONE();
+}
 /* END_CASE */
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_config.crypto_combinations.data mbedtls-3.6.6/tests/suites/test_suite_config.crypto_combinations.data
--- mbedtls-3.6.5/tests/suites/test_suite_config.crypto_combinations.data	2025-10-14 19:12:37.052193200 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_config.crypto_combinations.data	2026-03-27 19:00:27.651243000 +0200
@@ -12,3 +12,19 @@
 Config: ECC: Montgomery curves only
 depends_on:!MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED:MBEDTLS_ECP_MONTGOMERY_ENABLED
 pass:
+
+Config: PK export keys on the stack (PK is ECC-only) (USE_PSA)
+depends_on:PK_EXPORT_KEYS_ON_THE_STACK:MBEDTLS_USE_PSA_CRYPTO
+pass:
+
+Config: PK export keys on the stack (PK is ECC-only) (!USE_PSA)
+depends_on:PK_EXPORT_KEYS_ON_THE_STACK:!MBEDTLS_USE_PSA_CRYPTO
+pass:
+
+Config: PK export keys on the heap (PK is not ECC-only) (USE_PSA)
+depends_on:!PK_EXPORT_KEYS_ON_THE_STACK:MBEDTLS_USE_PSA_CRYPTO
+pass:
+
+Config: PK export keys on the heap (PK is not ECC-only) (!USE_PSA)
+depends_on:!PK_EXPORT_KEYS_ON_THE_STACK:!MBEDTLS_USE_PSA_CRYPTO
+pass:
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_config.function mbedtls-3.6.6/tests/suites/test_suite_config.function
--- mbedtls-3.6.5/tests/suites/test_suite_config.function	2025-10-01 18:16:57.164702700 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_config.function	2026-03-27 19:00:27.651493300 +0200
@@ -1,5 +1,5 @@
 /* BEGIN_HEADER */
-
+#include "pk_internal.h"
 /* END_HEADER */
 
 /* BEGIN_CASE */
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_debug.data mbedtls-3.6.6/tests/suites/test_suite_debug.data
--- mbedtls-3.6.5/tests/suites/test_suite_debug.data	2025-10-14 19:12:37.055056300 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_debug.data	2026-03-27 19:00:27.653398000 +0200
@@ -1,12 +1,46 @@
 printf "%" MBEDTLS_PRINTF_SIZET, 0
 printf_int_expr:PRINTF_SIZET:sizeof(size_t):0:"0"
 
+printf "%" MBEDTLS_PRINTF_SIZET, 1 byte
+printf_int_expr:PRINTF_SIZET:sizeof(size_t):42:"42"
+
+printf "%" MBEDTLS_PRINTF_SIZET, 4 bytes
+printf_int_expr:PRINTF_SIZET:sizeof(size_t):0xfedcba98:"4275878552"
+
+printf "%" MBEDTLS_PRINTF_SIZET, 8 bytes
+depends_on:SIZE_MAX>=0xffffffffffffffff
+printf_int_expr:PRINTF_SIZET:sizeof(size_t):0xfedcba9876543210:"18364758544493064720"
+
 printf "%" MBEDTLS_PRINTF_LONGLONG, 0
 printf_int_expr:PRINTF_LONGLONG:sizeof(long long):0:"0"
 
+printf "%" MBEDTLS_PRINTF_LONGLONG, 1 byte
+printf_int_expr:PRINTF_LONGLONG:sizeof(long long):42:"42"
+
+printf "%" MBEDTLS_PRINTF_LONGLONG, 4 bytes
+printf_int_expr:PRINTF_LONGLONG:sizeof(long long):0xfedcba98:"4275878552"
+
+printf "%" MBEDTLS_PRINTF_LONGLONG, 8 bytes
+printf_int_expr:PRINTF_LONGLONG:sizeof(long long):0x7edcba9876543210:"9141386507638288912"
+
+printf "%" MBEDTLS_PRINTF_LONGLONG, 8 bytes, negative
+printf_int_expr:PRINTF_LONGLONG:sizeof(long long):-0x7edcba9876543210:"-9141386507638288912"
+
 printf "%" MBEDTLS_PRINTF_MS_TIME, 0
 printf_int_expr:PRINTF_MS_TIME:sizeof(mbedtls_ms_time_t):0:"0"
 
+printf "%" MBEDTLS_PRINTF_MS_TIME, 1 byte
+printf_int_expr:PRINTF_MS_TIME:sizeof(mbedtls_ms_time_t):42:"42"
+
+printf "%" MBEDTLS_PRINTF_MS_TIME, 4 bytes
+printf_int_expr:PRINTF_MS_TIME:sizeof(mbedtls_ms_time_t):0xfedcba98:"4275878552"
+
+printf "%" MBEDTLS_PRINTF_MS_TIME, 8 bytes
+printf_int_expr:PRINTF_MS_TIME:sizeof(mbedtls_ms_time_t):0x7edcba9876543210:"9141386507638288912"
+
+printf "%" MBEDTLS_PRINTF_MS_TIME, 8 bytes, negative
+printf_int_expr:PRINTF_MS_TIME:sizeof(mbedtls_ms_time_t):-0x7edcba9876543210:"-9141386507638288912"
+
 Debug print msg (threshold 1, level 0)
 debug_print_msg_threshold:1:0:"MyFile":999:"MyFile(0999)\: Text message, 2 == 2\n"
 
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_debug.function mbedtls-3.6.6/tests/suites/test_suite_debug.function
--- mbedtls-3.6.5/tests/suites/test_suite_debug.function	2025-10-14 19:12:37.055496500 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_debug.function	2026-03-27 19:00:27.653524900 +0200
@@ -113,11 +113,11 @@
     /* Nominal case: buffer just large enough */
     TEST_CALLOC(output, n + 1);
     if ((size_t) sizeof_x <= sizeof(int)) { // Any smaller integers would be promoted to an int due to calling a vararg function
-        TEST_EQUAL(n, mbedtls_snprintf(output, n + 1, format, (int) x));
+        TEST_EQUAL(n, mbedtls_debug_snprintf(output, n + 1, format, (int) x));
     } else if (sizeof_x == sizeof(long)) {
-        TEST_EQUAL(n, mbedtls_snprintf(output, n + 1, format, (long) x));
+        TEST_EQUAL(n, mbedtls_debug_snprintf(output, n + 1, format, (long) x));
     } else if (sizeof_x == sizeof(long long)) {
-        TEST_EQUAL(n, mbedtls_snprintf(output, n + 1, format, (long long) x));
+        TEST_EQUAL(n, mbedtls_debug_snprintf(output, n + 1, format, (long long) x));
     } else {
         TEST_FAIL(
             "sizeof_x <= sizeof(int) || sizeof_x == sizeof(long) || sizeof_x == sizeof(long long)");
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_entropy.data mbedtls-3.6.6/tests/suites/test_suite_entropy.data
--- mbedtls-3.6.5/tests/suites/test_suite_entropy.data	2025-10-14 19:12:37.059346400 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_entropy.data	2026-03-27 19:00:27.656213800 +0200
@@ -4,6 +4,9 @@
 Entropy init-free-init-free
 entropy_init_free:1
 
+Entropy: count default sources
+entropy_count_sources:
+
 Create NV seed_file
 nv_seed_file_create:
 
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_entropy.function mbedtls-3.6.6/tests/suites/test_suite_entropy.function
--- mbedtls-3.6.5/tests/suites/test_suite_entropy.function	2025-10-14 19:12:37.059480200 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_entropy.function	2026-03-27 19:00:27.656295500 +0200
@@ -171,6 +171,29 @@
 }
 /* END_CASE */
 
+/* BEGIN_CASE */
+void entropy_count_sources()
+{
+    mbedtls_entropy_context ctx;
+    mbedtls_entropy_init(&ctx);
+
+#if defined(MBEDTLS_ENTROPY_HAVE_SOURCES)
+    TEST_EQUAL(MBEDTLS_ENTROPY_HAVE_SOURCES, ctx.source_count);
+#else
+    TEST_EQUAL(0, ctx.source_count);
+#endif
+
+#if defined(MBEDTLS_ENTROPY_NV_SEED)
+    TEST_EQUAL(MBEDTLS_ENTROPY_TRUE_SOURCES + 1, ctx.source_count);
+#else
+    TEST_EQUAL(MBEDTLS_ENTROPY_TRUE_SOURCES, ctx.source_count);
+#endif
+
+exit:
+    mbedtls_entropy_free(&ctx);
+}
+/* END_CASE */
+
 /* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */
 void entropy_seed_file(char *path, int ret)
 {
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_pkwrite.function mbedtls-3.6.6/tests/suites/test_suite_pkwrite.function
--- mbedtls-3.6.5/tests/suites/test_suite_pkwrite.function	2025-10-14 19:12:37.080114800 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_pkwrite.function	2026-03-27 19:00:27.670221800 +0200
@@ -66,15 +66,59 @@
     return 0;
 }
 
+static int pk_write_check_context(mbedtls_pk_context *key,
+                                  int is_public_key, int is_der,
+                                  unsigned char *check_buf, size_t check_buf_len)
+{
+    int ret = -1;
+    unsigned char *buf = NULL;
+    int expected_error = is_der ?
+                         MBEDTLS_ERR_ASN1_BUF_TOO_SMALL :
+                         MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
+
+    /* Test with:
+     * - buffer too small (all sizes)
+     * - buffer exactly the right size
+     * - buffer a bit larger - DER functions should write to the end of the
+     *   buffer, and we can only tell the difference with a larger buffer
+     */
+    for (size_t buf_size = 1; buf_size <= check_buf_len + 2; buf_size++) {
+        mbedtls_free(buf);
+        buf = NULL;
+        TEST_CALLOC(buf, buf_size);
+
+        unsigned char *start_buf = buf;
+        size_t out_len = buf_size;
+        int expected_result = buf_size < check_buf_len ? expected_error : 0;
+        mbedtls_test_set_step(buf_size);
+
+        TEST_EQUAL(pk_write_any_key(key, &start_buf, &out_len, is_public_key,
+                                    is_der), expected_result);
+
+        if (expected_result == 0) {
+            TEST_MEMORY_COMPARE(start_buf, out_len, check_buf, check_buf_len);
+
+            if (is_der) {
+                /* Data should be at the end of the buffer */
+                TEST_ASSERT(start_buf + out_len == buf + buf_size);
+            }
+        }
+    }
+
+    ret = 0;
+
+exit:
+    mbedtls_free(buf);
+    return ret;
+}
+
+
 static void pk_write_check_common(char *key_file, int is_public_key, int is_der)
 {
     mbedtls_pk_context key;
     mbedtls_pk_init(&key);
-    unsigned char *buf = NULL;
     unsigned char *check_buf = NULL;
-    unsigned char *start_buf;
-    size_t buf_len, check_buf_len;
-    int expected_result;
+    size_t check_buf_len;
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     mbedtls_svc_key_id_t opaque_id = MBEDTLS_SVC_KEY_ID_INIT;
     psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
@@ -100,8 +144,6 @@
     }
     TEST_ASSERT(check_buf_len > 0);
 
-    TEST_CALLOC(buf, check_buf_len);
-
     if (is_public_key) {
         TEST_EQUAL(mbedtls_pk_parse_public_keyfile(&key, key_file), 0);
     } else {
@@ -109,28 +151,14 @@
                                             mbedtls_test_rnd_std_rand, NULL), 0);
     }
 
-    start_buf = buf;
-    buf_len = check_buf_len;
-    if (is_der) {
-        expected_result = MBEDTLS_ERR_ASN1_BUF_TOO_SMALL;
-    } else {
-        expected_result = MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
+    if (pk_write_check_context(&key, is_public_key, is_der,
+                               check_buf, check_buf_len) != 0) {
+        goto exit;
     }
-    /* Intentionally pass a wrong size for the provided output buffer and check
-     * that the writing functions fails as expected. */
-    for (size_t i = 1; i < buf_len; i++) {
-        TEST_EQUAL(pk_write_any_key(&key, &start_buf, &i, is_public_key,
-                                    is_der), expected_result);
-    }
-    TEST_EQUAL(pk_write_any_key(&key, &start_buf, &buf_len, is_public_key,
-                                is_der), 0);
-
-    TEST_MEMORY_COMPARE(start_buf, buf_len, check_buf, check_buf_len);
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     /* Verify that pk_write works also for opaque private keys */
     if (!is_public_key) {
-        memset(buf, 0, check_buf_len);
         /* Turn the key PK context into an opaque one.
          * Note: set some practical usage for the key to make get_psa_attributes() happy. */
         TEST_EQUAL(mbedtls_pk_get_psa_attributes(&key, PSA_KEY_USAGE_SIGN_MESSAGE, &key_attr), 0);
@@ -138,18 +166,11 @@
         mbedtls_pk_free(&key);
         mbedtls_pk_init(&key);
         TEST_EQUAL(mbedtls_pk_setup_opaque(&key, opaque_id), 0);
-        start_buf = buf;
-        buf_len = check_buf_len;
-        /* Intentionally pass a wrong size for the provided output buffer and check
-         * that the writing functions fails as expected. */
-        for (size_t i = 1; i < buf_len; i++) {
-            TEST_EQUAL(pk_write_any_key(&key, &start_buf, &i, is_public_key,
-                                        is_der), expected_result);
-        }
-        TEST_EQUAL(pk_write_any_key(&key, &start_buf, &buf_len, is_public_key,
-                                    is_der), 0);
 
-        TEST_MEMORY_COMPARE(start_buf, buf_len, check_buf, check_buf_len);
+        if (pk_write_check_context(&key, is_public_key, is_der,
+                                   check_buf, check_buf_len) != 0) {
+            goto exit;
+        }
     }
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
@@ -157,7 +178,6 @@
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     psa_destroy_key(opaque_id);
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
-    mbedtls_free(buf);
     mbedtls_free(check_buf);
     mbedtls_pk_free(&key);
     USE_PSA_DONE();
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_platform.function mbedtls-3.6.6/tests/suites/test_suite_platform.function
--- mbedtls-3.6.5/tests/suites/test_suite_platform.function	2025-10-14 19:12:37.080621700 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_platform.function	2026-03-27 19:00:27.670602000 +0200
@@ -127,7 +127,7 @@
     unsigned char *buf;
     buf = mbedtls_calloc((size_t) num, (size_t) size);
     /* Dummy usage of the pointer to prevent optimizing it */
-    mbedtls_printf("calloc pointer : %p\n", buf);
+    mbedtls_printf("calloc pointer : %p\n", (void *) buf);
     TEST_ASSERT(buf == NULL);
 
 exit:
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_platform_printf.data mbedtls-3.6.6/tests/suites/test_suite_platform_printf.data
--- mbedtls-3.6.5/tests/suites/test_suite_platform_printf.data	2025-10-14 19:12:37.080762900 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_platform_printf.data	2026-03-27 19:00:27.670738000 +0200
@@ -3,58 +3,86 @@
 # and strings through the test framework.
 
 printf "%d", 0
-printf_int:"%d":0:"0"
+printf_integer:"%d":PRINTF_CAST_INT:0:"0"
 
 printf "%d", -0
-printf_int:"%d":-0:"0"
+printf_integer:"%d":PRINTF_CAST_INT:-0:"0"
 
 printf "%d", 0x0
-printf_int:"%d":0x0:"0"
+printf_integer:"%d":PRINTF_CAST_INT:0x0:"0"
 
 printf "%d", 0x00
-printf_int:"%d":0x00:"0"
+printf_integer:"%d":PRINTF_CAST_INT:0x00:"0"
 
 printf "%d", 0x000000000000000000000000000000000000000000
-printf_int:"%d":0x000000000000000000000000000000000000000000:"0"
+printf_integer:"%d":PRINTF_CAST_INT:0x000000000000000000000000000000000000000000:"0"
 
 printf "%d", -0x0
-printf_int:"%d":-0x0:"0"
+printf_integer:"%d":PRINTF_CAST_INT:-0x0:"0"
 
 printf "%d", 1
-printf_int:"%d":1:"1"
+printf_integer:"%d":PRINTF_CAST_INT:1:"1"
 
 printf "%d", 0x1
-printf_int:"%d":0x1:"1"
+printf_integer:"%d":PRINTF_CAST_INT:0x1:"1"
 
 printf "%d", 0x0000000000000000000000000000000000000000001
-printf_int:"%d":0x0000000000000000000000000000000000000000001:"1"
+printf_integer:"%d":PRINTF_CAST_INT:0x0000000000000000000000000000000000000000001:"1"
 
 printf "%d", -1
-printf_int:"%d":-1:"-1"
+printf_integer:"%d":PRINTF_CAST_INT:-1:"-1"
 
 printf "%d", -0x1
-printf_int:"%d":-0x1:"-1"
+printf_integer:"%d":PRINTF_CAST_INT:-0x1:"-1"
 
 printf "%d", -0x0000000000000000000000000000000000000000001
-printf_int:"%d":-0x0000000000000000000000000000000000000000001:"-1"
+printf_integer:"%d":PRINTF_CAST_INT:-0x0000000000000000000000000000000000000000001:"-1"
 
 printf "%d", 2147483647
-printf_int:"%d":2147483647:"2147483647"
+printf_integer:"%d":PRINTF_CAST_INT:2147483647:"2147483647"
 
 printf "%d", 0x7fffffff
-printf_int:"%d":0x7fffffff:"2147483647"
+printf_integer:"%d":PRINTF_CAST_INT:0x7fffffff:"2147483647"
 
 printf "%d", -2147483647
-printf_int:"%d":-2147483647:"-2147483647"
+printf_integer:"%d":PRINTF_CAST_INT:-2147483647:"-2147483647"
 
 printf "%d", -0x7fffffff
-printf_int:"%d":-0x7fffffff:"-2147483647"
+printf_integer:"%d":PRINTF_CAST_INT:-0x7fffffff:"-2147483647"
 
 printf "%d", -2147483648
-printf_int:"%d":-2147483648:"-2147483648"
+printf_integer:"%d":PRINTF_CAST_INT:-2147483648:"-2147483648"
 
 printf "%d", -0x80000000
-printf_int:"%d":-0x80000000:"-2147483648"
+printf_integer:"%d":PRINTF_CAST_INT:-0x80000000:"-2147483648"
+
+printf "%u", 0x80000000
+printf_integer:"%u":PRINTF_CAST_INT:-0x80000000:"2147483648"
+
+printf "%zx", 0x12345678
+depends_on:HAVE_C99_PRINTF
+printf_integer:"%zx":PRINTF_CAST_SIZE_T:0x12345678:"12345678"
+
+printf "%zu", 0x80000000
+depends_on:HAVE_C99_PRINTF
+printf_integer:"%zu":PRINTF_CAST_SIZE_T:0x80000000:"2147483648"
+
+printf "%zx", 0xffffffff
+depends_on:HAVE_C99_PRINTF
+printf_integer:"%zx":PRINTF_CAST_SIZE_T:0xffffffff:"ffffffff"
+
+printf "%zx", 0xffffffffffffffff
+depends_on:HAVE_C99_PRINTF:SIZE_T_AT_LEAST_64_BIT
+printf_integer:"%zx":PRINTF_CAST_SIZE_T:0xffffffffffffffff:"ffffffffffffffff"
+
+printf "%lld", 0x7fffffffffffffff
+printf_integer:"%lld":PRINTF_CAST_LONG_LONG:0x7fffffffffffffff:"9223372036854775807"
+
+printf "%lld", -0x8000000000000000
+printf_integer:"%lld":PRINTF_CAST_LONG_LONG:-0x8000000000000000:"-9223372036854775808"
+
+printf "%llx", 0x102030405060708
+printf_integer:"%llx":PRINTF_CAST_UNSIGNED_LONG_LONG:0x0102030405060708:"102030405060708"
 
 # Test that LONG_MAX is coming out untruncated through the test framework.
 printf "%lx", LONG_MAX
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_platform_printf.function mbedtls-3.6.6/tests/suites/test_suite_platform_printf.function
--- mbedtls-3.6.5/tests/suites/test_suite_platform_printf.function	2025-10-14 19:12:37.080966700 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_platform_printf.function	2026-03-27 19:00:27.670853900 +0200
@@ -15,6 +15,34 @@
 #include <stdlib.h>
 #include <string.h>
 
+#if SIZE_MAX >= 0xffffffffffffffff
+#define SIZE_T_AT_LEAST_64_BIT
+#endif
+
+/* Older Windows runtimes have a non-compliant printf family, e.g.
+ * it doesn't understand `%zu` to print a `size_t`. MSVC provides a
+ * C99-compliant printf family (at least enough for our purposes),
+ * since Visual Studio 2015. With MinGW, you get the non-compliant legacy
+ * printf by default, but can select the standard-compliant version
+ * at compile time. In the Mbed TLS 3.6 LTS, we use the default, so
+ * we can't rely on %z being understood. The debug module defines
+ * `MBEDTLS_PRINTF_SIZET` for that, and this is tested in test_suite_debug.
+ * Here we just skip the test cases that break the legacy Windows printf.
+ */
+#if !(defined(__MINGW32__))
+#define HAVE_C99_PRINTF
+#endif
+
+typedef enum {
+    PRINTF_CAST_INT,
+    PRINTF_CAST_UNSIGNED,
+    PRINTF_CAST_SIZE_T,
+    PRINTF_CAST_LONG,
+    PRINTF_CAST_UNSIGNED_LONG,
+    PRINTF_CAST_LONG_LONG,
+    PRINTF_CAST_UNSIGNED_LONG_LONG,
+} printf_cast_type_t;
+
 #define NEWLINE_CHAR '\n'
 #define SPACE_CHAR ' '
 #define DOUBLE_QUOTE_CHAR '"'
@@ -22,18 +50,41 @@
 #define QUESTION_CHAR '?'
 #define BACKSLASH_CHAR '\\'
 #define LOWERCASE_N_CHAR 'n'
+
 /* END_HEADER */
 
 /* BEGIN_CASE */
-void printf_int(char *format, /* any format expecting one int argument, e.g. "%d" */
-                int x, char *result)
+void printf_integer(char *format, /* format expecting one foo_t argument */
+                    int type,     /* enum value from printf_cast_type_t */
+                    intmax_t value,
+                    char *result)
 {
     char *output = NULL;
     const size_t n = strlen(result);
+    int ret = 0;
 
     /* Nominal case: buffer just large enough */
     TEST_CALLOC(output, n + 1);
-    TEST_EQUAL(n, mbedtls_snprintf(output, n + 1, format, x));
+    switch (type) {
+        case PRINTF_CAST_INT:
+            ret = mbedtls_snprintf(output, n + 1, format, (int) value);
+            break;
+        case PRINTF_CAST_UNSIGNED:
+            ret = mbedtls_snprintf(output, n + 1, format, (unsigned) value);
+            break;
+        case PRINTF_CAST_SIZE_T:
+            ret = mbedtls_snprintf(output, n + 1, format, (size_t) value);
+            break;
+        case PRINTF_CAST_LONG_LONG:
+            ret = mbedtls_snprintf(output, n + 1, format, (long long) value);
+            break;
+        case PRINTF_CAST_UNSIGNED_LONG_LONG:
+            ret = mbedtls_snprintf(output, n + 1, format, (unsigned long long) value);
+            break;
+        default:
+            TEST_FAIL("Unsupported type");
+    }
+    TEST_EQUAL(n, ret);
     TEST_MEMORY_COMPARE(result, n + 1, output, n + 1);
     mbedtls_free(output);
     output = NULL;
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_platform_unix.data mbedtls-3.6.6/tests/suites/test_suite_platform_unix.data
--- mbedtls-3.6.5/tests/suites/test_suite_platform_unix.data	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/tests/suites/test_suite_platform_unix.data	2026-03-27 19:00:27.671048900 +0200
@@ -0,0 +1,16 @@
+<unistd.h> smoke test
+unistd_available:
+
+# At the time of writing, we don't actually use CLOCK_REALTIME.
+# But it's the only clock that's guaranteed by POSIX.
+clock_gettime(CLOCK_REALTIME) smoke test
+clock_gettime_available:CLOCK_REALTIME
+
+# Used for mbedtls_ms_time() on platforms where we don't think
+# CLOCK_BOOTTIME is available.
+clock_gettime(CLOCK_MONOTONIC) smoke test
+clock_gettime_available:CLOCK_MONOTONIC
+
+# Used in library/timing.c and programs/test/benchmark.c
+gettimeofday() smoke test
+gettimeofday_available:
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_platform_unix.function mbedtls-3.6.6/tests/suites/test_suite_platform_unix.function
--- mbedtls-3.6.5/tests/suites/test_suite_platform_unix.function	1970-01-01 02:00:00.000000000 +0200
+++ mbedtls-3.6.6/tests/suites/test_suite_platform_unix.function	2026-03-27 19:00:27.671113000 +0200
@@ -0,0 +1,68 @@
+/* BEGIN_HEADER */
+/* Test access to the Unix primitives used in platform_util.c and elsewhere.
+ * We aren't testing that they work, just getting an easy-to-understand
+ * diagnostic if they aren't available.
+ * (There is a separate test suite for the platform_util.h interfacces.)
+ */
+
+#include <mbedtls/platform_util.h>
+#include <mbedtls/platform.h>
+#include "common.h"
+
+#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE)
+
+#include <time.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#else /* defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) */
+
+/* Constants used in the test data need to be defined even if no test
+ * functions that use them are enabled.
+ * Undefine the macros first in case a system header does define them
+ * even though we haven't recognized the platform as Unix-like. */
+#undef CLOCK_REALTIME
+#define CLOCK_REALTIME 0
+#undef CLOCK_MONOTONIC
+#define CLOCK_MONOTONIC 0
+
+#endif /* defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) */
+
+/* END_HEADER */
+
+/* Note: we can't make the whole test suite depend on
+ * MBEDTLS_PLATFORM_IS_UNIXLIKE, because file-level dependencies can only
+ * come from build_info.h, platform.h or some test helper headers, not
+ * from internal macros. */
+/* BEGIN_DEPENDENCIES
+ * END_DEPENDENCIES */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PLATFORM_IS_UNIXLIKE */
+void unistd_available()
+{
+    pid_t pid = getpid();
+    TEST_LE_S(1, pid);
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PLATFORM_IS_UNIXLIKE */
+void clock_gettime_available(int clockid)
+{
+    struct timespec ts = { 0, 0 };
+    memset(&ts, 0, sizeof(ts));
+    int ret = clock_gettime(clockid, &ts);
+    TEST_ASSERT_ERRNO(ret == 0);
+    TEST_ASSERT(ts.tv_sec != 0 || ts.tv_nsec != 0);
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PLATFORM_IS_UNIXLIKE */
+void gettimeofday_available()
+{
+    struct timeval tv = { 0, 0 };
+    memset(&tv, 0, sizeof(tv));
+    int ret = gettimeofday(&tv, NULL);
+    TEST_ASSERT_ERRNO(ret == 0);
+    TEST_LE_S(1, tv.tv_sec);
+}
+/* END_CASE */
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_psa_crypto.data mbedtls-3.6.6/tests/suites/test_suite_psa_crypto.data
--- mbedtls-3.6.5/tests/suites/test_suite_psa_crypto.data	2025-10-14 19:12:37.083127000 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_psa_crypto.data	2026-03-27 19:00:27.672885700 +0200
@@ -248,10 +248,18 @@
 depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_SECP_R1_256
 import_export:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):PSA_KEY_USAGE_EXPORT:PSA_ALG_ECDSA_ANY:0:256:0:PSA_SUCCESS:1
 
+PSA import/export EC secp256r1 key pair: buffer too small
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_SECP_R1_256
+import_export:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):PSA_KEY_USAGE_EXPORT:PSA_ALG_ECDSA_ANY:0:256:-1:PSA_ERROR_BUFFER_TOO_SMALL:1
+
 PSA import/export-public EC secp256r1: good
 depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_SECP_R1_256
 import_export_public_key:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):PSA_ALG_ECDSA_ANY:0:0:PSA_SUCCESS:"047772656f814b399279d5e1f1781fac6f099a3c5ca1b0e35351834b08b65e0b572590cdaf8f769361bcf34acfc11e5e074e8426bdde04be6e653945449617de45"
 
+PSA import/export-public EC secp256r1: buffer too small
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_SECP_R1_256
+import_export_public_key:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):PSA_ALG_ECDSA_ANY:0:-1:PSA_ERROR_BUFFER_TOO_SMALL:"047772656f814b399279d5e1f1781fac6f099a3c5ca1b0e35351834b08b65e0b572590cdaf8f769361bcf34acfc11e5e074e8426bdde04be6e653945449617de45"
+
 PSA import/export EC secp384r1 key pair: good
 depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_SECP_R1_384
 import_export:"3f5d8d9be280b5696cc5cc9f94cf8af7e6b61dd6592b2ab2b3a4c607450417ec327dcdcaed7c10053d719a0574f0a76a":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):PSA_KEY_USAGE_EXPORT:PSA_ALG_ECDSA_ANY:0:384:0:PSA_SUCCESS:1
@@ -264,10 +272,18 @@
 depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_SECP_R1_521
 import_export:"01b1b6ad07bb79e7320da59860ea28e055284f6058f279de666e06d435d2af7bda28d99fa47b7dd0963e16b0073078ee8b8a38d966a582f46d19ff95df3ad9685aae":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):PSA_KEY_USAGE_EXPORT:PSA_ALG_ECDSA_ANY:0:521:0:PSA_SUCCESS:1
 
+PSA import/export EC secp521r1 key pair: buffer too small
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_SECP_R1_521
+import_export:"01b1b6ad07bb79e7320da59860ea28e055284f6058f279de666e06d435d2af7bda28d99fa47b7dd0963e16b0073078ee8b8a38d966a582f46d19ff95df3ad9685aae":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):PSA_KEY_USAGE_EXPORT:PSA_ALG_ECDSA_ANY:0:521:-1:PSA_ERROR_BUFFER_TOO_SMALL:1
+
 PSA import/export-public EC secp521r1: good
 depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_SECP_R1_521
 import_export_public_key:"01b1b6ad07bb79e7320da59860ea28e055284f6058f279de666e06d435d2af7bda28d99fa47b7dd0963e16b0073078ee8b8a38d966a582f46d19ff95df3ad9685aae":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):PSA_ALG_ECDSA_ANY:0:0:PSA_SUCCESS:"04001de142d54f69eb038ee4b7af9d3ca07736fd9cf719eb354d69879ee7f3c136fb0fbf9f08f86be5fa128ec1a051d3e6c643e85ada8ffacf3663c260bd2c844b6f5600cee8e48a9e65d09cadd89f235dee05f3b8a646be715f1f67d5b434e0ff23a1fc07ef7740193e40eeff6f3bcdfd765aa9155033524fe4f205f5444e292c4c2f6ac1"
 
+PSA import/export-public EC secp521r1: buffer too small
+depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_SECP_R1_521
+import_export_public_key:"01b1b6ad07bb79e7320da59860ea28e055284f6058f279de666e06d435d2af7bda28d99fa47b7dd0963e16b0073078ee8b8a38d966a582f46d19ff95df3ad9685aae":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):PSA_ALG_ECDSA_ANY:0:-1:PSA_ERROR_BUFFER_TOO_SMALL:"04001de142d54f69eb038ee4b7af9d3ca07736fd9cf719eb354d69879ee7f3c136fb0fbf9f08f86be5fa128ec1a051d3e6c643e85ada8ffacf3663c260bd2c844b6f5600cee8e48a9e65d09cadd89f235dee05f3b8a646be715f1f67d5b434e0ff23a1fc07ef7740193e40eeff6f3bcdfd765aa9155033524fe4f205f5444e292c4c2f6ac1"
+
 PSA import/export EC brainpool256r1 key pair: good
 depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_BRAINPOOL_P_R1_256
 import_export:"2161d6f2db76526fa62c16f356a80f01f32f776784b36aa99799a8b7662080ff":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_BRAINPOOL_P_R1):PSA_KEY_USAGE_EXPORT:PSA_ALG_ECDSA_ANY:0:256:0:PSA_SUCCESS:1
@@ -300,6 +316,10 @@
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_MONTGOMERY_255
 import_export:"77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):PSA_KEY_USAGE_EXPORT:PSA_ALG_ECDH:0:255:0:PSA_SUCCESS:0
 
+PSA import/export EC curve25519 key pair: buffer too small
+depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_MONTGOMERY_255
+import_export:"70076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c6a":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):PSA_KEY_USAGE_EXPORT:PSA_ALG_ECDH:0:255:-1:PSA_ERROR_BUFFER_TOO_SMALL:1
+
 PSA import/export-public EC curve25519: accept unmasked input
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_MONTGOMERY_255
 import_export_public_key:"77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):PSA_ALG_ECDH:0:0:PSA_SUCCESS:"8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a"
@@ -308,6 +328,10 @@
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_MONTGOMERY_255
 import_export_public_key:"70076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c6a":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):PSA_ALG_ECDH:0:0:PSA_SUCCESS:"8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a"
 
+PSA import/export-public EC curve25519: buffer too small
+depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_MONTGOMERY_255
+import_export_public_key:"70076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c6a":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):PSA_ALG_ECDH:0:-1:PSA_ERROR_BUFFER_TOO_SMALL:"8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a"
+
 PSA import/export EC curve448 key pair: good (already properly masked, key from RFC 7748 6.2 Alice))
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_MONTGOMERY_448
 import_export:"988f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a59872eb":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):PSA_KEY_USAGE_EXPORT:PSA_ALG_ECDH:0:448:0:PSA_SUCCESS:1
@@ -316,6 +340,10 @@
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_MONTGOMERY_448
 import_export:"9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):PSA_KEY_USAGE_EXPORT:PSA_ALG_ECDH:0:448:0:PSA_SUCCESS:0
 
+PSA import/export EC curve448 key pair: buffer too small
+depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_MONTGOMERY_448
+import_export:"988f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a59872eb":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):PSA_KEY_USAGE_EXPORT:PSA_ALG_ECDH:0:448:-1:PSA_ERROR_BUFFER_TOO_SMALL:1
+
 PSA import/export-public EC curve448: accept masked input (key from RFC 7748 6.2 Alice)
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_MONTGOMERY_448
 import_export_public_key:"988f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a59872eb":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):PSA_ALG_ECDH:0:0:PSA_SUCCESS:"9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0"
@@ -324,6 +352,10 @@
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_MONTGOMERY_448
 import_export_public_key:"9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):PSA_ALG_ECDH:0:0:PSA_SUCCESS:"9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0"
 
+PSA import/export-public EC curve448: buffer too small (key from RFC 7748 6.2 Alice)
+depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_MONTGOMERY_448
+import_export_public_key:"988f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a59872eb":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):PSA_ALG_ECDH:0:-1:PSA_ERROR_BUFFER_TOO_SMALL:"9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0"
+
 PSA import/export-public: cannot export-public a symmetric key
 depends_on:PSA_WANT_ALG_CBC_NO_PADDING:PSA_WANT_KEY_TYPE_AES
 import_export_public_key:"2b7e151628aed2a6abf7158809cf4f3c":PSA_KEY_TYPE_AES:PSA_ALG_CBC_NO_PADDING:0:0:PSA_ERROR_INVALID_ARGUMENT:"2b7e151628aed2a6abf7158809cf4f3c"
@@ -624,6 +656,10 @@
 depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_EXPORT:PSA_WANT_DH_RFC7919_2048
 import_export_public_key:" ":PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):PSA_ALG_FFDH:0:0:PSA_SUCCESS:" "
 
+PSA import/export-public FFDH RFC7919 key pair 2048, buffer too small
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_EXPORT:PSA_WANT_DH_RFC7919_2048
+import_export_public_key:" ":PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):PSA_ALG_FFDH:0:-1:PSA_ERROR_BUFFER_TOO_SMALL:" "
+
 PSA import/export-public FFDH RFC7919 public key 3072 good
 depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_PUBLIC_KEY:PSA_WANT_DH_RFC7919_3072
 import_export_public_key:" ":PSA_KEY_TYPE_DH_PUBLIC_KEY(PSA_DH_FAMILY_RFC7919):PSA_ALG_FFDH:0:0:PSA_SUCCESS:" "
@@ -656,6 +692,10 @@
 depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_EXPORT:PSA_WANT_DH_RFC7919_8192
 import_export_public_key:" ":PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):PSA_ALG_FFDH:0:0:PSA_SUCCESS:" "
 
+PSA import/export-public FFDH RFC7919 key pair 8192 buffer too small
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_EXPORT:PSA_WANT_DH_RFC7919_8192
+import_export_public_key:" ":PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):PSA_ALG_FFDH:0:-1:PSA_ERROR_BUFFER_TOO_SMALL:" "
+
 PSA import: reject raw data key of length 0
 # The spec allows either INVALID_ARGUMENT or NOT_SUPPORTED
 import_with_data:"":PSA_KEY_TYPE_RAW_DATA:0:PSA_ERROR_INVALID_ARGUMENT
@@ -5225,6 +5265,14 @@
 depends_on:PSA_WANT_ALG_SHA_256
 derive_setup:PSA_ALG_CATEGORY_KEY_DERIVATION:PSA_ERROR_NOT_SUPPORTED
 
+PSA key derivation setup: ECDH + HKDF-SHA-256, good
+depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_ALG_HKDF:PSA_WANT_ALG_SHA_256
+derive_setup:PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)):PSA_SUCCESS
+
+PSA key derivation setup: ECDH, unknown KDF
+depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_ALG_HKDF
+derive_setup:PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(0)):PSA_ERROR_NOT_SUPPORTED
+
 Parse binary string
 parse_binary_string_test:"123456":0x123456
 
@@ -5372,7 +5420,6 @@
 depends_on:PSA_WANT_ALG_HKDF:PSA_WANT_ALG_SHA_256
 derive_input:PSA_ALG_HKDF(PSA_ALG_SHA_256):PSA_KEY_DERIVATION_INPUT_SECRET:PSA_KEY_TYPE_NONE:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_INFO:PSA_KEY_TYPE_NONE:"":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_COST:INPUT_INTEGER:"100000":PSA_ERROR_INVALID_ARGUMENT:PSA_KEY_TYPE_NONE:PSA_ERROR_BAD_STATE
 
-
 PSA key derivation: TLS 1.2 PRF SHA-256, good case
 depends_on:PSA_WANT_ALG_SHA_256:PSA_WANT_ALG_TLS12_PRF
 derive_input:PSA_ALG_TLS12_PRF(PSA_ALG_SHA_256):PSA_KEY_DERIVATION_INPUT_SEED:PSA_KEY_TYPE_NONE:"":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SECRET:PSA_KEY_TYPE_DERIVE:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_LABEL:PSA_KEY_TYPE_NONE:"":PSA_SUCCESS:PSA_KEY_TYPE_DERIVE:PSA_SUCCESS
@@ -7180,6 +7227,7 @@
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_ALG_HKDF:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE:PSA_WANT_ECC_SECP_R1_256
 key_agreement_setup:PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)):PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)):"c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433":"04d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf6356fbf3ca366cc23e8157854c13c58d6aac23f046ada30f8353e74f33039872ff":PSA_ERROR_INVALID_ARGUMENT
 
+
 PSA key agreement setup: ECDH + HKDF-SHA-256: public key on different curve
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_ALG_HKDF:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ECC_SECP_R1_384
 key_agreement_setup:PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)):PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)):"c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433":"04e558dbef53eecde3d3fccfc1aea08a89a987475d12fd950d83cfa41732bc509d0d1ac43a0336def96fda41d0774a3571dcfbec7aacf3196472169e838430367f66eebe3c6e70c416dd5f0c68759dd1fff83fa40142209dff5eaad96db9e6386c":PSA_ERROR_INVALID_ARGUMENT
@@ -7188,10 +7236,6 @@
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_ALG_HKDF:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY:PSA_WANT_ECC_SECP_R1_256
 key_agreement_setup:PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)):PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1):PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)):"04d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf6356fbf3ca366cc23e8157854c13c58d6aac23f046ada30f8353e74f33039872ab":"04d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf6356fbf3ca366cc23e8157854c13c58d6aac23f046ada30f8353e74f33039872ab":PSA_ERROR_INVALID_ARGUMENT
 
-PSA key agreement setup: ECDH, unknown KDF
-depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_ALG_HKDF:PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY:PSA_WANT_ECC_SECP_R1_256
-key_agreement_setup:PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(0)):PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(0)):"c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433":"04d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf6356fbf3ca366cc23e8157854c13c58d6aac23f046ada30f8353e74f33039872ab":PSA_ERROR_NOT_SUPPORTED
-
 PSA key agreement setup: bad key agreement algorithm
 depends_on:PSA_WANT_ALG_HKDF:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE:PSA_WANT_ECC_SECP_R1_256
 key_agreement_setup:PSA_ALG_KEY_AGREEMENT(0, PSA_ALG_HKDF(PSA_ALG_SHA_256)):PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):PSA_ALG_KEY_AGREEMENT(0, PSA_ALG_HKDF(PSA_ALG_SHA_256)):"c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433":"04d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf6356fbf3ca366cc23e8157854c13c58d6aac23f046ada30f8353e74f33039872ab":PSA_ERROR_INVALID_ARGUMENT
@@ -7200,77 +7244,205 @@
 depends_on:PSA_WANT_ALG_HKDF:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE:PSA_WANT_ECC_SECP_R1_256
 key_agreement_setup:PSA_ALG_HKDF(PSA_ALG_SHA_256):PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):PSA_ALG_HKDF(PSA_ALG_SHA_256):"c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433":"04d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf6356fbf3ca366cc23e8157854c13c58d6aac23f046ada30f8353e74f33039872ab":PSA_ERROR_INVALID_ARGUMENT
 
-PSA raw key agreement: ECDH SECP256R1 (RFC 5903)
+PSA key agreement setup: FFDH-2048 + HKDF-SHA-256: good
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_ALG_HKDF:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_2048
+key_agreement_setup:PSA_ALG_KEY_AGREEMENT(PSA_ALG_FFDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)):PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):PSA_ALG_KEY_AGREEMENT(PSA_ALG_FFDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)):" ":" ":PSA_SUCCESS
+
+PSA key agreement setup: FFDH-2048 + HKDF-SHA-256: peer key is p-1
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_ALG_HKDF:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_2048
+key_agreement_setup:PSA_ALG_KEY_AGREEMENT(PSA_ALG_FFDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)):PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):PSA_ALG_KEY_AGREEMENT(PSA_ALG_FFDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)):" ":" ":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: ECDH SECP256R1 (RFC 5903)
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE:PSA_WANT_ECC_SECP_R1_256
-raw_key_agreement:PSA_ALG_ECDH:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433":"04d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf6356fbf3ca366cc23e8157854c13c58d6aac23f046ada30f8353e74f33039872ab":"d6840f6b42f6edafd13116e0e12565202fef8e9ece7dce03812464d04b9442de"
+key_agreement:PSA_ALG_ECDH:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433":"04d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf6356fbf3ca366cc23e8157854c13c58d6aac23f046ada30f8353e74f33039872ab":"d6840f6b42f6edafd13116e0e12565202fef8e9ece7dce03812464d04b9442de":PSA_SUCCESS
 
-PSA raw key agreement: ECDH SECP384R1 (RFC 5903)
+PSA (raw) key agreement: ECDH SECP384R1 (RFC 5903)
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE:PSA_WANT_ECC_SECP_R1_384
-raw_key_agreement:PSA_ALG_ECDH:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"099f3c7034d4a2c699884d73a375a67f7624ef7c6b3c0f160647b67414dce655e35b538041e649ee3faef896783ab194":"04e558dbef53eecde3d3fccfc1aea08a89a987475d12fd950d83cfa41732bc509d0d1ac43a0336def96fda41d0774a3571dcfbec7aacf3196472169e838430367f66eebe3c6e70c416dd5f0c68759dd1fff83fa40142209dff5eaad96db9e6386c":"11187331c279962d93d604243fd592cb9d0a926f422e47187521287e7156c5c4d603135569b9e9d09cf5d4a270f59746"
+key_agreement:PSA_ALG_ECDH:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"099f3c7034d4a2c699884d73a375a67f7624ef7c6b3c0f160647b67414dce655e35b538041e649ee3faef896783ab194":"04e558dbef53eecde3d3fccfc1aea08a89a987475d12fd950d83cfa41732bc509d0d1ac43a0336def96fda41d0774a3571dcfbec7aacf3196472169e838430367f66eebe3c6e70c416dd5f0c68759dd1fff83fa40142209dff5eaad96db9e6386c":"11187331c279962d93d604243fd592cb9d0a926f422e47187521287e7156c5c4d603135569b9e9d09cf5d4a270f59746":PSA_SUCCESS
 
-PSA raw key agreement: ECDH SECP521R1 (RFC 5903)
+PSA (raw) key agreement: ECDH SECP521R1 (RFC 5903)
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE:PSA_WANT_ECC_SECP_R1_521
-raw_key_agreement:PSA_ALG_ECDH:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"0037ade9319a89f4dabdb3ef411aaccca5123c61acab57b5393dce47608172a095aa85a30fe1c2952c6771d937ba9777f5957b2639bab072462f68c27a57382d4a52":"0400d0b3975ac4b799f5bea16d5e13e9af971d5e9b984c9f39728b5e5739735a219b97c356436adc6e95bb0352f6be64a6c2912d4ef2d0433ced2b6171640012d9460f015c68226383956e3bd066e797b623c27ce0eac2f551a10c2c724d9852077b87220b6536c5c408a1d2aebb8e86d678ae49cb57091f4732296579ab44fcd17f0fc56a":"01144c7d79ae6956bc8edb8e7c787c4521cb086fa64407f97894e5e6b2d79b04d1427e73ca4baa240a34786859810c06b3c715a3a8cc3151f2bee417996d19f3ddea"
+key_agreement:PSA_ALG_ECDH:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"0037ade9319a89f4dabdb3ef411aaccca5123c61acab57b5393dce47608172a095aa85a30fe1c2952c6771d937ba9777f5957b2639bab072462f68c27a57382d4a52":"0400d0b3975ac4b799f5bea16d5e13e9af971d5e9b984c9f39728b5e5739735a219b97c356436adc6e95bb0352f6be64a6c2912d4ef2d0433ced2b6171640012d9460f015c68226383956e3bd066e797b623c27ce0eac2f551a10c2c724d9852077b87220b6536c5c408a1d2aebb8e86d678ae49cb57091f4732296579ab44fcd17f0fc56a":"01144c7d79ae6956bc8edb8e7c787c4521cb086fa64407f97894e5e6b2d79b04d1427e73ca4baa240a34786859810c06b3c715a3a8cc3151f2bee417996d19f3ddea":PSA_SUCCESS
 
-PSA raw key agreement: ECDH brainpoolP256r1 (RFC 7027)
+PSA (raw) key agreement: ECDH brainpoolP256r1 (RFC 7027)
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE:PSA_WANT_ECC_BRAINPOOL_P_R1_256
-raw_key_agreement:PSA_ALG_ECDH:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_BRAINPOOL_P_R1):"81db1ee100150ff2ea338d708271be38300cb54241d79950f77b063039804f1d":"048d2d688c6cf93e1160ad04cc4429117dc2c41825e1e9fca0addd34e6f1b39f7b990c57520812be512641e47034832106bc7d3e8dd0e4c7f1136d7006547cec6a":"89afc39d41d3b327814b80940b042590f96556ec91e6ae7939bce31f3a18bf2b"
+key_agreement:PSA_ALG_ECDH:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_BRAINPOOL_P_R1):"81db1ee100150ff2ea338d708271be38300cb54241d79950f77b063039804f1d":"048d2d688c6cf93e1160ad04cc4429117dc2c41825e1e9fca0addd34e6f1b39f7b990c57520812be512641e47034832106bc7d3e8dd0e4c7f1136d7006547cec6a":"89afc39d41d3b327814b80940b042590f96556ec91e6ae7939bce31f3a18bf2b":PSA_SUCCESS
 
-PSA raw key agreement: ECDH brainpoolP384r1 (RFC 7027)
+PSA (raw) key agreement: ECDH brainpoolP384r1 (RFC 7027)
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE:PSA_WANT_ECC_BRAINPOOL_P_R1_384
-raw_key_agreement:PSA_ALG_ECDH:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_BRAINPOOL_P_R1):"1e20f5e048a5886f1f157c74e91bde2b98c8b52d58e5003d57053fc4b0bd65d6f15eb5d1ee1610df870795143627d042":"044d44326f269a597a5b58bba565da5556ed7fd9a8a9eb76c25f46db69d19dc8ce6ad18e404b15738b2086df37e71d1eb462d692136de56cbe93bf5fa3188ef58bc8a3a0ec6c1e151a21038a42e9185329b5b275903d192f8d4e1f32fe9cc78c48":"0bd9d3a7ea0b3d519d09d8e48d0785fb744a6b355e6304bc51c229fbbce239bbadf6403715c35d4fb2a5444f575d4f42"
+key_agreement:PSA_ALG_ECDH:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_BRAINPOOL_P_R1):"1e20f5e048a5886f1f157c74e91bde2b98c8b52d58e5003d57053fc4b0bd65d6f15eb5d1ee1610df870795143627d042":"044d44326f269a597a5b58bba565da5556ed7fd9a8a9eb76c25f46db69d19dc8ce6ad18e404b15738b2086df37e71d1eb462d692136de56cbe93bf5fa3188ef58bc8a3a0ec6c1e151a21038a42e9185329b5b275903d192f8d4e1f32fe9cc78c48":"0bd9d3a7ea0b3d519d09d8e48d0785fb744a6b355e6304bc51c229fbbce239bbadf6403715c35d4fb2a5444f575d4f42":PSA_SUCCESS
 
-PSA raw key agreement: ECDH brainpoolP512r1 (RFC 7027)
+PSA (raw) key agreement: ECDH brainpoolP512r1 (RFC 7027)
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE:PSA_WANT_ECC_BRAINPOOL_P_R1_512
-raw_key_agreement:PSA_ALG_ECDH:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_BRAINPOOL_P_R1):"16302ff0dbbb5a8d733dab7141c1b45acbc8715939677f6a56850a38bd87bd59b09e80279609ff333eb9d4c061231fb26f92eeb04982a5f1d1764cad57665422":"049d45f66de5d67e2e6db6e93a59ce0bb48106097ff78a081de781cdb31fce8ccbaaea8dd4320c4119f1e9cd437a2eab3731fa9668ab268d871deda55a5473199f2fdc313095bcdd5fb3a91636f07a959c8e86b5636a1e930e8396049cb481961d365cc11453a06c719835475b12cb52fc3c383bce35e27ef194512b71876285fa":"a7927098655f1f9976fa50a9d566865dc530331846381c87256baf3226244b76d36403c024d7bbf0aa0803eaff405d3d24f11a9b5c0bef679fe1454b21c4cd1f"
+key_agreement:PSA_ALG_ECDH:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_BRAINPOOL_P_R1):"16302ff0dbbb5a8d733dab7141c1b45acbc8715939677f6a56850a38bd87bd59b09e80279609ff333eb9d4c061231fb26f92eeb04982a5f1d1764cad57665422":"049d45f66de5d67e2e6db6e93a59ce0bb48106097ff78a081de781cdb31fce8ccbaaea8dd4320c4119f1e9cd437a2eab3731fa9668ab268d871deda55a5473199f2fdc313095bcdd5fb3a91636f07a959c8e86b5636a1e930e8396049cb481961d365cc11453a06c719835475b12cb52fc3c383bce35e27ef194512b71876285fa":"a7927098655f1f9976fa50a9d566865dc530331846381c87256baf3226244b76d36403c024d7bbf0aa0803eaff405d3d24f11a9b5c0bef679fe1454b21c4cd1f":PSA_SUCCESS
 
-PSA raw key agreement: X25519 (RFC 7748: Alice)
+PSA (raw) key agreement: X25519 (RFC 7748: Alice)
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE:PSA_WANT_ECC_MONTGOMERY_255
-raw_key_agreement:PSA_ALG_ECDH:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):"77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a":"de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f":"4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"
+key_agreement:PSA_ALG_ECDH:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):"77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a":"de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f":"4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742":PSA_SUCCESS
 
-PSA raw key agreement: X25519 (RFC 7748: Bob)
+PSA (raw) key agreement: X25519 (RFC 7748: Bob)
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE:PSA_WANT_ECC_MONTGOMERY_255
-raw_key_agreement:PSA_ALG_ECDH:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):"5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb":"8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a":"4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"
+key_agreement:PSA_ALG_ECDH:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):"5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb":"8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a":"4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742":PSA_SUCCESS
 
-PSA raw key agreement: X448 (RFC 7748: Alice)
+PSA (raw) key agreement: X448 (RFC 7748: Alice)
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE:PSA_WANT_ECC_MONTGOMERY_448
-raw_key_agreement:PSA_ALG_ECDH:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):"9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b":"3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609":"07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d"
+key_agreement:PSA_ALG_ECDH:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):"9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b":"3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609":"07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d":PSA_SUCCESS
 
-PSA raw key agreement: X448 (RFC 7748: Bob)
+PSA (raw) key agreement: X448 (RFC 7748: Bob)
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE:PSA_WANT_ECC_MONTGOMERY_448
-raw_key_agreement:PSA_ALG_ECDH:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):"1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d":"9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0":"07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d"
+key_agreement:PSA_ALG_ECDH:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_MONTGOMERY):"1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d":"9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0":"07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d":PSA_SUCCESS
+
+PSA (raw) key agreement: FFDH 2048 bits
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_2048
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":" ":PSA_SUCCESS
+
+PSA (raw) key agreement: FFDH 2048 bits, peer's key is zero
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_2048
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 2048 bits, peer's key is one
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_2048
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 2048 bits, peer's key is p-1
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_2048
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 2048 bits, peer's key is p
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_2048
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 2048 bits, peer's key is p+1
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_2048
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
 
-PSA raw key agreement: FFDH 2048 bits
+PSA (raw) key agreement: FFDH 2048 bits, peer's key is ff...ff
 depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_2048
-raw_key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":" "
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
 
-PSA raw key agreement: FFDH 2048 bits (shared secred with leading zeros)
+PSA (raw) key agreement: FFDH 2048 bits (shared secret with leading zeros)
 depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_2048
-raw_key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":" "
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":" ":PSA_SUCCESS
 
-PSA raw key agreement: FFDH 3072 bits
+PSA (raw) key agreement: FFDH 3072 bits
 depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_3072
-raw_key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":" "
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":" ":PSA_SUCCESS
 
-PSA raw key agreement: FFDH 3072 bits (shared secred with leading zeros)
+PSA (raw) key agreement: FFDH 3072 bits, peer's key is zero
 depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_3072
-raw_key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":" "
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
 
-PSA raw key agreement: FFDH 4096 bits
+PSA (raw) key agreement: FFDH 3072 bits, peer's key is one
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_3072
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 3072 bits, peer's key is p-1
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_3072
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 3072 bits, peer's key is p
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_3072
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 3072 bits, peer's key is p+1
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_3072
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 3072 bits, peer's key is ff...ff
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_3072
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 3072 bits (shared secret with leading zeros)
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_3072
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":" ":PSA_SUCCESS
+
+PSA (raw) key agreement: FFDH 4096 bits
 depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_4096
-raw_key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":" "
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":" ":PSA_SUCCESS
 
-PSA raw key agreement: FFDH 4096 bits (shared secred with leading zeros)
+PSA (raw) key agreement: FFDH 4096 bits, peer's key is zero
 depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_4096
-raw_key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":" "
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
 
-PSA raw key agreement: FFDH 6144 bits
+PSA (raw) key agreement: FFDH 4096 bits, peer's key is one
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_4096
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 4096 bits, peer's key is p-1
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_4096
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 4096 bits, peer's key is p
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_4096
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 4096 bits, peer's key is p+1
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_4096
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 4096 bits, peer's key is ff...ff
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_4096
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 4096 bits (shared secret with leading zeros)
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_4096
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":" ":PSA_SUCCESS
+
+PSA (raw) key agreement: FFDH 6144 bits
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_6144
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":" ":PSA_SUCCESS
+
+PSA (raw) key agreement: FFDH 6144 bits, peer's key is zero
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_6144
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 6144 bits, peer's key is one
 depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_6144
-raw_key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":" "
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
 
-PSA raw key agreement: FFDH 6144 bits (shared secred with leading zeros)
+PSA (raw) key agreement: FFDH 6144 bits, peer's key is p-1
 depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_6144
-raw_key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":" "
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 6144 bits, peer's key is p
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_6144
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 6144 bits, peer's key is p+1
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_6144
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 6144 bits, peer's key is ff...ff
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_6144
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 6144 bits (shared secret with leading zeros)
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_6144
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":" ":PSA_SUCCESS
+
+PSA (raw) key agreement: FFDH 8192 bits, peer's key is zero
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_8192
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 8192 bits, peer's key is one
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_8192
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 8192 bits, peer's key is p-1
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_8192
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 8192 bits, peer's key is p
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_8192
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 8192 bits, peer's key is p+1
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_8192
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
+
+PSA (raw) key agreement: FFDH 8192 bits, peer's key is ff...ff
+depends_on:PSA_WANT_ALG_FFDH:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_DH_KEY_PAIR_IMPORT:PSA_WANT_DH_RFC7919_8192
+key_agreement:PSA_ALG_FFDH:PSA_KEY_TYPE_DH_KEY_PAIR(PSA_DH_FAMILY_RFC7919):" ":" ":"":PSA_ERROR_INVALID_ARGUMENT
 
 PSA key agreement: ECDH SECP256R1 (RFC 5903) + HKDF-SHA-256: capacity=8160
 depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_ALG_HKDF:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE:PSA_WANT_ECC_SECP_R1_256
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_psa_crypto_entropy.data mbedtls-3.6.6/tests/suites/test_suite_psa_crypto_entropy.data
--- mbedtls-3.6.5/tests/suites/test_suite_psa_crypto_entropy.data	2025-10-14 19:12:37.087891000 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_psa_crypto_entropy.data	2026-03-27 19:00:27.676462200 +0200
@@ -1,3 +1,82 @@
+Create NV seed file
+create_nv_seed:
+
+Custom entropy sources: all standard
+custom_entropy_sources:0x0000ffff:PSA_SUCCESS
+
+# MBEDTLS_PSA_INJECT_ENTROPY means that a source of entropy (the seed file)
+# is effectively always available.
+Custom entropy sources: none
+depends_on:!MBEDTLS_PSA_INJECT_ENTROPY
+custom_entropy_sources:0:PSA_ERROR_INSUFFICIENT_ENTROPY
+
+Fake entropy: never returns anything
+fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:0:0:0:0:PSA_ERROR_INSUFFICIENT_ENTROPY
+
+Fake entropy: less than the block size
+fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:-1:-1:-1:PSA_ERROR_INSUFFICIENT_ENTROPY
+
+Fake entropy: not enough for a nonce
+depends_on:ENTROPY_NONCE_LEN != 0
+fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:ENTROPY_NONCE_LEN - 1:-1:-1:-1:PSA_ERROR_INSUFFICIENT_ENTROPY
+
+Fake entropy: one block eventually
+depends_on:ENTROPY_NONCE_LEN == 0
+fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:0:0:0:MBEDTLS_ENTROPY_BLOCK_SIZE:PSA_SUCCESS
+
+Fake entropy: one block in two steps
+depends_on:ENTROPY_NONCE_LEN == 0
+fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:1:-1:-1:PSA_SUCCESS
+
+Fake entropy: more than one block in two steps
+depends_on:ENTROPY_NONCE_LEN == 0
+fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:-1:-1:PSA_SUCCESS
+
+Fake entropy: two blocks eventually
+fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:0:MBEDTLS_ENTROPY_BLOCK_SIZE:0:MBEDTLS_ENTROPY_BLOCK_SIZE:PSA_SUCCESS
+
+NV seed only: less than minimum
+entropy_from_nv_seed:MBEDTLS_ENTROPY_MIN_PLATFORM - 1:PSA_ERROR_INSUFFICIENT_ENTROPY
+
+NV seed only: less than one block
+entropy_from_nv_seed:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:PSA_ERROR_INSUFFICIENT_ENTROPY
+
+NV seed only: just enough
+entropy_from_nv_seed:ENTROPY_MIN_NV_SEED_SIZE:PSA_SUCCESS
+
+Explicit reseed: basic tests
+reseed_basic:
+
+Explicit reseed: entropy consumption
+reseed_consumption:
+
+Deplete: entropy consumption
+deplete_consumption:
+
+Prediction resistance: entropy consumption
+prediction_resistance_consumption:
+
+Prediction resistance: bad state
+prediction_resistance_bad_state:
+
+Prediction resistance: bad arguments
+prediction_resistance_bad_arguments:
+
+Explicit reseed: uniqueness tests (0 = 0)
+reseed_uniqueness:"":""
+
+Explicit reseed: uniqueness tests (0 != 5)
+reseed_uniqueness:"":"706572736f"
+
+Explicit reseed: uniqueness tests (5 = 5)
+reseed_uniqueness:"706572736f":"706572736f"
+
+Explicit reseed: uniqueness tests (5 != 5)
+reseed_uniqueness:"706572736f":"706572736e"
+
+Explicit reseed: uniqueness tests (5 != 10)
+reseed_uniqueness:"706572736f":"706572736f706572736f"
+
 PSA external RNG failure: generate random and key
 external_rng_failure_generate:
 
@@ -25,6 +104,18 @@
 depends_on:PSA_WANT_ALG_RSA_PKCS1V15_SIGN:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_EXPORT:MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_SIGN
 external_rng_failure_sign:PSA_KEY_TYPE_RSA_KEY_PAIR:" ":PSA_ALG_RSA_PKCS1V15_SIGN_RAW:32
 
+PSA RNG after fork: parent gets random never
+psa_rng_fork:-1
+
+PSA RNG after fork: parent gets random before
+psa_rng_fork:0
+
+PSA RNG after fork: parent gets random between
+psa_rng_fork:1
+
+PSA RNG after fork: parent gets random after
+psa_rng_fork:2
+
 PSA validate entropy injection: good, minimum size
 validate_entropy_seed_injection:MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE:PSA_SUCCESS:MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE:PSA_ERROR_NOT_PERMITTED
 
@@ -43,3 +134,5 @@
 PSA validate entropy injection: before and after crypto_init
 run_entropy_inject_with_crypto_init:
 
+Recreate NV seed file
+create_nv_seed:
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_psa_crypto_entropy.function mbedtls-3.6.6/tests/suites/test_suite_psa_crypto_entropy.function
--- mbedtls-3.6.5/tests/suites/test_suite_psa_crypto_entropy.function	2025-10-14 19:12:37.088067500 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_psa_crypto_entropy.function	2026-03-27 19:00:27.676816500 +0200
@@ -2,11 +2,171 @@
 #include <stdint.h>
 #include <string.h>
 
+#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE)
+#include <test/fork_helpers.h>
+#endif
+
 #include <psa/crypto.h>
 
+/* Some tests in this module configure entropy sources. */
+#include "psa_crypto_invasive.h"
+
 #include "mbedtls/entropy.h"
 #include "entropy_poll.h"
 
+#define ENTROPY_MIN_NV_SEED_SIZE                                        \
+    MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_BLOCK_SIZE)
+
+#include "psa_crypto_random_impl.h"
+#if defined(MBEDTLS_PSA_HMAC_DRBG_MD_TYPE)
+/* PSA crypto uses the HMAC_DRBG module. It reads from the entropy source twice:
+ * once for the initial entropy and once for a nonce. The nonce length is
+ * half the entropy length. For SHA-256, SHA-384 or SHA-512, the
+ * entropy length is 256 per the documentation of mbedtls_hmac_drbg_seed(),
+ * and PSA crypto doesn't support other hashes for HMAC_DRBG. */
+#define ENTROPY_NONCE_LEN (256 / 2)
+#else
+/* PSA crypto uses the CTR_DRBG module. In some configurations, it needs
+ * to read from the entropy source twice: once for the initial entropy
+ * and once for a nonce. */
+#include "mbedtls/ctr_drbg.h"
+#define ENTROPY_NONCE_LEN MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN
+#endif
+
+#if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+
+typedef struct {
+    size_t threshold; /* Minimum bytes to make mbedtls_entropy_func happy */
+    size_t max_steps;
+    size_t *length_sequence;
+    size_t step;
+} fake_entropy_state_t;
+
+static int fake_entropy_source(void *state_arg,
+                               unsigned char *output, size_t len,
+                               size_t *olen)
+{
+    fake_entropy_state_t *state = state_arg;
+    size_t i;
+
+    if (state->step >= state->max_steps) {
+        return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
+    }
+
+    *olen = MIN(len, state->length_sequence[state->step]);
+    for (i = 0; i < *olen; i++) {
+        output[i] = i;
+    }
+    ++state->step;
+    return 0;
+}
+
+#define ENTROPY_SOURCE_PLATFORM                 0x00000001
+#define ENTROPY_SOURCE_TIMING                   0x00000002
+#define ENTROPY_SOURCE_HARDWARE                 0x00000004
+#define ENTROPY_SOURCE_NV_SEED                  0x00000008
+#define ENTROPY_SOURCE_FAKE                     0x40000000
+
+static uint32_t custom_entropy_sources_mask;
+static fake_entropy_state_t fake_entropy_state;
+
+/* This is a modified version of mbedtls_entropy_init() from entropy.c
+ * which chooses entropy sources dynamically. */
+static void custom_entropy_init(mbedtls_entropy_context *ctx)
+{
+    ctx->source_count = 0;
+    memset(ctx->source, 0, sizeof(ctx->source));
+
+#if defined(MBEDTLS_THREADING_C)
+    mbedtls_mutex_init(&ctx->mutex);
+#endif
+
+    ctx->accumulator_started = 0;
+    mbedtls_md_init(&ctx->accumulator);
+
+#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY)
+    if (custom_entropy_sources_mask & ENTROPY_SOURCE_PLATFORM) {
+        mbedtls_entropy_add_source(ctx, mbedtls_platform_entropy_poll, NULL,
+                                   MBEDTLS_ENTROPY_MIN_PLATFORM,
+                                   MBEDTLS_ENTROPY_SOURCE_STRONG);
+    }
+#endif
+#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
+    if (custom_entropy_sources_mask & ENTROPY_SOURCE_HARDWARE) {
+        mbedtls_entropy_add_source(ctx, mbedtls_hardware_poll, NULL,
+                                   MBEDTLS_ENTROPY_MIN_HARDWARE,
+                                   MBEDTLS_ENTROPY_SOURCE_STRONG);
+    }
+#endif
+#if defined(MBEDTLS_ENTROPY_NV_SEED)
+    if (custom_entropy_sources_mask & ENTROPY_SOURCE_NV_SEED) {
+        mbedtls_entropy_add_source(ctx, mbedtls_nv_seed_poll, NULL,
+                                   MBEDTLS_ENTROPY_BLOCK_SIZE,
+                                   MBEDTLS_ENTROPY_SOURCE_STRONG);
+        ctx->initial_entropy_run = 0;
+    } else {
+        /* Skip the NV seed even though it's compiled in. */
+        ctx->initial_entropy_run = 1;
+    }
+#endif
+
+    if (custom_entropy_sources_mask & ENTROPY_SOURCE_FAKE) {
+        mbedtls_entropy_add_source(ctx,
+                                   fake_entropy_source, &fake_entropy_state,
+                                   fake_entropy_state.threshold,
+                                   MBEDTLS_ENTROPY_SOURCE_STRONG);
+    }
+}
+
+static size_t fake_entropy_lengths[] = {
+    MBEDTLS_ENTROPY_BLOCK_SIZE,
+    MBEDTLS_ENTROPY_BLOCK_SIZE,
+    MBEDTLS_ENTROPY_BLOCK_SIZE,
+    MBEDTLS_ENTROPY_BLOCK_SIZE,
+    MBEDTLS_ENTROPY_BLOCK_SIZE,
+    MBEDTLS_ENTROPY_BLOCK_SIZE,
+};
+
+/** Initialize PSA with a deterministic RNG seed.
+ *
+ * \param max_entropy_queries   Maximum number of queries to the entropy source.
+ *                              Once this number has been reached, the
+ *                              entropy source will fail.
+ */
+static int psa_init_deterministic(size_t max_entropy_queries)
+{
+    TEST_LE_U(max_entropy_queries, ARRAY_LENGTH(fake_entropy_lengths));
+
+    fake_entropy_state.threshold = MBEDTLS_ENTROPY_BLOCK_SIZE;
+    fake_entropy_state.step = 0;
+    fake_entropy_state.max_steps = max_entropy_queries;
+    fake_entropy_state.length_sequence = fake_entropy_lengths;
+
+    custom_entropy_sources_mask = ENTROPY_SOURCE_FAKE;
+    PSA_ASSERT(mbedtls_psa_crypto_configure_entropy_sources(
+                   custom_entropy_init, mbedtls_entropy_free));
+    PSA_INIT();
+    return 1;
+
+exit:
+    return 0;
+}
+#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */
+
+#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) && \
+    !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+static void child_psa_get_random(void *param,
+                                 uint8_t *output, size_t output_size,
+                                 size_t *output_length)
+{
+    (void) param;
+    PSA_ASSERT(psa_generate_random(output, output_size));
+    *output_length = output_size;
+exit:
+    ;
+}
+#endif  /* MBEDTLS_PLATFORM_IS_UNIXLIKE && !MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+
 /* Calculating the minimum allowed entropy size in bytes */
 #define MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, \
                                                 MBEDTLS_ENTROPY_BLOCK_SIZE)
@@ -68,6 +228,375 @@
 
 /* END_HEADER */
 
+/* BEGIN_DEPENDENCIES
+ * depends_on:MBEDTLS_PSA_CRYPTO_C
+ * END_DEPENDENCIES
+ */
+
+/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+void create_nv_seed()
+{
+    static unsigned char seed[ENTROPY_MIN_NV_SEED_SIZE];
+    TEST_ASSERT(mbedtls_nv_seed_write(seed, sizeof(seed)) >= 0);
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+void custom_entropy_sources(int sources_arg, int expected_init_status_arg)
+{
+    psa_status_t expected_init_status = expected_init_status_arg;
+    uint8_t random[10] = { 0 };
+
+    custom_entropy_sources_mask = sources_arg;
+    PSA_ASSERT(mbedtls_psa_crypto_configure_entropy_sources(
+                   custom_entropy_init, mbedtls_entropy_free));
+
+    TEST_EQUAL(psa_crypto_init(), expected_init_status);
+    if (expected_init_status != PSA_SUCCESS) {
+        goto exit;
+    }
+
+    PSA_ASSERT(psa_generate_random(random, sizeof(random)));
+
+exit:
+    PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+void fake_entropy_source(int threshold,
+                         int amount1,
+                         int amount2,
+                         int amount3,
+                         int amount4,
+                         int expected_init_status_arg)
+{
+    psa_status_t expected_init_status = expected_init_status_arg;
+    uint8_t random[10] = { 0 };
+    size_t lengths[4];
+
+    fake_entropy_state.threshold = threshold;
+    fake_entropy_state.step = 0;
+    fake_entropy_state.max_steps = 0;
+    if (amount1 >= 0) {
+        lengths[fake_entropy_state.max_steps++] = amount1;
+    }
+    if (amount2 >= 0) {
+        lengths[fake_entropy_state.max_steps++] = amount2;
+    }
+    if (amount3 >= 0) {
+        lengths[fake_entropy_state.max_steps++] = amount3;
+    }
+    if (amount4 >= 0) {
+        lengths[fake_entropy_state.max_steps++] = amount4;
+    }
+    fake_entropy_state.length_sequence = lengths;
+
+    custom_entropy_sources_mask = ENTROPY_SOURCE_FAKE;
+    PSA_ASSERT(mbedtls_psa_crypto_configure_entropy_sources(
+                   custom_entropy_init, mbedtls_entropy_free));
+
+    TEST_EQUAL(psa_crypto_init(), expected_init_status);
+    if (expected_init_status != PSA_SUCCESS) {
+        goto exit;
+    }
+
+    PSA_ASSERT(psa_generate_random(random, sizeof(random)));
+
+exit:
+    PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+void entropy_from_nv_seed(int seed_size_arg,
+                          int expected_init_status_arg)
+{
+    psa_status_t expected_init_status = expected_init_status_arg;
+    uint8_t random[10] = { 0 };
+    uint8_t *seed = NULL;
+    size_t seed_size = seed_size_arg;
+
+    TEST_CALLOC(seed, seed_size);
+    TEST_ASSERT(mbedtls_nv_seed_write(seed, seed_size) >= 0);
+
+    custom_entropy_sources_mask = ENTROPY_SOURCE_NV_SEED;
+    PSA_ASSERT(mbedtls_psa_crypto_configure_entropy_sources(
+                   custom_entropy_init, mbedtls_entropy_free));
+
+    TEST_EQUAL(psa_crypto_init(), expected_init_status);
+    if (expected_init_status != PSA_SUCCESS) {
+        goto exit;
+    }
+
+    PSA_ASSERT(psa_generate_random(random, sizeof(random)));
+
+exit:
+    mbedtls_free(seed);
+    PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+void reseed_basic()
+{
+    uint8_t random[10];
+    const uint8_t perso[5] = { 'p', 'e', 'r', 's', 'o' };
+
+    TEST_EQUAL(psa_random_reseed(NULL, 0), PSA_ERROR_BAD_STATE);
+    TEST_EQUAL(psa_random_deplete(), PSA_ERROR_BAD_STATE);
+    TEST_EQUAL(psa_generate_random(random, sizeof(random)), PSA_ERROR_BAD_STATE);
+
+    PSA_INIT();
+
+    PSA_ASSERT(psa_random_reseed(NULL, 0));
+    PSA_ASSERT(psa_random_reseed(perso, sizeof(perso)));
+    PSA_ASSERT(psa_generate_random(random, sizeof(random)));
+
+    PSA_ASSERT(psa_random_deplete());
+    PSA_ASSERT(psa_generate_random(random, sizeof(random)));
+
+    mbedtls_psa_crypto_free();
+
+    TEST_EQUAL(psa_random_reseed(NULL, 0), PSA_ERROR_BAD_STATE);
+    TEST_EQUAL(psa_random_deplete(), PSA_ERROR_BAD_STATE);
+    TEST_EQUAL(psa_generate_random(random, sizeof(random)), PSA_ERROR_BAD_STATE);
+
+exit:
+    PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+void prediction_resistance_bad_state()
+{
+    uint8_t random[10];
+
+    /* RNG inactive before initialization */
+    TEST_EQUAL(psa_random_set_prediction_resistance(0), PSA_ERROR_BAD_STATE);
+    TEST_EQUAL(psa_random_set_prediction_resistance(1), PSA_ERROR_BAD_STATE);
+    TEST_EQUAL(psa_generate_random(random, sizeof(random)), PSA_ERROR_BAD_STATE);
+
+    PSA_INIT();
+
+    /* Good cases, as controls */
+    PSA_ASSERT(psa_generate_random(random, sizeof(random)));
+    PSA_ASSERT(psa_random_set_prediction_resistance(0));
+#if MBEDTLS_ENTROPY_TRUE_SOURCES > 0
+    PSA_ASSERT(psa_random_set_prediction_resistance(1));
+#endif
+
+    /* RNG inactive after shutdown */
+    mbedtls_psa_crypto_free();
+    TEST_EQUAL(psa_random_set_prediction_resistance(0), PSA_ERROR_BAD_STATE);
+    TEST_EQUAL(psa_random_set_prediction_resistance(1), PSA_ERROR_BAD_STATE);
+    TEST_EQUAL(psa_generate_random(random, sizeof(random)), PSA_ERROR_BAD_STATE);
+
+exit:
+    PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+void prediction_resistance_bad_arguments()
+{
+    uint8_t random[10];
+
+    PSA_INIT();
+
+    TEST_EQUAL(psa_random_set_prediction_resistance(2), PSA_ERROR_INVALID_ARGUMENT);
+    TEST_EQUAL(psa_random_set_prediction_resistance(-1), PSA_ERROR_INVALID_ARGUMENT);
+
+    /* Good cases, as controls */
+    PSA_ASSERT(psa_generate_random(random, sizeof(random)));
+    PSA_ASSERT(psa_random_set_prediction_resistance(0));
+#if MBEDTLS_ENTROPY_TRUE_SOURCES > 0
+    PSA_ASSERT(psa_random_set_prediction_resistance(1));
+#else
+    TEST_EQUAL(psa_random_set_prediction_resistance(1), PSA_ERROR_NOT_SUPPORTED);
+#endif
+
+exit:
+    PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+/* Check that reseeding consumes entropy.
+ *
+ * For simplicity, this test function assumes that the DRBG has prediction
+ * resistance turned off, so the few RNG queries in this function don't
+ * trigger a reseed.
+ */
+void reseed_consumption()
+{
+    uint8_t random[10] = { 0 };
+    const size_t max_get_entropy = 4;
+
+    if (!psa_init_deterministic(max_get_entropy)) {
+        goto exit;
+    }
+
+    /* Depending on the DRBG parameters, the initial seeding may
+     * consume entropy once or twice. Zero would be deeply unsettling
+     * (how can you initialize the RNG without entropy?). More than 2 would
+     * be ok, but the test code would need to be adapted. */
+    TEST_LE_U(1, fake_entropy_state.step);
+    TEST_LE_U(fake_entropy_state.step, 2);
+    /* Arrange to have exactly 2 entropy blocks remaining. */
+    fake_entropy_state.step = max_get_entropy - 2;
+
+    /* Explicit reseed, consumes 1 entropy block, 1 remaining */
+    PSA_ASSERT(psa_random_reseed(NULL, 0));
+    PSA_ASSERT(psa_generate_random(random, sizeof(random)));
+
+    /* Explicit reseed, consumes 1 entropy block, 0 remaining */
+    PSA_ASSERT(psa_random_reseed(NULL, 0));
+    PSA_ASSERT(psa_generate_random(random, sizeof(random)));
+
+    /* All entropy blocks are now consumed */
+    TEST_EQUAL(psa_random_reseed(NULL, 0), PSA_ERROR_INSUFFICIENT_ENTROPY);
+
+    /* The random generator is still fine after failing to reseed
+     * explicitly. Should it be? */
+    PSA_ASSERT(psa_generate_random(random, sizeof(random)));
+
+exit:
+    PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+void deplete_consumption()
+{
+    uint8_t random[10] = { 0 };
+
+    if (!psa_init_deterministic(4)) {
+        goto exit;
+    }
+
+    /* Depending on the DRBG parameters, the initial seeding may
+     * consume entropy once or twice. Reset to 1 to keep things simple. */
+    fake_entropy_state.step = 1;
+
+    PSA_ASSERT(psa_random_deplete());
+    TEST_EQUAL(fake_entropy_state.step, 1);
+
+    PSA_ASSERT(psa_generate_random(random, sizeof(random)));
+    TEST_LE_U(2, fake_entropy_state.step);
+
+exit:
+    PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG:MBEDTLS_ENTROPY_HAVE_TRUE_SOURCES */
+void prediction_resistance_consumption()
+{
+    uint8_t random[10] = { 0 };
+
+    if (!psa_init_deterministic(4)) {
+        goto exit;
+    }
+
+    /* Depending on the DRBG parameters, the initial seeding may
+     * consume entropy once or twice. Reset to 1 to keep things simple. */
+    fake_entropy_state.step = 1;
+
+    /* Default: no prediction resistance */
+    /* (Note, we assume that prediction resistance is not effectively enabled
+     * at compile time by setting a very low reseed interval.) */
+    PSA_ASSERT(psa_generate_random(random, sizeof(random)));
+    TEST_EQUAL(fake_entropy_state.step, 1);
+
+    /* Explicitly enable prediction resistance */
+    PSA_ASSERT(psa_random_set_prediction_resistance(1));
+    TEST_EQUAL(fake_entropy_state.step, 1);
+    PSA_ASSERT(psa_generate_random(random, sizeof(random)));
+    TEST_EQUAL(fake_entropy_state.step, 2);
+    PSA_ASSERT(psa_generate_random(random, sizeof(random)));
+    TEST_EQUAL(fake_entropy_state.step, 3);
+
+    /* Explicitly disable prediction resistance */
+    PSA_ASSERT(psa_random_set_prediction_resistance(0));
+    TEST_EQUAL(fake_entropy_state.step, 3);
+    PSA_ASSERT(psa_generate_random(random, sizeof(random)));
+    TEST_EQUAL(fake_entropy_state.step, 3);
+    PSA_ASSERT(psa_generate_random(random, sizeof(random)));
+    TEST_EQUAL(fake_entropy_state.step, 3);
+
+exit:
+    PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+void reseed_uniqueness(data_t *perso1, data_t *perso2)
+{
+    uint8_t random0[10] = { 0 };
+    uint8_t random1[10] = { 0 };
+    uint8_t random2[10] = { 0 };
+    uint8_t random_again[10] = { 0 };
+    /* Enough for 2 initial seeding + 2 reseed + 2 getrandom with
+     * prediction resistance */
+    size_t max_entropy_queries = 6;
+
+    /* Reference: no reseed */
+    if (!psa_init_deterministic(max_entropy_queries)) {
+        goto exit;
+    }
+    PSA_ASSERT(psa_generate_random(random0, sizeof(random0)));
+    mbedtls_psa_crypto_free();
+
+    /* Reference: no reseed, again */
+    if (!psa_init_deterministic(max_entropy_queries)) {
+        goto exit;
+    }
+    PSA_ASSERT(psa_generate_random(random_again, sizeof(random_again)));
+    mbedtls_psa_crypto_free();
+    TEST_MEMORY_COMPARE(random0, sizeof(random0),
+                        random_again, sizeof(random_again));
+
+    /* Reseed with a personalization string */
+    if (!psa_init_deterministic(max_entropy_queries)) {
+        goto exit;
+    }
+    PSA_ASSERT(psa_random_reseed(perso1->x, perso1->len));
+    PSA_ASSERT(psa_generate_random(random1, sizeof(random1)));
+    mbedtls_psa_crypto_free();
+    TEST_ASSERT(memcmp(random0, random1, sizeof(random1)) != 0);
+
+    /* Reseed with a personalization string (same or different) */
+    if (!psa_init_deterministic(max_entropy_queries)) {
+        goto exit;
+    }
+    PSA_ASSERT(psa_random_reseed(perso2->x, perso2->len));
+    PSA_ASSERT(psa_generate_random(random2, sizeof(random2)));
+    mbedtls_psa_crypto_free();
+    if (perso1->len == perso2->len &&
+        memcmp(perso1->x, perso2->x, perso1->len) == 0) {
+        TEST_MEMORY_COMPARE(random1, sizeof(random1),
+                            random2, sizeof(random2));
+    } else {
+        TEST_ASSERT(memcmp(random1, random2, sizeof(random2)) != 0);
+    }
+
+    /* Reseed twice */
+    if (!psa_init_deterministic(max_entropy_queries)) {
+        goto exit;
+    }
+    PSA_ASSERT(psa_random_reseed(perso1->x, perso1->len));
+    PSA_ASSERT(psa_random_reseed(perso1->x, perso1->len));
+    PSA_ASSERT(psa_generate_random(random2, sizeof(random2)));
+    mbedtls_psa_crypto_free();
+    TEST_ASSERT(memcmp(random0, random2, sizeof(random2)) != 0);
+    TEST_ASSERT(memcmp(random1, random2, sizeof(random2)) != 0);
+
+exit:
+    PSA_DONE();
+}
+/* END_CASE */
+
 /* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
 void external_rng_failure_generate()
 {
@@ -83,6 +612,11 @@
     PSA_ASSERT(psa_generate_key(&attributes, &key));
     PSA_ASSERT(psa_destroy_key(key));
 
+    TEST_EQUAL(psa_random_reseed(NULL, 0), PSA_ERROR_NOT_SUPPORTED);
+    TEST_EQUAL(psa_random_deplete(), PSA_ERROR_NOT_SUPPORTED);
+    TEST_EQUAL(psa_random_set_prediction_resistance(0), PSA_ERROR_NOT_SUPPORTED);
+    TEST_EQUAL(psa_random_set_prediction_resistance(1), PSA_ERROR_NOT_SUPPORTED);
+
     mbedtls_test_disable_insecure_external_rng();
     TEST_EQUAL(PSA_ERROR_INSUFFICIENT_ENTROPY,
                psa_generate_random(output, sizeof(output)));
@@ -146,6 +680,81 @@
 }
 /* END_CASE */
 
+/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG:MBEDTLS_PLATFORM_IS_UNIXLIKE */
+/* Test that if a program calls fork(), the PSA RNG returns different byte
+ * sequences in each child process, and that they're different from the
+ * parent process.
+ *
+ * The argument parent_when controls when the parent calls
+ * psa_generate_random(): -1 = never, 0 = before forking, >0 = after forking
+ * that many children.
+ *
+ * Note that passing tests don't mean that everything is fine, they only
+ * mean that things are not too obviously broken. It's possible to badly
+ * design the RNG so that, for example, different child processes will
+ * have the same RNG output sequence but at an offset, or so that a child
+ * process's RNG is seeded from RNG output of the parent (making it
+ * predictable if an adversary happens to be able to get the right chunk
+ * of RNG output from th parent), or different sequencing of forking
+ * grand^n-children ends up with them having identical RNG output sequences.
+ * These bad designs are practically impossible to detect through testing,
+ * and must be excluded by human reasoning on the RNG design.
+ */
+void psa_rng_fork(int parent_when)
+{
+    struct {
+        /* We read 16 bytes from the RNG. This is large enough so that the
+         * probability of a coincidence is negligible, and small enough that
+         * the RNG won't spontaneously decide reseed to unless it has
+         * prediction resistance. */
+        unsigned char rng_output[16];
+    } child[2], parent;
+    memset(child, 0, sizeof(child));
+    memset(&parent, 0, sizeof(parent));
+
+    PSA_INIT();
+
+    /* Create some child processes, have them generate random data
+     * and report that data back to the original process. */
+    for (size_t i = 0; i < ARRAY_LENGTH(child); i++) {
+        mbedtls_test_set_step(i);
+        if ((size_t) parent_when == i) {
+            PSA_ASSERT(psa_generate_random(parent.rng_output,
+                                           sizeof(parent.rng_output)));
+        }
+        size_t length;
+        TEST_EQUAL(mbedtls_test_fork_run_child(
+                       child_psa_get_random, NULL,
+                       child[i].rng_output, sizeof(child[i].rng_output),
+                       &length), 0);
+        TEST_EQUAL(length, sizeof(child[i].rng_output));
+    }
+
+    if (parent_when == ARRAY_LENGTH(child)) {
+        PSA_ASSERT(psa_generate_random(parent.rng_output,
+                                       sizeof(parent.rng_output)));
+    }
+
+    /* Did the children have different RNG states? */
+    TEST_ASSERT(memcmp(child[0].rng_output,
+                       child[1].rng_output,
+                       sizeof(parent.rng_output)) != 0);
+    /* If parent_when >= 0: did the children have different RNG states
+     * from the parent?
+     * If parent_when < 0: did the children get nonzero RNG output?
+     */
+    for (size_t i = 0; i < ARRAY_LENGTH(child); i++) {
+        mbedtls_test_set_step(i);
+        TEST_ASSERT(memcmp(parent.rng_output,
+                           child[i].rng_output,
+                           sizeof(parent.rng_output)) != 0);
+    }
+
+exit:
+    PSA_DONE();
+}
+/* END_CASE */
+
 /* BEGIN_CASE depends_on:MBEDTLS_PSA_INJECT_ENTROPY */
 void validate_entropy_seed_injection(int seed_length_a,
                                      int expected_status_a,
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_psa_crypto.function mbedtls-3.6.6/tests/suites/test_suite_psa_crypto.function
--- mbedtls-3.6.5/tests/suites/test_suite_psa_crypto.function	2025-10-14 19:12:37.083654000 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_psa_crypto.function	2026-03-27 19:00:27.673466700 +0200
@@ -6490,11 +6490,94 @@
     PSA_ASSERT(psa_aead_set_nonce(&operation, nonce->x, nonce->len));
 
     if (operation.alg == PSA_ALG_CCM) {
-        PSA_ASSERT(psa_aead_finish(&operation, final_data,
+        /* For CCM, finishing without setting lengths must fail. */
+        TEST_EQUAL(psa_aead_finish(&operation, final_data,
                                    finish_output_size,
                                    &output_part_length,
                                    tag_buffer, tag_length,
-                                   &tag_size));
+                                   &tag_size),
+                   PSA_ERROR_BAD_STATE);
+        psa_aead_abort(&operation);
+
+        /* For CCM, finishing after setting length without aead_update/ad must fail. */
+        PSA_ASSERT(psa_aead_encrypt_setup(&operation, key, alg));
+        PSA_ASSERT(psa_aead_set_nonce(&operation, nonce->x, nonce->len));
+
+        PSA_ASSERT(psa_aead_set_lengths(&operation, additional_data->len,
+                                        input_data->len));
+        TEST_EQUAL(psa_aead_finish(&operation, final_data,
+                                   finish_output_size,
+                                   &output_part_length,
+                                   tag_buffer, tag_length,
+                                   &tag_size),
+                   PSA_ERROR_INVALID_ARGUMENT);
+        psa_aead_abort(&operation);
+
+        /* Valid path */
+        PSA_ASSERT(psa_aead_encrypt_setup(&operation, key, alg));
+        PSA_ASSERT(psa_aead_set_nonce(&operation, nonce->x, nonce->len));
+
+        PSA_ASSERT(psa_aead_set_lengths(&operation, additional_data->len,
+                                        input_data->len));
+        PSA_ASSERT(psa_aead_update_ad(&operation, additional_data->x,
+                                      additional_data->len));
+        PSA_ASSERT(psa_aead_update(&operation, input_data->x,
+                                   input_data->len, output_data,
+                                   output_size, &output_length));
+
+        TEST_EQUAL(psa_aead_finish(&operation, final_data,
+                                   finish_output_size,
+                                   &output_part_length,
+                                   tag_buffer, tag_length,
+                                   &tag_size),
+                   PSA_SUCCESS);
+        psa_aead_abort(&operation);
+
+        /* For CCM, verifying without setting lengths must fail. */
+        PSA_ASSERT(psa_aead_decrypt_setup(&operation, key, alg));
+        PSA_ASSERT(psa_aead_set_nonce(&operation, nonce->x, nonce->len));
+        TEST_EQUAL(psa_aead_verify(&operation, final_data,
+                                   finish_output_size,
+                                   &output_part_length,
+                                   tag_buffer,
+                                   tag_length),
+                   PSA_ERROR_BAD_STATE);
+        psa_aead_abort(&operation);
+
+        /* For CCM, verifying after setting length without aead_update/ad must fail. */
+        PSA_ASSERT(psa_aead_decrypt_setup(&operation, key, alg));
+        PSA_ASSERT(psa_aead_set_nonce(&operation, nonce->x, nonce->len));
+
+        PSA_ASSERT(psa_aead_set_lengths(&operation, additional_data->len,
+                                        input_data->len));
+        TEST_EQUAL(psa_aead_verify(&operation, final_data,
+                                   finish_output_size,
+                                   &output_part_length,
+                                   tag_buffer,
+                                   tag_length),
+                   PSA_ERROR_INVALID_ARGUMENT);
+        psa_aead_abort(&operation);
+
+        /* Valid path */
+        PSA_ASSERT(psa_aead_decrypt_setup(&operation, key, alg));
+        PSA_ASSERT(psa_aead_set_nonce(&operation, nonce->x, nonce->len));
+
+        PSA_ASSERT(psa_aead_set_lengths(&operation, additional_data->len,
+                                        input_data->len));
+        PSA_ASSERT(psa_aead_update_ad(&operation, additional_data->x,
+                                      additional_data->len));
+        PSA_ASSERT(psa_aead_update(&operation, input_data->x,
+                                   input_data->len, output_data,
+                                   output_size, &output_length));
+
+        /* psa_driver_wrapper_aead_verify, which is called after psa_aead_final_checks
+           will return PSA_ERROR_INVALID_SIGNATURE */
+        TEST_EQUAL(psa_aead_verify(&operation, final_data,
+                                   finish_output_size,
+                                   &output_part_length,
+                                   tag_buffer,
+                                   tag_length),
+                   PSA_ERROR_INVALID_SIGNATURE);
     } else {
         PSA_ASSERT(psa_aead_finish(&operation, final_data,
                                    finish_output_size,
@@ -6562,11 +6645,97 @@
                                        PSA_AEAD_NONCE_MAX_SIZE,
                                        &nonce_length));
     if (operation.alg == PSA_ALG_CCM) {
-        PSA_ASSERT(psa_aead_finish(&operation, final_data,
+        /* For CCM, finishing without setting lengths must fail. */
+        TEST_EQUAL(psa_aead_finish(&operation, final_data,
                                    finish_output_size,
                                    &output_part_length,
                                    tag_buffer, tag_length,
-                                   &tag_size));
+                                   &tag_size),
+                   PSA_ERROR_BAD_STATE);
+        psa_aead_abort(&operation);
+
+        /* For CCM, finishing after setting length without aead_update/ad must fail. */
+        PSA_ASSERT(psa_aead_encrypt_setup(&operation, key, alg));
+        PSA_ASSERT(psa_aead_generate_nonce(&operation, nonce_buffer,
+                                           PSA_AEAD_NONCE_MAX_SIZE,
+                                           &nonce_length));
+
+        PSA_ASSERT(psa_aead_set_lengths(&operation, additional_data->len,
+                                        input_data->len));
+        TEST_EQUAL(psa_aead_finish(&operation, final_data,
+                                   finish_output_size,
+                                   &output_part_length,
+                                   tag_buffer, tag_length,
+                                   &tag_size),
+                   PSA_ERROR_INVALID_ARGUMENT);
+        psa_aead_abort(&operation);
+
+        /* Valid path */
+        PSA_ASSERT(psa_aead_encrypt_setup(&operation, key, alg));
+        PSA_ASSERT(psa_aead_generate_nonce(&operation, nonce_buffer,
+                                           PSA_AEAD_NONCE_MAX_SIZE,
+                                           &nonce_length));
+
+        PSA_ASSERT(psa_aead_set_lengths(&operation, additional_data->len,
+                                        input_data->len));
+        PSA_ASSERT(psa_aead_update_ad(&operation, additional_data->x,
+                                      additional_data->len));
+        PSA_ASSERT(psa_aead_update(&operation, input_data->x,
+                                   input_data->len, output_data,
+                                   output_size, &output_length));
+
+        TEST_EQUAL(psa_aead_finish(&operation, final_data,
+                                   finish_output_size,
+                                   &output_part_length,
+                                   tag_buffer, tag_length,
+                                   &tag_size),
+                   PSA_SUCCESS);
+        psa_aead_abort(&operation);
+
+        /* For CCM, verifying without setting lengths must fail. */
+        PSA_ASSERT(psa_aead_decrypt_setup(&operation, key, alg));
+        PSA_ASSERT(psa_aead_set_nonce(&operation, nonce->x, nonce->len));
+        TEST_EQUAL(psa_aead_verify(&operation, final_data,
+                                   finish_output_size,
+                                   &output_part_length,
+                                   tag_buffer,
+                                   tag_length),
+                   PSA_ERROR_BAD_STATE);
+        psa_aead_abort(&operation);
+
+        /* For CCM, verifying after setting length without aead_update/ad must fail. */
+        PSA_ASSERT(psa_aead_decrypt_setup(&operation, key, alg));
+        PSA_ASSERT(psa_aead_set_nonce(&operation, nonce->x, nonce->len));
+
+        PSA_ASSERT(psa_aead_set_lengths(&operation, additional_data->len,
+                                        input_data->len));
+        TEST_EQUAL(psa_aead_verify(&operation, final_data,
+                                   finish_output_size,
+                                   &output_part_length,
+                                   tag_buffer,
+                                   tag_length),
+                   PSA_ERROR_INVALID_ARGUMENT);
+        psa_aead_abort(&operation);
+
+        /* Valid path */
+        PSA_ASSERT(psa_aead_decrypt_setup(&operation, key, alg));
+        PSA_ASSERT(psa_aead_set_nonce(&operation, nonce->x, nonce->len));
+        PSA_ASSERT(psa_aead_set_lengths(&operation, additional_data->len,
+                                        input_data->len));
+        PSA_ASSERT(psa_aead_update_ad(&operation, additional_data->x,
+                                      additional_data->len));
+        PSA_ASSERT(psa_aead_update(&operation, input_data->x,
+                                   input_data->len, output_data,
+                                   output_size, &output_length));
+
+        /* psa_driver_wrapper_aead_verify, which is called after psa_aead_final_checks
+           will return PSA_ERROR_INVALID_SIGNATURE */
+        TEST_EQUAL(psa_aead_verify(&operation, final_data,
+                                   finish_output_size,
+                                   &output_part_length,
+                                   tag_buffer,
+                                   tag_length),
+                   PSA_ERROR_INVALID_SIGNATURE);
     } else {
         PSA_ASSERT(psa_aead_finish(&operation, final_data,
                                    finish_output_size,
@@ -9797,7 +9966,7 @@
 void key_agreement_setup(int alg_arg,
                          int our_key_type_arg, int our_key_alg_arg,
                          data_t *our_key_data, data_t *peer_key_data,
-                         int expected_status_arg)
+                         int expected_status_keyag_arg)
 {
     mbedtls_svc_key_id_t our_key = MBEDTLS_SVC_KEY_ID_INIT;
     psa_algorithm_t alg = alg_arg;
@@ -9805,8 +9974,7 @@
     psa_key_type_t our_key_type = our_key_type_arg;
     psa_key_derivation_operation_t operation = psa_key_derivation_operation_init_short();
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-    psa_status_t expected_status = expected_status_arg;
-    psa_status_t status;
+    psa_status_t expected_status_keyag = expected_status_keyag_arg;
 
     PSA_ASSERT(psa_crypto_init());
 
@@ -9817,20 +9985,13 @@
                               our_key_data->x, our_key_data->len,
                               &our_key));
 
-    /* The tests currently include inputs that should fail at either step.
-     * Test cases that fail at the setup step should be changed to call
-     * key_derivation_setup instead, and this function should be renamed
-     * to key_agreement_fail. */
-    status = psa_key_derivation_setup(&operation, alg);
-    if (status == PSA_SUCCESS) {
-        TEST_EQUAL(psa_key_derivation_key_agreement(
-                       &operation, PSA_KEY_DERIVATION_INPUT_SECRET,
-                       our_key,
-                       peer_key_data->x, peer_key_data->len),
-                   expected_status);
-    } else {
-        TEST_ASSERT(status == expected_status);
-    }
+    PSA_ASSERT(psa_key_derivation_setup(&operation, alg));
+
+    TEST_EQUAL(psa_key_derivation_key_agreement(
+                   &operation, PSA_KEY_DERIVATION_INPUT_SECRET,
+                   our_key,
+                   peer_key_data->x, peer_key_data->len),
+               expected_status_keyag);
 
 exit:
     psa_key_derivation_abort(&operation);
@@ -9840,15 +10001,17 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
-void raw_key_agreement(int alg_arg,
-                       int our_key_type_arg, data_t *our_key_data,
-                       data_t *peer_key_data,
-                       data_t *expected_output)
+void key_agreement(int alg_arg,
+                   int our_key_type_arg, data_t *our_key_data,
+                   data_t *peer_key_data,
+                   data_t *expected_output,
+                   int expected_status)
 {
     mbedtls_svc_key_id_t our_key = MBEDTLS_SVC_KEY_ID_INIT;
     psa_algorithm_t alg = alg_arg;
     psa_key_type_t our_key_type = our_key_type_arg;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    unsigned char *bad_peer_key = NULL;
     unsigned char *output = NULL;
     size_t output_length = ~0;
     size_t key_bits;
@@ -9866,36 +10029,105 @@
     key_bits = psa_get_key_bits(&attributes);
 
     /* Validate size macros */
-    TEST_LE_U(expected_output->len,
-              PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE(our_key_type, key_bits));
+    if (expected_status == PSA_SUCCESS) {
+        TEST_LE_U(expected_output->len,
+                  PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE(our_key_type, key_bits));
+    }
     TEST_LE_U(PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE(our_key_type, key_bits),
               PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE);
 
+    /* Note: the case where we expect PSA_ERROR_BUFFER_TOO_SMALL is not covered
+     * by separate test data, but by additional code below in this function. */
+    const size_t output_alloc_size = expected_status == PSA_SUCCESS ?
+                                     expected_output->len :
+                                     PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE(our_key_type, key_bits);
+
     /* Good case with exact output size */
-    TEST_CALLOC(output, expected_output->len);
-    PSA_ASSERT(psa_raw_key_agreement(alg, our_key,
+    TEST_CALLOC(output, output_alloc_size);
+    TEST_EQUAL(psa_raw_key_agreement(alg, our_key,
+                                     peer_key_data->x, peer_key_data->len,
+                                     output, output_alloc_size,
+                                     &output_length),
+               expected_status);
+    if (expected_status == PSA_SUCCESS) {
+        TEST_MEMORY_COMPARE(output, output_length,
+                            expected_output->x, expected_output->len);
+    }
+    mbedtls_free(output);
+    output = NULL;
+    output_length = ~0;
+
+    /* Larger output buffer */
+    TEST_CALLOC(output, output_alloc_size + 1);
+    TEST_EQUAL(psa_raw_key_agreement(alg, our_key,
                                      peer_key_data->x, peer_key_data->len,
+                                     output, output_alloc_size + 1,
+                                     &output_length),
+               expected_status);
+    if (expected_status == PSA_SUCCESS) {
+        TEST_MEMORY_COMPARE(output, output_length,
+                            expected_output->x, expected_output->len);
+    }
+    mbedtls_free(output);
+    output = NULL;
+    output_length = ~0;
+
+    /* The tests for wrong buffer sizes only make sense with good data. */
+    if (expected_status != PSA_SUCCESS) {
+        goto exit;
+    }
+
+    /* Input buffer (peer key) too small */
+    size_t bad_peer_key_len = peer_key_data->len - 1;
+    TEST_CALLOC(bad_peer_key, bad_peer_key_len);
+    memcpy(bad_peer_key, peer_key_data->x, bad_peer_key_len);
+    TEST_CALLOC(output, expected_output->len);
+    TEST_EQUAL(PSA_ERROR_INVALID_ARGUMENT,
+               psa_raw_key_agreement(alg, our_key,
+                                     bad_peer_key, bad_peer_key_len,
                                      output, expected_output->len,
                                      &output_length));
-    TEST_MEMORY_COMPARE(output, output_length,
-                        expected_output->x, expected_output->len);
     mbedtls_free(output);
     output = NULL;
     output_length = ~0;
+    mbedtls_free(bad_peer_key);
+    bad_peer_key = NULL;
 
-    /* Larger buffer */
-    TEST_CALLOC(output, expected_output->len + 1);
-    PSA_ASSERT(psa_raw_key_agreement(alg, our_key,
-                                     peer_key_data->x, peer_key_data->len,
-                                     output, expected_output->len + 1,
+    /* Input buffer (peer key) too large (leading 0) */
+    bad_peer_key_len = peer_key_data->len + 1;
+    TEST_CALLOC(bad_peer_key, bad_peer_key_len);
+    bad_peer_key[0] = 0x00;
+    memcpy(bad_peer_key + 1, peer_key_data->x, peer_key_data->len);
+    TEST_CALLOC(output, expected_output->len);
+    TEST_EQUAL(PSA_ERROR_INVALID_ARGUMENT,
+               psa_raw_key_agreement(alg, our_key,
+                                     bad_peer_key, bad_peer_key_len,
+                                     output, expected_output->len,
+                                     &output_length));
+    mbedtls_free(output);
+    output = NULL;
+    output_length = ~0;
+    mbedtls_free(bad_peer_key);
+    bad_peer_key = NULL;
+
+    /* Input buffer (peer key) too large (larger value) */
+    bad_peer_key_len = peer_key_data->len + 1;
+    TEST_CALLOC(bad_peer_key, bad_peer_key_len);
+    bad_peer_key[0] = 0x01;
+    memcpy(bad_peer_key + 1, peer_key_data->x, peer_key_data->len);
+    TEST_CALLOC(output, expected_output->len);
+    TEST_EQUAL(PSA_ERROR_INVALID_ARGUMENT,
+               psa_raw_key_agreement(alg, our_key,
+                                     bad_peer_key, bad_peer_key_len,
+                                     output, expected_output->len,
                                      &output_length));
-    TEST_MEMORY_COMPARE(output, output_length,
-                        expected_output->x, expected_output->len);
     mbedtls_free(output);
     output = NULL;
     output_length = ~0;
+    mbedtls_free(bad_peer_key);
+    bad_peer_key = NULL;
 
-    /* Buffer too small */
+    /* Output buffer too small */
     TEST_CALLOC(output, expected_output->len - 1);
     TEST_EQUAL(psa_raw_key_agreement(alg, our_key,
                                      peer_key_data->x, peer_key_data->len,
@@ -9908,6 +10140,7 @@
     output = NULL;
 
 exit:
+    mbedtls_free(bad_peer_key);
     mbedtls_free(output);
     psa_destroy_key(our_key);
     PSA_DONE();
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_psa_crypto_init.data mbedtls-3.6.6/tests/suites/test_suite_psa_crypto_init.data
--- mbedtls-3.6.5/tests/suites/test_suite_psa_crypto_init.data	2025-10-14 19:12:37.089624400 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_psa_crypto_init.data	2026-03-27 19:00:27.677610900 +0200
@@ -1,6 +1,3 @@
-Create NV seed file
-create_nv_seed:
-
 PSA init/deinit
 init_deinit:2
 
@@ -24,49 +21,3 @@
 
 No key slot access after deinit
 validate_module_init_key_based:1
-
-Custom entropy sources: all standard
-custom_entropy_sources:0x0000ffff:PSA_SUCCESS
-
-# MBEDTLS_PSA_INJECT_ENTROPY means that a source of entropy (the seed file)
-# is effectively always available.
-Custom entropy sources: none
-depends_on:!MBEDTLS_PSA_INJECT_ENTROPY
-custom_entropy_sources:0:PSA_ERROR_INSUFFICIENT_ENTROPY
-
-Fake entropy: never returns anything
-fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:0:0:0:0:PSA_ERROR_INSUFFICIENT_ENTROPY
-
-Fake entropy: less than the block size
-fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:-1:-1:-1:PSA_ERROR_INSUFFICIENT_ENTROPY
-
-Fake entropy: not enough for a nonce
-depends_on:ENTROPY_NONCE_LEN != 0
-fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:ENTROPY_NONCE_LEN - 1:-1:-1:-1:PSA_ERROR_INSUFFICIENT_ENTROPY
-
-Fake entropy: one block eventually
-depends_on:ENTROPY_NONCE_LEN == 0
-fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:0:0:0:MBEDTLS_ENTROPY_BLOCK_SIZE:PSA_SUCCESS
-
-Fake entropy: one block in two steps
-depends_on:ENTROPY_NONCE_LEN == 0
-fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:1:-1:-1:PSA_SUCCESS
-
-Fake entropy: more than one block in two steps
-depends_on:ENTROPY_NONCE_LEN == 0
-fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:-1:-1:PSA_SUCCESS
-
-Fake entropy: two blocks eventually
-fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:0:MBEDTLS_ENTROPY_BLOCK_SIZE:0:MBEDTLS_ENTROPY_BLOCK_SIZE:PSA_SUCCESS
-
-NV seed only: less than minimum
-entropy_from_nv_seed:MBEDTLS_ENTROPY_MIN_PLATFORM - 1:PSA_ERROR_INSUFFICIENT_ENTROPY
-
-NV seed only: less than one block
-entropy_from_nv_seed:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:PSA_ERROR_INSUFFICIENT_ENTROPY
-
-NV seed only: just enough
-entropy_from_nv_seed:ENTROPY_MIN_NV_SEED_SIZE:PSA_SUCCESS
-
-Recreate NV seed file
-create_nv_seed:
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_psa_crypto_init.function mbedtls-3.6.6/tests/suites/test_suite_psa_crypto_init.function
--- mbedtls-3.6.5/tests/suites/test_suite_psa_crypto_init.function	2025-10-14 19:12:37.089777000 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_psa_crypto_init.function	2026-03-27 19:00:27.677751500 +0200
@@ -2,12 +2,9 @@
 #include <stdint.h>
 
 #include "psa_crypto_core.h"
-/* Some tests in this module configure entropy sources. */
+/* For mbedtls_psa_crypto_configure_entropy_sources() */
 #include "psa_crypto_invasive.h"
 
-#include "mbedtls/entropy.h"
-#include "entropy_poll.h"
-
 static int check_stats(void)
 {
     mbedtls_psa_stats_t stats;
@@ -25,111 +22,6 @@
     return 0;
 }
 
-#define ENTROPY_MIN_NV_SEED_SIZE                                        \
-    MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_BLOCK_SIZE)
-
-#include "psa_crypto_random_impl.h"
-#if defined(MBEDTLS_PSA_HMAC_DRBG_MD_TYPE)
-/* PSA crypto uses the HMAC_DRBG module. It reads from the entropy source twice:
- * once for the initial entropy and once for a nonce. The nonce length is
- * half the entropy length. For SHA-256, SHA-384 or SHA-512, the
- * entropy length is 256 per the documentation of mbedtls_hmac_drbg_seed(),
- * and PSA crypto doesn't support other hashes for HMAC_DRBG. */
-#define ENTROPY_NONCE_LEN (256 / 2)
-#else
-/* PSA crypto uses the CTR_DRBG module. In some configurations, it needs
- * to read from the entropy source twice: once for the initial entropy
- * and once for a nonce. */
-#include "mbedtls/ctr_drbg.h"
-#define ENTROPY_NONCE_LEN MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN
-#endif
-
-#if !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
-
-typedef struct {
-    size_t threshold; /* Minimum bytes to make mbedtls_entropy_func happy */
-    size_t max_steps;
-    size_t *length_sequence;
-    size_t step;
-} fake_entropy_state_t;
-static int fake_entropy_source(void *state_arg,
-                               unsigned char *output, size_t len,
-                               size_t *olen)
-{
-    fake_entropy_state_t *state = state_arg;
-    size_t i;
-
-    if (state->step >= state->max_steps) {
-        return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
-    }
-
-    *olen = MIN(len, state->length_sequence[state->step]);
-    for (i = 0; i < *olen; i++) {
-        output[i] = i;
-    }
-    ++state->step;
-    return 0;
-}
-
-#define ENTROPY_SOURCE_PLATFORM                 0x00000001
-#define ENTROPY_SOURCE_TIMING                   0x00000002
-#define ENTROPY_SOURCE_HARDWARE                 0x00000004
-#define ENTROPY_SOURCE_NV_SEED                  0x00000008
-#define ENTROPY_SOURCE_FAKE                     0x40000000
-
-static uint32_t custom_entropy_sources_mask;
-static fake_entropy_state_t fake_entropy_state;
-
-/* This is a modified version of mbedtls_entropy_init() from entropy.c
- * which chooses entropy sources dynamically. */
-static void custom_entropy_init(mbedtls_entropy_context *ctx)
-{
-    ctx->source_count = 0;
-    memset(ctx->source, 0, sizeof(ctx->source));
-
-#if defined(MBEDTLS_THREADING_C)
-    mbedtls_mutex_init(&ctx->mutex);
-#endif
-
-    ctx->accumulator_started = 0;
-    mbedtls_md_init(&ctx->accumulator);
-
-#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY)
-    if (custom_entropy_sources_mask & ENTROPY_SOURCE_PLATFORM) {
-        mbedtls_entropy_add_source(ctx, mbedtls_platform_entropy_poll, NULL,
-                                   MBEDTLS_ENTROPY_MIN_PLATFORM,
-                                   MBEDTLS_ENTROPY_SOURCE_STRONG);
-    }
-#endif
-#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
-    if (custom_entropy_sources_mask & ENTROPY_SOURCE_HARDWARE) {
-        mbedtls_entropy_add_source(ctx, mbedtls_hardware_poll, NULL,
-                                   MBEDTLS_ENTROPY_MIN_HARDWARE,
-                                   MBEDTLS_ENTROPY_SOURCE_STRONG);
-    }
-#endif
-#if defined(MBEDTLS_ENTROPY_NV_SEED)
-    if (custom_entropy_sources_mask & ENTROPY_SOURCE_NV_SEED) {
-        mbedtls_entropy_add_source(ctx, mbedtls_nv_seed_poll, NULL,
-                                   MBEDTLS_ENTROPY_BLOCK_SIZE,
-                                   MBEDTLS_ENTROPY_SOURCE_STRONG);
-        ctx->initial_entropy_run = 0;
-    } else {
-        /* Skip the NV seed even though it's compiled in. */
-        ctx->initial_entropy_run = 1;
-    }
-#endif
-
-    if (custom_entropy_sources_mask & ENTROPY_SOURCE_FAKE) {
-        mbedtls_entropy_add_source(ctx,
-                                   fake_entropy_source, &fake_entropy_state,
-                                   fake_entropy_state.threshold,
-                                   MBEDTLS_ENTROPY_SOURCE_STRONG);
-    }
-}
-
-#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */
-
 #if defined MBEDTLS_THREADING_PTHREAD
 
 typedef struct {
@@ -190,14 +82,6 @@
  * END_DEPENDENCIES
  */
 
-/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
-void create_nv_seed()
-{
-    static unsigned char seed[ENTROPY_MIN_NV_SEED_SIZE];
-    TEST_ASSERT(mbedtls_nv_seed_write(seed, sizeof(seed)) >= 0);
-}
-/* END_CASE */
-
 /* BEGIN_CASE */
 void init_deinit(int count)
 {
@@ -333,99 +217,3 @@
     TEST_ASSERT(mbedtls_svc_key_id_is_null(key));
 }
 /* END_CASE */
-
-/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
-void custom_entropy_sources(int sources_arg, int expected_init_status_arg)
-{
-    psa_status_t expected_init_status = expected_init_status_arg;
-    uint8_t random[10] = { 0 };
-
-    custom_entropy_sources_mask = sources_arg;
-    PSA_ASSERT(mbedtls_psa_crypto_configure_entropy_sources(
-                   custom_entropy_init, mbedtls_entropy_free));
-
-    TEST_EQUAL(psa_crypto_init(), expected_init_status);
-    if (expected_init_status != PSA_SUCCESS) {
-        goto exit;
-    }
-
-    PSA_ASSERT(psa_generate_random(random, sizeof(random)));
-
-exit:
-    PSA_DONE();
-}
-/* END_CASE */
-
-/* BEGIN_CASE depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
-void fake_entropy_source(int threshold,
-                         int amount1,
-                         int amount2,
-                         int amount3,
-                         int amount4,
-                         int expected_init_status_arg)
-{
-    psa_status_t expected_init_status = expected_init_status_arg;
-    uint8_t random[10] = { 0 };
-    size_t lengths[4];
-
-    fake_entropy_state.threshold = threshold;
-    fake_entropy_state.step = 0;
-    fake_entropy_state.max_steps = 0;
-    if (amount1 >= 0) {
-        lengths[fake_entropy_state.max_steps++] = amount1;
-    }
-    if (amount2 >= 0) {
-        lengths[fake_entropy_state.max_steps++] = amount2;
-    }
-    if (amount3 >= 0) {
-        lengths[fake_entropy_state.max_steps++] = amount3;
-    }
-    if (amount4 >= 0) {
-        lengths[fake_entropy_state.max_steps++] = amount4;
-    }
-    fake_entropy_state.length_sequence = lengths;
-
-    custom_entropy_sources_mask = ENTROPY_SOURCE_FAKE;
-    PSA_ASSERT(mbedtls_psa_crypto_configure_entropy_sources(
-                   custom_entropy_init, mbedtls_entropy_free));
-
-    TEST_EQUAL(psa_crypto_init(), expected_init_status);
-    if (expected_init_status != PSA_SUCCESS) {
-        goto exit;
-    }
-
-    PSA_ASSERT(psa_generate_random(random, sizeof(random)));
-
-exit:
-    PSA_DONE();
-}
-/* END_CASE */
-
-/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
-void entropy_from_nv_seed(int seed_size_arg,
-                          int expected_init_status_arg)
-{
-    psa_status_t expected_init_status = expected_init_status_arg;
-    uint8_t random[10] = { 0 };
-    uint8_t *seed = NULL;
-    size_t seed_size = seed_size_arg;
-
-    TEST_CALLOC(seed, seed_size);
-    TEST_ASSERT(mbedtls_nv_seed_write(seed, seed_size) >= 0);
-
-    custom_entropy_sources_mask = ENTROPY_SOURCE_NV_SEED;
-    PSA_ASSERT(mbedtls_psa_crypto_configure_entropy_sources(
-                   custom_entropy_init, mbedtls_entropy_free));
-
-    TEST_EQUAL(psa_crypto_init(), expected_init_status);
-    if (expected_init_status != PSA_SUCCESS) {
-        goto exit;
-    }
-
-    PSA_ASSERT(psa_generate_random(random, sizeof(random)));
-
-exit:
-    mbedtls_free(seed);
-    PSA_DONE();
-}
-/* END_CASE */
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_psa_crypto_op_fail.generated.data mbedtls-3.6.6/tests/suites/test_suite_psa_crypto_op_fail.generated.data
--- mbedtls-3.6.5/tests/suites/test_suite_psa_crypto_op_fail.generated.data	2025-10-14 19:12:37.099197100 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_psa_crypto_op_fail.generated.data	2026-03-27 19:00:27.682926000 +0200
@@ -46858,29 +46858,21 @@
 ## # skipped because: not implemented: PSA_WANT_ALG_XTS
 ## PSA mac XTS: invalid with AES
 ## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_AES
-## mac_fail:PSA_KEY_TYPE_AES:"48657265006973206b6579a064617461":PSA_ALG_XTS:PSA_ERROR_INVALID_ARGUMENT
+## mac_fail:PSA_KEY_TYPE_AES:"48657265006973206b6579a06461746148657265006973206b6579a064617461":PSA_ALG_XTS:PSA_ERROR_INVALID_ARGUMENT
+
+PSA cipher XTS: !XTS with AES
+depends_on:!PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_AES
+cipher_fail:PSA_KEY_TYPE_AES:"48657265006973206b6579a06461746148657265006973206b6579a064617461":PSA_ALG_XTS:PSA_ERROR_NOT_SUPPORTED
 
 ## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## PSA mac XTS: invalid with ARIA
+## PSA cipher XTS: incompatible with ARIA
 ## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_ARIA
-## mac_fail:PSA_KEY_TYPE_ARIA:"48657265006973206b6579a064617461":PSA_ALG_XTS:PSA_ERROR_INVALID_ARGUMENT
+## cipher_fail:PSA_KEY_TYPE_ARIA:"48657265006973206b6579a064617461":PSA_ALG_XTS:PSA_ERROR_INVALID_ARGUMENT
 
 ## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## PSA mac XTS: invalid with CAMELLIA
+## PSA cipher XTS: incompatible with CAMELLIA
 ## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_CAMELLIA
-## mac_fail:PSA_KEY_TYPE_CAMELLIA:"48657265006973206b6579a064617461":PSA_ALG_XTS:PSA_ERROR_INVALID_ARGUMENT
-
-PSA cipher XTS: !XTS with AES
-depends_on:!PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_AES
-cipher_fail:PSA_KEY_TYPE_AES:"48657265006973206b6579a064617461":PSA_ALG_XTS:PSA_ERROR_NOT_SUPPORTED
-
-PSA cipher XTS: !XTS with ARIA
-depends_on:!PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_ARIA
-cipher_fail:PSA_KEY_TYPE_ARIA:"48657265006973206b6579a064617461":PSA_ALG_XTS:PSA_ERROR_NOT_SUPPORTED
-
-PSA cipher XTS: !XTS with CAMELLIA
-depends_on:!PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_CAMELLIA
-cipher_fail:PSA_KEY_TYPE_CAMELLIA:"48657265006973206b6579a064617461":PSA_ALG_XTS:PSA_ERROR_NOT_SUPPORTED
+## cipher_fail:PSA_KEY_TYPE_CAMELLIA:"48657265006973206b6579a064617461":PSA_ALG_XTS:PSA_ERROR_INVALID_ARGUMENT
 
 ## # skipped because: not implemented: PSA_WANT_ALG_XTS
 ## PSA cipher XTS: incompatible with CHACHA20
@@ -47048,47 +47040,17 @@
 ## # skipped because: not implemented: PSA_WANT_ALG_XTS
 ## PSA aead XTS: invalid with AES
 ## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_AES
-## aead_fail:PSA_KEY_TYPE_AES:"48657265006973206b6579a064617461":PSA_ALG_XTS:PSA_ERROR_INVALID_ARGUMENT
-
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## PSA aead XTS: invalid with ARIA
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_ARIA
-## aead_fail:PSA_KEY_TYPE_ARIA:"48657265006973206b6579a064617461":PSA_ALG_XTS:PSA_ERROR_INVALID_ARGUMENT
-
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## PSA aead XTS: invalid with CAMELLIA
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_CAMELLIA
-## aead_fail:PSA_KEY_TYPE_CAMELLIA:"48657265006973206b6579a064617461":PSA_ALG_XTS:PSA_ERROR_INVALID_ARGUMENT
+## aead_fail:PSA_KEY_TYPE_AES:"48657265006973206b6579a06461746148657265006973206b6579a064617461":PSA_ALG_XTS:PSA_ERROR_INVALID_ARGUMENT
 
 ## # skipped because: not implemented: PSA_WANT_ALG_XTS
 ## PSA sign XTS: invalid with AES
 ## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_AES
-## sign_fail:PSA_KEY_TYPE_AES:"48657265006973206b6579a064617461":PSA_ALG_XTS:0:PSA_ERROR_INVALID_ARGUMENT
-
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## PSA sign XTS: invalid with ARIA
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_ARIA
-## sign_fail:PSA_KEY_TYPE_ARIA:"48657265006973206b6579a064617461":PSA_ALG_XTS:0:PSA_ERROR_INVALID_ARGUMENT
-
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## PSA sign XTS: invalid with CAMELLIA
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_CAMELLIA
-## sign_fail:PSA_KEY_TYPE_CAMELLIA:"48657265006973206b6579a064617461":PSA_ALG_XTS:0:PSA_ERROR_INVALID_ARGUMENT
+## sign_fail:PSA_KEY_TYPE_AES:"48657265006973206b6579a06461746148657265006973206b6579a064617461":PSA_ALG_XTS:0:PSA_ERROR_INVALID_ARGUMENT
 
 ## # skipped because: not implemented: PSA_WANT_ALG_XTS
 ## PSA asymmetric_encryption XTS: invalid with AES
 ## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_AES
-## asymmetric_encryption_fail:PSA_KEY_TYPE_AES:"48657265006973206b6579a064617461":PSA_ALG_XTS:0:PSA_ERROR_INVALID_ARGUMENT
-
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## PSA asymmetric_encryption XTS: invalid with ARIA
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_ARIA
-## asymmetric_encryption_fail:PSA_KEY_TYPE_ARIA:"48657265006973206b6579a064617461":PSA_ALG_XTS:0:PSA_ERROR_INVALID_ARGUMENT
-
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## PSA asymmetric_encryption XTS: invalid with CAMELLIA
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_CAMELLIA
-## asymmetric_encryption_fail:PSA_KEY_TYPE_CAMELLIA:"48657265006973206b6579a064617461":PSA_ALG_XTS:0:PSA_ERROR_INVALID_ARGUMENT
+## asymmetric_encryption_fail:PSA_KEY_TYPE_AES:"48657265006973206b6579a06461746148657265006973206b6579a064617461":PSA_ALG_XTS:0:PSA_ERROR_INVALID_ARGUMENT
 
 ## # skipped because: not implemented: PSA_WANT_ALG_XTS
 ## PSA key_derivation XTS: invalid
@@ -47098,16 +47060,6 @@
 ## # skipped because: not implemented: PSA_WANT_ALG_XTS
 ## PSA key_agreement XTS: invalid with AES
 ## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_AES
-## key_agreement_fail:PSA_KEY_TYPE_AES:"48657265006973206b6579a064617461":PSA_ALG_XTS:0:PSA_ERROR_INVALID_ARGUMENT
-
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## PSA key_agreement XTS: invalid with ARIA
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_ARIA
-## key_agreement_fail:PSA_KEY_TYPE_ARIA:"48657265006973206b6579a064617461":PSA_ALG_XTS:0:PSA_ERROR_INVALID_ARGUMENT
-
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## PSA key_agreement XTS: invalid with CAMELLIA
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_CAMELLIA
-## key_agreement_fail:PSA_KEY_TYPE_CAMELLIA:"48657265006973206b6579a064617461":PSA_ALG_XTS:0:PSA_ERROR_INVALID_ARGUMENT
+## key_agreement_fail:PSA_KEY_TYPE_AES:"48657265006973206b6579a06461746148657265006973206b6579a064617461":PSA_ALG_XTS:0:PSA_ERROR_INVALID_ARGUMENT
 
 # End of automatically generated file.
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_psa_crypto_persistent_key.data mbedtls-3.6.6/tests/suites/test_suite_psa_crypto_persistent_key.data
--- mbedtls-3.6.5/tests/suites/test_suite_psa_crypto_persistent_key.data	2025-10-14 19:12:37.100426200 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_psa_crypto_persistent_key.data	2026-03-27 19:00:27.683697200 +0200
@@ -33,6 +33,9 @@
 Parse storage: truncated key
 parse_storage_data_check:" ":"":PSA_KEY_LIFETIME_PERSISTENT:PSA_KEY_TYPE_RSA_KEY_PAIR:0:PSA_KEY_USAGE_EXPORT:PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION:PSA_ALG_CATEGORY_SIGN:PSA_ERROR_DATA_INVALID
 
+Key identifier ranges
+key_id_ranges:
+
 # Not specific to files, but only run this test in an environment where the maximum size could be reached.
 Save maximum-size persistent raw key
 depends_on:MBEDTLS_PSA_ITS_FILE_C
@@ -133,3 +136,150 @@
 
 Destroy invalid id: 0xffffffff
 destroy_nonexistent:0xffffffff:PSA_ERROR_INVALID_HANDLE
+
+Load key: owner=0 id=1, good, 1 byte
+load_primed_storage:0:1:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_SUCCESS:PSA_SUCCESS:PSA_SUCCESS
+
+Load key: owner=0 id=2, good
+load_primed_storage:0:2:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_SUCCESS:PSA_SUCCESS:PSA_SUCCESS
+
+Load key: owner=0 id=PSA_KEY_USER_MIN, good
+load_primed_storage:0:PSA_KEY_ID_USER_MIN:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_SUCCESS:PSA_SUCCESS:PSA_SUCCESS
+
+Load key: owner=0 id=PSA_KEY_USER_MAX, good
+load_primed_storage:0:PSA_KEY_ID_USER_MIN:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_SUCCESS:PSA_SUCCESS:PSA_SUCCESS
+
+Load key: owner=0 id=0 (bad id)
+load_primed_storage:0:0:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE:PSA_SUCCESS
+
+Load key: owner=0 id=PSA_KEY_ID_VOLATILE_MIN (bad id)
+load_primed_storage:0:PSA_KEY_ID_VOLATILE_MIN:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE
+
+Load key: owner=0 id=PSA_KEY_ID_VOLATILE_MAX (bad id)
+load_primed_storage:0:PSA_KEY_ID_VOLATILE_MAX:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE
+
+# We use the numerical ID in the test data because the numerical range
+# of built-in keys is part of the interface contract between the library
+# and third-party code that provide built-in keys. We can extend this
+# range, but shrinking it would be an incompatible change.
+Load key: owner=0 id=MBEDTLS_PSA_KEY_ID_BUILTIN_MIN (bad id)
+load_primed_storage:0:0x7fff0000:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_SUCCESS:PSA_SUCCESS:PSA_SUCCESS
+
+Load key: owner=0 id=MBEDTLS_PSA_KEY_ID_BUILTIN_MAX (bad id)
+load_primed_storage:0:0x7fffefff:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_SUCCESS:PSA_SUCCESS:PSA_SUCCESS
+
+Load key: owner=0 id=0x7fffffff (bad id: not in any range)
+load_primed_storage:0:KEY_ID_OUTSIDE_DEFINED_RANGES:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_SUCCESS:PSA_SUCCESS:PSA_SUCCESS
+
+Load key: owner=0 id=0xffff0000 (bad id: reserved file UID, not in use)
+load_primed_storage:0:0xffff0000:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE
+
+Load key: owner=0 id=entropy file seed
+load_primed_storage:0:PSA_CRYPTO_ITS_RANDOM_SEED_UID:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE
+
+Load key: owner=0 id=0xffffffff (bad id: reserved file UID, not in use)
+load_primed_storage:0:0xffffffff:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE
+
+Load key: owner=42 id=2, good
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:42:2:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_SUCCESS:PSA_SUCCESS:PSA_SUCCESS
+
+Load key: owner=42 id=PSA_KEY_USER_MIN, good
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:42:PSA_KEY_ID_USER_MIN:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_SUCCESS:PSA_SUCCESS:PSA_SUCCESS
+
+Load key: owner=42 id=PSA_KEY_USER_MAX, good
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:42:PSA_KEY_ID_USER_MIN:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_SUCCESS:PSA_SUCCESS:PSA_SUCCESS
+
+Load key: owner=42 id=0 (bad id)
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:42:0:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE:PSA_SUCCESS
+
+Load key: owner=42 id=PSA_KEY_ID_VOLATILE_MIN (bad id)
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:42:PSA_KEY_ID_VOLATILE_MIN:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE
+
+Load key: owner=42 id=PSA_KEY_ID_VOLATILE_MAX (bad id)
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:42:PSA_KEY_ID_VOLATILE_MAX:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE
+
+# We use the numerical ID in the test data because the numerical range
+# of built-in keys is part of the interface contract between the library
+# and third-party code that provide built-in keys. We can extend this
+# range, but shrinking it would be an incompatible change.
+Load key: owner=42 id=MBEDTLS_PSA_KEY_ID_BUILTIN_MIN (bad id)
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:42:0x7fff0000:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_SUCCESS:PSA_SUCCESS:PSA_SUCCESS
+
+Load key: owner=42 id=MBEDTLS_PSA_KEY_ID_BUILTIN_MAX (bad id)
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:42:0x7fffefff:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_SUCCESS:PSA_SUCCESS:PSA_SUCCESS
+
+Load key: owner=42 id=0x7fffffff (bad id: not in any range)
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:42:KEY_ID_OUTSIDE_DEFINED_RANGES:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_SUCCESS:PSA_SUCCESS:PSA_SUCCESS
+
+Load key: owner=42 id=0xffff0000 (bad id: reserved file UID, not in use)
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:42:0xffff0000:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE
+
+Load key: owner=42 id=(entropy file seed & 0xffffffff)
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:42:PSA_CRYPTO_ITS_RANDOM_SEED_UID:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE
+
+Load key: owner=42 id=0xffffffff (bad id: reserved file UID, not in use)
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:42:0xffffffff:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE
+
+Load key: owner=-0x80000000 id=2, good
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:-0x80000000:2:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_SUCCESS:PSA_SUCCESS:PSA_SUCCESS
+
+Load key: owner=-0x80000000 id=PSA_KEY_USER_MIN, good
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:-0x80000000:PSA_KEY_ID_USER_MIN:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_SUCCESS:PSA_SUCCESS:PSA_SUCCESS
+
+Load key: owner=-0x80000000 id=PSA_KEY_USER_MAX, good
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:-0x80000000:PSA_KEY_ID_USER_MIN:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_SUCCESS:PSA_SUCCESS:PSA_SUCCESS
+
+Load key: owner=-0x80000000 id=0 (bad id)
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:-0x80000000:0:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE:PSA_SUCCESS
+
+Load key: owner=-0x80000000 id=PSA_KEY_ID_VOLATILE_MIN (bad id)
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:-0x80000000:PSA_KEY_ID_VOLATILE_MIN:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE
+
+Load key: owner=-0x80000000 id=PSA_KEY_ID_VOLATILE_MAX (bad id)
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:-0x80000000:PSA_KEY_ID_VOLATILE_MAX:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE
+
+# We use the numerical ID in the test data because the numerical range
+# of built-in keys is part of the interface contract between the library
+# and third-party code that provide built-in keys. We can extend this
+# range, but shrinking it would be an incompatible change.
+Load key: owner=-0x80000000 id=MBEDTLS_PSA_KEY_ID_BUILTIN_MIN (bad id)
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:-0x80000000:0x7fff0000:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_SUCCESS:PSA_SUCCESS:PSA_SUCCESS
+
+Load key: owner=-0x80000000 id=MBEDTLS_PSA_KEY_ID_BUILTIN_MAX (bad id)
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:-0x80000000:0x7fffefff:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_SUCCESS:PSA_SUCCESS:PSA_SUCCESS
+
+Load key: owner=-0x80000000 id=0x7fffffff (bad id: not in any range)
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:-0x80000000:KEY_ID_OUTSIDE_DEFINED_RANGES:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_SUCCESS:PSA_SUCCESS:PSA_SUCCESS
+
+Load key: owner=-0x80000000 id=0xffff0000 (bad id: reserved file UID, not in use)
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:-0x80000000:0xffff0000:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE
+
+Load key: owner=-0x80000000 id=(entropy file seed & 0xffffffff)
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:-0x80000000:PSA_CRYPTO_ITS_RANDOM_SEED_UID:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE
+
+Load key: owner=-0x80000000 id=0xffffffff (bad id: reserved file UID, not in use)
+depends_on:MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+load_primed_storage:-0x80000000:0xffffffff:"505341004b455900000000000100000001100800010000000000000000000000010000004c":PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_psa_crypto_persistent_key.function mbedtls-3.6.6/tests/suites/test_suite_psa_crypto_persistent_key.function
--- mbedtls-3.6.5/tests/suites/test_suite_psa_crypto_persistent_key.function	2025-10-14 19:12:37.100662000 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_psa_crypto_persistent_key.function	2026-03-27 19:00:27.683838100 +0200
@@ -14,9 +14,32 @@
 
 #include <stdint.h>
 
+#include "mbedtls/ctr_drbg.h"
+#include "psa_crypto_its.h"
 #include "psa_crypto_slot_management.h"
 #include "psa_crypto_storage.h"
 
+#define KEY_ID_IN_USER_RANGE(id)                                        \
+    (PSA_KEY_ID_USER_MIN <= (id) && (id) <= PSA_KEY_ID_USER_MAX)
+
+#define KEY_ID_IN_VOLATILE_RANGE(id)                                    \
+    (PSA_KEY_ID_VOLATILE_MIN <= (id) && (id) <= PSA_KEY_ID_VOLATILE_MAX)
+
+#if defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS)
+#define KEY_ID_IN_BUILTIN_RANGE(id)                                     \
+    (MBEDTLS_PSA_KEY_ID_BUILTIN_MIN <= (id) && (id) <= MBEDTLS_PSA_KEY_ID_BUILTIN_MAX)
+#else
+#define KEY_ID_IN_BUILTIN_RANGE(id) 0
+#endif
+
+/* Range of file UIDs reserved for uses other than storing a key.
+ * Defined by the TF-PSA-Crypto storage specification
+ * docs/architecture/mbed-crypto-storage-specification.md */
+#define KEY_ID_IN_RESERVED_FILE_ID_RANGE(id) (0xffff0000 <= ((id) & 0xffffffff))
+
+/* Define a key ID that is in none of the recognized ranges and not 0 */
+#define KEY_ID_OUTSIDE_DEFINED_RANGES 0x7fffffffu
+
 #define PSA_KEY_STORAGE_MAGIC_HEADER "PSA\0KEY"
 #define PSA_KEY_STORAGE_MAGIC_HEADER_LENGTH (sizeof(PSA_KEY_STORAGE_MAGIC_HEADER))
 
@@ -34,6 +57,9 @@
     uint8_t key_data[];
 } psa_persistent_key_storage_format;
 
+const size_t persistent_key_payload_offset =
+    offsetof(psa_persistent_key_storage_format, key_data);
+
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
@@ -118,6 +144,48 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
+void key_id_ranges()
+{
+    /* PSA Crypto API specification */
+    TEST_EQUAL(PSA_KEY_ID_NULL, 0x00000000);
+    TEST_EQUAL(PSA_KEY_ID_USER_MIN, 0x00000001);
+    TEST_EQUAL(PSA_KEY_ID_USER_MAX, 0x3fffffff);
+    TEST_EQUAL(PSA_KEY_ID_VENDOR_MIN, 0x40000000);
+    TEST_EQUAL(PSA_KEY_ID_VENDOR_MAX, 0x7fffffff);
+
+    /* Volatile key IDs */
+    TEST_LE_U(PSA_KEY_ID_VENDOR_MIN, PSA_KEY_ID_VOLATILE_MIN);
+    TEST_LE_U(PSA_KEY_ID_VOLATILE_MAX, PSA_KEY_ID_VENDOR_MAX);
+    TEST_LE_U(PSA_KEY_ID_VOLATILE_MIN, PSA_KEY_ID_VOLATILE_MAX);
+
+    /* Built-in key IDs */
+    /* Mbed TLS 2.27 reserved  0x7fff0000..0x7fffefff for built-in keys.
+     * Integrators may have hard-coded built-in key IDs in this range,
+     * so if this range starts conflicting with something else, it's
+     * an incompatible change. */
+#if defined(MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS)
+    TEST_LE_U(MBEDTLS_PSA_KEY_ID_BUILTIN_MIN, 0x7fff0000);
+    TEST_LE_U(MBEDTLS_PSA_KEY_ID_BUILTIN_MAX, 0x7fffefff);
+    TEST_LE_U(PSA_KEY_ID_VENDOR_MIN, MBEDTLS_PSA_KEY_ID_BUILTIN_MIN);
+    TEST_LE_U(MBEDTLS_PSA_KEY_ID_BUILTIN_MAX, PSA_KEY_ID_VENDOR_MAX);
+#endif /* MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */
+    /* To avoid confusion, make sure we avoid the built-in key ID range
+     * even in builds without built-in keys.. */
+    if (PSA_KEY_ID_VOLATILE_MIN <= 0x7fff0000) {
+        TEST_LE_U(PSA_KEY_ID_VOLATILE_MAX + 1, 0x7fff0000);
+    } else {
+        TEST_LE_U(0x7fffefff + 1, PSA_KEY_ID_VOLATILE_MIN);
+    }
+
+    /* Sanity check on test data */
+    TEST_ASSERT(!KEY_ID_IN_USER_RANGE(KEY_ID_OUTSIDE_DEFINED_RANGES));
+    TEST_ASSERT(!KEY_ID_IN_VOLATILE_RANGE(KEY_ID_OUTSIDE_DEFINED_RANGES));
+    TEST_ASSERT(!KEY_ID_IN_BUILTIN_RANGE(KEY_ID_OUTSIDE_DEFINED_RANGES));
+    TEST_ASSERT(!KEY_ID_IN_RESERVED_FILE_ID_RANGE(KEY_ID_OUTSIDE_DEFINED_RANGES));
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
 void save_large_persistent_key(int data_length_arg, int expected_status)
 {
     mbedtls_svc_key_id_t key_id = mbedtls_svc_key_id_make(1, 42);
@@ -338,3 +406,173 @@
     PSA_DONE();
 }
 /* END_CASE */
+
+/* BEGIN_CASE */
+/* Write content to the file that corresponds to the given key ID,
+ * then attempt to use a key with this ID.
+ * Depending on the validity of the key ID and storage content,
+ * this may or may not work.
+ */
+void load_primed_storage(int32_t owner_id,
+                         int64_t key_id_arg, /* 0..2^32-1 */
+                         data_t *content,
+                         int expected_attributes_status_arg,
+                         int expected_export_status_arg,
+                         int expected_destroy_status_arg)
+{
+    mbedtls_svc_key_id_t key_id = mbedtls_svc_key_id_make(owner_id, key_id_arg);
+    /* Storage UID (file name) for the given key ID, following the storage
+     * specification. */
+    psa_storage_uid_t uid = (uint64_t) owner_id << 32 | key_id_arg;
+    psa_status_t expected_attributes_status = expected_attributes_status_arg;
+    psa_status_t expected_export_status = expected_export_status_arg;
+    psa_status_t expected_destroy_status = expected_destroy_status_arg;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    uint8_t *key_data = NULL;
+    struct psa_storage_info_t info;
+
+    /* Sanity checks on the test data */
+    /* The test framework doesn't support unsigned types, so check that
+     * the key ID is in the actual valid range here. */
+    TEST_LE_U(0, key_id_arg);
+    TEST_LE_U(key_id_arg, 0xffffffff);
+#if !defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER)
+    TEST_EQUAL(owner_id, 0);
+#endif
+
+    PSA_INIT();
+
+    /* This is the start of the test case, so normally, no key exists.
+     * The test data is based on the assumption that the key doesn't exist.
+     * However, there are some cases where a key does exist:
+     * - A volatile key used by the PSA RNG.
+     * - A built-in key provided by the platform (in our test code:
+     *   mbedtls_psa_platform_get_builtin_key() in platform_builtin_keys.c).
+     * In such cases, we'll have different expectations.
+     */
+    int key_already_existed =
+        psa_get_key_attributes(key_id, &attributes) == PSA_SUCCESS;
+    if (key_already_existed) {
+        expected_attributes_status = PSA_SUCCESS;
+        expected_export_status =
+            (psa_get_key_usage_flags(&attributes) & PSA_KEY_USAGE_EXPORT ?
+             PSA_SUCCESS :
+             PSA_KEY_TYPE_IS_PUBLIC_KEY(psa_get_key_type(&attributes)) ?
+             PSA_SUCCESS :
+             PSA_ERROR_NOT_PERMITTED);
+    }
+    /* In case this is a built-in key, psa_get_key_attributes()
+     * loads it into the cache. Purge the cache to make sure the loading
+     * code gets triggered. */
+    psa_purge_key(key_id);
+
+    /* Prime the storage. */
+    psa_status_t file_status = psa_its_get_info(uid, &info);
+    if (uid == 0) {
+        /* 0 is not a valid file ID, according to the PSA secure storage
+         * API specification. */
+        if (file_status == PSA_ERROR_DOES_NOT_EXIST) {
+            /* Our own partial storage implementation (psa_its_file.c)
+             * is not compliant, it returns the wrong error code here.
+             * That's not a problem, just let it go. */
+        } else {
+            TEST_EQUAL(file_status, PSA_ERROR_INVALID_ARGUMENT);
+        }
+    } else if (KEY_ID_IN_RESERVED_FILE_ID_RANGE(key_id_arg) &&
+               file_status == PSA_SUCCESS) {
+        /* The key ID corresponds to a reserved file (e.g. transaction
+         * log or entropy seed). Don't corrupt that file. */
+    } else {
+        TEST_EQUAL(file_status, PSA_ERROR_DOES_NOT_EXIST);
+        TEST_EQUAL(psa_its_set(uid, content->len, content->x, 0), PSA_SUCCESS);
+    }
+
+    /* Reading attributes should work for any valid key. */
+    TEST_EQUAL(psa_get_key_attributes(key_id, &attributes),
+               expected_attributes_status);
+    if (expected_attributes_status == PSA_SUCCESS && !key_already_existed) {
+        /* It's not our job here to validate the attributes, but do
+         * sanity-check the attributes related to persistence. */
+        TEST_ASSERT(mbedtls_svc_key_id_equal(key_id,
+                                             psa_get_key_id(&attributes)));
+        TEST_EQUAL(psa_get_key_lifetime(&attributes),
+                   PSA_KEY_LIFETIME_PERSISTENT);
+    }
+
+    /* Extract the key material from the file.
+     * We assume that the file uses the standard key representation in
+     * storage, which is always the case at the time of writing.
+     * If the file is truncated, there is no key material, and we just
+     * declare an empty buffer here.
+     */
+    const uint8_t *payload = NULL;
+    size_t payload_length = 0;
+    if (content->len >= persistent_key_payload_offset) {
+        payload = content->x + persistent_key_payload_offset;
+        payload_length = content->len - persistent_key_payload_offset;
+    }
+
+    /* Exporting should work for a valid key that has export permission. */
+    /* Allocate enough memory for the key data (assuming the key
+     * representation in storage is not compressed compared to the
+     * export format). */
+    size_t key_data_size = content->len;
+    size_t key_data_length = SIZE_MAX;
+    TEST_CALLOC(key_data, key_data_size);
+    TEST_EQUAL(psa_export_key(key_id,
+                              key_data, key_data_size, &key_data_length),
+               expected_export_status);
+    if (expected_export_status == PSA_SUCCESS) {
+        if (key_already_existed) {
+            /* The key already existed. We don't know what it is,
+             * but check that it is not what we put in storage. */
+            TEST_ASSERT(key_data_length != payload_length ||
+                        memcmp(key_data, payload, payload_length));
+        } else {
+            TEST_MEMORY_COMPARE(key_data, key_data_length,
+                                payload, payload_length);
+        }
+    }
+    /* Assert that the data length is sensible even if export failed.
+     * This reduces the risk of memory corruption if an application
+     * doesn't check the return status of export(). */
+    TEST_LE_U(key_data_length, key_data_size);
+
+    if (key_already_existed) {
+        /* There was a key with the key ID under test, for example a key
+         * used by the PSA RNG. Don't disrupt whatever is using that key.
+         * Pure the key cache: this is necessary if the key was a built-in
+         * key which got loaded into the cache by the get_attributes and
+         * export calls above, otherwise PSA_DONE() would legitimately
+         * complain about a non-empty cache.
+         */
+        psa_purge_key(key_id);
+    } else {
+        /* Destroying the key should work even for malformed content.
+         * But it should not work for reserved file IDs. */
+        TEST_EQUAL(psa_destroy_key(key_id), expected_destroy_status);
+        if (uid == 0) {
+            /* Invalid file UID. No point in asserting anything about the file. */
+        } else if (expected_destroy_status == PSA_SUCCESS) {
+            file_status = psa_its_get_info(uid, &info);
+            if (key_id_arg == 0) {
+                /* psa_destroy_key(0) is defined as a no-op, so it should not
+                 * affect the file. */
+                TEST_EQUAL(file_status, PSA_SUCCESS);
+            } else {
+                TEST_EQUAL(file_status, PSA_ERROR_DOES_NOT_EXIST);
+            }
+        }
+    }
+
+exit:
+    psa_reset_key_attributes(&attributes);
+    PSA_DONE();
+    if (!KEY_ID_IN_RESERVED_FILE_ID_RANGE(key_id_arg)) {
+        /* The key ID corresponds to a reserved file (e.g. transaction
+         * log or entropy seed). Don't corrupt that file. */
+        psa_its_remove(uid);
+    }
+    mbedtls_free(key_data);
+}
+/* END_CASE */
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_psa_crypto_storage_format.current.data mbedtls-3.6.6/tests/suites/test_suite_psa_crypto_storage_format.current.data
--- mbedtls-3.6.5/tests/suites/test_suite_psa_crypto_storage_format.current.data	2025-10-14 19:12:37.104888000 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_psa_crypto_storage_format.current.data	2026-03-27 19:00:27.685970500 +0200
@@ -186,9 +186,9 @@
 ## key_storage_save:0x0001:PSA_KEY_TYPE_AES:128:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_TRUNCATED_MAC(PSA_ALG_CBC_MAC,16):0x0000:"48657265006973206b6579a064617461":"505341004b455900000000000100000000248000013c00000001d003000000001000000048657265006973206b6579a064617461"
 
 ## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## save type: AES 128-bit, XTS
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_AES
-## key_storage_save:0x0001:PSA_KEY_TYPE_AES:128:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a064617461":"505341004b4559000000000001000000002480000103000000ff4004000000001000000048657265006973206b6579a064617461"
+## save type: AES 256-bit, XTS
+## depends_on:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_AES
+## key_storage_save:0x0001:PSA_KEY_TYPE_AES:256:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b4559000000000001000000002400010103000000ff4004000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461"
 
 save type: AES 192-bit
 depends_on:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:PSA_WANT_KEY_TYPE_AES
@@ -271,11 +271,6 @@
 ## depends_on:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:PSA_WANT_ALG_CBC_MAC:PSA_WANT_KEY_TYPE_AES
 ## key_storage_save:0x0001:PSA_KEY_TYPE_AES:192:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_TRUNCATED_MAC(PSA_ALG_CBC_MAC,16):0x0000:"48657265006973206b6579a0646174614865726500697320":"505341004b45590000000000010000000024c000013c00000001d003000000001800000048657265006973206b6579a0646174614865726500697320"
 
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## save type: AES 192-bit, XTS
-## depends_on:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_AES
-## key_storage_save:0x0001:PSA_KEY_TYPE_AES:192:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a0646174614865726500697320":"505341004b45590000000000010000000024c0000103000000ff4004000000001800000048657265006973206b6579a0646174614865726500697320"
-
 save type: AES 256-bit
 depends_on:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:PSA_WANT_KEY_TYPE_AES
 key_storage_save:0x0001:PSA_KEY_TYPE_AES:256:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b4559000000000001000000002400010100000000000000000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461"
@@ -358,9 +353,9 @@
 ## key_storage_save:0x0001:PSA_KEY_TYPE_AES:256:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_TRUNCATED_MAC(PSA_ALG_CBC_MAC,16):0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b455900000000000100000000240001013c00000001d003000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461"
 
 ## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## save type: AES 256-bit, XTS
-## depends_on:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_AES
-## key_storage_save:0x0001:PSA_KEY_TYPE_AES:256:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b4559000000000001000000002400010103000000ff4004000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461"
+## save type: AES 512-bit, XTS
+## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_AES
+## key_storage_save:0x0001:PSA_KEY_TYPE_AES:512:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a06461746148657265006973206b6579a06461746148657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b4559000000000001000000002400020103000000ff4004000000004000000048657265006973206b6579a06461746148657265006973206b6579a06461746148657265006973206b6579a06461746148657265006973206b6579a064617461"
 
 save type: ARIA 128-bit
 depends_on:PSA_WANT_KEY_TYPE_ARIA
@@ -435,11 +430,6 @@
 ## depends_on:PSA_WANT_ALG_CBC_MAC:PSA_WANT_KEY_TYPE_ARIA
 ## key_storage_save:0x0001:PSA_KEY_TYPE_ARIA:128:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_TRUNCATED_MAC(PSA_ALG_CBC_MAC,16):0x0000:"48657265006973206b6579a064617461":"505341004b455900000000000100000006248000013c00000001d003000000001000000048657265006973206b6579a064617461"
 
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## save type: ARIA 128-bit, XTS
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_ARIA
-## key_storage_save:0x0001:PSA_KEY_TYPE_ARIA:128:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a064617461":"505341004b4559000000000001000000062480000103000000ff4004000000001000000048657265006973206b6579a064617461"
-
 save type: ARIA 192-bit
 depends_on:PSA_WANT_KEY_TYPE_ARIA
 key_storage_save:0x0001:PSA_KEY_TYPE_ARIA:192:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"48657265006973206b6579a0646174614865726500697320":"505341004b45590000000000010000000624c0000100000000000000000000001800000048657265006973206b6579a0646174614865726500697320"
@@ -513,11 +503,6 @@
 ## depends_on:PSA_WANT_ALG_CBC_MAC:PSA_WANT_KEY_TYPE_ARIA
 ## key_storage_save:0x0001:PSA_KEY_TYPE_ARIA:192:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_TRUNCATED_MAC(PSA_ALG_CBC_MAC,16):0x0000:"48657265006973206b6579a0646174614865726500697320":"505341004b45590000000000010000000624c000013c00000001d003000000001800000048657265006973206b6579a0646174614865726500697320"
 
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## save type: ARIA 192-bit, XTS
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_ARIA
-## key_storage_save:0x0001:PSA_KEY_TYPE_ARIA:192:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a0646174614865726500697320":"505341004b45590000000000010000000624c0000103000000ff4004000000001800000048657265006973206b6579a0646174614865726500697320"
-
 save type: ARIA 256-bit
 depends_on:PSA_WANT_KEY_TYPE_ARIA
 key_storage_save:0x0001:PSA_KEY_TYPE_ARIA:256:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b4559000000000001000000062400010100000000000000000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461"
@@ -591,11 +576,6 @@
 ## depends_on:PSA_WANT_ALG_CBC_MAC:PSA_WANT_KEY_TYPE_ARIA
 ## key_storage_save:0x0001:PSA_KEY_TYPE_ARIA:256:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_TRUNCATED_MAC(PSA_ALG_CBC_MAC,16):0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b455900000000000100000006240001013c00000001d003000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461"
 
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## save type: ARIA 256-bit, XTS
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_ARIA
-## key_storage_save:0x0001:PSA_KEY_TYPE_ARIA:256:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b4559000000000001000000062400010103000000ff4004000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461"
-
 save type: CAMELLIA 128-bit
 depends_on:PSA_WANT_KEY_TYPE_CAMELLIA
 key_storage_save:0x0001:PSA_KEY_TYPE_CAMELLIA:128:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"48657265006973206b6579a064617461":"505341004b4559000000000001000000032480000100000000000000000000001000000048657265006973206b6579a064617461"
@@ -669,11 +649,6 @@
 ## depends_on:PSA_WANT_ALG_CBC_MAC:PSA_WANT_KEY_TYPE_CAMELLIA
 ## key_storage_save:0x0001:PSA_KEY_TYPE_CAMELLIA:128:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_TRUNCATED_MAC(PSA_ALG_CBC_MAC,16):0x0000:"48657265006973206b6579a064617461":"505341004b455900000000000100000003248000013c00000001d003000000001000000048657265006973206b6579a064617461"
 
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## save type: CAMELLIA 128-bit, XTS
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_CAMELLIA
-## key_storage_save:0x0001:PSA_KEY_TYPE_CAMELLIA:128:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a064617461":"505341004b4559000000000001000000032480000103000000ff4004000000001000000048657265006973206b6579a064617461"
-
 save type: CAMELLIA 192-bit
 depends_on:PSA_WANT_KEY_TYPE_CAMELLIA
 key_storage_save:0x0001:PSA_KEY_TYPE_CAMELLIA:192:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"48657265006973206b6579a0646174614865726500697320":"505341004b45590000000000010000000324c0000100000000000000000000001800000048657265006973206b6579a0646174614865726500697320"
@@ -747,11 +722,6 @@
 ## depends_on:PSA_WANT_ALG_CBC_MAC:PSA_WANT_KEY_TYPE_CAMELLIA
 ## key_storage_save:0x0001:PSA_KEY_TYPE_CAMELLIA:192:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_TRUNCATED_MAC(PSA_ALG_CBC_MAC,16):0x0000:"48657265006973206b6579a0646174614865726500697320":"505341004b45590000000000010000000324c000013c00000001d003000000001800000048657265006973206b6579a0646174614865726500697320"
 
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## save type: CAMELLIA 192-bit, XTS
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_CAMELLIA
-## key_storage_save:0x0001:PSA_KEY_TYPE_CAMELLIA:192:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a0646174614865726500697320":"505341004b45590000000000010000000324c0000103000000ff4004000000001800000048657265006973206b6579a0646174614865726500697320"
-
 save type: CAMELLIA 256-bit
 depends_on:PSA_WANT_KEY_TYPE_CAMELLIA
 key_storage_save:0x0001:PSA_KEY_TYPE_CAMELLIA:256:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b4559000000000001000000032400010100000000000000000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461"
@@ -825,11 +795,6 @@
 ## depends_on:PSA_WANT_ALG_CBC_MAC:PSA_WANT_KEY_TYPE_CAMELLIA
 ## key_storage_save:0x0001:PSA_KEY_TYPE_CAMELLIA:256:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_TRUNCATED_MAC(PSA_ALG_CBC_MAC,16):0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b455900000000000100000003240001013c00000001d003000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461"
 
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## save type: CAMELLIA 256-bit, XTS
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_CAMELLIA
-## key_storage_save:0x0001:PSA_KEY_TYPE_CAMELLIA:256:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b4559000000000001000000032400010103000000ff4004000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461"
-
 save type: CHACHA20 256-bit
 depends_on:PSA_WANT_KEY_TYPE_CHACHA20
 key_storage_save:0x0001:PSA_KEY_TYPE_CHACHA20:256:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b4559000000000001000000042000010100000000000000000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461"
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_psa_crypto_storage_format.v0.data mbedtls-3.6.6/tests/suites/test_suite_psa_crypto_storage_format.v0.data
--- mbedtls-3.6.5/tests/suites/test_suite_psa_crypto_storage_format.v0.data	2025-10-14 19:12:37.108060000 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_psa_crypto_storage_format.v0.data	2026-03-27 19:00:27.688298700 +0200
@@ -274,9 +274,9 @@
 ## key_storage_read:0x0001:PSA_KEY_TYPE_AES:128:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_TRUNCATED_MAC(PSA_ALG_CBC_MAC,16):0x0000:"48657265006973206b6579a064617461":"505341004b455900000000000100000000248000013c00000001d003000000001000000048657265006973206b6579a064617461":TEST_FLAG_EXERCISE
 
 ## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## read type: AES 128-bit, XTS
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_AES
-## key_storage_read:0x0001:PSA_KEY_TYPE_AES:128:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a064617461":"505341004b4559000000000001000000002480000103000000ff4004000000001000000048657265006973206b6579a064617461":TEST_FLAG_EXERCISE
+## read type: AES 256-bit, XTS
+## depends_on:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_AES
+## key_storage_read:0x0001:PSA_KEY_TYPE_AES:256:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b4559000000000001000000002400010103000000ff4004000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461":TEST_FLAG_EXERCISE
 
 read type: AES 192-bit
 depends_on:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:PSA_WANT_KEY_TYPE_AES
@@ -359,11 +359,6 @@
 ## depends_on:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:PSA_WANT_ALG_CBC_MAC:PSA_WANT_KEY_TYPE_AES
 ## key_storage_read:0x0001:PSA_KEY_TYPE_AES:192:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_TRUNCATED_MAC(PSA_ALG_CBC_MAC,16):0x0000:"48657265006973206b6579a0646174614865726500697320":"505341004b45590000000000010000000024c000013c00000001d003000000001800000048657265006973206b6579a0646174614865726500697320":TEST_FLAG_EXERCISE
 
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## read type: AES 192-bit, XTS
-## depends_on:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_AES
-## key_storage_read:0x0001:PSA_KEY_TYPE_AES:192:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a0646174614865726500697320":"505341004b45590000000000010000000024c0000103000000ff4004000000001800000048657265006973206b6579a0646174614865726500697320":TEST_FLAG_EXERCISE
-
 read type: AES 256-bit
 depends_on:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:PSA_WANT_KEY_TYPE_AES
 key_storage_read:0x0001:PSA_KEY_TYPE_AES:256:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b4559000000000001000000002400010100000000000000000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461":TEST_FLAG_EXERCISE
@@ -446,9 +441,9 @@
 ## key_storage_read:0x0001:PSA_KEY_TYPE_AES:256:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_TRUNCATED_MAC(PSA_ALG_CBC_MAC,16):0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b455900000000000100000000240001013c00000001d003000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461":TEST_FLAG_EXERCISE
 
 ## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## read type: AES 256-bit, XTS
-## depends_on:!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_AES
-## key_storage_read:0x0001:PSA_KEY_TYPE_AES:256:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b4559000000000001000000002400010103000000ff4004000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461":TEST_FLAG_EXERCISE
+## read type: AES 512-bit, XTS
+## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_AES
+## key_storage_read:0x0001:PSA_KEY_TYPE_AES:512:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a06461746148657265006973206b6579a06461746148657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b4559000000000001000000002400020103000000ff4004000000004000000048657265006973206b6579a06461746148657265006973206b6579a06461746148657265006973206b6579a06461746148657265006973206b6579a064617461":TEST_FLAG_EXERCISE
 
 read type: ARIA 128-bit
 depends_on:PSA_WANT_KEY_TYPE_ARIA
@@ -523,11 +518,6 @@
 ## depends_on:PSA_WANT_ALG_CBC_MAC:PSA_WANT_KEY_TYPE_ARIA
 ## key_storage_read:0x0001:PSA_KEY_TYPE_ARIA:128:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_TRUNCATED_MAC(PSA_ALG_CBC_MAC,16):0x0000:"48657265006973206b6579a064617461":"505341004b455900000000000100000006248000013c00000001d003000000001000000048657265006973206b6579a064617461":TEST_FLAG_EXERCISE
 
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## read type: ARIA 128-bit, XTS
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_ARIA
-## key_storage_read:0x0001:PSA_KEY_TYPE_ARIA:128:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a064617461":"505341004b4559000000000001000000062480000103000000ff4004000000001000000048657265006973206b6579a064617461":TEST_FLAG_EXERCISE
-
 read type: ARIA 192-bit
 depends_on:PSA_WANT_KEY_TYPE_ARIA
 key_storage_read:0x0001:PSA_KEY_TYPE_ARIA:192:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"48657265006973206b6579a0646174614865726500697320":"505341004b45590000000000010000000624c0000100000000000000000000001800000048657265006973206b6579a0646174614865726500697320":TEST_FLAG_EXERCISE
@@ -601,11 +591,6 @@
 ## depends_on:PSA_WANT_ALG_CBC_MAC:PSA_WANT_KEY_TYPE_ARIA
 ## key_storage_read:0x0001:PSA_KEY_TYPE_ARIA:192:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_TRUNCATED_MAC(PSA_ALG_CBC_MAC,16):0x0000:"48657265006973206b6579a0646174614865726500697320":"505341004b45590000000000010000000624c000013c00000001d003000000001800000048657265006973206b6579a0646174614865726500697320":TEST_FLAG_EXERCISE
 
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## read type: ARIA 192-bit, XTS
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_ARIA
-## key_storage_read:0x0001:PSA_KEY_TYPE_ARIA:192:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a0646174614865726500697320":"505341004b45590000000000010000000624c0000103000000ff4004000000001800000048657265006973206b6579a0646174614865726500697320":TEST_FLAG_EXERCISE
-
 read type: ARIA 256-bit
 depends_on:PSA_WANT_KEY_TYPE_ARIA
 key_storage_read:0x0001:PSA_KEY_TYPE_ARIA:256:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b4559000000000001000000062400010100000000000000000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461":TEST_FLAG_EXERCISE
@@ -679,11 +664,6 @@
 ## depends_on:PSA_WANT_ALG_CBC_MAC:PSA_WANT_KEY_TYPE_ARIA
 ## key_storage_read:0x0001:PSA_KEY_TYPE_ARIA:256:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_TRUNCATED_MAC(PSA_ALG_CBC_MAC,16):0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b455900000000000100000006240001013c00000001d003000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461":TEST_FLAG_EXERCISE
 
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## read type: ARIA 256-bit, XTS
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_ARIA
-## key_storage_read:0x0001:PSA_KEY_TYPE_ARIA:256:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b4559000000000001000000062400010103000000ff4004000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461":TEST_FLAG_EXERCISE
-
 read type: CAMELLIA 128-bit
 depends_on:PSA_WANT_KEY_TYPE_CAMELLIA
 key_storage_read:0x0001:PSA_KEY_TYPE_CAMELLIA:128:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"48657265006973206b6579a064617461":"505341004b4559000000000001000000032480000100000000000000000000001000000048657265006973206b6579a064617461":TEST_FLAG_EXERCISE
@@ -757,11 +737,6 @@
 ## depends_on:PSA_WANT_ALG_CBC_MAC:PSA_WANT_KEY_TYPE_CAMELLIA
 ## key_storage_read:0x0001:PSA_KEY_TYPE_CAMELLIA:128:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_TRUNCATED_MAC(PSA_ALG_CBC_MAC,16):0x0000:"48657265006973206b6579a064617461":"505341004b455900000000000100000003248000013c00000001d003000000001000000048657265006973206b6579a064617461":TEST_FLAG_EXERCISE
 
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## read type: CAMELLIA 128-bit, XTS
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_CAMELLIA
-## key_storage_read:0x0001:PSA_KEY_TYPE_CAMELLIA:128:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a064617461":"505341004b4559000000000001000000032480000103000000ff4004000000001000000048657265006973206b6579a064617461":TEST_FLAG_EXERCISE
-
 read type: CAMELLIA 192-bit
 depends_on:PSA_WANT_KEY_TYPE_CAMELLIA
 key_storage_read:0x0001:PSA_KEY_TYPE_CAMELLIA:192:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"48657265006973206b6579a0646174614865726500697320":"505341004b45590000000000010000000324c0000100000000000000000000001800000048657265006973206b6579a0646174614865726500697320":TEST_FLAG_EXERCISE
@@ -835,11 +810,6 @@
 ## depends_on:PSA_WANT_ALG_CBC_MAC:PSA_WANT_KEY_TYPE_CAMELLIA
 ## key_storage_read:0x0001:PSA_KEY_TYPE_CAMELLIA:192:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_TRUNCATED_MAC(PSA_ALG_CBC_MAC,16):0x0000:"48657265006973206b6579a0646174614865726500697320":"505341004b45590000000000010000000324c000013c00000001d003000000001800000048657265006973206b6579a0646174614865726500697320":TEST_FLAG_EXERCISE
 
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## read type: CAMELLIA 192-bit, XTS
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_CAMELLIA
-## key_storage_read:0x0001:PSA_KEY_TYPE_CAMELLIA:192:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a0646174614865726500697320":"505341004b45590000000000010000000324c0000103000000ff4004000000001800000048657265006973206b6579a0646174614865726500697320":TEST_FLAG_EXERCISE
-
 read type: CAMELLIA 256-bit
 depends_on:PSA_WANT_KEY_TYPE_CAMELLIA
 key_storage_read:0x0001:PSA_KEY_TYPE_CAMELLIA:256:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b4559000000000001000000032400010100000000000000000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461":TEST_FLAG_EXERCISE
@@ -913,11 +883,6 @@
 ## depends_on:PSA_WANT_ALG_CBC_MAC:PSA_WANT_KEY_TYPE_CAMELLIA
 ## key_storage_read:0x0001:PSA_KEY_TYPE_CAMELLIA:256:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_VERIFY_MESSAGE:PSA_ALG_TRUNCATED_MAC(PSA_ALG_CBC_MAC,16):0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b455900000000000100000003240001013c00000001d003000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461":TEST_FLAG_EXERCISE
 
-## # skipped because: not implemented: PSA_WANT_ALG_XTS
-## read type: CAMELLIA 256-bit, XTS
-## depends_on:PSA_WANT_ALG_XTS:PSA_WANT_KEY_TYPE_CAMELLIA
-## key_storage_read:0x0001:PSA_KEY_TYPE_CAMELLIA:256:PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_EXPORT:PSA_ALG_XTS:0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b4559000000000001000000032400010103000000ff4004000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461":TEST_FLAG_EXERCISE
-
 read type: CHACHA20 256-bit
 depends_on:PSA_WANT_KEY_TYPE_CHACHA20
 key_storage_read:0x0001:PSA_KEY_TYPE_CHACHA20:256:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"48657265006973206b6579a06461746148657265006973206b6579a064617461":"505341004b4559000000000001000000042000010100000000000000000000002000000048657265006973206b6579a06461746148657265006973206b6579a064617461":TEST_FLAG_EXERCISE
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_ssl.data mbedtls-3.6.6/tests/suites/test_suite_ssl.data
--- mbedtls-3.6.5/tests/suites/test_suite_ssl.data	2025-10-14 19:12:37.113084600 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_ssl.data	2026-03-27 19:00:27.691119700 +0200
@@ -3524,3 +3524,25 @@
 TLS 1.3 Keying Material Exporter: Handshake not done
 depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_TEST_AT_LEAST_ONE_TLS1_3_CIPHERSUITE:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:PSA_WANT_ALG_RSA_PKCS1V15_SIGN:MBEDTLS_X509_RSASSA_PSS_SUPPORT
 ssl_tls_exporter_too_early:MBEDTLS_SSL_VERSION_TLS1_3:1:MBEDTLS_SSL_SERVER_CERTIFICATE
+
+TLS 1.3 - HRR then TLS 1.2 second ClientHello
+tls13_hrr_then_tls12_second_client_hello
+
+Baseline for: Server using sig_alg not offered by the client - RSA with SHA256
+depends_on:MBEDTLS_CAN_HANDLE_RSA_TEST_KEY:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED:MBEDTLS_MD_CAN_SHA256
+send_invalid_sig_alg:MBEDTLS_SSL_SIG_RSA:MBEDTLS_SSL_HASH_SHA256:0
+
+Negative Test: Server using sig_alg not offered by the client - RSA with SHA256
+depends_on:MBEDTLS_CAN_HANDLE_RSA_TEST_KEY:MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED:MBEDTLS_MD_CAN_SHA256
+send_invalid_sig_alg:MBEDTLS_SSL_SIG_RSA:MBEDTLS_SSL_HASH_SHA256:MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER
+
+Baseline for: Server using sig_alg not offered by the client - ECDSA with SHA512
+depends_on:MBEDTLS_CAN_HANDLE_ECDSA_TEST_KEY:MBEDTLS_CAN_HANDLE_ECDSA_CLIENT_TEST_KEY:MBEDTLS_MD_CAN_SHA512
+send_invalid_sig_alg:MBEDTLS_SSL_SIG_ECDSA:MBEDTLS_SSL_HASH_SHA512:0
+
+Negative Test: Server using sig_alg not offered by the client - ECDSA with SHA512
+depends_on:MBEDTLS_CAN_HANDLE_ECDSA_TEST_KEY:MBEDTLS_CAN_HANDLE_ECDSA_CLIENT_TEST_KEY:MBEDTLS_MD_CAN_SHA512
+send_invalid_sig_alg:MBEDTLS_SSL_SIG_ECDSA:MBEDTLS_SSL_HASH_SHA512:MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER
+
+Default verify_result before doing a handshake
+verify_result_without_handshake
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_ssl.function mbedtls-3.6.6/tests/suites/test_suite_ssl.function
--- mbedtls-3.6.5/tests/suites/test_suite_ssl.function	2025-10-14 19:12:37.115257000 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_ssl.function	2026-03-27 19:00:27.691512000 +0200
@@ -5727,6 +5727,140 @@
 }
 /* END_CASE */
 
+/* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:MBEDTLS_SSL_HAVE_CHACHAPOLY:MBEDTLS_MD_CAN_SHA256:MBEDTLS_TEST_HAS_ADDITIONAL_HASH:MBEDTLS_TEST_HAS_DEFAULT_EC_GROUP*/
+void send_invalid_sig_alg(int sig, int hash, int expected_ret)
+{
+    // This is a test about the client behaviour in case it receives a key exchange signed with a
+    // sig_alg it didn't specify in the client hello. The input specifies a target_sig_alg, which we
+    // make sure that the client does not offer but the server does. Then we make the server believe
+    // that target_sig_alg is the only one the client offered.
+
+    // Remark: We need an additional hash algorithm offered, because if we don't have it, the server
+    // realises too early that there is no common ground and we don't get the chance to manipulate
+    // it. This is why we need MBEDTLS_TEST_HAS_ADDITIONAL_HASH in the requirements.
+
+    enum { BUFFSIZE = 16384 };
+    uint16_t *client_sig_algs = NULL;
+    mbedtls_test_ssl_endpoint server, client;
+    memset(&server, 0, sizeof(server));
+    memset(&client, 0, sizeof(client));
+    mbedtls_test_handshake_test_options options;
+    memset(&options, 0, sizeof(options));
+    int forced_ciphersuite[2] = { 0, 0 };
+
+    uint16_t target_sig_alg = ((hash << 8) | sig);
+
+    mbedtls_test_init_handshake_options(&options);
+
+    // Make sure the server has credentials for target_sig_alg
+    if (sig == MBEDTLS_SSL_SIG_ECDSA) {
+        options.pk_alg = MBEDTLS_PK_ECDSA;
+    } else {
+        options.pk_alg = MBEDTLS_PK_RSA;
+    }
+
+    // Force a ciphersuite where target_sig_alg is relevant
+    if (sig == MBEDTLS_SSL_SIG_ECDSA) {
+        forced_ciphersuite[0] =
+            mbedtls_ssl_get_ciphersuite_id("TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256");
+    } else {
+        forced_ciphersuite[0] =
+            mbedtls_ssl_get_ciphersuite_id("TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256");
+    }
+    TEST_ASSERT(forced_ciphersuite[0] != 0);
+
+    // Force TLS 1.2 as this test is a non-regression test for a bug in TLS 1.2 client and TLS 1.3
+    // behaviour in this regard is substantially different.
+    options.client_max_version = MBEDTLS_SSL_VERSION_TLS1_2;
+    options.server_max_version = MBEDTLS_SSL_VERSION_TLS1_2;
+
+#if defined(MBEDTLS_DEBUG_C)
+    mbedtls_test_ssl_log_pattern cli_pattern;
+    cli_pattern.pattern = "that was not offered";
+    cli_pattern.counter = 0;
+    options.cli_log_obj = &cli_pattern;
+    options.cli_log_fun = mbedtls_test_ssl_log_analyzer;
+    // Add loggers for easier debugging - we are not looking for any patterns in the server logs.
+    // To turn on debug output, uncomment the threshold line and set the macro in the definition
+    // of mbedtls_test_ssl_log_analyzer().
+    options.srv_log_obj = NULL;
+    options.srv_log_fun = mbedtls_test_ssl_log_analyzer;
+    mbedtls_debug_set_threshold(3);
+#endif
+
+    int ret = -1;
+
+    PSA_INIT();
+
+    ret = mbedtls_test_ssl_endpoint_init(&client, MBEDTLS_SSL_IS_CLIENT,
+                                         &options, NULL, NULL, NULL);
+    TEST_EQUAL(ret, 0);
+
+    mbedtls_ssl_conf_ciphersuites(&client.conf, forced_ciphersuite);
+
+    // Remove the target signature algorithm from the client's list
+    size_t client_sig_algs_len = 0;
+    while (client.conf.sig_algs[client_sig_algs_len++] != MBEDTLS_TLS1_3_SIG_NONE) {
+        ;
+    }
+    client_sig_algs_len--;
+
+    TEST_CALLOC(client_sig_algs, client_sig_algs_len);
+    size_t j = 0;
+    for (size_t i = 0; client.conf.sig_algs[i] != MBEDTLS_TLS1_3_SIG_NONE; i++) {
+        if (client.conf.sig_algs[i] != target_sig_alg) {
+            client_sig_algs[j++] = client.conf.sig_algs[i];
+        }
+    }
+    TEST_ASSERT(j < client_sig_algs_len);
+    client_sig_algs[j] = MBEDTLS_TLS1_3_SIG_NONE;
+    mbedtls_ssl_conf_sig_algs(&client.conf, client_sig_algs);
+
+    ret = mbedtls_test_ssl_endpoint_init(&server, MBEDTLS_SSL_IS_SERVER,
+                                         &options, NULL, NULL, NULL);
+    TEST_EQUAL(ret, 0);
+
+    mbedtls_ssl_conf_ciphersuites(&server.conf, forced_ciphersuite);
+
+    ret = mbedtls_test_mock_socket_connect(&server.socket, &client.socket,
+                                           BUFFSIZE);
+    TEST_EQUAL(ret, 0);
+
+    // Move the connection to the point before the server sending the key exchange message
+    ret = mbedtls_test_move_handshake_to_state(&server.ssl, &client.ssl,
+                                               MBEDTLS_SSL_SERVER_KEY_EXCHANGE);
+    TEST_EQUAL(ret, 0);
+
+    if (expected_ret != 0) {
+        // Make the server believe that the only sig_alg the client accepts is target_sig_alg
+        server.ssl.handshake->received_sig_algs[0] = target_sig_alg;
+        server.ssl.handshake->received_sig_algs[1] = MBEDTLS_TLS1_3_SIG_NONE;
+    }
+
+    // Move the connection to a state where it is certain that the client has parsed the server key
+    // exchange
+    ret = mbedtls_test_move_handshake_to_state(&client.ssl, &server.ssl,
+                                               MBEDTLS_SSL_CERTIFICATE_REQUEST);
+    TEST_EQUAL(ret, expected_ret);
+
+#if defined(MBEDTLS_DEBUG_C)
+    if (expected_ret != 0) {
+        TEST_EQUAL(cli_pattern.counter, 1);
+    }
+#endif
+
+exit:
+#if defined(MBEDTLS_DEBUG_C)
+    mbedtls_debug_set_threshold(0);
+#endif
+    mbedtls_test_free_handshake_options(&options);
+    mbedtls_test_ssl_endpoint_free(&server, NULL);
+    mbedtls_test_ssl_endpoint_free(&client, NULL);
+    mbedtls_free(client_sig_algs);
+    PSA_DONE();
+}
+/* END_CASE */
+
 /* BEGIN_CASE depends_on:MBEDTLS_SSL_KEYING_MATERIAL_EXPORT:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED:PSA_WANT_ECC_SECP_R1_384:PSA_WANT_ALG_SHA_256 */
 void ssl_tls_exporter_consistent_result(int proto, int exported_key_length, int use_context)
 {
@@ -5999,3 +6133,186 @@
     MD_OR_USE_PSA_DONE();
 }
 /* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_CLI_C:MBEDTLS_SSL_SRV_C:MBEDTLS_TEST_HAS_TLS1_3_CHACHA20_POLY1305_SHA256:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED:MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED:PSA_WANT_ALG_SHA_256:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ECC_SECP_R1_384:MBEDTLS_PK_CAN_ECDSA_SIGN:MBEDTLS_PK_CAN_ECDSA_VERIFY:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_DEBUG_C */
+void tls13_hrr_then_tls12_second_client_hello()
+{
+    int ret = -1;
+    mbedtls_test_ssl_endpoint client_ep, server_ep;
+    memset(&client_ep, 0, sizeof(client_ep));
+    memset(&server_ep, 0, sizeof(server_ep));
+    mbedtls_test_handshake_test_options client_options;
+    mbedtls_test_handshake_test_options server_options;
+    mbedtls_ssl_session saved_session;
+    mbedtls_test_ssl_log_pattern server_pattern =
+    { "Non compliant 2nd ClientHello, TLS 1.2 version", 0 };
+    uint16_t group_list[3] = {
+        MBEDTLS_SSL_IANA_TLS_GROUP_SECP256R1,
+        MBEDTLS_SSL_IANA_TLS_GROUP_SECP384R1,
+        MBEDTLS_SSL_IANA_TLS_GROUP_NONE
+    };
+    const int tls12_ciphersuite_list[2] = {
+        MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+        0
+    };
+
+    mbedtls_test_init_handshake_options(&client_options);
+    mbedtls_test_init_handshake_options(&server_options);
+    mbedtls_ssl_session_init(&saved_session);
+
+    PSA_INIT();
+
+    /*
+     * Run first handshake to get a ticket from the server.
+     */
+    client_options.pk_alg = MBEDTLS_PK_ECDSA;
+    client_options.group_list = group_list;
+    client_options.cipher = "TLS1-3-CHACHA20-POLY1305-SHA256";
+    server_options.pk_alg = MBEDTLS_PK_ECDSA;
+    server_options.group_list = group_list;
+
+    ret = mbedtls_test_get_tls13_ticket(&client_options, &server_options,
+                                        &saved_session);
+    TEST_EQUAL(ret, 0);
+
+    /*
+     * Prepare for handshake with the ticket.
+     */
+    /* Remove the group SECP256R1 from the list of groups supported by the
+     * server. Since it is the client's preferred group, the client will
+     * send a key share only for SECP256R1, forcing the server to send a HRR.
+     */
+    server_options.group_list = group_list + 1;
+
+    ret = mbedtls_test_ssl_endpoint_init(&client_ep, MBEDTLS_SSL_IS_CLIENT,
+                                         &client_options, NULL, NULL, NULL);
+    TEST_EQUAL(ret, 0);
+
+    server_options.srv_log_fun = mbedtls_test_ssl_log_analyzer;
+    server_options.srv_log_obj = &server_pattern;
+    ret = mbedtls_test_ssl_endpoint_init(&server_ep, MBEDTLS_SSL_IS_SERVER,
+                                         &server_options, NULL, NULL, NULL);
+    TEST_EQUAL(ret, 0);
+
+    mbedtls_ssl_conf_session_tickets_cb(&server_ep.conf,
+                                        mbedtls_test_ticket_write,
+                                        mbedtls_test_ticket_parse,
+                                        NULL);
+
+    ret = mbedtls_test_mock_socket_connect(&(client_ep.socket),
+                                           &(server_ep.socket), 1024);
+    TEST_EQUAL(ret, 0);
+
+    ret = mbedtls_ssl_set_session(&(client_ep.ssl), &saved_session);
+    TEST_EQUAL(ret, 0);
+
+    /*
+     * Progress the handshake up to the point where the server has sent the
+     * HRR and the client has received and processed the server HRR but not
+     * written the second ClientHello in response to the HRR.
+     */
+    ret = mbedtls_test_move_handshake_to_state(
+        &(server_ep.ssl), &(client_ep.ssl),
+        MBEDTLS_SSL_HELLO_RETRY_REQUEST);
+    TEST_EQUAL(ret, 0);
+    TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO);
+
+    ret = mbedtls_test_move_handshake_to_state(
+        &(client_ep.ssl), &(server_ep.ssl),
+        MBEDTLS_SSL_CLIENT_HELLO);
+    TEST_EQUAL(ret, 0);
+    TEST_EQUAL(server_ep.ssl.state, MBEDTLS_SSL_CLIENT_HELLO);
+
+    #if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE)
+    /* If the compatibility mode is enabled, filter the dummy change_cipher_spec
+     * record sent by the server after the HRR. Otherwise, as we have switched
+     * the client to TLS 1.2 it would fail when reading this record.
+     */
+    ret = mbedtls_ssl_read_record(&(client_ep.ssl), 0);
+    TEST_EQUAL(ret, MBEDTLS_ERR_SSL_WANT_READ);
+    #endif
+
+    /*
+     * The client has just received the server's HRR and is expected to send a
+     * second ClientHello. Instead of sending a compliant second TLS 1.3
+     * ClientHello, we want it to send a TLS 1.2-only ClientHello. To achieve
+     * this, we reset the client with a TLS 1.2-only configuration before
+     * resuming the handshake with the server.
+     */
+    client_ep.ssl.tls_version = MBEDTLS_SSL_VERSION_TLS1_2;
+    mbedtls_ssl_conf_min_tls_version(&client_ep.conf, MBEDTLS_SSL_VERSION_TLS1_2);
+    mbedtls_ssl_conf_max_tls_version(&client_ep.conf, MBEDTLS_SSL_VERSION_TLS1_2);
+    mbedtls_ssl_conf_ciphersuites(&client_ep.conf, tls12_ciphersuite_list);
+
+    ret = mbedtls_ssl_session_reset(&(client_ep.ssl));
+    TEST_EQUAL(ret, 0);
+
+    /*
+     * Restart and try to complete the handshake on server side which is
+     * expected to fail early.
+     */
+
+    mbedtls_debug_set_threshold(1);
+    ret = mbedtls_test_move_handshake_to_state(
+        &(server_ep.ssl), &(client_ep.ssl),
+        MBEDTLS_SSL_HANDSHAKE_OVER);
+    TEST_EQUAL(ret, MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER);
+
+    TEST_EQUAL(server_pattern.counter, 1);
+    TEST_EQUAL(client_ep.ssl.state, MBEDTLS_SSL_SERVER_HELLO);
+    TEST_EQUAL(server_ep.ssl.state, MBEDTLS_SSL_CLIENT_HELLO);
+
+exit:
+    mbedtls_test_ssl_endpoint_free(&client_ep, NULL);
+    mbedtls_test_ssl_endpoint_free(&server_ep, NULL);
+    mbedtls_test_free_handshake_options(&client_options);
+    mbedtls_test_free_handshake_options(&server_options);
+    mbedtls_ssl_session_free(&saved_session);
+    mbedtls_debug_set_threshold(0);
+    PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED */
+void verify_result_without_handshake(void)
+{
+    /* Test the result of verification before we perform a handshake. */
+    mbedtls_ssl_context ssl;
+    mbedtls_ssl_config conf;
+
+    PSA_INIT();
+
+    mbedtls_ssl_init(&ssl);
+    mbedtls_ssl_config_init(&conf);
+
+    TEST_EQUAL(mbedtls_ssl_config_defaults(&conf,
+                                           MBEDTLS_SSL_IS_CLIENT,
+                                           MBEDTLS_SSL_TRANSPORT_STREAM,
+                                           MBEDTLS_SSL_PRESET_DEFAULT), 0);
+
+    mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
+    mbedtls_ssl_conf_ca_chain(&conf, NULL, NULL);
+    mbedtls_ssl_conf_rng(&conf, mbedtls_test_random, NULL);
+
+    TEST_EQUAL(mbedtls_ssl_setup(&ssl, &conf), 0);
+
+    uint32_t verify_result = mbedtls_ssl_get_verify_result(&ssl);
+
+    TEST_EQUAL(verify_result, 0xFFFFFFFF);
+
+    /* Set the verify result manually and check that session_free resets it. */
+
+    /* Set the verify result to 0. */
+    ssl.session_negotiate->verify_result = 0;
+
+    mbedtls_ssl_session_free(ssl.session_negotiate);
+
+    verify_result = mbedtls_ssl_get_verify_result(&ssl);
+    TEST_EQUAL(verify_result, 0xFFFFFFFF);
+
+exit:
+    mbedtls_ssl_config_free(&conf);
+    mbedtls_ssl_free(&ssl);
+    PSA_DONE();
+}
+/* END_CASE */
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_version.data mbedtls-3.6.6/tests/suites/test_suite_version.data
--- mbedtls-3.6.5/tests/suites/test_suite_version.data	2025-10-14 19:12:37.117262400 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_version.data	2026-03-27 19:00:27.693090200 +0200
@@ -1,8 +1,8 @@
 Check compile time library version
-check_compiletime_version:"3.6.5"
+check_compiletime_version:"3.6.6"
 
 Check runtime library version
-check_runtime_version:"3.6.5"
+check_runtime_version:"3.6.6"
 
 Check for MBEDTLS_VERSION_C
 check_feature:"MBEDTLS_VERSION_C":0
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_x509parse.data mbedtls-3.6.6/tests/suites/test_suite_x509parse.data
--- mbedtls-3.6.5/tests/suites/test_suite_x509parse.data	2025-10-14 19:12:37.118100200 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_x509parse.data	2026-03-27 19:00:27.694351000 +0200
@@ -1178,6 +1178,9 @@
 X509 CRT parse CN: IPv6 invalid address IPv4-mapped #3
 x509_crt_parse_cn_inet_pton:"\:\:1.2.3.4\:ffff":"":0
 
+X509 CRT parse CN: IPv6 invalid address IPv4-mapped #4
+x509_crt_parse_cn_inet_pton:"1.2.3.4\:":"":0
+
 X509 CRT verification with ca callback: failure
 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_MD_CAN_SHA1:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK
 x509_verify_ca_cb_failure:"../framework/data_files/server1.crt":"../framework/data_files/test-ca.crt":"NULL":MBEDTLS_ERR_X509_FATAL_ERROR
diff -Nru mbedtls-3.6.5/tests/suites/test_suite_x509parse.function mbedtls-3.6.6/tests/suites/test_suite_x509parse.function
--- mbedtls-3.6.5/tests/suites/test_suite_x509parse.function	2025-10-14 19:12:37.118395000 +0300
+++ mbedtls-3.6.6/tests/suites/test_suite_x509parse.function	2026-03-27 19:00:27.694553600 +0200
@@ -482,12 +482,22 @@
 void x509_crt_parse_cn_inet_pton(const char *cn, data_t *exp, int ref_ret)
 {
     uint32_t addr[4];
-    size_t addrlen = mbedtls_x509_crt_parse_cn_inet_pton(cn, addr);
+
+    char *cn_local = NULL;
+    size_t cn_local_len = strlen(cn) + 1;
+    TEST_CALLOC(cn_local, cn_local_len);
+    memcpy(cn_local, cn, cn_local_len);
+
+    size_t addrlen = mbedtls_x509_crt_parse_cn_inet_pton(cn_local, addr);
     TEST_EQUAL(addrlen, (size_t) ref_ret);
 
     if (addrlen) {
         TEST_MEMORY_COMPARE(exp->x, exp->len, addr, addrlen);
     }
+
+exit:
+    mbedtls_free(cn_local);
+
 }
 /* END_CASE */
 
diff -Nru mbedtls-3.6.5/visualc/VS2017/mbedTLS.vcxproj mbedtls-3.6.6/visualc/VS2017/mbedTLS.vcxproj
--- mbedtls-3.6.5/visualc/VS2017/mbedTLS.vcxproj	2025-10-14 19:12:37.124797300 +0300
+++ mbedtls-3.6.6/visualc/VS2017/mbedTLS.vcxproj	2026-03-27 19:00:27.699087100 +0200
@@ -249,11 +249,14 @@
     <ClInclude Include="..\..\framework\tests\include\test\asn1_helpers.h" />
     <ClInclude Include="..\..\framework\tests\include\test\bignum_codepath_check.h" />
     <ClInclude Include="..\..\framework\tests\include\test\bignum_helpers.h" />
+    <ClInclude Include="..\..\framework\tests\include\test\build_info.h" />
     <ClInclude Include="..\..\framework\tests\include\test\constant_flow.h" />
     <ClInclude Include="..\..\framework\tests\include\test\fake_external_rng_for_test.h" />
+    <ClInclude Include="..\..\framework\tests\include\test\fork_helpers.h" />
     <ClInclude Include="..\..\framework\tests\include\test\helpers.h" />
     <ClInclude Include="..\..\framework\tests\include\test\macros.h" />
     <ClInclude Include="..\..\framework\tests\include\test\memory.h" />
+    <ClInclude Include="..\..\framework\tests\include\test\pk_helpers.h" />
     <ClInclude Include="..\..\framework\tests\include\test\psa_crypto_helpers.h" />
     <ClInclude Include="..\..\framework\tests\include\test\psa_exercise_key.h" />
     <ClInclude Include="..\..\framework\tests\include\test\psa_helpers.h" />
@@ -276,6 +279,7 @@
     <ClInclude Include="..\..\framework\tests\include\test\drivers\signature.h" />
     <ClInclude Include="..\..\framework\tests\include\test\drivers\test_driver.h" />
     <ClInclude Include="..\..\framework\tests\include\test\drivers\test_driver_common.h" />
+    <ClInclude Include="..\..\framework\tests\include\test\drivers\xof.h" />
     <ClInclude Include="..\..\library\aesce.h" />
     <ClInclude Include="..\..\library\aesni.h" />
     <ClInclude Include="..\..\library\alignment.h" />
@@ -323,6 +327,7 @@
     <ClInclude Include="..\..\library\psa_crypto_its.h" />
     <ClInclude Include="..\..\library\psa_crypto_mac.h" />
     <ClInclude Include="..\..\library\psa_crypto_pake.h" />
+    <ClInclude Include="..\..\library\psa_crypto_random.h" />
     <ClInclude Include="..\..\library\psa_crypto_random_impl.h" />
     <ClInclude Include="..\..\library\psa_crypto_rsa.h" />
     <ClInclude Include="..\..\library\psa_crypto_se.h" />
@@ -415,6 +420,7 @@
     <ClCompile Include="..\..\library\psa_crypto_hash.c" />
     <ClCompile Include="..\..\library\psa_crypto_mac.c" />
     <ClCompile Include="..\..\library\psa_crypto_pake.c" />
+    <ClCompile Include="..\..\library\psa_crypto_random.c" />
     <ClCompile Include="..\..\library\psa_crypto_rsa.c" />
     <ClCompile Include="..\..\library\psa_crypto_se.c" />
     <ClCompile Include="..\..\library\psa_crypto_slot_management.c" />
@@ -458,7 +464,9 @@
     <ClCompile Include="..\..\framework\tests\src\bignum_codepath_check.c" />
     <ClCompile Include="..\..\framework\tests\src\bignum_helpers.c" />
     <ClCompile Include="..\..\framework\tests\src\fake_external_rng_for_test.c" />
+    <ClCompile Include="..\..\framework\tests\src\fork_helpers.c" />
     <ClCompile Include="..\..\framework\tests\src\helpers.c" />
+    <ClCompile Include="..\..\framework\tests\src\pk_helpers.c" />
     <ClCompile Include="..\..\framework\tests\src\psa_crypto_helpers.c" />
     <ClCompile Include="..\..\framework\tests\src\psa_crypto_stubs.c" />
     <ClCompile Include="..\..\framework\tests\src\psa_exercise_key.c" />
@@ -478,6 +486,7 @@
     <ClCompile Include="..\..\framework\tests\src\drivers\test_driver_mac.c" />
     <ClCompile Include="..\..\framework\tests\src\drivers\test_driver_pake.c" />
     <ClCompile Include="..\..\framework\tests\src\drivers\test_driver_signature.c" />
+    <ClCompile Include="..\..\framework\tests\src\drivers\xof.c" />
     <ClCompile Include="..\..\3rdparty\everest\library\everest.c" />
     <ClCompile Include="..\..\3rdparty\everest\library\Hacl_Curve25519_joined.c" />
     <ClCompile Include="..\..\3rdparty\everest\library\x25519.c" />
