Merge pull request #10004 from gilles-peskine-arm/doc-threading-needed-by-psa-3.6

Backport 3.6: Document PSA's need for threading
diff --git a/3rdparty/everest/include/everest/kremlin/c_endianness.h b/3rdparty/everest/include/everest/kremlin/c_endianness.h
index 5cfde5d..1b0d0eb 100644
--- a/3rdparty/everest/include/everest/kremlin/c_endianness.h
+++ b/3rdparty/everest/include/everest/kremlin/c_endianness.h
@@ -7,6 +7,8 @@
 #include <string.h>
 #include <inttypes.h>
 
+#include "kremlin/internal/callconv.h"
+
 /******************************************************************************/
 /* Implementing C.fst (part 2: endian-ness macros)                            */
 /******************************************************************************/
diff --git a/3rdparty/everest/include/everest/kremlin/internal/callconv.h b/3rdparty/everest/include/everest/kremlin/internal/callconv.h
index bf631ff..8ff8ca5 100644
--- a/3rdparty/everest/include/everest/kremlin/internal/callconv.h
+++ b/3rdparty/everest/include/everest/kremlin/internal/callconv.h
@@ -27,8 +27,10 @@
 /* Since KreMLin emits the inline keyword unconditionally, we follow the
  * guidelines at https://gcc.gnu.org/onlinedocs/gcc/Inline.html and make this
  * __inline__ to ensure the code compiles with -std=c90 and earlier. */
-#ifdef __GNUC__
+#if defined(__GNUC__)
 #  define inline __inline__
+#elif defined(_MSC_VER)
+#  define inline __inline
 #endif
 
 /* GCC-specific attribute syntax; everyone else gets the standard C inline
diff --git a/3rdparty/everest/include/everest/vs2013/inttypes.h b/3rdparty/everest/include/everest/vs2013/inttypes.h
deleted file mode 100644
index 77003be..0000000
--- a/3rdparty/everest/include/everest/vs2013/inttypes.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- *  Custom inttypes.h for VS2010 KreMLin requires these definitions,
- *  but VS2010 doesn't provide them.
- *
- *  Copyright 2016-2018 INRIA and Microsoft Corporation
- *  SPDX-License-Identifier: Apache-2.0
- *
- *  Licensed under the Apache License, Version 2.0 (the "License"); you may
- *  not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- *
- *  This file is part of Mbed TLS (https://tls.mbed.org)
- */
-
-#ifndef _INTTYPES_H_VS2010
-#define _INTTYPES_H_VS2010
-
-#include <stdint.h>
-
-#ifdef _MSC_VER
-#define inline __inline
-#endif
-
-/* VS2010 unsigned long == 8 bytes */
-
-#define PRIu64 "I64u"
-
-#endif
diff --git a/3rdparty/everest/include/everest/vs2013/stdbool.h b/3rdparty/everest/include/everest/vs2013/stdbool.h
deleted file mode 100644
index dcae6d8..0000000
--- a/3rdparty/everest/include/everest/vs2013/stdbool.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- *  Custom stdbool.h for VS2010 KreMLin requires these definitions,
- *  but VS2010 doesn't provide them.
- *
- *  Copyright 2016-2018 INRIA and Microsoft Corporation
- *  SPDX-License-Identifier: Apache-2.0
- *
- *  Licensed under the Apache License, Version 2.0 (the "License"); you may
- *  not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- *
- *  This file is part of Mbed TLS (https://tls.mbed.org)
- */
-
-#ifndef _STDBOOL_H_VS2010
-#define _STDBOOL_H_VS2010
-
-typedef int bool;
-
-static bool true = 1;
-static bool false = 0;
-
-#endif
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 99e2169..b63b7c3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -61,6 +61,7 @@
 
 # Set the project root directory.
 set(MBEDTLS_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+set(MBEDTLS_FRAMEWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/framework)
 
 option(ENABLE_PROGRAMS "Build Mbed TLS programs." ON)
 
diff --git a/ChangeLog.d/9652.txt b/ChangeLog.d/9652.txt
new file mode 100644
index 0000000..98a8eae
--- /dev/null
+++ b/ChangeLog.d/9652.txt
@@ -0,0 +1,9 @@
+Features
+   * MD module can now perform PSA dispatching also when
+     `MBEDTLS_PSA_CRYPTO_CLIENT && !MBEDTLS_PSA_CRYPTO_C`, even though this
+     configuration is not officially supported. This requires that a
+     PSA Crypto provider library which:
+     * supports the required `PSA_WANT_ALG_xxx` and
+     * implements `psa_can_do_hash()` on the client interface
+     is linked against Mbed TLS and that `psa_crypto_init()` is called before
+     performing any PSA call.
diff --git a/ChangeLog.d/fix-msvc-version-guard-format-zu.txt b/ChangeLog.d/fix-msvc-version-guard-format-zu.txt
new file mode 100644
index 0000000..2713f6c
--- /dev/null
+++ b/ChangeLog.d/fix-msvc-version-guard-format-zu.txt
@@ -0,0 +1,9 @@
+Bugfix
+   * Fix definition of MBEDTLS_PRINTF_SIZET to prevent runtime crashes that
+     occurred whenever SSL debugging was enabled on a copy of Mbed TLS built
+     with Visual Studio 2013 or MinGW.
+     Fixes #10017.
+   * Remove Everest Visual Studio 2010 compatibility headers, which could
+     shadow standard CRT headers inttypes.h and stdbool.h with incomplete
+     implementatios if placed on the include path, eg. when building Mbed TLS
+     with the .sln file shipped with the project.
diff --git a/ChangeLog.d/tls-hs-defrag-in.txt b/ChangeLog.d/tls-hs-defrag-in.txt
new file mode 100644
index 0000000..6bab02a
--- /dev/null
+++ b/ChangeLog.d/tls-hs-defrag-in.txt
@@ -0,0 +1,7 @@
+Bugfix
+   * Support re-assembly of fragmented handshake messages in TLS (both
+     1.2 and 1.3). The lack of support was causing handshake failures with
+     some servers, especially with TLS 1.3 in practice. There are a few
+     limitations, notably a fragmented ClientHello is only supported when
+     TLS 1.3 support is enabled. See the documentation of
+     mbedtls_ssl_handshake() for details.
diff --git a/SECURITY.md b/SECURITY.md
index 7ed72de..0af1903 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -144,3 +144,22 @@
 
 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
+
+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.
+
+**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).
+
+However, Mbed TLS aims to protect against memory corruption and other
+undefined behavior when parsing certificates and CSRs. If a CSR or signed
+certificate causes undefined behavior when it is parsed by Mbed TLS, that
+is considered a security vulnerability.
diff --git a/docs/architecture/psa-migration/md-cipher-dispatch.md b/docs/architecture/psa-migration/md-cipher-dispatch.md
index eda65a3..89b7b61 100644
--- a/docs/architecture/psa-migration/md-cipher-dispatch.md
+++ b/docs/architecture/psa-migration/md-cipher-dispatch.md
@@ -17,36 +17,44 @@
 
 #### Backward compatibility user story
 
-As a developer of an application that uses Mbed TLS's interfaces (including legacy crypto),  
-I want Mbed TLS to preserve backward compatibility,  
+As a developer of an application that uses Mbed TLS's interfaces (including legacy crypto),
+I want Mbed TLS to preserve backward compatibility,
 so that my code keeps working in new minor versions of Mbed TLS.
 
 #### Interface design user story
 
-As a developer of library code that uses Mbed TLS to perform cryptographic operations,  
-I want to know which functions to call and which feature macros to check,  
+As a developer of library code that uses Mbed TLS to perform cryptographic operations,
+I want to know which functions to call and which feature macros to check,
 so that my code works in all Mbed TLS configurations.
 
 Note: this is the same problem we face in X.509 and TLS.
 
 #### Hardware accelerator vendor user stories
 
-As a vendor of a platform with hardware acceleration for some crypto,  
-I want to build Mbed TLS in a way that uses my hardware wherever relevant,  
+As a vendor of a platform with hardware acceleration for some crypto,
+I want to build Mbed TLS in a way that uses my hardware wherever relevant,
 so that my customers maximally benefit from my hardware.
 
-As a vendor of a platform with hardware acceleration for some crypto,  
-I want to build Mbed TLS without software that replicates what my hardware does,  
+As a vendor of a platform with hardware acceleration for some crypto,
+I want to build Mbed TLS without software that replicates what my hardware does,
 to minimize the code size.
 
+#### Integrators of Mbed TLS alongside a PSA Crypto provider
+
+I have a platform where the PSA Crypto is already provided "externally" from
+Mbed TLS (ex: through TF-M in Zephyr) and I would like Mbed TLS to make use
+of it whenever possible in order to benefit from higher performances (if some
+hardware acceleration is supported in the provider) and/or higher isolation/security
+(if the PSA provider is running in a completetly separated/inaccessible context).
+
 #### Maintainer user stories
 
-As a maintainer of Mbed TLS,  
-I want to have clear rules for when to use which interface,  
+As a maintainer of Mbed TLS,
+I want to have clear rules for when to use which interface,
 to avoid bugs in “unusual” configurations.
 
-As a maintainer of Mbed TLS,  
-I want to avoid duplicating code,  
+As a maintainer of Mbed TLS,
+I want to avoid duplicating code,
 because this is inefficient and error-prone.
 
 ### Use PSA more
@@ -55,8 +63,8 @@
 
 The goal of this work is to arrange for more non-PSA interfaces to use PSA interfaces under the hood, without breaking code in the cases where this doesn't work. Using PSA interfaces has two benefits:
 
-* Where a PSA driver is available, it likely has better performance, and sometimes better security, than the built-in software implementation.
-* In many scenarios, where a PSA driver is available, this allows removing the software implementation altogether.
+* Where a PSA driver/provider is available, it likely has better performance, and sometimes better security, than the built-in software implementation.
+* In many scenarios, where a PSA driver/provider is available, this allows removing the software implementation altogether.
 * We may be able to get rid of some redundancies, for example the duplication between the implementations of HMAC in `md.c` and in `psa_crypto_mac.c`, and HKDF in `hkdf.c` and `psa_crypto.c`.
 
 ### Correct dependencies
@@ -72,7 +80,6 @@
 The following configuration options are described as experimental, and are likely to change at least marginally:
 
 * `MBEDTLS_PSA_CRYPTO_CLIENT`: “This interface is experimental and may change or be removed without notice.” In practice we don't want to remove this, but we may constrain how it's used.
-* `MBEDTLS_PSA_CRYPTO_DRIVERS`: “This interface is experimental. We intend to maintain backward compatibility with application code that relies on drivers, but the driver interfaces may change without notice.” In practice, this may mean constraints not only on how to write drivers, but also on how to integrate drivers into code that is platform code more than application code.
 * `MBEDTLS_PSA_CRYPTO_CONFIG`: “This feature is still experimental and is not ready for production since it is not completed.” We may want to change this, for example, to automatically enable more mechanisms (although this wouldn't be considered a backward compatibility break anyway, since we don't promise that you will not get a feature if you don't enable its `PSA_WANT_xxx`).
 
 ### Non-goals
@@ -190,7 +197,7 @@
 
 Here are some reasons why calling `psa_xxx()` to perform a hash or cipher calculation might not be desirable in some circumstances, explaining why the application would arrange to call the legacy software implementation instead.
 
-* `MBEDTLS_PSA_CRYPTO_C` is disabled.
+* `MBEDTLS_PSA_CRYPTO_CLIENT` is disabled.
 * There is a PSA driver which has not been initialized (this happens in `psa_crypto_init()`).
 * For ciphers, the keystore is not initialized yet, and Mbed TLS uses a custom implementation of PSA ITS where the file system is not accessible yet (because something else needs to happen first, and the application takes care that it happens before it calls `psa_crypto_init()`). A possible workaround may be to dispatch to the internal functions that are called after the keystore lookup, rather than to the PSA API functions (but this is incompatible with `MBEDTLS_PSA_CRYPTO_CLIENT`).
 * The requested mechanism is enabled in the legacy interface but not in the PSA interface. This was not really intended, but is possible, for example, if you enable `MBEDTLS_MD5_C` for PEM decoding with PBKDF1 but don't want `PSA_ALG_WANT_MD5` because it isn't supported for `PSA_ALG_RSA_PSS` and `PSA_ALG_DETERMINISTIC_ECDSA`.
@@ -208,7 +215,7 @@
 
 #### Non-support guarantees: requirements
 
-Generally speaking, just because some feature is not enabled in `mbedtls_config.h` or `psa_config.h` doesn't guarantee that it won't be enabled in the build. We can enable additional features through `build_info.h`.
+Generally speaking, just because some feature is not enabled in `mbedtls_config.h` or `crypto_config.h` doesn't guarantee that it won't be enabled in the build. We can enable additional features through `build_info.h` and other header files included there (`*adjust*.h`).
 
 If `PSA_WANT_xxx` is disabled, this should guarantee that attempting xxx through the PSA API will fail. This is generally guaranteed by the test suite `test_suite_psa_crypto_not_supported` with automatically enumerated test cases, so it would be inconvenient to carve out an exception.
 
@@ -331,14 +338,10 @@
 
 This will go away naturally in 4.0 when this macros is not longer an option (because it's always on).
 
-#### Don't support for `MBEDTLS_PSA_CRYPTO_CLIENT` without `MBEDTLS_PSA_CRYPTO_C`
+#### Support for `MBEDTLS_PSA_CRYPTO_CLIENT` without `MBEDTLS_PSA_CRYPTO_C`
 
 We generally don't really support builds with `MBEDTLS_PSA_CRYPTO_CLIENT` without `MBEDTLS_PSA_CRYPTO_C`. For example, both `MBEDTLS_USE_PSA_CRYPTO` and `MBEDTLS_SSL_PROTO_TLS1_3` require `MBEDTLS_PSA_CRYPTO_C`, while in principle they should only require `MBEDTLS_PSA_CRYPTO_CLIENT`.
 
-Considering this existing restriction which we do not plan to lift before 4.0, it is acceptable driver-only hashes and cipher support to have the same restriction in 3.x.
-
-It is however desirable for the design to keep support for `MBEDTLS_PSA_CRYPTO_CLIENT` in mind, in order to avoid making it more difficult to add in the future.
-
 #### For cipher: prioritize constrained devices and modern TLS
 
 The primary target is a configuration like TF-M's medium profile, plus TLS with only AEAD ciphersuites.
@@ -420,8 +423,9 @@
 
 For each hash algorithm, `md.h` defines a macro `MBEDTLS_MD_CAN_xxx` whenever the corresponding hash is available through MD light. These macros are only defined when `MBEDTLS_MD_LIGHT` is enabled. Per “[Availability of hashes](#availability-of-hashes)”, `MBEDTLS_MD_CAN_xxx` is enabled if:
 
-* the corresponding `MBEDTLS_xxx_C` is defined; or
-* one of `MBEDTLS_PSA_CRYPTO_C` or `MBEDTLS_PSA_CRYPTO_CLIENT` is enabled, and the corresponding `PSA_WANT_ALG_xxx` is enabled.
+* the corresponding `MBEDTLS_xxx_C` is defined.
+* `MBEDTLS_PSA_CRYPTO_C` is enabled and the corresponding `PSA_WANT_ALG_xxx` and `MBEDTLS_PSA_ACCEL_ALG_xxx` are enabled. This enables driver acceleration support.
+* `MBEDTLS_PSA_CRYPTO_CLIENT` is enabled the corresponding `PSA_WANT_ALG_xxx` is enabled. Then the Mbed TLS library must be linked against the PSA Crypto provider one which will eventually handle all PSA calls.
 
 Note that some algorithms have different spellings in legacy and PSA. Since MD is a legacy interface, we'll use the legacy names. Thus, for example:
 
@@ -440,7 +444,7 @@
 
 #### MD light internal support macros
 
-* If at least one hash has a PSA driver, define `MBEDTLS_MD_SOME_PSA`.
+* If at least one hash has a PSA driver or support in PSA Crypto provider, define `MBEDTLS_MD_SOME_PSA`.
 * If at least one hash has a legacy implementation, defined `MBEDTLS_MD_SOME_LEGACY`.
 
 #### Support for PSA in the MD context
@@ -488,15 +492,24 @@
 
 #### Determination of PSA support at runtime
 
+Mbed TLS defines internal symbols `MBEDTLS_MD_xxx_VIA_PSA` which are used to check if the `xxx` hash algorithm is supported in PSA. They are enabled when:
+
+* `MBEDTLS_PSA_CRYPTO_C && MBEDTLS_PSA_ACCEL_ALG_xxx`, i.e. when the PSA Crypto core is built with Mbed TLS and the `xxx` is accelerated through a driver.
+* `MBEDTLS_PSA_CRYPTO_CLIENT && PSA_WANT_ALG_xxx`, i.e. there is a PSA Crypto provider/server which supports `xxx` hash algorithm.
+
+MD internally uses the following private function to determine if PSA can be used at runtime or not:
+
 ```
-int psa_can_do_hash(psa_algorithm_t hash_alg);
+static int md_can_use_psa(const mbedtls_md_info_t *info)
 ```
 
-The job of this private function is to return 1 if `hash_alg` can be performed through PSA now, and 0 otherwise. It is only defined on algorithms that are enabled via PSA.
+Internally this function does the following:
 
-As a starting point, return 1 if PSA crypto's driver subsystem has been initialized.
+* First of all it converts the `mbedtls_md_info_t` to `psa_algorithm_t`. The result of this conversion is based on the `MBEDTLS_MD_xxx_VIA_PSA` symbols: if an algorithm does not have the corresponding `MBEDTLS_MD_xxx_VIA_PSA` enabled, then `md_can_use_psa` will return false.
 
-Usage note: for algorithms that are not enabled via PSA, calling `psa_can_do_hash` is generally safe: whether it returns 0 or 1, you can call a PSA hash function on the algorithm and it will return `PSA_ERROR_NOT_SUPPORTED`.
+* `int psa_can_do_hash(psa_algorithm_t hash_alg)` is then used to further checking if the PSA Crypto core has been initialized or not. If so then `md_can_use_psa` will finally succeed, otherwise it will fail.
+
+To be noted that in client/server builds (i.e. `MBEDTLS_PSA_CRYPTO_CLIENT && !MBEDTLS_PSA_CRYPTO_C`) the implementer of the client interface is expected to provide psa_can_do_hash().
 
 #### Support for PSA dispatch in hash operations
 
@@ -506,7 +519,7 @@
 
 If given an algorithm as an `mbedtls_md_type_t type` (possibly being the `type` field of a `const mbedtls_md_info_t *`):
 
-* If there is a PSA accelerator for this hash and `psa_can_do_hash(alg)`, call the corresponding PSA function, and if applicable set the engine to `MBEDTLS_MD_ENGINE_PSA`. (Skip this is `MBEDTLS_MD_SOME_PSA` is not defined.)
+* If there is a PSA accelerator/provider for this hash and `md_can_use_psa` succeeds, call the corresponding PSA function, and if applicable set the engine to `MBEDTLS_MD_ENGINE_PSA`. (Skip this is `MBEDTLS_MD_SOME_PSA` is not defined.)
 * Otherwise dispatch to the legacy module based on the type as currently done. (Skip this is `MBEDTLS_MD_SOME_LEGACY` is not defined.)
 * If no dispatch is possible, return `MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE`.
 
@@ -522,7 +535,7 @@
 
 > If an algorithm has a legacy implementation, it is also available through PSA.
 
-When `MBEDTLS_PSA_CRYPTO_CONFIG` is disabled, this is already the case. When is enabled, we will now make it so as well. Change `include/mbedtls/config_psa.h` accordingly.
+When `MBEDTLS_PSA_CRYPTO_CONFIG` is disabled, this is already the case. When is enabled, `include/config_adjust_psa_superset_legacy.h` will ensure that PSA configuration is always a superset of what's enabled in legacy.
 
 ### MD light optimizations
 
@@ -557,15 +570,6 @@
 
 PSA has its own HMAC implementation. In builds with both `MBEDTLS_MD_C` and `PSA_WANT_ALG_HMAC` not fully provided by drivers, we should have a single implementation. Replace the one in `md.h` by calls to the PSA driver interface. This will also give mixed-domain modules access to HMAC accelerated directly by a PSA driver (eliminating the need to a HMAC interface in software if all supported hashes have an accelerator that includes HMAC support).
 
-### Improving support for `MBEDTLS_PSA_CRYPTO_CLIENT`
-
-So far, MD light only dispatches to PSA if an algorithm is available via `MBEDTLS_PSA_CRYPTO_C`, not if it's available via `MBEDTLS_PSA_CRYPTO_CLIENT`. This is acceptable because `MBEDTLS_USE_PSA_CRYPTO` requires `MBEDTLS_PSA_CRYPTO_C`, hence mixed-domain code never invokes PSA.
-
-The architecture can be extended to support `MBEDTLS_PSA_CRYPTO_CLIENT` with a little extra work. Here is an overview of the task breakdown, which should be fleshed up after we've done the first [migration](#migration-to-md-light):
-
-* Compile-time dependencies: instead of checking `defined(MBEDTLS_PSA_CRYPTO_C)`, check `defined(MBEDTLS_PSA_CRYPTO_C) || defined(MBEDTLS_PSA_CRYPTO_CLIENT)`.
-* Implementers of `MBEDTLS_PSA_CRYPTO_CLIENT` will need to provide `psa_can_do_hash()` (or a more general function `psa_can_do`) alongside `psa_crypto_init()`. Note that at this point, it will become a public interface, hence we won't be able to change it at a whim.
-
 ### Internal "block cipher" abstraction (previously known as "Cipher light")
 
 #### Definition
diff --git a/docs/architecture/testing/invasive-testing.md b/docs/architecture/testing/invasive-testing.md
index 464f761..bf8d631 100644
--- a/docs/architecture/testing/invasive-testing.md
+++ b/docs/architecture/testing/invasive-testing.md
@@ -275,7 +275,7 @@
 
 Goal: test that `mbedtls_platform_zeroize` does wipe the memory buffer.
 
-Solution ([debugger](#debugger-based-testing)): implemented in `tests/scripts/test_zeroize.gdb`.
+Solution ([debugger](#debugger-based-testing)): implemented in `framework/tests/programs/test_zeroize.gdb`.
 
 Rationale: this cannot be tested by adding C code, because the danger is that the compiler optimizes the zeroization away, and any C code that observes the zeroization would cause the compiler not to optimize it away.
 
diff --git a/framework b/framework
index 2000db4..cab0c5f 160000
--- a/framework
+++ b/framework
@@ -1 +1 @@
-Subproject commit 2000db429553aa38e5875c621daf32aa8b63c340
+Subproject commit cab0c5fe19d5747cb9603552b80ebe64b9c67fdd
diff --git a/include/mbedtls/config_adjust_legacy_crypto.h b/include/mbedtls/config_adjust_legacy_crypto.h
index 3ba987e..331ac9b 100644
--- a/include/mbedtls/config_adjust_legacy_crypto.h
+++ b/include/mbedtls/config_adjust_legacy_crypto.h
@@ -48,6 +48,13 @@
 #endif
 #endif /* _MINGW32__ || (_MSC_VER && (_MSC_VER <= 1900)) */
 
+/* If MBEDTLS_PSA_CRYPTO_C is defined, make sure MBEDTLS_PSA_CRYPTO_CLIENT
+ * is defined as well to include all PSA code.
+ */
+#if defined(MBEDTLS_PSA_CRYPTO_C)
+#define MBEDTLS_PSA_CRYPTO_CLIENT
+#endif /* MBEDTLS_PSA_CRYPTO_C */
+
 /* Auto-enable CIPHER_C when any of the unauthenticated ciphers is builtin
  * in PSA. */
 #if defined(MBEDTLS_PSA_CRYPTO_C) && \
@@ -158,7 +165,66 @@
 #define MBEDTLS_MD_SHA3_512_VIA_PSA
 #define MBEDTLS_MD_SOME_PSA
 #endif
-#endif /* MBEDTLS_PSA_CRYPTO_C */
+
+#elif defined(MBEDTLS_PSA_CRYPTO_CLIENT)
+
+#if defined(PSA_WANT_ALG_MD5)
+#define MBEDTLS_MD_CAN_MD5
+#define MBEDTLS_MD_MD5_VIA_PSA
+#define MBEDTLS_MD_SOME_PSA
+#endif
+#if defined(PSA_WANT_ALG_SHA_1)
+#define MBEDTLS_MD_CAN_SHA1
+#define MBEDTLS_MD_SHA1_VIA_PSA
+#define MBEDTLS_MD_SOME_PSA
+#endif
+#if defined(PSA_WANT_ALG_SHA_224)
+#define MBEDTLS_MD_CAN_SHA224
+#define MBEDTLS_MD_SHA224_VIA_PSA
+#define MBEDTLS_MD_SOME_PSA
+#endif
+#if defined(PSA_WANT_ALG_SHA_256)
+#define MBEDTLS_MD_CAN_SHA256
+#define MBEDTLS_MD_SHA256_VIA_PSA
+#define MBEDTLS_MD_SOME_PSA
+#endif
+#if defined(PSA_WANT_ALG_SHA_384)
+#define MBEDTLS_MD_CAN_SHA384
+#define MBEDTLS_MD_SHA384_VIA_PSA
+#define MBEDTLS_MD_SOME_PSA
+#endif
+#if defined(PSA_WANT_ALG_SHA_512)
+#define MBEDTLS_MD_CAN_SHA512
+#define MBEDTLS_MD_SHA512_VIA_PSA
+#define MBEDTLS_MD_SOME_PSA
+#endif
+#if defined(PSA_WANT_ALG_RIPEMD160)
+#define MBEDTLS_MD_CAN_RIPEMD160
+#define MBEDTLS_MD_RIPEMD160_VIA_PSA
+#define MBEDTLS_MD_SOME_PSA
+#endif
+#if defined(PSA_WANT_ALG_SHA3_224)
+#define MBEDTLS_MD_CAN_SHA3_224
+#define MBEDTLS_MD_SHA3_224_VIA_PSA
+#define MBEDTLS_MD_SOME_PSA
+#endif
+#if defined(PSA_WANT_ALG_SHA3_256)
+#define MBEDTLS_MD_CAN_SHA3_256
+#define MBEDTLS_MD_SHA3_256_VIA_PSA
+#define MBEDTLS_MD_SOME_PSA
+#endif
+#if defined(PSA_WANT_ALG_SHA3_384)
+#define MBEDTLS_MD_CAN_SHA3_384
+#define MBEDTLS_MD_SHA3_384_VIA_PSA
+#define MBEDTLS_MD_SOME_PSA
+#endif
+#if defined(PSA_WANT_ALG_SHA3_512)
+#define MBEDTLS_MD_CAN_SHA3_512
+#define MBEDTLS_MD_SHA3_512_VIA_PSA
+#define MBEDTLS_MD_SOME_PSA
+#endif
+
+#endif /* !MBEDTLS_PSA_CRYPTO_CLIENT && !MBEDTLS_PSA_CRYPTO_C */
 
 /* Built-in implementations */
 #if defined(MBEDTLS_MD5_C)
@@ -352,13 +418,6 @@
 #define MBEDTLS_PK_CAN_ECDSA_SOME
 #endif
 
-/* If MBEDTLS_PSA_CRYPTO_C is defined, make sure MBEDTLS_PSA_CRYPTO_CLIENT
- * is defined as well to include all PSA code.
- */
-#if defined(MBEDTLS_PSA_CRYPTO_C)
-#define MBEDTLS_PSA_CRYPTO_CLIENT
-#endif /* MBEDTLS_PSA_CRYPTO_C */
-
 /* Helpers to state that each key is supported either on the builtin or PSA side. */
 #if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) || defined(PSA_WANT_ECC_SECP_R1_521)
 #define MBEDTLS_ECP_HAVE_SECP521R1
diff --git a/include/mbedtls/debug.h b/include/mbedtls/debug.h
index 424ed4b..e6f5dad 100644
--- a/include/mbedtls/debug.h
+++ b/include/mbedtls/debug.h
@@ -108,16 +108,16 @@
  *
  * This module provides debugging functions.
  */
-#if (defined(__MINGW32__) && __USE_MINGW_ANSI_STDIO == 0) || (defined(_MSC_VER) && _MSC_VER < 1800)
+#if defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER < 1900)
    #include <inttypes.h>
    #define MBEDTLS_PRINTF_SIZET     PRIuPTR
    #define MBEDTLS_PRINTF_LONGLONG  "I64d"
 #else \
-    /* (defined(__MINGW32__)  && __USE_MINGW_ANSI_STDIO == 0) || (defined(_MSC_VER) && _MSC_VER < 1800) */
+    /* defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER < 1900) */
    #define MBEDTLS_PRINTF_SIZET     "zu"
    #define MBEDTLS_PRINTF_LONGLONG  "lld"
 #endif \
-    /* (defined(__MINGW32__)  && __USE_MINGW_ANSI_STDIO == 0) || (defined(_MSC_VER) && _MSC_VER < 1800) */
+    /* defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER < 1900) */
 
 #if !defined(MBEDTLS_PRINTF_MS_TIME)
 #include <inttypes.h>
diff --git a/include/mbedtls/net_sockets.h b/include/mbedtls/net_sockets.h
index 85c1197..8e69bc0 100644
--- a/include/mbedtls/net_sockets.h
+++ b/include/mbedtls/net_sockets.h
@@ -229,7 +229,7 @@
 
 /**
  * \brief          Write at most 'len' characters. If no error occurs,
- *                 the actual amount read is returned.
+ *                 the actual amount written is returned.
  *
  * \param ctx      Socket
  * \param buf      The buffer to read from
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 42fffbf..97b0dcb 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -1724,7 +1724,16 @@
     int MBEDTLS_PRIVATE(early_data_state);
 #endif
 
-    unsigned MBEDTLS_PRIVATE(badmac_seen);       /*!< records with a bad MAC received    */
+    /** Multipurpose field.
+     *
+     * - DTLS: records with a bad MAC received.
+     * - TLS: accumulated length of handshake fragments (up to \c in_hslen).
+     *
+     * This field is multipurpose in order to preserve the ABI in the
+     * Mbed TLS 3.6 LTS branch. Until 3.6.2, it was only used in DTLS
+     * and called `badmac_seen`.
+     */
+    unsigned MBEDTLS_PRIVATE(badmac_seen_or_in_hsfraglen);
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
     /** Callback to customize X.509 certificate chain verification          */
@@ -4440,6 +4449,10 @@
  *                 with \c mbedtls_ssl_read()), not handshake messages.
  *                 With DTLS, this affects both ApplicationData and handshake.
  *
+ * \note           Defragmentation of TLS handshake messages is supported
+ *                 with some limitations. See the documentation of
+ *                 mbedtls_ssl_handshake() for details.
+ *
  * \note           This sets the maximum length for a record's payload,
  *                 excluding record overhead that will be added to it, see
  *                 \c mbedtls_ssl_get_record_expansion().
@@ -4970,6 +4983,24 @@
  *                 if a negotiation involving TLS 1.3 takes place (this may
  *                 be the case even if TLS 1.3 is offered but eventually
  *                 not selected).
+ *
+ * \note           In TLS, reception of fragmented handshake messages is
+ *                 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
+ *                   the fragments of a handshake message. (This is permitted
+ *                   in TLS 1.2 but not in TLS 1.3, but Mbed TLS rejects it
+ *                   even in TLS 1.2.)
  */
 int mbedtls_ssl_handshake(mbedtls_ssl_context *ssl);
 
diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h
index f48c087..a046ba5 100644
--- a/include/psa/crypto_extra.h
+++ b/include/psa/crypto_extra.h
@@ -583,6 +583,35 @@
 
 /** @} */
 
+/** \defgroup psa_crypto_client Functions defined by a client provider
+ *
+ * The functions in this group are meant to be implemented by providers of
+ * the PSA Crypto client interface. They are provided by the library when
+ * #MBEDTLS_PSA_CRYPTO_C is enabled.
+ *
+ * \note All functions in this group are experimental, as using
+ *       alternative client interface providers is experimental.
+ *
+ * @{
+ */
+
+/** Check if PSA is capable of handling the specified hash algorithm.
+ *
+ * This means that PSA core was built with the corresponding PSA_WANT_ALG_xxx
+ * set and that psa_crypto_init has already been called.
+ *
+ * \note When using Mbed TLS version of PSA core (i.e. MBEDTLS_PSA_CRYPTO_C is
+ *       set) for now this function only checks the state of the driver
+ *       subsystem, not the algorithm. This might be improved in the future.
+ *
+ * \param hash_alg  The hash algorithm.
+ *
+ * \return 1 if the PSA can handle \p hash_alg, 0 otherwise.
+ */
+int psa_can_do_hash(psa_algorithm_t hash_alg);
+
+/**@}*/
+
 /** \addtogroup crypto_types
  * @{
  */
diff --git a/library/psa_crypto_core.h b/library/psa_crypto_core.h
index df0ee50..c3c0770 100644
--- a/library/psa_crypto_core.h
+++ b/library/psa_crypto_core.h
@@ -25,18 +25,6 @@
 #endif
 
 /**
- * Tell if PSA is ready for this hash.
- *
- * \note            For now, only checks the state of the driver subsystem,
- *                  not the algorithm. Might do more in the future.
- *
- * \param hash_alg  The hash algorithm (ignored for now).
- *
- * \return 1 if the driver subsytem is ready, 0 otherwise.
- */
-int psa_can_do_hash(psa_algorithm_t hash_alg);
-
-/**
  * Tell if PSA is ready for this cipher.
  *
  * \note            For now, only checks the state of the driver subsystem,
diff --git a/library/psa_crypto_slot_management.c b/library/psa_crypto_slot_management.c
index 9850d8c..358c7a2 100644
--- a/library/psa_crypto_slot_management.c
+++ b/library/psa_crypto_slot_management.c
@@ -35,9 +35,9 @@
                       "Empty user key ID range");
 MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_VENDOR_MIN < PSA_KEY_ID_VENDOR_MAX,
                       "Empty vendor key ID range");
-MBEDTLS_STATIC_ASSERT(MBEDTLS_PSA_KEY_ID_BUILTIN_MIN < MBEDTLS_PSA_KEY_ID_BUILTIN_MAX,
+MBEDTLS_STATIC_ASSERT(MBEDTLS_PSA_KEY_ID_BUILTIN_MIN <= MBEDTLS_PSA_KEY_ID_BUILTIN_MAX,
                       "Empty builtin key ID range");
-MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_VOLATILE_MIN < PSA_KEY_ID_VOLATILE_MAX,
+MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_VOLATILE_MIN <= PSA_KEY_ID_VOLATILE_MAX,
                       "Empty volatile key ID range");
 
 MBEDTLS_STATIC_ASSERT(PSA_KEY_ID_USER_MAX < PSA_KEY_ID_VENDOR_MIN ||
diff --git a/library/ssl_misc.h b/library/ssl_misc.h
index 7495ae3..348c319 100644
--- a/library/ssl_misc.h
+++ b/library/ssl_misc.h
@@ -1830,10 +1830,11 @@
 MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_check_timer(mbedtls_ssl_context *ssl);
 
-void mbedtls_ssl_reset_in_out_pointers(mbedtls_ssl_context *ssl);
+void mbedtls_ssl_reset_in_pointers(mbedtls_ssl_context *ssl);
+void mbedtls_ssl_update_in_pointers(mbedtls_ssl_context *ssl);
+void mbedtls_ssl_reset_out_pointers(mbedtls_ssl_context *ssl);
 void mbedtls_ssl_update_out_pointers(mbedtls_ssl_context *ssl,
                                      mbedtls_ssl_transform *transform);
-void mbedtls_ssl_update_in_pointers(mbedtls_ssl_context *ssl);
 
 MBEDTLS_CHECK_RETURN_CRITICAL
 int mbedtls_ssl_session_reset_int(mbedtls_ssl_context *ssl, int partial);
diff --git a/library/ssl_msg.c b/library/ssl_msg.c
index dcda1d3..4adaf7d 100644
--- a/library/ssl_msg.c
+++ b/library/ssl_msg.c
@@ -25,6 +25,7 @@
 #include "constant_time_internal.h"
 #include "mbedtls/constant_time.h"
 
+#include <limits.h>
 #include <string.h>
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
@@ -3220,19 +3221,34 @@
 
 int mbedtls_ssl_prepare_handshake_record(mbedtls_ssl_context *ssl)
 {
-    if (ssl->in_msglen < mbedtls_ssl_hs_hdr_len(ssl)) {
-        MBEDTLS_SSL_DEBUG_MSG(1, ("handshake message too short: %" MBEDTLS_PRINTF_SIZET,
-                                  ssl->in_msglen));
-        return MBEDTLS_ERR_SSL_INVALID_RECORD;
-    }
+    if (ssl->badmac_seen_or_in_hsfraglen == 0) {
+        /* The handshake message must at least include the header.
+         * We may not have the full message yet in case of fragmentation.
+         * To simplify the code, we insist on having the header (and in
+         * particular the handshake message length) in the first
+         * fragment. */
+        if (ssl->in_msglen < mbedtls_ssl_hs_hdr_len(ssl)) {
+            MBEDTLS_SSL_DEBUG_MSG(1, ("handshake message too short: %" MBEDTLS_PRINTF_SIZET,
+                                      ssl->in_msglen));
+            return MBEDTLS_ERR_SSL_INVALID_RECORD;
+        }
 
-    ssl->in_hslen = mbedtls_ssl_hs_hdr_len(ssl) + ssl_get_hs_total_len(ssl);
+        ssl->in_hslen = mbedtls_ssl_hs_hdr_len(ssl) + ssl_get_hs_total_len(ssl);
+    }
 
     MBEDTLS_SSL_DEBUG_MSG(3, ("handshake message: msglen ="
                               " %" MBEDTLS_PRINTF_SIZET ", type = %u, hslen = %"
                               MBEDTLS_PRINTF_SIZET,
                               ssl->in_msglen, ssl->in_msg[0], ssl->in_hslen));
 
+    if (ssl->transform_in != NULL) {
+        MBEDTLS_SSL_DEBUG_MSG(4, ("decrypted handshake message:"
+                                  " iv-buf=%d hdr-buf=%d hdr-buf=%d",
+                                  (int) (ssl->in_iv - ssl->in_buf),
+                                  (int) (ssl->in_hdr - ssl->in_buf),
+                                  (int) (ssl->in_msg - ssl->in_buf)));
+    }
+
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
     if (ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
         int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -3292,10 +3308,103 @@
         }
     } else
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
-    /* With TLS we don't handle fragmentation (for now) */
-    if (ssl->in_msglen < ssl->in_hslen) {
-        MBEDTLS_SSL_DEBUG_MSG(1, ("TLS handshake fragmentation not supported"));
-        return MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
+    {
+        unsigned char *const reassembled_record_start =
+            ssl->in_buf + MBEDTLS_SSL_SEQUENCE_NUMBER_LEN;
+        unsigned char *const payload_start =
+            reassembled_record_start + mbedtls_ssl_in_hdr_len(ssl);
+        unsigned char *payload_end = payload_start + ssl->badmac_seen_or_in_hsfraglen;
+        /* How many more bytes we want to have a complete handshake message. */
+        const size_t hs_remain = ssl->in_hslen - ssl->badmac_seen_or_in_hsfraglen;
+        /* How many bytes of the current record are part of the first
+         * handshake message. There may be more handshake messages (possibly
+         * incomplete) in the same record; if so, we leave them after the
+         * current record, and ssl_consume_current_message() will take
+         * care of consuming the next handshake message. */
+        const size_t hs_this_fragment_len =
+            ssl->in_msglen > hs_remain ? hs_remain : ssl->in_msglen;
+        (void) hs_this_fragment_len;
+
+        MBEDTLS_SSL_DEBUG_MSG(3,
+                              ("%s handshake fragment: %" MBEDTLS_PRINTF_SIZET
+                               ", %u..%u of %" MBEDTLS_PRINTF_SIZET,
+                               (ssl->badmac_seen_or_in_hsfraglen != 0 ?
+                                "subsequent" :
+                                hs_this_fragment_len == ssl->in_hslen ?
+                                "sole" :
+                                "initial"),
+                               ssl->in_msglen,
+                               ssl->badmac_seen_or_in_hsfraglen,
+                               ssl->badmac_seen_or_in_hsfraglen +
+                               (unsigned) hs_this_fragment_len,
+                               ssl->in_hslen));
+
+        /* Move the received handshake fragment to have the whole message
+         * (at least the part received so far) in a single segment at a
+         * known offset in the input buffer.
+         * - When receiving a non-initial handshake fragment, append it to
+         *   the initial segment.
+         * - Even the initial handshake fragment is moved, if it was
+         *   encrypted with an explicit IV: decryption leaves the payload
+         *   after the explicit IV, but here we move it to start where the
+         *   IV was.
+         */
+#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
+        size_t const in_buf_len = ssl->in_buf_len;
+#else
+        size_t const in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN;
+#endif
+        if (payload_end + ssl->in_msglen > ssl->in_buf + in_buf_len) {
+            MBEDTLS_SSL_DEBUG_MSG(1,
+                                  ("Shouldn't happen: no room to move handshake fragment %"
+                                   MBEDTLS_PRINTF_SIZET " from %p to %p (buf=%p len=%"
+                                   MBEDTLS_PRINTF_SIZET ")",
+                                   ssl->in_msglen,
+                                   (void *) ssl->in_msg, (void *) payload_end,
+                                   (void *) ssl->in_buf, in_buf_len));
+            return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+        }
+        memmove(payload_end, ssl->in_msg, ssl->in_msglen);
+
+        ssl->badmac_seen_or_in_hsfraglen += (unsigned) ssl->in_msglen;
+        payload_end += ssl->in_msglen;
+
+        if (ssl->badmac_seen_or_in_hsfraglen < ssl->in_hslen) {
+            MBEDTLS_SSL_DEBUG_MSG(3, ("Prepare: waiting for more handshake fragments "
+                                      "%u/%" MBEDTLS_PRINTF_SIZET,
+                                      ssl->badmac_seen_or_in_hsfraglen, ssl->in_hslen));
+            ssl->in_hdr = payload_end;
+            ssl->in_msglen = 0;
+            mbedtls_ssl_update_in_pointers(ssl);
+            return MBEDTLS_ERR_SSL_CONTINUE_PROCESSING;
+        } else {
+            ssl->in_msglen = ssl->badmac_seen_or_in_hsfraglen;
+            ssl->badmac_seen_or_in_hsfraglen = 0;
+            ssl->in_hdr = reassembled_record_start;
+            mbedtls_ssl_update_in_pointers(ssl);
+
+            /* Update the record length in the fully reassembled record */
+            if (ssl->in_msglen > 0xffff) {
+                MBEDTLS_SSL_DEBUG_MSG(1,
+                                      ("Shouldn't happen: in_msglen=%"
+                                       MBEDTLS_PRINTF_SIZET " > 0xffff",
+                                       ssl->in_msglen));
+                return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+            }
+            MBEDTLS_PUT_UINT16_BE(ssl->in_msglen, ssl->in_len, 0);
+
+            size_t record_len = mbedtls_ssl_in_hdr_len(ssl) + ssl->in_msglen;
+            (void) record_len;
+            MBEDTLS_SSL_DEBUG_BUF(4, "reassembled record",
+                                  ssl->in_hdr, record_len);
+            if (ssl->in_hslen < ssl->in_msglen) {
+                MBEDTLS_SSL_DEBUG_MSG(3,
+                                      ("More handshake messages in the record: "
+                                       "%" MBEDTLS_PRINTF_SIZET " + %" MBEDTLS_PRINTF_SIZET,
+                                       ssl->in_hslen,
+                                       ssl->in_msglen - ssl->in_hslen));
+            }
+        }
     }
 
     return 0;
@@ -4640,6 +4749,14 @@
             return MBEDTLS_ERR_SSL_INTERNAL_ERROR;
         }
 
+        if (ssl->badmac_seen_or_in_hsfraglen != 0) {
+            /* Not all handshake fragments have arrived, do not consume. */
+            MBEDTLS_SSL_DEBUG_MSG(3, ("Consume: waiting for more handshake fragments "
+                                      "%u/%" MBEDTLS_PRINTF_SIZET,
+                                      ssl->badmac_seen_or_in_hsfraglen, ssl->in_hslen));
+            return 0;
+        }
+
         /*
          * Get next Handshake message in the current record
          */
@@ -4665,6 +4782,7 @@
             ssl->in_msglen -= ssl->in_hslen;
             memmove(ssl->in_msg, ssl->in_msg + ssl->in_hslen,
                     ssl->in_msglen);
+            MBEDTLS_PUT_UINT16_BE(ssl->in_msglen, ssl->in_len, 0);
 
             MBEDTLS_SSL_DEBUG_BUF(4, "remaining content in record",
                                   ssl->in_msg, ssl->in_msglen);
@@ -4967,10 +5085,12 @@
                     return ret;
                 }
 
-                if (ssl->conf->badmac_limit != 0 &&
-                    ++ssl->badmac_seen >= ssl->conf->badmac_limit) {
-                    MBEDTLS_SSL_DEBUG_MSG(1, ("too many records with bad MAC"));
-                    return MBEDTLS_ERR_SSL_INVALID_MAC;
+                if (ssl->conf->badmac_limit != 0) {
+                    ++ssl->badmac_seen_or_in_hsfraglen;
+                    if (ssl->badmac_seen_or_in_hsfraglen >= ssl->conf->badmac_limit) {
+                        MBEDTLS_SSL_DEBUG_MSG(1, ("too many records with bad MAC"));
+                        return MBEDTLS_ERR_SSL_INVALID_MAC;
+                    }
                 }
 
                 /* As above, invalid records cause
@@ -5028,6 +5148,18 @@
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
 
+    /* If we're in the middle of a fragmented TLS handshake message,
+     * we don't accept any other message type. For TLS 1.3, the spec forbids
+     * interleaving other message types between handshake fragments. For TLS
+     * 1.2, the spec does not forbid it but we do. */
+    if (ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_STREAM &&
+        ssl->badmac_seen_or_in_hsfraglen != 0 &&
+        ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE) {
+        MBEDTLS_SSL_DEBUG_MSG(1, ("non-handshake message in the middle"
+                                  " of a fragmented handshake message"));
+        return MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE;
+    }
+
     /*
      * Handle particular types of records
      */
@@ -5339,7 +5471,7 @@
     } else
 #endif
     {
-        ssl->in_ctr = ssl->in_hdr - MBEDTLS_SSL_SEQUENCE_NUMBER_LEN;
+        ssl->in_ctr = ssl->in_buf;
         ssl->in_len = ssl->in_hdr + 3;
 #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
         ssl->in_cid = ssl->in_len;
@@ -5355,24 +5487,35 @@
  * Setup an SSL context
  */
 
-void mbedtls_ssl_reset_in_out_pointers(mbedtls_ssl_context *ssl)
+void mbedtls_ssl_reset_in_pointers(mbedtls_ssl_context *ssl)
+{
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+    if (ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
+        ssl->in_hdr = ssl->in_buf;
+    } else
+#endif  /* MBEDTLS_SSL_PROTO_DTLS */
+    {
+        ssl->in_hdr = ssl->in_buf + MBEDTLS_SSL_SEQUENCE_NUMBER_LEN;
+    }
+
+    /* Derive other internal pointers. */
+    mbedtls_ssl_update_in_pointers(ssl);
+}
+
+void mbedtls_ssl_reset_out_pointers(mbedtls_ssl_context *ssl)
 {
     /* Set the incoming and outgoing record pointers. */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
     if (ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
         ssl->out_hdr = ssl->out_buf;
-        ssl->in_hdr  = ssl->in_buf;
     } else
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
     {
         ssl->out_ctr = ssl->out_buf;
-        ssl->out_hdr = ssl->out_buf + 8;
-        ssl->in_hdr  = ssl->in_buf  + 8;
+        ssl->out_hdr = ssl->out_buf + MBEDTLS_SSL_SEQUENCE_NUMBER_LEN;
     }
-
     /* Derive other internal pointers. */
     mbedtls_ssl_update_out_pointers(ssl, NULL /* no transform enabled */);
-    mbedtls_ssl_update_in_pointers(ssl);
 }
 
 /*
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index c773365..7f74248 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -344,12 +344,13 @@
                                    size_t out_buf_new_len)
 {
     int modified = 0;
-    size_t written_in = 0, iv_offset_in = 0, len_offset_in = 0;
+    size_t written_in = 0, iv_offset_in = 0, len_offset_in = 0, hdr_in = 0;
     size_t written_out = 0, iv_offset_out = 0, len_offset_out = 0;
     if (ssl->in_buf != NULL) {
         written_in = ssl->in_msg - ssl->in_buf;
         iv_offset_in = ssl->in_iv - ssl->in_buf;
         len_offset_in = ssl->in_len - ssl->in_buf;
+        hdr_in = ssl->in_hdr - ssl->in_buf;
         if (downsizing ?
             ssl->in_buf_len > in_buf_new_len && ssl->in_left < in_buf_new_len :
             ssl->in_buf_len < in_buf_new_len) {
@@ -381,7 +382,10 @@
     }
     if (modified) {
         /* Update pointers here to avoid doing it twice. */
-        mbedtls_ssl_reset_in_out_pointers(ssl);
+        ssl->in_hdr = ssl->in_buf + hdr_in;
+        mbedtls_ssl_update_in_pointers(ssl);
+        mbedtls_ssl_reset_out_pointers(ssl);
+
         /* Fields below might not be properly updated with record
          * splitting or with CID, so they are manually updated here. */
         ssl->out_msg = ssl->out_buf + written_out;
@@ -1409,7 +1413,8 @@
         goto error;
     }
 
-    mbedtls_ssl_reset_in_out_pointers(ssl);
+    mbedtls_ssl_reset_in_pointers(ssl);
+    mbedtls_ssl_reset_out_pointers(ssl);
 
 #if defined(MBEDTLS_SSL_DTLS_SRTP)
     memset(&ssl->dtls_srtp_info, 0, sizeof(ssl->dtls_srtp_info));
@@ -1474,7 +1479,8 @@
     /* Cancel any possibly running timer */
     mbedtls_ssl_set_timer(ssl, 0);
 
-    mbedtls_ssl_reset_in_out_pointers(ssl);
+    mbedtls_ssl_reset_in_pointers(ssl);
+    mbedtls_ssl_reset_out_pointers(ssl);
 
     /* Reset incoming message parsing */
     ssl->in_offt    = NULL;
@@ -1485,6 +1491,12 @@
     ssl->keep_current_message = 0;
     ssl->transform_in  = NULL;
 
+    /* TLS: reset in_hsfraglen, which is part of message parsing.
+     * DTLS: on a client reconnect, don't reset badmac_seen. */
+    if (!partial) {
+        ssl->badmac_seen_or_in_hsfraglen = 0;
+    }
+
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
     ssl->next_record_offset = 0;
     ssl->in_epoch = 0;
@@ -5014,7 +5026,7 @@
  *  uint8 in_cid<0..2^8-1>      // Connection ID: expected incoming value
  *  uint8 out_cid<0..2^8-1>     // Connection ID: outgoing value to use
  *  // fields from ssl_context
- *  uint32 badmac_seen;         // DTLS: number of records with failing MAC
+ *  uint32 badmac_seen_or_in_hsfraglen;         // DTLS: number of records with failing MAC
  *  uint64 in_window_top;       // DTLS: last validated record seq_num
  *  uint64 in_window;           // DTLS: bitmask for replay protection
  *  uint8 disable_datagram_packing; // DTLS: only one record per datagram
@@ -5156,7 +5168,7 @@
      */
     used += 4;
     if (used <= buf_len) {
-        MBEDTLS_PUT_UINT32_BE(ssl->badmac_seen, p, 0);
+        MBEDTLS_PUT_UINT32_BE(ssl->badmac_seen_or_in_hsfraglen, p, 0);
         p += 4;
     }
 
@@ -5386,7 +5398,7 @@
         return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
     }
 
-    ssl->badmac_seen = MBEDTLS_GET_UINT32_BE(p, 0);
+    ssl->badmac_seen_or_in_hsfraglen = MBEDTLS_GET_UINT32_BE(p, 0);
     p += 4;
 
 #if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
diff --git a/library/ssl_tls12_server.c b/library/ssl_tls12_server.c
index 03722ac..67df428 100644
--- a/library/ssl_tls12_server.c
+++ b/library/ssl_tls12_server.c
@@ -1057,28 +1057,6 @@
         MBEDTLS_SSL_DEBUG_MSG(1, ("bad client hello message"));
         return MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE;
     }
-    {
-        size_t handshake_len = MBEDTLS_GET_UINT24_BE(buf, 1);
-        MBEDTLS_SSL_DEBUG_MSG(3, ("client hello v3, handshake len.: %u",
-                                  (unsigned) handshake_len));
-
-        /* The record layer has a record size limit of 2^14 - 1 and
-         * fragmentation is not supported, so buf[1] should be zero. */
-        if (buf[1] != 0) {
-            MBEDTLS_SSL_DEBUG_MSG(1, ("bad client hello message: %u != 0",
-                                      (unsigned) buf[1]));
-            return MBEDTLS_ERR_SSL_DECODE_ERROR;
-        }
-
-        /* We don't support fragmentation of ClientHello (yet?) */
-        if (msg_len != mbedtls_ssl_hs_hdr_len(ssl) + handshake_len) {
-            MBEDTLS_SSL_DEBUG_MSG(1, ("bad client hello message: %u != %u + %u",
-                                      (unsigned) msg_len,
-                                      (unsigned) mbedtls_ssl_hs_hdr_len(ssl),
-                                      (unsigned) handshake_len));
-            return MBEDTLS_ERR_SSL_DECODE_ERROR;
-        }
-    }
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
     if (ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
diff --git a/programs/Makefile b/programs/Makefile
index 0604a68..e765886 100644
--- a/programs/Makefile
+++ b/programs/Makefile
@@ -1,4 +1,5 @@
 MBEDTLS_TEST_PATH = ../tests
+FRAMEWORK = ${MBEDTLS_PATH}/framework
 include ../scripts/common.make
 
 ifeq ($(shell uname -s),Linux)
@@ -24,6 +25,8 @@
 BUILD_DLOPEN =
 endif
 
+LOCAL_CFLAGS += -I$(FRAMEWORK)/tests/programs
+
 ## The following assignment is the list of base names of applications that
 ## will be built on Windows. Extra Linux/Unix/POSIX-only applications can
 ## be declared by appending with `APPS += ...` afterwards.
@@ -298,7 +301,7 @@
 
 SSL_TEST_OBJECTS = test/query_config.o ssl/ssl_test_lib.o
 SSL_TEST_DEPS = $(SSL_TEST_OBJECTS) \
-		test/query_config.h \
+		$(FRAMEWORK)/tests/programs/query_config.h \
 		ssl/ssl_test_lib.h \
 		ssl/ssl_test_common_source.c \
 		$(DEP)
@@ -319,7 +322,7 @@
 	echo "  CC    ssl/ssl_server2.c"
 	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) ssl/ssl_server2.c $(SSL_TEST_OBJECTS) $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
 
-ssl/ssl_context_info$(EXEXT): ssl/ssl_context_info.c test/query_config.o test/query_config.h $(DEP)
+ssl/ssl_context_info$(EXEXT): ssl/ssl_context_info.c test/query_config.o $(FRAMEWORK)/tests/programs/query_config.h $(DEP)
 	echo "  CC    ssl/ssl_context_info.c"
 	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) ssl/ssl_context_info.c test/query_config.o $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
 
@@ -360,17 +363,17 @@
 	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) test/dlopen.c $(LDFLAGS) $(DLOPEN_LDFLAGS) -o $@
 endif
 
-test/metatest$(EXEXT): test/metatest.c $(DEP)
-	echo "  CC    test/metatest.c"
-	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) -I ../library test/metatest.c    $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
+test/metatest$(EXEXT): $(FRAMEWORK)/tests/programs/metatest.c $(DEP)
+	echo "  CC    $(FRAMEWORK)/tests/programs/metatest.c"
+	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) -I ../library $(FRAMEWORK)/tests/programs/metatest.c    $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
 
-test/query_config.o: test/query_config.c test/query_config.h $(DEP)
-	echo "  CC    test/query_config.c"
+test/query_config.o: test/query_config.c $(FRAMEWORK)/tests/programs/query_config.h $(DEP)
+	echo "  CC    $(FRAMEWORK)/tests/programs/query_config.c"
 	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) -c test/query_config.c -o $@
 
-test/query_included_headers$(EXEXT): test/query_included_headers.c $(DEP)
-	echo "  CC    test/query_included_headers.c"
-	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) test/query_included_headers.c    $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
+test/query_included_headers$(EXEXT): $(FRAMEWORK)/tests/programs/query_included_headers.c $(DEP)
+	echo "  CC    $(FRAMEWORK)/tests/programs/query_included_headers.c"
+	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) $(FRAMEWORK)/tests/programs/query_included_headers.c    $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
 
 test/selftest$(EXEXT): test/selftest.c $(DEP)
 	echo "  CC    test/selftest.c"
@@ -380,13 +383,13 @@
 	echo "  CC    test/udp_proxy.c"
 	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) test/udp_proxy.c    $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
 
-test/zeroize$(EXEXT): test/zeroize.c $(DEP)
-	echo "  CC    test/zeroize.c"
-	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) test/zeroize.c    $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
+test/zeroize$(EXEXT): $(FRAMEWORK)/tests/programs/zeroize.c $(DEP)
+	echo "  CC    $(FRAMEWORK)/tests/programs/zeroize.c"
+	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) $(FRAMEWORK)/tests/programs/zeroize.c    $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
 
-test/query_compile_time_config$(EXEXT): test/query_compile_time_config.c test/query_config.o test/query_config.h $(DEP)
-	echo "  CC    test/query_compile_time_config.c"
-	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) test/query_compile_time_config.c test/query_config.o $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
+test/query_compile_time_config$(EXEXT): $(FRAMEWORK)/tests/programs/query_compile_time_config.c test/query_config.o $(FRAMEWORK)/tests/programs/query_config.h $(DEP)
+	echo "  CC    $(FRAMEWORK)/tests/programs/query_compile_time_config.c"
+	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) $(FRAMEWORK)/tests/programs/query_compile_time_config.c test/query_config.o $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
 
 util/pem2der$(EXEXT): util/pem2der.c $(DEP)
 	echo "  CC    util/pem2der.c"
diff --git a/programs/README.md b/programs/README.md
index f53bde5..a58037d 100644
--- a/programs/README.md
+++ b/programs/README.md
@@ -53,7 +53,7 @@
 
 ## Random number generator (RNG) examples
 
-* [`random/gen_entropy.c`](random/gen_entropy.c): shows how to use the default entropy sources to generate random data.  
+* [`random/gen_entropy.c`](random/gen_entropy.c): shows how to use the default entropy sources to generate random data.
   Note: most applications should only use the entropy generator to seed a cryptographic pseudorandom generator, as illustrated by `random/gen_random_ctr_drbg.c`.
 
 * [`random/gen_random_ctr_drbg.c`](random/gen_random_ctr_drbg.c): shows how to use the default entropy sources to seed a pseudorandom generator, and how to use the resulting random generator to generate random data.
@@ -96,7 +96,7 @@
 
 * [`test/udp_proxy.c`](test/udp_proxy.c): a UDP proxy that can inject certain failures (delay, duplicate, drop). Useful for testing DTLS.
 
-* [`test/zeroize.c`](test/zeroize.c): a test program for `mbedtls_platform_zeroize`, used by [`tests/scripts/test_zeroize.gdb`](tests/scripts/test_zeroize.gdb).
+* [`test/zeroize.c`](../framework/tests/programs/zeroize.c): a test program for `mbedtls_platform_zeroize`, used by [`test_zeroize.gdb`](../framework/tests/programs/test_zeroize.gdb).
 
 ## Development utilities
 
diff --git a/programs/demo_common.sh b/programs/demo_common.sh
deleted file mode 100644
index d8fcda5..0000000
--- a/programs/demo_common.sh
+++ /dev/null
@@ -1,137 +0,0 @@
-## Common shell functions used by demo scripts programs/*/*.sh.
-
-## How to write a demo script
-## ==========================
-##
-## Include this file near the top of each demo script:
-##   . "${0%/*}/../demo_common.sh"
-##
-## Start with a "msg" call that explains the purpose of the script.
-## Then call the "depends_on" function to ensure that all config
-## dependencies are met.
-##
-## As the last thing in the script, call the cleanup function.
-##
-## You can use the functions and variables described below.
-
-set -e -u
-
-## $root_dir is the root directory of the Mbed TLS source tree.
-root_dir="${0%/*}"
-# Find a nice path to the root directory, avoiding unnecessary "../".
-# The code supports demo scripts nested up to 4 levels deep.
-# The code works no matter where the demo script is relative to the current
-# directory, even if it is called with a relative path.
-n=4 # limit the search depth
-while ! [ -d "$root_dir/programs" ] || ! [ -d "$root_dir/library" ]; do
-  if [ $n -eq 0 ]; then
-    echo >&2 "This doesn't seem to be an Mbed TLS source tree."
-    exit 125
-  fi
-  n=$((n - 1))
-  case $root_dir in
-    .) root_dir="..";;
-    ..|?*/..) root_dir="$root_dir/..";;
-    ?*/*) root_dir="${root_dir%/*}";;
-    /*) root_dir="/";;
-    *) root_dir=".";;
-  esac
-done
-
-## $programs_dir is the directory containing the sample programs.
-# Assume an in-tree build.
-programs_dir="$root_dir/programs"
-
-## msg LINE...
-## msg <TEXT_ORIGIN
-## Display an informational message.
-msg () {
-  if [ $# -eq 0 ]; then
-    sed 's/^/# /'
-  else
-    for x in "$@"; do
-      echo "# $x"
-    done
-  fi
-}
-
-## run "Message" COMMAND ARGUMENT...
-## Display the message, then run COMMAND with the specified arguments.
-run () {
-    echo
-    echo "# $1"
-    shift
-    echo "+ $*"
-    "$@"
-}
-
-## Like '!', but stop on failure with 'set -e'
-not () {
-  if "$@"; then false; fi
-}
-
-## run_bad "Message" COMMAND ARGUMENT...
-## Like run, but the command is expected to fail.
-run_bad () {
-  echo
-  echo "$1 This must fail."
-  shift
-  echo "+ ! $*"
-  not "$@"
-}
-
-## config_has SYMBOL...
-## Succeeds if the library configuration has all SYMBOLs set.
-config_has () {
-  for x in "$@"; do
-    "$programs_dir/test/query_compile_time_config" "$x"
-  done
-}
-
-## depends_on SYMBOL...
-## Exit if the library configuration does not have all SYMBOLs set.
-depends_on () {
-  m=
-  for x in "$@"; do
-    if ! config_has "$x"; then
-      m="$m $x"
-    fi
-  done
-  if [ -n "$m" ]; then
-    cat >&2 <<EOF
-$0: this demo requires the following
-configuration options to be enabled at compile time:
- $m
-EOF
-    # Exit with a success status so that this counts as a pass for run_demos.py.
-    exit
-  fi
-}
-
-## Add the names of files to clean up to this whitespace-separated variable.
-## The file names must not contain whitespace characters.
-files_to_clean=
-
-## Call this function at the end of each script.
-## It is called automatically if the script is killed by a signal.
-cleanup () {
-  rm -f -- $files_to_clean
-}
-
-
-
-################################################################
-## End of the public interfaces. Code beyond this point is not
-## meant to be called directly from a demo script.
-
-trap 'cleanup; trap - HUP; kill -HUP $$' HUP
-trap 'cleanup; trap - INT; kill -INT $$' INT
-trap 'cleanup; trap - TERM; kill -TERM $$' TERM
-
-if config_has MBEDTLS_ENTROPY_NV_SEED; then
-  # Create a seedfile that's sufficiently long in all library configurations.
-  # This is necessary for programs that use randomness.
-  # Assume that the name of the seedfile is the default name.
-  files_to_clean="$files_to_clean seedfile"
-  dd if=/dev/urandom of=seedfile ibs=64 obs=64 count=1
-fi
diff --git a/programs/psa/key_ladder_demo.sh b/programs/psa/key_ladder_demo.sh
index e55da7e..e3afb66 100755
--- a/programs/psa/key_ladder_demo.sh
+++ b/programs/psa/key_ladder_demo.sh
@@ -3,7 +3,7 @@
 # Copyright The Mbed TLS Contributors
 # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
 
-. "${0%/*}/../demo_common.sh"
+. "${0%/*}/../../framework/scripts/demo_common.sh"
 
 msg <<'EOF'
 This script demonstrates the use of the PSA cryptography interface to
diff --git a/programs/psa/psa_hash_demo.sh b/programs/psa/psa_hash_demo.sh
index a26697c..c2cc87a 100755
--- a/programs/psa/psa_hash_demo.sh
+++ b/programs/psa/psa_hash_demo.sh
@@ -3,7 +3,7 @@
 # Copyright The Mbed TLS Contributors
 # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
 
-. "${0%/*}/../demo_common.sh"
+. "${0%/*}/../../framework/scripts/demo_common.sh"
 
 msg <<'EOF'
 This program demonstrates the use of the PSA cryptography interface to
diff --git a/programs/ssl/CMakeLists.txt b/programs/ssl/CMakeLists.txt
index 1a9e75e..4e954f0 100644
--- a/programs/ssl/CMakeLists.txt
+++ b/programs/ssl/CMakeLists.txt
@@ -35,20 +35,19 @@
     if(exe STREQUAL "ssl_client2" OR exe STREQUAL "ssl_server2")
         list(APPEND extra_sources
             ssl_test_lib.c
-            ${CMAKE_CURRENT_SOURCE_DIR}/../test/query_config.h
+            ${MBEDTLS_FRAMEWORK_DIR}/tests/programs/query_config.h
             ${CMAKE_CURRENT_BINARY_DIR}/../test/query_config.c)
     endif()
     add_executable(${exe} ${exe}.c $<TARGET_OBJECTS:mbedtls_test>
         ${extra_sources})
     target_link_libraries(${exe} ${libs} ${CMAKE_THREAD_LIBS_INIT})
-    target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../framework/tests/include
+    target_include_directories(${exe} PRIVATE ${MBEDTLS_FRAMEWORK_DIR}/tests/programs
+                                              ${MBEDTLS_FRAMEWORK_DIR}/tests/include
                                               ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/include)
     if(exe STREQUAL "ssl_client2" OR exe STREQUAL "ssl_server2")
         if(GEN_FILES)
             add_dependencies(${exe} generate_query_config_c)
         endif()
-        target_include_directories(${exe}
-            PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../test)
     endif()
 endforeach()
 
diff --git a/programs/ssl/ssl_context_info.c b/programs/ssl/ssl_context_info.c
index 51e8781..b9a0fe8 100644
--- a/programs/ssl/ssl_context_info.c
+++ b/programs/ssl/ssl_context_info.c
@@ -743,6 +743,13 @@
  *  uint8 alpn_chosen_len;
  *  uint8 alpn_chosen<0..2^8-1> // ALPN: negotiated application protocol
  *
+ * Note: In the mbedtls_ssl_context structure, badmac_seen is called
+ * badmac_seen_or_in_hsfraglen since Mbed TLS 3.6.2. The field contains
+ * the badmac_seen value in DTLS, and a handshake parsing intermediate
+ * value in non-DTLS TLS. The value is only meaningful for DTLS and should
+ * not be saved in non-DTLS TLS, so in this program, the context info file
+ * filed remains badmac_seen.
+ *
  * /p ssl   pointer to serialized session
  * /p len   number of bytes in the buffer
  */
diff --git a/programs/ssl/ssl_test_lib.h b/programs/ssl/ssl_test_lib.h
index 1da2dfb..d7fe80f 100644
--- a/programs/ssl/ssl_test_lib.h
+++ b/programs/ssl/ssl_test_lib.h
@@ -66,7 +66,7 @@
 
 #include <test/helpers.h>
 
-#include "../test/query_config.h"
+#include "query_config.h"
 
 #define ALPN_LIST_SIZE    10
 #define GROUP_LIST_SIZE   25
@@ -243,8 +243,8 @@
  * - free the provided PK context and re-initilize it as an opaque PK context
  *   wrapping the PSA key imported in the above step.
  *
- * \param[in/out] pk    On input the non-opaque PK context which contains the
- *                      key to be wrapped. On output the re-initialized PK
+ * \param[in,out] pk    On input, the non-opaque PK context which contains the
+ *                      key to be wrapped. On output, the re-initialized PK
  *                      context which represents the opaque version of the one
  *                      provided as input.
  * \param[in] psa_alg   The primary algorithm that will be associated to the
diff --git a/programs/test/CMakeLists.txt b/programs/test/CMakeLists.txt
index 70d827b..4511cdb 100644
--- a/programs/test/CMakeLists.txt
+++ b/programs/test/CMakeLists.txt
@@ -68,15 +68,22 @@
 endif()
 
 foreach(exe IN LISTS executables_libs executables_mbedcrypto)
+    set(source ${exe}.c)
     set(extra_sources "")
+    if(NOT EXISTS ${source} AND
+       EXISTS ${MBEDTLS_FRAMEWORK_DIR}/tests/programs/${source})
+         set(source ${MBEDTLS_FRAMEWORK_DIR}/tests/programs/${source})
+    endif()
+
     if(exe STREQUAL "query_compile_time_config")
         list(APPEND extra_sources
-            ${CMAKE_CURRENT_SOURCE_DIR}/query_config.h
+            ${MBEDTLS_FRAMEWORK_DIR}/tests/programs/query_config.h
             ${CMAKE_CURRENT_BINARY_DIR}/query_config.c)
     endif()
-    add_executable(${exe} ${exe}.c $<TARGET_OBJECTS:mbedtls_test>
+    add_executable(${exe} ${source} $<TARGET_OBJECTS:mbedtls_test>
         ${extra_sources})
-    target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../framework/tests/include)
+    target_include_directories(${exe} PRIVATE ${MBEDTLS_FRAMEWORK_DIR}/tests/include)
+    target_include_directories(${exe} PRIVATE ${MBEDTLS_FRAMEWORK_DIR}/tests/programs)
     target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../library)
     if(exe STREQUAL "query_compile_time_config")
         target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/programs/test/dlopen_demo.sh b/programs/test/dlopen_demo.sh
deleted file mode 100755
index 7280f1d..0000000
--- a/programs/test/dlopen_demo.sh
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/bin/sh
-
-# Run the shared library dynamic loading demo program.
-# This is only expected to work when Mbed TLS is built as a shared library.
-
-# Copyright The Mbed TLS Contributors
-# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
-
-. "${0%/*}/../demo_common.sh"
-
-msg "Test the dynamic loading of libmbed*"
-
-program="$programs_dir/test/dlopen"
-library_dir="$root_dir/library"
-
-# Skip this test if we don't have a shared library build. Detect this
-# through the absence of the demo program.
-if [ ! -e "$program" ]; then
-    msg "$0: this demo requires a shared library build."
-    # Exit with a success status so that this counts as a pass for run_demos.py.
-    exit
-fi
-
-# ELF-based Unix-like (Linux, *BSD, Solaris, ...)
-if [ -n "${LD_LIBRARY_PATH-}" ]; then
-    LD_LIBRARY_PATH="$library_dir:$LD_LIBRARY_PATH"
-else
-    LD_LIBRARY_PATH="$library_dir"
-fi
-export LD_LIBRARY_PATH
-
-# OSX/macOS
-if [ -n "${DYLD_LIBRARY_PATH-}" ]; then
-    DYLD_LIBRARY_PATH="$library_dir:$DYLD_LIBRARY_PATH"
-else
-    DYLD_LIBRARY_PATH="$library_dir"
-fi
-export DYLD_LIBRARY_PATH
-
-msg "Running dynamic loading test program: $program"
-msg "Loading libraries from: $library_dir"
-"$program"
diff --git a/programs/test/metatest.c b/programs/test/metatest.c
deleted file mode 100644
index f39cb54..0000000
--- a/programs/test/metatest.c
+++ /dev/null
@@ -1,484 +0,0 @@
-/** \file metatest.c
- *
- *  \brief Test features of the test framework.
- *
- * When you run this program, it runs a single "meta-test". A meta-test
- * performs an operation which should be caught as a failure by our
- * test framework. The meta-test passes if this program calls `exit` with
- * a nonzero status, or aborts, or is terminated by a signal, or if the
- * framework running the program considers the run an error (this happens
- * with Valgrind for a memory leak). The non-success of the meta-test
- * program means that the test failure has been caught correctly.
- *
- * Some failures are purely functional: the logic of the code causes the
- * test result to be set to FAIL. Other failures come from extra
- * instrumentation which is not present in a normal build; for example,
- * 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
- * the meta-tests for a given platform and validate that they trigger a
- * detected failure as expected.
- */
-
-/*
- *  Copyright The Mbed TLS Contributors
- *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
- */
-
-
-#include <mbedtls/debug.h>
-#include <mbedtls/platform.h>
-#include <mbedtls/platform_util.h>
-#include "test/helpers.h"
-#include "test/threading_helpers.h"
-#include "test/macros.h"
-#include "test/memory.h"
-#include "common.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#if defined(MBEDTLS_THREADING_C)
-#include <mbedtls/threading.h>
-#endif
-
-
-/* This is an external variable, so the compiler doesn't know that we're never
- * changing its value.
- */
-volatile int false_but_the_compiler_does_not_know = 0;
-
-/* Hide calls to calloc/free from static checkers such as
- * `gcc-12 -Wuse-after-free`, to avoid compile-time complaints about
- * code where we do mean to cause a runtime error. */
-void * (* volatile calloc_but_the_compiler_does_not_know)(size_t, size_t) = mbedtls_calloc;
-void(*volatile free_but_the_compiler_does_not_know)(void *) = mbedtls_free;
-
-/* Set n bytes at the address p to all-bits-zero, in such a way that
- * the compiler should not know that p is all-bits-zero. */
-static void set_to_zero_but_the_compiler_does_not_know(volatile void *p, size_t n)
-{
-    memset((void *) p, false_but_the_compiler_does_not_know, n);
-}
-
-/* Simulate an access to the given object, to avoid compiler optimizations
- * in code that prepares or consumes the object. */
-static void do_nothing_with_object(void *p)
-{
-    (void) p;
-}
-void(*volatile do_nothing_with_object_but_the_compiler_does_not_know)(void *) =
-    do_nothing_with_object;
-
-
-/****************************************************************/
-/* Test framework features */
-/****************************************************************/
-
-static void meta_test_fail(const char *name)
-{
-    (void) name;
-    mbedtls_test_fail("Forced test failure", __LINE__, __FILE__);
-}
-
-static void meta_test_not_equal(const char *name)
-{
-    int left = 20;
-    int right = 10;
-
-    (void) name;
-
-    TEST_EQUAL(left, right);
-exit:
-    ;
-}
-
-static void meta_test_not_le_s(const char *name)
-{
-    int left = 20;
-    int right = 10;
-
-    (void) name;
-
-    TEST_LE_S(left, right);
-exit:
-    ;
-}
-
-static void meta_test_not_le_u(const char *name)
-{
-    size_t left = 20;
-    size_t right = 10;
-
-    (void) name;
-
-    TEST_LE_U(left, right);
-exit:
-    ;
-}
-
-/****************************************************************/
-/* Platform features */
-/****************************************************************/
-
-static void null_pointer_dereference(const char *name)
-{
-    (void) name;
-    volatile char *volatile p;
-    set_to_zero_but_the_compiler_does_not_know(&p, sizeof(p));
-    /* Undefined behavior (read from null data pointer) */
-    mbedtls_printf("%p -> %u\n", (void *) p, (unsigned) *p);
-}
-
-static void null_pointer_call(const char *name)
-{
-    (void) name;
-    unsigned(*volatile p)(void);
-    set_to_zero_but_the_compiler_does_not_know(&p, sizeof(p));
-    /* Undefined behavior (execute null function pointer) */
-    /* The pointer representation may be truncated, but we don't care:
-     * the only point of printing it is to have some use of the pointer
-     * to dissuade the compiler from optimizing it away. */
-    mbedtls_printf("%lx() -> %u\n", (unsigned long) (uintptr_t) p, p());
-}
-
-
-/****************************************************************/
-/* Memory */
-/****************************************************************/
-
-static void read_after_free(const char *name)
-{
-    (void) name;
-    volatile char *p = calloc_but_the_compiler_does_not_know(1, 1);
-    *p = 'a';
-    free_but_the_compiler_does_not_know((void *) p);
-    /* Undefined behavior (read after free) */
-    mbedtls_printf("%u\n", (unsigned) *p);
-}
-
-static void double_free(const char *name)
-{
-    (void) name;
-    volatile char *p = calloc_but_the_compiler_does_not_know(1, 1);
-    *p = 'a';
-    free_but_the_compiler_does_not_know((void *) p);
-    /* Undefined behavior (double free) */
-    free_but_the_compiler_does_not_know((void *) p);
-}
-
-static void read_uninitialized_stack(const char *name)
-{
-    (void) name;
-    char buf[1];
-    if (false_but_the_compiler_does_not_know) {
-        buf[0] = '!';
-    }
-    char *volatile p = buf;
-    if (*p != 0) {
-        /* Unspecified result (read from uninitialized memory) */
-        mbedtls_printf("%u\n", (unsigned) *p);
-    }
-}
-
-static void memory_leak(const char *name)
-{
-    (void) name;
-    volatile char *p = calloc_but_the_compiler_does_not_know(1, 1);
-    mbedtls_printf("%u\n", (unsigned) *p);
-    /* Leak of a heap object */
-}
-
-/* name = "test_memory_poison_%(start)_%(offset)_%(count)_%(direction)"
- * Poison a region starting at start from an 8-byte aligned origin,
- * encompassing count bytes. Access the region at offset from the start.
- * %(start), %(offset) and %(count) are decimal integers.
- * %(direction) is either the character 'r' for read or 'w' for write.
- */
-static void test_memory_poison(const char *name)
-{
-    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",
-               &start, &offset, &count, &direction) != 4) {
-        mbedtls_fprintf(stderr, "%s: Bad name format: %s\n", __func__, name);
-        return;
-    }
-
-    union {
-        long long ll;
-        unsigned char buf[32];
-    } aligned;
-    memset(aligned.buf, 'a', sizeof(aligned.buf));
-
-    if (start > sizeof(aligned.buf)) {
-        mbedtls_fprintf(stderr,
-                        "%s: start=%" MBEDTLS_PRINTF_SIZET
-                        " > size=%" MBEDTLS_PRINTF_SIZET,
-                        __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,
-                        __func__, start + count, sizeof(aligned.buf));
-        return;
-    }
-    if (offset >= count) {
-        mbedtls_fprintf(stderr,
-                        "%s: offset=%" MBEDTLS_PRINTF_SIZET
-                        " >= count=%" MBEDTLS_PRINTF_SIZET,
-                        __func__, offset, count);
-        return;
-    }
-
-    MBEDTLS_TEST_MEMORY_POISON(aligned.buf + start, count);
-
-    if (direction == 'w') {
-        aligned.buf[start + offset] = 'b';
-        do_nothing_with_object_but_the_compiler_does_not_know(aligned.buf);
-    } else {
-        do_nothing_with_object_but_the_compiler_does_not_know(aligned.buf);
-        mbedtls_printf("%u\n", (unsigned) aligned.buf[start + offset]);
-    }
-}
-
-
-/****************************************************************/
-/* Threading */
-/****************************************************************/
-
-static void mutex_lock_not_initialized(const char *name)
-{
-    (void) name;
-#if defined(MBEDTLS_THREADING_C)
-    mbedtls_threading_mutex_t mutex;
-    memset(&mutex, 0, sizeof(mutex));
-    /* This mutex usage error is detected by our test framework's mutex usage
-     * verification framework. See framework/tests/src/threading_helpers.c. Other
-     * threading implementations (e.g. pthread without our instrumentation)
-     * might consider this normal usage. */
-    TEST_ASSERT(mbedtls_mutex_lock(&mutex) == 0);
-exit:
-    ;
-#endif
-}
-
-static void mutex_unlock_not_initialized(const char *name)
-{
-    (void) name;
-#if defined(MBEDTLS_THREADING_C)
-    mbedtls_threading_mutex_t mutex;
-    memset(&mutex, 0, sizeof(mutex));
-    /* This mutex usage error is detected by our test framework's mutex usage
-     * verification framework. See framework/tests/src/threading_helpers.c. Other
-     * threading implementations (e.g. pthread without our instrumentation)
-     * might consider this normal usage. */
-    TEST_ASSERT(mbedtls_mutex_unlock(&mutex) == 0);
-exit:
-    ;
-#endif
-}
-
-static void mutex_free_not_initialized(const char *name)
-{
-    (void) name;
-#if defined(MBEDTLS_THREADING_C)
-    mbedtls_threading_mutex_t mutex;
-    memset(&mutex, 0, sizeof(mutex));
-    /* This mutex usage error is detected by our test framework's mutex usage
-     * verification framework. See framework/tests/src/threading_helpers.c. Other
-     * threading implementations (e.g. pthread without our instrumentation)
-     * might consider this normal usage. */
-    mbedtls_mutex_free(&mutex);
-#endif
-}
-
-static void mutex_double_init(const char *name)
-{
-    (void) name;
-#if defined(MBEDTLS_THREADING_C)
-    mbedtls_threading_mutex_t mutex;
-    mbedtls_mutex_init(&mutex);
-    /* This mutex usage error is detected by our test framework's mutex usage
-     * verification framework. See framework/tests/src/threading_helpers.c. Other
-     * threading implementations (e.g. pthread without our instrumentation)
-     * might consider this normal usage. */
-    mbedtls_mutex_init(&mutex);
-    mbedtls_mutex_free(&mutex);
-#endif
-}
-
-static void mutex_double_free(const char *name)
-{
-    (void) name;
-#if defined(MBEDTLS_THREADING_C)
-    mbedtls_threading_mutex_t mutex;
-    mbedtls_mutex_init(&mutex);
-    mbedtls_mutex_free(&mutex);
-    /* This mutex usage error is detected by our test framework's mutex usage
-     * verification framework. See framework/tests/src/threading_helpers.c. Other
-     * threading implementations (e.g. pthread without our instrumentation)
-     * might consider this normal usage. */
-    mbedtls_mutex_free(&mutex);
-#endif
-}
-
-static void mutex_leak(const char *name)
-{
-    (void) name;
-#if defined(MBEDTLS_THREADING_C)
-    mbedtls_threading_mutex_t mutex;
-    mbedtls_mutex_init(&mutex);
-#endif
-    /* This mutex usage error is detected by our test framework's mutex usage
-     * verification framework. See framework/tests/src/threading_helpers.c. Other
-     * threading implementations (e.g. pthread without our instrumentation)
-     * might consider this normal usage. */
-}
-
-
-/****************************************************************/
-/* Command line entry point */
-/****************************************************************/
-
-typedef struct {
-    /** Command line argument that will trigger that metatest.
-     *
-     * Conventionally matches "[a-z0-9_]+". */
-    const char *name;
-
-    /** Platform under which that metatest is valid.
-     *
-     * - "any": should work anywhere.
-     * - "asan": triggers ASan (Address Sanitizer).
-     * - "msan": triggers MSan (Memory Sanitizer).
-     * - "pthread": requires MBEDTLS_THREADING_PTHREAD and MBEDTLS_TEST_HOOKS,
-     *   which enables MBEDTLS_TEST_MUTEX_USAGE internally in the test
-     *   framework (see framework/tests/src/threading_helpers.c).
-     */
-    const char *platform;
-
-    /** Function that performs the metatest.
-     *
-     * The function receives the name as an argument. This allows using the
-     * same function to perform multiple variants of a test based on the name.
-     *
-     * When executed on a conforming platform, the function is expected to
-     * either cause a test failure (mbedtls_test_fail()), or cause the
-     * program to abort in some way (e.g. by causing a segfault or by
-     * triggering a sanitizer).
-     *
-     * When executed on a non-conforming platform, the function may return
-     * normally or may have unpredictable behavior.
-     */
-    void (*entry_point)(const char *name);
-} metatest_t;
-
-/* The list of available meta-tests. Remember to register new functions here!
- *
- * Note that we always compile all the functions, so that `metatest --list`
- * will always list all the available meta-tests.
- *
- * See the documentation of metatest_t::platform for the meaning of
- * platform values.
- */
-metatest_t metatests[] = {
-    { "test_fail", "any", meta_test_fail },
-    { "test_not_equal", "any", meta_test_not_equal },
-    { "test_not_le_s", "any", meta_test_not_le_s },
-    { "test_not_le_u", "any", meta_test_not_le_u },
-    { "null_dereference", "any", null_pointer_dereference },
-    { "null_call", "any", null_pointer_call },
-    { "read_after_free", "asan", read_after_free },
-    { "double_free", "asan", double_free },
-    { "read_uninitialized_stack", "msan", read_uninitialized_stack },
-    { "memory_leak", "asan", memory_leak },
-    { "test_memory_poison_0_0_8_r", "poison", test_memory_poison },
-    { "test_memory_poison_0_0_8_w", "poison", test_memory_poison },
-    { "test_memory_poison_0_7_8_r", "poison", test_memory_poison },
-    { "test_memory_poison_0_7_8_w", "poison", test_memory_poison },
-    { "test_memory_poison_0_0_1_r", "poison", test_memory_poison },
-    { "test_memory_poison_0_0_1_w", "poison", test_memory_poison },
-    { "test_memory_poison_0_1_2_r", "poison", test_memory_poison },
-    { "test_memory_poison_0_1_2_w", "poison", test_memory_poison },
-    { "test_memory_poison_7_0_8_r", "poison", test_memory_poison },
-    { "test_memory_poison_7_0_8_w", "poison", test_memory_poison },
-    { "test_memory_poison_7_7_8_r", "poison", test_memory_poison },
-    { "test_memory_poison_7_7_8_w", "poison", test_memory_poison },
-    { "test_memory_poison_7_0_1_r", "poison", test_memory_poison },
-    { "test_memory_poison_7_0_1_w", "poison", test_memory_poison },
-    { "test_memory_poison_7_1_2_r", "poison", test_memory_poison },
-    { "test_memory_poison_7_1_2_w", "poison", test_memory_poison },
-    { "mutex_lock_not_initialized", "pthread", mutex_lock_not_initialized },
-    { "mutex_unlock_not_initialized", "pthread", mutex_unlock_not_initialized },
-    { "mutex_free_not_initialized", "pthread", mutex_free_not_initialized },
-    { "mutex_double_init", "pthread", mutex_double_init },
-    { "mutex_double_free", "pthread", mutex_double_free },
-    { "mutex_leak", "pthread", mutex_leak },
-    { NULL, NULL, NULL }
-};
-
-static void help(FILE *out, const char *argv0)
-{
-    mbedtls_fprintf(out, "Usage: %s list|TEST\n", argv0);
-    mbedtls_fprintf(out, "Run a meta-test that should cause a test failure.\n");
-    mbedtls_fprintf(out, "With 'list', list the available tests and their platform requirement.\n");
-}
-
-int main(int argc, char *argv[])
-{
-    const char *argv0 = argc > 0 ? argv[0] : "metatest";
-    if (argc != 2) {
-        help(stderr, argv0);
-        mbedtls_exit(MBEDTLS_EXIT_FAILURE);
-    }
-
-    /* Support "-help", "--help", "--list", etc. */
-    const char *command = argv[1];
-    while (*command == '-') {
-        ++command;
-    }
-
-    if (strcmp(argv[1], "help") == 0) {
-        help(stdout, argv0);
-        mbedtls_exit(MBEDTLS_EXIT_SUCCESS);
-    }
-    if (strcmp(argv[1], "list") == 0) {
-        for (const metatest_t *p = metatests; p->name != NULL; p++) {
-            mbedtls_printf("%s %s\n", p->name, p->platform);
-        }
-        mbedtls_exit(MBEDTLS_EXIT_SUCCESS);
-    }
-
-#if defined(MBEDTLS_TEST_MUTEX_USAGE)
-    mbedtls_test_mutex_usage_init();
-#endif
-
-    for (const metatest_t *p = metatests; p->name != NULL; p++) {
-        if (strcmp(argv[1], p->name) == 0) {
-            mbedtls_printf("Running metatest %s...\n", argv[1]);
-            p->entry_point(argv[1]);
-#if defined(MBEDTLS_TEST_MUTEX_USAGE)
-            mbedtls_test_mutex_usage_check();
-#endif
-            int result = (int) mbedtls_test_get_result();
-
-            mbedtls_printf("Running metatest %s... done, result=%d\n",
-                           argv[1], result);
-            mbedtls_exit(result == MBEDTLS_TEST_RESULT_SUCCESS ?
-                         MBEDTLS_EXIT_SUCCESS :
-                         MBEDTLS_EXIT_FAILURE);
-        }
-    }
-
-    mbedtls_fprintf(stderr, "%s: FATAL: No such metatest: %s\n",
-                    argv0, command);
-    mbedtls_exit(MBEDTLS_EXIT_FAILURE);
-}
diff --git a/programs/test/query_compile_time_config.c b/programs/test/query_compile_time_config.c
deleted file mode 100644
index a70e6da..0000000
--- a/programs/test/query_compile_time_config.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- *  Query the Mbed TLS compile time configuration
- *
- *  Copyright The Mbed TLS Contributors
- *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
- */
-
-#include "mbedtls/build_info.h"
-
-#include "mbedtls/platform.h"
-
-#define USAGE                                                                   \
-    "usage: %s [ -all | -any | -l ] <MBEDTLS_CONFIG> ...\n\n"                   \
-    "This program takes command line arguments which correspond to\n"           \
-    "the string representation of Mbed TLS compile time configurations.\n\n"    \
-    "If \"--all\" and \"--any\" are not used, then, if all given arguments\n"   \
-    "are defined in the Mbed TLS build, 0 is returned; otherwise 1 is\n"        \
-    "returned. Macro expansions of configurations will be printed (if any).\n"                                 \
-    "-l\tPrint all available configuration.\n"                                  \
-    "-all\tReturn 0 if all configurations are defined. Otherwise, return 1\n"   \
-    "-any\tReturn 0 if any configuration is defined. Otherwise, return 1\n"     \
-    "-h\tPrint this usage\n"
-
-#include <string.h>
-#include "query_config.h"
-
-int main(int argc, char *argv[])
-{
-    int i;
-
-    if (argc < 2 || strcmp(argv[1], "-h") == 0) {
-        mbedtls_printf(USAGE, argv[0]);
-        return MBEDTLS_EXIT_FAILURE;
-    }
-
-    if (strcmp(argv[1], "-l") == 0) {
-        list_config();
-        return 0;
-    }
-
-    if (strcmp(argv[1], "-all") == 0) {
-        for (i = 2; i < argc; i++) {
-            if (query_config(argv[i]) != 0) {
-                return 1;
-            }
-        }
-        return 0;
-    }
-
-    if (strcmp(argv[1], "-any") == 0) {
-        for (i = 2; i < argc; i++) {
-            if (query_config(argv[i]) == 0) {
-                return 0;
-            }
-        }
-        return 1;
-    }
-
-    for (i = 1; i < argc; i++) {
-        if (query_config(argv[i]) != 0) {
-            return 1;
-        }
-    }
-
-    return 0;
-}
diff --git a/programs/test/query_config.h b/programs/test/query_config.h
deleted file mode 100644
index 43f120b..0000000
--- a/programs/test/query_config.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- *  Query Mbed TLS compile time configurations from mbedtls_config.h
- *
- *  Copyright The Mbed TLS Contributors
- *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
- */
-
-#ifndef MBEDTLS_PROGRAMS_TEST_QUERY_CONFIG_H
-#define MBEDTLS_PROGRAMS_TEST_QUERY_CONFIG_H
-
-#include "mbedtls/build_info.h"
-
-/** Check whether a given configuration symbol is enabled.
- *
- * \param config    The symbol to query (e.g. "MBEDTLS_RSA_C").
- * \return          \c 0 if the symbol was defined at compile time
- *                  (in MBEDTLS_CONFIG_FILE or mbedtls_config.h),
- *                  \c 1 otherwise.
- *
- * \note            This function is defined in `programs/test/query_config.c`
- *                  which is automatically generated by
- *                  `scripts/generate_query_config.pl`.
- */
-int query_config(const char *config);
-
-/** List all enabled configuration symbols
- *
- * \note            This function is defined in `programs/test/query_config.c`
- *                  which is automatically generated by
- *                  `scripts/generate_query_config.pl`.
- */
-void list_config(void);
-
-#endif /* MBEDTLS_PROGRAMS_TEST_QUERY_CONFIG_H */
diff --git a/programs/test/query_included_headers.c b/programs/test/query_included_headers.c
deleted file mode 100644
index cdafa16..0000000
--- a/programs/test/query_included_headers.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/* Ad hoc report on included headers. */
-/*
- *  Copyright The Mbed TLS Contributors
- *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
- */
-
-#include <psa/crypto.h>
-#include <mbedtls/platform.h>
-
-int main(void)
-{
-
-    /* Which PSA platform header? */
-#if defined(PSA_CRYPTO_PLATFORM_H)
-    mbedtls_printf("PSA_CRYPTO_PLATFORM_H\n");
-#endif
-#if defined(PSA_CRYPTO_PLATFORM_ALT_H)
-    mbedtls_printf("PSA_CRYPTO_PLATFORM_ALT_H\n");
-#endif
-
-    /* Which PSA struct header? */
-#if defined(PSA_CRYPTO_STRUCT_H)
-    mbedtls_printf("PSA_CRYPTO_STRUCT_H\n");
-#endif
-#if defined(PSA_CRYPTO_STRUCT_ALT_H)
-    mbedtls_printf("PSA_CRYPTO_STRUCT_ALT_H\n");
-#endif
-
-}
diff --git a/programs/test/zeroize.c b/programs/test/zeroize.c
deleted file mode 100644
index c1cee0d..0000000
--- a/programs/test/zeroize.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Zeroize application for debugger-driven testing
- *
- * This is a simple test application used for debugger-driven testing to check
- * whether calls to mbedtls_platform_zeroize() are being eliminated by compiler
- * optimizations. This application is used by the GDB script at
- * tests/scripts/test_zeroize.gdb: the script sets a breakpoint at the last
- * return statement in the main() function of this program. The debugger
- * facilities are then used to manually inspect the memory and verify that the
- * call to mbedtls_platform_zeroize() was not eliminated.
- *
- *  Copyright The Mbed TLS Contributors
- *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
- */
-
-#include "mbedtls/build_info.h"
-
-#include <stdio.h>
-
-#include "mbedtls/platform.h"
-
-#include "mbedtls/platform_util.h"
-
-#define BUFFER_LEN 1024
-
-static void usage(void)
-{
-    mbedtls_printf("Zeroize is a simple program to assist with testing\n");
-    mbedtls_printf("the mbedtls_platform_zeroize() function by using the\n");
-    mbedtls_printf("debugger. This program takes a file as input and\n");
-    mbedtls_printf("prints the first %d characters. Usage:\n\n", BUFFER_LEN);
-    mbedtls_printf("       zeroize <FILE>\n");
-}
-
-int main(int argc, char **argv)
-{
-    int exit_code = MBEDTLS_EXIT_FAILURE;
-    FILE *fp;
-    char buf[BUFFER_LEN];
-    char *p = buf;
-    char *end = p + BUFFER_LEN;
-    int c;
-
-    if (argc != 2) {
-        mbedtls_printf("This program takes exactly 1 argument\n");
-        usage();
-        mbedtls_exit(exit_code);
-    }
-
-    fp = fopen(argv[1], "r");
-    if (fp == NULL) {
-        mbedtls_printf("Could not open file '%s'\n", argv[1]);
-        mbedtls_exit(exit_code);
-    }
-
-    while ((c = fgetc(fp)) != EOF && p < end - 1) {
-        *p++ = (char) c;
-    }
-    *p = '\0';
-
-    if (p - buf != 0) {
-        mbedtls_printf("%s\n", buf);
-        exit_code = MBEDTLS_EXIT_SUCCESS;
-    } else {
-        mbedtls_printf("The file is empty!\n");
-    }
-
-    fclose(fp);
-    mbedtls_platform_zeroize(buf, sizeof(buf));
-
-    mbedtls_exit(exit_code);   // GDB_BREAK_HERE -- don't remove this comment!
-}
diff --git a/scripts/generate_visualc_files.pl b/scripts/generate_visualc_files.pl
index bc1d502..9f28cdd 100755
--- a/scripts/generate_visualc_files.pl
+++ b/scripts/generate_visualc_files.pl
@@ -22,6 +22,7 @@
 my $vsx_sln_file = "$vsx_dir/mbedTLS.sln";
 
 my $programs_dir = 'programs';
+my $framework_programs_dir = 'framework/tests/programs';
 my $mbedtls_header_dir = 'include/mbedtls';
 my $psa_header_dir = 'include/psa';
 my $source_dir = 'library';
@@ -52,6 +53,7 @@
     3rdparty/everest/include/everest/kremlib
     tests/include
     framework/tests/include
+    framework/tests/programs
 );
 my $include_directories = join(';', map {"../../$_"} @include_directories);
 
@@ -112,7 +114,8 @@
         && -d $test_header_dir
         && -d $tls_test_header_dir
         && -d $test_drivers_header_dir
-        && -d $programs_dir;
+        && -d $programs_dir
+        && -d $framework_programs_dir;
 }
 
 sub slurp_file {
@@ -151,7 +154,14 @@
     (my $appname = $path) =~ s/.*\\//;
     my $is_test_app = ($path =~ m/^test\\/);
 
-    my $srcs = "<ClCompile Include=\"..\\..\\programs\\$path.c\" \/>";
+    my $srcs;
+    if( $appname eq "metatest" or $appname eq "query_compile_time_config" or
+        $appname eq "query_included_headers" or $appname eq "zeroize" ) {
+        $srcs = "<ClCompile Include=\"..\\..\\framework\\tests\\programs\\$appname.c\" \/>";
+    } else {
+        $srcs = "<ClCompile Include=\"..\\..\\programs\\$path.c\" \/>";
+    }
+
     if( $appname eq "ssl_client2" or $appname eq "ssl_server2" or
         $appname eq "query_compile_time_config" ) {
         $srcs .= "\n    <ClCompile Include=\"..\\..\\programs\\test\\query_config.c\" \/>";
@@ -267,6 +277,7 @@
                        $tls_test_header_dir,
                        $test_drivers_header_dir,
                        $source_dir,
+                       $framework_programs_dir,
                        @thirdparty_header_dirs,
                       );
     my @headers = (map { <$_/*.h> } @header_dirs);
diff --git a/scripts/make_generated_files.bat b/scripts/make_generated_files.bat
index 0c15c38..75c2de0 100644
--- a/scripts/make_generated_files.bat
+++ b/scripts/make_generated_files.bat
@@ -28,4 +28,5 @@
 python framework\scripts\generate_psa_tests.py || exit /b 1

 python framework\scripts\generate_test_keys.py --output framework\tests\include\test\test_keys.h || exit /b 1

 python framework\scripts\generate_test_cert_macros.py --output tests\src\test_certs.h || exit /b 1

+python framework\scripts\generate_tls_handshake_tests.py || exit /b 1

 python framework\scripts\generate_tls13_compat_tests.py || exit /b 1

diff --git a/tests/.gitignore b/tests/.gitignore
index 0c58875..10eb873 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -18,6 +18,7 @@
 
 ###START_GENERATED_FILES###
 # Generated source files
+/opt-testcases/handshake-generated.sh
 /opt-testcases/tls13-compat.sh
 /suites/*.generated.data
 /suites/test_suite_config.mbedtls_boolean.data
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 98973c9..aa8ae23 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -124,6 +124,24 @@
             # change too often in ways that don't affect the result
             # ((un)commenting some options).
     )
+
+    add_custom_command(
+        OUTPUT
+            ${CMAKE_CURRENT_SOURCE_DIR}/opt-testcases/handshake-generated.sh
+        WORKING_DIRECTORY
+            ${CMAKE_CURRENT_SOURCE_DIR}/..
+        COMMAND
+            "${MBEDTLS_PYTHON_EXECUTABLE}"
+            "${CMAKE_CURRENT_SOURCE_DIR}/../framework/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
+    )
+    add_custom_target(handshake-generated.sh
+        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/opt-testcases/handshake-generated.sh)
+    set_target_properties(handshake-generated.sh PROPERTIES EXCLUDE_FROM_ALL NO)
+    add_dependencies(${ssl_opt_target} handshake-generated.sh)
+
     add_custom_command(
         OUTPUT
             ${ecp_generated_data_files}
diff --git a/tests/Makefile b/tests/Makefile
index dd1af15..1fa5dd1 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -58,6 +58,13 @@
 # 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
+	echo "  Gen   $@"
+	$(PYTHON) ../framework/scripts/generate_tls_handshake_tests.py -o $@
+GENERATED_FILES += opt-testcases/handshake-generated.sh
+ssl-opt: opt-testcases/handshake-generated.sh
+
 opt-testcases/tls13-compat.sh: ../framework/scripts/generate_tls13_compat_tests.py
 	echo "  Gen   $@"
 	$(PYTHON) ../framework/scripts/generate_tls13_compat_tests.py -o $@
diff --git a/tests/scripts/check-generated-files.sh b/tests/scripts/check-generated-files.sh
index b61c5ac..088f16f 100755
--- a/tests/scripts/check-generated-files.sh
+++ b/tests/scripts/check-generated-files.sh
@@ -135,6 +135,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 framework/scripts/generate_tls13_compat_tests.py tests/opt-testcases/tls13-compat.sh
     check framework/scripts/generate_test_cert_macros.py tests/src/test_certs.h
     # generate_visualc_files enumerates source files (library/*.c). It doesn't
diff --git a/tests/scripts/components-build-system.sh b/tests/scripts/components-build-system.sh
index a6da8e6..5dc296a 100644
--- a/tests/scripts/components-build-system.sh
+++ b/tests/scripts/components-build-system.sh
@@ -13,7 +13,7 @@
     msg "build/test: make shared" # ~ 40s
     make SHARED=1 TEST_CPP=1 all check
     ldd programs/util/strerror | grep libmbedcrypto
-    programs/test/dlopen_demo.sh
+    $FRAMEWORK/tests/programs/dlopen_demo.sh
 }
 
 component_test_cmake_shared () {
@@ -22,7 +22,7 @@
     make
     ldd programs/util/strerror | grep libmbedcrypto
     make test
-    programs/test/dlopen_demo.sh
+    $FRAMEWORK/tests/programs/dlopen_demo.sh
 }
 
 support_test_cmake_out_of_source () {
diff --git a/tests/scripts/components-compiler.sh b/tests/scripts/components-compiler.sh
index a4b2323..c0edd20 100644
--- a/tests/scripts/components-compiler.sh
+++ b/tests/scripts/components-compiler.sh
@@ -135,7 +135,7 @@
         for compiler in clang gcc; do
             msg "test: $compiler $optimization_flag, mbedtls_platform_zeroize()"
             make programs CC="$compiler" DEBUG=1 CFLAGS="$optimization_flag"
-            gdb -ex "$gdb_disable_aslr" -x tests/scripts/test_zeroize.gdb -nw -batch -nx 2>&1 | tee test_zeroize.log
+            gdb -ex "$gdb_disable_aslr" -x $FRAMEWORK/tests/programs/test_zeroize.gdb -nw -batch -nx 2>&1 | tee test_zeroize.log
             grep "The buffer was correctly zeroized" test_zeroize.log
             not grep -i "error" test_zeroize.log
             rm -f test_zeroize.log
diff --git a/tests/scripts/test_zeroize.gdb b/tests/scripts/test_zeroize.gdb
deleted file mode 100644
index 57f771f..0000000
--- a/tests/scripts/test_zeroize.gdb
+++ /dev/null
@@ -1,64 +0,0 @@
-# test_zeroize.gdb
-#
-# Copyright The Mbed TLS Contributors
-# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
-#
-# Purpose
-#
-# Run a test using the debugger to check that the mbedtls_platform_zeroize()
-# function in platform_util.h is not being optimized out by the compiler. To do
-# so, the script loads the test program at programs/test/zeroize.c and sets a
-# breakpoint at the last return statement in main(). When the breakpoint is
-# hit, the debugger manually checks the contents to be zeroized and checks that
-# it is actually cleared.
-#
-# The mbedtls_platform_zeroize() test is debugger driven because there does not
-# seem to be a mechanism to reliably check whether the zeroize calls are being
-# eliminated by compiler optimizations from within the compiled program. The
-# problem is that a compiler would typically remove what it considers to be
-# "unnecessary" assignments as part of redundant code elimination. To identify
-# such code, the compilar will create some form dependency graph between
-# reads and writes to variables (among other situations). It will then use this
-# data structure to remove redundant code that does not have an impact on the
-# program's observable behavior. In the case of mbedtls_platform_zeroize(), an
-# intelligent compiler could determine that this function clears a block of
-# memory that is not accessed later in the program, so removing the call to
-# mbedtls_platform_zeroize() does not have an observable behavior. However,
-# inserting a test after a call to mbedtls_platform_zeroize() to check whether
-# the block of memory was correctly zeroed would force the compiler to not
-# eliminate the mbedtls_platform_zeroize() call. If this does not occur, then
-# the compiler potentially has a bug.
-#
-# Note: This test requires that the test program is compiled with -g3.
-
-set confirm off
-
-file ./programs/test/zeroize
-
-search GDB_BREAK_HERE
-break $_
-
-set args ./programs/test/zeroize.c
-run
-
-set $i = 0
-set $len = sizeof(buf)
-set $buf = buf
-
-while $i < $len
-    if $buf[$i++] != 0
-        echo The buffer at was not zeroized\n
-        quit 1
-    end
-end
-
-echo The buffer was correctly zeroized\n
-
-continue
-
-if $_exitcode != 0
-    echo The program did not terminate correctly\n
-    quit 1
-end
-
-quit 0
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 0376018..fdbe0a9 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -14457,6 +14457,20 @@
             -c "Handshake was completed" \
             -s "dumping .client hello, compression. (2 bytes)"
 
+# Handshake defragmentation testing
+
+# 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" \
+            "$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 heap memory usage after handshake
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 requires_config_enabled MBEDTLS_MEMORY_DEBUG
diff --git a/tests/suites/test_suite_debug.data b/tests/suites/test_suite_debug.data
index 8b17eb8..46b6be4 100644
--- a/tests/suites/test_suite_debug.data
+++ b/tests/suites/test_suite_debug.data
@@ -1,3 +1,12 @@
+printf "%" MBEDTLS_PRINTF_SIZET, 0
+printf_int_expr:PRINTF_SIZET:sizeof(size_t):0:"0"
+
+printf "%" MBEDTLS_PRINTF_LONGLONG, 0
+printf_int_expr:PRINTF_LONGLONG:sizeof(long long):0:"0"
+
+printf "%" MBEDTLS_PRINTF_MS_TIME, 0
+printf_int_expr:PRINTF_MS_TIME:sizeof(mbedtls_ms_time_t):0:"0"
+
 Debug print msg (threshold 1, level 0)
 debug_print_msg_threshold:1:0:"MyFile":999:"MyFile(0999)\: Text message, 2 == 2\n"
 
diff --git a/tests/suites/test_suite_debug.function b/tests/suites/test_suite_debug.function
index 878ceed..9e53107 100644
--- a/tests/suites/test_suite_debug.function
+++ b/tests/suites/test_suite_debug.function
@@ -4,11 +4,34 @@
 #include "mbedtls/pk.h"
 #include <test/ssl_helpers.h>
 
+#if defined(_WIN32)
+#   include <stdlib.h>
+#   include <crtdbg.h>
+#endif
+
+// Dummy type for builds without MBEDTLS_HAVE_TIME
+#if !defined(MBEDTLS_HAVE_TIME)
+typedef int64_t mbedtls_ms_time_t;
+#endif
+
+typedef enum {
+    PRINTF_SIZET,
+    PRINTF_LONGLONG,
+    PRINTF_MS_TIME,
+} printf_format_indicator_t;
+
+const char *const printf_formats[] = {
+    [PRINTF_SIZET]    = "%" MBEDTLS_PRINTF_SIZET,
+    [PRINTF_LONGLONG] = "%" MBEDTLS_PRINTF_LONGLONG,
+    [PRINTF_MS_TIME]  = "%" MBEDTLS_PRINTF_MS_TIME,
+};
+
 struct buffer_data {
     char buf[2000];
     char *ptr;
 };
 
+#if defined(MBEDTLS_SSL_TLS_C)
 static void string_debug(void *data, int level, const char *file, int line, const char *str)
 {
     struct buffer_data *buffer = (struct buffer_data *) data;
@@ -44,14 +67,77 @@
 
     buffer->ptr = p;
 }
+#endif /* MBEDTLS_SSL_TLS_C */
+
+#if defined(_WIN32)
+static void noop_invalid_parameter_handler(
+    const wchar_t *expression,
+    const wchar_t *function,
+    const wchar_t *file,
+    unsigned int line,
+    uintptr_t pReserved)
+{
+    (void) expression;
+    (void) function;
+    (void) file;
+    (void) line;
+    (void) pReserved;
+}
+#endif /* _WIN32 */
+
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
- * depends_on:MBEDTLS_DEBUG_C:MBEDTLS_SSL_TLS_C
+ * depends_on:MBEDTLS_DEBUG_C
  * END_DEPENDENCIES
  */
 
 /* BEGIN_CASE */
+void printf_int_expr(int format_indicator, intmax_t sizeof_x, intmax_t x, char *result)
+{
+#if defined(_WIN32)
+    /* Windows treats any invalid format specifiers passsed to the CRT as fatal assertion failures.
+       Disable this behaviour temporarily, so the rest of the test cases can complete. */
+    _invalid_parameter_handler saved_handler =
+        _set_invalid_parameter_handler(noop_invalid_parameter_handler);
+
+    // Disable assertion pop-up window in Debug builds
+    int saved_report_mode = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_REPORT_MODE);
+    _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
+#endif
+
+    const char *format = printf_formats[format_indicator];
+    char *output = NULL;
+    const size_t n = strlen(result);
+
+    /* 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));
+    } else if (sizeof_x == sizeof(long)) {
+        TEST_EQUAL(n, mbedtls_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));
+    } else {
+        TEST_FAIL(
+            "sizeof_x <= sizeof(int) || sizeof_x == sizeof(long) || sizeof_x == sizeof(long long)");
+    }
+    TEST_MEMORY_COMPARE(result, n + 1, output, n + 1);
+
+exit:
+    mbedtls_free(output);
+    output = NULL;
+
+#if defined(_WIN32)
+    // Restore default Windows behaviour
+    _set_invalid_parameter_handler(saved_handler);
+    _CrtSetReportMode(_CRT_ASSERT, saved_report_mode);
+    (void) saved_report_mode;
+#endif
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_SSL_TLS_C */
 void debug_print_msg_threshold(int threshold, int level, char *file,
                                int line, char *result_str)
 {
@@ -90,7 +176,7 @@
 }
 /* END_CASE */
 
-/* BEGIN_CASE */
+/* BEGIN_CASE depends_on:MBEDTLS_SSL_TLS_C */
 void mbedtls_debug_print_ret(char *file, int line, char *text, int value,
                              char *result_str)
 {
@@ -126,7 +212,7 @@
 }
 /* END_CASE */
 
-/* BEGIN_CASE */
+/* BEGIN_CASE depends_on:MBEDTLS_SSL_TLS_C */
 void mbedtls_debug_print_buf(char *file, int line, char *text,
                              data_t *data, char *result_str)
 {
@@ -162,7 +248,7 @@
 }
 /* END_CASE */
 
-/* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C:!MBEDTLS_X509_REMOVE_INFO */
+/* BEGIN_CASE depends_on:MBEDTLS_SSL_TLS_C:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C:!MBEDTLS_X509_REMOVE_INFO */
 void mbedtls_debug_print_crt(char *crt_file, char *file, int line,
                              char *prefix, char *result_str)
 {
@@ -202,7 +288,7 @@
 }
 /* END_CASE */
 
-/* BEGIN_CASE depends_on:MBEDTLS_BIGNUM_C */
+/* BEGIN_CASE depends_on:MBEDTLS_SSL_TLS_C:MBEDTLS_BIGNUM_C */
 void mbedtls_debug_print_mpi(char *value, char *file, int line,
                              char *prefix, char *result_str)
 {
diff --git a/tests/suites/test_suite_md.function b/tests/suites/test_suite_md.function
index 4e62154..4497d04 100644
--- a/tests/suites/test_suite_md.function
+++ b/tests/suites/test_suite_md.function
@@ -420,7 +420,7 @@
 }
 /* END_CASE */
 
-/* BEGIN_CASE */
+/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C */
 void md_psa_dynamic_dispatch(int md_type, int pre_psa_ret, int post_psa_engine)
 {
     const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_type);
diff --git a/tests/suites/test_suite_test_helpers.function b/tests/suites/test_suite_test_helpers.function
index 8c5d5ad..0139faf 100644
--- a/tests/suites/test_suite_test_helpers.function
+++ b/tests/suites/test_suite_test_helpers.function
@@ -15,7 +15,7 @@
 /* Test that poison+unpoison leaves the memory accessible. */
 /* We can't test that poisoning makes the memory inaccessible:
  * there's no sane way to catch an Asan/Valgrind complaint.
- * That negative testing is done in programs/test/metatest.c. */
+ * That negative testing is done in framework/tests/programs/metatest.c. */
 void memory_poison_unpoison(int align, int size)
 {
     unsigned char *buf = NULL;