Merge pull request #7857 from minosgalanakis/bugifx/address_curve_bits

[BigNum] test_suite_ecp: Fixed curve bit-length.
diff --git a/.travis.yml b/.travis.yml
index bf5ccd9..f411ec3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -32,6 +32,10 @@
           packages:
           - clang-10
           - gnutls-bin
+      env:
+        # Platform tests have an allocation that returns null
+        - ASAN_OPTIONS="allocator_may_return_null=1"
+        - MSAN_OPTIONS="allocator_may_return_null=1"
       script:
         # Do a manual build+test sequence rather than using all.sh,
         # because there's no all.sh component that does what we want,
@@ -89,6 +93,10 @@
         apt:
           packages:
           - gcc
+      env:
+        # Platform tests have an allocation that returns null
+        - ASAN_OPTIONS="allocator_may_return_null=1"
+        - MSAN_OPTIONS="allocator_may_return_null=1"
       script:
         # Do a manual build+test sequence rather than using all.sh.
         #
@@ -115,6 +123,10 @@
           packages:
           - clang
           - gnutls-bin
+      env:
+        # Platform tests have an allocation that returns null
+        - ASAN_OPTIONS="allocator_may_return_null=1"
+        - MSAN_OPTIONS="allocator_may_return_null=1"
       script:
         # Do a manual build+test sequence rather than using all.sh.
         #
@@ -129,13 +141,37 @@
         - tests/scripts/travis-log-failure.sh
         - tests/context-info.sh
 
+    - name: Arm64 accelerators tests on arm64 host
+      os: linux
+      dist: focal
+      arch: arm64
+      addons:
+        apt:
+          packages:
+          - gcc
+      script:
+        # Do a manual build+test sequence rather than using all.sh.
+        #
+        # This is arm64 host only test for no runtime detection case. Internal
+        # and Open CI do not include Arm64 host, and they check if components
+        # are be tested. As result, it will always fail on `pre-test-check` in
+        # them.
+        - scripts/config.py unset MBEDTLS_AESNI_C
+        - scripts/config.py unset MBEDTLS_PADLOCK_C
+        - scripts/config.py set MBEDTLS_AESCE_C
+        - scripts/config.py set MBEDTLS_AES_USE_HARDWARE_ONLY
+        - make generated_files
+        - make
+        - programs/test/selftest aes | grep "using AESCE"
+        - tests/context-info.sh
+
 after_failure:
 - tests/scripts/travis-log-failure.sh
 
 env:
   global:
     - SEED=1
-    - secure: "JECCru6HASpKZ0OLfHh8f/KXhKkdrCwjquZghd/qbA4ksxsWImjR7KEPERcaPndXEilzhDbKwuFvJiQX2duVgTGoq745YGhLZIjzo1i8tySkceCVd48P8WceYGz+F/bmY7r+m6fFNuxDSoGGSVeA4Lnjvmm8PFUP45YodDV9no4="
+    - secure: "GF/Fde5fkm15T/RNykrjrPV5Uh1KJ70cP308igL6Xkk3eJmqkkmWCe9JqRH12J3TeWw2fu9PYPHt6iFSg6jasgqysfUyg+W03knRT5QNn3h5eHgt36cQJiJr6t3whPrRaiM6U9omE0evm+c0cAwlkA3GGSMw8Z+na4EnKI6OFCo="
 
 install:
   - $PYTHON scripts/min_requirements.py
diff --git a/3rdparty/p256-m/p256-m/p256-m.c b/3rdparty/p256-m/p256-m/p256-m.c
index 53d306f..21a021b 100644
--- a/3rdparty/p256-m/p256-m/p256-m.c
+++ b/3rdparty/p256-m/p256-m/p256-m.c
@@ -199,10 +199,12 @@
  * Currently assembly optimisations are only supported with GCC/Clang for
  * Arm's Cortex-A and Cortex-M lines of CPUs, which start with the v6-M and
  * v7-M architectures. __ARM_ARCH_PROFILE is not defined for v6 and earlier.
+ * Thumb and 32-bit assembly is supported; aarch64 is not supported.
  */
 #if defined(__GNUC__) &&\
     defined(__ARM_ARCH) && __ARM_ARCH >= 6 && defined(__ARM_ARCH_PROFILE) && \
-    ( __ARM_ARCH_PROFILE == 77 || __ARM_ARCH_PROFILE == 65 ) /* 'M' or 'A' */
+    ( __ARM_ARCH_PROFILE == 77 || __ARM_ARCH_PROFILE == 65 ) /* 'M' or 'A' */ && \
+    !defined(__aarch64__)
 
 /*
  * This set of CPUs is conveniently partitioned as follows:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9092c49..4d7e0b0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -226,7 +226,9 @@
 endif(CMAKE_COMPILER_IS_CLANG)
 
 if(CMAKE_COMPILER_IS_IAR)
-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --warn_about_c_style_casts -Ohz")
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --warn_about_c_style_casts")
+    set(CMAKE_C_FLAGS_RELEASE     "-Ohz")
+    set(CMAKE_C_FLAGS_DEBUG       "--debug -On")
 endif(CMAKE_COMPILER_IS_IAR)
 
 if(CMAKE_COMPILER_IS_MSVC)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3a8c5c6..8454fb8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -84,8 +84,14 @@
 License and Copyright
 ---------------------
 
-All new files should include the [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) standard license header where possible. For licensing details, please see the [License section of the README](README.md#License).
+Unless specifically indicated otherwise in a file, Mbed TLS files are provided under the [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) license. See the [LICENSE](LICENSE) file for the full text of this license.
+
+Contributors must accept that their contributions are made under both the Apache-2.0 AND [GPL-2.0-or-later](https://spdx.org/licenses/GPL-2.0-or-later.html) licenses. This enables LTS (Long Term Support) branches of the software to be provided under either the Apache-2.0 or GPL-2.0-or-later licenses.
+
+All new files should include the [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) standard license header where possible.
 
 The copyright on contributions is retained by the original authors of the code. Where possible for new files, this should be noted in a comment at the top of the file in the form: "Copyright The Mbed TLS Contributors".
 
-When contributing code to us, the committer and all authors are required to make the submission under the terms of the [Developer Certificate of Origin](dco.txt), confirming that the code submitted can (legally) become part of the project, and be subject to the same Apache 2.0 license. This is done by including the standard Git `Signed-off-by:` line in every commit message. If more than one person contributed to the commit, they should also add their own `Signed-off-by:` line.
+When contributing code to us, the committer and all authors are required to make the submission under the terms of the [Developer Certificate of Origin](dco.txt), confirming that the code submitted can (legally) become part of the project, and is submitted under both the Apache-2.0 AND GPL-2.0-or-later licenses.
+
+This is done by including the standard Git `Signed-off-by:` line in every commit message. If more than one person contributed to the commit, they should also add their own `Signed-off-by:` line.
diff --git a/ChangeLog.d/add-aes-hardware-only-option.txt b/ChangeLog.d/add-aes-hardware-only-option.txt
new file mode 100644
index 0000000..a185aff
--- /dev/null
+++ b/ChangeLog.d/add-aes-hardware-only-option.txt
@@ -0,0 +1,6 @@
+Features
+   * New configuration option MBEDTLS_AES_USE_HARDWARE_ONLY introduced. When
+     using CPU-accelerated AES (e.g., Arm Crypto Extensions), this option
+     disables the plain C implementation and the run-time detection for the
+     CPU feature, which reduces code size and avoids the vulnerability of the
+     plain C implementation.
diff --git a/ChangeLog.d/add-pbkdf2-cmac.txt b/ChangeLog.d/add-pbkdf2-cmac.txt
new file mode 100644
index 0000000..0ed84ea
--- /dev/null
+++ b/ChangeLog.d/add-pbkdf2-cmac.txt
@@ -0,0 +1,2 @@
+Features
+   * Add support for PBKDF2-CMAC through the PSA API.
diff --git a/ChangeLog.d/add-rfc822-directoryname-csr-gen.txt b/ChangeLog.d/add-rfc822-directoryname-csr-gen.txt
new file mode 100644
index 0000000..ff8693c
--- /dev/null
+++ b/ChangeLog.d/add-rfc822-directoryname-csr-gen.txt
@@ -0,0 +1,3 @@
+Features
+   * Add a possibility to generate CSR's with RCF822 and directoryName subtype
+     of subjectAltName extension in x509 certificates.
diff --git a/ChangeLog.d/fix-a-few-unchecked-return.txt b/ChangeLog.d/fix-a-few-unchecked-return.txt
new file mode 100644
index 0000000..aadde36
--- /dev/null
+++ b/ChangeLog.d/fix-a-few-unchecked-return.txt
@@ -0,0 +1,3 @@
+Bugfix
+   * Fix some cases where mbedtls_mpi_mod_exp, RSA key construction or ECDSA
+     signature can silently return an incorrect result in low memory conditions.
diff --git a/ChangeLog.d/fix-aes-cbc-iv-corruption b/ChangeLog.d/fix-aes-cbc-iv-corruption
new file mode 100644
index 0000000..11eb946
--- /dev/null
+++ b/ChangeLog.d/fix-aes-cbc-iv-corruption
@@ -0,0 +1,3 @@
+Bugfix
+   * Fix a potential corruption of the passed-in IV when mbedtls_aes_crypt_cbc()
+     is called with zero length and padlock is not enabled.
diff --git a/ChangeLog.d/fix-empty-enum.txt b/ChangeLog.d/fix-empty-enum.txt
new file mode 100644
index 0000000..458d58f
--- /dev/null
+++ b/ChangeLog.d/fix-empty-enum.txt
@@ -0,0 +1,3 @@
+Bugfix
+   * Fix compile failure due to empty enum in cipher_wrap.c, when building
+     with a very minimal configuration. Fixes #7625.
diff --git a/ChangeLog.d/fix-iar-compiler-warnings.txt b/ChangeLog.d/fix-iar-compiler-warnings.txt
new file mode 100644
index 0000000..0dc2623
--- /dev/null
+++ b/ChangeLog.d/fix-iar-compiler-warnings.txt
@@ -0,0 +1,2 @@
+Bugfix
+   * Fix IAR compiler warnings.
diff --git a/ChangeLog.d/improve-doc-on-ecp-curve-optimized-representation.txt b/ChangeLog.d/improve-doc-on-ecp-curve-optimized-representation.txt
new file mode 100644
index 0000000..8fdc588
--- /dev/null
+++ b/ChangeLog.d/improve-doc-on-ecp-curve-optimized-representation.txt
@@ -0,0 +1,3 @@
+Features
+   * The documentation of mbedtls_ecp_group now describes the optimized
+     representation of A for some curves. Fixes #8045.
diff --git a/ChangeLog.d/psa_crypto_user_config_file.txt b/ChangeLog.d/psa_crypto_user_config_file.txt
new file mode 100644
index 0000000..f538f47
--- /dev/null
+++ b/ChangeLog.d/psa_crypto_user_config_file.txt
@@ -0,0 +1,3 @@
+Bugfix
+   * Don't try to include MBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE when
+     MBEDTLS_PSA_CRYPTO_CONFIG is disabled.
diff --git a/ChangeLog.d/use_heap_rsa_signature.txt b/ChangeLog.d/use_heap_rsa_signature.txt
new file mode 100644
index 0000000..e6d7b12
--- /dev/null
+++ b/ChangeLog.d/use_heap_rsa_signature.txt
@@ -0,0 +1,4 @@
+Changes
+   * Use heap memory to allocate DER encoded RSA private key.
+     This reduces stack usage significantly for RSA signature
+     operations when MBEDTLS_PSA_CRYPTO_C is defined.
diff --git a/ChangeLog.d/x509-ec-algorithm-identifier-fix.txt b/ChangeLog.d/x509-ec-algorithm-identifier-fix.txt
new file mode 100644
index 0000000..c1de491
--- /dev/null
+++ b/ChangeLog.d/x509-ec-algorithm-identifier-fix.txt
@@ -0,0 +1,4 @@
+Bugfix
+   * Fix x509 certificate generation to conform to RFC 5480 / RFC 5758 when
+     using ECC key. The certificate was rejected by some crypto frameworks.
+     Fixes #2924.
diff --git a/README.md b/README.md
index cbdb2df3..a3fcd2e 100644
--- a/README.md
+++ b/README.md
@@ -307,13 +307,14 @@
 License
 -------
 
-Unless specifically indicated otherwise in a file, Mbed TLS files are provided under the [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) license. See the [LICENSE](LICENSE) file for the full text of this license. Contributors must accept that their contributions are made under both the Apache-2.0 AND [GPL-2.0-or-later](https://spdx.org/licenses/GPL-2.0-or-later.html) licenses. This enables LTS (Long Term Support) branches of the software to be provided under either the Apache-2.0 OR GPL-2.0-or-later licenses.
+Unless specifically indicated otherwise in a file, Mbed TLS files are provided under the [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) license. See the [LICENSE](LICENSE) file for the full text of this license, and [the 'License and Copyright' section in the contributing guidelines](CONTRIBUTING.md#License-and-Copyright) for more information.
 
 ### Third-party code included in Mbed TLS
+
 This project contains code from other projects. This code is located within the `3rdparty/` directory. The original license text is included within project subdirectories, and in source files. The projects are listed below:
 
 * `3rdparty/everest/`: Files stem from [Project Everest](https://project-everest.github.io/) and are distributed under the Apache 2.0 license.
-* `3rdparty/p256-m/p256-m/`: Files have been taken from the [p256-m](https://github.com/mpg/p256-m) repository. The code in the original repository is distributed under the Apache 2.0 license. It is also used by the project under the Apache 2.0 license. We do not plan to regularly update these files, so they may not contain fixes and improvements present in the upstream project.
+* `3rdparty/p256-m/p256-m/`: Files have been taken from the [p256-m](https://github.com/mpg/p256-m) repository. The code in the original repository is distributed under the Apache 2.0 license. It is also used by Mbed TLS under the Apache 2.0 license. We do not plan to regularly update these files, so they may not contain fixes and improvements present in the upstream project.
 
 Contributing
 ------------
diff --git a/docs/architecture/psa-thread-safety.md b/docs/architecture/psa-thread-safety.md
new file mode 100644
index 0000000..b0ca808
--- /dev/null
+++ b/docs/architecture/psa-thread-safety.md
@@ -0,0 +1,284 @@
+Thread safety of the PSA subsystem
+==================================
+
+## Requirements
+
+### Backward compatibility requirement
+
+Code that is currently working must keep working. There can be an exception for code that uses features that are advertised as experimental; for example, it would be annoying but ok to add extra requirements for drivers.
+
+(In this section, “currently” means Mbed TLS releases without proper concurrency management: 3.0.0, 3.1.0, and any other subsequent 3.x version.)
+
+In particular, if you either protect all PSA calls with a mutex, or only ever call PSA functions from a single thread, your application currently works and must keep working. If your application currently builds and works with `MBEDTLS_PSA_CRYPTO_C` and `MBEDTLS_THREADING_C` enabled, it must keep building and working.
+
+As a consequence, we must not add a new platform requirement beyond mutexes for the base case. It would be ok to add new platform requirements if they're only needed for PSA drivers, or if they're only performance improvements.
+
+Tempting platform requirements that we cannot add to the default `MBEDTLS_THREADING_C` include:
+
+* Releasing a mutex from a different thread than the one that acquired it. This isn't even guaranteed to work with pthreads.
+* New primitives such as semaphores or condition variables.
+
+### Correctness out of the box
+
+If you build with `MBEDTLS_PSA_CRYPTO_C` and `MBEDTLS_THREADING_C`, the code must be functionally correct: no race conditions, deadlocks or livelocks.
+
+The [PSA Crypto API specification](https://armmbed.github.io/mbed-crypto/html/overview/conventions.html#concurrent-calls) defines minimum expectations for concurrent calls. They must work as if they had been executed one at a time, except that the following cases have undefined behavior:
+
+* Destroying a key while it's in use.
+* Concurrent calls using the same operation object. (An operation object may not be used by more than one thread at a time. But it can move from one thread to another between calls.)
+* Overlap of an output buffer with an input or output of a concurrent call.
+* Modification of an input buffer during a call.
+
+Note that while the specification does not define the behavior in such cases, Mbed TLS can be used as a crypto service. It's acceptable if an application can mess itself up, but it is not acceptable if an application can mess up the crypto service. As a consequence, destroying a key while it's in use may violate the security property that all key material is erased as soon as `psa_destroy_key` returns, but it may not cause data corruption or read-after-free inside the key store.
+
+### No spinning
+
+The code must not spin on a potentially non-blocking task. For example, this is proscribed:
+```
+lock(m);
+while (!its_my_turn) {
+    unlock(m);
+    lock(m);
+}
+```
+
+Rationale: this can cause battery drain, and can even be a livelock (spinning forever), e.g. if the thread that might unblock this one has a lower priority.
+
+### Driver requirements
+
+At the time of writing, the driver interface specification does not consider multithreaded environments.
+
+We need to define clear policies so that driver implementers know what to expect. Here are two possible policies at two ends of the spectrum; what is desirable is probably somewhere in between.
+
+* Driver entry points may be called concurrently from multiple threads, even if they're using the same key, and even including destroying a key while an operation is in progress on it.
+* At most one driver entry point is active at any given time.
+
+A more reasonable policy could be:
+
+* By default, each driver only has at most one entry point active at any given time. In other words, each driver has its own exclusive lock.
+* Drivers have an optional `"thread_safe"` boolean property. If true, it allows concurrent calls to this driver.
+* Even with a thread-safe driver, the core never starts the destruction of a key while there are operations in progress on it, and never performs concurrent calls on the same multipart operation.
+
+### Long-term performance requirements
+
+In the short term, correctness is the important thing. We can start with a global lock.
+
+In the medium to long term, performing a slow or blocking operation (for example, a driver call, or an RSA decryption) should not block other threads, even if they're calling the same driver or using the same key object.
+
+We may want to go directly to a more sophisticated approach because when a system works with a global lock, it's typically hard to get rid of it to get more fine-grained concurrency.
+
+### Key destruction long-term requirements
+
+As noted above in [“Correctness out of the box”](#correctness-out-of-the-box), when a key is destroyed, it's ok if `psa_destroy_key` allows copies of the key to live until ongoing operations using the key return. In the long term, it would be good to guarantee that `psa_destroy_key` wipes all copies of the key material.
+
+#### Summary of guarantees when `psa_destroy_key` returns
+
+* The key identifier doesn't exist. Rationale: this is a functional requirement for persistent keys: the caller can immediately create a new key with the same identifier.
+* The resources from the key have been freed. Rationale: in a low-resource condition, this may be necessary for the caller to re-create a similar key, which should be possible.
+* The call must not block indefinitely, and in particular cannot wait for an event that is triggered by application code such as calling an abort function. Rationale: this may not strictly be a functional requirement, but it is an expectation `psa_destroy_key` does not block forever due to another thread, which could potentially be another process on a multi-process system.
+* In the long term, no copy of the key material exists. Rationale: this is a security requirement. We do not have this requirement yet, but we need to document this as a security weakness, and we would like to become compliant.
+
+## Resources to protect
+
+Analysis of the behavior of the PSA key store as of Mbed TLS 9202ba37b19d3ea25c8451fd8597fce69eaa6867.
+
+### Global variables
+
+* `psa_crypto_slot_management::global_data.key_slots[i]`: see [“Key slots”](#key-slots).
+
+* `psa_crypto_slot_management::global_data.key_slots_initialized`:
+    * `psa_initialize_key_slots`: modification.
+    * `psa_wipe_all_key_slots`: modification.
+    * `psa_get_empty_key_slot`: read.
+    * `psa_get_and_lock_key_slot`: read.
+
+* `psa_crypto::global_data.rng`: depends on the RNG implementation. See [“Random generator”](#random-generator).
+    * `psa_generate_random`: query.
+    * `mbedtls_psa_crypto_configure_entropy_sources` (only if `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` is enabled): setup. Only called from `psa_crypto_init` via `mbedtls_psa_random_init`, or from test code.
+    * `mbedtls_psa_crypto_free`: deinit.
+    * `psa_crypto_init`: seed (via `mbedtls_psa_random_seed`); setup via `mbedtls_psa_crypto_configure_entropy_sources.
+
+* `psa_crypto::global_data.{initialized,rng_state}`: these are bit-fields and cannot be modified independently so they must be protected by the same mutex. The following functions access these fields:
+    * `mbedtls_psa_crypto_configure_entropy_sources` [`rng_state`] (only if `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` is enabled): read. Only called from `psa_crypto_init` via `mbedtls_psa_random_init`, or from test code.
+    * `mbedtls_psa_crypto_free`: modification.
+    * `psa_crypto_init`: modification.
+    * Many functions via `GUARD_MODULE_INITIALIZED`: read.
+
+### Key slots
+
+#### Key slot array traversal
+
+“Occupied key slot” is determined by `psa_is_key_slot_occupied` based on `slot->attr.type`.
+
+The following functions traverse the key slot array:
+
+* `psa_get_and_lock_key_slot_in_memory`: reads `slot->attr.id`.
+* `psa_get_and_lock_key_slot_in_memory`: calls `psa_lock_key_slot` on one occupied slot.
+* `psa_get_empty_key_slot`: calls `psa_is_key_slot_occupied`.
+* `psa_get_empty_key_slot`: calls `psa_wipe_key_slot` and more modifications on one occupied slot with no active user.
+* `psa_get_empty_key_slot`: calls `psa_lock_key_slot` and more modification on one unoccupied slot.
+* `psa_wipe_all_key_slots`: writes to all slots.
+* `mbedtls_psa_get_stats`: reads from all slots.
+
+#### Key slot state
+
+The following functions modify a slot's usage state:
+
+* `psa_lock_key_slot`: writes to `slot->lock_count`.
+* `psa_unlock_key_slot`: writes to `slot->lock_count`.
+* `psa_wipe_key_slot`: writes to `slot->lock_count`.
+* `psa_destroy_key`: reads `slot->lock_count`, calls `psa_lock_key_slot`.
+* `psa_wipe_all_key_slots`: writes to all slots.
+* `psa_get_empty_key_slot`: writes to `slot->lock_count` and calls `psa_wipe_key_slot` and `psa_lock_key_slot` on one occupied slot with no active user; calls `psa_lock_key_slot` on one unoccupied slot.
+* `psa_close_key`: reads `slot->lock_count`; calls `psa_get_and_lock_key_slot_in_memory`, `psa_wipe_key_slot` and `psa_unlock_key_slot`.
+* `psa_purge_key`: reads `slot->lock_count`; calls `psa_get_and_lock_key_slot_in_memory`, `psa_wipe_key_slot` and `psa_unlock_key_slot`.
+
+**slot->attr access:**
+`psa_crypto_core.h`:
+* `psa_key_slot_set_flags` - writes to attr.flags
+* `psa_key_slot_set_bits_in_flags` - writes to attr.flags
+* `psa_key_slot_clear_bits` - writes to attr.flags
+* `psa_is_key_slot_occupied` - reads attr.type (but see “[Determining whether a key slot is occupied](#determining-whether-a-key-slot-is-occupied)”)
+* `psa_key_slot_get_flags` - reads attr.flags
+
+`psa_crypto_slot_management.c`:
+* `psa_get_and_lock_key_slot_in_memory` - reads attr.id
+* `psa_get_empty_key_slot` - reads attr.lifetime
+* `psa_load_persistent_key_into_slot` - passes attr pointer to psa_load_persistent_key
+* `psa_load_persistent_key` - reads attr.id and passes pointer to psa_parse_key_data_from_storage
+* `psa_parse_key_data_from_storage` - writes to many attributes
+* `psa_get_and_lock_key_slot` - writes to attr.id, attr.lifetime, and attr.policy.usage
+* `psa_purge_key` - reads attr.lifetime, calls psa_wipe_key_slot
+* `mbedtls_psa_get_stats` - reads attr.lifetime, attr.id
+
+`psa_crypto.c`:
+* `psa_get_and_lock_key_slot_with_policy` - reads attr.type, attr.policy.
+* `psa_get_and_lock_transparent_key_slot_with_policy` - reads attr.lifetime
+* `psa_destroy_key` - reads attr.lifetime, attr.id
+* `psa_get_key_attributes` - copies all publicly available attributes of a key
+* `psa_export_key` - copies attributes
+* `psa_export_public_key` - reads attr.type, copies attributes
+* `psa_start_key_creation` - writes to the whole attr structure 
+* `psa_validate_optional_attributes` - reads attr.type, attr.bits
+* `psa_import_key` - reads attr.bits
+* `psa_copy_key` - reads attr.bits, attr.type, attr.lifetime, attr.policy
+* `psa_mac_setup` - copies whole attr structure
+* `psa_mac_compute_internal` - copies whole attr structure
+* `psa_verify_internal` - copies whole attr structure
+* `psa_sign_internal` - copies whole attr structure, reads attr.type
+* `psa_assymmetric_encrypt` - reads attr.type
+* `psa_assymetric_decrypt` - reads attr.type
+* `psa_cipher_setup` - copies whole attr structure, reads attr.type
+* `psa_cipher_encrypt` - copies whole attr structure, reads attr.type
+* `psa_cipher_decrypt` - copies whole attr structure, reads attr.type
+* `psa_aead_encrypt` - copies whole attr structure
+* `psa_aead_decrypt` - copies whole attr structure
+* `psa_aead_setup` - copies whole attr structure
+* `psa_generate_derived_key_internal` - reads attr.type, writes to and reads from attr.bits, copies whole attr structure
+* `psa_key_derivation_input_key` - reads attr.type
+* `psa_key_agreement_raw_internal` - reads attr.type and attr.bits
+
+#### Determining whether a key slot is occupied
+
+`psa_is_key_slot_occupied` currently uses the `attr.type` field to determine whether a key slot is occupied. This works because we maintain the invariant that an occupied slot contains key material. With concurrency, it is desirable to allow a key slot to be reserved, but not yet contain key material or even metadata. When creating a key, determining the key type can be costly, for example when loading a persistent key from storage or (not yet implemented) when importing or unwrapping a key using an interface that determines the key type from the data that it parses. So we should not need to hold the global key store lock while the key type is undetermined.
+
+Instead, `psa_is_key_slot_occupied` should use the key identifier to decide whether a slot is occupied. The key identifier is always readily available: when allocating a slot for a persistent key, it's an input of the function that allocates the key slot; when allocating a slot for a volatile key, the identifier is calculated from the choice of slot.
+
+#### Key slot content
+
+Other than what is used to determine the [“key slot state”](#key-slot-state), the contents of a key slot are only accessed as follows:
+
+* Modification during key creation (between `psa_start_key_creation` and `psa_finish_key_creation` or `psa_fail_key_creation`).
+* Destruction in `psa_wipe_key_slot`.
+* Read in many functions, between calls to `psa_lock_key_slot` and `psa_unlock_key_slot`.
+
+**slot->key access:** 
+* `psa_allocate_buffer_to_slot` - allocates key.data, sets key.bytes;
+* `psa_copy_key_material_into_slot` - writes to key.data
+* `psa_remove_key_data_from_memory` - writes and reads to/from key data
+* `psa_get_key_attributes` - reads from key data
+* `psa_export_key` - passes key data to psa_driver_wrapper_export_key
+* `psa_export_public_key` - passes key data to psa_driver_wrapper_export_public_key
+* `psa_finish_key_creation` - passes key data to psa_save_persistent_key
+* `psa_validate_optional_attributes` - passes key data and bytes to mbedtls_psa_rsa_load_representation
+* `psa_import_key` - passes key data to psa_driver_wrapper_import_key
+* `psa_copy_key` - passes key data to psa_driver_wrapper_copy_key, psa_copy_key_material_into_slot
+* `psa_mac_setup` - passes key data to psa_driver_wrapper_mac_sign_setup, psa_driver_wrapper_mac_verify_setup
+* `psa_mac_compute_internal` - passes key data to psa_driver_wrapper_mac_compute
+* `psa_sign_internal` - passes key data to psa_driver_wrapper_sign_message, psa_driver_wrapper_sign_hash
+* `psa_verify_internal` - passes key data to psa_driver_wrapper_verify_message, psa_driver_wrapper_verify_hash
+* `psa_asymmetric_encrypt` - passes key data to mbedtls_psa_rsa_load_representation
+* `psa_asymmetric_decrypt` - passes key data to mbedtls_psa_rsa_load_representation
+* `psa_cipher_setup ` - passes key data to psa_driver_wrapper_cipher_encrypt_setup and psa_driver_wrapper_cipher_decrypt_setup
+* `psa_cipher_encrypt` - passes key data to psa_driver_wrapper_cipher_encrypt
+* `psa_cipher_decrypt` - passes key data to psa_driver_wrapper_cipher_decrypt
+* `psa_aead_encrypt` - passes key data to psa_driver_wrapper_aead_encrypt
+* `psa_aead_decrypt` - passes key data to psa_driver_wrapper_aead_decrypt
+* `psa_aead_setup` - passes key data to psa_driver_wrapper_aead_encrypt_setup and psa_driver_wrapper_aead_decrypt_setup
+* `psa_generate_derived_key_internal` - passes key data to psa_driver_wrapper_import_key
+* `psa_key_derivation_input_key` - passes key data to psa_key_derivation_input_internal
+* `psa_key_agreement_raw_internal` - passes key data to mbedtls_psa_ecp_load_representation
+* `psa_generate_key` - passes key data to psa_driver_wrapper_generate_key
+
+### Random generator
+
+The PSA RNG can be accessed both from various PSA functions, and from application code via `mbedtls_psa_get_random`.
+
+With the built-in RNG implementations using `mbedtls_ctr_drbg_context` or `mbedtls_hmac_drbg_context`, querying the RNG with `mbedtls_xxx_drbg_random()` is thread-safe (protected by a mutex inside the RNG implementation), but other operations (init, free, seed) are not.
+
+When `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` is enabled, thread safety depends on the implementation.
+
+### Driver resources
+
+Depends on the driver. The PSA driver interface specification does not discuss whether drivers must support concurrent calls.
+
+## Simple global lock strategy
+
+Have a single mutex protecting all accesses to the key store and other global variables. In practice, this means every PSA API function needs to take the lock on entry and release on exit, except for:
+
+* Hash function.
+* Accessors for key attributes and other local structures.
+
+Note that operation functions do need to take the lock, since they need to prevent the destruction of the key.
+
+Note that this does not protect access to the RNG via `mbedtls_psa_get_random`, which is guaranteed to be thread-safe when `MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG` is disabled.
+
+This approach is conceptually simple, but requires extra instrumentation to every function and has bad performance in a multithreaded environment since a slow operation in one thread blocks unrelated operations on other threads.
+
+## Global lock excluding slot content
+
+Have a single mutex protecting all accesses to the key store and other global variables, except that it's ok to access the content of a key slot without taking the lock if one of the following conditions holds:
+
+* The key slot is in a state that guarantees that the thread has exclusive access.
+* The key slot is in a state that guarantees that no other thread can modify the slot content, and the accessing thread is only reading the slot.
+
+Note that a thread must hold the global mutex when it reads or changes a slot's state.
+
+### Slot states
+
+For concurrency purposes, a slot can be in one of three states:
+
+* UNUSED: no thread is currently accessing the slot. It may be occupied by a volatile key or a cached key.
+* WRITING: a thread has exclusive access to the slot. This can only happen in specific circumstances as detailed below.
+* READING: any thread may read from the slot.
+
+A high-level view of state transitions:
+
+* `psa_get_empty_key_slot`: UNUSED → WRITING.
+* `psa_get_and_lock_key_slot_in_memory`: UNUSED or READING → READING. This function only accepts slots in the UNUSED or READING state. A slot with the correct id but in the WRITING state is considered free.
+* `psa_unlock_key_slot`: READING → UNUSED or READING.
+* `psa_finish_key_creation`: WRITING → READING.
+* `psa_fail_key_creation`: WRITING → UNUSED.
+* `psa_wipe_key_slot`: any → UNUSED. If the slot is READING or WRITING on entry, this function must wait until the writer or all readers have finished. (By the way, the WRITING state is possible if `mbedtls_psa_crypto_free` is called while a key creation is in progress.) See [“Destruction of a key in use”](#destruction of a key in use).
+
+The current `state->lock_count` corresponds to the difference between UNUSED and READING: a slot is in use iff its lock count is nonzero, so `lock_count == 0` corresponds to UNUSED and `lock_count != 0` corresponds to READING.
+
+There is currently no indication of when a slot is in the WRITING state. This only happens between a call to `psa_start_key_creation` and a call to one of `psa_finish_key_creation` or `psa_fail_key_creation`. This new state can be conveyed by a new boolean flag, or by setting `lock_count` to `~0`.
+
+### Destruction of a key in use
+
+Problem: a key slot is destroyed (by `psa_wipe_key_slot`) while it's in use (READING or WRITING).
+
+TODO: how do we ensure that? This needs something more sophisticated than mutexes (concurrency number >2)! Even a per-slot mutex isn't enough (we'd need a reader-writer lock).
+
+Solution: after some team discussion, we've decided to rely on a new threading abstraction which mimics C11 (i.e. `mbedtls_fff` where `fff` is the C11 function name, having the same parameters and return type, with default implementations for C11, pthreads and Windows). We'll likely use condition variables in addition to mutexes.
diff --git a/docs/proposed/psa-driver-developer-guide.md b/docs/proposed/psa-driver-developer-guide.md
index d004483..6b207c8 100644
--- a/docs/proposed/psa-driver-developer-guide.md
+++ b/docs/proposed/psa-driver-developer-guide.md
@@ -2,6 +2,7 @@
 ============================================
 
 **This is a specification of work in progress. The implementation is not yet merged into Mbed TLS.**
+For a description of the current state of drivers Mbed TLS, see our [PSA Cryptoprocessor driver development examples](../psa-driver-example-and-guide.html).
 
 This document describes how to write drivers of cryptoprocessors such as accelerators and secure elements for the PSA cryptography subsystem of Mbed TLS.
 
diff --git a/docs/proposed/psa-driver-integration-guide.md b/docs/proposed/psa-driver-integration-guide.md
index 3d12ec6..8b3b404 100644
--- a/docs/proposed/psa-driver-integration-guide.md
+++ b/docs/proposed/psa-driver-integration-guide.md
@@ -2,6 +2,7 @@
 ==================================================
 
 **This is a specification of work in progress. The implementation is not yet merged into Mbed TLS.**
+For a description of the current state of drivers Mbed TLS, see our [PSA Cryptoprocessor driver development examples](../psa-driver-example-and-guide.html).
 
 This document describes how to build Mbed TLS with additional cryptoprocessor drivers that follow the PSA cryptoprocessor driver interface.
 
diff --git a/docs/proposed/psa-driver-interface.md b/docs/proposed/psa-driver-interface.md
index 41f90c9..1aa55b3 100644
--- a/docs/proposed/psa-driver-interface.md
+++ b/docs/proposed/psa-driver-interface.md
@@ -5,6 +5,8 @@
 
 This specification is work in progress and should be considered to be in a beta stage. There is ongoing work to implement this interface in Mbed TLS, which is the reference implementation of the PSA Cryptography API. At this stage, Arm does not expect major changes, but minor changes are expected based on experience from the first implementation and on external feedback.
 
+For a practical guide, with a description of the current state of drivers Mbed TLS, see our [PSA Cryptoprocessor driver development examples](../psa-driver-example-and-guide.html).
+
 ## Introduction
 
 ### Purpose of the driver interface
diff --git a/docs/proposed/psa-driver-wrappers-codegen-migration-guide.md b/docs/proposed/psa-driver-wrappers-codegen-migration-guide.md
index 6144aad..67157e5 100644
--- a/docs/proposed/psa-driver-wrappers-codegen-migration-guide.md
+++ b/docs/proposed/psa-driver-wrappers-codegen-migration-guide.md
@@ -1,11 +1,11 @@
 Migrating to an auto generated psa_crypto_driver_wrappers.c file
 ================================================================
 
-**This is a specification of work in progress. The implementation is not yet merged into Mbed TLS.**
-
 This document describes how to migrate to the auto generated psa_crypto_driver_wrappers.c file.
 It is meant to give the library user migration guidelines while the Mbed TLS project tides over multiple minor revs of version 1.0, after which this will be merged into psa-driver-interface.md.
 
+For a practical guide with a description of the current state of drivers Mbed TLS, see our [PSA Cryptoprocessor driver development examples](../psa-driver-example-and-guide.html).
+
 ## Introduction
 
 The design of the Driver Wrappers code generation is based on the design proposal https://github.com/Mbed-TLS/mbedtls/pull/5067
diff --git a/docs/psa-driver-example-and-guide.md b/docs/psa-driver-example-and-guide.md
index ff66124..ae3c04c 100644
--- a/docs/psa-driver-example-and-guide.md
+++ b/docs/psa-driver-example-and-guide.md
@@ -29,8 +29,8 @@
 | Transparent Driver  | Opaque Driver       |
 |---------------------|---------------------|
 | `import_key`        | `import_key`        |
-| `export_key`        | `export_key`        |
 | `export_public_key` | `export_public_key` |
+|                     | `export_key`        |
 |                     | `copy_key`          |
 |                     | `get_builtin_key`   |
 
diff --git a/doxygen/mbedtls.doxyfile b/doxygen/mbedtls.doxyfile
index 8c7c7cc..7fd5dde 100644
--- a/doxygen/mbedtls.doxyfile
+++ b/doxygen/mbedtls.doxyfile
@@ -51,4 +51,5 @@
                          "MBEDTLS_CHECK_RETURN_TYPICAL="    \
                          "MBEDTLS_CHECK_RETURN_OPTIONAL="   \
                          "MBEDTLS_PRINTF_ATTRIBUTE(a,b)="   \
+                         "__DOXYGEN__"                      \
 
diff --git a/include/mbedtls/build_info.h b/include/mbedtls/build_info.h
index 5b8a40d..c0424da 100644
--- a/include/mbedtls/build_info.h
+++ b/include/mbedtls/build_info.h
@@ -59,6 +59,7 @@
 #define inline __inline
 #endif
 
+/* X.509, TLS and non-PSA crypto configuration */
 #if !defined(MBEDTLS_CONFIG_FILE)
 #include "mbedtls/mbedtls_config.h"
 #else
@@ -80,6 +81,18 @@
 #include MBEDTLS_USER_CONFIG_FILE
 #endif
 
+/* PSA crypto configuration */
+#if defined(MBEDTLS_PSA_CRYPTO_CONFIG)
+#if defined(MBEDTLS_PSA_CRYPTO_CONFIG_FILE)
+#include MBEDTLS_PSA_CRYPTO_CONFIG_FILE
+#else
+#include "psa/crypto_config.h"
+#endif
+#if defined(MBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE)
+#include MBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE
+#endif
+#endif /* defined(MBEDTLS_PSA_CRYPTO_CONFIG) */
+
 /* Auto-enable MBEDTLS_CTR_DRBG_USE_128_BIT_KEY if
  * MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH and MBEDTLS_CTR_DRBG_C defined
  * to ensure a 128-bit key size in CTR_DRBG.
@@ -208,6 +221,14 @@
 #define MBEDTLS_PK_PARSE_C
 #endif
 
+/* Helper symbol to state that the PK module has support for EC keys. This
+ * can either be provided through the legacy ECP solution or through the
+ * PSA friendly MBEDTLS_PK_USE_PSA_EC_DATA (see pk.h for its description). */
+#if defined(MBEDTLS_ECP_C) || \
+    (defined(MBEDTLS_USE_PSA_CRYPTO) && defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY))
+#define MBEDTLS_PK_HAVE_ECC_KEYS
+#endif /* MBEDTLS_PK_USE_PSA_EC_DATA || MBEDTLS_ECP_C */
+
 /* The following blocks make it easier to disable all of TLS,
  * or of TLS 1.2 or 1.3 or DTLS, without having to manually disable all
  * key exchanges, options and extensions related to them. */
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index 7a87971..ca267bd 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -412,10 +412,6 @@
 #error "MBEDTLS_MEMORY_DEBUG defined, but not all prerequisites"
 #endif
 
-#if defined(MBEDTLS_PADLOCK_C) && !defined(MBEDTLS_HAVE_ASM)
-#error "MBEDTLS_PADLOCK_C defined, but not all prerequisites"
-#endif
-
 #if defined(MBEDTLS_PEM_PARSE_C) && !defined(MBEDTLS_BASE64_C)
 #error "MBEDTLS_PEM_PARSE_C defined, but not all prerequisites"
 #endif
@@ -425,7 +421,7 @@
 #endif
 
 #if defined(MBEDTLS_PK_C) && \
-    !defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_ECP_LIGHT)
+    !defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_PK_HAVE_ECC_KEYS)
 #error "MBEDTLS_PK_C defined, but not all prerequisites"
 #endif
 
@@ -986,15 +982,15 @@
 #error "MBEDTLS_VERSION_FEATURES defined, but not all prerequisites"
 #endif
 
-#if defined(MBEDTLS_X509_USE_C) && ( !defined(MBEDTLS_BIGNUM_C) ||  \
-    !defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_PARSE_C) ||    \
+#if defined(MBEDTLS_X509_USE_C) && \
+    (!defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_PARSE_C) ||   \
     !defined(MBEDTLS_PK_PARSE_C) ||                                 \
     ( !defined(MBEDTLS_MD_C) && !defined(MBEDTLS_USE_PSA_CRYPTO) ) )
 #error "MBEDTLS_X509_USE_C defined, but not all prerequisites"
 #endif
 
-#if defined(MBEDTLS_X509_CREATE_C) && ( !defined(MBEDTLS_BIGNUM_C) ||  \
-    !defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_WRITE_C) ||       \
+#if defined(MBEDTLS_X509_CREATE_C) && \
+    (!defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_WRITE_C) ||      \
     !defined(MBEDTLS_PK_PARSE_C) ||                                    \
     ( !defined(MBEDTLS_MD_C) && !defined(MBEDTLS_USE_PSA_CRYPTO) ) )
 #error "MBEDTLS_X509_CREATE_C defined, but not all prerequisites"
@@ -1099,8 +1095,8 @@
 
 #if defined(MBEDTLS_PKCS7_C) && ( ( !defined(MBEDTLS_ASN1_PARSE_C) ) || \
     ( !defined(MBEDTLS_OID_C) ) || ( !defined(MBEDTLS_PK_PARSE_C) ) || \
-    ( !defined(MBEDTLS_X509_CRT_PARSE_C) ) ||\
-    ( !defined(MBEDTLS_X509_CRL_PARSE_C) ) || ( !defined(MBEDTLS_BIGNUM_C) ) || \
+    ( !defined(MBEDTLS_X509_CRT_PARSE_C) ) || \
+    ( !defined(MBEDTLS_X509_CRL_PARSE_C) ) || \
     ( !defined(MBEDTLS_MD_C) ) )
 #error  "MBEDTLS_PKCS7_C is defined, but not all prerequisites"
 #endif
diff --git a/include/mbedtls/config_psa.h b/include/mbedtls/config_psa.h
index e113865..a5d001b 100644
--- a/include/mbedtls/config_psa.h
+++ b/include/mbedtls/config_psa.h
@@ -30,24 +30,8 @@
 #ifndef MBEDTLS_CONFIG_PSA_H
 #define MBEDTLS_CONFIG_PSA_H
 
-#if defined(MBEDTLS_PSA_CRYPTO_CONFIG)
-#if defined(MBEDTLS_PSA_CRYPTO_CONFIG_FILE)
-#include MBEDTLS_PSA_CRYPTO_CONFIG_FILE
-#else
-#include "psa/crypto_config.h"
-#endif
-#endif /* defined(MBEDTLS_PSA_CRYPTO_CONFIG) */
-
-#if defined(MBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE)
-#include MBEDTLS_PSA_CRYPTO_USER_CONFIG_FILE
-#endif
-
 #include "psa/crypto_legacy.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 
 
 /****************************************************************/
@@ -113,6 +97,13 @@
 #define PSA_WANT_ALG_SHA_512 1
 #endif
 
+#if defined(MBEDTLS_SHA3_C)
+#define PSA_WANT_ALG_SHA3_224 1
+#define PSA_WANT_ALG_SHA3_256 1
+#define PSA_WANT_ALG_SHA3_384 1
+#define PSA_WANT_ALG_SHA3_512 1
+#endif
+
 
 /****************************************************************/
 /* Require built-in implementations based on PSA requirements */
@@ -270,9 +261,30 @@
 #define MBEDTLS_SHA512_C
 #endif
 
+#if defined(PSA_WANT_ALG_SHA3_224) && !defined(MBEDTLS_PSA_ACCEL_ALG_SHA3_224)
+#define MBEDTLS_PSA_BUILTIN_ALG_SHA3_224 1
+#define MBEDTLS_SHA3_C
+#endif
+
+#if defined(PSA_WANT_ALG_SHA3_256) && !defined(MBEDTLS_PSA_ACCEL_ALG_SHA3_256)
+#define MBEDTLS_PSA_BUILTIN_ALG_SHA3_256 1
+#define MBEDTLS_SHA3_C
+#endif
+
+#if defined(PSA_WANT_ALG_SHA3_384) && !defined(MBEDTLS_PSA_ACCEL_ALG_SHA3_384)
+#define MBEDTLS_PSA_BUILTIN_ALG_SHA3_384 1
+#define MBEDTLS_SHA3_C
+#endif
+
+#if defined(PSA_WANT_ALG_SHA3_512) && !defined(MBEDTLS_PSA_ACCEL_ALG_SHA3_512)
+#define MBEDTLS_PSA_BUILTIN_ALG_SHA3_512 1
+#define MBEDTLS_SHA3_C
+#endif
+
 #if defined(PSA_WANT_ALG_PBKDF2_HMAC)
 #if !defined(MBEDTLS_PSA_ACCEL_ALG_PBKDF2_HMAC)
 #define MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC 1
+#define PSA_HAVE_SOFT_PBKDF2_HMAC
 #if !defined(MBEDTLS_PSA_ACCEL_ALG_HMAC)
 #define MBEDTLS_PSA_BUILTIN_ALG_HMAC 1
 #endif /* !MBEDTLS_PSA_ACCEL_ALG_HMAC */
@@ -438,13 +450,21 @@
 #define PSA_HAVE_SOFT_BLOCK_AEAD 1
 #endif
 
+#if defined(PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128)
+#if !defined(MBEDTLS_PSA_ACCEL_ALG_PBKDF2_AES_CMAC_PRF_128)
+#define MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_AES_CMAC_PRF_128 1
+#define PSA_HAVE_SOFT_PBKDF2_CMAC
+#endif /* !MBEDTLS_PSA_ACCEL_ALG_PBKDF2_AES_CMAC_PRF_128 */
+#endif /* PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128 */
+
 #if defined(PSA_WANT_KEY_TYPE_AES)
 #if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_AES)
 #define PSA_HAVE_SOFT_KEY_TYPE_AES 1
 #endif /* !MBEDTLS_PSA_ACCEL_KEY_TYPE_AES */
 #if defined(PSA_HAVE_SOFT_KEY_TYPE_AES) || \
     defined(PSA_HAVE_SOFT_BLOCK_MODE) || \
-    defined(PSA_HAVE_SOFT_BLOCK_AEAD)
+    defined(PSA_HAVE_SOFT_BLOCK_AEAD) || \
+    defined(PSA_HAVE_SOFT_PBKDF2_CMAC)
 #define MBEDTLS_PSA_BUILTIN_KEY_TYPE_AES 1
 #define MBEDTLS_AES_C
 #endif /* PSA_HAVE_SOFT_KEY_TYPE_AES || PSA_HAVE_SOFT_BLOCK_MODE */
@@ -515,12 +535,18 @@
 
 #if defined(PSA_WANT_ALG_CMAC)
 #if !defined(MBEDTLS_PSA_ACCEL_ALG_CMAC) || \
-    defined(PSA_HAVE_SOFT_BLOCK_CIPHER)
+    defined(PSA_HAVE_SOFT_BLOCK_CIPHER) || \
+    defined(PSA_HAVE_SOFT_PBKDF2_CMAC)
 #define MBEDTLS_PSA_BUILTIN_ALG_CMAC 1
 #define MBEDTLS_CMAC_C
 #endif /* !MBEDTLS_PSA_ACCEL_ALG_CMAC */
 #endif /* PSA_WANT_ALG_CMAC */
 
+#if defined(PSA_HAVE_SOFT_PBKDF2_HMAC) || \
+    defined(PSA_HAVE_SOFT_PBKDF2_CMAC)
+#define PSA_HAVE_SOFT_PBKDF2 1
+#endif /* PSA_HAVE_SOFT_PBKDF2_HMAC || PSA_HAVE_SOFT_PBKDF2_CMAC */
+
 #if defined(PSA_WANT_ALG_CTR)
 #if !defined(MBEDTLS_PSA_ACCEL_ALG_CTR) || \
     defined(PSA_HAVE_SOFT_BLOCK_CIPHER)
@@ -873,6 +899,17 @@
 #define PSA_WANT_ALG_SHA_512 1
 #endif
 
+#if defined(MBEDTLS_SHA3_C)
+#define MBEDTLS_PSA_BUILTIN_ALG_SHA3_224 1
+#define MBEDTLS_PSA_BUILTIN_ALG_SHA3_256 1
+#define MBEDTLS_PSA_BUILTIN_ALG_SHA3_384 1
+#define MBEDTLS_PSA_BUILTIN_ALG_SHA3_512 1
+#define PSA_WANT_ALG_SHA3_224 1
+#define PSA_WANT_ALG_SHA3_256 1
+#define PSA_WANT_ALG_SHA3_384 1
+#define PSA_WANT_ALG_SHA3_512 1
+#endif
+
 #if defined(MBEDTLS_AES_C)
 #define PSA_WANT_KEY_TYPE_AES 1
 #define MBEDTLS_PSA_BUILTIN_KEY_TYPE_AES 1
@@ -1059,8 +1096,4 @@
 #define PSA_WANT_KEY_TYPE_PASSWORD_HASH 1
 #define PSA_WANT_KEY_TYPE_RAW_DATA 1
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* MBEDTLS_CONFIG_PSA_H */
diff --git a/include/mbedtls/constant_time.h b/include/mbedtls/constant_time.h
index 91a9e7f..ebecf35 100644
--- a/include/mbedtls/constant_time.h
+++ b/include/mbedtls/constant_time.h
@@ -23,20 +23,22 @@
 
 #include <stddef.h>
 
-
 /** Constant-time buffer comparison without branches.
  *
  * This is equivalent to the standard memcmp function, but is likely to be
- * compiled to code using bitwise operation rather than a branch.
+ * compiled to code using bitwise operations rather than a branch, such that
+ * the time taken is constant w.r.t. the data pointed to by \p a and \p b,
+ * and w.r.t. whether \p a and \p b are equal or not. It is not constant-time
+ * w.r.t. \p n .
  *
  * This function can be used to write constant-time code by replacing branches
  * with bit operations using masks.
  *
- * \param a     Pointer to the first buffer.
- * \param b     Pointer to the second buffer.
- * \param n     The number of bytes to compare in the buffer.
+ * \param a     Pointer to the first buffer, containing at least \p n bytes. May not be NULL.
+ * \param b     Pointer to the second buffer, containing at least \p n bytes. May not be NULL.
+ * \param n     The number of bytes to compare.
  *
- * \return      Zero if the content of the two buffer is the same,
+ * \return      Zero if the contents of the two buffers are the same,
  *              otherwise non-zero.
  */
 int mbedtls_ct_memcmp(const void *a,
diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h
index 0e678a3..a89d4d2 100644
--- a/include/mbedtls/ecp.h
+++ b/include/mbedtls/ecp.h
@@ -197,6 +197,27 @@
  * odd prime as mbedtls_ecp_mul() requires an odd number, and
  * mbedtls_ecdsa_sign() requires that it is prime for blinding purposes.
  *
+ * The default implementation only initializes \p A without setting it to the
+ * authentic value for curves with <code>A = -3</code>(SECP256R1, etc), in which
+ * case you need to load \p A by yourself when using domain parameters directly,
+ * for example:
+ * \code
+ * mbedtls_mpi_init(&A);
+ * mbedtls_ecp_group_init(&grp);
+ * CHECK_RETURN(mbedtls_ecp_group_load(&grp, grp_id));
+ * if (mbedtls_ecp_group_a_is_minus_3(&grp)) {
+ *     CHECK_RETURN(mbedtls_mpi_sub_int(&A, &grp.P, 3));
+ * } else {
+ *     CHECK_RETURN(mbedtls_mpi_copy(&A, &grp.A));
+ * }
+ *
+ * do_something_with_a(&A);
+ *
+ * cleanup:
+ * mbedtls_mpi_free(&A);
+ * mbedtls_ecp_group_free(&grp);
+ * \endcode
+ *
  * For Montgomery curves, we do not store \p A, but <code>(A + 2) / 4</code>,
  * which is the quantity used in the formulas. Additionally, \p nbits is
  * not the size of \p N but the required size for private keys.
@@ -223,8 +244,11 @@
 typedef struct mbedtls_ecp_group {
     mbedtls_ecp_group_id id;    /*!< An internal group identifier. */
     mbedtls_mpi P;              /*!< The prime modulus of the base field. */
-    mbedtls_mpi A;              /*!< For Short Weierstrass: \p A in the equation. For
-                                     Montgomery curves: <code>(A + 2) / 4</code>. */
+    mbedtls_mpi A;              /*!< For Short Weierstrass: \p A in the equation. Note that
+                                     \p A is not set to the authentic value in some cases.
+                                     Refer to detailed description of ::mbedtls_ecp_group if
+                                     using domain parameters in the structure.
+                                     For Montgomery curves: <code>(A + 2) / 4</code>. */
     mbedtls_mpi B;              /*!< For Short Weierstrass: \p B in the equation.
                                      For Montgomery curves: unused. */
     mbedtls_ecp_point G;        /*!< The generator of the subgroup used. */
@@ -992,6 +1016,26 @@
 
 #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
 /**
+ * \brief           This function checks if domain parameter A of the curve is
+ *                  \c -3.
+ *
+ * \note            This function is only defined for short Weierstrass curves.
+ *                  It may not be included in builds without any short
+ *                  Weierstrass curve.
+ *
+ * \param grp       The ECP group to use.
+ *                  This must be initialized and have group parameters
+ *                  set, for example through mbedtls_ecp_group_load().
+ *
+ * \return          \c 1 if <code>A = -3</code>.
+ * \return          \c 0 Otherwise.
+ */
+static inline int mbedtls_ecp_group_a_is_minus_3(const mbedtls_ecp_group *grp)
+{
+    return grp->A.MBEDTLS_PRIVATE(p) == NULL;
+}
+
+/**
  * \brief           This function performs multiplication and addition of two
  *                  points by integers: \p R = \p m * \p P + \p n * \p Q
  *
diff --git a/include/mbedtls/mbedtls_config.h b/include/mbedtls/mbedtls_config.h
index 7c15382..2a24a45 100644
--- a/include/mbedtls/mbedtls_config.h
+++ b/include/mbedtls/mbedtls_config.h
@@ -172,15 +172,47 @@
  * This allows different allocators (self-implemented or provided) to be
  * provided to the platform abstraction layer.
  *
- * Enabling MBEDTLS_PLATFORM_MEMORY without the
+ * Enabling #MBEDTLS_PLATFORM_MEMORY without the
  * MBEDTLS_PLATFORM_{FREE,CALLOC}_MACROs will provide
  * "mbedtls_platform_set_calloc_free()" allowing you to set an alternative calloc() and
  * free() function pointer at runtime.
  *
- * Enabling MBEDTLS_PLATFORM_MEMORY and specifying
+ * Enabling #MBEDTLS_PLATFORM_MEMORY and specifying
  * MBEDTLS_PLATFORM_{CALLOC,FREE}_MACROs will allow you to specify the
  * alternate function at compile time.
  *
+ * An overview of how the value of mbedtls_calloc is determined:
+ *
+ * - if !MBEDTLS_PLATFORM_MEMORY
+ *     - mbedtls_calloc = calloc
+ * - if MBEDTLS_PLATFORM_MEMORY
+ *     - if (MBEDTLS_PLATFORM_CALLOC_MACRO && MBEDTLS_PLATFORM_FREE_MACRO):
+ *         - mbedtls_calloc = MBEDTLS_PLATFORM_CALLOC_MACRO
+ *     - if !(MBEDTLS_PLATFORM_CALLOC_MACRO && MBEDTLS_PLATFORM_FREE_MACRO):
+ *         - Dynamic setup via mbedtls_platform_set_calloc_free is now possible with a default value MBEDTLS_PLATFORM_STD_CALLOC.
+ *         - How is MBEDTLS_PLATFORM_STD_CALLOC handled?
+ *         - if MBEDTLS_PLATFORM_NO_STD_FUNCTIONS:
+ *             - MBEDTLS_PLATFORM_STD_CALLOC is not set to anything;
+ *             - MBEDTLS_PLATFORM_STD_MEM_HDR can be included if present;
+ *         - if !MBEDTLS_PLATFORM_NO_STD_FUNCTIONS:
+ *             - if MBEDTLS_PLATFORM_STD_CALLOC is present:
+ *                 - User-defined MBEDTLS_PLATFORM_STD_CALLOC is respected;
+ *             - if !MBEDTLS_PLATFORM_STD_CALLOC:
+ *                 - MBEDTLS_PLATFORM_STD_CALLOC = calloc
+ *
+ *         - At this point the presence of MBEDTLS_PLATFORM_STD_CALLOC is checked.
+ *         - if !MBEDTLS_PLATFORM_STD_CALLOC
+ *             - MBEDTLS_PLATFORM_STD_CALLOC = uninitialized_calloc
+ *
+ *         - mbedtls_calloc = MBEDTLS_PLATFORM_STD_CALLOC.
+ *
+ * Defining MBEDTLS_PLATFORM_CALLOC_MACRO and #MBEDTLS_PLATFORM_STD_CALLOC at the same time is not possible.
+ * MBEDTLS_PLATFORM_CALLOC_MACRO and MBEDTLS_PLATFORM_FREE_MACRO must both be defined or undefined at the same time.
+ * #MBEDTLS_PLATFORM_STD_CALLOC and #MBEDTLS_PLATFORM_STD_FREE do not have to be defined at the same time, as, if they are used,
+ * dynamic setup of these functions is possible. See the tree above to see how are they handled in all cases.
+ * An uninitialized #MBEDTLS_PLATFORM_STD_CALLOC always fails, returning a null pointer.
+ * An uninitialized #MBEDTLS_PLATFORM_STD_FREE does not do anything.
+ *
  * Requires: MBEDTLS_PLATFORM_C
  *
  * Enable this layer to allow use of alternative memory allocators.
@@ -1998,8 +2030,15 @@
  * If the symbol #MBEDTLS_PSA_CRYPTO_CONFIG_FILE is defined, it specifies
  * an alternative header to include instead of include/psa/crypto_config.h.
  *
- * This feature is still experimental and is not ready for production since
- * it is not completed.
+ * \warning This option is experimental, in that the set of `PSA_WANT_XXX`
+ *          symbols is not completely finalized yet, and the configuration
+ *          tooling is not ideally adapted to having two separate configuration
+ *          files.
+ *          Future minor releases of Mbed TLS may make minor changes to those
+ *          symbols, but we will endeavor to provide a transition path.
+ *          Nonetheless, this option is considered mature enough to use in
+ *          production, as long as you accept that you may need to make
+ *          minor changes to psa/crypto_config.h when upgrading Mbed TLS.
  */
 //#define MBEDTLS_PSA_CRYPTO_CONFIG
 
@@ -3701,8 +3740,29 @@
 
 /* Platform options */
 //#define MBEDTLS_PLATFORM_STD_MEM_HDR   <stdlib.h> /**< Header to include if MBEDTLS_PLATFORM_NO_STD_FUNCTIONS is defined. Don't define if no header is needed. */
-//#define MBEDTLS_PLATFORM_STD_CALLOC        calloc /**< Default allocator to use, can be undefined */
-//#define MBEDTLS_PLATFORM_STD_FREE            free /**< Default free to use, can be undefined */
+
+/** \def MBEDTLS_PLATFORM_STD_CALLOC
+ *
+ * Default allocator to use, can be undefined.
+ * It must initialize the allocated buffer memory to zeroes.
+ * The size of the buffer is the product of the two parameters.
+ * The calloc function returns either a null pointer or a pointer to the allocated space.
+ * If the product is 0, the function may either return NULL or a valid pointer to an array of size 0 which is a valid input to the deallocation function.
+ * An uninitialized #MBEDTLS_PLATFORM_STD_CALLOC always fails, returning a null pointer.
+ * See the description of #MBEDTLS_PLATFORM_MEMORY for more details.
+ * The corresponding deallocation function is #MBEDTLS_PLATFORM_STD_FREE.
+ */
+//#define MBEDTLS_PLATFORM_STD_CALLOC        calloc
+
+/** \def MBEDTLS_PLATFORM_STD_FREE
+ *
+ * Default free to use, can be undefined.
+ * NULL is a valid parameter, and the function must do nothing.
+ * A non-null parameter will always be a pointer previously returned by #MBEDTLS_PLATFORM_STD_CALLOC and not yet freed.
+ * An uninitialized #MBEDTLS_PLATFORM_STD_FREE does not do anything.
+ * See the description of #MBEDTLS_PLATFORM_MEMORY for more details (same principles as for MBEDTLS_PLATFORM_STD_CALLOC apply).
+ */
+//#define MBEDTLS_PLATFORM_STD_FREE            free
 //#define MBEDTLS_PLATFORM_STD_SETBUF      setbuf /**< Default setbuf to use, can be undefined */
 //#define MBEDTLS_PLATFORM_STD_EXIT            exit /**< Default exit to use, can be undefined */
 //#define MBEDTLS_PLATFORM_STD_TIME            time /**< Default time to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */
@@ -3716,10 +3776,10 @@
 //#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE  mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */
 //#define MBEDTLS_PLATFORM_STD_NV_SEED_FILE  "seedfile" /**< Seed file to read/write with default implementation */
 
-/* To Use Function Macros MBEDTLS_PLATFORM_C must be enabled */
+/* To use the following function macros, MBEDTLS_PLATFORM_C must be enabled. */
 /* MBEDTLS_PLATFORM_XXX_MACRO and MBEDTLS_PLATFORM_XXX_ALT cannot both be defined */
-//#define MBEDTLS_PLATFORM_CALLOC_MACRO        calloc /**< Default allocator macro to use, can be undefined */
-//#define MBEDTLS_PLATFORM_FREE_MACRO            free /**< Default free macro to use, can be undefined */
+//#define MBEDTLS_PLATFORM_CALLOC_MACRO        calloc /**< Default allocator macro to use, can be undefined. See MBEDTLS_PLATFORM_STD_CALLOC for requirements. */
+//#define MBEDTLS_PLATFORM_FREE_MACRO            free /**< Default free macro to use, can be undefined. See MBEDTLS_PLATFORM_STD_FREE for requirements. */
 //#define MBEDTLS_PLATFORM_EXIT_MACRO            exit /**< Default exit macro to use, can be undefined */
 //#define MBEDTLS_PLATFORM_SETBUF_MACRO      setbuf /**< Default setbuf macro to use, can be undefined */
 //#define MBEDTLS_PLATFORM_TIME_MACRO            time /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */
@@ -4009,4 +4069,18 @@
  */
 //#define MBEDTLS_ECP_WITH_MPI_UINT
 
+/*
+ * Disable plain C implementation for AES.
+ *
+ * When the plain C implementation is enabled, and an implementation using a
+ * special CPU feature (such as MBEDTLS_AESCE_C) is also enabled, runtime
+ * detection will be used to select between them.
+ *
+ * If only one implementation is present, runtime detection will not be used.
+ * This configuration will crash at runtime if running on a CPU without the
+ * necessary features. It will not build unless at least one of MBEDTLS_AESCE_C
+ * and/or MBEDTLS_AESNI_C is enabled & present in the build.
+ */
+//#define MBEDTLS_AES_USE_HARDWARE_ONLY
+
 /** \} name SECTION: Module configuration options */
diff --git a/include/mbedtls/md.h b/include/mbedtls/md.h
index dde95c5..c9a7858 100644
--- a/include/mbedtls/md.h
+++ b/include/mbedtls/md.h
@@ -85,6 +85,26 @@
 #define MBEDTLS_MD_RIPEMD160_VIA_PSA
 #define MBEDTLS_MD_SOME_PSA
 #endif
+#if defined(MBEDTLS_PSA_ACCEL_ALG_SHA3_224)
+#define MBEDTLS_MD_CAN_SHA3_224
+#define MBEDTLS_MD_SHA3_224_VIA_PSA
+#define MBEDTLS_MD_SOME_PSA
+#endif
+#if defined(MBEDTLS_PSA_ACCEL_ALG_SHA3_256)
+#define MBEDTLS_MD_CAN_SHA3_256
+#define MBEDTLS_MD_SHA3_256_VIA_PSA
+#define MBEDTLS_MD_SOME_PSA
+#endif
+#if defined(MBEDTLS_PSA_ACCEL_ALG_SHA3_384)
+#define MBEDTLS_MD_CAN_SHA3_384
+#define MBEDTLS_MD_SHA3_384_VIA_PSA
+#define MBEDTLS_MD_SOME_PSA
+#endif
+#if defined(MBEDTLS_PSA_ACCEL_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_C */
 
 /* Built-in implementations */
@@ -117,6 +137,7 @@
 #define MBEDTLS_MD_CAN_SHA3_256
 #define MBEDTLS_MD_CAN_SHA3_384
 #define MBEDTLS_MD_CAN_SHA3_512
+#define MBEDTLS_MD_SOME_LEGACY
 #endif
 #if defined(MBEDTLS_RIPEMD160_C)
 #define MBEDTLS_MD_CAN_RIPEMD160
diff --git a/include/mbedtls/net_sockets.h b/include/mbedtls/net_sockets.h
index 14316fb..1096d66 100644
--- a/include/mbedtls/net_sockets.h
+++ b/include/mbedtls/net_sockets.h
@@ -286,6 +286,10 @@
  * \brief          Closes down the connection and free associated data
  *
  * \param ctx      The context to close
+ *
+ * \note           This function frees and clears data associated with the
+ *                 context but does not free the memory pointed to by \p ctx.
+ *                 This memory is the responsibility of the caller.
  */
 void mbedtls_net_close(mbedtls_net_context *ctx);
 
@@ -293,6 +297,10 @@
  * \brief          Gracefully shutdown the connection and free associated data
  *
  * \param ctx      The context to free
+ *
+ * \note           This function frees and clears data associated with the
+ *                 context but does not free the memory pointed to by \p ctx.
+ *                 This memory is the responsibility of the caller.
  */
 void mbedtls_net_free(mbedtls_net_context *ctx);
 
diff --git a/include/mbedtls/oid.h b/include/mbedtls/oid.h
index e333ba1..9545072 100644
--- a/include/mbedtls/oid.h
+++ b/include/mbedtls/oid.h
@@ -270,6 +270,15 @@
 
 #define MBEDTLS_OID_DIGEST_ALG_RIPEMD160        MBEDTLS_OID_TELETRUST "\x03\x02\x01" /**< id-ripemd160 OBJECT IDENTIFIER :: { iso(1) identified-organization(3) teletrust(36) algorithm(3) hashAlgorithm(2) ripemd160(1) } */
 
+#define MBEDTLS_OID_DIGEST_ALG_SHA3_224         MBEDTLS_OID_NIST_ALG "\x02\x07" /**< id-sha3-224 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistAlgorithms(4) hashalgs(2) sha3-224(7) } */
+
+#define MBEDTLS_OID_DIGEST_ALG_SHA3_256         MBEDTLS_OID_NIST_ALG "\x02\x08" /**< id-sha3-256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistAlgorithms(4) hashalgs(2) sha3-256(8) } */
+
+#define MBEDTLS_OID_DIGEST_ALG_SHA3_384         MBEDTLS_OID_NIST_ALG "\x02\x09" /**< id-sha3-384 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistAlgorithms(4) hashalgs(2) sha3-384(9) } */
+
+#define MBEDTLS_OID_DIGEST_ALG_SHA3_512         MBEDTLS_OID_NIST_ALG "\x02\x0a" /**< id-sha3-512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistAlgorithms(4) hashalgs(2) sha3-512(10) } */
+
+
 #define MBEDTLS_OID_HMAC_SHA1                   MBEDTLS_OID_RSA_COMPANY "\x02\x07" /**< id-hmacWithSHA1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 7 } */
 
 #define MBEDTLS_OID_HMAC_SHA224                 MBEDTLS_OID_RSA_COMPANY "\x02\x08" /**< id-hmacWithSHA224 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 8 } */
@@ -280,6 +289,16 @@
 
 #define MBEDTLS_OID_HMAC_SHA512                 MBEDTLS_OID_RSA_COMPANY "\x02\x0B" /**< id-hmacWithSHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 11 } */
 
+#define MBEDTLS_OID_HMAC_SHA3_224               MBEDTLS_OID_NIST_ALG "\x02\x0d" /**< id-hmacWithSHA3-512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistAlgorithms(4) hashalgs(2) hmacWithSHA3-224(13) } */
+
+#define MBEDTLS_OID_HMAC_SHA3_256               MBEDTLS_OID_NIST_ALG "\x02\x0e" /**< id-hmacWithSHA3-512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistAlgorithms(4) hashalgs(2) hmacWithSHA3-256(14) } */
+
+#define MBEDTLS_OID_HMAC_SHA3_384               MBEDTLS_OID_NIST_ALG "\x02\x0f" /**< id-hmacWithSHA3-512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistAlgorithms(4) hashalgs(2) hmacWithSHA3-384(15) } */
+
+#define MBEDTLS_OID_HMAC_SHA3_512               MBEDTLS_OID_NIST_ALG "\x02\x10" /**< id-hmacWithSHA3-512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistAlgorithms(4) hashalgs(2) hmacWithSHA3-512(16) } */
+
+#define MBEDTLS_OID_HMAC_RIPEMD160              MBEDTLS_OID_INTERNET "\x05\x05\x08\x01\x04" /**< id-hmacWithSHA1 OBJECT IDENTIFIER ::= {iso(1) iso-identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) ipsec(8) isakmpOakley(1) hmacRIPEMD160(4)} */
+
 /*
  * Encryption algorithms
  */
diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h
index f56c942..41e980d 100644
--- a/include/mbedtls/pk.h
+++ b/include/mbedtls/pk.h
@@ -173,7 +173,7 @@
 
 /* Internal helper to define which fields in the pk_context structure below
  * should be used for EC keys: legacy ecp_keypair or the raw (PSA friendly)
- * format. It should be noticed that this only affect how data is stored, not
+ * format. It should be noticed that this only affects how data is stored, not
  * which functions are used for various operations. The overall picture looks
  * like this:
  * - if USE_PSA is not defined and ECP_C is then use ecp_keypair data structure
@@ -200,6 +200,28 @@
 #define MBEDTLS_PK_HAVE_ECC_KEYS
 #endif /* MBEDTLS_PK_USE_PSA_EC_DATA || MBEDTLS_ECP_C */
 
+/* Internal helper to define which fields in the pk_context structure below
+ * should be used for EC keys: legacy ecp_keypair or the raw (PSA friendly)
+ * format. It should be noted that this only affect how data is stored, not
+ * which functions are used for various operations. The overall picture looks
+ * like this:
+ * - if USE_PSA is not defined and ECP_C is then use ecp_keypair data structure
+ *   and legacy functions
+ * - if USE_PSA is defined and
+ *     - if ECP_C then use ecp_keypair structure, convert data to a PSA friendly
+ *       format and use PSA functions
+ *     - if !ECP_C then use new raw data and PSA functions directly.
+ *
+ * The main reason for the "intermediate" (USE_PSA + ECP_C) above is that as long
+ * as ECP_C is defined mbedtls_pk_ec() gives the user read/write access to the
+ * ecp_keypair structure inside the pk_context so they can modify it using
+ * ECP functions which are not under the PK module's control.
+ */
+#if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY) && \
+    !defined(MBEDTLS_ECP_C)
+#define MBEDTLS_PK_USE_PSA_EC_DATA
+#endif /* MBEDTLS_USE_PSA_CRYPTO && !MBEDTLS_ECP_C */
+
 /**
  * \brief           Types for interfacing with the debug module
  */
diff --git a/include/mbedtls/platform.h b/include/mbedtls/platform.h
index 768c756..3fc1fd0 100644
--- a/include/mbedtls/platform.h
+++ b/include/mbedtls/platform.h
@@ -130,11 +130,22 @@
 #endif
 #endif /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */
 
+/* Enable certain documented defines only when generating doxygen to avoid
+ * an "unrecognized define" error. */
+#if defined(__DOXYGEN__) && !defined(MBEDTLS_PLATFORM_STD_CALLOC)
+#define MBEDTLS_PLATFORM_STD_CALLOC
+#endif
+
+#if defined(__DOXYGEN__) && !defined(MBEDTLS_PLATFORM_STD_FREE)
+#define MBEDTLS_PLATFORM_STD_FREE
+#endif
 
 /** \} name SECTION: Module settings */
 
 /*
  * The function pointers for calloc and free.
+ * Please see MBEDTLS_PLATFORM_STD_CALLOC and MBEDTLS_PLATFORM_STD_FREE
+ * in mbedtls_config.h for more information about behaviour and requirements.
  */
 #if defined(MBEDTLS_PLATFORM_MEMORY)
 #if defined(MBEDTLS_PLATFORM_FREE_MACRO) && \
diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h
index 6e1f5b6..a9267c7 100644
--- a/include/mbedtls/x509.h
+++ b/include/mbedtls/x509.h
@@ -503,7 +503,8 @@
                              mbedtls_asn1_named_data *first);
 int mbedtls_x509_write_sig(unsigned char **p, unsigned char *start,
                            const char *oid, size_t oid_len,
-                           unsigned char *sig, size_t size);
+                           unsigned char *sig, size_t size,
+                           mbedtls_pk_type_t pk_alg);
 int mbedtls_x509_get_ns_cert_type(unsigned char **p,
                                   const unsigned char *end,
                                   unsigned char *ns_cert_type);
@@ -525,6 +526,9 @@
 int mbedtls_x509_info_key_usage(char **buf, size_t *size,
                                 unsigned int key_usage);
 
+int mbedtls_x509_write_set_san_common(mbedtls_asn1_named_data **extensions,
+                                      const mbedtls_x509_san_list *san_list);
+
 /**
  * \brief          This function parses a CN string as an IP address.
  *
diff --git a/include/psa/crypto_builtin_key_derivation.h b/include/psa/crypto_builtin_key_derivation.h
index cd6d51d..8a2143a 100644
--- a/include/psa/crypto_builtin_key_derivation.h
+++ b/include/psa/crypto_builtin_key_derivation.h
@@ -105,7 +105,7 @@
 } psa_tls12_prf_key_derivation_t;
 #endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) ||
         * MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */
-#if defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC)
+#if defined(PSA_HAVE_SOFT_PBKDF2)
 typedef enum {
     PSA_PBKDF2_STATE_INIT,             /* no input provided */
     PSA_PBKDF2_STATE_INPUT_COST_SET,   /* input cost has been set */
@@ -125,6 +125,6 @@
     uint8_t MBEDTLS_PRIVATE(bytes_used);
     uint32_t MBEDTLS_PRIVATE(block_number);
 } psa_pbkdf2_key_derivation_t;
-#endif /* MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC */
+#endif /* PSA_HAVE_SOFT_PBKDF2 */
 
 #endif /* PSA_CRYPTO_BUILTIN_KEY_DERIVATION_H */
diff --git a/include/psa/crypto_builtin_primitives.h b/include/psa/crypto_builtin_primitives.h
index c78c8d0..d3e0692 100644
--- a/include/psa/crypto_builtin_primitives.h
+++ b/include/psa/crypto_builtin_primitives.h
@@ -45,6 +45,7 @@
 #include "mbedtls/sha1.h"
 #include "mbedtls/sha256.h"
 #include "mbedtls/sha512.h"
+#include "mbedtls/sha3.h"
 
 #if defined(MBEDTLS_PSA_BUILTIN_ALG_MD5) || \
     defined(MBEDTLS_PSA_BUILTIN_ALG_RIPEMD160) || \
@@ -52,7 +53,11 @@
     defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_224) || \
     defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_256) || \
     defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_384) || \
-    defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_512)
+    defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_512) || \
+    defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224) || \
+    defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256) || \
+    defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384) || \
+    defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512)
 #define MBEDTLS_PSA_BUILTIN_HASH
 #endif
 
@@ -77,6 +82,12 @@
         defined(MBEDTLS_PSA_BUILTIN_ALG_SHA_384)
         mbedtls_sha512_context sha512;
 #endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224) || \
+        defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256) || \
+        defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384) || \
+        defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512)
+        mbedtls_sha3_context sha3;
+#endif
     } MBEDTLS_PRIVATE(ctx);
 } mbedtls_psa_hash_operation_t;
 
diff --git a/include/psa/crypto_config.h b/include/psa/crypto_config.h
index 9da28de..4e7a71e 100644
--- a/include/psa/crypto_config.h
+++ b/include/psa/crypto_config.h
@@ -76,6 +76,7 @@
 #define PSA_WANT_ALG_MD5                        1
 #define PSA_WANT_ALG_OFB                        1
 #define PSA_WANT_ALG_PBKDF2_HMAC                1
+#define PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128    1
 #define PSA_WANT_ALG_RIPEMD160                  1
 #define PSA_WANT_ALG_RSA_OAEP                   1
 #define PSA_WANT_ALG_RSA_PKCS1V15_CRYPT         1
@@ -86,12 +87,17 @@
 #define PSA_WANT_ALG_SHA_256                    1
 #define PSA_WANT_ALG_SHA_384                    1
 #define PSA_WANT_ALG_SHA_512                    1
+#define PSA_WANT_ALG_SHA3_224                   1
+#define PSA_WANT_ALG_SHA3_256                   1
+#define PSA_WANT_ALG_SHA3_384                   1
+#define PSA_WANT_ALG_SHA3_512                   1
 #define PSA_WANT_ALG_STREAM_CIPHER              1
 #define PSA_WANT_ALG_TLS12_PRF                  1
 #define PSA_WANT_ALG_TLS12_PSK_TO_MS            1
 #define PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS       1
 
-/* Note: when adding support, also adjust include/mbedtls/config_psa.h */
+/* XTS is not yet supported via the PSA API in Mbed TLS.
+ * Note: when adding support, also adjust include/mbedtls/config_psa.h */
 //#define PSA_WANT_ALG_XTS                        1
 
 #define PSA_WANT_ECC_BRAINPOOL_P_R1_256         1
diff --git a/include/psa/crypto_driver_contexts_key_derivation.h b/include/psa/crypto_driver_contexts_key_derivation.h
index 5b4e474..3fb29ff 100644
--- a/include/psa/crypto_driver_contexts_key_derivation.h
+++ b/include/psa/crypto_driver_contexts_key_derivation.h
@@ -55,7 +55,7 @@
 #if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS)
     psa_tls12_ecjpake_to_pms_t MBEDTLS_PRIVATE(tls12_ecjpake_to_pms);
 #endif
-#if defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC)
+#if defined(PSA_HAVE_SOFT_PBKDF2)
     psa_pbkdf2_key_derivation_t MBEDTLS_PRIVATE(pbkdf2);
 #endif
 } psa_driver_key_derivation_context_t;
diff --git a/include/psa/crypto_sizes.h b/include/psa/crypto_sizes.h
index 55c0b1f..98ffbce 100644
--- a/include/psa/crypto_sizes.h
+++ b/include/psa/crypto_sizes.h
@@ -125,28 +125,43 @@
  * This macro expands to a compile-time constant integer. This value
  * is the maximum size of a hash in bytes.
  */
-/* Note: for HMAC-SHA-3, the block size is 144 bytes for HMAC-SHA3-226,
+/* Note: for HMAC-SHA-3, the block size is 144 bytes for HMAC-SHA3-224,
  * 136 bytes for HMAC-SHA3-256, 104 bytes for SHA3-384, 72 bytes for
  * HMAC-SHA3-512. */
 /* Note: PSA_HASH_MAX_SIZE should be kept in sync with MBEDTLS_MD_MAX_SIZE,
  * see the note on MBEDTLS_MD_MAX_SIZE for details. */
-#if defined(PSA_WANT_ALG_SHA_512)
-#define PSA_HASH_MAX_SIZE 64
+#if defined(PSA_WANT_ALG_SHA3_224)
+#define PSA_HMAC_MAX_HASH_BLOCK_SIZE 144
+#elif defined(PSA_WANT_ALG_SHA3_256)
+#define PSA_HMAC_MAX_HASH_BLOCK_SIZE 136
+#elif defined(PSA_WANT_ALG_SHA_512)
 #define PSA_HMAC_MAX_HASH_BLOCK_SIZE 128
 #elif defined(PSA_WANT_ALG_SHA_384)
-#define PSA_HASH_MAX_SIZE 48
 #define PSA_HMAC_MAX_HASH_BLOCK_SIZE 128
+#elif defined(PSA_WANT_ALG_SHA3_384)
+#define PSA_HMAC_MAX_HASH_BLOCK_SIZE 104
+#elif defined(PSA_WANT_ALG_SHA3_512)
+#define PSA_HMAC_MAX_HASH_BLOCK_SIZE 72
 #elif defined(PSA_WANT_ALG_SHA_256)
-#define PSA_HASH_MAX_SIZE 32
 #define PSA_HMAC_MAX_HASH_BLOCK_SIZE 64
 #elif defined(PSA_WANT_ALG_SHA_224)
-#define PSA_HASH_MAX_SIZE 28
 #define PSA_HMAC_MAX_HASH_BLOCK_SIZE 64
 #else /* SHA-1 or smaller */
-#define PSA_HASH_MAX_SIZE 20
 #define PSA_HMAC_MAX_HASH_BLOCK_SIZE 64
 #endif
 
+#if defined(PSA_WANT_ALG_SHA_512) || defined(PSA_WANT_ALG_SHA3_512)
+#define PSA_HASH_MAX_SIZE 64
+#elif defined(PSA_WANT_ALG_SHA_384) || defined(PSA_WANT_ALG_SHA3_384)
+#define PSA_HASH_MAX_SIZE 48
+#elif defined(PSA_WANT_ALG_SHA_256) || defined(PSA_WANT_ALG_SHA3_256)
+#define PSA_HASH_MAX_SIZE 32
+#elif defined(PSA_WANT_ALG_SHA_224) || defined(PSA_WANT_ALG_SHA3_224)
+#define PSA_HASH_MAX_SIZE 28
+#else /* SHA-1 or smaller */
+#define PSA_HASH_MAX_SIZE 20
+#endif
+
 /** \def PSA_MAC_MAX_SIZE
  *
  * Maximum size of a MAC.
diff --git a/include/psa/crypto_values.h b/include/psa/crypto_values.h
index 580e3ae..241b7c8 100644
--- a/include/psa/crypto_values.h
+++ b/include/psa/crypto_values.h
@@ -2115,6 +2115,10 @@
  */
 #define PSA_ALG_PBKDF2_AES_CMAC_PRF_128         ((psa_algorithm_t) 0x08800200)
 
+#define PSA_ALG_IS_PBKDF2(kdf_alg)                                      \
+    (PSA_ALG_IS_PBKDF2_HMAC(kdf_alg) || \
+     ((kdf_alg) == PSA_ALG_PBKDF2_AES_CMAC_PRF_128))
+
 #define PSA_ALG_KEY_DERIVATION_MASK             ((psa_algorithm_t) 0xfe00ffff)
 #define PSA_ALG_KEY_AGREEMENT_MASK              ((psa_algorithm_t) 0xffff0000)
 
diff --git a/library/.gitignore b/library/.gitignore
index b4dc918..5a29a43 100644
--- a/library/.gitignore
+++ b/library/.gitignore
@@ -2,8 +2,9 @@
 *.sln
 *.vcxproj
 
-# Automatically generated files
+###START_GENERATED_FILES###
 /error.c
 /version_features.c
 /ssl_debug_helpers_generated.c
 /psa_crypto_driver_wrappers.c
+###END_GENERATED_FILES###
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index 03e48df..351edd0 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -99,6 +99,7 @@
     x509_crl.c
     x509_crt.c
     x509_csr.c
+    x509write.c
     x509write_crt.c
     x509write_csr.c
 )
diff --git a/library/Makefile b/library/Makefile
index 194a847..c383c32 100644
--- a/library/Makefile
+++ b/library/Makefile
@@ -167,6 +167,7 @@
 	   x509_crl.o \
 	   x509_crt.o \
 	   x509_csr.o \
+   	   x509write.o \
 	   x509write_crt.o \
 	   x509write_csr.o \
 	   pkcs7.o \
diff --git a/library/aes.c b/library/aes.c
index 6d718f4..47a5e3e 100644
--- a/library/aes.c
+++ b/library/aes.c
@@ -19,7 +19,7 @@
 /*
  *  The AES block cipher was designed by Vincent Rijmen and Joan Daemen.
  *
- *  http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf
+ *  https://csrc.nist.gov/csrc/media/projects/cryptographic-standards-and-guidelines/documents/aes-development/rijndael-ammended.pdf
  *  http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
  */
 
@@ -33,6 +33,36 @@
 #include "mbedtls/platform.h"
 #include "mbedtls/platform_util.h"
 #include "mbedtls/error.h"
+
+#if defined(__aarch64__)
+#if !defined(MBEDTLS_AESCE_C) && defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
+#error "MBEDTLS_AES_USE_HARDWARE_ONLY defined, but not all prerequisites"
+#endif
+#endif
+
+#if defined(__amd64__) || defined(__x86_64__) || \
+    ((defined(_M_X64) || defined(_M_AMD64)) && !defined(_M_ARM64EC))
+#if !defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
+#error "MBEDTLS_AES_USE_HARDWARE_ONLY defined, but not all prerequisites"
+#endif
+#endif
+
+#if defined(__i386__) || defined(_M_IX86)
+#if defined(MBEDTLS_AES_USE_HARDWARE_ONLY) && !defined(MBEDTLS_AESNI_C)
+#error "MBEDTLS_AES_USE_HARDWARE_ONLY defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PADLOCK_C)
+#if !defined(MBEDTLS_HAVE_ASM)
+#error "MBEDTLS_PADLOCK_C defined, but not all prerequisites"
+#endif
+#if defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
+#error "MBEDTLS_AES_USE_HARDWARE_ONLY cannot be defined when " \
+    "MBEDTLS_PADLOCK_C is set"
+#endif
+#endif
+#endif
+
 #if defined(MBEDTLS_PADLOCK_C)
 #include "padlock.h"
 #endif
@@ -47,7 +77,7 @@
 
 #if !defined(MBEDTLS_AES_ALT)
 
-#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86)
+#if defined(MBEDTLS_VIA_PADLOCK_HAVE_CODE)
 static int aes_padlock_ace = -1;
 #endif
 
@@ -542,7 +572,7 @@
  * Note that the offset is in units of elements of buf, i.e. 32-bit words,
  * i.e. an offset of 1 means 4 bytes and so on.
  */
-#if (defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86)) ||        \
+#if (defined(MBEDTLS_VIA_PADLOCK_HAVE_CODE)) ||        \
     (defined(MBEDTLS_AESNI_C) && MBEDTLS_AESNI_HAVE_CODE == 2)
 #define MAY_NEED_TO_ALIGN
 #endif
@@ -554,7 +584,7 @@
 #if defined(MAY_NEED_TO_ALIGN)
     int align_16_bytes = 0;
 
-#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86)
+#if defined(MBEDTLS_VIA_PADLOCK_HAVE_CODE)
     if (aes_padlock_ace == -1) {
         aes_padlock_ace = mbedtls_padlock_has_support(MBEDTLS_PADLOCK_ACE);
     }
@@ -595,7 +625,6 @@
 int mbedtls_aes_setkey_enc(mbedtls_aes_context *ctx, const unsigned char *key,
                            unsigned int keybits)
 {
-    unsigned int i;
     uint32_t *RK;
 
     switch (keybits) {
@@ -624,19 +653,20 @@
 #endif
 
 #if defined(MBEDTLS_AESCE_C) && defined(MBEDTLS_HAVE_ARM64)
-    if (mbedtls_aesce_has_support()) {
+    if (MBEDTLS_AESCE_HAS_SUPPORT()) {
         return mbedtls_aesce_setkey_enc((unsigned char *) RK, key, keybits);
     }
 #endif
 
-    for (i = 0; i < (keybits >> 5); i++) {
+#if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
+    for (unsigned int i = 0; i < (keybits >> 5); i++) {
         RK[i] = MBEDTLS_GET_UINT32_LE(key, i << 2);
     }
 
     switch (ctx->nr) {
         case 10:
 
-            for (i = 0; i < 10; i++, RK += 4) {
+            for (unsigned int i = 0; i < 10; i++, RK += 4) {
                 RK[4]  = RK[0] ^ RCON[i] ^
                          ((uint32_t) FSb[MBEDTLS_BYTE_1(RK[3])]) ^
                          ((uint32_t) FSb[MBEDTLS_BYTE_2(RK[3])] <<  8) ^
@@ -652,7 +682,7 @@
 #if !defined(MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH)
         case 12:
 
-            for (i = 0; i < 8; i++, RK += 6) {
+            for (unsigned int i = 0; i < 8; i++, RK += 6) {
                 RK[6]  = RK[0] ^ RCON[i] ^
                          ((uint32_t) FSb[MBEDTLS_BYTE_1(RK[5])]) ^
                          ((uint32_t) FSb[MBEDTLS_BYTE_2(RK[5])] <<  8) ^
@@ -669,7 +699,7 @@
 
         case 14:
 
-            for (i = 0; i < 7; i++, RK += 8) {
+            for (unsigned int i = 0; i < 7; i++, RK += 8) {
                 RK[8]  = RK[0] ^ RCON[i] ^
                          ((uint32_t) FSb[MBEDTLS_BYTE_1(RK[7])]) ^
                          ((uint32_t) FSb[MBEDTLS_BYTE_2(RK[7])] <<  8) ^
@@ -695,6 +725,7 @@
     }
 
     return 0;
+#endif /* !MBEDTLS_AES_USE_HARDWARE_ONLY */
 }
 #endif /* !MBEDTLS_AES_SETKEY_ENC_ALT */
 
@@ -705,10 +736,13 @@
 int mbedtls_aes_setkey_dec(mbedtls_aes_context *ctx, const unsigned char *key,
                            unsigned int keybits)
 {
-    int i, j, ret;
+#if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
+    uint32_t *SK;
+#endif
+    int ret;
     mbedtls_aes_context cty;
     uint32_t *RK;
-    uint32_t *SK;
+
 
     mbedtls_aes_init(&cty);
 
@@ -731,7 +765,7 @@
 #endif
 
 #if defined(MBEDTLS_AESCE_C) && defined(MBEDTLS_HAVE_ARM64)
-    if (mbedtls_aesce_has_support()) {
+    if (MBEDTLS_AESCE_HAS_SUPPORT()) {
         mbedtls_aesce_inverse_key(
             (unsigned char *) RK,
             (const unsigned char *) (cty.buf + cty.rk_offset),
@@ -740,15 +774,16 @@
     }
 #endif
 
+#if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
     SK = cty.buf + cty.rk_offset + cty.nr * 4;
 
     *RK++ = *SK++;
     *RK++ = *SK++;
     *RK++ = *SK++;
     *RK++ = *SK++;
-
-    for (i = ctx->nr - 1, SK -= 8; i > 0; i--, SK -= 8) {
-        for (j = 0; j < 4; j++, SK++) {
+    SK -= 8;
+    for (int i = ctx->nr - 1; i > 0; i--, SK -= 8) {
+        for (int j = 0; j < 4; j++, SK++) {
             *RK++ = AES_RT0(FSb[MBEDTLS_BYTE_0(*SK)]) ^
                     AES_RT1(FSb[MBEDTLS_BYTE_1(*SK)]) ^
                     AES_RT2(FSb[MBEDTLS_BYTE_2(*SK)]) ^
@@ -760,7 +795,7 @@
     *RK++ = *SK++;
     *RK++ = *SK++;
     *RK++ = *SK++;
-
+#endif /* !MBEDTLS_AES_USE_HARDWARE_ONLY */
 exit:
     mbedtls_aes_free(&cty);
 
@@ -1057,22 +1092,25 @@
 #endif
 
 #if defined(MBEDTLS_AESCE_C) && defined(MBEDTLS_HAVE_ARM64)
-    if (mbedtls_aesce_has_support()) {
+    if (MBEDTLS_AESCE_HAS_SUPPORT()) {
         return mbedtls_aesce_crypt_ecb(ctx, mode, input, output);
     }
 #endif
 
-#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86)
+#if defined(MBEDTLS_VIA_PADLOCK_HAVE_CODE)
     if (aes_padlock_ace > 0) {
         return mbedtls_padlock_xcryptecb(ctx, mode, input, output);
     }
 #endif
 
+#if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
     if (mode == MBEDTLS_AES_ENCRYPT) {
         return mbedtls_internal_aes_encrypt(ctx, input, output);
     } else {
         return mbedtls_internal_aes_decrypt(ctx, input, output);
     }
+#endif
+
 }
 
 #if defined(MBEDTLS_CIPHER_MODE_CBC)
@@ -1094,11 +1132,16 @@
         return MBEDTLS_ERR_AES_BAD_INPUT_DATA;
     }
 
+    /* Nothing to do if length is zero. */
+    if (length == 0) {
+        return 0;
+    }
+
     if (length % 16) {
         return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH;
     }
 
-#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86)
+#if defined(MBEDTLS_VIA_PADLOCK_HAVE_CODE)
     if (aes_padlock_ace > 0) {
         if (mbedtls_padlock_xcryptcbc(ctx, mode, length, iv, input, output) == 0) {
             return 0;
@@ -1850,29 +1893,33 @@
 #if defined(MBEDTLS_AES_ALT)
         mbedtls_printf("  AES note: alternative implementation.\n");
 #else /* MBEDTLS_AES_ALT */
-#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86)
-        if (mbedtls_padlock_has_support(MBEDTLS_PADLOCK_ACE)) {
-            mbedtls_printf("  AES note: using VIA Padlock.\n");
-        } else
-#endif
 #if defined(MBEDTLS_AESNI_HAVE_CODE)
 #if MBEDTLS_AESNI_HAVE_CODE == 1
         mbedtls_printf("  AES note: AESNI code present (assembly implementation).\n");
 #elif MBEDTLS_AESNI_HAVE_CODE == 2
         mbedtls_printf("  AES note: AESNI code present (intrinsics implementation).\n");
 #else
-#error Unrecognised value for MBEDTLS_AESNI_HAVE_CODE
+#error "Unrecognised value for MBEDTLS_AESNI_HAVE_CODE"
 #endif
         if (mbedtls_aesni_has_support(MBEDTLS_AESNI_AES)) {
             mbedtls_printf("  AES note: using AESNI.\n");
         } else
 #endif
+#if defined(MBEDTLS_VIA_PADLOCK_HAVE_CODE)
+        if (mbedtls_padlock_has_support(MBEDTLS_PADLOCK_ACE)) {
+            mbedtls_printf("  AES note: using VIA Padlock.\n");
+        } else
+#endif
 #if defined(MBEDTLS_AESCE_C) && defined(MBEDTLS_HAVE_ARM64)
-        if (mbedtls_aesce_has_support()) {
+        if (MBEDTLS_AESCE_HAS_SUPPORT()) {
             mbedtls_printf("  AES note: using AESCE.\n");
         } else
 #endif
-        mbedtls_printf("  AES note: built-in implementation.\n");
+        {
+#if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
+            mbedtls_printf("  AES note: built-in implementation.\n");
+#endif
+        }
 #endif /* MBEDTLS_AES_ALT */
     }
 
diff --git a/library/aesce.c b/library/aesce.c
index ed3cca1..6f75a67 100644
--- a/library/aesce.c
+++ b/library/aesce.c
@@ -94,25 +94,39 @@
 #endif /* !(__ARM_FEATURE_CRYPTO || __ARM_FEATURE_AES) ||
           MBEDTLS_ENABLE_ARM_CRYPTO_EXTENSIONS_COMPILER_FLAG */
 
-#if defined(__linux__)
+#if defined(__linux__) && !defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
+
 #include <asm/hwcap.h>
 #include <sys/auxv.h>
-#endif
 
+signed char mbedtls_aesce_has_support_result = -1;
+
+#if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
 /*
  * AES instruction support detection routine
  */
-int mbedtls_aesce_has_support(void)
+int mbedtls_aesce_has_support_impl(void)
 {
-#if defined(__linux__)
-    unsigned long auxval = getauxval(AT_HWCAP);
-    return (auxval & (HWCAP_ASIMD | HWCAP_AES)) ==
-           (HWCAP_ASIMD | HWCAP_AES);
-#else
-    /* Assume AES instructions are supported. */
-    return 1;
-#endif
+    /* To avoid many calls to getauxval, cache the result. This is
+     * thread-safe, because we store the result in a char so cannot
+     * be vulnerable to non-atomic updates.
+     * It is possible that we could end up setting result more than
+     * once, but that is harmless.
+     */
+    if (mbedtls_aesce_has_support_result == -1) {
+        unsigned long auxval = getauxval(AT_HWCAP);
+        if ((auxval & (HWCAP_ASIMD | HWCAP_AES)) ==
+            (HWCAP_ASIMD | HWCAP_AES)) {
+            mbedtls_aesce_has_support_result = 1;
+        } else {
+            mbedtls_aesce_has_support_result = 0;
+        }
+    }
+    return mbedtls_aesce_has_support_result;
 }
+#endif
+
+#endif /* defined(__linux__) && !defined(MBEDTLS_AES_USE_HARDWARE_ONLY) */
 
 /* Single round of AESCE encryption */
 #define AESCE_ENCRYPT_ROUND                   \
diff --git a/library/aesce.h b/library/aesce.h
index b12bf76..735c8cf 100644
--- a/library/aesce.h
+++ b/library/aesce.h
@@ -42,12 +42,29 @@
 extern "C" {
 #endif
 
+#if defined(__linux__) && !defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
+
+extern signed char mbedtls_aesce_has_support_result;
+
 /**
  * \brief          Internal function to detect the crypto extension in CPUs.
  *
  * \return         1 if CPU has support for the feature, 0 otherwise
  */
-int mbedtls_aesce_has_support(void);
+int mbedtls_aesce_has_support_impl(void);
+
+#define MBEDTLS_AESCE_HAS_SUPPORT() (mbedtls_aesce_has_support_result == -1 ? \
+                                     mbedtls_aesce_has_support_impl() : \
+                                     mbedtls_aesce_has_support_result)
+
+#else /* defined(__linux__) && !defined(MBEDTLS_AES_USE_HARDWARE_ONLY) */
+
+/* If we are not on Linux, we can't detect support so assume that it's supported.
+ * Similarly, assume support if MBEDTLS_AES_USE_HARDWARE_ONLY is set.
+ */
+#define MBEDTLS_AESCE_HAS_SUPPORT() 1
+
+#endif /* defined(__linux__) && !defined(MBEDTLS_AES_USE_HARDWARE_ONLY) */
 
 /**
  * \brief          Internal AES-ECB block encryption and decryption
diff --git a/library/aesni.c b/library/aesni.c
index 3e3dccb..5f25a82 100644
--- a/library/aesni.c
+++ b/library/aesni.c
@@ -41,6 +41,7 @@
 #include <immintrin.h>
 #endif
 
+#if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
 /*
  * AES-NI support detection routine
  */
@@ -70,6 +71,7 @@
 
     return (c & what) != 0;
 }
+#endif /* !MBEDTLS_AES_USE_HARDWARE_ONLY */
 
 #if MBEDTLS_AESNI_HAVE_CODE == 2
 
diff --git a/library/aesni.h b/library/aesni.h
index 82947e4..332a0f0 100644
--- a/library/aesni.h
+++ b/library/aesni.h
@@ -35,13 +35,20 @@
 /* Can we do AESNI with inline assembly?
  * (Only implemented with gas syntax, only for 64-bit.)
  */
-#if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && \
-    (defined(__amd64__) || defined(__x86_64__))   &&  \
-    !defined(MBEDTLS_HAVE_X86_64)
+#if !defined(MBEDTLS_HAVE_X86_64) && \
+    (defined(__amd64__) || defined(__x86_64__) || \
+    defined(_M_X64) || defined(_M_AMD64)) && \
+    !defined(_M_ARM64EC)
 #define MBEDTLS_HAVE_X86_64
 #endif
 
-#if defined(MBEDTLS_AESNI_C)
+#if !defined(MBEDTLS_HAVE_X86) && \
+    (defined(__i386__) || defined(_M_IX86))
+#define MBEDTLS_HAVE_X86
+#endif
+
+#if defined(MBEDTLS_AESNI_C) && \
+    (defined(MBEDTLS_HAVE_X86_64) || defined(MBEDTLS_HAVE_X86))
 
 /* Can we do AESNI with intrinsics?
  * (Only implemented with certain compilers, only for certain targets.)
@@ -67,8 +74,13 @@
  * In the long run, we will likely remove the assembly implementation. */
 #if defined(MBEDTLS_AESNI_HAVE_INTRINSICS)
 #define MBEDTLS_AESNI_HAVE_CODE 2 // via intrinsics
-#elif defined(MBEDTLS_HAVE_X86_64)
+#elif defined(MBEDTLS_HAVE_ASM) && \
+    defined(__GNUC__) && defined(MBEDTLS_HAVE_X86_64)
 #define MBEDTLS_AESNI_HAVE_CODE 1 // via assembly
+#elif defined(__GNUC__)
+#   error "Must use `-mpclmul -msse2 -maes` for MBEDTLS_AESNI_C"
+#else
+#error "MBEDTLS_AESNI_C defined, but neither intrinsics nor assembly available"
 #endif
 
 #if defined(MBEDTLS_AESNI_HAVE_CODE)
@@ -88,7 +100,11 @@
  *
  * \return         1 if CPU has support for the feature, 0 otherwise
  */
+#if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
 int mbedtls_aesni_has_support(unsigned int what);
+#else
+#define mbedtls_aesni_has_support(what) 1
+#endif
 
 /**
  * \brief          Internal AES-NI AES-ECB block encryption and decryption
diff --git a/library/base64.c b/library/base64.c
index 3eb9e7c..fa22e53 100644
--- a/library/base64.c
+++ b/library/base64.c
@@ -24,6 +24,7 @@
 #if defined(MBEDTLS_BASE64_C)
 
 #include "mbedtls/base64.h"
+#include "base64_internal.h"
 #include "constant_time_internal.h"
 
 #include <stdint.h>
@@ -33,6 +34,39 @@
 #include "mbedtls/platform.h"
 #endif /* MBEDTLS_SELF_TEST */
 
+MBEDTLS_STATIC_TESTABLE
+unsigned char mbedtls_ct_base64_enc_char(unsigned char value)
+{
+    unsigned char digit = 0;
+    /* For each range of values, if value is in that range, mask digit with
+     * the corresponding value. Since value can only be in a single range,
+     * only at most one masking will change digit. */
+    digit |= mbedtls_ct_uchar_in_range_if(0, 25, value, 'A' + value);
+    digit |= mbedtls_ct_uchar_in_range_if(26, 51, value, 'a' + value - 26);
+    digit |= mbedtls_ct_uchar_in_range_if(52, 61, value, '0' + value - 52);
+    digit |= mbedtls_ct_uchar_in_range_if(62, 62, value, '+');
+    digit |= mbedtls_ct_uchar_in_range_if(63, 63, value, '/');
+    return digit;
+}
+
+MBEDTLS_STATIC_TESTABLE
+signed char mbedtls_ct_base64_dec_value(unsigned char c)
+{
+    unsigned char val = 0;
+    /* For each range of digits, if c is in that range, mask val with
+     * the corresponding value. Since c can only be in a single range,
+     * only at most one masking will change val. Set val to one plus
+     * the desired value so that it stays 0 if c is in none of the ranges. */
+    val |= mbedtls_ct_uchar_in_range_if('A', 'Z', c, c - 'A' +  0 + 1);
+    val |= mbedtls_ct_uchar_in_range_if('a', 'z', c, c - 'a' + 26 + 1);
+    val |= mbedtls_ct_uchar_in_range_if('0', '9', c, c - '0' + 52 + 1);
+    val |= mbedtls_ct_uchar_in_range_if('+', '+', c, c - '+' + 62 + 1);
+    val |= mbedtls_ct_uchar_in_range_if('/', '/', c, c - '/' + 63 + 1);
+    /* At this point, val is 0 if c is an invalid digit and v+1 if c is
+     * a digit with the value v. */
+    return val - 1;
+}
+
 /*
  * Encode a buffer into base64 format
  */
diff --git a/library/base64_internal.h b/library/base64_internal.h
new file mode 100644
index 0000000..f9f56d7
--- /dev/null
+++ b/library/base64_internal.h
@@ -0,0 +1,57 @@
+/**
+ * \file base64_internal.h
+ *
+ * \brief RFC 1521 base64 encoding/decoding: interfaces for invasive testing
+ */
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  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.
+ */
+
+#ifndef MBEDTLS_BASE64_INTERNAL
+#define MBEDTLS_BASE64_INTERNAL
+
+#include "common.h"
+
+#if defined(MBEDTLS_TEST_HOOKS)
+
+/** Given a value in the range 0..63, return the corresponding Base64 digit.
+ *
+ * The implementation assumes that letters are consecutive (e.g. ASCII
+ * but not EBCDIC).
+ *
+ * \param value     A value in the range 0..63.
+ *
+ * \return          A base64 digit converted from \p value.
+ */
+unsigned char mbedtls_ct_base64_enc_char(unsigned char value);
+
+/** Given a Base64 digit, return its value.
+ *
+ * If c is not a Base64 digit ('A'..'Z', 'a'..'z', '0'..'9', '+' or '/'),
+ * return -1.
+ *
+ * The implementation assumes that letters are consecutive (e.g. ASCII
+ * but not EBCDIC).
+ *
+ * \param c     A base64 digit.
+ *
+ * \return      The value of the base64 digit \p c.
+ */
+signed char mbedtls_ct_base64_dec_value(unsigned char c);
+
+#endif /* MBEDTLS_TEST_HOOKS */
+
+#endif /* MBEDTLS_BASE64_INTERNAL */
diff --git a/library/bignum.c b/library/bignum.c
index f2a8641..0a0022c 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -54,6 +54,132 @@
 #define MPI_VALIDATE(cond)                                           \
     MBEDTLS_INTERNAL_VALIDATE(cond)
 
+/*
+ * Compare signed values in constant time
+ */
+int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X,
+                          const mbedtls_mpi *Y,
+                          unsigned *ret)
+{
+    mbedtls_ct_condition_t different_sign, X_is_negative, Y_is_negative, result;
+
+    MPI_VALIDATE_RET(X != NULL);
+    MPI_VALIDATE_RET(Y != NULL);
+    MPI_VALIDATE_RET(ret != NULL);
+
+    if (X->n != Y->n) {
+        return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
+    }
+
+    /*
+     * Set sign_N to 1 if N >= 0, 0 if N < 0.
+     * We know that N->s == 1 if N >= 0 and N->s == -1 if N < 0.
+     */
+    X_is_negative = mbedtls_ct_bool((X->s & 2) >> 1);
+    Y_is_negative = mbedtls_ct_bool((Y->s & 2) >> 1);
+
+    /*
+     * If the signs are different, then the positive operand is the bigger.
+     * That is if X is negative (X_is_negative == 1), then X < Y is true and it
+     * is false if X is positive (X_is_negative == 0).
+     */
+    different_sign = mbedtls_ct_bool_xor(X_is_negative, Y_is_negative); // non-zero if different sign
+    result = mbedtls_ct_bool_and(different_sign, X_is_negative);
+
+    /*
+     * Assuming signs are the same, compare X and Y. We switch the comparison
+     * order if they are negative so that we get the right result, regardles of
+     * sign.
+     */
+
+    /* This array is used to conditionally swap the pointers in const time */
+    void * const p[2] = { X->p, Y->p };
+    size_t i = mbedtls_ct_size_if_else_0(X_is_negative, 1);
+    mbedtls_ct_condition_t lt = mbedtls_mpi_core_lt_ct(p[i], p[i ^ 1], X->n);
+
+    /*
+     * Store in result iff the signs are the same (i.e., iff different_sign == false). If
+     * the signs differ, result has already been set, so we don't change it.
+     */
+    result = mbedtls_ct_bool_or(result,
+                                mbedtls_ct_bool_and(mbedtls_ct_bool_not(different_sign), lt));
+
+    *ret = mbedtls_ct_uint_if_else_0(result, 1);
+
+    return 0;
+}
+
+/*
+ * Conditionally assign X = Y, without leaking information
+ * about whether the assignment was made or not.
+ * (Leaking information about the respective sizes of X and Y is ok however.)
+ */
+#if defined(_MSC_VER) && defined(_M_ARM64) && (_MSC_FULL_VER < 193131103)
+/*
+ * MSVC miscompiles this function if it's inlined prior to Visual Studio 2022 version 17.1. See:
+ * https://developercommunity.visualstudio.com/t/c-compiler-miscompiles-part-of-mbedtls-library-on/1646989
+ */
+__declspec(noinline)
+#endif
+int mbedtls_mpi_safe_cond_assign(mbedtls_mpi *X,
+                                 const mbedtls_mpi *Y,
+                                 unsigned char assign)
+{
+    int ret = 0;
+    MPI_VALIDATE_RET(X != NULL);
+    MPI_VALIDATE_RET(Y != NULL);
+
+    MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
+
+    mbedtls_ct_condition_t do_assign = mbedtls_ct_bool(assign);
+
+    X->s = (int) mbedtls_ct_uint_if(do_assign, Y->s, X->s);
+
+    mbedtls_mpi_core_cond_assign(X->p, Y->p, Y->n, do_assign);
+
+    mbedtls_ct_condition_t do_not_assign = mbedtls_ct_bool_not(do_assign);
+    for (size_t i = Y->n; i < X->n; i++) {
+        X->p[i] = mbedtls_ct_mpi_uint_if_else_0(do_not_assign, X->p[i]);
+    }
+
+cleanup:
+    return ret;
+}
+
+/*
+ * Conditionally swap X and Y, without leaking information
+ * about whether the swap was made or not.
+ * Here it is not ok to simply swap the pointers, which would lead to
+ * different memory access patterns when X and Y are used afterwards.
+ */
+int mbedtls_mpi_safe_cond_swap(mbedtls_mpi *X,
+                               mbedtls_mpi *Y,
+                               unsigned char swap)
+{
+    int ret = 0;
+    int s;
+    MPI_VALIDATE_RET(X != NULL);
+    MPI_VALIDATE_RET(Y != NULL);
+
+    if (X == Y) {
+        return 0;
+    }
+
+    mbedtls_ct_condition_t do_swap = mbedtls_ct_bool(swap);
+
+    MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
+    MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Y, X->n));
+
+    s = X->s;
+    X->s = (int) mbedtls_ct_uint_if(do_swap, Y->s, X->s);
+    Y->s = (int) mbedtls_ct_uint_if(do_swap, s, Y->s);
+
+    mbedtls_mpi_core_cond_swap(X->p, Y->p, X->n, do_swap);
+
+cleanup:
+    return ret;
+}
+
 /* Implementation that should never be optimized out by the compiler */
 #define mbedtls_mpi_zeroize_and_free(v, n) mbedtls_zeroize_and_free(v, ciL * (n))
 
@@ -258,6 +384,10 @@
     return (mbedtls_mpi_uint) 0 - (mbedtls_mpi_uint) z;
 }
 
+/* Convert x to a sign, i.e. to 1, if x is positive, or -1, if x is negative.
+ * This looks awkward but generates smaller code than (x < 0 ? -1 : 1) */
+#define TO_SIGN(x) ((((mbedtls_mpi_uint) x) >> (biL - 1)) * -2 + 1)
+
 /*
  * Set value from integer
  */
@@ -270,7 +400,7 @@
     memset(X->p, 0, X->n * ciL);
 
     X->p[0] = mpi_sint_abs(z);
-    X->s    = (z < 0) ? -1 : 1;
+    X->s    = TO_SIGN(z);
 
 cleanup:
 
@@ -326,16 +456,35 @@
  */
 size_t mbedtls_mpi_lsb(const mbedtls_mpi *X)
 {
-    size_t i, j, count = 0;
+    size_t i;
     MBEDTLS_INTERNAL_VALIDATE_RET(X != NULL, 0);
 
+#if defined(__has_builtin)
+#if (MBEDTLS_MPI_UINT_MAX == UINT_MAX) && __has_builtin(__builtin_ctz)
+    #define mbedtls_mpi_uint_ctz __builtin_ctz
+#elif (MBEDTLS_MPI_UINT_MAX == ULONG_MAX) && __has_builtin(__builtin_ctzl)
+    #define mbedtls_mpi_uint_ctz __builtin_ctzl
+#elif (MBEDTLS_MPI_UINT_MAX == ULLONG_MAX) && __has_builtin(__builtin_ctzll)
+    #define mbedtls_mpi_uint_ctz __builtin_ctzll
+#endif
+#endif
+
+#if defined(mbedtls_mpi_uint_ctz)
     for (i = 0; i < X->n; i++) {
-        for (j = 0; j < biL; j++, count++) {
+        if (X->p[i] != 0) {
+            return i * biL + mbedtls_mpi_uint_ctz(X->p[i]);
+        }
+    }
+#else
+    size_t count = 0;
+    for (i = 0; i < X->n; i++) {
+        for (size_t j = 0; j < biL; j++, count++) {
             if (((X->p[i] >> j) & 1) != 0) {
                 return count;
             }
         }
     }
+#endif
 
     return 0;
 }
@@ -796,9 +945,8 @@
         }
     }
 
-    if (i == 0 && j == 0) {
-        return 0;
-    }
+    /* If i == j == 0, i.e. abs(X) == abs(Y),
+     * we end up returning 0 at the end of the function. */
 
     if (i > j) {
         return 1;
@@ -880,7 +1028,7 @@
     MPI_VALIDATE_RET(X != NULL);
 
     *p  = mpi_sint_abs(z);
-    Y.s = (z < 0) ? -1 : 1;
+    Y.s = TO_SIGN(z);
     Y.n = 1;
     Y.p = p;
 
@@ -1068,7 +1216,7 @@
     MPI_VALIDATE_RET(A != NULL);
 
     p[0] = mpi_sint_abs(b);
-    B.s = (b < 0) ? -1 : 1;
+    B.s = TO_SIGN(b);
     B.n = 1;
     B.p = p;
 
@@ -1086,7 +1234,7 @@
     MPI_VALIDATE_RET(A != NULL);
 
     p[0] = mpi_sint_abs(b);
-    B.s = (b < 0) ? -1 : 1;
+    B.s = TO_SIGN(b);
     B.n = 1;
     B.p = p;
 
@@ -1436,7 +1584,7 @@
     MPI_VALIDATE_RET(A != NULL);
 
     p[0] = mpi_sint_abs(b);
-    B.s = (b < 0) ? -1 : 1;
+    B.s = TO_SIGN(b);
     B.n = 1;
     B.p = p;
 
@@ -1602,10 +1750,8 @@
 
     for (size_t i = 0; i < T_size; i++) {
         MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign(R, &T[i],
-                                                     (unsigned char) mbedtls_ct_size_bool_eq(i,
-                                                                                             idx)));
+                                                     (unsigned char) mbedtls_ct_uint_eq(i, idx)));
     }
-
 cleanup:
     return ret;
 }
@@ -1680,8 +1826,9 @@
      * and squarings. Firstly, when multiplying by an element of the window
      * W[i], we do a constant-trace table lookup to obfuscate i. This leaves
      * squarings as having a different memory access patterns from other
-     * multiplications. So secondly, we put the accumulator X in the table as
-     * well, and also do a constant-trace table lookup to multiply by X.
+     * multiplications. So secondly, we put the accumulator in the table as
+     * well, and also do a constant-trace table lookup to multiply by the
+     * accumulator which is W[x_index].
      *
      * This way, all multiplications take the form of a lookup-and-multiply.
      * The number of lookup-and-multiply operations inside each iteration of
@@ -1694,19 +1841,16 @@
      * observe both memory accesses and branches. However, branch prediction
      * exploitation typically requires many traces of execution over the same
      * data, which is defeated by randomized blinding.
-     *
-     * To achieve this, we make a copy of X and we use the table entry in each
-     * calculation from this point on.
      */
     const size_t x_index = 0;
     mbedtls_mpi_init(&W[x_index]);
-    mbedtls_mpi_copy(&W[x_index], X);
 
     j = N->n + 1;
-    /* All W[i] and X must have at least N->n limbs for the mpi_montmul()
-     * and mpi_montred() calls later. Here we ensure that W[1] and X are
-     * large enough, and later we'll grow other W[i] to the same length.
-     * They must not be shrunk midway through this function!
+    /* All W[i] including the accumulator must have at least N->n limbs for
+     * the mpi_montmul() and mpi_montred() calls later. Here we ensure that
+     * W[1] and the accumulator W[x_index] are large enough. later we'll grow
+     * other W[i] to the same length. They must not be shrunk midway through
+     * this function!
      */
     MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[x_index], j));
     MBEDTLS_MPI_CHK(mbedtls_mpi_grow(&W[1],  j));
@@ -1887,7 +2031,7 @@
     /*
      * Load the result in the output variable.
      */
-    mbedtls_mpi_copy(X, &W[x_index]);
+    MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, &W[x_index]));
 
 cleanup:
 
@@ -2165,29 +2309,30 @@
 
 #if defined(MBEDTLS_GENPRIME)
 
-static const int small_prime[] =
-{
-    3,    5,    7,   11,   13,   17,   19,   23,
-    29,   31,   37,   41,   43,   47,   53,   59,
-    61,   67,   71,   73,   79,   83,   89,   97,
-    101,  103,  107,  109,  113,  127,  131,  137,
-    139,  149,  151,  157,  163,  167,  173,  179,
-    181,  191,  193,  197,  199,  211,  223,  227,
-    229,  233,  239,  241,  251,  257,  263,  269,
-    271,  277,  281,  283,  293,  307,  311,  313,
-    317,  331,  337,  347,  349,  353,  359,  367,
-    373,  379,  383,  389,  397,  401,  409,  419,
-    421,  431,  433,  439,  443,  449,  457,  461,
-    463,  467,  479,  487,  491,  499,  503,  509,
-    521,  523,  541,  547,  557,  563,  569,  571,
-    577,  587,  593,  599,  601,  607,  613,  617,
-    619,  631,  641,  643,  647,  653,  659,  661,
-    673,  677,  683,  691,  701,  709,  719,  727,
-    733,  739,  743,  751,  757,  761,  769,  773,
-    787,  797,  809,  811,  821,  823,  827,  829,
-    839,  853,  857,  859,  863,  877,  881,  883,
-    887,  907,  911,  919,  929,  937,  941,  947,
-    953,  967,  971,  977,  983,  991,  997, -103
+/* Gaps between primes, starting at 3. https://oeis.org/A001223 */
+static const unsigned char small_prime_gaps[] = {
+    2, 2, 4, 2, 4, 2, 4, 6,
+    2, 6, 4, 2, 4, 6, 6, 2,
+    6, 4, 2, 6, 4, 6, 8, 4,
+    2, 4, 2, 4, 14, 4, 6, 2,
+    10, 2, 6, 6, 4, 6, 6, 2,
+    10, 2, 4, 2, 12, 12, 4, 2,
+    4, 6, 2, 10, 6, 6, 6, 2,
+    6, 4, 2, 10, 14, 4, 2, 4,
+    14, 6, 10, 2, 4, 6, 8, 6,
+    6, 4, 6, 8, 4, 8, 10, 2,
+    10, 2, 6, 4, 6, 8, 4, 2,
+    4, 12, 8, 4, 8, 4, 6, 12,
+    2, 18, 6, 10, 6, 6, 2, 6,
+    10, 6, 6, 2, 6, 6, 4, 2,
+    12, 10, 2, 4, 6, 6, 2, 12,
+    4, 6, 8, 10, 8, 10, 8, 6,
+    6, 4, 8, 6, 4, 8, 4, 14,
+    10, 12, 2, 10, 2, 4, 2, 10,
+    14, 4, 2, 4, 14, 4, 2, 4,
+    20, 4, 8, 10, 8, 4, 6, 6,
+    14, 4, 6, 6, 8, 6, /*reaches 997*/
+    0 /* the last entry is effectively unused */
 };
 
 /*
@@ -2204,20 +2349,20 @@
     int ret = 0;
     size_t i;
     mbedtls_mpi_uint r;
+    unsigned p = 3; /* The first odd prime */
 
     if ((X->p[0] & 1) == 0) {
         return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
     }
 
-    for (i = 0; small_prime[i] > 0; i++) {
-        if (mbedtls_mpi_cmp_int(X, small_prime[i]) <= 0) {
-            return 1;
-        }
-
-        MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, small_prime[i]));
-
+    for (i = 0; i < sizeof(small_prime_gaps); p += small_prime_gaps[i], i++) {
+        MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, p));
         if (r == 0) {
-            return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
+            if (mbedtls_mpi_cmp_int(X, p) == 0) {
+                return 1;
+            } else {
+                return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
+            }
         }
     }
 
diff --git a/library/bignum_core.c b/library/bignum_core.c
index 8bf819c..48b640b 100644
--- a/library/bignum_core.c
+++ b/library/bignum_core.c
@@ -144,54 +144,92 @@
 
 /* Whether min <= A, in constant time.
  * A_limbs must be at least 1. */
-unsigned mbedtls_mpi_core_uint_le_mpi(mbedtls_mpi_uint min,
-                                      const mbedtls_mpi_uint *A,
-                                      size_t A_limbs)
+mbedtls_ct_condition_t mbedtls_mpi_core_uint_le_mpi(mbedtls_mpi_uint min,
+                                                    const mbedtls_mpi_uint *A,
+                                                    size_t A_limbs)
 {
     /* min <= least significant limb? */
-    unsigned min_le_lsl = 1 ^ mbedtls_ct_mpi_uint_lt(A[0], min);
+    mbedtls_ct_condition_t min_le_lsl = mbedtls_ct_uint_ge(A[0], min);
 
     /* limbs other than the least significant one are all zero? */
-    mbedtls_mpi_uint msll_mask = 0;
+    mbedtls_ct_condition_t msll_mask = MBEDTLS_CT_FALSE;
     for (size_t i = 1; i < A_limbs; i++) {
-        msll_mask |= A[i];
+        msll_mask = mbedtls_ct_bool_or(msll_mask, mbedtls_ct_bool(A[i]));
     }
-    /* The most significant limbs of A are not all zero iff msll_mask != 0. */
-    unsigned msll_nonzero = mbedtls_ct_mpi_uint_mask(msll_mask) & 1;
 
     /* min <= A iff the lowest limb of A is >= min or the other limbs
      * are not all zero. */
-    return min_le_lsl | msll_nonzero;
+    return mbedtls_ct_bool_or(msll_mask, min_le_lsl);
+}
+
+mbedtls_ct_condition_t mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A,
+                                              const mbedtls_mpi_uint *B,
+                                              size_t limbs)
+{
+    mbedtls_ct_condition_t ret = MBEDTLS_CT_FALSE, cond = MBEDTLS_CT_FALSE, done = MBEDTLS_CT_FALSE;
+
+    for (size_t i = limbs; i > 0; i--) {
+        /*
+         * If B[i - 1] < A[i - 1] then A < B is false and the result must
+         * remain 0.
+         *
+         * Again even if we can make a decision, we just mark the result and
+         * the fact that we are done and continue looping.
+         */
+        cond = mbedtls_ct_uint_lt(B[i - 1], A[i - 1]);
+        done = mbedtls_ct_bool_or(done, cond);
+
+        /*
+         * If A[i - 1] < B[i - 1] then A < B is true.
+         *
+         * Again even if we can make a decision, we just mark the result and
+         * the fact that we are done and continue looping.
+         */
+        cond = mbedtls_ct_uint_lt(A[i - 1], B[i - 1]);
+        ret  = mbedtls_ct_bool_or(ret, mbedtls_ct_bool_and(cond, mbedtls_ct_bool_not(done)));
+        done = mbedtls_ct_bool_or(done, cond);
+    }
+
+    /*
+     * If all the limbs were equal, then the numbers are equal, A < B is false
+     * and leaving the result 0 is correct.
+     */
+
+    return ret;
 }
 
 void mbedtls_mpi_core_cond_assign(mbedtls_mpi_uint *X,
                                   const mbedtls_mpi_uint *A,
                                   size_t limbs,
-                                  unsigned char assign)
+                                  mbedtls_ct_condition_t assign)
 {
     if (X == A) {
         return;
     }
 
-    mbedtls_ct_mpi_uint_cond_assign(limbs, X, A, assign);
+    /* This function is very performance-sensitive for RSA. For this reason
+     * we have the loop below, instead of calling mbedtls_ct_memcpy_if
+     * (this is more optimal since here we don't have to handle the case where
+     * we copy awkwardly sized data).
+     */
+    for (size_t i = 0; i < limbs; i++) {
+        X[i] = mbedtls_ct_mpi_uint_if(assign, A[i], X[i]);
+    }
 }
 
 void mbedtls_mpi_core_cond_swap(mbedtls_mpi_uint *X,
                                 mbedtls_mpi_uint *Y,
                                 size_t limbs,
-                                unsigned char swap)
+                                mbedtls_ct_condition_t swap)
 {
     if (X == Y) {
         return;
     }
 
-    /* all-bits 1 if swap is 1, all-bits 0 if swap is 0 */
-    mbedtls_mpi_uint limb_mask = mbedtls_ct_mpi_uint_mask(swap);
-
     for (size_t i = 0; i < limbs; i++) {
         mbedtls_mpi_uint tmp = X[i];
-        X[i] = (X[i] & ~limb_mask) | (Y[i] & limb_mask);
-        Y[i] = (Y[i] & ~limb_mask) | (tmp & limb_mask);
+        X[i] = mbedtls_ct_mpi_uint_if(swap, Y[i], X[i]);
+        Y[i] = mbedtls_ct_mpi_uint_if(swap, tmp, Y[i]);
     }
 }
 
@@ -422,11 +460,10 @@
 {
     mbedtls_mpi_uint c = 0;
 
-    /* all-bits 0 if cond is 0, all-bits 1 if cond is non-0 */
-    const mbedtls_mpi_uint mask = mbedtls_ct_mpi_uint_mask(cond);
+    mbedtls_ct_condition_t do_add = mbedtls_ct_bool(cond);
 
     for (size_t i = 0; i < limbs; i++) {
-        mbedtls_mpi_uint add = mask & A[i];
+        mbedtls_mpi_uint add = mbedtls_ct_mpi_uint_if_else_0(do_add, A[i]);
         mbedtls_mpi_uint t = c + X[i];
         c = (t < X[i]);
         t += add;
@@ -568,7 +605,11 @@
      * So the correct return value is already in X if (carry ^ borrow) = 0,
      * but is in (the lower AN_limbs limbs of) T if (carry ^ borrow) = 1.
      */
-    mbedtls_ct_mpi_uint_cond_assign(AN_limbs, X, T, (unsigned char) (carry ^ borrow));
+    mbedtls_ct_memcpy_if(mbedtls_ct_bool(carry ^ borrow),
+                         (unsigned char *) X,
+                         (unsigned char *) T,
+                         NULL,
+                         AN_limbs * sizeof(mbedtls_mpi_uint));
 }
 
 int mbedtls_mpi_core_get_mont_r2_unsafe(mbedtls_mpi *X,
@@ -593,7 +634,7 @@
                                            size_t index)
 {
     for (size_t i = 0; i < count; i++, table += limbs) {
-        unsigned char assign = mbedtls_ct_size_bool_eq(i, index);
+        mbedtls_ct_condition_t assign = mbedtls_ct_uint_eq(i, index);
         mbedtls_mpi_core_cond_assign(dest, table, limbs, assign);
     }
 }
@@ -633,7 +674,7 @@
                             int (*f_rng)(void *, unsigned char *, size_t),
                             void *p_rng)
 {
-    unsigned ge_lower = 1, lt_upper = 0;
+    mbedtls_ct_condition_t ge_lower = MBEDTLS_CT_TRUE, lt_upper = MBEDTLS_CT_FALSE;
     size_t n_bits = mbedtls_mpi_core_bitlen(N, limbs);
     size_t n_bytes = (n_bits + 7) / 8;
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -678,7 +719,7 @@
 
         ge_lower = mbedtls_mpi_core_uint_le_mpi(min, X, limbs);
         lt_upper = mbedtls_mpi_core_lt_ct(X, N, limbs);
-    } while (ge_lower == 0 || lt_upper == 0);
+    } while (mbedtls_ct_bool_and(ge_lower, lt_upper) == MBEDTLS_CT_FALSE);
 
 cleanup:
     return ret;
@@ -686,16 +727,16 @@
 
 static size_t exp_mod_get_window_size(size_t Ebits)
 {
-    size_t wsize = (Ebits > 671) ? 6 : (Ebits > 239) ? 5 :
-                   (Ebits >  79) ? 4 : 1;
-
-#if (MBEDTLS_MPI_WINDOW_SIZE < 6)
-    if (wsize > MBEDTLS_MPI_WINDOW_SIZE) {
-        wsize = MBEDTLS_MPI_WINDOW_SIZE;
-    }
+#if MBEDTLS_MPI_WINDOW_SIZE >= 6
+    return (Ebits > 671) ? 6 : (Ebits > 239) ? 5 : (Ebits >  79) ? 4 : 1;
+#elif MBEDTLS_MPI_WINDOW_SIZE == 5
+    return (Ebits > 239) ? 5 : (Ebits >  79) ? 4 : 1;
+#elif MBEDTLS_MPI_WINDOW_SIZE > 1
+    return (Ebits >  79) ? MBEDTLS_MPI_WINDOW_SIZE : 1;
+#else
+    (void) Ebits;
+    return 1;
 #endif
-
-    return wsize;
 }
 
 size_t mbedtls_mpi_core_exp_mod_working_limbs(size_t AN_limbs, size_t E_limbs)
diff --git a/library/bignum_core.h b/library/bignum_core.h
index 21a5a11..e5500f1 100644
--- a/library/bignum_core.h
+++ b/library/bignum_core.h
@@ -86,6 +86,8 @@
 #include "mbedtls/bignum.h"
 #endif
 
+#include "constant_time_internal.h"
+
 #define ciL    (sizeof(mbedtls_mpi_uint))     /** chars in limb  */
 #define biL    (ciL << 3)                     /** bits  in limb  */
 #define biH    (ciL << 2)                     /** half limb size */
@@ -142,11 +144,29 @@
  * \param A_limbs  The number of limbs of \p A.
  *                 This must be at least 1.
  *
- * \return         1 if \p min is less than or equal to \p A, otherwise 0.
+ * \return         MBEDTLS_CT_TRUE if \p min is less than or equal to \p A, otherwise MBEDTLS_CT_FALSE.
  */
-unsigned mbedtls_mpi_core_uint_le_mpi(mbedtls_mpi_uint min,
-                                      const mbedtls_mpi_uint *A,
-                                      size_t A_limbs);
+mbedtls_ct_condition_t mbedtls_mpi_core_uint_le_mpi(mbedtls_mpi_uint min,
+                                                    const mbedtls_mpi_uint *A,
+                                                    size_t A_limbs);
+
+/**
+ * \brief          Check if one unsigned MPI is less than another in constant
+ *                 time.
+ *
+ * \param A        The left-hand MPI. This must point to an array of limbs
+ *                 with the same allocated length as \p B.
+ * \param B        The right-hand MPI. This must point to an array of limbs
+ *                 with the same allocated length as \p A.
+ * \param limbs    The number of limbs in \p A and \p B.
+ *                 This must not be 0.
+ *
+ * \return         MBEDTLS_CT_TRUE  if \p A is less than \p B.
+ *                 MBEDTLS_CT_FALSE if \p A is greater than or equal to \p B.
+ */
+mbedtls_ct_condition_t mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A,
+                                              const mbedtls_mpi_uint *B,
+                                              size_t limbs);
 
 /**
  * \brief   Perform a safe conditional copy of an MPI which doesn't reveal
@@ -158,21 +178,17 @@
  * \param[in]  A        The address of the source MPI. This must be initialized.
  * \param      limbs    The number of limbs of \p A.
  * \param      assign   The condition deciding whether to perform the
- *                      assignment or not. Must be either 0 or 1:
- *                      * \c 1: Perform the assignment `X = A`.
- *                      * \c 0: Keep the original value of \p X.
+ *                      assignment or not. Callers will need to use
+ *                      the constant time interface (e.g. `mbedtls_ct_bool()`)
+ *                      to construct this argument.
  *
  * \note           This function avoids leaking any information about whether
  *                 the assignment was done or not.
- *
- * \warning        If \p assign is neither 0 nor 1, the result of this function
- *                 is indeterminate, and the resulting value in \p X might be
- *                 neither its original value nor the value in \p A.
  */
 void mbedtls_mpi_core_cond_assign(mbedtls_mpi_uint *X,
                                   const mbedtls_mpi_uint *A,
                                   size_t limbs,
-                                  unsigned char assign);
+                                  mbedtls_ct_condition_t assign);
 
 /**
  * \brief   Perform a safe conditional swap of two MPIs which doesn't reveal
@@ -184,21 +200,15 @@
  *                          This must be initialized.
  * \param         limbs     The number of limbs of \p X and \p Y.
  * \param         swap      The condition deciding whether to perform
- *                          the swap or not. Must be either 0 or 1:
- *                          * \c 1: Swap the values of \p X and \p Y.
- *                          * \c 0: Keep the original values of \p X and \p Y.
+ *                          the swap or not.
  *
  * \note           This function avoids leaking any information about whether
  *                 the swap was done or not.
- *
- * \warning        If \p swap is neither 0 nor 1, the result of this function
- *                 is indeterminate, and both \p X and \p Y might end up with
- *                 values different to either of the original ones.
  */
 void mbedtls_mpi_core_cond_swap(mbedtls_mpi_uint *X,
                                 mbedtls_mpi_uint *Y,
                                 size_t limbs,
-                                unsigned char swap);
+                                mbedtls_ct_condition_t swap);
 
 /** Import X from unsigned binary data, little-endian.
  *
diff --git a/library/bignum_mod.c b/library/bignum_mod.c
index 4d67829..2f0e9ed 100644
--- a/library/bignum_mod.c
+++ b/library/bignum_mod.c
@@ -19,7 +19,7 @@
 
 #include "common.h"
 
-#if defined(MBEDTLS_BIGNUM_C)
+#if defined(MBEDTLS_BIGNUM_C) && defined(MBEDTLS_ECP_WITH_MPI_UINT)
 
 #include <string.h>
 
@@ -403,4 +403,4 @@
     return ret;
 }
 
-#endif /* MBEDTLS_BIGNUM_C */
+#endif /* MBEDTLS_BIGNUM_C && MBEDTLS_ECP_WITH_MPI_UINT */
diff --git a/library/bignum_mod_raw.c b/library/bignum_mod_raw.c
index eff5627..5ee1b19 100644
--- a/library/bignum_mod_raw.c
+++ b/library/bignum_mod_raw.c
@@ -19,7 +19,7 @@
 
 #include "common.h"
 
-#if defined(MBEDTLS_BIGNUM_C)
+#if defined(MBEDTLS_BIGNUM_C) && defined(MBEDTLS_ECP_WITH_MPI_UINT)
 
 #include <string.h>
 
@@ -40,7 +40,7 @@
                                      const mbedtls_mpi_mod_modulus *N,
                                      unsigned char assign)
 {
-    mbedtls_mpi_core_cond_assign(X, A, N->limbs, assign);
+    mbedtls_mpi_core_cond_assign(X, A, N->limbs, mbedtls_ct_bool(assign));
 }
 
 void mbedtls_mpi_mod_raw_cond_swap(mbedtls_mpi_uint *X,
@@ -48,7 +48,7 @@
                                    const mbedtls_mpi_mod_modulus *N,
                                    unsigned char swap)
 {
-    mbedtls_mpi_core_cond_swap(X, Y, N->limbs, swap);
+    mbedtls_mpi_core_cond_swap(X, Y, N->limbs, mbedtls_ct_bool(swap));
 }
 
 int mbedtls_mpi_mod_raw_read(mbedtls_mpi_uint *X,
@@ -285,4 +285,4 @@
     (void) mbedtls_mpi_core_add_if(X, N->p, N->limbs, (unsigned) borrow);
 }
 
-#endif /* MBEDTLS_BIGNUM_C */
+#endif /* MBEDTLS_BIGNUM_C && MBEDTLS_ECP_WITH_MPI_UINT */
diff --git a/library/cipher_wrap.c b/library/cipher_wrap.c
index da4e739..6ab2f5f 100644
--- a/library/cipher_wrap.c
+++ b/library/cipher_wrap.c
@@ -120,8 +120,10 @@
     MBEDTLS_CIPHER_BASE_INDEX_NULL_BASE,
 #endif
 #if defined(MBEDTLS_CIPHER_MODE_XTS) && defined(MBEDTLS_AES_C)
-    MBEDTLS_CIPHER_BASE_INDEX_XTS_AES
+    MBEDTLS_CIPHER_BASE_INDEX_XTS_AES,
 #endif
+    /* Prevent compile failure due to empty enum */
+    MBEDTLS_CIPHER_BASE_PREVENT_EMPTY_ENUM
 };
 
 #if defined(MBEDTLS_GCM_C)
diff --git a/library/common.h b/library/common.h
index 97dc1d3..3c472c6 100644
--- a/library/common.h
+++ b/library/common.h
@@ -288,7 +288,7 @@
 /* Normal case (64-bit pointers): use "r" as the constraint for pointer operands to asm */
 #define MBEDTLS_ASM_AARCH64_PTR_CONSTRAINT "r"
 #else
-#error Unrecognised pointer size for aarch64
+#error "Unrecognised pointer size for aarch64"
 #endif
 #endif
 
diff --git a/library/constant_time.c b/library/constant_time.c
index 5265005..d3c69cf 100644
--- a/library/constant_time.c
+++ b/library/constant_time.c
@@ -22,29 +22,14 @@
  * might be translated to branches by some compilers on some platforms.
  */
 
+#include <limits.h>
+
 #include "common.h"
 #include "constant_time_internal.h"
 #include "mbedtls/constant_time.h"
 #include "mbedtls/error.h"
 #include "mbedtls/platform_util.h"
 
-#if defined(MBEDTLS_BIGNUM_C)
-#include "mbedtls/bignum.h"
-#include "bignum_core.h"
-#endif
-
-#if defined(MBEDTLS_SSL_TLS_C)
-#include "ssl_misc.h"
-#endif
-
-#if defined(MBEDTLS_RSA_C)
-#include "mbedtls/rsa.h"
-#endif
-
-#if defined(MBEDTLS_BASE64_C)
-#include "constant_time_invasive.h"
-#endif
-
 #include <string.h>
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
@@ -60,6 +45,15 @@
 #define PSA_TO_MBEDTLS_ERR(status) local_err_translation(status)
 #endif
 
+#if !defined(MBEDTLS_CT_ASM)
+/*
+ * Define an object with the value zero, such that the compiler cannot prove that it
+ * has the value zero (because it is volatile, it "may be modified in ways unknown to
+ * the implementation").
+ */
+volatile mbedtls_ct_uint_t mbedtls_ct_zero = 0;
+#endif
+
 /*
  * Define MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS where assembly is present to
  * perform fast unaligned access to volatile data.
@@ -70,15 +64,12 @@
  * Some of these definitions could be moved into alignment.h but for now they are
  * only used here.
  */
-#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) && defined(MBEDTLS_HAVE_ASM)
-#if ((defined(__arm__) || defined(__thumb__) || defined(__thumb2__)) && \
-    (UINTPTR_MAX == 0xfffffffful)) || defined(__aarch64__)
+#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) && \
+    ((defined(MBEDTLS_CT_ARM_ASM) && (UINTPTR_MAX == 0xfffffffful)) || \
+    defined(MBEDTLS_CT_AARCH64_ASM))
 /* We check pointer sizes to avoid issues with them not matching register size requirements */
 #define MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS
-#endif
-#endif
 
-#if defined(MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS)
 static inline uint32_t mbedtls_get_unaligned_volatile_uint32(volatile const unsigned char *p)
 {
     /* This is UB, even where it's safe:
@@ -86,14 +77,17 @@
      * so instead the same thing is expressed in assembly below.
      */
     uint32_t r;
-#if defined(__arm__) || defined(__thumb__) || defined(__thumb2__)
+#if defined(MBEDTLS_CT_ARM_ASM)
     asm volatile ("ldr %0, [%1]" : "=r" (r) : "r" (p) :);
-#elif defined(__aarch64__)
+#elif defined(MBEDTLS_CT_AARCH64_ASM)
     asm volatile ("ldr %w0, [%1]" : "=r" (r) : MBEDTLS_ASM_AARCH64_PTR_CONSTRAINT(p) :);
+#else
+#error "No assembly defined for mbedtls_get_unaligned_volatile_uint32"
 #endif
     return r;
 }
-#endif /* MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS */
+#endif /* defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) &&
+          (defined(MBEDTLS_CT_ARM_ASM) || defined(MBEDTLS_CT_AARCH64_ASM)) */
 
 int mbedtls_ct_memcmp(const void *a,
                       const void *b,
@@ -129,336 +123,69 @@
     return (int) diff;
 }
 
-unsigned mbedtls_ct_uint_mask(unsigned value)
-{
-    /* MSVC has a warning about unary minus on unsigned, but this is
-     * well-defined and precisely what we want to do here */
-#if defined(_MSC_VER)
-#pragma warning( push )
-#pragma warning( disable : 4146 )
-#endif
-    return -((value | -value) >> (sizeof(value) * 8 - 1));
-#if defined(_MSC_VER)
-#pragma warning( pop )
-#endif
-}
-
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
-
-size_t mbedtls_ct_size_mask(size_t value)
-{
-    /* MSVC has a warning about unary minus on unsigned integer types,
-     * but this is well-defined and precisely what we want to do here. */
-#if defined(_MSC_VER)
-#pragma warning( push )
-#pragma warning( disable : 4146 )
-#endif
-    return -((value | -value) >> (sizeof(value) * 8 - 1));
-#if defined(_MSC_VER)
-#pragma warning( pop )
-#endif
-}
-
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */
-
-#if defined(MBEDTLS_BIGNUM_C)
-
-mbedtls_mpi_uint mbedtls_ct_mpi_uint_mask(mbedtls_mpi_uint value)
-{
-    /* MSVC has a warning about unary minus on unsigned, but this is
-     * well-defined and precisely what we want to do here */
-#if defined(_MSC_VER)
-#pragma warning( push )
-#pragma warning( disable : 4146 )
-#endif
-    return -((value | -value) >> (sizeof(value) * 8 - 1));
-#if defined(_MSC_VER)
-#pragma warning( pop )
-#endif
-}
-
-#endif /* MBEDTLS_BIGNUM_C */
-
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC)
-
-/** Constant-flow mask generation for "less than" comparison:
- * - if \p x < \p y, return all-bits 1, that is (size_t) -1
- * - otherwise, return all bits 0, that is 0
- *
- * This function can be used to write constant-time code by replacing branches
- * with bit operations using masks.
- *
- * \param x     The first value to analyze.
- * \param y     The second value to analyze.
- *
- * \return      All-bits-one if \p x is less than \p y, otherwise zero.
- */
-static size_t mbedtls_ct_size_mask_lt(size_t x,
-                                      size_t y)
-{
-    /* This has the most significant bit set if and only if x < y */
-    const size_t sub = x - y;
-
-    /* sub1 = (x < y) ? 1 : 0 */
-    const size_t sub1 = sub >> (sizeof(sub) * 8 - 1);
-
-    /* mask = (x < y) ? 0xff... : 0x00... */
-    const size_t mask = mbedtls_ct_size_mask(sub1);
-
-    return mask;
-}
-
-size_t mbedtls_ct_size_mask_ge(size_t x,
-                               size_t y)
-{
-    return ~mbedtls_ct_size_mask_lt(x, y);
-}
-
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */
-
-#if defined(MBEDTLS_BASE64_C)
-
-/* Return 0xff if low <= c <= high, 0 otherwise.
- *
- * Constant flow with respect to c.
- */
-MBEDTLS_STATIC_TESTABLE
-unsigned char mbedtls_ct_uchar_mask_of_range(unsigned char low,
-                                             unsigned char high,
-                                             unsigned char c)
-{
-    /* low_mask is: 0 if low <= c, 0x...ff if low > c */
-    unsigned low_mask = ((unsigned) c - low) >> 8;
-    /* high_mask is: 0 if c <= high, 0x...ff if c > high */
-    unsigned high_mask = ((unsigned) high - c) >> 8;
-    return ~(low_mask | high_mask) & 0xff;
-}
-
-#endif /* MBEDTLS_BASE64_C */
-
-unsigned mbedtls_ct_size_bool_eq(size_t x,
-                                 size_t y)
-{
-    /* diff = 0 if x == y, non-zero otherwise */
-    const size_t diff = x ^ y;
-
-    /* MSVC has a warning about unary minus on unsigned integer types,
-     * but this is well-defined and precisely what we want to do here. */
-#if defined(_MSC_VER)
-#pragma warning( push )
-#pragma warning( disable : 4146 )
-#endif
-
-    /* diff_msb's most significant bit is equal to x != y */
-    const size_t diff_msb = (diff | (size_t) -diff);
-
-#if defined(_MSC_VER)
-#pragma warning( pop )
-#endif
-
-    /* diff1 = (x != y) ? 1 : 0 */
-    const unsigned diff1 = diff_msb >> (sizeof(diff_msb) * 8 - 1);
-
-    return 1 ^ diff1;
-}
-
 #if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
 
-/** Constant-flow "greater than" comparison:
- * return x > y
- *
- * This is equivalent to \p x > \p y, but is likely to be compiled
- * to code using bitwise operation rather than a branch.
- *
- * \param x     The first value to analyze.
- * \param y     The second value to analyze.
- *
- * \return      1 if \p x greater than \p y, otherwise 0.
- */
-static unsigned mbedtls_ct_size_gt(size_t x,
-                                   size_t y)
-{
-    /* Return the sign bit (1 for negative) of (y - x). */
-    return (y - x) >> (sizeof(size_t) * 8 - 1);
-}
-
-#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */
-
-#if defined(MBEDTLS_BIGNUM_C)
-
-unsigned mbedtls_ct_mpi_uint_lt(const mbedtls_mpi_uint x,
-                                const mbedtls_mpi_uint y)
-{
-    mbedtls_mpi_uint ret;
-    mbedtls_mpi_uint cond;
-
-    /*
-     * Check if the most significant bits (MSB) of the operands are different.
-     */
-    cond = (x ^ y);
-    /*
-     * If the MSB are the same then the difference x-y will be negative (and
-     * have its MSB set to 1 during conversion to unsigned) if and only if x<y.
-     */
-    ret = (x - y) & ~cond;
-    /*
-     * If the MSB are different, then the operand with the MSB of 1 is the
-     * bigger. (That is if y has MSB of 1, then x<y is true and it is false if
-     * the MSB of y is 0.)
-     */
-    ret |= y & cond;
-
-
-    ret = ret >> (sizeof(mbedtls_mpi_uint) * 8 - 1);
-
-    return (unsigned) ret;
-}
-
-#endif /* MBEDTLS_BIGNUM_C */
-
-unsigned mbedtls_ct_uint_if(unsigned condition,
-                            unsigned if1,
-                            unsigned if0)
-{
-    unsigned mask = mbedtls_ct_uint_mask(condition);
-    return (mask & if1) | (~mask & if0);
-}
-
-#if defined(MBEDTLS_BIGNUM_C)
-
-void mbedtls_ct_mpi_uint_cond_assign(size_t n,
-                                     mbedtls_mpi_uint *dest,
-                                     const mbedtls_mpi_uint *src,
-                                     unsigned char condition)
-{
-    size_t i;
-
-    /* MSVC has a warning about unary minus on unsigned integer types,
-     * but this is well-defined and precisely what we want to do here. */
-#if defined(_MSC_VER)
-#pragma warning( push )
-#pragma warning( disable : 4146 )
-#endif
-
-    /* all-bits 1 if condition is 1, all-bits 0 if condition is 0 */
-    const mbedtls_mpi_uint mask = -condition;
-
-#if defined(_MSC_VER)
-#pragma warning( pop )
-#endif
-
-    for (i = 0; i < n; i++) {
-        dest[i] = (src[i] & mask) | (dest[i] & ~mask);
-    }
-}
-
-#endif /* MBEDTLS_BIGNUM_C */
-
-#if defined(MBEDTLS_BASE64_C)
-
-unsigned char mbedtls_ct_base64_enc_char(unsigned char value)
-{
-    unsigned char digit = 0;
-    /* For each range of values, if value is in that range, mask digit with
-     * the corresponding value. Since value can only be in a single range,
-     * only at most one masking will change digit. */
-    digit |= mbedtls_ct_uchar_mask_of_range(0, 25, value) & ('A' + value);
-    digit |= mbedtls_ct_uchar_mask_of_range(26, 51, value) & ('a' + value - 26);
-    digit |= mbedtls_ct_uchar_mask_of_range(52, 61, value) & ('0' + value - 52);
-    digit |= mbedtls_ct_uchar_mask_of_range(62, 62, value) & '+';
-    digit |= mbedtls_ct_uchar_mask_of_range(63, 63, value) & '/';
-    return digit;
-}
-
-signed char mbedtls_ct_base64_dec_value(unsigned char c)
-{
-    unsigned char val = 0;
-    /* For each range of digits, if c is in that range, mask val with
-     * the corresponding value. Since c can only be in a single range,
-     * only at most one masking will change val. Set val to one plus
-     * the desired value so that it stays 0 if c is in none of the ranges. */
-    val |= mbedtls_ct_uchar_mask_of_range('A', 'Z', c) & (c - 'A' +  0 + 1);
-    val |= mbedtls_ct_uchar_mask_of_range('a', 'z', c) & (c - 'a' + 26 + 1);
-    val |= mbedtls_ct_uchar_mask_of_range('0', '9', c) & (c - '0' + 52 + 1);
-    val |= mbedtls_ct_uchar_mask_of_range('+', '+', c) & (c - '+' + 62 + 1);
-    val |= mbedtls_ct_uchar_mask_of_range('/', '/', c) & (c - '/' + 63 + 1);
-    /* At this point, val is 0 if c is an invalid digit and v+1 if c is
-     * a digit with the value v. */
-    return val - 1;
-}
-
-#endif /* MBEDTLS_BASE64_C */
-
-#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
-
-/** Shift some data towards the left inside a buffer.
- *
- * `mbedtls_ct_mem_move_to_left(start, total, offset)` is functionally
- * equivalent to
- * ```
- * memmove(start, start + offset, total - offset);
- * memset(start + offset, 0, total - offset);
- * ```
- * but it strives to use a memory access pattern (and thus total timing)
- * that does not depend on \p offset. This timing independence comes at
- * the expense of performance.
- *
- * \param start     Pointer to the start of the buffer.
- * \param total     Total size of the buffer.
- * \param offset    Offset from which to copy \p total - \p offset bytes.
- */
-static void mbedtls_ct_mem_move_to_left(void *start,
-                                        size_t total,
-                                        size_t offset)
+void mbedtls_ct_memmove_left(void *start, size_t total, size_t offset)
 {
     volatile unsigned char *buf = start;
-    size_t i, n;
-    if (total == 0) {
-        return;
-    }
-    for (i = 0; i < total; i++) {
-        unsigned no_op = mbedtls_ct_size_gt(total - offset, i);
+    for (size_t i = 0; i < total; i++) {
+        mbedtls_ct_condition_t no_op = mbedtls_ct_uint_gt(total - offset, i);
         /* The first `total - offset` passes are a no-op. The last
          * `offset` passes shift the data one byte to the left and
          * zero out the last byte. */
-        for (n = 0; n < total - 1; n++) {
+        for (size_t n = 0; n < total - 1; n++) {
             unsigned char current = buf[n];
-            unsigned char next = buf[n+1];
+            unsigned char next    = buf[n+1];
             buf[n] = mbedtls_ct_uint_if(no_op, current, next);
         }
-        buf[total-1] = mbedtls_ct_uint_if(no_op, buf[total-1], 0);
+        buf[total-1] = mbedtls_ct_uint_if_else_0(no_op, buf[total-1]);
     }
 }
 
 #endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */
 
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
-
-void mbedtls_ct_memcpy_if_eq(unsigned char *dest,
-                             const unsigned char *src,
-                             size_t len,
-                             size_t c1,
-                             size_t c2)
+void mbedtls_ct_memcpy_if(mbedtls_ct_condition_t condition,
+                          unsigned char *dest,
+                          const unsigned char *src1,
+                          const unsigned char *src2,
+                          size_t len)
 {
-    /* mask = c1 == c2 ? 0xff : 0x00 */
-    const size_t equal = mbedtls_ct_size_bool_eq(c1, c2);
+#if defined(MBEDTLS_CT_SIZE_64)
+    const uint64_t mask     = (uint64_t) condition;
+    const uint64_t not_mask = (uint64_t) ~mbedtls_ct_compiler_opaque(condition);
+#else
+    const uint32_t mask     = (uint32_t) condition;
+    const uint32_t not_mask = (uint32_t) ~mbedtls_ct_compiler_opaque(condition);
+#endif
+
+    /* If src2 is NULL, setup src2 so that we read from the destination address.
+     *
+     * This means that if src2 == NULL && condition is false, the result will be a
+     * no-op because we read from dest and write the same data back into dest.
+     */
+    if (src2 == NULL) {
+        src2 = dest;
+    }
 
     /* dest[i] = c1 == c2 ? src[i] : dest[i] */
     size_t i = 0;
 #if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)
-    const uint32_t mask32 = (uint32_t) mbedtls_ct_size_mask(equal);
-    const unsigned char mask = (unsigned char) mask32 & 0xff;
-
-    for (; (i + 4) <= len; i += 4) {
-        uint32_t a = mbedtls_get_unaligned_uint32(src  + i) &  mask32;
-        uint32_t b = mbedtls_get_unaligned_uint32(dest + i) & ~mask32;
-        mbedtls_put_unaligned_uint32(dest + i, a | b);
+#if defined(MBEDTLS_CT_SIZE_64)
+    for (; (i + 8) <= len; i += 8) {
+        uint64_t a = mbedtls_get_unaligned_uint64(src1 + i) & mask;
+        uint64_t b = mbedtls_get_unaligned_uint64(src2 + i) & not_mask;
+        mbedtls_put_unaligned_uint64(dest + i, a | b);
     }
 #else
-    const unsigned char mask = (unsigned char) mbedtls_ct_size_mask(equal);
+    for (; (i + 4) <= len; i += 4) {
+        uint32_t a = mbedtls_get_unaligned_uint32(src1 + i) & mask;
+        uint32_t b = mbedtls_get_unaligned_uint32(src2 + i) & not_mask;
+        mbedtls_put_unaligned_uint32(dest + i, a | b);
+    }
+#endif /* defined(MBEDTLS_CT_SIZE_64) */
 #endif /* MBEDTLS_EFFICIENT_UNALIGNED_ACCESS */
     for (; i < len; i++) {
-        dest[i] = (src[i] & mask) | (dest[i] & ~mask);
+        dest[i] = (src1[i] & mask) | (src2[i] & not_mask);
     }
 }
 
@@ -472,547 +199,27 @@
     size_t offsetval;
 
     for (offsetval = offset_min; offsetval <= offset_max; offsetval++) {
-        mbedtls_ct_memcpy_if_eq(dest, src + offsetval, len,
-                                offsetval, offset);
+        mbedtls_ct_memcpy_if(mbedtls_ct_uint_eq(offsetval, offset), dest, src + offsetval, NULL,
+                             len);
     }
 }
 
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
-
-#if defined(PSA_WANT_ALG_SHA_384)
-#define MAX_HASH_BLOCK_LENGTH PSA_HASH_BLOCK_LENGTH(PSA_ALG_SHA_384)
-#elif defined(PSA_WANT_ALG_SHA_256)
-#define MAX_HASH_BLOCK_LENGTH PSA_HASH_BLOCK_LENGTH(PSA_ALG_SHA_256)
-#else /* See check_config.h */
-#define MAX_HASH_BLOCK_LENGTH PSA_HASH_BLOCK_LENGTH(PSA_ALG_SHA_1)
-#endif
-
-int mbedtls_ct_hmac(mbedtls_svc_key_id_t key,
-                    psa_algorithm_t mac_alg,
-                    const unsigned char *add_data,
-                    size_t add_data_len,
-                    const unsigned char *data,
-                    size_t data_len_secret,
-                    size_t min_data_len,
-                    size_t max_data_len,
-                    unsigned char *output)
-{
-    /*
-     * This function breaks the HMAC abstraction and uses psa_hash_clone()
-     * extension in order to get constant-flow behaviour.
-     *
-     * HMAC(msg) is defined as HASH(okey + HASH(ikey + msg)) where + means
-     * concatenation, and okey/ikey are the XOR of the key with some fixed bit
-     * patterns (see RFC 2104, sec. 2).
-     *
-     * We'll first compute ikey/okey, then inner_hash = HASH(ikey + msg) by
-     * hashing up to minlen, then cloning the context, and for each byte up
-     * to maxlen finishing up the hash computation, keeping only the
-     * correct result.
-     *
-     * Then we only need to compute HASH(okey + inner_hash) and we're done.
-     */
-    psa_algorithm_t hash_alg = PSA_ALG_HMAC_GET_HASH(mac_alg);
-    const size_t block_size = PSA_HASH_BLOCK_LENGTH(hash_alg);
-    unsigned char key_buf[MAX_HASH_BLOCK_LENGTH];
-    const size_t hash_size = PSA_HASH_LENGTH(hash_alg);
-    psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
-    size_t hash_length;
-
-    unsigned char aux_out[PSA_HASH_MAX_SIZE];
-    psa_hash_operation_t aux_operation = PSA_HASH_OPERATION_INIT;
-    size_t offset;
-    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
-
-    size_t mac_key_length;
-    size_t i;
-
-#define PSA_CHK(func_call)        \
-    do {                            \
-        status = (func_call);       \
-        if (status != PSA_SUCCESS) \
-        goto cleanup;           \
-    } while (0)
-
-    /* Export MAC key
-     * We assume key length is always exactly the output size
-     * which is never more than the block size, thus we use block_size
-     * as the key buffer size.
-     */
-    PSA_CHK(psa_export_key(key, key_buf, block_size, &mac_key_length));
-
-    /* Calculate ikey */
-    for (i = 0; i < mac_key_length; i++) {
-        key_buf[i] = (unsigned char) (key_buf[i] ^ 0x36);
-    }
-    for (; i < block_size; ++i) {
-        key_buf[i] = 0x36;
-    }
-
-    PSA_CHK(psa_hash_setup(&operation, hash_alg));
-
-    /* Now compute inner_hash = HASH(ikey + msg) */
-    PSA_CHK(psa_hash_update(&operation, key_buf, block_size));
-    PSA_CHK(psa_hash_update(&operation, add_data, add_data_len));
-    PSA_CHK(psa_hash_update(&operation, data, min_data_len));
-
-    /* Fill the hash buffer in advance with something that is
-     * not a valid hash (barring an attack on the hash and
-     * deliberately-crafted input), in case the caller doesn't
-     * check the return status properly. */
-    memset(output, '!', hash_size);
-
-    /* For each possible length, compute the hash up to that point */
-    for (offset = min_data_len; offset <= max_data_len; offset++) {
-        PSA_CHK(psa_hash_clone(&operation, &aux_operation));
-        PSA_CHK(psa_hash_finish(&aux_operation, aux_out,
-                                PSA_HASH_MAX_SIZE, &hash_length));
-        /* Keep only the correct inner_hash in the output buffer */
-        mbedtls_ct_memcpy_if_eq(output, aux_out, hash_size,
-                                offset, data_len_secret);
-
-        if (offset < max_data_len) {
-            PSA_CHK(psa_hash_update(&operation, data + offset, 1));
-        }
-    }
-
-    /* Abort current operation to prepare for final operation */
-    PSA_CHK(psa_hash_abort(&operation));
-
-    /* Calculate okey */
-    for (i = 0; i < mac_key_length; i++) {
-        key_buf[i] = (unsigned char) ((key_buf[i] ^ 0x36) ^ 0x5C);
-    }
-    for (; i < block_size; ++i) {
-        key_buf[i] = 0x5C;
-    }
-
-    /* Now compute HASH(okey + inner_hash) */
-    PSA_CHK(psa_hash_setup(&operation, hash_alg));
-    PSA_CHK(psa_hash_update(&operation, key_buf, block_size));
-    PSA_CHK(psa_hash_update(&operation, output, hash_size));
-    PSA_CHK(psa_hash_finish(&operation, output, hash_size, &hash_length));
-
-#undef PSA_CHK
-
-cleanup:
-    mbedtls_platform_zeroize(key_buf, MAX_HASH_BLOCK_LENGTH);
-    mbedtls_platform_zeroize(aux_out, PSA_HASH_MAX_SIZE);
-
-    psa_hash_abort(&operation);
-    psa_hash_abort(&aux_operation);
-    return PSA_TO_MBEDTLS_ERR(status);
-}
-
-#undef MAX_HASH_BLOCK_LENGTH
-
-#else
-int mbedtls_ct_hmac(mbedtls_md_context_t *ctx,
-                    const unsigned char *add_data,
-                    size_t add_data_len,
-                    const unsigned char *data,
-                    size_t data_len_secret,
-                    size_t min_data_len,
-                    size_t max_data_len,
-                    unsigned char *output)
-{
-    /*
-     * This function breaks the HMAC abstraction and uses the md_clone()
-     * extension to the MD API in order to get constant-flow behaviour.
-     *
-     * HMAC(msg) is defined as HASH(okey + HASH(ikey + msg)) where + means
-     * concatenation, and okey/ikey are the XOR of the key with some fixed bit
-     * patterns (see RFC 2104, sec. 2), which are stored in ctx->hmac_ctx.
-     *
-     * We'll first compute inner_hash = HASH(ikey + msg) by hashing up to
-     * minlen, then cloning the context, and for each byte up to maxlen
-     * finishing up the hash computation, keeping only the correct result.
-     *
-     * Then we only need to compute HASH(okey + inner_hash) and we're done.
-     */
-    const mbedtls_md_type_t md_alg = mbedtls_md_get_type(ctx->md_info);
-    /* TLS 1.2 only supports SHA-384, SHA-256, SHA-1, MD-5,
-     * all of which have the same block size except SHA-384. */
-    const size_t block_size = md_alg == MBEDTLS_MD_SHA384 ? 128 : 64;
-    const unsigned char * const ikey = ctx->hmac_ctx;
-    const unsigned char * const okey = ikey + block_size;
-    const size_t hash_size = mbedtls_md_get_size(ctx->md_info);
-
-    unsigned char aux_out[MBEDTLS_MD_MAX_SIZE];
-    mbedtls_md_context_t aux;
-    size_t offset;
-    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-
-    mbedtls_md_init(&aux);
-
-#define MD_CHK(func_call) \
-    do {                    \
-        ret = (func_call);  \
-        if (ret != 0)      \
-        goto cleanup;   \
-    } while (0)
-
-    MD_CHK(mbedtls_md_setup(&aux, ctx->md_info, 0));
-
-    /* After hmac_start() of hmac_reset(), ikey has already been hashed,
-     * so we can start directly with the message */
-    MD_CHK(mbedtls_md_update(ctx, add_data, add_data_len));
-    MD_CHK(mbedtls_md_update(ctx, data, min_data_len));
-
-    /* Fill the hash buffer in advance with something that is
-     * not a valid hash (barring an attack on the hash and
-     * deliberately-crafted input), in case the caller doesn't
-     * check the return status properly. */
-    memset(output, '!', hash_size);
-
-    /* For each possible length, compute the hash up to that point */
-    for (offset = min_data_len; offset <= max_data_len; offset++) {
-        MD_CHK(mbedtls_md_clone(&aux, ctx));
-        MD_CHK(mbedtls_md_finish(&aux, aux_out));
-        /* Keep only the correct inner_hash in the output buffer */
-        mbedtls_ct_memcpy_if_eq(output, aux_out, hash_size,
-                                offset, data_len_secret);
-
-        if (offset < max_data_len) {
-            MD_CHK(mbedtls_md_update(ctx, data + offset, 1));
-        }
-    }
-
-    /* The context needs to finish() before it starts() again */
-    MD_CHK(mbedtls_md_finish(ctx, aux_out));
-
-    /* Now compute HASH(okey + inner_hash) */
-    MD_CHK(mbedtls_md_starts(ctx));
-    MD_CHK(mbedtls_md_update(ctx, okey, block_size));
-    MD_CHK(mbedtls_md_update(ctx, output, hash_size));
-    MD_CHK(mbedtls_md_finish(ctx, output));
-
-    /* Done, get ready for next time */
-    MD_CHK(mbedtls_md_hmac_reset(ctx));
-
-#undef MD_CHK
-
-cleanup:
-    mbedtls_md_free(&aux);
-    return ret;
-}
-#endif /* MBEDTLS_USE_PSA_CRYPTO */
-
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */
-
-#if defined(MBEDTLS_BIGNUM_C)
-
-#define MPI_VALIDATE_RET(cond)                                       \
-    MBEDTLS_INTERNAL_VALIDATE_RET(cond, MBEDTLS_ERR_MPI_BAD_INPUT_DATA)
-
-/*
- * Conditionally assign X = Y, without leaking information
- * about whether the assignment was made or not.
- * (Leaking information about the respective sizes of X and Y is ok however.)
- */
-#if defined(_MSC_VER) && defined(_M_ARM64) && (_MSC_FULL_VER < 193131103)
-/*
- * MSVC miscompiles this function if it's inlined prior to Visual Studio 2022 version 17.1. See:
- * https://developercommunity.visualstudio.com/t/c-compiler-miscompiles-part-of-mbedtls-library-on/1646989
- */
-__declspec(noinline)
-#endif
-int mbedtls_mpi_safe_cond_assign(mbedtls_mpi *X,
-                                 const mbedtls_mpi *Y,
-                                 unsigned char assign)
-{
-    int ret = 0;
-    MPI_VALIDATE_RET(X != NULL);
-    MPI_VALIDATE_RET(Y != NULL);
-
-    /* all-bits 1 if assign is 1, all-bits 0 if assign is 0 */
-    mbedtls_mpi_uint limb_mask = mbedtls_ct_mpi_uint_mask(assign);
-
-    MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
-
-    X->s = (int) mbedtls_ct_uint_if(assign, Y->s, X->s);
-
-    mbedtls_mpi_core_cond_assign(X->p, Y->p, Y->n, assign);
-
-    for (size_t i = Y->n; i < X->n; i++) {
-        X->p[i] &= ~limb_mask;
-    }
-
-cleanup:
-    return ret;
-}
-
-/*
- * Conditionally swap X and Y, without leaking information
- * about whether the swap was made or not.
- * Here it is not ok to simply swap the pointers, which would lead to
- * different memory access patterns when X and Y are used afterwards.
- */
-int mbedtls_mpi_safe_cond_swap(mbedtls_mpi *X,
-                               mbedtls_mpi *Y,
-                               unsigned char swap)
-{
-    int ret = 0;
-    int s;
-    MPI_VALIDATE_RET(X != NULL);
-    MPI_VALIDATE_RET(Y != NULL);
-
-    if (X == Y) {
-        return 0;
-    }
-
-    MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
-    MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Y, X->n));
-
-    s = X->s;
-    X->s = (int) mbedtls_ct_uint_if(swap, Y->s, X->s);
-    Y->s = (int) mbedtls_ct_uint_if(swap, s, Y->s);
-
-    mbedtls_mpi_core_cond_swap(X->p, Y->p, X->n, swap);
-
-cleanup:
-    return ret;
-}
-
-/*
- * Compare unsigned values in constant time
- */
-unsigned mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A,
-                                const mbedtls_mpi_uint *B,
-                                size_t limbs)
-{
-    unsigned ret, cond, done;
-
-    /* The value of any of these variables is either 0 or 1 for the rest of
-     * their scope. */
-    ret = cond = done = 0;
-
-    for (size_t i = limbs; i > 0; i--) {
-        /*
-         * If B[i - 1] < A[i - 1] then A < B is false and the result must
-         * remain 0.
-         *
-         * Again even if we can make a decision, we just mark the result and
-         * the fact that we are done and continue looping.
-         */
-        cond = mbedtls_ct_mpi_uint_lt(B[i - 1], A[i - 1]);
-        done |= cond;
-
-        /*
-         * If A[i - 1] < B[i - 1] then A < B is true.
-         *
-         * Again even if we can make a decision, we just mark the result and
-         * the fact that we are done and continue looping.
-         */
-        cond = mbedtls_ct_mpi_uint_lt(A[i - 1], B[i - 1]);
-        ret |= cond & (1 - done);
-        done |= cond;
-    }
-
-    /*
-     * If all the limbs were equal, then the numbers are equal, A < B is false
-     * and leaving the result 0 is correct.
-     */
-
-    return ret;
-}
-
-/*
- * Compare signed values in constant time
- */
-int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X,
-                          const mbedtls_mpi *Y,
-                          unsigned *ret)
-{
-    size_t i;
-    /* The value of any of these variables is either 0 or 1 at all times. */
-    unsigned cond, done, X_is_negative, Y_is_negative;
-
-    MPI_VALIDATE_RET(X != NULL);
-    MPI_VALIDATE_RET(Y != NULL);
-    MPI_VALIDATE_RET(ret != NULL);
-
-    if (X->n != Y->n) {
-        return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
-    }
-
-    /*
-     * Set sign_N to 1 if N >= 0, 0 if N < 0.
-     * We know that N->s == 1 if N >= 0 and N->s == -1 if N < 0.
-     */
-    X_is_negative = (X->s & 2) >> 1;
-    Y_is_negative = (Y->s & 2) >> 1;
-
-    /*
-     * If the signs are different, then the positive operand is the bigger.
-     * That is if X is negative (X_is_negative == 1), then X < Y is true and it
-     * is false if X is positive (X_is_negative == 0).
-     */
-    cond = (X_is_negative ^ Y_is_negative);
-    *ret = cond & X_is_negative;
-
-    /*
-     * This is a constant-time function. We might have the result, but we still
-     * need to go through the loop. Record if we have the result already.
-     */
-    done = cond;
-
-    for (i = X->n; i > 0; i--) {
-        /*
-         * If Y->p[i - 1] < X->p[i - 1] then X < Y is true if and only if both
-         * X and Y are negative.
-         *
-         * Again even if we can make a decision, we just mark the result and
-         * the fact that we are done and continue looping.
-         */
-        cond = mbedtls_ct_mpi_uint_lt(Y->p[i - 1], X->p[i - 1]);
-        *ret |= cond & (1 - done) & X_is_negative;
-        done |= cond;
-
-        /*
-         * If X->p[i - 1] < Y->p[i - 1] then X < Y is true if and only if both
-         * X and Y are positive.
-         *
-         * Again even if we can make a decision, we just mark the result and
-         * the fact that we are done and continue looping.
-         */
-        cond = mbedtls_ct_mpi_uint_lt(X->p[i - 1], Y->p[i - 1]);
-        *ret |= cond & (1 - done) & (1 - X_is_negative);
-        done |= cond;
-    }
-
-    return 0;
-}
-
-#endif /* MBEDTLS_BIGNUM_C */
-
 #if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
 
-int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input,
-                                         size_t ilen,
-                                         unsigned char *output,
-                                         size_t output_max_len,
-                                         size_t *olen)
+void mbedtls_ct_zeroize_if(mbedtls_ct_condition_t condition, void *buf, size_t len)
 {
-    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    size_t i, plaintext_max_size;
-
-    /* The following variables take sensitive values: their value must
-     * not leak into the observable behavior of the function other than
-     * the designated outputs (output, olen, return value). Otherwise
-     * this would open the execution of the function to
-     * side-channel-based variants of the Bleichenbacher padding oracle
-     * attack. Potential side channels include overall timing, memory
-     * access patterns (especially visible to an adversary who has access
-     * to a shared memory cache), and branches (especially visible to
-     * an adversary who has access to a shared code cache or to a shared
-     * branch predictor). */
-    size_t pad_count = 0;
-    unsigned bad = 0;
-    unsigned char pad_done = 0;
-    size_t plaintext_size = 0;
-    unsigned output_too_large;
-
-    plaintext_max_size = (output_max_len > ilen - 11) ? ilen - 11
-                                                        : output_max_len;
-
-    /* Check and get padding length in constant time and constant
-     * memory trace. The first byte must be 0. */
-    bad |= input[0];
-
-
-    /* Decode EME-PKCS1-v1_5 padding: 0x00 || 0x02 || PS || 0x00
-     * where PS must be at least 8 nonzero bytes. */
-    bad |= input[1] ^ MBEDTLS_RSA_CRYPT;
-
-    /* Read the whole buffer. Set pad_done to nonzero if we find
-     * the 0x00 byte and remember the padding length in pad_count. */
-    for (i = 2; i < ilen; i++) {
-        pad_done  |= ((input[i] | (unsigned char) -input[i]) >> 7) ^ 1;
-        pad_count += ((pad_done | (unsigned char) -pad_done) >> 7) ^ 1;
+    uint32_t mask = (uint32_t) ~condition;
+    uint8_t *p = (uint8_t *) buf;
+    size_t i = 0;
+#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)
+    for (; (i + 4) <= len; i += 4) {
+        mbedtls_put_unaligned_uint32((void *) (p + i),
+                                     mbedtls_get_unaligned_uint32((void *) (p + i)) & mask);
     }
-
-
-    /* If pad_done is still zero, there's no data, only unfinished padding. */
-    bad |= mbedtls_ct_uint_if(pad_done, 0, 1);
-
-    /* There must be at least 8 bytes of padding. */
-    bad |= mbedtls_ct_size_gt(8, pad_count);
-
-    /* If the padding is valid, set plaintext_size to the number of
-     * remaining bytes after stripping the padding. If the padding
-     * is invalid, avoid leaking this fact through the size of the
-     * output: use the maximum message size that fits in the output
-     * buffer. Do it without branches to avoid leaking the padding
-     * validity through timing. RSA keys are small enough that all the
-     * size_t values involved fit in unsigned int. */
-    plaintext_size = mbedtls_ct_uint_if(
-        bad, (unsigned) plaintext_max_size,
-        (unsigned) (ilen - pad_count - 3));
-
-    /* Set output_too_large to 0 if the plaintext fits in the output
-     * buffer and to 1 otherwise. */
-    output_too_large = mbedtls_ct_size_gt(plaintext_size,
-                                          plaintext_max_size);
-
-    /* Set ret without branches to avoid timing attacks. Return:
-     * - INVALID_PADDING if the padding is bad (bad != 0).
-     * - OUTPUT_TOO_LARGE if the padding is good but the decrypted
-     *   plaintext does not fit in the output buffer.
-     * - 0 if the padding is correct. */
-    ret = -(int) mbedtls_ct_uint_if(
-        bad, -MBEDTLS_ERR_RSA_INVALID_PADDING,
-        mbedtls_ct_uint_if(output_too_large,
-                           -MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE,
-                           0));
-
-    /* If the padding is bad or the plaintext is too large, zero the
-     * data that we're about to copy to the output buffer.
-     * We need to copy the same amount of data
-     * from the same buffer whether the padding is good or not to
-     * avoid leaking the padding validity through overall timing or
-     * through memory or cache access patterns. */
-    bad = mbedtls_ct_uint_mask(bad | output_too_large);
-    for (i = 11; i < ilen; i++) {
-        input[i] &= ~bad;
+#endif
+    for (; i < len; i++) {
+        p[i] = p[i] & mask;
     }
-
-    /* If the plaintext is too large, truncate it to the buffer size.
-     * Copy anyway to avoid revealing the length through timing, because
-     * revealing the length is as bad as revealing the padding validity
-     * for a Bleichenbacher attack. */
-    plaintext_size = mbedtls_ct_uint_if(output_too_large,
-                                        (unsigned) plaintext_max_size,
-                                        (unsigned) plaintext_size);
-
-    /* Move the plaintext to the leftmost position where it can start in
-     * the working buffer, i.e. make it start plaintext_max_size from
-     * the end of the buffer. Do this with a memory access trace that
-     * does not depend on the plaintext size. After this move, the
-     * starting location of the plaintext is no longer sensitive
-     * information. */
-    mbedtls_ct_mem_move_to_left(input + ilen - plaintext_max_size,
-                                plaintext_max_size,
-                                plaintext_max_size - plaintext_size);
-
-    /* Finally copy the decrypted plaintext plus trailing zeros into the output
-     * buffer. If output_max_len is 0, then output may be an invalid pointer
-     * and the result of memcpy() would be undefined; prevent undefined
-     * behavior making sure to depend only on output_max_len (the size of the
-     * user-provided output buffer), which is independent from plaintext
-     * length, validity of padding, success of the decryption, and other
-     * secrets. */
-    if (output_max_len != 0) {
-        memcpy(output, input + ilen - plaintext_max_size, plaintext_max_size);
-    }
-
-    /* Report the amount of data we copied to the output buffer. In case
-     * of errors (bad padding or output too large), the value of *olen
-     * when this function returns is not specified. Making it equivalent
-     * to the good case limits the risks of leaking the padding validity. */
-    *olen = plaintext_size;
-
-    return ret;
 }
 
-#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */
+#endif /* defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) */
diff --git a/library/constant_time_impl.h b/library/constant_time_impl.h
new file mode 100644
index 0000000..8da15a8
--- /dev/null
+++ b/library/constant_time_impl.h
@@ -0,0 +1,437 @@
+/**
+ *  Constant-time functions
+ *
+ *  For readability, the static inline definitions are here, and
+ *  constant_time_internal.h has only the declarations.
+ *
+ *  This results in duplicate declarations of the form:
+ *      static inline void f() { ... }
+ *      static inline void f();
+ *  when constant_time_internal.h is included. This appears to behave
+ *  exactly as if the declaration-without-definition was not present.
+ *
+ *  Copyright The Mbed TLS Contributors
+ *  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.
+ */
+
+#ifndef MBEDTLS_CONSTANT_TIME_IMPL_H
+#define MBEDTLS_CONSTANT_TIME_IMPL_H
+
+#include <stddef.h>
+
+#include "common.h"
+
+#if defined(MBEDTLS_BIGNUM_C)
+#include "mbedtls/bignum.h"
+#endif
+
+/* constant_time_impl.h contains all the static inline implementations,
+ * so that constant_time_internal.h is more readable.
+ *
+ * gcc generates warnings about duplicate declarations, so disable this
+ * warning.
+ */
+#ifdef __GNUC__
+    #pragma GCC diagnostic push
+    #pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
+
+/* Disable asm under Memsan because it confuses Memsan and generates false errors.
+ *
+ * We also disable under Valgrind by default, because it's more useful
+ * for Valgrind to test the plain C implementation. MBEDTLS_TEST_CONSTANT_FLOW_ASM //no-check-names
+ * may be set to permit building asm under Valgrind.
+ */
+#if defined(MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN) || \
+    (defined(MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND) && !defined(MBEDTLS_TEST_CONSTANT_FLOW_ASM)) //no-check-names
+#define MBEDTLS_CT_NO_ASM
+#elif defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+#define MBEDTLS_CT_NO_ASM
+#endif
+#endif
+
+/* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */
+#if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && (!defined(__ARMCC_VERSION) || \
+    __ARMCC_VERSION >= 6000000) && !defined(MBEDTLS_CT_NO_ASM)
+#define MBEDTLS_CT_ASM
+#if (defined(__arm__) || defined(__thumb__) || defined(__thumb2__))
+#define MBEDTLS_CT_ARM_ASM
+#elif defined(__aarch64__)
+#define MBEDTLS_CT_AARCH64_ASM
+#endif
+#endif
+
+#define MBEDTLS_CT_SIZE (sizeof(mbedtls_ct_uint_t) * 8)
+
+
+/* ============================================================================
+ * Core const-time primitives
+ */
+
+/* Ensure that the compiler cannot know the value of x (i.e., cannot optimise
+ * based on its value) after this function is called.
+ *
+ * If we are not using assembly, this will be fairly inefficient, so its use
+ * should be minimised.
+ */
+
+#if !defined(MBEDTLS_CT_ASM)
+extern volatile mbedtls_ct_uint_t mbedtls_ct_zero;
+#endif
+
+/**
+ * \brief   Ensure that a value cannot be known at compile time.
+ *
+ * \param x        The value to hide from the compiler.
+ * \return         The same value that was passed in, such that the compiler
+ *                 cannot prove its value (even for calls of the form
+ *                 x = mbedtls_ct_compiler_opaque(1), x will be unknown).
+ *
+ * \note           This is mainly used in constructing mbedtls_ct_condition_t
+ *                 values and performing operations over them, to ensure that
+ *                 there is no way for the compiler to ever know anything about
+ *                 the value of an mbedtls_ct_condition_t.
+ */
+static inline mbedtls_ct_uint_t mbedtls_ct_compiler_opaque(mbedtls_ct_uint_t x)
+{
+#if defined(MBEDTLS_CT_ASM)
+    asm volatile ("" : [x] "+r" (x) :);
+    return x;
+#else
+    return x ^ mbedtls_ct_zero;
+#endif
+}
+
+/*
+ * Selecting unified syntax is needed for gcc, and harmless on clang.
+ *
+ * This is needed because on Thumb 1, condition flags are always set, so
+ * e.g. "negs" is supported but "neg" is not (on Thumb 2, both exist).
+ *
+ * Under Thumb 1 unified syntax, only the "negs" form is accepted, and
+ * under divided syntax, only the "neg" form is accepted. clang only
+ * supports unified syntax.
+ *
+ * On Thumb 2 and Arm, both compilers are happy with the "s" suffix,
+ * although we don't actually care about setting the flags.
+ *
+ * For gcc, restore divided syntax afterwards - otherwise old versions of gcc
+ * seem to apply unified syntax globally, which breaks other asm code.
+ */
+#if !defined(__clang__)
+#define RESTORE_ASM_SYNTAX  ".syntax divided             \n\t"
+#else
+#define RESTORE_ASM_SYNTAX
+#endif
+
+/* Convert a number into a condition in constant time. */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool(mbedtls_ct_uint_t x)
+{
+    /*
+     * Define mask-generation code that, as far as possible, will not use branches or conditional instructions.
+     *
+     * For some platforms / type sizes, we define assembly to assure this.
+     *
+     * Otherwise, we define a plain C fallback which (in May 2023) does not get optimised into
+     * conditional instructions or branches by trunk clang, gcc, or MSVC v19.
+     */
+#if defined(MBEDTLS_CT_AARCH64_ASM) && (defined(MBEDTLS_CT_SIZE_32) || defined(MBEDTLS_CT_SIZE_64))
+    mbedtls_ct_uint_t s;
+    asm volatile ("neg %x[s], %x[x]                     \n\t"
+                  "orr %x[x], %x[s], %x[x]              \n\t"
+                  "asr %x[x], %x[x], 63"
+                  :
+                  [s] "=&r" (s),
+                  [x] "+&r" (x)
+                  :
+                  :
+                  );
+    return (mbedtls_ct_condition_t) x;
+#elif defined(MBEDTLS_CT_ARM_ASM) && defined(MBEDTLS_CT_SIZE_32)
+    uint32_t s;
+    asm volatile (".syntax unified                       \n\t"
+                  "negs %[s], %[x]                       \n\t"
+                  "orrs %[x], %[x], %[s]                 \n\t"
+                  "asrs %[x], %[x], #31                  \n\t"
+                  RESTORE_ASM_SYNTAX
+                  :
+                  [s] "=&l" (s),
+                  [x] "+&l" (x)
+                  :
+                  :
+                  "cc" /* clobbers flag bits */
+                  );
+    return (mbedtls_ct_condition_t) x;
+#else
+    const mbedtls_ct_uint_t xo = mbedtls_ct_compiler_opaque(x);
+#if defined(_MSC_VER)
+    /* MSVC has a warning about unary minus on unsigned, but this is
+     * well-defined and precisely what we want to do here */
+#pragma warning( push )
+#pragma warning( disable : 4146 )
+#endif
+    // y is negative (i.e., top bit set) iff x is non-zero
+    mbedtls_ct_int_t y = (-xo) | -(xo >> 1);
+
+    // extract only the sign bit of y so that y == 1 (if x is non-zero) or 0 (if x is zero)
+    y = (((mbedtls_ct_uint_t) y) >> (MBEDTLS_CT_SIZE - 1));
+
+    // -y has all bits set (if x is non-zero), or all bits clear (if x is zero)
+    return (mbedtls_ct_condition_t) (-y);
+#if defined(_MSC_VER)
+#pragma warning( pop )
+#endif
+#endif
+}
+
+static inline mbedtls_ct_uint_t mbedtls_ct_if(mbedtls_ct_condition_t condition,
+                                              mbedtls_ct_uint_t if1,
+                                              mbedtls_ct_uint_t if0)
+{
+#if defined(MBEDTLS_CT_AARCH64_ASM) && (defined(MBEDTLS_CT_SIZE_32) || defined(MBEDTLS_CT_SIZE_64))
+    asm volatile ("and %x[if1], %x[if1], %x[condition]       \n\t"
+                  "mvn %x[condition], %x[condition]          \n\t"
+                  "and %x[condition], %x[condition], %x[if0] \n\t"
+                  "orr %x[condition], %x[if1], %x[condition]"
+                  :
+                  [condition] "+&r" (condition),
+                  [if1] "+&r" (if1)
+                  :
+                  [if0] "r" (if0)
+                  :
+                  );
+    return (mbedtls_ct_uint_t) condition;
+#elif defined(MBEDTLS_CT_ARM_ASM) && defined(MBEDTLS_CT_SIZE_32)
+    asm volatile (".syntax unified                           \n\t"
+                  "ands %[if1], %[if1], %[condition]         \n\t"
+                  "mvns %[condition], %[condition]           \n\t"
+                  "ands %[condition], %[condition], %[if0]   \n\t"
+                  "orrs %[condition], %[if1], %[condition]   \n\t"
+                  RESTORE_ASM_SYNTAX
+                  :
+                  [condition] "+&l" (condition),
+                  [if1] "+&l" (if1)
+                  :
+                  [if0] "l" (if0)
+                  :
+                  "cc"
+                  );
+    return (mbedtls_ct_uint_t) condition;
+#else
+    mbedtls_ct_condition_t not_cond =
+        (mbedtls_ct_condition_t) (~mbedtls_ct_compiler_opaque(condition));
+    return (mbedtls_ct_uint_t) ((condition & if1) | (not_cond & if0));
+#endif
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_uint_lt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y)
+{
+#if defined(MBEDTLS_CT_AARCH64_ASM) && (defined(MBEDTLS_CT_SIZE_32) || defined(MBEDTLS_CT_SIZE_64))
+    uint64_t s1;
+    asm volatile ("eor     %x[s1], %x[y], %x[x]          \n\t"
+                  "sub     %x[x], %x[x], %x[y]           \n\t"
+                  "bic     %x[x], %x[x], %x[s1]          \n\t"
+                  "and     %x[s1], %x[s1], %x[y]         \n\t"
+                  "orr     %x[s1], %x[x], %x[s1]         \n\t"
+                  "asr     %x[x], %x[s1], 63"
+                  : [s1] "=&r" (s1), [x] "+&r" (x)
+                  : [y] "r" (y)
+                  :
+                  );
+    return (mbedtls_ct_condition_t) x;
+#elif defined(MBEDTLS_CT_ARM_ASM) && defined(MBEDTLS_CT_SIZE_32)
+    uint32_t s1;
+    asm volatile (
+        ".syntax unified                    \n\t"
+#if defined(__thumb__) && !defined(__thumb2__)
+        "movs     %[s1], %[x]               \n\t"
+        "eors     %[s1], %[s1], %[y]        \n\t"
+#else
+        "eors     %[s1], %[x], %[y]         \n\t"
+#endif
+        "subs    %[x], %[x], %[y]           \n\t"
+        "bics    %[x], %[x], %[s1]          \n\t"
+        "ands    %[y], %[s1], %[y]          \n\t"
+        "orrs    %[x], %[x], %[y]           \n\t"
+        "asrs    %[x], %[x], #31            \n\t"
+        RESTORE_ASM_SYNTAX
+        : [s1] "=&l" (s1), [x] "+&l" (x),  [y] "+&l" (y)
+        :
+        :
+        "cc"
+        );
+    return (mbedtls_ct_condition_t) x;
+#else
+    /* Ensure that the compiler cannot optimise the following operations over x and y,
+     * even if it knows the value of x and y.
+     */
+    const mbedtls_ct_uint_t xo = mbedtls_ct_compiler_opaque(x);
+    const mbedtls_ct_uint_t yo = mbedtls_ct_compiler_opaque(y);
+    /*
+     * Check if the most significant bits (MSB) of the operands are different.
+     * cond is true iff the MSBs differ.
+     */
+    mbedtls_ct_condition_t cond = mbedtls_ct_bool((xo ^ yo) >> (MBEDTLS_CT_SIZE - 1));
+
+    /*
+     * If the MSB are the same then the difference x-y will be negative (and
+     * have its MSB set to 1 during conversion to unsigned) if and only if x<y.
+     *
+     * If the MSB are different, then the operand with the MSB of 1 is the
+     * bigger. (That is if y has MSB of 1, then x<y is true and it is false if
+     * the MSB of y is 0.)
+     */
+
+    // Select either y, or x - y
+    mbedtls_ct_uint_t ret = mbedtls_ct_if(cond, yo, (mbedtls_ct_uint_t) (xo - yo));
+
+    // Extract only the MSB of ret
+    ret = ret >> (MBEDTLS_CT_SIZE - 1);
+
+    // Convert to a condition (i.e., all bits set iff non-zero)
+    return mbedtls_ct_bool(ret);
+#endif
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_uint_ne(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y)
+{
+    /* diff = 0 if x == y, non-zero otherwise */
+    const mbedtls_ct_uint_t diff = mbedtls_ct_compiler_opaque(x) ^ mbedtls_ct_compiler_opaque(y);
+
+    /* all ones if x != y, 0 otherwise */
+    return mbedtls_ct_bool(diff);
+}
+
+static inline unsigned char mbedtls_ct_uchar_in_range_if(unsigned char low,
+                                                         unsigned char high,
+                                                         unsigned char c,
+                                                         unsigned char t)
+{
+    const unsigned char co = (unsigned char) mbedtls_ct_compiler_opaque(c);
+    const unsigned char to = (unsigned char) mbedtls_ct_compiler_opaque(t);
+
+    /* low_mask is: 0 if low <= c, 0x...ff if low > c */
+    unsigned low_mask = ((unsigned) co - low) >> 8;
+    /* high_mask is: 0 if c <= high, 0x...ff if c > high */
+    unsigned high_mask = ((unsigned) high - co) >> 8;
+
+    return (unsigned char) (~(low_mask | high_mask)) & to;
+}
+
+
+/* ============================================================================
+ * Everything below here is trivial wrapper functions
+ */
+
+static inline size_t mbedtls_ct_size_if(mbedtls_ct_condition_t condition,
+                                        size_t if1,
+                                        size_t if0)
+{
+    return (size_t) mbedtls_ct_if(condition, (mbedtls_ct_uint_t) if1, (mbedtls_ct_uint_t) if0);
+}
+
+static inline unsigned mbedtls_ct_uint_if(mbedtls_ct_condition_t condition,
+                                          unsigned if1,
+                                          unsigned if0)
+{
+    return (unsigned) mbedtls_ct_if(condition, (mbedtls_ct_uint_t) if1, (mbedtls_ct_uint_t) if0);
+}
+
+#if defined(MBEDTLS_BIGNUM_C)
+
+static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t condition,
+                                                      mbedtls_mpi_uint if1,
+                                                      mbedtls_mpi_uint if0)
+{
+    return (mbedtls_mpi_uint) mbedtls_ct_if(condition,
+                                            (mbedtls_ct_uint_t) if1,
+                                            (mbedtls_ct_uint_t) if0);
+}
+
+#endif
+
+static inline size_t mbedtls_ct_size_if_else_0(mbedtls_ct_condition_t condition, size_t if1)
+{
+    return (size_t) (condition & if1);
+}
+
+static inline unsigned mbedtls_ct_uint_if_else_0(mbedtls_ct_condition_t condition, unsigned if1)
+{
+    return (unsigned) (condition & if1);
+}
+
+#if defined(MBEDTLS_BIGNUM_C)
+
+static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if_else_0(mbedtls_ct_condition_t condition,
+                                                             mbedtls_mpi_uint if1)
+{
+    return (mbedtls_mpi_uint) (condition & if1);
+}
+
+#endif /* MBEDTLS_BIGNUM_C */
+
+static inline mbedtls_ct_condition_t mbedtls_ct_uint_eq(mbedtls_ct_uint_t x,
+                                                        mbedtls_ct_uint_t y)
+{
+    return ~mbedtls_ct_uint_ne(x, y);
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_uint_gt(mbedtls_ct_uint_t x,
+                                                        mbedtls_ct_uint_t y)
+{
+    return mbedtls_ct_uint_lt(y, x);
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_uint_ge(mbedtls_ct_uint_t x,
+                                                        mbedtls_ct_uint_t y)
+{
+    return ~mbedtls_ct_uint_lt(x, y);
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_uint_le(mbedtls_ct_uint_t x,
+                                                        mbedtls_ct_uint_t y)
+{
+    return ~mbedtls_ct_uint_gt(x, y);
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_xor(mbedtls_ct_condition_t x,
+                                                         mbedtls_ct_condition_t y)
+{
+    return (mbedtls_ct_condition_t) (x ^ y);
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_and(mbedtls_ct_condition_t x,
+                                                         mbedtls_ct_condition_t y)
+{
+    return (mbedtls_ct_condition_t) (x & y);
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_or(mbedtls_ct_condition_t x,
+                                                        mbedtls_ct_condition_t y)
+{
+    return (mbedtls_ct_condition_t) (x | y);
+}
+
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_not(mbedtls_ct_condition_t x)
+{
+    return (mbedtls_ct_condition_t) (~x);
+}
+
+#ifdef __GNUC__
+    #pragma GCC diagnostic pop
+#endif
+
+#endif /* MBEDTLS_CONSTANT_TIME_IMPL_H */
diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h
index c4a32c7..44b74ae 100644
--- a/library/constant_time_internal.h
+++ b/library/constant_time_internal.h
@@ -20,224 +20,444 @@
 #ifndef MBEDTLS_CONSTANT_TIME_INTERNAL_H
 #define MBEDTLS_CONSTANT_TIME_INTERNAL_H
 
+#include <stdint.h>
+#include <stddef.h>
+
 #include "common.h"
 
 #if defined(MBEDTLS_BIGNUM_C)
 #include "mbedtls/bignum.h"
 #endif
 
-#if defined(MBEDTLS_SSL_TLS_C)
-#include "ssl_misc.h"
+/* The constant-time interface provides various operations that are likely
+ * to result in constant-time code that does not branch or use conditional
+ * instructions for secret data (for secret pointers, this also applies to
+ * the data pointed to).
+ *
+ * It has three main parts:
+ *
+ * - boolean operations
+ *   These are all named mbedtls_ct_<type>_<operation>.
+ *   They operate over <type> and return mbedtls_ct_condition_t.
+ *   All arguments are considered secret.
+ *   example: bool x = y | z          =>    x = mbedtls_ct_bool_or(y, z)
+ *   example: bool x = y == z         =>    x = mbedtls_ct_uint_eq(y, z)
+ *
+ * - conditional data selection
+ *   These are all named mbedtls_ct_<type>_if and mbedtls_ct_<type>_if_else_0
+ *   All arguments are considered secret.
+ *   example: size_t a = x ? b : c    =>    a = mbedtls_ct_size_if(x, b, c)
+ *   example: unsigned a = x ? b : 0  =>    a = mbedtls_ct_uint__if_else_0(x, b)
+ *
+ * - block memory operations
+ *   Only some arguments are considered secret, as documented for each
+ *   function.
+ *   example: if (x) memcpy(...)      =>    mbedtls_ct_memcpy_if(x, ...)
+ *
+ * mbedtls_ct_condition_t must be treated as opaque and only created and
+ * manipulated via the functions in this header. The compiler should never
+ * be able to prove anything about its value at compile-time.
+ *
+ * mbedtls_ct_uint_t is an unsigned integer type over which constant time
+ * operations may be performed via the functions in this header. It is as big
+ * as the larger of size_t and mbedtls_mpi_uint, i.e. it is safe to cast
+ * to/from "unsigned int", "size_t", and "mbedtls_mpi_uint" (and any other
+ * not-larger integer types).
+ *
+ * For Arm (32-bit, 64-bit and Thumb), x86 and x86-64, assembly implementations
+ * are used to ensure that the generated code is constant time. For other
+ * architectures, it uses a plain C fallback designed to yield constant-time code
+ * (this has been observed to be constant-time on latest gcc, clang and MSVC
+ * as of May 2023).
+ *
+ * For readability, the static inline definitions are separated out into
+ * constant_time_impl.h.
+ */
+
+#if (SIZE_MAX > 0xffffffffffffffffULL)
+/* Pointer size > 64-bit */
+typedef size_t    mbedtls_ct_condition_t;
+typedef size_t    mbedtls_ct_uint_t;
+typedef ptrdiff_t mbedtls_ct_int_t;
+#define MBEDTLS_CT_TRUE  ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(SIZE_MAX))
+#elif (SIZE_MAX > 0xffffffff) || defined(MBEDTLS_HAVE_INT64)
+/* 32-bit < pointer size <= 64-bit, or 64-bit MPI */
+typedef uint64_t  mbedtls_ct_condition_t;
+typedef uint64_t  mbedtls_ct_uint_t;
+typedef int64_t   mbedtls_ct_int_t;
+#define MBEDTLS_CT_SIZE_64
+#define MBEDTLS_CT_TRUE  ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(UINT64_MAX))
+#else
+/* Pointer size <= 32-bit, and no 64-bit MPIs */
+typedef uint32_t  mbedtls_ct_condition_t;
+typedef uint32_t  mbedtls_ct_uint_t;
+typedef int32_t   mbedtls_ct_int_t;
+#define MBEDTLS_CT_SIZE_32
+#define MBEDTLS_CT_TRUE  ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(UINT32_MAX))
 #endif
+#define MBEDTLS_CT_FALSE ((mbedtls_ct_condition_t) mbedtls_ct_compiler_opaque(0))
 
-#include <stddef.h>
-
-
-/** Turn a value into a mask:
- * - if \p value == 0, return the all-bits 0 mask, aka 0
- * - otherwise, return the all-bits 1 mask, aka (unsigned) -1
- *
- * This function can be used to write constant-time code by replacing branches
- * with bit operations using masks.
- *
- * \param value     The value to analyze.
- *
- * \return          Zero if \p value is zero, otherwise all-bits-one.
+/* ============================================================================
+ * Boolean operations
  */
-unsigned mbedtls_ct_uint_mask(unsigned value);
 
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
-
-/** Turn a value into a mask:
- * - if \p value == 0, return the all-bits 0 mask, aka 0
- * - otherwise, return the all-bits 1 mask, aka (size_t) -1
+/** Convert a number into a mbedtls_ct_condition_t.
  *
- * This function can be used to write constant-time code by replacing branches
- * with bit operations using masks.
+ * \param x Number to convert.
  *
- * \param value     The value to analyze.
+ * \return MBEDTLS_CT_TRUE if \p x != 0, or MBEDTLS_CT_FALSE if \p x == 0
  *
- * \return          Zero if \p value is zero, otherwise all-bits-one.
  */
-size_t mbedtls_ct_size_mask(size_t value);
+static inline mbedtls_ct_condition_t mbedtls_ct_bool(mbedtls_ct_uint_t x);
 
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */
-
-#if defined(MBEDTLS_BIGNUM_C)
-
-/** Turn a value into a mask:
- * - if \p value == 0, return the all-bits 0 mask, aka 0
- * - otherwise, return the all-bits 1 mask, aka (mbedtls_mpi_uint) -1
+/** Boolean "not equal" operation.
  *
- * This function can be used to write constant-time code by replacing branches
- * with bit operations using masks.
+ * Functionally equivalent to:
  *
- * \param value     The value to analyze.
- *
- * \return          Zero if \p value is zero, otherwise all-bits-one.
- */
-mbedtls_mpi_uint mbedtls_ct_mpi_uint_mask(mbedtls_mpi_uint value);
-
-#endif /* MBEDTLS_BIGNUM_C */
-
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC)
-
-/** Constant-flow mask generation for "greater or equal" comparison:
- * - if \p x >= \p y, return all-bits 1, that is (size_t) -1
- * - otherwise, return all bits 0, that is 0
- *
- * This function can be used to write constant-time code by replacing branches
- * with bit operations using masks.
+ * \p x != \p y
  *
  * \param x     The first value to analyze.
  * \param y     The second value to analyze.
  *
- * \return      All-bits-one if \p x is greater or equal than \p y,
- *              otherwise zero.
+ * \return      MBEDTLS_CT_TRUE if \p x != \p y, otherwise MBEDTLS_CT_FALSE.
  */
-size_t mbedtls_ct_size_mask_ge(size_t x,
-                               size_t y);
+static inline mbedtls_ct_condition_t mbedtls_ct_uint_ne(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y);
 
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */
-
-/** Constant-flow boolean "equal" comparison:
- * return x == y
+/** Boolean "equals" operation.
  *
- * This is equivalent to \p x == \p y, but is likely to be compiled
- * to code using bitwise operation rather than a branch.
+ * Functionally equivalent to:
+ *
+ * \p x == \p y
  *
  * \param x     The first value to analyze.
  * \param y     The second value to analyze.
  *
- * \return      1 if \p x equals to \p y, otherwise 0.
+ * \return      MBEDTLS_CT_TRUE if \p x == \p y, otherwise MBEDTLS_CT_FALSE.
  */
-unsigned mbedtls_ct_size_bool_eq(size_t x,
-                                 size_t y);
+static inline mbedtls_ct_condition_t mbedtls_ct_uint_eq(mbedtls_ct_uint_t x,
+                                                        mbedtls_ct_uint_t y);
 
-#if defined(MBEDTLS_BIGNUM_C)
-
-/** Decide if an integer is less than the other, without branches.
+/** Boolean "less than" operation.
  *
- * This is equivalent to \p x < \p y, but is likely to be compiled
- * to code using bitwise operation rather than a branch.
+ * Functionally equivalent to:
+ *
+ * \p x < \p y
  *
  * \param x     The first value to analyze.
  * \param y     The second value to analyze.
  *
- * \return      1 if \p x is less than \p y, otherwise 0.
+ * \return      MBEDTLS_CT_TRUE if \p x < \p y, otherwise MBEDTLS_CT_FALSE.
  */
-unsigned mbedtls_ct_mpi_uint_lt(const mbedtls_mpi_uint x,
-                                const mbedtls_mpi_uint y);
+static inline mbedtls_ct_condition_t mbedtls_ct_uint_lt(mbedtls_ct_uint_t x, mbedtls_ct_uint_t y);
 
-/**
- * \brief          Check if one unsigned MPI is less than another in constant
- *                 time.
+/** Boolean "greater than" operation.
  *
- * \param A        The left-hand MPI. This must point to an array of limbs
- *                 with the same allocated length as \p B.
- * \param B        The right-hand MPI. This must point to an array of limbs
- *                 with the same allocated length as \p A.
- * \param limbs    The number of limbs in \p A and \p B.
- *                 This must not be 0.
+ * Functionally equivalent to:
  *
- * \return         The result of the comparison:
- *                 \c 1 if \p A is less than \p B.
- *                 \c 0 if \p A is greater than or equal to \p B.
+ * \p x > \p y
+ *
+ * \param x     The first value to analyze.
+ * \param y     The second value to analyze.
+ *
+ * \return      MBEDTLS_CT_TRUE if \p x > \p y, otherwise MBEDTLS_CT_FALSE.
  */
-unsigned mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A,
-                                const mbedtls_mpi_uint *B,
-                                size_t limbs);
-#endif /* MBEDTLS_BIGNUM_C */
+static inline mbedtls_ct_condition_t mbedtls_ct_uint_gt(mbedtls_ct_uint_t x,
+                                                        mbedtls_ct_uint_t y);
 
-/** Choose between two integer values without branches.
+/** Boolean "greater or equal" operation.
  *
- * This is equivalent to `condition ? if1 : if0`, but is likely to be compiled
- * to code using bitwise operation rather than a branch.
+ * Functionally equivalent to:
+ *
+ * \p x >= \p y
+ *
+ * \param x     The first value to analyze.
+ * \param y     The second value to analyze.
+ *
+ * \return      MBEDTLS_CT_TRUE if \p x >= \p y,
+ *              otherwise MBEDTLS_CT_FALSE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_uint_ge(mbedtls_ct_uint_t x,
+                                                        mbedtls_ct_uint_t y);
+
+/** Boolean "less than or equal" operation.
+ *
+ * Functionally equivalent to:
+ *
+ * \p x <= \p y
+ *
+ * \param x     The first value to analyze.
+ * \param y     The second value to analyze.
+ *
+ * \return      MBEDTLS_CT_TRUE if \p x <= \p y,
+ *              otherwise MBEDTLS_CT_FALSE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_uint_le(mbedtls_ct_uint_t x,
+                                                        mbedtls_ct_uint_t y);
+
+/** Boolean "xor" operation.
+ *
+ * Functionally equivalent to:
+ *
+ * \p x ^ \p y
+ *
+ * \param x     The first value to analyze.
+ * \param y     The second value to analyze.
+ *
+ * \note        This is more efficient than mbedtls_ct_uint_ne if both arguments are
+ *              mbedtls_ct_condition_t.
+ *
+ * \return      MBEDTLS_CT_TRUE if \p x ^ \p y,
+ *              otherwise MBEDTLS_CT_FALSE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_xor(mbedtls_ct_condition_t x,
+                                                         mbedtls_ct_condition_t y);
+
+/** Boolean "and" operation.
+ *
+ * Functionally equivalent to:
+ *
+ * \p x && \p y
+ *
+ * \param x     The first value to analyze.
+ * \param y     The second value to analyze.
+ *
+ * \return      MBEDTLS_CT_TRUE if \p x && \p y,
+ *              otherwise MBEDTLS_CT_FALSE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_and(mbedtls_ct_condition_t x,
+                                                         mbedtls_ct_condition_t y);
+
+/** Boolean "or" operation.
+ *
+ * Functionally equivalent to:
+ *
+ * \p x || \p y
+ *
+ * \param x     The first value to analyze.
+ * \param y     The second value to analyze.
+ *
+ * \return      MBEDTLS_CT_TRUE if \p x || \p y,
+ *              otherwise MBEDTLS_CT_FALSE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_or(mbedtls_ct_condition_t x,
+                                                        mbedtls_ct_condition_t y);
+
+/** Boolean "not" operation.
+ *
+ * Functionally equivalent to:
+ *
+ * ! \p x
+ *
+ * \param x     The value to invert
+ *
+ * \return      MBEDTLS_CT_FALSE if \p x, otherwise MBEDTLS_CT_TRUE.
+ */
+static inline mbedtls_ct_condition_t mbedtls_ct_bool_not(mbedtls_ct_condition_t x);
+
+
+/* ============================================================================
+ * Data selection operations
+ */
+
+/** Choose between two size_t values.
+ *
+ * Functionally equivalent to:
+ *
+ * condition ? if1 : if0.
  *
  * \param condition     Condition to test.
- * \param if1           Value to use if \p condition is nonzero.
- * \param if0           Value to use if \p condition is zero.
+ * \param if1           Value to use if \p condition == MBEDTLS_CT_TRUE.
+ * \param if0           Value to use if \p condition == MBEDTLS_CT_FALSE.
  *
- * \return  \c if1 if \p condition is nonzero, otherwise \c if0.
+ * \return  \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
  */
-unsigned mbedtls_ct_uint_if(unsigned condition,
-                            unsigned if1,
-                            unsigned if0);
+static inline size_t mbedtls_ct_size_if(mbedtls_ct_condition_t condition,
+                                        size_t if1,
+                                        size_t if0);
+
+/** Choose between two unsigned values.
+ *
+ * Functionally equivalent to:
+ *
+ * condition ? if1 : if0.
+ *
+ * \param condition     Condition to test.
+ * \param if1           Value to use if \p condition == MBEDTLS_CT_TRUE.
+ * \param if0           Value to use if \p condition == MBEDTLS_CT_FALSE.
+ *
+ * \return  \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
+ */
+static inline unsigned mbedtls_ct_uint_if(mbedtls_ct_condition_t condition,
+                                          unsigned if1,
+                                          unsigned if0);
 
 #if defined(MBEDTLS_BIGNUM_C)
 
-/** Conditionally assign a value without branches.
+/** Choose between two mbedtls_mpi_uint values.
  *
- * This is equivalent to `if ( condition ) dest = src`, but is likely
- * to be compiled to code using bitwise operation rather than a branch.
+ * Functionally equivalent to:
  *
- * \param n             \p dest and \p src must be arrays of limbs of size n.
- * \param dest          The MPI to conditionally assign to. This must point
- *                      to an initialized MPI.
- * \param src           The MPI to be assigned from. This must point to an
- *                      initialized MPI.
- * \param condition     Condition to test, must be 0 or 1.
+ * condition ? if1 : if0.
+ *
+ * \param condition     Condition to test.
+ * \param if1           Value to use if \p condition == MBEDTLS_CT_TRUE.
+ * \param if0           Value to use if \p condition == MBEDTLS_CT_FALSE.
+ *
+ * \return  \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise \c if0.
  */
-void mbedtls_ct_mpi_uint_cond_assign(size_t n,
-                                     mbedtls_mpi_uint *dest,
-                                     const mbedtls_mpi_uint *src,
-                                     unsigned char condition);
+static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if(mbedtls_ct_condition_t condition, \
+                                                      mbedtls_mpi_uint if1, \
+                                                      mbedtls_mpi_uint if0);
 
-#endif /* MBEDTLS_BIGNUM_C */
+#endif
 
-#if defined(MBEDTLS_BASE64_C)
-
-/** Given a value in the range 0..63, return the corresponding Base64 digit.
+/** Choose between an unsigned value and 0.
  *
- * The implementation assumes that letters are consecutive (e.g. ASCII
- * but not EBCDIC).
+ * Functionally equivalent to:
  *
- * \param value     A value in the range 0..63.
+ * condition ? if1 : 0.
  *
- * \return          A base64 digit converted from \p value.
+ * Functionally equivalent to mbedtls_ct_uint_if(condition, if1, 0) but
+ * results in smaller code size.
+ *
+ * \param condition     Condition to test.
+ * \param if1           Value to use if \p condition == MBEDTLS_CT_TRUE.
+ *
+ * \return  \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
  */
-unsigned char mbedtls_ct_base64_enc_char(unsigned char value);
+static inline unsigned mbedtls_ct_uint_if_else_0(mbedtls_ct_condition_t condition, unsigned if1);
 
-/** Given a Base64 digit, return its value.
+/** Choose between a size_t value and 0.
  *
- * If c is not a Base64 digit ('A'..'Z', 'a'..'z', '0'..'9', '+' or '/'),
- * return -1.
+ * Functionally equivalent to:
  *
- * The implementation assumes that letters are consecutive (e.g. ASCII
- * but not EBCDIC).
+ * condition ? if1 : 0.
  *
- * \param c     A base64 digit.
+ * Functionally equivalent to mbedtls_ct_size_if(condition, if1, 0) but
+ * results in smaller code size.
  *
- * \return      The value of the base64 digit \p c.
+ * \param condition     Condition to test.
+ * \param if1           Value to use if \p condition == MBEDTLS_CT_TRUE.
+ *
+ * \return  \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
  */
-signed char mbedtls_ct_base64_dec_value(unsigned char c);
+static inline size_t mbedtls_ct_size_if_else_0(mbedtls_ct_condition_t condition, size_t if1);
 
-#endif /* MBEDTLS_BASE64_C */
+#if defined(MBEDTLS_BIGNUM_C)
 
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
-
-/** Conditional memcpy without branches.
+/** Choose between an mbedtls_mpi_uint value and 0.
  *
- * This is equivalent to `if ( c1 == c2 ) memcpy(dest, src, len)`, but is likely
- * to be compiled to code using bitwise operation rather than a branch.
+ * Functionally equivalent to:
  *
- * \param dest      The pointer to conditionally copy to.
- * \param src       The pointer to copy from. Shouldn't overlap with \p dest.
- * \param len       The number of bytes to copy.
- * \param c1        The first value to analyze in the condition.
- * \param c2        The second value to analyze in the condition.
+ * condition ? if1 : 0.
+ *
+ * Functionally equivalent to mbedtls_ct_mpi_uint_if(condition, if1, 0) but
+ * results in smaller code size.
+ *
+ * \param condition     Condition to test.
+ * \param if1           Value to use if \p condition == MBEDTLS_CT_TRUE.
+ *
+ * \return  \c if1 if \p condition == MBEDTLS_CT_TRUE, otherwise 0.
  */
-void mbedtls_ct_memcpy_if_eq(unsigned char *dest,
-                             const unsigned char *src,
-                             size_t len,
-                             size_t c1, size_t c2);
+static inline mbedtls_mpi_uint mbedtls_ct_mpi_uint_if_else_0(mbedtls_ct_condition_t condition,
+                                                             mbedtls_mpi_uint if1);
 
-/** Copy data from a secret position with constant flow.
+#endif
+
+/** Constant-flow char selection
  *
- * This function copies \p len bytes from \p src_base + \p offset_secret to \p
- * dst, with a code flow and memory access pattern that does not depend on \p
- * offset_secret, but only on \p offset_min, \p offset_max and \p len.
- * Functionally equivalent to `memcpy(dst, src + offset_secret, len)`.
+ * \param low   Secret. Bottom of range
+ * \param high  Secret. Top of range
+ * \param c     Secret. Value to compare to range
+ * \param t     Secret. Value to return, if in range
+ *
+ * \return      \p t if \p low <= \p c <= \p high, 0 otherwise.
+ */
+static inline unsigned char mbedtls_ct_uchar_in_range_if(unsigned char low,
+                                                         unsigned char high,
+                                                         unsigned char c,
+                                                         unsigned char t);
+
+
+/* ============================================================================
+ * Block memory operations
+ */
+
+#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
+
+/** Conditionally set a block of memory to zero.
+ *
+ * Regardless of the condition, every byte will be read once and written to
+ * once.
+ *
+ * \param condition     Secret. Condition to test.
+ * \param buf           Secret. Pointer to the start of the buffer.
+ * \param len           Number of bytes to set to zero.
+ *
+ * \warning Unlike mbedtls_platform_zeroize, this does not have the same guarantees
+ * about not being optimised away if the memory is never read again.
+ */
+void mbedtls_ct_zeroize_if(mbedtls_ct_condition_t condition, void *buf, size_t len);
+
+/** Shift some data towards the left inside a buffer.
+ *
+ * Functionally equivalent to:
+ *
+ * memmove(start, start + offset, total - offset);
+ * memset(start + (total - offset), 0, offset);
+ *
+ * Timing independence comes at the expense of performance.
+ *
+ * \param start     Secret. Pointer to the start of the buffer.
+ * \param total     Total size of the buffer.
+ * \param offset    Secret. Offset from which to copy \p total - \p offset bytes.
+ */
+void mbedtls_ct_memmove_left(void *start,
+                             size_t total,
+                             size_t offset);
+
+#endif /* defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) */
+
+/** Conditional memcpy.
+ *
+ * Functionally equivalent to:
+ *
+ * if (condition) {
+ *      memcpy(dest, src1, len);
+ * } else {
+ *      if (src2 != NULL)
+ *          memcpy(dest, src2, len);
+ * }
+ *
+ * It will always read len bytes from src1.
+ * If src2 != NULL, it will always read len bytes from src2.
+ * If src2 == NULL, it will instead read len bytes from dest (as if src2 == dest).
+ *
+ * \param condition The condition
+ * \param dest      Secret. Destination pointer.
+ * \param src1      Secret. Pointer to copy from (if \p condition == MBEDTLS_CT_TRUE).
+ *                  This may be equal to \p dest, but may not overlap in other ways.
+ * \param src2      Secret (contents only - may branch to determine if this parameter is NULL).
+ *                  Pointer to copy from (if \p condition == MBEDTLS_CT_FALSE and \p src2 is not NULL). May be NULL.
+ *                  This may be equal to \p dest, but may not overlap it in other ways. It may overlap with \p src1.
+ * \param len       Number of bytes to copy.
+ */
+void mbedtls_ct_memcpy_if(mbedtls_ct_condition_t condition,
+                          unsigned char *dest,
+                          const unsigned char *src1,
+                          const unsigned char *src2,
+                          size_t len
+                          );
+
+/** Copy data from a secret position.
+ *
+ * Functionally equivalent to:
+ *
+ * memcpy(dst, src + offset, len)
+ *
+ * This function copies \p len bytes from \p src_base + \p offset to \p
+ * dst, with a code flow and memory access pattern that does not depend on
+ * \p offset, but only on \p offset_min, \p offset_max and \p len.
  *
  * \note                This function reads from \p dest, but the value that
  *                      is read does not influence the result and this
@@ -246,12 +466,12 @@
  *                      positives from static or dynamic analyzers, especially
  *                      if \p dest is not initialized.
  *
- * \param dest          The destination buffer. This must point to a writable
+ * \param dest          Secret. The destination buffer. This must point to a writable
  *                      buffer of at least \p len bytes.
- * \param src           The base of the source buffer. This must point to a
+ * \param src           Secret. The base of the source buffer. This must point to a
  *                      readable buffer of at least \p offset_max + \p len
- *                      bytes. Shouldn't overlap with \p dest.
- * \param offset        The offset in the source buffer from which to copy.
+ *                      bytes. Shouldn't overlap with \p dest
+ * \param offset        Secret. The offset in the source buffer from which to copy.
  *                      This must be no less than \p offset_min and no greater
  *                      than \p offset_max.
  * \param offset_min    The minimal value of \p offset.
@@ -265,99 +485,14 @@
                               size_t offset_max,
                               size_t len);
 
-/** Compute the HMAC of variable-length data with constant flow.
- *
- * This function computes the HMAC of the concatenation of \p add_data and \p
- * data, and does with a code flow and memory access pattern that does not
- * depend on \p data_len_secret, but only on \p min_data_len and \p
- * max_data_len. In particular, this function always reads exactly \p
- * max_data_len bytes from \p data.
- *
- * \param ctx               The HMAC context. It must have keys configured
- *                          with mbedtls_md_hmac_starts() and use one of the
- *                          following hashes: SHA-384, SHA-256, SHA-1 or MD-5.
- *                          It is reset using mbedtls_md_hmac_reset() after
- *                          the computation is complete to prepare for the
- *                          next computation.
- * \param add_data          The first part of the message whose HMAC is being
- *                          calculated. This must point to a readable buffer
- *                          of \p add_data_len bytes.
- * \param add_data_len      The length of \p add_data in bytes.
- * \param data              The buffer containing the second part of the
- *                          message. This must point to a readable buffer
- *                          of \p max_data_len bytes.
- * \param data_len_secret   The length of the data to process in \p data.
- *                          This must be no less than \p min_data_len and no
- *                          greater than \p max_data_len.
- * \param min_data_len      The minimal length of the second part of the
- *                          message, read from \p data.
- * \param max_data_len      The maximal length of the second part of the
- *                          message, read from \p data.
- * \param output            The HMAC will be written here. This must point to
- *                          a writable buffer of sufficient size to hold the
- *                          HMAC value.
- *
- * \retval 0 on success.
- * \retval #MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED
- *         The hardware accelerator failed.
+/* Documented in include/mbedtls/constant_time.h. a and b are secret.
+
+   int mbedtls_ct_memcmp(const void *a,
+                         const void *b,
+                         size_t n);
  */
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
-int mbedtls_ct_hmac(mbedtls_svc_key_id_t key,
-                    psa_algorithm_t alg,
-                    const unsigned char *add_data,
-                    size_t add_data_len,
-                    const unsigned char *data,
-                    size_t data_len_secret,
-                    size_t min_data_len,
-                    size_t max_data_len,
-                    unsigned char *output);
-#else
-int mbedtls_ct_hmac(mbedtls_md_context_t *ctx,
-                    const unsigned char *add_data,
-                    size_t add_data_len,
-                    const unsigned char *data,
-                    size_t data_len_secret,
-                    size_t min_data_len,
-                    size_t max_data_len,
-                    unsigned char *output);
-#endif /* MBEDTLS_USE_PSA_CRYPTO */
 
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */
-
-#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
-
-/** This function performs the unpadding part of a PKCS#1 v1.5 decryption
- *  operation (EME-PKCS1-v1_5 decoding).
- *
- * \note The return value from this function is a sensitive value
- *       (this is unusual). #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE shouldn't happen
- *       in a well-written application, but 0 vs #MBEDTLS_ERR_RSA_INVALID_PADDING
- *       is often a situation that an attacker can provoke and leaking which
- *       one is the result is precisely the information the attacker wants.
- *
- * \param input          The input buffer which is the payload inside PKCS#1v1.5
- *                       encryption padding, called the "encoded message EM"
- *                       by the terminology.
- * \param ilen           The length of the payload in the \p input buffer.
- * \param output         The buffer for the payload, called "message M" by the
- *                       PKCS#1 terminology. This must be a writable buffer of
- *                       length \p output_max_len bytes.
- * \param olen           The address at which to store the length of
- *                       the payload. This must not be \c NULL.
- * \param output_max_len The length in bytes of the output buffer \p output.
- *
- * \return      \c 0 on success.
- * \return      #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE
- *              The output buffer is too small for the unpadded payload.
- * \return      #MBEDTLS_ERR_RSA_INVALID_PADDING
- *              The input doesn't contain properly formatted padding.
- */
-int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input,
-                                         size_t ilen,
-                                         unsigned char *output,
-                                         size_t output_max_len,
-                                         size_t *olen);
-
-#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */
+/* Include the implementation of static inline functions above. */
+#include "constant_time_impl.h"
 
 #endif /* MBEDTLS_CONSTANT_TIME_INTERNAL_H */
diff --git a/library/constant_time_invasive.h b/library/constant_time_invasive.h
deleted file mode 100644
index c176b28..0000000
--- a/library/constant_time_invasive.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * \file constant_time_invasive.h
- *
- * \brief Constant-time module: interfaces for invasive testing only.
- *
- * The interfaces in this file are intended for testing purposes only.
- * They SHOULD NOT be made available in library integrations except when
- * building the library for testing.
- */
-/*
- *  Copyright The Mbed TLS Contributors
- *  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.
- */
-
-#ifndef MBEDTLS_CONSTANT_TIME_INVASIVE_H
-#define MBEDTLS_CONSTANT_TIME_INVASIVE_H
-
-#include "common.h"
-
-#if defined(MBEDTLS_TEST_HOOKS)
-
-/** Turn a value into a mask:
- * - if \p low <= \p c <= \p high,
- *   return the all-bits 1 mask, aka (unsigned) -1
- * - otherwise, return the all-bits 0 mask, aka 0
- *
- * \param low   The value to analyze.
- * \param high  The value to analyze.
- * \param c     The value to analyze.
- *
- * \return      All-bits-one if \p low <= \p c <= \p high, otherwise zero.
- */
-unsigned char mbedtls_ct_uchar_mask_of_range(unsigned char low,
-                                             unsigned char high,
-                                             unsigned char c);
-
-#endif /* MBEDTLS_TEST_HOOKS */
-
-#endif /* MBEDTLS_CONSTANT_TIME_INVASIVE_H */
diff --git a/library/ctr_drbg.c b/library/ctr_drbg.c
index acc4208..fdd753d 100644
--- a/library/ctr_drbg.c
+++ b/library/ctr_drbg.c
@@ -19,7 +19,7 @@
 /*
  *  The NIST SP 800-90 DRBGs are described in the following publication.
  *
- *  http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf
+ *  https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-90r.pdf
  */
 
 #include "common.h"
diff --git a/library/debug.c b/library/debug.c
index 56bc3f6..0983cb0 100644
--- a/library/debug.c
+++ b/library/debug.c
@@ -144,7 +144,6 @@
 
     debug_send_line(ssl, level, file, line, str);
 
-    idx = 0;
     memset(txt, 0, sizeof(txt));
     for (i = 0; i < len; i++) {
         if (i >= 4096) {
@@ -202,17 +201,54 @@
 }
 #endif /* MBEDTLS_ECP_LIGHT */
 
-#if defined(MBEDTLS_BIGNUM_C)
 #if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
+static void mbedtls_debug_print_ec_coord(const mbedtls_ssl_context *ssl, int level,
+                                         const char *file, int line, const char *text,
+                                         const unsigned char *buf, size_t len)
+{
+    char str[DEBUG_BUF_SIZE];
+    size_t i, idx = 0;
+
+    mbedtls_snprintf(str + idx, sizeof(str) - idx, "value of '%s' (%u bits) is:\n",
+                     text, (unsigned int) len * 8);
+
+    debug_send_line(ssl, level, file, line, str);
+
+    for (i = 0; i < len; i++) {
+        if (i >= 4096) {
+            break;
+        }
+
+        if (i % 16 == 0) {
+            if (i > 0) {
+                mbedtls_snprintf(str + idx, sizeof(str) - idx, "\n");
+                debug_send_line(ssl, level, file, line, str);
+
+                idx = 0;
+            }
+        }
+
+        idx += mbedtls_snprintf(str + idx, sizeof(str) - idx, " %02x",
+                                (unsigned int) buf[i]);
+    }
+
+    if (len > 0) {
+        for (/* i = i */; i % 16 != 0; i++) {
+            idx += mbedtls_snprintf(str + idx, sizeof(str) - idx, "   ");
+        }
+
+        mbedtls_snprintf(str + idx, sizeof(str) - idx, "\n");
+        debug_send_line(ssl, level, file, line, str);
+    }
+}
+
 void mbedtls_debug_print_psa_ec(const mbedtls_ssl_context *ssl, int level,
                                 const char *file, int line,
                                 const char *text, const mbedtls_pk_context *pk)
 {
     char str[DEBUG_BUF_SIZE];
-    mbedtls_mpi mpi;
-    const uint8_t *mpi_start;
-    size_t mpi_len;
-    int ret;
+    const uint8_t *coord_start;
+    size_t coord_len;
 
     if (NULL == ssl              ||
         NULL == ssl->conf        ||
@@ -223,32 +259,21 @@
 
     /* For the description of pk->pk_raw content please refer to the description
      * psa_export_public_key() function. */
-    mpi_len = (pk->pub_raw_len - 1)/2;
+    coord_len = (pk->pub_raw_len - 1)/2;
 
     /* X coordinate */
-    mbedtls_mpi_init(&mpi);
-    mpi_start = pk->pub_raw + 1;
-    ret = mbedtls_mpi_read_binary(&mpi, mpi_start, mpi_len);
-    if (ret != 0) {
-        return;
-    }
+    coord_start = pk->pub_raw + 1;
     mbedtls_snprintf(str, sizeof(str), "%s(X)", text);
-    mbedtls_debug_print_mpi(ssl, level, file, line, str, &mpi);
-    mbedtls_mpi_free(&mpi);
+    mbedtls_debug_print_ec_coord(ssl, level, file, line, str, coord_start, coord_len);
 
     /* Y coordinate */
-    mbedtls_mpi_init(&mpi);
-    mpi_start = mpi_start + mpi_len;
-    ret = mbedtls_mpi_read_binary(&mpi, mpi_start, mpi_len);
-    if (ret != 0) {
-        return;
-    }
+    coord_start = coord_start + coord_len;
     mbedtls_snprintf(str, sizeof(str), "%s(Y)", text);
-    mbedtls_debug_print_mpi(ssl, level, file, line, str, &mpi);
-    mbedtls_mpi_free(&mpi);
+    mbedtls_debug_print_ec_coord(ssl, level, file, line, str, coord_start, coord_len);
 }
 #endif /* MBEDTLS_PK_USE_PSA_EC_DATA */
 
+#if defined(MBEDTLS_BIGNUM_C)
 void mbedtls_debug_print_mpi(const mbedtls_ssl_context *ssl, int level,
                              const char *file, int line,
                              const char *text, const mbedtls_mpi *X)
@@ -324,19 +349,21 @@
         mbedtls_snprintf(name, sizeof(name), "%s%s", text, items[i].name);
         name[sizeof(name) - 1] = '\0';
 
+#if defined(MBEDTLS_RSA_C)
         if (items[i].type == MBEDTLS_PK_DEBUG_MPI) {
             mbedtls_debug_print_mpi(ssl, level, file, line, name, items[i].value);
         } else
+#endif /* MBEDTLS_RSA_C */
 #if defined(MBEDTLS_ECP_LIGHT)
         if (items[i].type == MBEDTLS_PK_DEBUG_ECP) {
             mbedtls_debug_print_ecp(ssl, level, file, line, name, items[i].value);
         } else
-#endif
+#endif /* MBEDTLS_ECP_LIGHT */
 #if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
         if (items[i].type == MBEDTLS_PK_DEBUG_PSA_EC) {
             mbedtls_debug_print_psa_ec(ssl, level, file, line, name, items[i].value);
         } else
-#endif
+#endif /* MBEDTLS_PK_USE_PSA_EC_DATA */
         { debug_send_line(ssl, level, file, line,
                           "should not happen\n"); }
     }
diff --git a/library/ecdsa.c b/library/ecdsa.c
index 1faec16..6e55f22 100644
--- a/library/ecdsa.c
+++ b/library/ecdsa.c
@@ -373,7 +373,7 @@
 
 #if defined(MBEDTLS_ECP_RESTARTABLE)
     if (rs_ctx != NULL && rs_ctx->sig != NULL) {
-        mbedtls_mpi_copy(r, pr);
+        MBEDTLS_MPI_CHK(mbedtls_mpi_copy(r, pr));
     }
 #endif
 
@@ -447,7 +447,7 @@
     MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(d, data, grp_len));
     MBEDTLS_MPI_CHK(derive_mpi(grp, &h, buf, blen));
     MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&h, data + grp_len, grp_len));
-    mbedtls_hmac_drbg_seed_buf(p_rng, md_info, data, 2 * grp_len);
+    MBEDTLS_MPI_CHK(mbedtls_hmac_drbg_seed_buf(p_rng, md_info, data, 2 * grp_len));
 
 #if defined(MBEDTLS_ECP_RESTARTABLE)
     if (rs_ctx != NULL && rs_ctx->det != NULL) {
diff --git a/library/ecp.c b/library/ecp.c
index 870773c..f9b6672 100644
--- a/library/ecp.c
+++ b/library/ecp.c
@@ -1255,7 +1255,7 @@
     MPI_ECP_SQR(rhs, X);
 
     /* Special case for A = -3 */
-    if (grp->A.p == NULL) {
+    if (mbedtls_ecp_group_a_is_minus_3(grp)) {
         MPI_ECP_SUB_INT(rhs, rhs, 3);
     } else {
         MPI_ECP_ADD(rhs, rhs, &grp->A);
@@ -1526,7 +1526,7 @@
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
 
     /* Special case for A = -3 */
-    if (grp->A.p == NULL) {
+    if (mbedtls_ecp_group_a_is_minus_3(grp)) {
         /* tmp[0] <- M = 3(X + Z^2)(X - Z^2) */
         MPI_ECP_SQR(&tmp[1],  &P->Z);
         MPI_ECP_ADD(&tmp[2],  &P->X,  &tmp[1]);
diff --git a/library/entropy_poll.c b/library/entropy_poll.c
index f90167c..bc71307 100644
--- a/library/entropy_poll.c
+++ b/library/entropy_poll.c
@@ -75,7 +75,7 @@
     return 0;
 }
 #else /* !_WIN32_WINNT_WINXP */
-#error Entropy not available before Windows XP, use MBEDTLS_NO_PLATFORM_ENTROPY
+#error "Entropy not available before Windows XP, use MBEDTLS_NO_PLATFORM_ENTROPY"
 #endif /* !_WIN32_WINNT_WINXP */
 #else /* _WIN32 && !EFIX64 && !EFI32 */
 
diff --git a/library/gcm.c b/library/gcm.c
index a05e4c3..786290f 100644
--- a/library/gcm.c
+++ b/library/gcm.c
@@ -98,7 +98,7 @@
 #endif
 
 #if defined(MBEDTLS_AESCE_C) && defined(MBEDTLS_HAVE_ARM64)
-    if (mbedtls_aesce_has_support()) {
+    if (MBEDTLS_AESCE_HAS_SUPPORT()) {
         return 0;
     }
 #endif
@@ -209,7 +209,7 @@
 #endif /* MBEDTLS_AESNI_HAVE_CODE */
 
 #if defined(MBEDTLS_AESCE_C) && defined(MBEDTLS_HAVE_ARM64)
-    if (mbedtls_aesce_has_support()) {
+    if (MBEDTLS_AESCE_HAS_SUPPORT()) {
         unsigned char h[16];
 
         /* mbedtls_aesce_gcm_mult needs big-endian input */
@@ -884,6 +884,13 @@
             mbedtls_printf("  GCM note: using AESNI.\n");
         } else
 #endif
+
+#if defined(MBEDTLS_AESCE_C) && defined(MBEDTLS_HAVE_ARM64)
+        if (MBEDTLS_AESCE_HAS_SUPPORT()) {
+            mbedtls_printf("  GCM note: using AESCE.\n");
+        } else
+#endif
+
         mbedtls_printf("  GCM note: built-in implementation.\n");
 #endif /* MBEDTLS_GCM_ALT */
     }
diff --git a/library/md.c b/library/md.c
index 7c4c69f..0b2ea4d 100644
--- a/library/md.c
+++ b/library/md.c
@@ -232,6 +232,22 @@
         case MBEDTLS_MD_SHA512:
             return PSA_ALG_SHA_512;
 #endif
+#if defined(MBEDTLS_MD_SHA3_224_VIA_PSA)
+        case MBEDTLS_MD_SHA3_224:
+            return PSA_ALG_SHA3_224;
+#endif
+#if defined(MBEDTLS_MD_SHA3_256_VIA_PSA)
+        case MBEDTLS_MD_SHA3_256:
+            return PSA_ALG_SHA3_256;
+#endif
+#if defined(MBEDTLS_MD_SHA3_384_VIA_PSA)
+        case MBEDTLS_MD_SHA3_384:
+            return PSA_ALG_SHA3_384;
+#endif
+#if defined(MBEDTLS_MD_SHA3_512_VIA_PSA)
+        case MBEDTLS_MD_SHA3_512:
+            return PSA_ALG_SHA3_512;
+#endif
         default:
             return PSA_ALG_NONE;
     }
diff --git a/library/oid.c b/library/oid.c
index 47a311b..608b6c8 100644
--- a/library/oid.c
+++ b/library/oid.c
@@ -761,6 +761,30 @@
         MBEDTLS_MD_RIPEMD160,
     },
 #endif
+#if defined(MBEDTLS_MD_CAN_SHA3_224)
+    {
+        OID_DESCRIPTOR(MBEDTLS_OID_DIGEST_ALG_SHA3_224,    "id-sha3-224",    "SHA-3-224"),
+        MBEDTLS_MD_SHA3_224,
+    },
+#endif
+#if defined(MBEDTLS_MD_CAN_SHA3_256)
+    {
+        OID_DESCRIPTOR(MBEDTLS_OID_DIGEST_ALG_SHA3_256,    "id-sha3-256",    "SHA-3-256"),
+        MBEDTLS_MD_SHA3_256,
+    },
+#endif
+#if defined(MBEDTLS_MD_CAN_SHA3_384)
+    {
+        OID_DESCRIPTOR(MBEDTLS_OID_DIGEST_ALG_SHA3_384,    "id-sha3-384",    "SHA-3-384"),
+        MBEDTLS_MD_SHA3_384,
+    },
+#endif
+#if defined(MBEDTLS_MD_CAN_SHA3_512)
+    {
+        OID_DESCRIPTOR(MBEDTLS_OID_DIGEST_ALG_SHA3_512,    "id-sha3-512",    "SHA-3-512"),
+        MBEDTLS_MD_SHA3_512,
+    },
+#endif
     {
         NULL_OID_DESCRIPTOR,
         MBEDTLS_MD_NONE,
@@ -796,7 +820,7 @@
         OID_DESCRIPTOR(MBEDTLS_OID_HMAC_SHA224,    "hmacSHA224",    "HMAC-SHA-224"),
         MBEDTLS_MD_SHA224,
     },
-#endif
+#endif /* MBEDTLS_MD_CAN_SHA224 */
 #if defined(MBEDTLS_MD_CAN_SHA256)
     {
         OID_DESCRIPTOR(MBEDTLS_OID_HMAC_SHA256,    "hmacSHA256",    "HMAC-SHA-256"),
@@ -815,6 +839,36 @@
         MBEDTLS_MD_SHA512,
     },
 #endif /* MBEDTLS_MD_CAN_SHA512 */
+#if defined(MBEDTLS_MD_CAN_SHA3_224)
+    {
+        OID_DESCRIPTOR(MBEDTLS_OID_HMAC_SHA3_224,    "hmacSHA3-224",    "HMAC-SHA3-224"),
+        MBEDTLS_MD_SHA3_224,
+    },
+#endif /* MBEDTLS_MD_CAN_SHA3_224 */
+#if defined(MBEDTLS_MD_CAN_SHA3_256)
+    {
+        OID_DESCRIPTOR(MBEDTLS_OID_HMAC_SHA3_256,    "hmacSHA3-256",    "HMAC-SHA3-256"),
+        MBEDTLS_MD_SHA3_256,
+    },
+#endif /* MBEDTLS_MD_CAN_SHA3_256 */
+#if defined(MBEDTLS_MD_CAN_SHA3_384)
+    {
+        OID_DESCRIPTOR(MBEDTLS_OID_HMAC_SHA3_384,    "hmacSHA3-384",    "HMAC-SHA3-384"),
+        MBEDTLS_MD_SHA3_384,
+    },
+#endif /* MBEDTLS_MD_CAN_SHA3_384 */
+#if defined(MBEDTLS_MD_CAN_SHA3_512)
+    {
+        OID_DESCRIPTOR(MBEDTLS_OID_HMAC_SHA3_512,    "hmacSHA3-512",    "HMAC-SHA3-512"),
+        MBEDTLS_MD_SHA3_512,
+    },
+#endif /* MBEDTLS_MD_CAN_SHA3_512 */
+#if defined(MBEDTLS_MD_CAN_RIPEMD160)
+    {
+        OID_DESCRIPTOR(MBEDTLS_OID_HMAC_RIPEMD160,    "hmacRIPEMD160",    "HMAC-RIPEMD160"),
+        MBEDTLS_MD_RIPEMD160,
+    },
+#endif /* MBEDTLS_MD_CAN_RIPEMD160 */
     {
         NULL_OID_DESCRIPTOR,
         MBEDTLS_MD_NONE,
diff --git a/library/padlock.h b/library/padlock.h
index b5f0d7d..ae5c486 100644
--- a/library/padlock.h
+++ b/library/padlock.h
@@ -42,6 +42,8 @@
 #if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && defined(__i386__) && \
     !defined(MBEDTLS_HAVE_ASAN)
 
+#define MBEDTLS_VIA_PADLOCK_HAVE_CODE
+
 #ifndef MBEDTLS_HAVE_X86
 #define MBEDTLS_HAVE_X86
 #endif
diff --git a/library/pk_wrap.c b/library/pk_wrap.c
index 4ee761e..e67138b 100644
--- a/library/pk_wrap.c
+++ b/library/pk_wrap.c
@@ -302,11 +302,16 @@
     psa_status_t status;
     mbedtls_pk_context key;
     int key_len;
-    unsigned char buf[MBEDTLS_PK_RSA_PRV_DER_MAX_BYTES];
+    unsigned char *buf = NULL;
+    buf = mbedtls_calloc(1, MBEDTLS_PK_RSA_PRV_DER_MAX_BYTES);
+    if (buf == NULL) {
+        return MBEDTLS_ERR_PK_ALLOC_FAILED;
+    }
     mbedtls_pk_info_t pk_info = mbedtls_rsa_info;
 
     *sig_len = mbedtls_rsa_get_len(rsa_ctx);
     if (sig_size < *sig_len) {
+        mbedtls_free(buf);
         return MBEDTLS_ERR_PK_BUFFER_TOO_SMALL;
     }
 
@@ -314,8 +319,9 @@
      * re-construct one to make it happy */
     key.pk_info = &pk_info;
     key.pk_ctx = rsa_ctx;
-    key_len = mbedtls_pk_write_key_der(&key, buf, sizeof(buf));
+    key_len = mbedtls_pk_write_key_der(&key, buf, MBEDTLS_PK_RSA_PRV_DER_MAX_BYTES);
     if (key_len <= 0) {
+        mbedtls_free(buf);
         return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
     }
     psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH);
@@ -323,7 +329,7 @@
     psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
 
     status = psa_import_key(&attributes,
-                            buf + sizeof(buf) - key_len, key_len,
+                            buf + MBEDTLS_PK_RSA_PRV_DER_MAX_BYTES - key_len, key_len,
                             &key_id);
     if (status != PSA_SUCCESS) {
         ret = PSA_PK_TO_MBEDTLS_ERR(status);
@@ -339,6 +345,7 @@
     ret = 0;
 
 cleanup:
+    mbedtls_free(buf);
     status = psa_destroy_key(key_id);
     if (ret == 0 && status != PSA_SUCCESS) {
         ret = PSA_PK_TO_MBEDTLS_ERR(status);
diff --git a/library/pkparse.c b/library/pkparse.c
index f03ace2..fe01a11 100644
--- a/library/pkparse.c
+++ b/library/pkparse.c
@@ -34,9 +34,6 @@
 #include "mbedtls/rsa.h"
 #endif
 #include "mbedtls/ecp.h"
-#if defined(MBEDTLS_RSA_C) || defined(MBEDTLS_ECP_C)
-#include "pkwrite.h"
-#endif
 #if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
 #include "pk_internal.h"
 #endif
diff --git a/library/pkwrite.c b/library/pkwrite.c
index 4ec0b81..439428c 100644
--- a/library/pkwrite.c
+++ b/library/pkwrite.c
@@ -165,7 +165,7 @@
                               const mbedtls_pk_context *pk)
 {
     size_t len = 0;
-    uint8_t buf[PSA_EXPORT_KEY_PAIR_MAX_SIZE];
+    uint8_t buf[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
 
     if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) {
         if (psa_export_public_key(pk->priv_id, buf, sizeof(buf), &len) != PSA_SUCCESS) {
diff --git a/library/pkwrite.h b/library/pkwrite.h
index aa2f17b..8cfa64b 100644
--- a/library/pkwrite.h
+++ b/library/pkwrite.h
@@ -27,6 +27,10 @@
 
 #include "mbedtls/pk.h"
 
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+#include "psa/crypto.h"
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
 /*
  * Max sizes of key per types. Shown as tag + len (+ content).
  */
@@ -74,6 +78,19 @@
 #endif /* MBEDTLS_RSA_C */
 
 #if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
+
+/* Find the maximum number of bytes necessary to store an EC point. When USE_PSA
+ * is defined this means looking for the maximum between PSA and built-in
+ * supported curves. */
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+#define MBEDTLS_PK_MAX_ECC_BYTES   (PSA_BITS_TO_BYTES(PSA_VENDOR_ECC_MAX_CURVE_BITS) > \
+                                    MBEDTLS_ECP_MAX_BYTES ? \
+                                    PSA_BITS_TO_BYTES(PSA_VENDOR_ECC_MAX_CURVE_BITS) : \
+                                    MBEDTLS_ECP_MAX_BYTES)
+#else /* MBEDTLS_USE_PSA_CRYPTO */
+#define MBEDTLS_PK_MAX_ECC_BYTES   MBEDTLS_ECP_MAX_BYTES
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
 /*
  * EC public keys:
  *  SubjectPublicKeyInfo  ::=  SEQUENCE  {      1 + 2
@@ -85,7 +102,7 @@
  *                                            + 2 * ECP_MAX (coords)    [1]
  *  }
  */
-#define MBEDTLS_PK_ECP_PUB_DER_MAX_BYTES    (30 + 2 * MBEDTLS_ECP_MAX_BYTES)
+#define MBEDTLS_PK_ECP_PUB_DER_MAX_BYTES    (30 + 2 * MBEDTLS_PK_MAX_ECC_BYTES)
 
 /*
  * EC private keys:
@@ -96,7 +113,7 @@
  *      publicKey  [1] BIT STRING OPTIONAL      1 + 2 + [1] above
  *    }
  */
-#define MBEDTLS_PK_ECP_PRV_DER_MAX_BYTES    (29 + 3 * MBEDTLS_ECP_MAX_BYTES)
+#define MBEDTLS_PK_ECP_PRV_DER_MAX_BYTES    (29 + 3 * MBEDTLS_PK_MAX_ECC_BYTES)
 
 #else /* MBEDTLS_PK_HAVE_ECC_KEYS */
 
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 2b9eca8..84da7ad 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -5093,7 +5093,7 @@
     defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || \
     defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS) || \
     defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS) || \
-    defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC)
+    defined(PSA_HAVE_SOFT_PBKDF2)
 #define AT_LEAST_ONE_BUILTIN_KDF
 #endif /* At least one builtin KDF */
 
@@ -5193,8 +5193,8 @@
                                  sizeof(operation->ctx.tls12_ecjpake_to_pms.data));
     } else
 #endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS) */
-#if defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC)
-    if (PSA_ALG_IS_PBKDF2_HMAC(kdf_alg)) {
+#if defined(PSA_HAVE_SOFT_PBKDF2)
+    if (PSA_ALG_IS_PBKDF2(kdf_alg)) {
         if (operation->ctx.pbkdf2.salt != NULL) {
             mbedtls_zeroize_and_free(operation->ctx.pbkdf2.salt,
                                      operation->ctx.pbkdf2.salt_length);
@@ -5202,7 +5202,7 @@
 
         status = PSA_SUCCESS;
     } else
-#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC) */
+#endif /* defined(PSA_HAVE_SOFT_PBKDF2) */
     {
         status = PSA_ERROR_BAD_STATE;
     }
@@ -5529,7 +5529,7 @@
 }
 #endif
 
-#if defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC)
+#if defined(PSA_HAVE_SOFT_PBKDF2)
 static psa_status_t psa_key_derivation_pbkdf2_generate_block(
     psa_pbkdf2_key_derivation_t *pbkdf2,
     psa_algorithm_t prf_alg,
@@ -5578,11 +5578,14 @@
     memcpy(U_accumulator, U_i, prf_output_length);
 
     for (i = 1; i < pbkdf2->input_cost; i++) {
+        /* We are passing prf_output_length as mac_size because the driver
+         * function directly sets mac_output_length as mac_size upon success.
+         * See https://github.com/Mbed-TLS/mbedtls/issues/7801 */
         status = psa_driver_wrapper_mac_compute(attributes,
                                                 pbkdf2->password,
                                                 pbkdf2->password_length,
                                                 prf_alg, U_i, prf_output_length,
-                                                U_i, sizeof(U_i),
+                                                U_i, prf_output_length,
                                                 &mac_output_length);
         if (status != PSA_SUCCESS) {
             goto cleanup;
@@ -5614,6 +5617,10 @@
         prf_alg = PSA_ALG_HMAC(PSA_ALG_PBKDF2_HMAC_GET_HASH(kdf_alg));
         prf_output_length = PSA_HASH_LENGTH(prf_alg);
         psa_set_key_type(&attributes, PSA_KEY_TYPE_HMAC);
+    } else if (kdf_alg == PSA_ALG_PBKDF2_AES_CMAC_PRF_128) {
+        prf_alg = PSA_ALG_CMAC;
+        prf_output_length = PSA_MAC_LENGTH(PSA_KEY_TYPE_AES, 128U, PSA_ALG_CMAC);
+        psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
     } else {
         return PSA_ERROR_INVALID_ARGUMENT;
     }
@@ -5658,7 +5665,7 @@
 
     return PSA_SUCCESS;
 }
-#endif /* MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC */
+#endif /* PSA_HAVE_SOFT_PBKDF2 */
 
 psa_status_t psa_key_derivation_output_bytes(
     psa_key_derivation_operation_t *operation,
@@ -5713,12 +5720,12 @@
             &operation->ctx.tls12_ecjpake_to_pms, output, output_length);
     } else
 #endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS */
-#if defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC)
-    if (PSA_ALG_IS_PBKDF2_HMAC(kdf_alg)) {
+#if defined(PSA_HAVE_SOFT_PBKDF2)
+    if (PSA_ALG_IS_PBKDF2(kdf_alg)) {
         status = psa_key_derivation_pbkdf2_read(&operation->ctx.pbkdf2, kdf_alg,
                                                 output, output_length);
     } else
-#endif /* MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC */
+#endif /* PSA_HAVE_SOFT_PBKDF2 */
 
     {
         (void) kdf_alg;
@@ -6145,6 +6152,11 @@
         return 1;
     }
 #endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_AES_CMAC_PRF_128)
+    if (kdf_alg == PSA_ALG_PBKDF2_AES_CMAC_PRF_128) {
+        return 1;
+    }
+#endif
     return 0;
 }
 
@@ -6170,10 +6182,14 @@
     }
 
     /* All currently supported key derivation algorithms (apart from
-     * ecjpake to pms) are based on a hash algorithm. */
+     * ecjpake to pms and pbkdf2_aes_cmac_128) are based on a hash algorithm. */
     psa_algorithm_t hash_alg = PSA_ALG_HKDF_GET_HASH(kdf_alg);
     size_t hash_size = PSA_HASH_LENGTH(hash_alg);
-    if (kdf_alg != PSA_ALG_TLS12_ECJPAKE_TO_PMS) {
+    if (kdf_alg == PSA_ALG_TLS12_ECJPAKE_TO_PMS) {
+        hash_size = PSA_HASH_LENGTH(PSA_ALG_SHA_256);
+    } else if (kdf_alg == PSA_ALG_PBKDF2_AES_CMAC_PRF_128) {
+        hash_size = PSA_MAC_LENGTH(PSA_KEY_TYPE_AES, 128U, PSA_ALG_CMAC);
+    } else {
         if (hash_size == 0) {
             return PSA_ERROR_NOT_SUPPORTED;
         }
@@ -6185,8 +6201,6 @@
         if (status != PSA_SUCCESS) {
             return status;
         }
-    } else {
-        hash_size = PSA_HASH_LENGTH(PSA_ALG_SHA_256);
     }
 
     if ((PSA_ALG_IS_TLS12_PRF(kdf_alg) ||
@@ -6638,7 +6652,7 @@
 }
 #endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS */
 
-#if defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC)
+#if defined(PSA_HAVE_SOFT_PBKDF2)
 static psa_status_t psa_pbkdf2_set_input_cost(
     psa_pbkdf2_key_derivation_t *pbkdf2,
     psa_key_derivation_step_t step,
@@ -6703,6 +6717,7 @@
     return PSA_SUCCESS;
 }
 
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC)
 static psa_status_t psa_pbkdf2_hmac_set_password(psa_algorithm_t hash_alg,
                                                  const uint8_t *input,
                                                  size_t input_len,
@@ -6719,6 +6734,39 @@
     }
     return status;
 }
+#endif /* MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC */
+
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_AES_CMAC_PRF_128)
+static psa_status_t psa_pbkdf2_cmac_set_password(const uint8_t *input,
+                                                 size_t input_len,
+                                                 uint8_t *output,
+                                                 size_t *output_len)
+{
+    psa_status_t status = PSA_SUCCESS;
+    if (input_len != PSA_MAC_LENGTH(PSA_KEY_TYPE_AES, 128U, PSA_ALG_CMAC)) {
+        psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+        uint8_t zeros[16] = { 0 };
+        psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
+        psa_set_key_bits(&attributes, PSA_BYTES_TO_BITS(sizeof(zeros)));
+        psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_MESSAGE);
+        /* Passing PSA_MAC_LENGTH(PSA_KEY_TYPE_AES, 128U, PSA_ALG_CMAC) as
+         * mac_size as the driver function sets mac_output_length = mac_size
+         * on success. See https://github.com/Mbed-TLS/mbedtls/issues/7801 */
+        status = psa_driver_wrapper_mac_compute(&attributes,
+                                                zeros, sizeof(zeros),
+                                                PSA_ALG_CMAC, input, input_len,
+                                                output,
+                                                PSA_MAC_LENGTH(PSA_KEY_TYPE_AES,
+                                                               128U,
+                                                               PSA_ALG_CMAC),
+                                                output_len);
+    } else {
+        memcpy(output, input, input_len);
+        *output_len = PSA_MAC_LENGTH(PSA_KEY_TYPE_AES, 128U, PSA_ALG_CMAC);
+    }
+    return status;
+}
+#endif /* MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_AES_CMAC_PRF_128 */
 
 static psa_status_t psa_pbkdf2_set_password(psa_pbkdf2_key_derivation_t *pbkdf2,
                                             psa_algorithm_t kdf_alg,
@@ -6730,13 +6778,23 @@
         return PSA_ERROR_BAD_STATE;
     }
 
-    if (data_length != 0) {
-        if (PSA_ALG_IS_PBKDF2_HMAC(kdf_alg)) {
-            psa_algorithm_t hash_alg = PSA_ALG_PBKDF2_HMAC_GET_HASH(kdf_alg);
-            status = psa_pbkdf2_hmac_set_password(hash_alg, data, data_length,
-                                                  pbkdf2->password,
-                                                  &pbkdf2->password_length);
-        }
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC)
+    if (PSA_ALG_IS_PBKDF2_HMAC(kdf_alg)) {
+        psa_algorithm_t hash_alg = PSA_ALG_PBKDF2_HMAC_GET_HASH(kdf_alg);
+        status = psa_pbkdf2_hmac_set_password(hash_alg, data, data_length,
+                                              pbkdf2->password,
+                                              &pbkdf2->password_length);
+    } else
+#endif /* MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC */
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_AES_CMAC_PRF_128)
+    if (kdf_alg == PSA_ALG_PBKDF2_AES_CMAC_PRF_128) {
+        status = psa_pbkdf2_cmac_set_password(data, data_length,
+                                              pbkdf2->password,
+                                              &pbkdf2->password_length);
+    } else
+#endif /* MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_AES_CMAC_PRF_128 */
+    {
+        return PSA_ERROR_INVALID_ARGUMENT;
     }
 
     pbkdf2->state = PSA_PBKDF2_STATE_PASSWORD_SET;
@@ -6759,7 +6817,7 @@
             return PSA_ERROR_INVALID_ARGUMENT;
     }
 }
-#endif /* MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC */
+#endif /* PSA_HAVE_SOFT_PBKDF2 */
 
 /** Check whether the given key type is acceptable for the given
  * input step of a key derivation.
@@ -6856,12 +6914,12 @@
             &operation->ctx.tls12_ecjpake_to_pms, step, data, data_length);
     } else
 #endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS */
-#if defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC)
-    if (PSA_ALG_IS_PBKDF2_HMAC(kdf_alg)) {
+#if defined(PSA_HAVE_SOFT_PBKDF2)
+    if (PSA_ALG_IS_PBKDF2(kdf_alg)) {
         status = psa_pbkdf2_input(&operation->ctx.pbkdf2, kdf_alg,
                                   step, data, data_length);
     } else
-#endif /* MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC */
+#endif /* PSA_HAVE_SOFT_PBKDF2 */
     {
         /* This can't happen unless the operation object was not initialized */
         (void) data;
@@ -6885,12 +6943,12 @@
     psa_status_t status;
     psa_algorithm_t kdf_alg = psa_key_derivation_get_kdf_alg(operation);
 
-#if defined(MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC)
-    if (PSA_ALG_IS_PBKDF2_HMAC(kdf_alg)) {
+#if defined(PSA_HAVE_SOFT_PBKDF2)
+    if (PSA_ALG_IS_PBKDF2(kdf_alg)) {
         status = psa_pbkdf2_set_input_cost(
             &operation->ctx.pbkdf2, step, value);
     } else
-#endif /* MBEDTLS_PSA_BUILTIN_ALG_PBKDF2_HMAC */
+#endif /* PSA_HAVE_SOFT_PBKDF2 */
     {
         (void) step;
         (void) value;
diff --git a/library/psa_crypto_hash.c b/library/psa_crypto_hash.c
index ddf7094..dad1826 100644
--- a/library/psa_crypto_hash.c
+++ b/library/psa_crypto_hash.c
@@ -74,6 +74,25 @@
             mbedtls_sha512_free(&operation->ctx.sha512);
             break;
 #endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224)
+        case PSA_ALG_SHA3_224:
+#endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256)
+        case PSA_ALG_SHA3_256:
+#endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384)
+        case PSA_ALG_SHA3_384:
+#endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512)
+        case PSA_ALG_SHA3_512:
+#endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224) || \
+            defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256) || \
+            defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384) || \
+            defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512)
+            mbedtls_sha3_free(&operation->ctx.sha3);
+            break;
+#endif
         default:
             return PSA_ERROR_BAD_STATE;
     }
@@ -135,6 +154,30 @@
             ret = mbedtls_sha512_starts(&operation->ctx.sha512, 0);
             break;
 #endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224)
+        case PSA_ALG_SHA3_224:
+            mbedtls_sha3_init(&operation->ctx.sha3);
+            ret = mbedtls_sha3_starts(&operation->ctx.sha3, MBEDTLS_SHA3_224);
+            break;
+#endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256)
+        case PSA_ALG_SHA3_256:
+            mbedtls_sha3_init(&operation->ctx.sha3);
+            ret = mbedtls_sha3_starts(&operation->ctx.sha3, MBEDTLS_SHA3_256);
+            break;
+#endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384)
+        case PSA_ALG_SHA3_384:
+            mbedtls_sha3_init(&operation->ctx.sha3);
+            ret = mbedtls_sha3_starts(&operation->ctx.sha3, MBEDTLS_SHA3_384);
+            break;
+#endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512)
+        case PSA_ALG_SHA3_512:
+            mbedtls_sha3_init(&operation->ctx.sha3);
+            ret = mbedtls_sha3_starts(&operation->ctx.sha3, MBEDTLS_SHA3_512);
+            break;
+#endif
         default:
             return PSA_ALG_IS_HASH(alg) ?
                    PSA_ERROR_NOT_SUPPORTED :
@@ -197,6 +240,26 @@
                                  &source_operation->ctx.sha512);
             break;
 #endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224)
+        case PSA_ALG_SHA3_224:
+#endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256)
+        case PSA_ALG_SHA3_256:
+#endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384)
+        case PSA_ALG_SHA3_384:
+#endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512)
+        case PSA_ALG_SHA3_512:
+#endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224) || \
+            defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256) || \
+            defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384) || \
+            defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512)
+            mbedtls_sha3_clone(&target_operation->ctx.sha3,
+                               &source_operation->ctx.sha3);
+            break;
+#endif
         default:
             (void) source_operation;
             (void) target_operation;
@@ -257,6 +320,26 @@
                                         input, input_length);
             break;
 #endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224)
+        case PSA_ALG_SHA3_224:
+#endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256)
+        case PSA_ALG_SHA3_256:
+#endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384)
+        case PSA_ALG_SHA3_384:
+#endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512)
+        case PSA_ALG_SHA3_512:
+#endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224) || \
+    defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256) || \
+    defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384) || \
+    defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512)
+    ret = mbedtls_sha3_update(&operation->ctx.sha3,
+                              input, input_length);
+    break;
+#endif
         default:
             (void) input;
             (void) input_length;
@@ -327,6 +410,25 @@
             ret = mbedtls_sha512_finish(&operation->ctx.sha512, hash);
             break;
 #endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224)
+        case PSA_ALG_SHA3_224:
+#endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256)
+        case PSA_ALG_SHA3_256:
+#endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384)
+        case PSA_ALG_SHA3_384:
+#endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512)
+        case PSA_ALG_SHA3_512:
+#endif
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_224) || \
+    defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_256) || \
+    defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_384) || \
+    defined(MBEDTLS_PSA_BUILTIN_ALG_SHA3_512)
+    ret = mbedtls_sha3_finish(&operation->ctx.sha3, hash, hash_size);
+    break;
+#endif
         default:
             (void) hash;
             return PSA_ERROR_BAD_STATE;
diff --git a/library/psa_crypto_pake.c b/library/psa_crypto_pake.c
index caba5a1..8de8569 100644
--- a/library/psa_crypto_pake.c
+++ b/library/psa_crypto_pake.c
@@ -178,12 +178,12 @@
         return status;
     }
 
-    psa_crypto_driver_pake_get_user_len(inputs, &user_len);
+    status = psa_crypto_driver_pake_get_user_len(inputs, &user_len);
     if (status != PSA_SUCCESS) {
         return status;
     }
 
-    psa_crypto_driver_pake_get_peer_len(inputs, &peer_len);
+    status = psa_crypto_driver_pake_get_peer_len(inputs, &peer_len);
     if (status != PSA_SUCCESS) {
         return status;
     }
diff --git a/library/psa_crypto_storage.h b/library/psa_crypto_storage.h
index 04768f8..edd9b94 100644
--- a/library/psa_crypto_storage.h
+++ b/library/psa_crypto_storage.h
@@ -39,7 +39,7 @@
 /* Sanity check: a file size must fit in 32 bits. Allow a generous
  * 64kB of metadata. */
 #if PSA_CRYPTO_MAX_STORAGE_SIZE > 0xffff0000
-#error PSA_CRYPTO_MAX_STORAGE_SIZE > 0xffff0000
+#error "PSA_CRYPTO_MAX_STORAGE_SIZE > 0xffff0000"
 #endif
 
 /** The maximum permitted persistent slot number.
diff --git a/library/rsa.c b/library/rsa.c
index ad49796..d0782f5 100644
--- a/library/rsa.c
+++ b/library/rsa.c
@@ -56,6 +56,164 @@
 
 #include "mbedtls/platform.h"
 
+
+#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
+
+/** This function performs the unpadding part of a PKCS#1 v1.5 decryption
+ *  operation (EME-PKCS1-v1_5 decoding).
+ *
+ * \note The return value from this function is a sensitive value
+ *       (this is unusual). #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE shouldn't happen
+ *       in a well-written application, but 0 vs #MBEDTLS_ERR_RSA_INVALID_PADDING
+ *       is often a situation that an attacker can provoke and leaking which
+ *       one is the result is precisely the information the attacker wants.
+ *
+ * \param input          The input buffer which is the payload inside PKCS#1v1.5
+ *                       encryption padding, called the "encoded message EM"
+ *                       by the terminology.
+ * \param ilen           The length of the payload in the \p input buffer.
+ * \param output         The buffer for the payload, called "message M" by the
+ *                       PKCS#1 terminology. This must be a writable buffer of
+ *                       length \p output_max_len bytes.
+ * \param olen           The address at which to store the length of
+ *                       the payload. This must not be \c NULL.
+ * \param output_max_len The length in bytes of the output buffer \p output.
+ *
+ * \return      \c 0 on success.
+ * \return      #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE
+ *              The output buffer is too small for the unpadded payload.
+ * \return      #MBEDTLS_ERR_RSA_INVALID_PADDING
+ *              The input doesn't contain properly formatted padding.
+ */
+static int mbedtls_ct_rsaes_pkcs1_v15_unpadding(unsigned char *input,
+                                                size_t ilen,
+                                                unsigned char *output,
+                                                size_t output_max_len,
+                                                size_t *olen)
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    size_t i, plaintext_max_size;
+
+    /* The following variables take sensitive values: their value must
+     * not leak into the observable behavior of the function other than
+     * the designated outputs (output, olen, return value). Otherwise
+     * this would open the execution of the function to
+     * side-channel-based variants of the Bleichenbacher padding oracle
+     * attack. Potential side channels include overall timing, memory
+     * access patterns (especially visible to an adversary who has access
+     * to a shared memory cache), and branches (especially visible to
+     * an adversary who has access to a shared code cache or to a shared
+     * branch predictor). */
+    size_t pad_count = 0;
+    mbedtls_ct_condition_t bad;
+    mbedtls_ct_condition_t pad_done;
+    size_t plaintext_size = 0;
+    mbedtls_ct_condition_t output_too_large;
+
+    plaintext_max_size = (output_max_len > ilen - 11) ? ilen - 11
+                                                        : output_max_len;
+
+    /* Check and get padding length in constant time and constant
+     * memory trace. The first byte must be 0. */
+    bad = mbedtls_ct_bool(input[0]);
+
+
+    /* Decode EME-PKCS1-v1_5 padding: 0x00 || 0x02 || PS || 0x00
+     * where PS must be at least 8 nonzero bytes. */
+    bad = mbedtls_ct_bool_or(bad, mbedtls_ct_uint_ne(input[1], MBEDTLS_RSA_CRYPT));
+
+    /* Read the whole buffer. Set pad_done to nonzero if we find
+     * the 0x00 byte and remember the padding length in pad_count. */
+    pad_done = MBEDTLS_CT_FALSE;
+    for (i = 2; i < ilen; i++) {
+        mbedtls_ct_condition_t found = mbedtls_ct_uint_eq(input[i], 0);
+        pad_done   = mbedtls_ct_bool_or(pad_done, found);
+        pad_count += mbedtls_ct_uint_if_else_0(mbedtls_ct_bool_not(pad_done), 1);
+    }
+
+    /* If pad_done is still zero, there's no data, only unfinished padding. */
+    bad = mbedtls_ct_bool_or(bad, mbedtls_ct_bool_not(pad_done));
+
+    /* There must be at least 8 bytes of padding. */
+    bad = mbedtls_ct_bool_or(bad, mbedtls_ct_uint_gt(8, pad_count));
+
+    /* If the padding is valid, set plaintext_size to the number of
+     * remaining bytes after stripping the padding. If the padding
+     * is invalid, avoid leaking this fact through the size of the
+     * output: use the maximum message size that fits in the output
+     * buffer. Do it without branches to avoid leaking the padding
+     * validity through timing. RSA keys are small enough that all the
+     * size_t values involved fit in unsigned int. */
+    plaintext_size = mbedtls_ct_uint_if(
+        bad, (unsigned) plaintext_max_size,
+        (unsigned) (ilen - pad_count - 3));
+
+    /* Set output_too_large to 0 if the plaintext fits in the output
+     * buffer and to 1 otherwise. */
+    output_too_large = mbedtls_ct_uint_gt(plaintext_size,
+                                          plaintext_max_size);
+
+    /* Set ret without branches to avoid timing attacks. Return:
+     * - INVALID_PADDING if the padding is bad (bad != 0).
+     * - OUTPUT_TOO_LARGE if the padding is good but the decrypted
+     *   plaintext does not fit in the output buffer.
+     * - 0 if the padding is correct. */
+    ret = -(int) mbedtls_ct_uint_if(
+        bad,
+        (unsigned) (-(MBEDTLS_ERR_RSA_INVALID_PADDING)),
+        mbedtls_ct_uint_if_else_0(
+            output_too_large,
+            (unsigned) (-(MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE)))
+        );
+
+    /* If the padding is bad or the plaintext is too large, zero the
+     * data that we're about to copy to the output buffer.
+     * We need to copy the same amount of data
+     * from the same buffer whether the padding is good or not to
+     * avoid leaking the padding validity through overall timing or
+     * through memory or cache access patterns. */
+    mbedtls_ct_zeroize_if(mbedtls_ct_bool_or(bad, output_too_large), input + 11, ilen - 11);
+
+    /* If the plaintext is too large, truncate it to the buffer size.
+     * Copy anyway to avoid revealing the length through timing, because
+     * revealing the length is as bad as revealing the padding validity
+     * for a Bleichenbacher attack. */
+    plaintext_size = mbedtls_ct_uint_if(output_too_large,
+                                        (unsigned) plaintext_max_size,
+                                        (unsigned) plaintext_size);
+
+    /* Move the plaintext to the leftmost position where it can start in
+     * the working buffer, i.e. make it start plaintext_max_size from
+     * the end of the buffer. Do this with a memory access trace that
+     * does not depend on the plaintext size. After this move, the
+     * starting location of the plaintext is no longer sensitive
+     * information. */
+    mbedtls_ct_memmove_left(input + ilen - plaintext_max_size,
+                            plaintext_max_size,
+                            plaintext_max_size - plaintext_size);
+
+    /* Finally copy the decrypted plaintext plus trailing zeros into the output
+     * buffer. If output_max_len is 0, then output may be an invalid pointer
+     * and the result of memcpy() would be undefined; prevent undefined
+     * behavior making sure to depend only on output_max_len (the size of the
+     * user-provided output buffer), which is independent from plaintext
+     * length, validity of padding, success of the decryption, and other
+     * secrets. */
+    if (output_max_len != 0) {
+        memcpy(output, input + ilen - plaintext_max_size, plaintext_max_size);
+    }
+
+    /* Report the amount of data we copied to the output buffer. In case
+     * of errors (bad padding or output too large), the value of *olen
+     * when this function returns is not specified. Making it equivalent
+     * to the good case limits the risks of leaking the padding validity. */
+    *olen = plaintext_size;
+
+    return ret;
+}
+
+#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */
+
 #if !defined(MBEDTLS_RSA_ALT)
 
 int mbedtls_rsa_import(mbedtls_rsa_context *ctx,
diff --git a/library/rsa_alt_helpers.c b/library/rsa_alt_helpers.c
index 3451469..5cc4636 100644
--- a/library/rsa_alt_helpers.c
+++ b/library/rsa_alt_helpers.c
@@ -126,7 +126,7 @@
     }
 
     for (; attempt < num_primes; ++attempt) {
-        mbedtls_mpi_lset(&K, primes[attempt]);
+        MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&K, primes[attempt]));
 
         /* Check if gcd(K,N) = 1 */
         MBEDTLS_MPI_CHK(mbedtls_mpi_gcd(P, &K, N));
diff --git a/library/sha3.c b/library/sha3.c
index 4b97a85..dca5790 100644
--- a/library/sha3.c
+++ b/library/sha3.c
@@ -259,10 +259,13 @@
 int mbedtls_sha3_finish(mbedtls_sha3_context *ctx,
                         uint8_t *output, size_t olen)
 {
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
     /* Catch SHA-3 families, with fixed output length */
     if (ctx->olen > 0) {
         if (ctx->olen > olen) {
-            return MBEDTLS_ERR_SHA3_BAD_INPUT_DATA;
+            ret = MBEDTLS_ERR_SHA3_BAD_INPUT_DATA;
+            goto exit;
         }
         olen = ctx->olen;
     }
@@ -280,7 +283,11 @@
         }
     }
 
-    return 0;
+    ret = 0;
+
+exit:
+    mbedtls_sha3_free(ctx);
+    return ret;
 }
 
 /*
diff --git a/library/ssl_misc.h b/library/ssl_misc.h
index f4264fb..8a709e4 100644
--- a/library/ssl_misc.h
+++ b/library/ssl_misc.h
@@ -2796,4 +2796,64 @@
 int mbedtls_ssl_tls13_finalize_client_hello(mbedtls_ssl_context *ssl);
 #endif
 
+#if defined(MBEDTLS_TEST_HOOKS) && defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
+
+/** Compute the HMAC of variable-length data with constant flow.
+ *
+ * This function computes the HMAC of the concatenation of \p add_data and \p
+ * data, and does with a code flow and memory access pattern that does not
+ * depend on \p data_len_secret, but only on \p min_data_len and \p
+ * max_data_len. In particular, this function always reads exactly \p
+ * max_data_len bytes from \p data.
+ *
+ * \param ctx               The HMAC context. It must have keys configured
+ *                          with mbedtls_md_hmac_starts() and use one of the
+ *                          following hashes: SHA-384, SHA-256, SHA-1 or MD-5.
+ *                          It is reset using mbedtls_md_hmac_reset() after
+ *                          the computation is complete to prepare for the
+ *                          next computation.
+ * \param add_data          The first part of the message whose HMAC is being
+ *                          calculated. This must point to a readable buffer
+ *                          of \p add_data_len bytes.
+ * \param add_data_len      The length of \p add_data in bytes.
+ * \param data              The buffer containing the second part of the
+ *                          message. This must point to a readable buffer
+ *                          of \p max_data_len bytes.
+ * \param data_len_secret   The length of the data to process in \p data.
+ *                          This must be no less than \p min_data_len and no
+ *                          greater than \p max_data_len.
+ * \param min_data_len      The minimal length of the second part of the
+ *                          message, read from \p data.
+ * \param max_data_len      The maximal length of the second part of the
+ *                          message, read from \p data.
+ * \param output            The HMAC will be written here. This must point to
+ *                          a writable buffer of sufficient size to hold the
+ *                          HMAC value.
+ *
+ * \retval 0 on success.
+ * \retval #MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED
+ *         The hardware accelerator failed.
+ */
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+int mbedtls_ct_hmac(mbedtls_svc_key_id_t key,
+                    psa_algorithm_t mac_alg,
+                    const unsigned char *add_data,
+                    size_t add_data_len,
+                    const unsigned char *data,
+                    size_t data_len_secret,
+                    size_t min_data_len,
+                    size_t max_data_len,
+                    unsigned char *output);
+#else
+int mbedtls_ct_hmac(mbedtls_md_context_t *ctx,
+                    const unsigned char *add_data,
+                    size_t add_data_len,
+                    const unsigned char *data,
+                    size_t data_len_secret,
+                    size_t min_data_len,
+                    size_t max_data_len,
+                    unsigned char *output);
+#endif /* defined(MBEDTLS_USE_PSA_CRYPTO) */
+#endif /* MBEDTLS_TEST_HOOKS && defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC) */
+
 #endif /* ssl_misc.h */
diff --git a/library/ssl_msg.c b/library/ssl_msg.c
index e36a653..c8ffc1e 100644
--- a/library/ssl_msg.c
+++ b/library/ssl_msg.c
@@ -60,6 +60,234 @@
 #define PSA_TO_MBEDTLS_ERR(status) local_err_translation(status)
 #endif
 
+#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+
+#if defined(PSA_WANT_ALG_SHA_384)
+#define MAX_HASH_BLOCK_LENGTH PSA_HASH_BLOCK_LENGTH(PSA_ALG_SHA_384)
+#elif defined(PSA_WANT_ALG_SHA_256)
+#define MAX_HASH_BLOCK_LENGTH PSA_HASH_BLOCK_LENGTH(PSA_ALG_SHA_256)
+#else /* See check_config.h */
+#define MAX_HASH_BLOCK_LENGTH PSA_HASH_BLOCK_LENGTH(PSA_ALG_SHA_1)
+#endif
+
+MBEDTLS_STATIC_TESTABLE
+int mbedtls_ct_hmac(mbedtls_svc_key_id_t key,
+                    psa_algorithm_t mac_alg,
+                    const unsigned char *add_data,
+                    size_t add_data_len,
+                    const unsigned char *data,
+                    size_t data_len_secret,
+                    size_t min_data_len,
+                    size_t max_data_len,
+                    unsigned char *output)
+{
+    /*
+     * This function breaks the HMAC abstraction and uses psa_hash_clone()
+     * extension in order to get constant-flow behaviour.
+     *
+     * HMAC(msg) is defined as HASH(okey + HASH(ikey + msg)) where + means
+     * concatenation, and okey/ikey are the XOR of the key with some fixed bit
+     * patterns (see RFC 2104, sec. 2).
+     *
+     * We'll first compute ikey/okey, then inner_hash = HASH(ikey + msg) by
+     * hashing up to minlen, then cloning the context, and for each byte up
+     * to maxlen finishing up the hash computation, keeping only the
+     * correct result.
+     *
+     * Then we only need to compute HASH(okey + inner_hash) and we're done.
+     */
+    psa_algorithm_t hash_alg = PSA_ALG_HMAC_GET_HASH(mac_alg);
+    const size_t block_size = PSA_HASH_BLOCK_LENGTH(hash_alg);
+    unsigned char key_buf[MAX_HASH_BLOCK_LENGTH];
+    const size_t hash_size = PSA_HASH_LENGTH(hash_alg);
+    psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
+    size_t hash_length;
+
+    unsigned char aux_out[PSA_HASH_MAX_SIZE];
+    psa_hash_operation_t aux_operation = PSA_HASH_OPERATION_INIT;
+    size_t offset;
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    size_t mac_key_length;
+    size_t i;
+
+#define PSA_CHK(func_call)        \
+    do {                            \
+        status = (func_call);       \
+        if (status != PSA_SUCCESS) \
+        goto cleanup;           \
+    } while (0)
+
+    /* Export MAC key
+     * We assume key length is always exactly the output size
+     * which is never more than the block size, thus we use block_size
+     * as the key buffer size.
+     */
+    PSA_CHK(psa_export_key(key, key_buf, block_size, &mac_key_length));
+
+    /* Calculate ikey */
+    for (i = 0; i < mac_key_length; i++) {
+        key_buf[i] = (unsigned char) (key_buf[i] ^ 0x36);
+    }
+    for (; i < block_size; ++i) {
+        key_buf[i] = 0x36;
+    }
+
+    PSA_CHK(psa_hash_setup(&operation, hash_alg));
+
+    /* Now compute inner_hash = HASH(ikey + msg) */
+    PSA_CHK(psa_hash_update(&operation, key_buf, block_size));
+    PSA_CHK(psa_hash_update(&operation, add_data, add_data_len));
+    PSA_CHK(psa_hash_update(&operation, data, min_data_len));
+
+    /* Fill the hash buffer in advance with something that is
+     * not a valid hash (barring an attack on the hash and
+     * deliberately-crafted input), in case the caller doesn't
+     * check the return status properly. */
+    memset(output, '!', hash_size);
+
+    /* For each possible length, compute the hash up to that point */
+    for (offset = min_data_len; offset <= max_data_len; offset++) {
+        PSA_CHK(psa_hash_clone(&operation, &aux_operation));
+        PSA_CHK(psa_hash_finish(&aux_operation, aux_out,
+                                PSA_HASH_MAX_SIZE, &hash_length));
+        /* Keep only the correct inner_hash in the output buffer */
+        mbedtls_ct_memcpy_if(mbedtls_ct_uint_eq(offset, data_len_secret),
+                             output, aux_out, NULL, hash_size);
+
+        if (offset < max_data_len) {
+            PSA_CHK(psa_hash_update(&operation, data + offset, 1));
+        }
+    }
+
+    /* Abort current operation to prepare for final operation */
+    PSA_CHK(psa_hash_abort(&operation));
+
+    /* Calculate okey */
+    for (i = 0; i < mac_key_length; i++) {
+        key_buf[i] = (unsigned char) ((key_buf[i] ^ 0x36) ^ 0x5C);
+    }
+    for (; i < block_size; ++i) {
+        key_buf[i] = 0x5C;
+    }
+
+    /* Now compute HASH(okey + inner_hash) */
+    PSA_CHK(psa_hash_setup(&operation, hash_alg));
+    PSA_CHK(psa_hash_update(&operation, key_buf, block_size));
+    PSA_CHK(psa_hash_update(&operation, output, hash_size));
+    PSA_CHK(psa_hash_finish(&operation, output, hash_size, &hash_length));
+
+#undef PSA_CHK
+
+cleanup:
+    mbedtls_platform_zeroize(key_buf, MAX_HASH_BLOCK_LENGTH);
+    mbedtls_platform_zeroize(aux_out, PSA_HASH_MAX_SIZE);
+
+    psa_hash_abort(&operation);
+    psa_hash_abort(&aux_operation);
+    return PSA_TO_MBEDTLS_ERR(status);
+}
+
+#undef MAX_HASH_BLOCK_LENGTH
+
+#else
+MBEDTLS_STATIC_TESTABLE
+int mbedtls_ct_hmac(mbedtls_md_context_t *ctx,
+                    const unsigned char *add_data,
+                    size_t add_data_len,
+                    const unsigned char *data,
+                    size_t data_len_secret,
+                    size_t min_data_len,
+                    size_t max_data_len,
+                    unsigned char *output)
+{
+    /*
+     * This function breaks the HMAC abstraction and uses the md_clone()
+     * extension to the MD API in order to get constant-flow behaviour.
+     *
+     * HMAC(msg) is defined as HASH(okey + HASH(ikey + msg)) where + means
+     * concatenation, and okey/ikey are the XOR of the key with some fixed bit
+     * patterns (see RFC 2104, sec. 2), which are stored in ctx->hmac_ctx.
+     *
+     * We'll first compute inner_hash = HASH(ikey + msg) by hashing up to
+     * minlen, then cloning the context, and for each byte up to maxlen
+     * finishing up the hash computation, keeping only the correct result.
+     *
+     * Then we only need to compute HASH(okey + inner_hash) and we're done.
+     */
+    const mbedtls_md_type_t md_alg = mbedtls_md_get_type(ctx->md_info);
+    /* TLS 1.2 only supports SHA-384, SHA-256, SHA-1, MD-5,
+     * all of which have the same block size except SHA-384. */
+    const size_t block_size = md_alg == MBEDTLS_MD_SHA384 ? 128 : 64;
+    const unsigned char * const ikey = ctx->hmac_ctx;
+    const unsigned char * const okey = ikey + block_size;
+    const size_t hash_size = mbedtls_md_get_size(ctx->md_info);
+
+    unsigned char aux_out[MBEDTLS_MD_MAX_SIZE];
+    mbedtls_md_context_t aux;
+    size_t offset;
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+    mbedtls_md_init(&aux);
+
+#define MD_CHK(func_call) \
+    do {                    \
+        ret = (func_call);  \
+        if (ret != 0)      \
+        goto cleanup;   \
+    } while (0)
+
+    MD_CHK(mbedtls_md_setup(&aux, ctx->md_info, 0));
+
+    /* After hmac_start() of hmac_reset(), ikey has already been hashed,
+     * so we can start directly with the message */
+    MD_CHK(mbedtls_md_update(ctx, add_data, add_data_len));
+    MD_CHK(mbedtls_md_update(ctx, data, min_data_len));
+
+    /* Fill the hash buffer in advance with something that is
+     * not a valid hash (barring an attack on the hash and
+     * deliberately-crafted input), in case the caller doesn't
+     * check the return status properly. */
+    memset(output, '!', hash_size);
+
+    /* For each possible length, compute the hash up to that point */
+    for (offset = min_data_len; offset <= max_data_len; offset++) {
+        MD_CHK(mbedtls_md_clone(&aux, ctx));
+        MD_CHK(mbedtls_md_finish(&aux, aux_out));
+        /* Keep only the correct inner_hash in the output buffer */
+        mbedtls_ct_memcpy_if(mbedtls_ct_uint_eq(offset, data_len_secret),
+                             output, aux_out, NULL, hash_size);
+
+        if (offset < max_data_len) {
+            MD_CHK(mbedtls_md_update(ctx, data + offset, 1));
+        }
+    }
+
+    /* The context needs to finish() before it starts() again */
+    MD_CHK(mbedtls_md_finish(ctx, aux_out));
+
+    /* Now compute HASH(okey + inner_hash) */
+    MD_CHK(mbedtls_md_starts(ctx));
+    MD_CHK(mbedtls_md_update(ctx, okey, block_size));
+    MD_CHK(mbedtls_md_update(ctx, output, hash_size));
+    MD_CHK(mbedtls_md_finish(ctx, output));
+
+    /* Done, get ready for next time */
+    MD_CHK(mbedtls_md_hmac_reset(ctx));
+
+#undef MD_CHK
+
+cleanup:
+    mbedtls_md_free(&aux);
+    return ret;
+}
+
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */
+
 static uint32_t ssl_get_hs_total_len(mbedtls_ssl_context const *ssl);
 
 /*
@@ -1690,11 +1918,11 @@
         padlen = data[rec->data_len - 1];
 
         if (auth_done == 1) {
-            const size_t mask = mbedtls_ct_size_mask_ge(
+            const mbedtls_ct_condition_t ge = mbedtls_ct_uint_ge(
                 rec->data_len,
                 padlen + 1);
-            correct &= mask;
-            padlen  &= mask;
+            correct = mbedtls_ct_size_if_else_0(ge, correct);
+            padlen  = mbedtls_ct_size_if_else_0(ge, padlen);
         } else {
 #if defined(MBEDTLS_SSL_DEBUG_ALL)
             if (rec->data_len < transform->maclen + padlen + 1) {
@@ -1706,12 +1934,11 @@
                                           padlen + 1));
             }
 #endif
-
-            const size_t mask = mbedtls_ct_size_mask_ge(
+            const mbedtls_ct_condition_t ge = mbedtls_ct_uint_ge(
                 rec->data_len,
                 transform->maclen + padlen + 1);
-            correct &= mask;
-            padlen  &= mask;
+            correct = mbedtls_ct_size_if_else_0(ge, correct);
+            padlen  = mbedtls_ct_size_if_else_0(ge, padlen);
         }
 
         padlen++;
@@ -1740,19 +1967,20 @@
             /* pad_count += (idx >= padding_idx) &&
              *              (check[idx] == padlen - 1);
              */
-            const size_t mask = mbedtls_ct_size_mask_ge(idx, padding_idx);
-            const size_t equal = mbedtls_ct_size_bool_eq(check[idx],
-                                                         padlen - 1);
-            pad_count += mask & equal;
+            const mbedtls_ct_condition_t a = mbedtls_ct_uint_ge(idx, padding_idx);
+            size_t increment = mbedtls_ct_size_if_else_0(a, 1);
+            const mbedtls_ct_condition_t b = mbedtls_ct_uint_eq(check[idx], padlen - 1);
+            increment = mbedtls_ct_size_if_else_0(b, increment);
+            pad_count += increment;
         }
-        correct &= mbedtls_ct_size_bool_eq(pad_count, padlen);
+        correct = mbedtls_ct_size_if_else_0(mbedtls_ct_uint_eq(pad_count, padlen), padlen);
 
 #if defined(MBEDTLS_SSL_DEBUG_ALL)
         if (padlen > 0 && correct == 0) {
             MBEDTLS_SSL_DEBUG_MSG(1, ("bad padding byte detected"));
         }
 #endif
-        padlen &= mbedtls_ct_size_mask(correct);
+        padlen = mbedtls_ct_size_if_else_0(mbedtls_ct_bool(correct), padlen);
 
 #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
 
diff --git a/library/ssl_tls12_server.c b/library/ssl_tls12_server.c
index 9b992d6..34ac091 100644
--- a/library/ssl_tls12_server.c
+++ b/library/ssl_tls12_server.c
@@ -3506,9 +3506,8 @@
     unsigned char *pms = ssl->handshake->premaster + pms_offset;
     unsigned char ver[2];
     unsigned char fake_pms[48], peer_pms[48];
-    unsigned char mask;
-    size_t i, peer_pmslen;
-    unsigned int diff;
+    size_t peer_pmslen;
+    mbedtls_ct_condition_t diff;
 
     /* In case of a failure in decryption, the decryption may write less than
      * 2 bytes of output, but we always read the first two bytes. It doesn't
@@ -3537,13 +3536,10 @@
     /* Avoid data-dependent branches while checking for invalid
      * padding, to protect against timing-based Bleichenbacher-type
      * attacks. */
-    diff  = (unsigned int) ret;
-    diff |= peer_pmslen ^ 48;
-    diff |= peer_pms[0] ^ ver[0];
-    diff |= peer_pms[1] ^ ver[1];
-
-    /* mask = diff ? 0xff : 0x00 using bit operations to avoid branches */
-    mask = mbedtls_ct_uint_mask(diff);
+    diff = mbedtls_ct_bool(ret);
+    diff = mbedtls_ct_bool_or(diff, mbedtls_ct_uint_ne(peer_pmslen, 48));
+    diff = mbedtls_ct_bool_or(diff, mbedtls_ct_uint_ne(peer_pms[0], ver[0]));
+    diff = mbedtls_ct_bool_or(diff, mbedtls_ct_uint_ne(peer_pms[1], ver[1]));
 
     /*
      * Protection against Bleichenbacher's attack: invalid PKCS#1 v1.5 padding
@@ -3562,7 +3558,7 @@
     }
 
 #if defined(MBEDTLS_SSL_DEBUG_ALL)
-    if (diff != 0) {
+    if (diff != MBEDTLS_CT_FALSE) {
         MBEDTLS_SSL_DEBUG_MSG(1, ("bad client key exchange message"));
     }
 #endif
@@ -3576,9 +3572,7 @@
 
     /* Set pms to either the true or the fake PMS, without
      * data-dependent branches. */
-    for (i = 0; i < ssl->handshake->pmslen; i++) {
-        pms[i] = (mask & fake_pms[i]) | ((~mask) & peer_pms[i]);
-    }
+    mbedtls_ct_memcpy_if(diff, pms, fake_pms, peer_pms, ssl->handshake->pmslen);
 
     return 0;
 }
diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c
index a063084..20cecdb 100644
--- a/library/ssl_tls13_generic.c
+++ b/library/ssl_tls13_generic.c
@@ -1521,6 +1521,7 @@
     return 0;
 }
 
+#if defined(PSA_WANT_ALG_FFDH)
 static psa_status_t  mbedtls_ssl_get_psa_ffdh_info_from_tls_id(
     uint16_t tls_id, size_t *bits, psa_key_type_t *key_type)
 {
@@ -1549,6 +1550,7 @@
             return PSA_ERROR_NOT_SUPPORTED;
     }
 }
+#endif /* PSA_WANT_ALG_FFDH */
 
 int mbedtls_ssl_tls13_generate_and_write_xxdh_key_exchange(
     mbedtls_ssl_context *ssl,
diff --git a/library/x509_create.c b/library/x509_create.c
index cdfc82a..bd772d3 100644
--- a/library/x509_create.c
+++ b/library/x509_create.c
@@ -285,9 +285,11 @@
 
 int mbedtls_x509_write_sig(unsigned char **p, unsigned char *start,
                            const char *oid, size_t oid_len,
-                           unsigned char *sig, size_t size)
+                           unsigned char *sig, size_t size,
+                           mbedtls_pk_type_t pk_alg)
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    int write_null_par;
     size_t len = 0;
 
     if (*p < start || (size_t) (*p - start) < size) {
@@ -310,8 +312,19 @@
 
     // Write OID
     //
-    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_algorithm_identifier(p, start, oid,
-                                                                      oid_len, 0));
+    if (pk_alg == MBEDTLS_PK_ECDSA) {
+        /*
+         * The AlgorithmIdentifier's parameters field must be absent for DSA/ECDSA signature
+         * algorithms, see https://www.rfc-editor.org/rfc/rfc5480#page-17 and
+         * https://www.rfc-editor.org/rfc/rfc5758#section-3.
+         */
+        write_null_par = 0;
+    } else {
+        write_null_par = 1;
+    }
+    MBEDTLS_ASN1_CHK_ADD(len,
+                         mbedtls_asn1_write_algorithm_identifier_ext(p, start, oid, oid_len,
+                                                                     0, write_null_par));
 
     return (int) len;
 }
diff --git a/library/x509_crt.c b/library/x509_crt.c
index b40bad2..2cbced2 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -1599,7 +1599,7 @@
 cleanup:
     FindClose(hFind);
 #else /* !_WIN32_WINNT_XP */
-#error mbedtls_x509_crt_parse_path not available before Windows XP
+#error "mbedtls_x509_crt_parse_path not available before Windows XP"
 #endif /* !_WIN32_WINNT_XP */
 #else /* _WIN32 */
     int t_ret;
diff --git a/library/x509write.c b/library/x509write.c
new file mode 100644
index 0000000..cd3c739
--- /dev/null
+++ b/library/x509write.c
@@ -0,0 +1,186 @@
+/*
+ *  X.509 internal, common functions for writing
+ *
+ *  Copyright The Mbed TLS Contributors
+ *  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.
+ */
+#include "common.h"
+#if defined(MBEDTLS_X509_CSR_WRITE_C) || defined(MBEDTLS_X509_CRT_WRITE_C)
+
+#include "mbedtls/x509_crt.h"
+#include "mbedtls/asn1write.h"
+#include "mbedtls/error.h"
+#include "mbedtls/oid.h"
+#include "mbedtls/platform.h"
+#include "mbedtls/platform_util.h"
+#include "mbedtls/md.h"
+
+#include <string.h>
+#include <stdint.h>
+
+#if defined(MBEDTLS_PEM_WRITE_C)
+#include "mbedtls/pem.h"
+#endif /* MBEDTLS_PEM_WRITE_C */
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+#include "psa/crypto.h"
+#include "mbedtls/psa_util.h"
+#include "md_psa.h"
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+#define CHECK_OVERFLOW_ADD(a, b) \
+    do                         \
+    {                           \
+        if (a > SIZE_MAX - (b)) \
+        { \
+            return MBEDTLS_ERR_X509_BAD_INPUT_DATA; \
+        }                            \
+        a += b; \
+    } while (0)
+
+int mbedtls_x509_write_set_san_common(mbedtls_asn1_named_data **extensions,
+                                      const mbedtls_x509_san_list *san_list)
+{
+    int ret = 0;
+    const mbedtls_x509_san_list *cur;
+    unsigned char *buf;
+    unsigned char *p;
+    size_t len;
+    size_t buflen = 0;
+
+    /* Determine the maximum size of the SubjectAltName list */
+    for (cur = san_list; cur != NULL; cur = cur->next) {
+        /* Calculate size of the required buffer */
+        switch (cur->node.type) {
+            case MBEDTLS_X509_SAN_DNS_NAME:
+            case MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER:
+            case MBEDTLS_X509_SAN_IP_ADDRESS:
+            case MBEDTLS_X509_SAN_RFC822_NAME:
+                /* length of value for each name entry,
+                 * maximum 4 bytes for the length field,
+                 * 1 byte for the tag/type.
+                 */
+                CHECK_OVERFLOW_ADD(buflen, cur->node.san.unstructured_name.len);
+                CHECK_OVERFLOW_ADD(buflen, 4 + 1);
+                break;
+            case MBEDTLS_X509_SAN_DIRECTORY_NAME:
+            {
+                const mbedtls_asn1_named_data *chunk = &cur->node.san.directory_name;
+                while (chunk != NULL) {
+                    // Max 4 bytes for length, +1 for tag,
+                    // additional 4 max for length, +1 for tag.
+                    // See x509_write_name for more information.
+                    CHECK_OVERFLOW_ADD(buflen, 4 + 1 + 4 + 1);
+                    CHECK_OVERFLOW_ADD(buflen, chunk->oid.len);
+                    CHECK_OVERFLOW_ADD(buflen, chunk->val.len);
+                    chunk = chunk->next;
+                }
+                CHECK_OVERFLOW_ADD(buflen, 4 + 1);
+                break;
+            }
+            default:
+                /* Not supported - return. */
+                return MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE;
+        }
+    }
+
+    /* Add the extra length field and tag */
+    CHECK_OVERFLOW_ADD(buflen, 4 + 1);
+
+    /* Allocate buffer */
+    buf = mbedtls_calloc(1, buflen);
+    if (buf == NULL) {
+        return MBEDTLS_ERR_ASN1_ALLOC_FAILED;
+    }
+    p = buf + buflen;
+
+    /* Write ASN.1-based structure */
+    cur = san_list;
+    len = 0;
+    while (cur != NULL) {
+        size_t single_san_len = 0;
+        switch (cur->node.type) {
+            case MBEDTLS_X509_SAN_DNS_NAME:
+            case MBEDTLS_X509_SAN_RFC822_NAME:
+            case MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER:
+            case MBEDTLS_X509_SAN_IP_ADDRESS:
+            {
+                const unsigned char *unstructured_name =
+                    (const unsigned char *) cur->node.san.unstructured_name.p;
+                size_t unstructured_name_len = cur->node.san.unstructured_name.len;
+
+                MBEDTLS_ASN1_CHK_CLEANUP_ADD(single_san_len,
+                                             mbedtls_asn1_write_raw_buffer(
+                                                 &p, buf,
+                                                 unstructured_name, unstructured_name_len));
+                MBEDTLS_ASN1_CHK_CLEANUP_ADD(single_san_len, mbedtls_asn1_write_len(
+                                                 &p, buf, unstructured_name_len));
+                MBEDTLS_ASN1_CHK_CLEANUP_ADD(single_san_len,
+                                             mbedtls_asn1_write_tag(
+                                                 &p, buf,
+                                                 MBEDTLS_ASN1_CONTEXT_SPECIFIC | cur->node.type));
+            }
+            break;
+            case MBEDTLS_X509_SAN_DIRECTORY_NAME:
+                MBEDTLS_ASN1_CHK_CLEANUP_ADD(single_san_len,
+                                             mbedtls_x509_write_names(&p, buf,
+                                                                      (mbedtls_asn1_named_data *) &
+                                                                      cur->node
+                                                                      .san.directory_name));
+                MBEDTLS_ASN1_CHK_CLEANUP_ADD(single_san_len,
+                                             mbedtls_asn1_write_len(&p, buf, single_san_len));
+                MBEDTLS_ASN1_CHK_CLEANUP_ADD(single_san_len,
+                                             mbedtls_asn1_write_tag(&p, buf,
+                                                                    MBEDTLS_ASN1_CONTEXT_SPECIFIC |
+                                                                    MBEDTLS_ASN1_CONSTRUCTED |
+                                                                    MBEDTLS_X509_SAN_DIRECTORY_NAME));
+                break;
+            default:
+                /* Error out on an unsupported SAN */
+                ret = MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE;
+                goto cleanup;
+        }
+        cur = cur->next;
+        /* check for overflow */
+        if (len > SIZE_MAX - single_san_len) {
+            ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA;
+            goto cleanup;
+        }
+        len += single_san_len;
+    }
+
+    MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_len(&p, buf, len));
+    MBEDTLS_ASN1_CHK_CLEANUP_ADD(len,
+                                 mbedtls_asn1_write_tag(&p, buf,
+                                                        MBEDTLS_ASN1_CONSTRUCTED |
+                                                        MBEDTLS_ASN1_SEQUENCE));
+
+    ret = mbedtls_x509_set_extension(extensions,
+                                     MBEDTLS_OID_SUBJECT_ALT_NAME,
+                                     MBEDTLS_OID_SIZE(MBEDTLS_OID_SUBJECT_ALT_NAME),
+                                     0,
+                                     buf + buflen - len, len);
+
+    /* If we exceeded the allocated buffer it means that maximum size of the SubjectAltName list
+     * was incorrectly calculated and memory is corrupted. */
+    if (p < buf) {
+        ret = MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
+    }
+cleanup:
+    mbedtls_free(buf);
+    return ret;
+}
+
+#endif /* MBEDTLS_X509_CSR_WRITE_C || MBEDTLS_X509_CRT_WRITE_C */
diff --git a/library/x509write_crt.c b/library/x509write_crt.c
index bcee4dc..a8a3022 100644
--- a/library/x509write_crt.c
+++ b/library/x509write_crt.c
@@ -48,16 +48,6 @@
 #include "md_psa.h"
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
-#define CHECK_OVERFLOW_ADD(a, b) \
-    do                         \
-    {                           \
-        if (a > SIZE_MAX - (b)) \
-        { \
-            return MBEDTLS_ERR_X509_BAD_INPUT_DATA; \
-        }                            \
-        a += b; \
-    } while (0)
-
 void mbedtls_x509write_crt_init(mbedtls_x509write_cert *ctx)
 {
     memset(ctx, 0, sizeof(mbedtls_x509write_cert));
@@ -166,131 +156,7 @@
 int mbedtls_x509write_crt_set_subject_alternative_name(mbedtls_x509write_cert *ctx,
                                                        const mbedtls_x509_san_list *san_list)
 {
-    int ret = 0;
-    const mbedtls_x509_san_list *cur;
-    unsigned char *buf;
-    unsigned char *p;
-    size_t len;
-    size_t buflen = 0;
-
-    /* Determine the maximum size of the SubjectAltName list */
-    for (cur = san_list; cur != NULL; cur = cur->next) {
-        /* Calculate size of the required buffer */
-        switch (cur->node.type) {
-            case MBEDTLS_X509_SAN_DNS_NAME:
-            case MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER:
-            case MBEDTLS_X509_SAN_IP_ADDRESS:
-            case MBEDTLS_X509_SAN_RFC822_NAME:
-                /* length of value for each name entry,
-                 * maximum 4 bytes for the length field,
-                 * 1 byte for the tag/type.
-                 */
-                CHECK_OVERFLOW_ADD(buflen, cur->node.san.unstructured_name.len);
-                CHECK_OVERFLOW_ADD(buflen, 4 + 1);
-                break;
-            case MBEDTLS_X509_SAN_DIRECTORY_NAME:
-            {
-                const mbedtls_asn1_named_data *chunk = &cur->node.san.directory_name;
-                while (chunk != NULL) {
-                    // Max 4 bytes for length, +1 for tag,
-                    // additional 4 max for length, +1 for tag.
-                    // See x509_write_name for more information.
-                    CHECK_OVERFLOW_ADD(buflen, 4 + 1 + 4 + 1);
-                    CHECK_OVERFLOW_ADD(buflen, chunk->oid.len);
-                    CHECK_OVERFLOW_ADD(buflen, chunk->val.len);
-                    chunk = chunk->next;
-                }
-                CHECK_OVERFLOW_ADD(buflen, 4 + 1);
-                break;
-            }
-            default:
-                /* Not supported - return. */
-                return MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE;
-        }
-    }
-
-    /* Add the extra length field and tag */
-    CHECK_OVERFLOW_ADD(buflen, 4 + 1);
-
-    /* Allocate buffer */
-    buf = mbedtls_calloc(1, buflen);
-    if (buf == NULL) {
-        return MBEDTLS_ERR_ASN1_ALLOC_FAILED;
-    }
-    p = buf + buflen;
-
-    /* Write ASN.1-based structure */
-    cur = san_list;
-    len = 0;
-    while (cur != NULL) {
-        size_t single_san_len = 0;
-        switch (cur->node.type) {
-            case MBEDTLS_X509_SAN_DNS_NAME:
-            case MBEDTLS_X509_SAN_RFC822_NAME:
-            case MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER:
-            case MBEDTLS_X509_SAN_IP_ADDRESS:
-            {
-                const unsigned char *unstructured_name =
-                    (const unsigned char *) cur->node.san.unstructured_name.p;
-                size_t unstructured_name_len = cur->node.san.unstructured_name.len;
-
-                MBEDTLS_ASN1_CHK_CLEANUP_ADD(single_san_len,
-                                             mbedtls_asn1_write_raw_buffer(
-                                                 &p, buf,
-                                                 unstructured_name, unstructured_name_len));
-                MBEDTLS_ASN1_CHK_CLEANUP_ADD(single_san_len, mbedtls_asn1_write_len(
-                                                 &p, buf, unstructured_name_len));
-                MBEDTLS_ASN1_CHK_CLEANUP_ADD(single_san_len,
-                                             mbedtls_asn1_write_tag(
-                                                 &p, buf,
-                                                 MBEDTLS_ASN1_CONTEXT_SPECIFIC | cur->node.type));
-            }
-            break;
-            case MBEDTLS_X509_SAN_DIRECTORY_NAME:
-                MBEDTLS_ASN1_CHK_CLEANUP_ADD(single_san_len,
-                                             mbedtls_x509_write_names(&p, buf,
-                                                                      (mbedtls_asn1_named_data *) &
-                                                                      cur->node
-                                                                      .san.directory_name));
-                MBEDTLS_ASN1_CHK_CLEANUP_ADD(single_san_len,
-                                             mbedtls_asn1_write_len(&p, buf, single_san_len));
-                MBEDTLS_ASN1_CHK_CLEANUP_ADD(single_san_len,
-                                             mbedtls_asn1_write_tag(&p, buf,
-                                                                    MBEDTLS_ASN1_CONTEXT_SPECIFIC |
-                                                                    MBEDTLS_ASN1_CONSTRUCTED |
-                                                                    MBEDTLS_X509_SAN_DIRECTORY_NAME));
-                break;
-            default:
-                /* Error out on an unsupported SAN */
-                ret = MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE;
-                goto cleanup;
-        }
-        cur = cur->next;
-        /* check for overflow */
-        if (len > SIZE_MAX - single_san_len) {
-            ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA;
-            goto cleanup;
-        }
-        len += single_san_len;
-    }
-
-    MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_len(&p, buf, len));
-    MBEDTLS_ASN1_CHK_CLEANUP_ADD(len,
-                                 mbedtls_asn1_write_tag(&p, buf,
-                                                        MBEDTLS_ASN1_CONSTRUCTED |
-                                                        MBEDTLS_ASN1_SEQUENCE));
-
-    ret = mbedtls_x509write_crt_set_extension(
-        ctx,
-        MBEDTLS_OID_SUBJECT_ALT_NAME,
-        MBEDTLS_OID_SIZE(MBEDTLS_OID_SUBJECT_ALT_NAME),
-        0,
-        buf + buflen - len,
-        len);
-
-cleanup:
-    mbedtls_free(buf);
-    return ret;
+    return mbedtls_x509_write_set_san_common(&ctx->extensions, san_list);
 }
 
 
@@ -577,6 +443,7 @@
     size_t sub_len = 0, pub_len = 0, sig_and_oid_len = 0, sig_len;
     size_t len = 0;
     mbedtls_pk_type_t pk_alg;
+    int write_sig_null_par;
 
     /*
      * Prepare data to be signed at the end of the target buffer
@@ -668,9 +535,20 @@
     /*
      *  Signature   ::=  AlgorithmIdentifier
      */
+    if (pk_alg == MBEDTLS_PK_ECDSA) {
+        /*
+         * The AlgorithmIdentifier's parameters field must be absent for DSA/ECDSA signature
+         * algorithms, see https://www.rfc-editor.org/rfc/rfc5480#page-17 and
+         * https://www.rfc-editor.org/rfc/rfc5758#section-3.
+         */
+        write_sig_null_par = 0;
+    } else {
+        write_sig_null_par = 1;
+    }
     MBEDTLS_ASN1_CHK_ADD(len,
-                         mbedtls_asn1_write_algorithm_identifier(&c, buf,
-                                                                 sig_oid, strlen(sig_oid), 0));
+                         mbedtls_asn1_write_algorithm_identifier_ext(&c, buf,
+                                                                     sig_oid, strlen(sig_oid),
+                                                                     0, write_sig_null_par));
 
     /*
      *  Serial   ::=  INTEGER
@@ -762,8 +640,8 @@
      * into the CRT buffer. */
     c2 = buf + size;
     MBEDTLS_ASN1_CHK_ADD(sig_and_oid_len, mbedtls_x509_write_sig(&c2, c,
-                                                                 sig_oid, sig_oid_len, sig,
-                                                                 sig_len));
+                                                                 sig_oid, sig_oid_len,
+                                                                 sig, sig_len, pk_alg));
 
     /*
      * Memory layout after this step:
diff --git a/library/x509write_csr.c b/library/x509write_csr.c
index b67cdde..d996052 100644
--- a/library/x509write_csr.c
+++ b/library/x509write_csr.c
@@ -89,100 +89,7 @@
 int mbedtls_x509write_csr_set_subject_alternative_name(mbedtls_x509write_csr *ctx,
                                                        const mbedtls_x509_san_list *san_list)
 {
-    int ret = 0;
-    const mbedtls_x509_san_list *cur;
-    unsigned char *buf;
-    unsigned char *p;
-    size_t len;
-    size_t buflen = 0;
-
-    /* Determine the maximum size of the SubjectAltName list */
-    for (cur = san_list; cur != NULL; cur = cur->next) {
-        /* Calculate size of the required buffer */
-        switch (cur->node.type) {
-            case MBEDTLS_X509_SAN_DNS_NAME:
-            case MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER:
-            case MBEDTLS_X509_SAN_IP_ADDRESS:
-                /* length of value for each name entry,
-                 * maximum 4 bytes for the length field,
-                 * 1 byte for the tag/type.
-                 */
-                buflen += cur->node.san.unstructured_name.len + 4 + 1;
-                break;
-
-            default:
-                /* Not supported - skip. */
-                break;
-        }
-    }
-
-    /* Add the extra length field and tag */
-    buflen += 4 + 1;
-
-    /* Allocate buffer */
-    buf = mbedtls_calloc(1, buflen);
-    if (buf == NULL) {
-        return MBEDTLS_ERR_ASN1_ALLOC_FAILED;
-    }
-
-    mbedtls_platform_zeroize(buf, buflen);
-    p = buf + buflen;
-
-    /* Write ASN.1-based structure */
-    cur = san_list;
-    len = 0;
-    while (cur != NULL) {
-        switch (cur->node.type) {
-            case MBEDTLS_X509_SAN_DNS_NAME:
-            case MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER:
-            case MBEDTLS_X509_SAN_IP_ADDRESS:
-            {
-                const unsigned char *unstructured_name =
-                    (const unsigned char *) cur->node.san.unstructured_name.p;
-                size_t unstructured_name_len = cur->node.san.unstructured_name.len;
-
-                MBEDTLS_ASN1_CHK_CLEANUP_ADD(len,
-                                             mbedtls_asn1_write_raw_buffer(
-                                                 &p, buf,
-                                                 unstructured_name, unstructured_name_len));
-                MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_len(
-                                                 &p, buf, unstructured_name_len));
-                MBEDTLS_ASN1_CHK_CLEANUP_ADD(len,
-                                             mbedtls_asn1_write_tag(
-                                                 &p, buf,
-                                                 MBEDTLS_ASN1_CONTEXT_SPECIFIC | cur->node.type));
-            }
-            break;
-            default:
-                /* Skip unsupported names. */
-                break;
-        }
-        cur = cur->next;
-    }
-
-    MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_len(&p, buf, len));
-    MBEDTLS_ASN1_CHK_CLEANUP_ADD(len,
-                                 mbedtls_asn1_write_tag(&p, buf,
-                                                        MBEDTLS_ASN1_CONSTRUCTED |
-                                                        MBEDTLS_ASN1_SEQUENCE));
-
-    ret = mbedtls_x509write_csr_set_extension(
-        ctx,
-        MBEDTLS_OID_SUBJECT_ALT_NAME,
-        MBEDTLS_OID_SIZE(MBEDTLS_OID_SUBJECT_ALT_NAME),
-        0,
-        buf + buflen - len,
-        len);
-
-    /* If we exceeded the allocated buffer it means that maximum size of the SubjectAltName list
-     * was incorrectly calculated and memory is corrupted. */
-    if (p < buf) {
-        ret = MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
-    }
-
-cleanup:
-    mbedtls_free(buf);
-    return ret;
+    return mbedtls_x509_write_set_san_common(&ctx->extensions, san_list);
 }
 
 int mbedtls_x509write_csr_set_key_usage(mbedtls_x509write_csr *ctx, unsigned char key_usage)
@@ -363,7 +270,7 @@
     c2 = buf + size;
     MBEDTLS_ASN1_CHK_ADD(sig_and_oid_len,
                          mbedtls_x509_write_sig(&c2, buf + len, sig_oid, sig_oid_len,
-                                                sig, sig_len));
+                                                sig, sig_len, pk_alg));
 
     /*
      * Compact the space between the CSR data and signature by moving the
diff --git a/programs/.gitignore b/programs/.gitignore
index d11db9e..a641c31 100644
--- a/programs/.gitignore
+++ b/programs/.gitignore
@@ -5,10 +5,6 @@
 *.sln
 *.vcxproj
 
-# Generated source files
-/psa/psa_constant_names_generated.c
-/test/query_config.c
-
 aes/crypt_and_hash
 cipher/cipher_aead_demo
 hash/generic_sum
@@ -75,5 +71,11 @@
 x509/load_roots
 x509/req_app
 
+###START_GENERATED_FILES###
+# Generated source files
+/psa/psa_constant_names_generated.c
+/test/query_config.c
+
 # Generated data files
 pkey/keyfile.key
+###END_GENERATED_FILES###
diff --git a/programs/pkey/gen_key.c b/programs/pkey/gen_key.c
index 9bee275..99e8850 100644
--- a/programs/pkey/gen_key.c
+++ b/programs/pkey/gen_key.c
@@ -180,7 +180,9 @@
     char buf[1024];
     int i;
     char *p, *q;
+#if defined(MBEDTLS_RSA_C)
     mbedtls_mpi N, P, Q, D, E, DP, DQ, QP;
+#endif /* MBEDTLS_RSA_C */
     mbedtls_entropy_context entropy;
     mbedtls_ctr_drbg_context ctr_drbg;
     const char *pers = "gen_key";
@@ -191,10 +193,11 @@
     /*
      * Set to sane values
      */
-
+#if defined(MBEDTLS_RSA_C)
     mbedtls_mpi_init(&N); mbedtls_mpi_init(&P); mbedtls_mpi_init(&Q);
     mbedtls_mpi_init(&D); mbedtls_mpi_init(&E); mbedtls_mpi_init(&DP);
     mbedtls_mpi_init(&DQ); mbedtls_mpi_init(&QP);
+#endif /* MBEDTLS_RSA_C */
 
     mbedtls_pk_init(&key);
     mbedtls_ctr_drbg_init(&ctr_drbg);
@@ -409,9 +412,11 @@
 #endif
     }
 
+#if defined(MBEDTLS_RSA_C)
     mbedtls_mpi_free(&N); mbedtls_mpi_free(&P); mbedtls_mpi_free(&Q);
     mbedtls_mpi_free(&D); mbedtls_mpi_free(&E); mbedtls_mpi_free(&DP);
     mbedtls_mpi_free(&DQ); mbedtls_mpi_free(&QP);
+#endif /* MBEDTLS_RSA_C */
 
     mbedtls_pk_free(&key);
     mbedtls_ctr_drbg_free(&ctr_drbg);
diff --git a/programs/pkey/key_app_writer.c b/programs/pkey/key_app_writer.c
index e8f3e85..179094c 100644
--- a/programs/pkey/key_app_writer.c
+++ b/programs/pkey/key_app_writer.c
@@ -203,7 +203,9 @@
     mbedtls_ctr_drbg_context ctr_drbg;
 
     mbedtls_pk_context key;
+#if defined(MBEDTLS_RSA_C)
     mbedtls_mpi N, P, Q, D, E, DP, DQ, QP;
+#endif /* MBEDTLS_RSA_C */
 
     /*
      * Set to sane values
@@ -225,9 +227,11 @@
     }
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
+#if defined(MBEDTLS_RSA_C)
     mbedtls_mpi_init(&N); mbedtls_mpi_init(&P); mbedtls_mpi_init(&Q);
     mbedtls_mpi_init(&D); mbedtls_mpi_init(&E); mbedtls_mpi_init(&DP);
     mbedtls_mpi_init(&DQ); mbedtls_mpi_init(&QP);
+#endif /* MBEDTLS_RSA_C */
 
     if (argc < 2) {
 usage:
@@ -423,9 +427,11 @@
 #endif
     }
 
+#if defined(MBEDTLS_RSA_C)
     mbedtls_mpi_free(&N); mbedtls_mpi_free(&P); mbedtls_mpi_free(&Q);
     mbedtls_mpi_free(&D); mbedtls_mpi_free(&E); mbedtls_mpi_free(&DP);
     mbedtls_mpi_free(&DQ); mbedtls_mpi_free(&QP);
+#endif /* MBEDTLS_RSA_C */
 
     mbedtls_pk_free(&key);
 
diff --git a/programs/test/generate_cpp_dummy_build.sh b/programs/test/generate_cpp_dummy_build.sh
index 94e9115..2541683 100755
--- a/programs/test/generate_cpp_dummy_build.sh
+++ b/programs/test/generate_cpp_dummy_build.sh
@@ -63,6 +63,7 @@
     for header in include/mbedtls/*.h include/psa/*.h; do
         case ${header#include/} in
             mbedtls/mbedtls_config.h) :;; # not meant for direct inclusion
+            mbedtls/config_*.h) :;; # not meant for direct inclusion
             psa/crypto_config.h) :;; # not meant for direct inclusion
             # Some of the psa/crypto_*.h headers are not meant to be included
             # directly. They do have include guards that make them no-ops if
diff --git a/programs/test/selftest.c b/programs/test/selftest.c
index f896d4f..cc5e00e 100644
--- a/programs/test/selftest.c
+++ b/programs/test/selftest.c
@@ -73,23 +73,51 @@
     void *empty2 = mbedtls_calloc(0, 1);
     void *buffer1 = mbedtls_calloc(1, 1);
     void *buffer2 = mbedtls_calloc(1, 1);
+    unsigned int buffer_3_size = 256;
+    unsigned int buffer_4_size = 4097; /* Allocate more than the usual page size */
+    unsigned char *buffer3 = mbedtls_calloc(buffer_3_size, 1);
+    unsigned char *buffer4 = mbedtls_calloc(buffer_4_size, 1);
 
     if (empty1 == NULL && empty2 == NULL) {
         if (verbose) {
-            mbedtls_printf("  CALLOC(0): passed (NULL)\n");
+            mbedtls_printf("  CALLOC(0,1): passed (NULL)\n");
         }
     } else if (empty1 == NULL || empty2 == NULL) {
         if (verbose) {
-            mbedtls_printf("  CALLOC(0): failed (mix of NULL and non-NULL)\n");
+            mbedtls_printf("  CALLOC(0,1): failed (mix of NULL and non-NULL)\n");
         }
         ++failures;
     } else if (empty1 == empty2) {
         if (verbose) {
-            mbedtls_printf("  CALLOC(0): passed (same non-null)\n");
+            mbedtls_printf("  CALLOC(0,1): passed (same non-null)\n");
         }
     } else {
         if (verbose) {
-            mbedtls_printf("  CALLOC(0): passed (distinct non-null)\n");
+            mbedtls_printf("  CALLOC(0,1): passed (distinct non-null)\n");
+        }
+    }
+
+    mbedtls_free(empty1);
+    mbedtls_free(empty2);
+
+    empty1 = mbedtls_calloc(1, 0);
+    empty2 = mbedtls_calloc(1, 0);
+    if (empty1 == NULL && empty2 == NULL) {
+        if (verbose) {
+            mbedtls_printf("  CALLOC(1,0): passed (NULL)\n");
+        }
+    } else if (empty1 == NULL || empty2 == NULL) {
+        if (verbose) {
+            mbedtls_printf("  CALLOC(1,0): failed (mix of NULL and non-NULL)\n");
+        }
+        ++failures;
+    } else if (empty1 == empty2) {
+        if (verbose) {
+            mbedtls_printf("  CALLOC(1,0): passed (same non-null)\n");
+        }
+    } else {
+        if (verbose) {
+            mbedtls_printf("  CALLOC(1,0): passed (distinct non-null)\n");
         }
     }
 
@@ -122,6 +150,28 @@
         }
     }
 
+    for (unsigned int i = 0; i < buffer_3_size; i++) {
+        if (buffer3[i] != 0) {
+            ++failures;
+            if (verbose) {
+                mbedtls_printf("  CALLOC(%u): failed (memory not initialized to 0)\n",
+                               buffer_3_size);
+            }
+            break;
+        }
+    }
+
+    for (unsigned int i = 0; i < buffer_4_size; i++) {
+        if (buffer4[i] != 0) {
+            ++failures;
+            if (verbose) {
+                mbedtls_printf("  CALLOC(%u): failed (memory not initialized to 0)\n",
+                               buffer_4_size);
+            }
+            break;
+        }
+    }
+
     if (verbose) {
         mbedtls_printf("\n");
     }
@@ -129,6 +179,8 @@
     mbedtls_free(empty2);
     mbedtls_free(buffer1);
     mbedtls_free(buffer2);
+    mbedtls_free(buffer3);
+    mbedtls_free(buffer4);
     return failures;
 }
 #endif /* MBEDTLS_SELF_TEST */
diff --git a/programs/x509/cert_req.c b/programs/x509/cert_req.c
index 23e816b..558d8cc 100644
--- a/programs/x509/cert_req.c
+++ b/programs/x509/cert_req.c
@@ -23,10 +23,10 @@
 /* md.h is included this early since MD_CAN_XXX macros are defined there. */
 #include "mbedtls/md.h"
 
-#if !defined(MBEDTLS_X509_CSR_WRITE_C) || !defined(MBEDTLS_FS_IO) ||  \
+#if !defined(MBEDTLS_X509_CSR_WRITE_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \
     !defined(MBEDTLS_PK_PARSE_C) || !defined(MBEDTLS_MD_CAN_SHA256) || \
     !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_CTR_DRBG_C) || \
-    !defined(MBEDTLS_PEM_WRITE_C)
+    !defined(MBEDTLS_PEM_WRITE_C) || !defined(MBEDTLS_FS_IO)
 int main(void)
 {
     mbedtls_printf("MBEDTLS_X509_CSR_WRITE_C and/or MBEDTLS_FS_IO and/or "
@@ -66,10 +66,12 @@
     "    output_file=%%s      default: cert.req\n"      \
     "    subject_name=%%s     default: CN=Cert,O=mbed TLS,C=UK\n"   \
     "    san=%%s              default: (none)\n"       \
-    "                        Semicolon-separated-list of values:\n"     \
-    "                          DNS:value\n"            \
-    "                          URI:value\n"            \
-    "                          IP:value (Only IPv4 is supported)\n"             \
+    "                           Semicolon-separated-list of values:\n" \
+    "                           DNS:value\n"            \
+    "                           URI:value\n"            \
+    "                           RFC822:value\n"         \
+    "                           IP:value (Only IPv4 is supported)\n" \
+    "                           DN:list of comma separated key=value pairs\n" \
     "    key_usage=%%s        default: (empty)\n"       \
     "                        Comma-separated-list of values:\n"     \
     "                          digital_signature\n"     \
@@ -153,12 +155,13 @@
     mbedtls_pk_context key;
     char buf[1024];
     int i;
-    char *p, *q, *r, *subtype_value;
+    char *p, *q, *r;
     mbedtls_x509write_csr req;
     mbedtls_entropy_context entropy;
     mbedtls_ctr_drbg_context ctr_drbg;
     const char *pers = "csr example app";
     mbedtls_x509_san_list *cur, *prev;
+    mbedtls_asn1_named_data *ext_san_dirname = NULL;
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
     uint8_t ip[4] = { 0 };
 #endif
@@ -218,11 +221,34 @@
         } else if (strcmp(p, "subject_name") == 0) {
             opt.subject_name = q;
         } else if (strcmp(p, "san") == 0) {
+            char *subtype_value;
             prev = NULL;
 
             while (q != NULL) {
-                if ((r = strchr(q, ';')) != NULL) {
+                char *semicolon;
+                r = q;
+
+                /* Find the first non-escaped ; occurrence and remove escaped ones */
+                do {
+                    if ((semicolon = strchr(r, ';')) != NULL) {
+                        if (*(semicolon-1) != '\\') {
+                            r = semicolon;
+                            break;
+                        }
+                        /* Remove the escape character */
+                        size_t size_left = strlen(semicolon);
+                        memmove(semicolon-1, semicolon, size_left);
+                        *(semicolon + size_left - 1) = '\0';
+                        /* r will now point at the character after the semicolon */
+                        r = semicolon;
+                    }
+
+                } while (semicolon != NULL);
+
+                if (semicolon != NULL) {
                     *r++ = '\0';
+                } else {
+                    r = NULL;
                 }
 
                 cur = mbedtls_calloc(1, sizeof(mbedtls_x509_san_list));
@@ -236,13 +262,13 @@
                 if ((subtype_value = strchr(q, ':')) != NULL) {
                     *subtype_value++ = '\0';
                 }
-
-                if (strcmp(q, "URI") == 0) {
+                if (strcmp(q, "RFC822") == 0) {
+                    cur->node.type = MBEDTLS_X509_SAN_RFC822_NAME;
+                } else if (strcmp(q, "URI") == 0) {
                     cur->node.type = MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER;
                 } else if (strcmp(q, "DNS") == 0) {
                     cur->node.type = MBEDTLS_X509_SAN_DNS_NAME;
                 } else if (strcmp(q, "IP") == 0) {
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
                     size_t ip_len = 0;
                     cur->node.type = MBEDTLS_X509_SAN_IP_ADDRESS;
                     ip_len = mbedtls_x509_crt_parse_cn_inet_pton(subtype_value, ip);
@@ -251,21 +277,28 @@
                                        subtype_value);
                         goto exit;
                     }
-#else
-                    mbedtls_printf("IP SAN parsing requires MBEDTLS_X509_CRT_PARSE_C to be defined");
-                    goto exit;
-#endif
+                    cur->node.san.unstructured_name.p = (unsigned char *) ip;
+                    cur->node.san.unstructured_name.len = sizeof(ip);
+                } else if (strcmp(q, "DN") == 0) {
+                    cur->node.type = MBEDTLS_X509_SAN_DIRECTORY_NAME;
+                    if ((ret = mbedtls_x509_string_to_names(&ext_san_dirname,
+                                                            subtype_value)) != 0) {
+                        mbedtls_strerror(ret, buf, sizeof(buf));
+                        mbedtls_printf(
+                            " failed\n  !  mbedtls_x509_string_to_names "
+                            "returned -0x%04x - %s\n\n",
+                            (unsigned int) -ret, buf);
+                        goto exit;
+                    }
+                    cur->node.san.directory_name = *ext_san_dirname;
                 } else {
                     mbedtls_free(cur);
                     goto usage;
                 }
 
-                if (strcmp(q, "IP") == 0) {
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
-                    cur->node.san.unstructured_name.p = (unsigned char *) ip;
-                    cur->node.san.unstructured_name.len = sizeof(ip);
-#endif
-                } else {
+                if (cur->node.type == MBEDTLS_X509_SAN_RFC822_NAME ||
+                    cur->node.type == MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER ||
+                    cur->node.type == MBEDTLS_X509_SAN_DNS_NAME) {
                     q = subtype_value;
                     cur->node.san.unstructured_name.p = (unsigned char *) q;
                     cur->node.san.unstructured_name.len = strlen(q);
@@ -280,7 +313,6 @@
                 prev = cur;
                 q = r;
             }
-
         } else if (strcmp(p, "md") == 0) {
             const mbedtls_md_info_t *md_info =
                 mbedtls_md_info_from_string(q);
@@ -467,6 +499,7 @@
     }
 
     mbedtls_x509write_csr_free(&req);
+    mbedtls_asn1_free_named_data_list(&ext_san_dirname);
     mbedtls_pk_free(&key);
     mbedtls_ctr_drbg_free(&ctr_drbg);
     mbedtls_entropy_free(&entropy);
diff --git a/programs/x509/cert_write.c b/programs/x509/cert_write.c
index e58f528..40b1871 100644
--- a/programs/x509/cert_write.c
+++ b/programs/x509/cert_write.c
@@ -530,6 +530,8 @@
                     SET_OID(ext_key_usage->buf, MBEDTLS_OID_TIME_STAMPING);
                 } else if (strcmp(q, "OCSPSigning") == 0) {
                     SET_OID(ext_key_usage->buf, MBEDTLS_OID_OCSP_SIGNING);
+                } else if (strcmp(q, "any") == 0) {
+                    SET_OID(ext_key_usage->buf, MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE);
                 } else {
                     mbedtls_printf("Invalid argument for option %s\n", p);
                     goto usage;
diff --git a/scripts/code_size_compare.py b/scripts/code_size_compare.py
index 0ed2899..53d859e 100755
--- a/scripts/code_size_compare.py
+++ b/scripts/code_size_compare.py
@@ -24,15 +24,18 @@
 # limitations under the License.
 
 import argparse
+import logging
 import os
 import re
+import shutil
 import subprocess
 import sys
 import typing
 from enum import Enum
 
-from mbedtls_dev import typing_util
 from mbedtls_dev import build_tree
+from mbedtls_dev import logging_util
+from mbedtls_dev import typing_util
 
 class SupportedArch(Enum):
     """Supported architecture for code size measurement."""
@@ -42,13 +45,13 @@
     X86_64 = 'x86_64'
     X86 = 'x86'
 
-CONFIG_TFM_MEDIUM_MBEDCRYPTO_H = "../configs/tfm_mbedcrypto_config_profile_medium.h"
-CONFIG_TFM_MEDIUM_PSA_CRYPTO_H = "../configs/crypto_config_profile_medium.h"
+
 class SupportedConfig(Enum):
     """Supported configuration for code size measurement."""
     DEFAULT = 'default'
     TFM_MEDIUM = 'tfm-medium'
 
+
 # Static library
 MBEDTLS_STATIC_LIB = {
     'CRYPTO': 'library/libmbedcrypto.a',
@@ -56,23 +59,111 @@
     'TLS': 'library/libmbedtls.a',
 }
 
+class CodeSizeDistinctInfo: # pylint: disable=too-few-public-methods
+    """Data structure to store possibly distinct information for code size
+    comparison."""
+    def __init__( #pylint: disable=too-many-arguments
+            self,
+            version: str,
+            git_rev: str,
+            arch: str,
+            config: str,
+            compiler: str,
+            opt_level: str,
+    ) -> None:
+        """
+        :param: version: which version to compare with for code size.
+        :param: git_rev: Git revision to calculate code size.
+        :param: arch: architecture to measure code size on.
+        :param: config: Configuration type to calculate code size.
+                        (See SupportedConfig)
+        :param: compiler: compiler used to build library/*.o.
+        :param: opt_level: Options that control optimization. (E.g. -Os)
+        """
+        self.version = version
+        self.git_rev = git_rev
+        self.arch = arch
+        self.config = config
+        self.compiler = compiler
+        self.opt_level = opt_level
+        # Note: Variables below are not initialized by class instantiation.
+        self.pre_make_cmd = [] #type: typing.List[str]
+        self.make_cmd = ''
+
+    def get_info_indication(self):
+        """Return a unique string to indicate Code Size Distinct Information."""
+        return '{git_rev}-{arch}-{config}-{compiler}'.format(**self.__dict__)
+
+
+class CodeSizeCommonInfo: # pylint: disable=too-few-public-methods
+    """Data structure to store common information for code size comparison."""
+    def __init__(
+            self,
+            host_arch: str,
+            measure_cmd: str,
+    ) -> None:
+        """
+        :param host_arch: host architecture.
+        :param measure_cmd: command to measure code size for library/*.o.
+        """
+        self.host_arch = host_arch
+        self.measure_cmd = measure_cmd
+
+    def get_info_indication(self):
+        """Return a unique string to indicate Code Size Common Information."""
+        return '{measure_tool}'\
+               .format(measure_tool=self.measure_cmd.strip().split(' ')[0])
+
+class CodeSizeResultInfo: # pylint: disable=too-few-public-methods
+    """Data structure to store result options for code size comparison."""
+    def __init__( #pylint: disable=too-many-arguments
+            self,
+            record_dir: str,
+            comp_dir: str,
+            with_markdown=False,
+            stdout=False,
+            show_all=False,
+    ) -> None:
+        """
+        :param record_dir: directory to store code size record.
+        :param comp_dir: directory to store results of code size comparision.
+        :param with_markdown: write comparision result into a markdown table.
+                              (Default: False)
+        :param stdout: direct comparison result into sys.stdout.
+                       (Default False)
+        :param show_all: show all objects in comparison result. (Default False)
+        """
+        self.record_dir = record_dir
+        self.comp_dir = comp_dir
+        self.with_markdown = with_markdown
+        self.stdout = stdout
+        self.show_all = show_all
+
+
 DETECT_ARCH_CMD = "cc -dM -E - < /dev/null"
 def detect_arch() -> str:
     """Auto-detect host architecture."""
     cc_output = subprocess.check_output(DETECT_ARCH_CMD, shell=True).decode()
-    if "__aarch64__" in cc_output:
+    if '__aarch64__' in cc_output:
         return SupportedArch.AARCH64.value
-    if "__arm__" in cc_output:
+    if '__arm__' in cc_output:
         return SupportedArch.AARCH32.value
-    if "__x86_64__" in cc_output:
+    if '__x86_64__' in cc_output:
         return SupportedArch.X86_64.value
-    if "__x86__" in cc_output:
+    if '__i386__' in cc_output:
         return SupportedArch.X86.value
     else:
         print("Unknown host architecture, cannot auto-detect arch.")
         sys.exit(1)
 
-class CodeSizeInfo: # pylint: disable=too-few-public-methods
+TFM_MEDIUM_CONFIG_H = 'configs/tfm_mbedcrypto_config_profile_medium.h'
+TFM_MEDIUM_CRYPTO_CONFIG_H = 'configs/crypto_config_profile_medium.h'
+
+CONFIG_H = 'include/mbedtls/mbedtls_config.h'
+CRYPTO_CONFIG_H = 'include/psa/crypto_config.h'
+BACKUP_SUFFIX = '.code_size.bak'
+
+class CodeSizeBuildInfo: # pylint: disable=too-few-public-methods
     """Gather information used to measure code size.
 
     It collects information about architecture, configuration in order to
@@ -80,90 +171,367 @@
     """
 
     SupportedArchConfig = [
-        "-a " + SupportedArch.AARCH64.value + " -c " + SupportedConfig.DEFAULT.value,
-        "-a " + SupportedArch.AARCH32.value + " -c " + SupportedConfig.DEFAULT.value,
-        "-a " + SupportedArch.X86_64.value  + " -c " + SupportedConfig.DEFAULT.value,
-        "-a " + SupportedArch.X86.value     + " -c " + SupportedConfig.DEFAULT.value,
-        "-a " + SupportedArch.ARMV8_M.value + " -c " + SupportedConfig.TFM_MEDIUM.value,
+        '-a ' + SupportedArch.AARCH64.value + ' -c ' + SupportedConfig.DEFAULT.value,
+        '-a ' + SupportedArch.AARCH32.value + ' -c ' + SupportedConfig.DEFAULT.value,
+        '-a ' + SupportedArch.X86_64.value  + ' -c ' + SupportedConfig.DEFAULT.value,
+        '-a ' + SupportedArch.X86.value     + ' -c ' + SupportedConfig.DEFAULT.value,
+        '-a ' + SupportedArch.ARMV8_M.value + ' -c ' + SupportedConfig.TFM_MEDIUM.value,
     ]
 
-    def __init__(self, arch: str, config: str, sys_arch: str) -> None:
+    def __init__(
+            self,
+            size_dist_info: CodeSizeDistinctInfo,
+            host_arch: str,
+            logger: logging.Logger,
+    ) -> None:
         """
-        arch: architecture to measure code size on.
-        config: configuration type to measure code size with.
-        sys_arch: host architecture.
-        make_command: command to build library (Inferred from arch and config).
+        :param size_dist_info:
+            CodeSizeDistinctInfo containing info for code size measurement.
+                - size_dist_info.arch: architecture to measure code size on.
+                - size_dist_info.config: configuration type to measure
+                                         code size with.
+                - size_dist_info.compiler: compiler used to build library/*.o.
+                - size_dist_info.opt_level: Options that control optimization.
+                                            (E.g. -Os)
+        :param host_arch: host architecture.
+        :param logger: logging module
         """
-        self.arch = arch
-        self.config = config
-        self.sys_arch = sys_arch
-        self.make_command = self.set_make_command()
+        self.arch = size_dist_info.arch
+        self.config = size_dist_info.config
+        self.compiler = size_dist_info.compiler
+        self.opt_level = size_dist_info.opt_level
 
-    def set_make_command(self) -> str:
-        """Infer build command based on architecture and configuration."""
+        self.make_cmd = ['make', '-j', 'lib']
 
+        self.host_arch = host_arch
+        self.logger = logger
+
+    def check_correctness(self) -> bool:
+        """Check whether we are using proper / supported combination
+        of information to build library/*.o."""
+
+        # default config
         if self.config == SupportedConfig.DEFAULT.value and \
-            self.arch == self.sys_arch:
-            return 'make -j lib CFLAGS=\'-Os \' '
+            self.arch == self.host_arch:
+            return True
+        # TF-M
         elif self.arch == SupportedArch.ARMV8_M.value and \
              self.config == SupportedConfig.TFM_MEDIUM.value:
-            return \
-                 'make -j lib CC=armclang \
-                  CFLAGS=\'--target=arm-arm-none-eabi -mcpu=cortex-m33 -Os \
-                 -DMBEDTLS_CONFIG_FILE=\\\"' + CONFIG_TFM_MEDIUM_MBEDCRYPTO_H + '\\\" \
-                 -DMBEDTLS_PSA_CRYPTO_CONFIG_FILE=\\\"' + CONFIG_TFM_MEDIUM_PSA_CRYPTO_H + '\\\" \''
+            return True
+
+        return False
+
+    def infer_pre_make_command(self) -> typing.List[str]:
+        """Infer command to set up proper configuration before running make."""
+        pre_make_cmd = [] #type: typing.List[str]
+        if self.config == SupportedConfig.TFM_MEDIUM.value:
+            pre_make_cmd.append('cp {src} {dest}'
+                                .format(src=TFM_MEDIUM_CONFIG_H, dest=CONFIG_H))
+            pre_make_cmd.append('cp {src} {dest}'
+                                .format(src=TFM_MEDIUM_CRYPTO_CONFIG_H,
+                                        dest=CRYPTO_CONFIG_H))
+
+        return pre_make_cmd
+
+    def infer_make_cflags(self) -> str:
+        """Infer CFLAGS by instance attributes in CodeSizeDistinctInfo."""
+        cflags = [] #type: typing.List[str]
+
+        # set optimization level
+        cflags.append(self.opt_level)
+        # set compiler by config
+        if self.config == SupportedConfig.TFM_MEDIUM.value:
+            self.compiler = 'armclang'
+            cflags.append('-mcpu=cortex-m33')
+        # set target
+        if self.compiler == 'armclang':
+            cflags.append('--target=arm-arm-none-eabi')
+
+        return ' '.join(cflags)
+
+    def infer_make_command(self) -> str:
+        """Infer make command by CFLAGS and CC."""
+
+        if self.check_correctness():
+            # set CFLAGS=
+            self.make_cmd.append('CFLAGS=\'{}\''.format(self.infer_make_cflags()))
+            # set CC=
+            self.make_cmd.append('CC={}'.format(self.compiler))
+            return ' '.join(self.make_cmd)
         else:
-            print("Unsupported combination of architecture: {} and configuration: {}"
-                  .format(self.arch, self.config))
-            print("\nPlease use supported combination of architecture and configuration:")
-            for comb in CodeSizeInfo.SupportedArchConfig:
-                print(comb)
-            print("\nFor your system, please use:")
-            for comb in CodeSizeInfo.SupportedArchConfig:
-                if "default" in comb and self.sys_arch not in comb:
+            self.logger.error("Unsupported combination of architecture: {} " \
+                              "and configuration: {}.\n"
+                              .format(self.arch,
+                                      self.config))
+            self.logger.error("Please use supported combination of " \
+                             "architecture and configuration:")
+            for comb in CodeSizeBuildInfo.SupportedArchConfig:
+                self.logger.error(comb)
+            self.logger.error("")
+            self.logger.error("For your system, please use:")
+            for comb in CodeSizeBuildInfo.SupportedArchConfig:
+                if "default" in comb and self.host_arch not in comb:
                     continue
-                print(comb)
+                self.logger.error(comb)
             sys.exit(1)
 
-class SizeEntry: # pylint: disable=too-few-public-methods
-    """Data Structure to only store information of code size."""
-    def __init__(self, text, data, bss, dec):
-        self.text = text
-        self.data = data
-        self.bss = bss
-        self.total = dec # total <=> dec
 
-class CodeSizeBase:
+class CodeSizeCalculator:
+    """ A calculator to calculate code size of library/*.o based on
+    Git revision and code size measurement tool.
+    """
+
+    def __init__( #pylint: disable=too-many-arguments
+            self,
+            git_rev: str,
+            pre_make_cmd: typing.List[str],
+            make_cmd: str,
+            measure_cmd: str,
+            logger: logging.Logger,
+    ) -> None:
+        """
+        :param git_rev: Git revision. (E.g: commit)
+        :param pre_make_cmd: command to set up proper config before running make.
+        :param make_cmd: command to build library/*.o.
+        :param measure_cmd: command to measure code size for library/*.o.
+        :param logger: logging module
+        """
+        self.repo_path = "."
+        self.git_command = "git"
+        self.make_clean = 'make clean'
+
+        self.git_rev = git_rev
+        self.pre_make_cmd = pre_make_cmd
+        self.make_cmd = make_cmd
+        self.measure_cmd = measure_cmd
+        self.logger = logger
+
+    @staticmethod
+    def validate_git_revision(git_rev: str) -> str:
+        result = subprocess.check_output(["git", "rev-parse", "--verify",
+                                          git_rev + "^{commit}"],
+                                         shell=False, universal_newlines=True)
+        return result[:7]
+
+    def _create_git_worktree(self) -> str:
+        """Create a separate worktree for Git revision.
+        If Git revision is current, use current worktree instead."""
+
+        if self.git_rev == 'current':
+            self.logger.debug("Using current work directory.")
+            git_worktree_path = self.repo_path
+        else:
+            self.logger.debug("Creating git worktree for {}."
+                              .format(self.git_rev))
+            git_worktree_path = os.path.join(self.repo_path,
+                                             "temp-" + self.git_rev)
+            subprocess.check_output(
+                [self.git_command, "worktree", "add", "--detach",
+                 git_worktree_path, self.git_rev], cwd=self.repo_path,
+                stderr=subprocess.STDOUT
+            )
+
+        return git_worktree_path
+
+    @staticmethod
+    def backup_config_files(restore: bool) -> None:
+        """Backup / Restore config files."""
+        if restore:
+            shutil.move(CONFIG_H + BACKUP_SUFFIX, CONFIG_H)
+            shutil.move(CRYPTO_CONFIG_H + BACKUP_SUFFIX, CRYPTO_CONFIG_H)
+        else:
+            shutil.copy(CONFIG_H, CONFIG_H + BACKUP_SUFFIX)
+            shutil.copy(CRYPTO_CONFIG_H, CRYPTO_CONFIG_H + BACKUP_SUFFIX)
+
+    def _build_libraries(self, git_worktree_path: str) -> None:
+        """Build library/*.o in the specified worktree."""
+
+        self.logger.debug("Building library/*.o for {}."
+                          .format(self.git_rev))
+        my_environment = os.environ.copy()
+        try:
+            if self.git_rev == 'current':
+                self.backup_config_files(restore=False)
+            for pre_cmd in self.pre_make_cmd:
+                subprocess.check_output(
+                    pre_cmd, env=my_environment, shell=True,
+                    cwd=git_worktree_path, stderr=subprocess.STDOUT,
+                    universal_newlines=True
+                )
+            subprocess.check_output(
+                self.make_clean, env=my_environment, shell=True,
+                cwd=git_worktree_path, stderr=subprocess.STDOUT,
+                universal_newlines=True
+            )
+            subprocess.check_output(
+                self.make_cmd, env=my_environment, shell=True,
+                cwd=git_worktree_path, stderr=subprocess.STDOUT,
+                universal_newlines=True
+            )
+            if self.git_rev == 'current':
+                self.backup_config_files(restore=True)
+        except subprocess.CalledProcessError as e:
+            self._handle_called_process_error(e, git_worktree_path)
+
+    def _gen_raw_code_size(self, git_worktree_path: str) -> typing.Dict[str, str]:
+        """Measure code size by a tool and return in UTF-8 encoding."""
+
+        self.logger.debug("Measuring code size for {} by `{}`."
+                          .format(self.git_rev,
+                                  self.measure_cmd.strip().split(' ')[0]))
+
+        res = {}
+        for mod, st_lib in MBEDTLS_STATIC_LIB.items():
+            try:
+                result = subprocess.check_output(
+                    [self.measure_cmd + ' ' + st_lib], cwd=git_worktree_path,
+                    shell=True, universal_newlines=True
+                )
+                res[mod] = result
+            except subprocess.CalledProcessError as e:
+                self._handle_called_process_error(e, git_worktree_path)
+
+        return res
+
+    def _remove_worktree(self, git_worktree_path: str) -> None:
+        """Remove temporary worktree."""
+        if git_worktree_path != self.repo_path:
+            self.logger.debug("Removing temporary worktree {}."
+                              .format(git_worktree_path))
+            subprocess.check_output(
+                [self.git_command, "worktree", "remove", "--force",
+                 git_worktree_path], cwd=self.repo_path,
+                stderr=subprocess.STDOUT
+            )
+
+    def _handle_called_process_error(self, e: subprocess.CalledProcessError,
+                                     git_worktree_path: str) -> None:
+        """Handle a CalledProcessError and quit the program gracefully.
+        Remove any extra worktrees so that the script may be called again."""
+
+        # Tell the user what went wrong
+        self.logger.error(e, exc_info=True)
+        self.logger.error("Process output:\n {}".format(e.output))
+
+        # Quit gracefully by removing the existing worktree
+        self._remove_worktree(git_worktree_path)
+        sys.exit(-1)
+
+    def cal_libraries_code_size(self) -> typing.Dict[str, str]:
+        """Do a complete round to calculate code size of library/*.o
+        by measurement tool.
+
+        :return A dictionary of measured code size
+            - typing.Dict[mod: str]
+        """
+
+        git_worktree_path = self._create_git_worktree()
+        try:
+            self._build_libraries(git_worktree_path)
+            res = self._gen_raw_code_size(git_worktree_path)
+        finally:
+            self._remove_worktree(git_worktree_path)
+
+        return res
+
+
+class CodeSizeGenerator:
+    """ A generator based on size measurement tool for library/*.o.
+
+    This is an abstract class. To use it, derive a class that implements
+    write_record and write_comparison methods, then call both of them with
+    proper arguments.
+    """
+    def __init__(self, logger: logging.Logger) -> None:
+        """
+        :param logger: logging module
+        """
+        self.logger = logger
+
+    def write_record(
+            self,
+            git_rev: str,
+            code_size_text: typing.Dict[str, str],
+            output: typing_util.Writable
+    ) -> None:
+        """Write size record into a file.
+
+        :param git_rev: Git revision. (E.g: commit)
+        :param code_size_text:
+            string output (utf-8) from measurement tool of code size.
+                - typing.Dict[mod: str]
+        :param output: output stream which the code size record is written to.
+                       (Note: Normally write code size record into File)
+        """
+        raise NotImplementedError
+
+    def write_comparison( #pylint: disable=too-many-arguments
+            self,
+            old_rev: str,
+            new_rev: str,
+            output: typing_util.Writable,
+            with_markdown=False,
+            show_all=False
+    ) -> None:
+        """Write a comparision result into a stream between two Git revisions.
+
+        :param old_rev: old Git revision to compared with.
+        :param new_rev: new Git revision to compared with.
+        :param output: output stream which the code size record is written to.
+                       (File / sys.stdout)
+        :param with_markdown:  write comparision result in a markdown table.
+                               (Default: False)
+        :param show_all: show all objects in comparison result. (Default False)
+        """
+        raise NotImplementedError
+
+
+class CodeSizeGeneratorWithSize(CodeSizeGenerator):
     """Code Size Base Class for size record saving and writing."""
 
-    def __init__(self) -> None:
-        """ Variable code_size is used to store size info for any revisions.
-        code_size: (data format)
-        {revision: {module: {file_name: SizeEntry,
-                             etc ...
-                            },
-                    etc ...
-                   },
-         etc ...
-        }
-        """
-        self.code_size = {} #type: typing.Dict[str, typing.Dict]
+    class SizeEntry: # pylint: disable=too-few-public-methods
+        """Data Structure to only store information of code size."""
+        def __init__(self, text: int, data: int, bss: int, dec: int):
+            self.text = text
+            self.data = data
+            self.bss = bss
+            self.total = dec # total <=> dec
 
-    def set_size_record(self, revision: str, mod: str, size_text: str) -> None:
-        """Store size information for target revision and high-level module.
+    def __init__(self, logger: logging.Logger) -> None:
+        """ Variable code_size is used to store size info for any Git revisions.
+        :param code_size:
+            Data Format as following:
+            code_size = {
+                git_rev: {
+                    module: {
+                        file_name: SizeEntry,
+                        ...
+                    },
+                    ...
+                },
+                ...
+            }
+        """
+        super().__init__(logger)
+        self.code_size = {} #type: typing.Dict[str, typing.Dict]
+        self.mod_total_suffix = '-' + 'TOTALS'
+
+    def _set_size_record(self, git_rev: str, mod: str, size_text: str) -> None:
+        """Store size information for target Git revision and high-level module.
 
         size_text Format: text data bss dec hex filename
         """
         size_record = {}
         for line in size_text.splitlines()[1:]:
             data = line.split()
-            size_record[data[5]] = SizeEntry(data[0], data[1], data[2], data[3])
-        if revision in self.code_size:
-            self.code_size[revision].update({mod: size_record})
-        else:
-            self.code_size[revision] = {mod: size_record}
+            if re.match(r'\s*\(TOTALS\)', data[5]):
+                data[5] = mod + self.mod_total_suffix
+            # file_name: SizeEntry(text, data, bss, dec)
+            size_record[data[5]] = CodeSizeGeneratorWithSize.SizeEntry(
+                int(data[0]), int(data[1]), int(data[2]), int(data[3]))
+        self.code_size.setdefault(git_rev, {}).update({mod: size_record})
 
-    def read_size_record(self, revision: str, fname: str) -> None:
+    def read_size_record(self, git_rev: str, fname: str) -> None:
         """Read size information from csv file and write it into code_size.
 
         fname Format: filename text data bss dec
@@ -179,232 +547,325 @@
                     continue
 
                 if mod:
-                    size_record[data[0]] = \
-                        SizeEntry(data[1], data[2], data[3], data[4])
+                    # file_name: SizeEntry(text, data, bss, dec)
+                    size_record[data[0]] = CodeSizeGeneratorWithSize.SizeEntry(
+                        int(data[1]), int(data[2]), int(data[3]), int(data[4]))
 
                 # check if we hit record for the end of a module
-                m = re.match(r'.?TOTALS', line)
+                m = re.match(r'\w+' + self.mod_total_suffix, line)
                 if m:
-                    if revision in self.code_size:
-                        self.code_size[revision].update({mod: size_record})
+                    if git_rev in self.code_size:
+                        self.code_size[git_rev].update({mod: size_record})
                     else:
-                        self.code_size[revision] = {mod: size_record}
+                        self.code_size[git_rev] = {mod: size_record}
                     mod = ""
                     size_record = {}
 
-    def _size_reader_helper(
+    def write_record(
             self,
-            revision: str,
-            output: typing_util.Writable
-    ) -> typing.Iterator[tuple]:
-        """A helper function to peel code_size based on revision."""
-        for mod, file_size in self.code_size[revision].items():
-            output.write("\n" + mod + "\n")
-            for fname, size_entry in file_size.items():
-                yield mod, fname, size_entry
-
-    def write_size_record(
-            self,
-            revision: str,
+            git_rev: str,
+            code_size_text: typing.Dict[str, str],
             output: typing_util.Writable
     ) -> None:
         """Write size information to a file.
 
-        Writing Format: file_name text data bss total(dec)
+        Writing Format: filename text data bss total(dec)
         """
-        output.write("{:<30} {:>7} {:>7} {:>7} {:>7}\n"
-                     .format("filename", "text", "data", "bss", "total"))
-        for _, fname, size_entry in self._size_reader_helper(revision, output):
-            output.write("{:<30} {:>7} {:>7} {:>7} {:>7}\n"
-                         .format(fname, size_entry.text, size_entry.data,\
-                                 size_entry.bss, size_entry.total))
+        for mod, size_text in code_size_text.items():
+            self._set_size_record(git_rev, mod, size_text)
 
-    def write_comparison(
+        format_string = "{:<30} {:>7} {:>7} {:>7} {:>7}\n"
+        output.write(format_string.format("filename",
+                                          "text", "data", "bss", "total"))
+
+        for mod, f_size in self.code_size[git_rev].items():
+            output.write("\n" + mod + "\n")
+            for fname, size_entry in f_size.items():
+                output.write(format_string
+                             .format(fname,
+                                     size_entry.text, size_entry.data,
+                                     size_entry.bss, size_entry.total))
+
+    def write_comparison( #pylint: disable=too-many-arguments
             self,
             old_rev: str,
             new_rev: str,
-            output: typing_util.Writable
+            output: typing_util.Writable,
+            with_markdown=False,
+            show_all=False
     ) -> None:
+        # pylint: disable=too-many-locals
         """Write comparison result into a file.
 
-        Writing Format: file_name current(total) old(total) change(Byte) change_pct(%)
+        Writing Format:
+            Markdown Output:
+                filename new(text) new(data) change(text) change(data)
+            CSV Output:
+                filename new(text) new(data) old(text) old(data) change(text) change(data)
         """
-        output.write("{:<30} {:>7} {:>7} {:>7} {:>7}\n"
-                     .format("filename", "current", "old", "change", "change%"))
-        for mod, fname, size_entry in self._size_reader_helper(new_rev, output):
-            new_size = int(size_entry.total)
-            # check if we have the file in old revision
-            if fname in self.code_size[old_rev][mod]:
-                old_size = int(self.code_size[old_rev][mod][fname].total)
-                change = new_size - old_size
-                if old_size != 0:
-                    change_pct = change / old_size
-                else:
-                    change_pct = 0
-                output.write("{:<30} {:>7} {:>7} {:>7} {:>7.2%}\n"
-                             .format(fname, new_size, old_size, change, change_pct))
+        header_line = ["filename", "new(text)", "old(text)", "change(text)",
+                       "new(data)", "old(data)", "change(data)"]
+        if with_markdown:
+            dash_line = [":----", "----:", "----:", "----:",
+                         "----:", "----:", "----:"]
+            # | filename | new(text) | new(data) | change(text) | change(data) |
+            line_format = "| {0:<30} | {1:>9} | {4:>9} | {3:>12} | {6:>12} |\n"
+            bold_text = lambda x: '**' + str(x) + '**'
+        else:
+            # filename new(text) new(data) old(text) old(data) change(text) change(data)
+            line_format = "{0:<30} {1:>9} {4:>9} {2:>10} {5:>10} {3:>12} {6:>12}\n"
+
+        def cal_sect_change(
+                old_size: typing.Optional[CodeSizeGeneratorWithSize.SizeEntry],
+                new_size: typing.Optional[CodeSizeGeneratorWithSize.SizeEntry],
+                sect: str
+        ) -> typing.List:
+            """Inner helper function to calculate size change for a section.
+
+            Convention for special cases:
+                - If the object has been removed in new Git revision,
+                  the size is minus code size of old Git revision;
+                  the size change is marked as `Removed`,
+                - If the object only exists in new Git revision,
+                  the size is code size of new Git revision;
+                  the size change is marked as `None`,
+
+            :param: old_size: code size for objects in old Git revision.
+            :param: new_size: code size for objects in new Git revision.
+            :param: sect: section to calculate from `size` tool. This could be
+                          any instance variable in SizeEntry.
+            :return: List of [section size of objects for new Git revision,
+                     section size of objects for old Git revision,
+                     section size change of objects between two Git revisions]
+            """
+            if old_size and new_size:
+                new_attr = new_size.__dict__[sect]
+                old_attr = old_size.__dict__[sect]
+                delta = new_attr - old_attr
+                change_attr = '{0:{1}}'.format(delta, '+' if delta else '')
+            elif old_size:
+                new_attr = 'Removed'
+                old_attr = old_size.__dict__[sect]
+                delta = - old_attr
+                change_attr = '{0:{1}}'.format(delta, '+' if delta else '')
+            elif new_size:
+                new_attr = new_size.__dict__[sect]
+                old_attr = 'NotCreated'
+                delta = new_attr
+                change_attr = '{0:{1}}'.format(delta, '+' if delta else '')
             else:
-                output.write("{} {}\n".format(fname, new_size))
+                # Should never happen
+                new_attr = 'Error'
+                old_attr = 'Error'
+                change_attr = 'Error'
+            return [new_attr, old_attr, change_attr]
+
+        # sort dictionary by key
+        sort_by_k = lambda item: item[0].lower()
+        def get_results(
+                f_rev_size:
+                typing.Dict[str,
+                            typing.Dict[str,
+                                        CodeSizeGeneratorWithSize.SizeEntry]]
+            ) -> typing.List:
+            """Return List of results in the format of:
+            [filename, new(text), old(text), change(text),
+             new(data), old(data), change(data)]
+            """
+            res = []
+            for fname, revs_size in sorted(f_rev_size.items(), key=sort_by_k):
+                old_size = revs_size.get(old_rev)
+                new_size = revs_size.get(new_rev)
+
+                text_sect = cal_sect_change(old_size, new_size, 'text')
+                data_sect = cal_sect_change(old_size, new_size, 'data')
+                # skip the files that haven't changed in code size
+                if not show_all and text_sect[-1] == '0' and data_sect[-1] == '0':
+                    continue
+
+                res.append([fname, *text_sect, *data_sect])
+            return res
+
+        # write header
+        output.write(line_format.format(*header_line))
+        if with_markdown:
+            output.write(line_format.format(*dash_line))
+        for mod in MBEDTLS_STATIC_LIB:
+        # convert self.code_size to:
+        # {
+        #   file_name: {
+        #       old_rev: SizeEntry,
+        #       new_rev: SizeEntry
+        #   },
+        #   ...
+        # }
+            f_rev_size = {} #type: typing.Dict[str, typing.Dict]
+            for fname, size_entry in self.code_size[old_rev][mod].items():
+                f_rev_size.setdefault(fname, {}).update({old_rev: size_entry})
+            for fname, size_entry in self.code_size[new_rev][mod].items():
+                f_rev_size.setdefault(fname, {}).update({new_rev: size_entry})
+
+            mod_total_sz = f_rev_size.pop(mod + self.mod_total_suffix)
+            res = get_results(f_rev_size)
+            total_clm = get_results({mod + self.mod_total_suffix: mod_total_sz})
+            if with_markdown:
+                # bold row of mod-TOTALS in markdown table
+                total_clm = [[bold_text(j) for j in i] for i in total_clm]
+            res += total_clm
+
+            # write comparison result
+            for line in res:
+                output.write(line_format.format(*line))
 
 
-class CodeSizeComparison(CodeSizeBase):
+class CodeSizeComparison:
     """Compare code size between two Git revisions."""
 
-    def __init__(
+    def __init__( #pylint: disable=too-many-arguments
             self,
-            old_revision: str,
-            new_revision: str,
-            result_dir: str,
-            code_size_info: CodeSizeInfo
+            old_size_dist_info: CodeSizeDistinctInfo,
+            new_size_dist_info: CodeSizeDistinctInfo,
+            size_common_info: CodeSizeCommonInfo,
+            result_options: CodeSizeResultInfo,
+            logger: logging.Logger,
     ) -> None:
         """
-        old_revision: revision to compare against.
-        new_revision:
-        result_dir: directory for comparison result.
-        code_size_info: an object containing information to build library.
+        :param old_size_dist_info: CodeSizeDistinctInfo containing old distinct
+                                   info to compare code size with.
+        :param new_size_dist_info: CodeSizeDistinctInfo containing new distinct
+                                   info to take as comparision base.
+        :param size_common_info: CodeSizeCommonInfo containing common info for
+                                 both old and new size distinct info and
+                                 measurement tool.
+        :param result_options: CodeSizeResultInfo containing results options for
+                               code size record and comparision.
+        :param logger: logging module
         """
-        super().__init__()
-        self.repo_path = "."
-        self.result_dir = os.path.abspath(result_dir)
-        os.makedirs(self.result_dir, exist_ok=True)
 
-        self.csv_dir = os.path.abspath("code_size_records/")
+        self.logger = logger
+
+        self.old_size_dist_info = old_size_dist_info
+        self.new_size_dist_info = new_size_dist_info
+        self.size_common_info = size_common_info
+        # infer pre make command
+        self.old_size_dist_info.pre_make_cmd = CodeSizeBuildInfo(
+            self.old_size_dist_info, self.size_common_info.host_arch,
+            self.logger).infer_pre_make_command()
+        self.new_size_dist_info.pre_make_cmd = CodeSizeBuildInfo(
+            self.new_size_dist_info, self.size_common_info.host_arch,
+            self.logger).infer_pre_make_command()
+        # infer make command
+        self.old_size_dist_info.make_cmd = CodeSizeBuildInfo(
+            self.old_size_dist_info, self.size_common_info.host_arch,
+            self.logger).infer_make_command()
+        self.new_size_dist_info.make_cmd = CodeSizeBuildInfo(
+            self.new_size_dist_info, self.size_common_info.host_arch,
+            self.logger).infer_make_command()
+        # initialize size parser with corresponding measurement tool
+        self.code_size_generator = self.__generate_size_parser()
+
+        self.result_options = result_options
+        self.csv_dir = os.path.abspath(self.result_options.record_dir)
         os.makedirs(self.csv_dir, exist_ok=True)
+        self.comp_dir = os.path.abspath(self.result_options.comp_dir)
+        os.makedirs(self.comp_dir, exist_ok=True)
 
-        self.old_rev = old_revision
-        self.new_rev = new_revision
-        self.git_command = "git"
-        self.make_clean = 'make clean'
-        self.make_command = code_size_info.make_command
-        self.fname_suffix = "-" + code_size_info.arch + "-" +\
-                            code_size_info.config
-
-    @staticmethod
-    def validate_revision(revision: str) -> bytes:
-        result = subprocess.check_output(["git", "rev-parse", "--verify",
-                                          revision + "^{commit}"], shell=False)
-        return result
-
-    def _create_git_worktree(self, revision: str) -> str:
-        """Make a separate worktree for revision.
-        Do not modify the current worktree."""
-
-        if revision == "current":
-            print("Using current work directory")
-            git_worktree_path = self.repo_path
+    def __generate_size_parser(self):
+        """Generate a parser for the corresponding measurement tool."""
+        if re.match(r'size', self.size_common_info.measure_cmd.strip()):
+            return CodeSizeGeneratorWithSize(self.logger)
         else:
-            print("Creating git worktree for", revision)
-            git_worktree_path = os.path.join(self.repo_path, "temp-" + revision)
-            subprocess.check_output(
-                [self.git_command, "worktree", "add", "--detach",
-                 git_worktree_path, revision], cwd=self.repo_path,
-                stderr=subprocess.STDOUT
-            )
+            self.logger.error("Unsupported measurement tool: `{}`."
+                              .format(self.size_common_info.measure_cmd
+                                      .strip().split(' ')[0]))
+            sys.exit(1)
 
-        return git_worktree_path
+    def cal_code_size(
+            self,
+            size_dist_info: CodeSizeDistinctInfo
+        ) -> typing.Dict[str, str]:
+        """Calculate code size of library/*.o in a UTF-8 encoding"""
 
-    def _build_libraries(self, git_worktree_path: str) -> None:
-        """Build libraries in the specified worktree."""
+        return CodeSizeCalculator(size_dist_info.git_rev,
+                                  size_dist_info.pre_make_cmd,
+                                  size_dist_info.make_cmd,
+                                  self.size_common_info.measure_cmd,
+                                  self.logger).cal_libraries_code_size()
 
-        my_environment = os.environ.copy()
-        try:
-            subprocess.check_output(
-                self.make_clean, env=my_environment, shell=True,
-                cwd=git_worktree_path, stderr=subprocess.STDOUT,
-            )
-            subprocess.check_output(
-                self.make_command, env=my_environment, shell=True,
-                cwd=git_worktree_path, stderr=subprocess.STDOUT,
-            )
-        except subprocess.CalledProcessError as e:
-            self._handle_called_process_error(e, git_worktree_path)
+    def gen_code_size_report(self, size_dist_info: CodeSizeDistinctInfo) -> None:
+        """Generate code size record and write it into a file."""
 
-    def _gen_code_size_csv(self, revision: str, git_worktree_path: str) -> None:
-        """Generate code size csv file."""
-
-        if revision == "current":
-            print("Measuring code size in current work directory")
-        else:
-            print("Measuring code size for", revision)
-
-        for mod, st_lib in MBEDTLS_STATIC_LIB.items():
-            try:
-                result = subprocess.check_output(
-                    ["size", st_lib, "-t"], cwd=git_worktree_path
-                )
-            except subprocess.CalledProcessError as e:
-                self._handle_called_process_error(e, git_worktree_path)
-            size_text = result.decode("utf-8")
-
-            self.set_size_record(revision, mod, size_text)
-
-        print("Generating code size csv for", revision)
-        csv_file = open(os.path.join(self.csv_dir, revision +
-                                     self.fname_suffix + ".csv"), "w")
-        self.write_size_record(revision, csv_file)
-
-    def _remove_worktree(self, git_worktree_path: str) -> None:
-        """Remove temporary worktree."""
-        if git_worktree_path != self.repo_path:
-            print("Removing temporary worktree", git_worktree_path)
-            subprocess.check_output(
-                [self.git_command, "worktree", "remove", "--force",
-                 git_worktree_path], cwd=self.repo_path,
-                stderr=subprocess.STDOUT
-            )
-
-    def _get_code_size_for_rev(self, revision: str) -> None:
-        """Generate code size csv file for the specified git revision."""
-
+        self.logger.info("Start to generate code size record for {}."
+                         .format(size_dist_info.git_rev))
+        output_file = os.path.join(
+            self.csv_dir,
+            '{}-{}.csv'
+            .format(size_dist_info.get_info_indication(),
+                    self.size_common_info.get_info_indication()))
         # Check if the corresponding record exists
-        csv_fname = revision + self.fname_suffix +  ".csv"
-        if (revision != "current") and \
-           os.path.exists(os.path.join(self.csv_dir, csv_fname)):
-            print("Code size csv file for", revision, "already exists.")
-            self.read_size_record(revision, os.path.join(self.csv_dir, csv_fname))
+        if size_dist_info.git_rev != "current" and \
+           os.path.exists(output_file):
+            self.logger.debug("Code size csv file for {} already exists."
+                              .format(size_dist_info.git_rev))
+            self.code_size_generator.read_size_record(
+                size_dist_info.git_rev, output_file)
         else:
-            git_worktree_path = self._create_git_worktree(revision)
-            self._build_libraries(git_worktree_path)
-            self._gen_code_size_csv(revision, git_worktree_path)
-            self._remove_worktree(git_worktree_path)
+            # measure code size
+            code_size_text = self.cal_code_size(size_dist_info)
 
-    def _gen_code_size_comparison(self) -> int:
-        """Generate results of the size changes between two revisions,
-        old and new. Measured code size results of these two revisions
-        must be available."""
+            self.logger.debug("Generating code size csv for {}."
+                              .format(size_dist_info.git_rev))
+            output = open(output_file, "w")
+            self.code_size_generator.write_record(
+                size_dist_info.git_rev, code_size_text, output)
 
-        res_file = open(os.path.join(self.result_dir, "compare-" +
-                                     self.old_rev + "-" + self.new_rev +
-                                     self.fname_suffix +
-                                     ".csv"), "w")
+    def gen_code_size_comparison(self) -> None:
+        """Generate results of code size changes between two Git revisions,
+        old and new.
 
-        print("\nGenerating comparison results between",\
-                self.old_rev, "and", self.new_rev)
-        self.write_comparison(self.old_rev, self.new_rev, res_file)
+        - Measured code size result of these two Git revisions must be available.
+        - The result is directed into either file / stdout depending on
+          the option, size_common_info.result_options.stdout. (Default: file)
+        """
 
-        return 0
+        self.logger.info("Start to generate comparision result between "\
+                         "{} and {}."
+                         .format(self.old_size_dist_info.git_rev,
+                                 self.new_size_dist_info.git_rev))
+        if self.result_options.stdout:
+            output = sys.stdout
+        else:
+            output_file = os.path.join(
+                self.comp_dir,
+                '{}-{}-{}.{}'
+                .format(self.old_size_dist_info.get_info_indication(),
+                        self.new_size_dist_info.get_info_indication(),
+                        self.size_common_info.get_info_indication(),
+                        'md' if self.result_options.with_markdown else 'csv'))
+            output = open(output_file, "w")
 
-    def get_comparision_results(self) -> int:
-        """Compare size of library/*.o between self.old_rev and self.new_rev,
-        and generate the result file."""
+        self.logger.debug("Generating comparison results between {} and {}."
+                          .format(self.old_size_dist_info.git_rev,
+                                  self.new_size_dist_info.git_rev))
+        if self.result_options.with_markdown or self.result_options.stdout:
+            print("Measure code size between {} and {} by `{}`."
+                  .format(self.old_size_dist_info.get_info_indication(),
+                          self.new_size_dist_info.get_info_indication(),
+                          self.size_common_info.get_info_indication()),
+                  file=output)
+        self.code_size_generator.write_comparison(
+            self.old_size_dist_info.git_rev,
+            self.new_size_dist_info.git_rev,
+            output, self.result_options.with_markdown,
+            self.result_options.show_all)
+
+    def get_comparision_results(self) -> None:
+        """Compare size of library/*.o between self.old_size_dist_info and
+        self.old_size_dist_info and generate the result file."""
         build_tree.check_repo_path()
-        self._get_code_size_for_rev(self.old_rev)
-        self._get_code_size_for_rev(self.new_rev)
-        return self._gen_code_size_comparison()
-
-    def _handle_called_process_error(self, e: subprocess.CalledProcessError,
-                                     git_worktree_path: str) -> None:
-        """Handle a CalledProcessError and quit the program gracefully.
-        Remove any extra worktrees so that the script may be called again."""
-
-        # Tell the user what went wrong
-        print("The following command: {} failed and exited with code {}"
-              .format(e.cmd, e.returncode))
-        print("Process output:\n {}".format(str(e.output, "utf-8")))
-
-        # Quit gracefully by removing the existing worktree
-        self._remove_worktree(git_worktree_path)
-        sys.exit(-1)
+        self.gen_code_size_report(self.old_size_dist_info)
+        self.gen_code_size_report(self.new_size_dist_info)
+        self.gen_code_size_comparison()
 
 def main():
     parser = argparse.ArgumentParser(description=(__doc__))
@@ -412,55 +873,92 @@
         'required arguments',
         'required arguments to parse for running ' + os.path.basename(__file__))
     group_required.add_argument(
-        "-o", "--old-rev", type=str, required=True,
-        help="old revision for comparison.")
+        '-o', '--old-rev', type=str, required=True,
+        help='old Git revision for comparison.')
 
     group_optional = parser.add_argument_group(
         'optional arguments',
         'optional arguments to parse for running ' + os.path.basename(__file__))
     group_optional.add_argument(
-        "-r", "--result-dir", type=str, default="comparison",
-        help="directory where comparison result is stored, \
-              default is comparison")
+        '--record-dir', type=str, default='code_size_records',
+        help='directory where code size record is stored. '
+             '(Default: code_size_records)')
     group_optional.add_argument(
-        "-n", "--new-rev", type=str, default=None,
-        help="new revision for comparison, default is the current work \
-              directory, including uncommitted changes.")
+        '--comp-dir', type=str, default='comparison',
+        help='directory where comparison result is stored. '
+             '(Default: comparison)')
     group_optional.add_argument(
-        "-a", "--arch", type=str, default=detect_arch(),
+        '-n', '--new-rev', type=str, default='current',
+        help='new Git revision as comparison base. '
+             '(Default is the current work directory, including uncommitted '
+             'changes.)')
+    group_optional.add_argument(
+        '-a', '--arch', type=str, default=detect_arch(),
         choices=list(map(lambda s: s.value, SupportedArch)),
-        help="specify architecture for code size comparison, default is the\
-              host architecture.")
+        help='Specify architecture for code size comparison. '
+             '(Default is the host architecture.)')
     group_optional.add_argument(
-        "-c", "--config", type=str, default=SupportedConfig.DEFAULT.value,
+        '-c', '--config', type=str, default=SupportedConfig.DEFAULT.value,
         choices=list(map(lambda s: s.value, SupportedConfig)),
-        help="specify configuration type for code size comparison,\
-              default is the current MbedTLS configuration.")
+        help='Specify configuration type for code size comparison. '
+             '(Default is the current MbedTLS configuration.)')
+    group_optional.add_argument(
+        '--markdown', action='store_true', dest='markdown',
+        help='Show comparision of code size in a markdown table. '
+             '(Only show the files that have changed).')
+    group_optional.add_argument(
+        '--stdout', action='store_true', dest='stdout',
+        help='Set this option to direct comparison result into sys.stdout. '
+             '(Default: file)')
+    group_optional.add_argument(
+        '--show-all', action='store_true', dest='show_all',
+        help='Show all the objects in comparison result, including the ones '
+             'that haven\'t changed in code size. (Default: False)')
+    group_optional.add_argument(
+        '--verbose', action='store_true', dest='verbose',
+        help='Show logs in detail for code size measurement. '
+             '(Default: False)')
     comp_args = parser.parse_args()
 
-    if os.path.isfile(comp_args.result_dir):
-        print("Error: {} is not a directory".format(comp_args.result_dir))
-        parser.exit()
+    logger = logging.getLogger()
+    logging_util.configure_logger(logger, split_level=logging.NOTSET)
+    logger.setLevel(logging.DEBUG if comp_args.verbose else logging.INFO)
 
-    validate_res = CodeSizeComparison.validate_revision(comp_args.old_rev)
-    old_revision = validate_res.decode().replace("\n", "")
+    if os.path.isfile(comp_args.record_dir):
+        logger.error("record directory: {} is not a directory"
+                     .format(comp_args.record_dir))
+        sys.exit(1)
+    if os.path.isfile(comp_args.comp_dir):
+        logger.error("comparison directory: {} is not a directory"
+                     .format(comp_args.comp_dir))
+        sys.exit(1)
 
-    if comp_args.new_rev is not None:
-        validate_res = CodeSizeComparison.validate_revision(comp_args.new_rev)
-        new_revision = validate_res.decode().replace("\n", "")
-    else:
-        new_revision = "current"
+    comp_args.old_rev = CodeSizeCalculator.validate_git_revision(
+        comp_args.old_rev)
+    if comp_args.new_rev != 'current':
+        comp_args.new_rev = CodeSizeCalculator.validate_git_revision(
+            comp_args.new_rev)
 
-    code_size_info = CodeSizeInfo(comp_args.arch, comp_args.config,
-                                  detect_arch())
-    print("Measure code size for architecture: {}, configuration: {}\n"
-          .format(code_size_info.arch, code_size_info.config))
-    result_dir = comp_args.result_dir
-    size_compare = CodeSizeComparison(old_revision, new_revision, result_dir,
-                                      code_size_info)
-    return_code = size_compare.get_comparision_results()
-    sys.exit(return_code)
+    # version, git_rev, arch, config, compiler, opt_level
+    old_size_dist_info = CodeSizeDistinctInfo(
+        'old', comp_args.old_rev, comp_args.arch, comp_args.config, 'cc', '-Os')
+    new_size_dist_info = CodeSizeDistinctInfo(
+        'new', comp_args.new_rev, comp_args.arch, comp_args.config, 'cc', '-Os')
+    # host_arch, measure_cmd
+    size_common_info = CodeSizeCommonInfo(
+        detect_arch(), 'size -t')
+    # record_dir, comp_dir, with_markdown, stdout, show_all
+    result_options = CodeSizeResultInfo(
+        comp_args.record_dir, comp_args.comp_dir,
+        comp_args.markdown, comp_args.stdout, comp_args.show_all)
 
+    logger.info("Measure code size between {} and {} by `{}`."
+                .format(old_size_dist_info.get_info_indication(),
+                        new_size_dist_info.get_info_indication(),
+                        size_common_info.get_info_indication()))
+    CodeSizeComparison(old_size_dist_info, new_size_dist_info,
+                       size_common_info, result_options,
+                       logger).get_comparision_results()
 
 if __name__ == "__main__":
     main()
diff --git a/scripts/data_files/driver_jsons/mbedtls_test_transparent_driver.json b/scripts/data_files/driver_jsons/mbedtls_test_transparent_driver.json
index 9eb259f..b9b2d68 100644
--- a/scripts/data_files/driver_jsons/mbedtls_test_transparent_driver.json
+++ b/scripts/data_files/driver_jsons/mbedtls_test_transparent_driver.json
@@ -7,7 +7,7 @@
         {
             "_comment":     "The Mbed TLS transparent driver supports import key/export key",
             "mbedtls/c_condition":    "defined(PSA_CRYPTO_DRIVER_TEST)",
-            "entry_points": ["import_key", "export_key"],
+            "entry_points": ["import_key"],
             "fallback":     true
         },
         {
diff --git a/scripts/gitignore_patch.sh b/scripts/gitignore_patch.sh
new file mode 100755
index 0000000..74ec66c
--- /dev/null
+++ b/scripts/gitignore_patch.sh
@@ -0,0 +1,71 @@
+#!/bin/bash
+#
+# Copyright The Mbed TLS Contributors
+# 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.
+#
+# Purpose
+#
+# For adapting gitignore files for releases so generated files can be included.
+#
+# Usage: gitignore_add_generated_files.sh  [ -h | --help ] etc
+#
+
+set -eu
+
+print_usage()
+{
+    echo "Usage: $0"
+    echo -e "  -h|--help\t\tPrint this help."
+    echo -e "  -i|--ignore\t\tAdd generated files to the gitignores."
+    echo -e "  -u|--unignore\t\tRemove generated files from the gitignores."
+}
+
+if [[ $# -eq 0 ]]; then
+    print_usage
+    exit 1
+elif [[ $# -ge 2 ]]; then
+    echo "Too many arguments!"
+    exit 1
+fi
+
+case "$1" in
+    -i | --ignore)
+        IGNORE=true
+        ;;
+    -u | --uignore)
+        IGNORE=false
+        ;;
+    -h | --help | "")
+        print_usage
+        exit 1
+        ;;
+    *)
+        echo "Unknown argument: $1"
+        echo "run '$0 --help' for options"
+        exit 1
+esac
+
+GITIGNORES=$(find . -name ".gitignore")
+for GITIGNORE in $GITIGNORES; do
+    if $IGNORE; then
+        sed -i '/###START_COMMENTED_GENERATED_FILES###/,/###END_COMMENTED_GENERATED_FILES###/s/^# //' $GITIGNORE
+        sed -i 's/###START_COMMENTED_GENERATED_FILES###/###START_GENERATED_FILES###/' $GITIGNORE
+        sed -i 's/###END_COMMENTED_GENERATED_FILES###/###END_GENERATED_FILES###/' $GITIGNORE
+    else
+        sed -i '/###START_GENERATED_FILES###/,/###END_GENERATED_FILES###/s/^/# /' $GITIGNORE
+        sed -i 's/###START_GENERATED_FILES###/###START_COMMENTED_GENERATED_FILES###/' $GITIGNORE
+        sed -i 's/###END_GENERATED_FILES###/###END_COMMENTED_GENERATED_FILES###/' $GITIGNORE
+    fi
+done
diff --git a/scripts/mbedtls_dev/crypto_data_tests.py b/scripts/mbedtls_dev/crypto_data_tests.py
new file mode 100644
index 0000000..7593952
--- /dev/null
+++ b/scripts/mbedtls_dev/crypto_data_tests.py
@@ -0,0 +1,123 @@
+"""Generate test data for cryptographic mechanisms.
+
+This module is a work in progress, only implementing a few cases for now.
+"""
+
+# Copyright The Mbed TLS Contributors
+# 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.
+
+import hashlib
+from typing import Callable, Dict, Iterator, List, Optional #pylint: disable=unused-import
+
+from . import crypto_knowledge
+from . import psa_information
+from . import test_case
+
+
+def psa_low_level_dependencies(*expressions: str) -> List[str]:
+    """Infer dependencies of a PSA low-level test case by looking for PSA_xxx symbols.
+
+    This function generates MBEDTLS_PSA_BUILTIN_xxx symbols.
+    """
+    high_level = psa_information.automatic_dependencies(*expressions)
+    for dep in high_level:
+        assert dep.startswith('PSA_WANT_')
+    return ['MBEDTLS_PSA_BUILTIN_' + dep[9:] for dep in high_level]
+
+
+class HashPSALowLevel:
+    """Generate test cases for the PSA low-level hash interface."""
+
+    def __init__(self, info: psa_information.Information) -> None:
+        self.info = info
+        base_algorithms = sorted(info.constructors.algorithms)
+        all_algorithms = \
+            [crypto_knowledge.Algorithm(expr)
+             for expr in info.constructors.generate_expressions(base_algorithms)]
+        self.algorithms = \
+            [alg
+             for alg in all_algorithms
+             if (not alg.is_wildcard and
+                 alg.can_do(crypto_knowledge.AlgorithmCategory.HASH))]
+
+    # CALCULATE[alg] = function to return the hash of its argument in hex
+    # TO-DO: implement the None entries with a third-party library, because
+    # hashlib might not have everything, depending on the Python version and
+    # the underlying OpenSSL. On Ubuntu 16.04, truncated sha512 and sha3/shake
+    # are not available. On Ubuntu 22.04, md2, md4 and ripemd160 are not
+    # available.
+    CALCULATE = {
+        'PSA_ALG_MD5': lambda data: hashlib.md5(data).hexdigest(),
+        'PSA_ALG_RIPEMD160': None, #lambda data: hashlib.new('ripdemd160').hexdigest()
+        'PSA_ALG_SHA_1': lambda data: hashlib.sha1(data).hexdigest(),
+        'PSA_ALG_SHA_224': lambda data: hashlib.sha224(data).hexdigest(),
+        'PSA_ALG_SHA_256': lambda data: hashlib.sha256(data).hexdigest(),
+        'PSA_ALG_SHA_384': lambda data: hashlib.sha384(data).hexdigest(),
+        'PSA_ALG_SHA_512': lambda data: hashlib.sha512(data).hexdigest(),
+        'PSA_ALG_SHA_512_224': None, #lambda data: hashlib.new('sha512_224').hexdigest()
+        'PSA_ALG_SHA_512_256': None, #lambda data: hashlib.new('sha512_256').hexdigest()
+        'PSA_ALG_SHA3_224': None, #lambda data: hashlib.sha3_224(data).hexdigest(),
+        'PSA_ALG_SHA3_256': None, #lambda data: hashlib.sha3_256(data).hexdigest(),
+        'PSA_ALG_SHA3_384': None, #lambda data: hashlib.sha3_384(data).hexdigest(),
+        'PSA_ALG_SHA3_512': None, #lambda data: hashlib.sha3_512(data).hexdigest(),
+        'PSA_ALG_SHAKE256_512': None, #lambda data: hashlib.shake_256(data).hexdigest(64),
+    } #type: Dict[str, Optional[Callable[[bytes], str]]]
+
+    @staticmethod
+    def one_test_case(alg: crypto_knowledge.Algorithm,
+                      function: str, note: str,
+                      arguments: List[str]) -> test_case.TestCase:
+        """Construct one test case involving a hash."""
+        tc = test_case.TestCase()
+        tc.set_description('{}{} {}'
+                           .format(function,
+                                   ' ' + note if note else '',
+                                   alg.short_expression()))
+        tc.set_dependencies(psa_low_level_dependencies(alg.expression))
+        tc.set_function(function)
+        tc.set_arguments([alg.expression] +
+                         ['"{}"'.format(arg) for arg in arguments])
+        return tc
+
+    def test_cases_for_hash(self,
+                            alg: crypto_knowledge.Algorithm
+                            ) -> Iterator[test_case.TestCase]:
+        """Enumerate all test cases for one hash algorithm."""
+        calc = self.CALCULATE[alg.expression]
+        if calc is None:
+            return # not implemented yet
+
+        short = b'abc'
+        hash_short = calc(short)
+        long = (b'Hello, world. Here are 16 unprintable bytes: ['
+                b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a'
+                b'\x80\x81\x82\x83\xfe\xff]. '
+                b' This message was brought to you by a natural intelligence. '
+                b' If you can read this, good luck with your debugging!')
+        hash_long = calc(long)
+
+        yield self.one_test_case(alg, 'hash_empty', '', [calc(b'')])
+        yield self.one_test_case(alg, 'hash_valid_one_shot', '',
+                                 [short.hex(), hash_short])
+        for n in [0, 1, 64, len(long) - 1, len(long)]:
+            yield self.one_test_case(alg, 'hash_valid_multipart',
+                                     '{} + {}'.format(n, len(long) - n),
+                                     [long[:n].hex(), calc(long[:n]),
+                                      long[n:].hex(), hash_long])
+
+    def all_test_cases(self) -> Iterator[test_case.TestCase]:
+        """Enumerate all test cases for all hash algorithms."""
+        for alg in self.algorithms:
+            yield from self.test_cases_for_hash(alg)
diff --git a/scripts/mbedtls_dev/logging_util.py b/scripts/mbedtls_dev/logging_util.py
new file mode 100644
index 0000000..db1ebfe
--- /dev/null
+++ b/scripts/mbedtls_dev/logging_util.py
@@ -0,0 +1,57 @@
+"""Auxiliary functions used for logging module.
+"""
+
+# Copyright The Mbed TLS Contributors
+# 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.
+
+import logging
+import sys
+
+def configure_logger(
+        logger: logging.Logger,
+        log_format="[%(levelname)s]: %(message)s",
+        split_level=logging.WARNING
+    ) -> None:
+    """
+    Configure the logging.Logger instance so that:
+        - Format is set to any log_format.
+            Default: "[%(levelname)s]: %(message)s"
+        - loglevel >= split_level are printed to stderr.
+        - loglevel <  split_level are printed to stdout.
+            Default: logging.WARNING
+    """
+    class MaxLevelFilter(logging.Filter):
+        # pylint: disable=too-few-public-methods
+        def __init__(self, max_level, name=''):
+            super().__init__(name)
+            self.max_level = max_level
+
+        def filter(self, record: logging.LogRecord) -> bool:
+            return record.levelno <= self.max_level
+
+    log_formatter = logging.Formatter(log_format)
+
+    # set loglevel >= split_level to be printed to stderr
+    stderr_hdlr = logging.StreamHandler(sys.stderr)
+    stderr_hdlr.setLevel(split_level)
+    stderr_hdlr.setFormatter(log_formatter)
+
+    # set loglevel < split_level to be printed to stdout
+    stdout_hdlr = logging.StreamHandler(sys.stdout)
+    stdout_hdlr.addFilter(MaxLevelFilter(split_level - 1))
+    stdout_hdlr.setFormatter(log_formatter)
+
+    logger.addHandler(stderr_hdlr)
+    logger.addHandler(stdout_hdlr)
diff --git a/scripts/mbedtls_dev/psa_information.py b/scripts/mbedtls_dev/psa_information.py
new file mode 100644
index 0000000..a82df41
--- /dev/null
+++ b/scripts/mbedtls_dev/psa_information.py
@@ -0,0 +1,162 @@
+"""Collect information about PSA cryptographic mechanisms.
+"""
+
+# Copyright The Mbed TLS Contributors
+# 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.
+
+import re
+from typing import Dict, FrozenSet, List, Optional
+
+from . import macro_collector
+
+
+class Information:
+    """Gather information about PSA constructors."""
+
+    def __init__(self) -> None:
+        self.constructors = self.read_psa_interface()
+
+    @staticmethod
+    def remove_unwanted_macros(
+            constructors: macro_collector.PSAMacroEnumerator
+    ) -> None:
+        # Mbed TLS does not support finite-field DSA.
+        # Don't attempt to generate any related test case.
+        constructors.key_types.discard('PSA_KEY_TYPE_DSA_KEY_PAIR')
+        constructors.key_types.discard('PSA_KEY_TYPE_DSA_PUBLIC_KEY')
+
+    def read_psa_interface(self) -> macro_collector.PSAMacroEnumerator:
+        """Return the list of known key types, algorithms, etc."""
+        constructors = macro_collector.InputsForTest()
+        header_file_names = ['include/psa/crypto_values.h',
+                             'include/psa/crypto_extra.h']
+        test_suites = ['tests/suites/test_suite_psa_crypto_metadata.data']
+        for header_file_name in header_file_names:
+            constructors.parse_header(header_file_name)
+        for test_cases in test_suites:
+            constructors.parse_test_cases(test_cases)
+        self.remove_unwanted_macros(constructors)
+        constructors.gather_arguments()
+        return constructors
+
+
+def psa_want_symbol(name: str) -> str:
+    """Return the PSA_WANT_xxx symbol associated with a PSA crypto feature."""
+    if name.startswith('PSA_'):
+        return name[:4] + 'WANT_' + name[4:]
+    else:
+        raise ValueError('Unable to determine the PSA_WANT_ symbol for ' + name)
+
+def finish_family_dependency(dep: str, bits: int) -> str:
+    """Finish dep if it's a family dependency symbol prefix.
+
+    A family dependency symbol prefix is a PSA_WANT_ symbol that needs to be
+    qualified by the key size. If dep is such a symbol, finish it by adjusting
+    the prefix and appending the key size. Other symbols are left unchanged.
+    """
+    return re.sub(r'_FAMILY_(.*)', r'_\1_' + str(bits), dep)
+
+def finish_family_dependencies(dependencies: List[str], bits: int) -> List[str]:
+    """Finish any family dependency symbol prefixes.
+
+    Apply `finish_family_dependency` to each element of `dependencies`.
+    """
+    return [finish_family_dependency(dep, bits) for dep in dependencies]
+
+SYMBOLS_WITHOUT_DEPENDENCY = frozenset([
+    'PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG', # modifier, only in policies
+    'PSA_ALG_AEAD_WITH_SHORTENED_TAG', # modifier
+    'PSA_ALG_ANY_HASH', # only in policies
+    'PSA_ALG_AT_LEAST_THIS_LENGTH_MAC', # modifier, only in policies
+    'PSA_ALG_KEY_AGREEMENT', # chaining
+    'PSA_ALG_TRUNCATED_MAC', # modifier
+])
+def automatic_dependencies(*expressions: str) -> List[str]:
+    """Infer dependencies of a test case by looking for PSA_xxx symbols.
+
+    The arguments are strings which should be C expressions. Do not use
+    string literals or comments as this function is not smart enough to
+    skip them.
+    """
+    used = set()
+    for expr in expressions:
+        used.update(re.findall(r'PSA_(?:ALG|ECC_FAMILY|KEY_TYPE)_\w+', expr))
+    used.difference_update(SYMBOLS_WITHOUT_DEPENDENCY)
+    return sorted(psa_want_symbol(name) for name in used)
+
+# Define set of regular expressions and dependencies to optionally append
+# extra dependencies for test case.
+AES_128BIT_ONLY_DEP_REGEX = r'AES\s(192|256)'
+AES_128BIT_ONLY_DEP = ["!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH"]
+
+DEPENDENCY_FROM_KEY = {
+    AES_128BIT_ONLY_DEP_REGEX: AES_128BIT_ONLY_DEP
+}#type: Dict[str, List[str]]
+def generate_key_dependencies(description: str) -> List[str]:
+    """Return additional dependencies based on pairs of REGEX and dependencies.
+    """
+    deps = []
+    for regex, dep in DEPENDENCY_FROM_KEY.items():
+        if re.search(regex, description):
+            deps += dep
+
+    return deps
+
+# A temporary hack: at the time of writing, not all dependency symbols
+# are implemented yet. Skip test cases for which the dependency symbols are
+# not available. Once all dependency symbols are available, this hack must
+# be removed so that a bug in the dependency symbols properly leads to a test
+# failure.
+def read_implemented_dependencies(filename: str) -> FrozenSet[str]:
+    return frozenset(symbol
+                     for line in open(filename)
+                     for symbol in re.findall(r'\bPSA_WANT_\w+\b', line))
+_implemented_dependencies = None #type: Optional[FrozenSet[str]] #pylint: disable=invalid-name
+def hack_dependencies_not_implemented(dependencies: List[str]) -> None:
+    global _implemented_dependencies #pylint: disable=global-statement,invalid-name
+    if _implemented_dependencies is None:
+        _implemented_dependencies = \
+            read_implemented_dependencies('include/psa/crypto_config.h')
+    if not all((dep.lstrip('!') in _implemented_dependencies or
+                not dep.lstrip('!').startswith('PSA_WANT'))
+               for dep in dependencies):
+        dependencies.append('DEPENDENCY_NOT_IMPLEMENTED_YET')
+
+def tweak_key_pair_dependency(dep: str, usage: str):
+    """
+    This helper function add the proper suffix to PSA_WANT_KEY_TYPE_xxx_KEY_PAIR
+    symbols according to the required usage.
+    """
+    ret_list = list()
+    if dep.endswith('KEY_PAIR'):
+        if usage == "BASIC":
+            # BASIC automatically includes IMPORT and EXPORT for test purposes (see
+            # config_psa.h).
+            ret_list.append(re.sub(r'KEY_PAIR', r'KEY_PAIR_BASIC', dep))
+            ret_list.append(re.sub(r'KEY_PAIR', r'KEY_PAIR_IMPORT', dep))
+            ret_list.append(re.sub(r'KEY_PAIR', r'KEY_PAIR_EXPORT', dep))
+        elif usage == "GENERATE":
+            ret_list.append(re.sub(r'KEY_PAIR', r'KEY_PAIR_GENERATE', dep))
+    else:
+        # No replacement to do in this case
+        ret_list.append(dep)
+    return ret_list
+
+def fix_key_pair_dependencies(dep_list: List[str], usage: str):
+    new_list = [new_deps
+                for dep in dep_list
+                for new_deps in tweak_key_pair_dependency(dep, usage)]
+
+    return new_list
diff --git a/tests/.gitignore b/tests/.gitignore
index 6db65d1..973ebb5 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -1,11 +1,6 @@
 *.sln
 *.vcxproj
 
-# Generated source files
-/suites/*.generated.data
-/suites/test_suite_psa_crypto_storage_format.v[0-9]*.data
-/suites/test_suite_psa_crypto_storage_format.current.data
-
 *.log
 /test_suite*
 data_files/mpi_write
@@ -20,3 +15,10 @@
 src/libmbed*
 
 libtestdriver1/*
+
+###START_GENERATED_FILES###
+# Generated source files
+/suites/*.generated.data
+/suites/test_suite_psa_crypto_storage_format.v[0-9]*.data
+/suites/test_suite_psa_crypto_storage_format.current.data
+###END_GENERATED_FILES###
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 9bd93f1..0869aaa 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -118,8 +118,10 @@
             --directory ${CMAKE_CURRENT_BINARY_DIR}/suites
         DEPENDS
             ${CMAKE_CURRENT_SOURCE_DIR}/../tests/scripts/generate_psa_tests.py
+            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/crypto_data_tests.py
             ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/crypto_knowledge.py
             ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/macro_collector.py
+            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/psa_information.py
             ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/psa_storage.py
             ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/test_case.py
             ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/test_data_generation.py
diff --git a/tests/Makefile b/tests/Makefile
index 75dc3c6..ec016d8 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -121,8 +121,10 @@
 
 $(GENERATED_PSA_DATA_FILES): generated_psa_test_data
 generated_psa_test_data: scripts/generate_psa_tests.py
+generated_psa_test_data: ../scripts/mbedtls_dev/crypto_data_tests.py
 generated_psa_test_data: ../scripts/mbedtls_dev/crypto_knowledge.py
 generated_psa_test_data: ../scripts/mbedtls_dev/macro_collector.py
+generated_psa_test_data: ../scripts/mbedtls_dev/psa_information.py
 generated_psa_test_data: ../scripts/mbedtls_dev/psa_storage.py
 generated_psa_test_data: ../scripts/mbedtls_dev/test_case.py
 generated_psa_test_data: ../scripts/mbedtls_dev/test_data_generation.py
diff --git a/tests/compat.sh b/tests/compat.sh
index 2e03e44..b070e71 100755
--- a/tests/compat.sh
+++ b/tests/compat.sh
@@ -126,10 +126,41 @@
     printf "            \tAlso available: GnuTLS (needs v3.2.15 or higher)\n"
     printf "  -M|--memcheck\tCheck memory leaks and errors.\n"
     printf "  -v|--verbose\tSet verbose output.\n"
+    printf "     --list-test-case\tList all potential test cases (No Execution)\n"
     printf "     --outcome-file\tFile where test outcomes are written\n"
     printf "                   \t(default: \$MBEDTLS_TEST_OUTCOME_FILE, none if empty)\n"
 }
 
+# print_test_case <CLIENT> <SERVER> <STANDARD_CIPHER_SUITE>
+print_test_case() {
+    for i in $3; do
+        uniform_title $1 $2 $i
+        echo $TITLE
+    done
+}
+
+# list_test_case lists all potential test cases in compat.sh without execution
+list_test_case() {
+    reset_ciphersuites
+    for TYPE in $TYPES; do
+        add_common_ciphersuites
+        add_openssl_ciphersuites
+        add_gnutls_ciphersuites
+        add_mbedtls_ciphersuites
+    done
+
+    for VERIFY in $VERIFIES; do
+        VERIF=$(echo $VERIFY | tr '[:upper:]' '[:lower:]')
+        for MODE in $MODES; do
+            print_test_case m O "$O_CIPHERS"
+            print_test_case O m "$O_CIPHERS"
+            print_test_case m G "$G_CIPHERS"
+            print_test_case G m "$G_CIPHERS"
+            print_test_case m m "$M_CIPHERS"
+        done
+    done
+}
+
 get_options() {
     while [ $# -gt 0 ]; do
         case "$1" in
@@ -157,6 +188,12 @@
             -M|--memcheck)
                 MEMCHECK=1
                 ;;
+            # Please check scripts/check_test_cases.py correspondingly
+            # if you have to modify option, --list-test-case
+            --list-test-case)
+                list_test_case
+                exit $?
+                ;;
             --outcome-file)
                 shift; MBEDTLS_TEST_OUTCOME_FILE=$1
                 ;;
@@ -826,6 +863,14 @@
     echo "EXIT: $EXIT" >> $CLI_OUT
 }
 
+# uniform_title <CLIENT> <SERVER> <STANDARD_CIPHER_SUITE>
+# $TITLE is considered as test case description for both --list-test-case and
+# MBEDTLS_TEST_OUTCOME_FILE. This function aims to control the format of
+# each test case description.
+uniform_title() {
+    TITLE="$1->$2 $MODE,$VERIF $3"
+}
+
 # record_outcome <outcome> [<failure-reason>]
 record_outcome() {
     echo "$1"
@@ -863,8 +908,7 @@
 run_client() {
     # announce what we're going to do
     TESTS=$(( $TESTS + 1 ))
-    TITLE="${1%"${1#?}"}->${SERVER_NAME%"${SERVER_NAME#?}"}"
-    TITLE="$TITLE $MODE,$VERIF $2"
+    uniform_title "${1%"${1#?}"}" "${SERVER_NAME%"${SERVER_NAME#?}"}" $2
     DOTS72="........................................................................"
     printf "%s %.*s " "$TITLE" "$((71 - ${#TITLE}))" "$DOTS72"
 
diff --git a/tests/data_files/Makefile b/tests/data_files/Makefile
index eff44d8..b5f0844 100644
--- a/tests/data_files/Makefile
+++ b/tests/data_files/Makefile
@@ -60,6 +60,14 @@
 	$(OPENSSL) pkey -in $< -out $@ -inform PEM -outform DER -passin "pass:$(test_ca_pwd_rsa)"
 all_final += test-ca.key.der
 
+# This is only used for generating cert_example_multi_nocn.crt
+test-ca_nocn.crt: $(test_ca_key_file_rsa)
+	$(MBEDTLS_CERT_WRITE) is_ca=1 serial=3 selfsign=1 \
+		subject_key=$(test_ca_key_file_rsa) subject_pwd=$(test_ca_pwd_rsa)  subject_name="C=NL" \
+		issuer_key=$(test_ca_key_file_rsa) issuer_pwd=$(test_ca_pwd_rsa) issuer_name="C=NL" \
+		not_before=20190210144400 not_after=20290210144400 md=SHA1 version=3 output_file=$@
+all_intermediate += test-ca_nocn.crt
+
 test-ca-sha1.crt: $(test_ca_key_file_rsa) test-ca.req.sha256
 	$(MBEDTLS_CERT_WRITE) is_ca=1 serial=3 request_file=test-ca.req.sha256 selfsign=1 issuer_name="C=NL,O=PolarSSL,CN=PolarSSL Test CA" issuer_key=$(test_ca_key_file_rsa) issuer_pwd=$(test_ca_pwd_rsa) not_before=20190210144400 not_after=20290210144400 md=SHA1 version=3 output_file=$@
 all_final += test-ca-sha1.crt
@@ -99,6 +107,16 @@
 		-passin "pass:$(test_ca_pwd_rsa)" -set_serial 17 -days 3653 -sha256 \
 		-in $< > $@
 
+cert_example_multi_nocn.csr: rsa_pkcs1_1024_clear.pem
+	$(MBEDTLS_CERT_REQ) filename=$< output_file=$@ subject_name='C=NL'
+all_intermediate += cert_example_multi_nocn.csr
+
+parse_input/cert_example_multi_nocn.crt cert_example_multi_nocn.crt: cert_example_multi_nocn.csr test-ca_nocn.crt
+	$(OPENSSL) x509 -req -CA test-ca_nocn.crt -CAkey $(test_ca_key_file_rsa) \
+		-extfile $(test_ca_config_file) -extensions ext_multi_nocn -passin "pass:$(test_ca_pwd_rsa)" \
+		-set_serial  0xf7c67ff8e9a963f9 -days 3653 -sha1 -in $< > $@
+all_final += cert_example_multi_nocn.crt
+
 parse_input/test_csr_v3_keyUsage.csr.der: rsa_pkcs1_1024_clear.pem
 	$(OPENSSL) req -new -subj '/CN=etcd' -config $(test_ca_config_file) -key rsa_pkcs1_1024_clear.pem -outform DER -out $@ -reqexts csr_ext_v3_keyUsage
 parse_input/test_csr_v3_subjectAltName.csr.der: rsa_pkcs1_1024_clear.pem
@@ -168,13 +186,28 @@
 test_ca_key_file_ec = test-ca2.key
 
 test-ca2.req.sha256: $(test_ca_key_file_ec)
-	$(MBEDTLS_CERT_REQ) output_file=$@ filename=$(test_ca_key_file_ec) subject_name="C=NL,O=PolarSSL,CN=Polarssl Test EC CA" md=SHA256
+	$(MBEDTLS_CERT_REQ) output_file=$@ filename=$(test_ca_key_file_ec) \
+	subject_name="C=NL,O=PolarSSL,CN=Polarssl Test EC CA" md=SHA256
 all_intermediate += test-ca2.req.sha256
 
 test-ca2.crt: $(test_ca_key_file_ec) test-ca2.req.sha256
-	$(MBEDTLS_CERT_WRITE) is_ca=1 serial=13926223505202072808 request_file=test-ca2.req.sha256 selfsign=1 issuer_name="C=NL,O=PolarSSL,CN=Polarssl Test EC CA" issuer_key=$(test_ca_key_file_ec) not_before=20190210144400 not_after=20290210144400 md=SHA256 version=3 output_file=$@
+	$(MBEDTLS_CERT_WRITE) is_ca=1 serial=13926223505202072808 selfsign=1 \
+		request_file=test-ca2.req.sha256 \
+		issuer_name="C=NL,O=PolarSSL,CN=Polarssl Test EC CA" \
+		issuer_key=$(test_ca_key_file_ec) \
+		not_before=20190210144400 not_after=20290210144400 \
+		md=SHA256 version=3 output_file=$@
 all_final += test-ca2.crt
 
+test-ca2.ku-%.crt: test-ca2.ku-%.crt.openssl.v3_ext $(test_ca_key_file_ec) test-ca2.req.sha256
+	$(OPENSSL) x509 -req -in test-ca2.req.sha256 -extfile $< \
+		-signkey $(test_ca_key_file_ec) -days 3653 -out $@
+
+all_final += test-ca2.ku-crl.crt \
+			 test-ca2.ku-crt.crt \
+			 test-ca2.ku-crt_crl.crt \
+			 test-ca2.ku-ds.crt
+
 test-ca2-future.crt: $(test_ca_key_file_ec) test-ca2.req.sha256
 	$(MBEDTLS_CERT_WRITE) is_ca=1 serial=13926223505202072808 request_file=test-ca2.req.sha256 selfsign=1 \
 		issuer_name="C=NL,O=PolarSSL,CN=Polarssl Test EC CA" issuer_key=$(test_ca_key_file_ec) \
@@ -199,10 +232,14 @@
 all_final += $(test_ca_ec_cat)
 
 parse_input/test-ca-any_policy.crt: $(test_ca_key_file_rsa) test-ca.req.sha256
-	$(OPENSSL) req -x509 -config $(test_ca_config_file) -extensions v3_any_policy_ca -key $(test_ca_key_file_rsa) -passin "pass:$(test_ca_pwd_rsa)" -set_serial 0 -days 3653 -sha256 -in test-ca.req.sha256 -out $@
+	$(OPENSSL) req -x509 -config $(test_ca_config_file) -extensions v3_any_policy_ca \
+		-key $(test_ca_key_file_rsa) -passin "pass:$(test_ca_pwd_rsa)" \
+		-set_serial 0 -days 3653 -sha256 -in test-ca.req.sha256 -out $@
 
 parse_input/test-ca-any_policy_ec.crt: $(test_ca_key_file_ec) test-ca.req_ec.sha256
-	$(OPENSSL) req -x509 -config $(test_ca_config_file) -extensions v3_any_policy_ca -key $(test_ca_key_file_ec) -set_serial 0 -days 3653 -sha256 -in test-ca.req_ec.sha256 -out $@
+	$(OPENSSL) req -x509 -config $(test_ca_config_file) -extensions v3_any_policy_ca \
+		-key $(test_ca_key_file_ec) -set_serial 0 -days 3653 -sha256 \
+		-in test-ca.req_ec.sha256 -out $@
 
 parse_input/test-ca-any_policy_with_qualifier.crt: $(test_ca_key_file_rsa) test-ca.req.sha256
 	$(OPENSSL) req -x509 -config $(test_ca_config_file) -extensions v3_any_policy_qualifier_ca -key $(test_ca_key_file_rsa) -passin "pass:$(test_ca_pwd_rsa)" -set_serial 0 -days 3653 -sha256 -in test-ca.req.sha256 -out $@
@@ -414,9 +451,23 @@
 
 # try to forge a copy of test-int-ca3 with different key
 server5-ss-forgeca.crt: server5.key
-	$(FAKETIME) '2015-09-01 14:08:43' $(OPENSSL) req -x509 -new -subj "/C=UK/O=mbed TLS/CN=mbed TLS Test intermediate CA 3" -set_serial 77 -config $(test_ca_config_file) -extensions noext_ca -days 3650 -sha256 -key $< -out $@
+	$(OPENSSL) req -x509 -new -subj "/C=UK/O=mbed TLS/CN=mbed TLS Test intermediate CA 3" \
+		-set_serial 77 -config $(test_ca_config_file) -extensions noext_ca \
+		-days 3650 -sha256 -key $< -out $@
 all_final += server5-ss-forgeca.crt
 
+server5-selfsigned.crt: server5.key
+	openssl req -x509 -key server5.key \
+        -sha256 -days 3650 -nodes \
+        -addext basicConstraints=critical,CA:FALSE \
+        -addext keyUsage=critical,digitalSignature \
+        -addext subjectKeyIdentifier=hash   \
+        -addext authorityKeyIdentifier=none \
+        -set_serial 0x53a2cb4b124ead837da894b2 \
+        -subj "/CN=selfsigned/OU=testing/O=PolarSSL/C=NL" \
+        -out $@
+all_final += server5-selfsigned.crt
+
 parse_input/server5-othername.crt.der: server5.key
 	$(OPENSSL) req -x509 -new -subj "/C=UK/O=Mbed TLS/CN=Mbed TLS othername SAN" -set_serial 77 -config $(test_ca_config_file) -extensions othername_san -days 3650 -sha256 -key $< -outform der -out $@
 
@@ -486,6 +537,59 @@
 	{ head -n-2 $<; tail -n-2 $< | sed -e '1s/0\(=*\)$$/_\1/' -e '1s/[^_=]\(=*\)$$/0\1/' -e '1s/_/1/'; } > $@
 all_final += test-int-ca3-badsign.crt
 
+# server9*
+
+server9.csr: server9.key
+	$(OPENSSL) req -new -subj "/C=NL/O=PolarSSL/CN=localhost" \
+					-key $< -out $@
+parse_input/server9.crt server9.crt: server9-sha1.crt
+	cp $< $@
+all_final += server9.crt
+all_intermediate += server9.csr server9-sha1.crt
+
+server9-%.crt: server9.csr $(test_ca_crt) $(test_ca_key_file_rsa)
+	$(OPENSSL) x509 -req -extfile $(cli_crt_extensions_file) -extensions cli-rsa \
+		-passin "pass:$(test_ca_pwd_rsa)" -CA $(test_ca_crt) -CAkey $(test_ca_key_file_rsa) \
+		-set_serial $(SERVER9_CRT_SERIAL) -days 3653 \
+		-sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:max \
+		-sigopt rsa_mgf1_md:$(@F:server9-%.crt=%) -$(@F:server9-%.crt=%) \
+		-in $< -out $@
+server9-sha1.crt: SERVER9_CRT_SERIAL=22
+parse_input/server9-sha224.crt server9-sha224.crt: SERVER9_CRT_SERIAL=23
+parse_input/server9-sha256.crt server9-sha256.crt: SERVER9_CRT_SERIAL=24
+parse_input/server9-sha384.crt server9-sha384.crt: SERVER9_CRT_SERIAL=25
+parse_input/server9-sha512.crt server9-sha512.crt: SERVER9_CRT_SERIAL=26
+all_final += server9-sha224.crt server9-sha256.crt server9-sha384.crt server9-sha512.crt
+
+server9-defaults.crt: server9.csr $(test_ca_crt) $(test_ca_key_file_rsa)
+	$(OPENSSL) x509 -req -extfile $(cli_crt_extensions_file) -extensions cli-rsa \
+		-passin "pass:$(test_ca_pwd_rsa)" -CA $(test_ca_crt) -CAkey $(test_ca_key_file_rsa) \
+		-set_serial 72 -days 3653 \
+		-sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:max -sha1 \
+		-in $< -out $@
+all_final += server9-defaults.crt
+
+server9-badsign.crt: server9.crt
+	{ head -n-2 $<; tail -n-2 $< | sed -e '1s/0\(=*\)$$/_\1/' -e '1s/[^_=]\(=*\)$$/0\1/' -e '1s/_/1/'; } > $@
+all_final += server9-badsign.crt
+
+server9-with-ca.crt: server9.crt $(test_ca_crt)
+	cat $^ > $@
+all_final += server9-with-ca.crt
+
+# FIXME: This file needs special sequence. It should be update manually
+server9-bad-saltlen.crt: server9.csr $(test_ca_crt) $(test_ca_key_file_rsa)
+	false
+
+server9-bad-mgfhash.crt: server9.csr $(test_ca_crt) $(test_ca_key_file_rsa)
+	$(OPENSSL) x509 -req -extfile $(cli_crt_extensions_file) -extensions cli-rsa \
+		-passin "pass:$(test_ca_pwd_rsa)" -CA $(test_ca_crt) -CAkey $(test_ca_key_file_rsa) \
+		-set_serial 24 -days 3653 \
+		-sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:max \
+		-sigopt rsa_mgf1_md:sha224 -sha256 \
+		-in $< -out $@
+all_final += server9-bad-mgfhash.crt
+
 # server10*
 
 server10.crt: server10.key test-int-ca3.crt test-int-ca3.key
@@ -1304,8 +1408,7 @@
 
 server1.req.sha256.ext: server1.key
 	# Generating this with OpenSSL as a comparison point to test we're getting the same result
-	openssl req -new -out $@ -key $< -subj '/C=NL/O=PolarSSL/CN=PolarSSL Server 1' -sha256 -addext "extendedKeyUsage=serverAuth" -addext "subjectAltName=URI:http://pki.example.com/,IP:127.1.1.0,DNS:example.com"
-all_final += server1.req.sha256.ext
+	openssl req -new -out $@ -key $< -subj '/C=NL/O=PolarSSL/CN=PolarSSL Server 1' -sha256 -config server1.req.sha256.conf
 
 parse_input/server1.req.sha384 server1.req.sha384: server1.key
 	$(MBEDTLS_CERT_REQ) output_file=$@ filename=$< subject_name="C=NL,O=PolarSSL,CN=PolarSSL Server 1" md=SHA384
@@ -1385,9 +1488,35 @@
 
 # The use of 'Server 1' in the DN is intentional here, as the DN is hardcoded in the x509_write test suite.'
 server5.req.ku.sha1: server5.key
-	$(MBEDTLS_CERT_REQ) output_file=$@ filename=$< key_usage=digital_signature,non_repudiation subject_name="C=NL,O=PolarSSL,CN=PolarSSL Server 1" md=SHA1
+	$(OPENSSL) req -key $< -out $@ -new -nodes -subj "/C=NL/O=PolarSSL/CN=PolarSSL Server 1" -sha1 -addext keyUsage=digitalSignature,nonRepudiation
 all_final += server5.req.ku.sha1
 
+server5.ku-ds.crt: SERVER5_CRT_SERIAL=45
+server5.ku-ds.crt: SERVER5_KEY_USAGE=digital_signature
+server5.ku-ka.crt: SERVER5_CRT_SERIAL=46
+server5.ku-ka.crt: SERVER5_KEY_USAGE=key_agreement
+server5.ku-ke.crt: SERVER5_CRT_SERIAL=47
+server5.ku-ke.crt: SERVER5_KEY_USAGE=key_encipherment
+server5.eku-cs.crt: SERVER5_CRT_SERIAL=58
+server5.eku-cs.crt: SERVER5_EXT_KEY_USAGE=codeSigning
+server5.eku-cs_any.crt: SERVER5_CRT_SERIAL=59
+server5.eku-cs_any.crt: SERVER5_EXT_KEY_USAGE=codeSigning,any
+server5.eku-cli.crt: SERVER5_CRT_SERIAL=60
+server5.eku-cli.crt: SERVER5_EXT_KEY_USAGE=clientAuth
+server5.eku-srv_cli.crt: SERVER5_CRT_SERIAL=61
+server5.eku-srv_cli.crt: SERVER5_EXT_KEY_USAGE=serverAuth,clientAuth
+server5.eku-srv.crt: SERVER5_CRT_SERIAL=62
+server5.eku-srv.crt: SERVER5_EXT_KEY_USAGE=serverAuth
+server5.ku-%.crt: SERVER5_EXT_OPTS=key_usage=$(SERVER5_KEY_USAGE)
+server5.eku-%.crt: SERVER5_EXT_OPTS=ext_key_usage=$(SERVER5_EXT_KEY_USAGE)
+server5.%.crt: server5.key
+	$(MBEDTLS_CERT_WRITE) \
+		subject_key=$< subject_name="C=NL,O=PolarSSL,CN=localhost" serial=$(SERVER5_CRT_SERIAL) \
+		issuer_crt=$(test_ca_crt_file_ec) issuer_key=$(test_ca_key_file_ec) $(SERVER5_EXT_OPTS) \
+		not_before=20190210144406 not_after=20290210144406 md=SHA256 version=3 output_file=$@
+all_final += server5.ku-ka.crt server5.ku-ke.crt server5.ku-ds.crt
+all_final += server5.eku-cs.crt server5.eku-cs_any.crt server5.eku-cli.crt server5.eku-srv_cli.crt server5.eku-srv.crt
+
 # server6*
 
 server6.csr: server6.key
@@ -1399,6 +1528,18 @@
 				-extfile server5.crt.openssl.v3_ext -set_serial 10 -days 3650 -sha256 -in $< -out $@
 all_final += server6.crt
 
+server6-ss-child.csr : server6.key
+	$(OPENSSL) req -new -subj "/CN=selfsigned-child/OU=testing/O=PolarSSL/C=NL" \
+		-key $< -out $@
+all_intermediate += server6-ss-child.csr
+server6-ss-child.crt: server6-ss-child.csr server5-selfsigned.crt server5.key server6-ss-child.crt.openssl.v3_ext
+	$(OPENSSL) x509 -req -CA server5-selfsigned.crt -CAkey server5.key \
+				-extfile server6-ss-child.crt.openssl.v3_ext \
+				-set_serial 0x53a2cb5822399474a7ec79ec \
+				-days 3650 -sha256 -in $< -out $@
+all_final += server6-ss-child.crt
+
+
 ################################################################
 ### Generate certificates for CRT write check tests
 ################################################################
@@ -1449,7 +1590,7 @@
 	$(OPENSSL) x509 -inform PEM -in $< -outform DER -out $@
 server1.commas.crt: server1.key parse_input/server1.req.commas.sha256 $(test_ca_crt) $(test_ca_key_file_rsa)
 	$(MBEDTLS_CERT_WRITE) request_file=parse_input/server1.req.commas.sha256 issuer_crt=$(test_ca_crt) issuer_key=$(test_ca_key_file_rsa) issuer_pwd=$(test_ca_pwd_rsa) version=1 not_before=20190210144406 not_after=20290210144406 md=SHA1 version=3 output_file=$@
-all_final += server1.crt server1.noauthid.crt server1.crt.der server1.commas.crt
+all_final += server1.crt server1.noauthid.crt parse_input/server1.crt.der server1.commas.crt
 
 parse_input/server1.key_usage.crt: parse_input/server1.req.sha256
 server1.key_usage.crt: server1.req.sha256
@@ -1487,6 +1628,16 @@
 	$(OPENSSL) x509 -inform PEM -in $< -outform DER -out $@
 all_final += server1.ca.crt server1.ca_noauthid.crt server1.ca.der
 
+server1-nospace.crt: server1.key test-ca.crt
+	$(MBEDTLS_CERT_WRITE) subject_key=$< serial=31\
+		subject_name="C=NL,O=PolarSSL,CN=polarssl.example"  \
+		issuer_crt=test-ca.crt issuer_key=$(test_ca_key_file_rsa) \
+		issuer_pwd=$(test_ca_pwd_rsa) \
+		not_before=20190210144406 not_after=20290210144406 \
+		md=SHA256 version=3 authority_identifier=1 \
+		output_file=$@
+all_final += server1-nospace.crt
+
 server1_ca.crt: server1.crt $(test_ca_crt)
 	cat server1.crt $(test_ca_crt) > $@
 all_final += server1_ca.crt
@@ -1545,8 +1696,13 @@
 crl.pem: $(test_ca_crt) $(test_ca_key_file_rsa) $(test_ca_config_file)
 	$(OPENSSL) ca -gencrl -batch -cert $(test_ca_crt) -keyfile $(test_ca_key_file_rsa) -key $(test_ca_pwd_rsa) -config $(test_ca_server1_config_file) -md sha1 -crldays 3653 -out $@
 
-crl-futureRevocationDate.pem: $(test_ca_crt) $(test_ca_key_file_rsa) $(test_ca_config_file) test-ca.server1.future-crl.db  test-ca.server1.future-crl.opensslconf
-	$(FAKETIME) '2028-12-31' $(OPENSSL) ca -gencrl -config test-ca.server1.future-crl.opensslconf -crldays 365 -passin "pass:$(test_ca_pwd_rsa)" -out $@
+crl-futureRevocationDate.pem: $(test_ca_crt) $(test_ca_key_file_rsa) \
+							  $(test_ca_config_file) 				\
+							  test-ca.server1.future-crl.db  \
+							  test-ca.server1.future-crl.opensslconf
+	$(FAKETIME) -f '+10y' $(OPENSSL) ca -gencrl \
+		-config test-ca.server1.future-crl.opensslconf -crldays 365 \
+		-passin "pass:$(test_ca_pwd_rsa)" -out $@
 
 server1_all: crl.pem crl-futureRevocationDate.pem server1.crt server1.noauthid.crt server1.crt.openssl server1.v1.crt server1.v1.crt.openssl server1.key_usage.crt server1.key_usage_noauthid.crt server1.key_usage.crt.openssl server1.cert_type.crt server1.cert_type_noauthid.crt server1.cert_type.crt.openssl server1.der server1.der.openssl server1.v1.der server1.v1.der.openssl server1.key_usage.der server1.key_usage.der.openssl server1.cert_type.der server1.cert_type.der.openssl
 
@@ -1564,6 +1720,25 @@
 	$(MBEDTLS_CERT_WRITE) request_file=server2.req.sha256 serial=2 issuer_crt=$(test_ca_crt) issuer_key=$(test_ca_key_file_rsa) issuer_pwd=$(test_ca_pwd_rsa) not_before=20190210144406 not_after=20290210144406 md=SHA256 version=3 output_file=$@
 all_final += server2-sha256.crt
 
+server2.ku-ka.crt: SERVER2_CRT_SERIAL=42
+server2.ku-ka.crt: SERVER2_KEY_USAGE=key_agreement
+server2.ku-ke.crt: SERVER2_CRT_SERIAL=43
+server2.ku-ke.crt: SERVER2_KEY_USAGE=key_encipherment
+server2.ku-ds.crt: SERVER2_CRT_SERIAL=44
+server2.ku-ds.crt: SERVER2_KEY_USAGE=digital_signature
+server2.ku-ds_ke.crt: SERVER2_CRT_SERIAL=48
+server2.ku-ds_ke.crt: SERVER2_KEY_USAGE=digital_signature,key_encipherment
+server2.ku-%.crt: server2.req.sha256
+	$(MBEDTLS_CERT_WRITE) request_file=server2.req.sha256 serial=$(SERVER2_CRT_SERIAL) \
+		issuer_crt=$(test_ca_crt) issuer_key=$(test_ca_key_file_rsa) issuer_pwd=$(test_ca_pwd_rsa) \
+		key_usage="$(SERVER2_KEY_USAGE)" \
+		not_before=20190210144406 not_after=20290210144406 md=SHA1 version=3 output_file=$@
+all_final += server2.ku-ka.crt server2.ku-ke.crt server2.ku-ds.crt server2.ku-ds_ke.crt
+
+server2-badsign.crt: server2.crt
+	{ head -n-2 $<; tail -n-2 $< | sed -e '1s/0\(=*\)$$/_\1/' -e '1s/[^_=]\(=*\)$$/0\1/' -e '1s/_/1/'; } > $@
+all_final += server2-badsign.crt
+
 # server3*
 
 parse_input/server3.crt server3.crt: server3.key
@@ -1820,6 +1995,41 @@
 	dd if=pkcs7_data_cert_signed_sha256.der of=$@ skip=19 bs=1
 all_final += pkcs7_data_cert_signeddata_sha256.der
 
+# - test-ca-v1.crt: v1 "CA", signs
+#     server1-v1.crt: v1 "intermediate CA", signs
+#         server2-v1*.crt: EE cert (without of with chain in same file)
+
+test-ca-v1.crt: $(test_ca_key_file_rsa) test-ca.req.sha256
+	$(MBEDTLS_CERT_WRITE) is_ca=1 serial_hex=53a2b68e05400e555c9395e5 \
+		request_file=test-ca.req.sha256 \
+		selfsign=1 issuer_name="CN=PolarSSL Test CA v1,OU=testing,O=PolarSSL,C=NL" \
+		issuer_key=$(test_ca_key_file_rsa) issuer_pwd=$(test_ca_pwd_rsa) \
+		not_before=20190210144400 not_after=20290210144400 md=SHA256 version=1 \
+		output_file=$@
+all_final += test-ca-v1.crt
+
+server1-v1.crt: server1.key test-ca-v1.crt
+	$(MBEDTLS_CERT_WRITE) subject_key=$< serial_hex=53a2b6c704cd4d8ebc800bc1\
+		subject_name="CN=server1/int-ca-v1,OU=testing,O=PolarSSL,C=NL"  \
+		issuer_crt=test-ca-v1.crt issuer_key=$(test_ca_key_file_rsa) \
+		issuer_pwd=$(test_ca_pwd_rsa) \
+		not_before=20190210144406 not_after=20290210144406 \
+		md=SHA256 version=1 \
+		output_file=$@
+all_final += server1-v1.crt
+
+server2-v1.crt: server2.key server1-v1.crt
+	$(MBEDTLS_CERT_WRITE) subject_key=$< serial_hex=53a2b6d9235dbc4573f9b76c\
+		subject_name="CN=server2,OU=testing,O=PolarSSL,C=NL"  \
+		issuer_crt=server1-v1.crt issuer_key=server1.key \
+		not_before=20190210144406 not_after=20290210144406 \
+		md=SHA256 version=1 \
+		output_file=$@
+all_final += server2-v1.crt
+
+server2-v1-chain.crt: server2-v1.crt server1-v1.crt
+	cat $^ > $@
+
 ################################################################
 #### Generate C format test certs header
 ################################################################
diff --git a/tests/data_files/Readme-x509.txt b/tests/data_files/Readme-x509.txt
index 84c775f..82f93d2 100644
--- a/tests/data_files/Readme-x509.txt
+++ b/tests/data_files/Readme-x509.txt
@@ -76,6 +76,10 @@
     -badsign.crt: S5 with corrupted signature
     -expired.crt: S5 with "not after" date in the past
     -future.crt: S5 with "not before" date in the future
+    -non-compliant.crt: S5, RFC non-compliant
+      (with forbidden EC algorithm identifier NULL parameter)
+      generated by (before fix):
+        cert_write subject_key=server5.key subject_name="CN=Test EC RFC non-compliant" issuer_crt=test-ca2.crt issuer_key=test-ca2.key
     -selfsigned.crt: Self-signed cert with S5 key
     -ss-expired.crt: Self-signed cert with S5 key, expired
     -ss-forgeca.crt: Copy of test-int-ca3 self-signed with S5 key
diff --git a/tests/data_files/cert_example_multi_nocn.crt b/tests/data_files/cert_example_multi_nocn.crt
index 1634846..08bf63c 100644
--- a/tests/data_files/cert_example_multi_nocn.crt
+++ b/tests/data_files/cert_example_multi_nocn.crt
@@ -1,13 +1,16 @@
 -----BEGIN CERTIFICATE-----
-MIIB/TCCAWagAwIBAgIJAPfGf/jpqWP5MA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNV
-BAYTAk5MMB4XDTE0MDEyMjEwMDQzM1oXDTI0MDEyMjEwMDQzM1owDTELMAkGA1UE
-BhMCTkwwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAN0Rip+ZurBoyirqO2pt
-WZftTslU5A3uzqB9oB6q6A7CuxNA24oSjokTJKXF9frY9ZDXyMrLxf6THa/aEiNz
-UnlGGrqgVyt2FjGzqK/nOJsIi2OZOgol7kXSGFi6uZMa7dRYmmMbN/z3FAifhWVJ
-81kybdHg6G3eUu1mtKkL2kCVAgMBAAGjZTBjMAkGA1UdEwQCMAAwCwYDVR0PBAQD
+MIICfjCCAWagAwIBAgIJAPfGf/jpqWP5MA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNV
+BAYTAk5MMB4XDTIzMDUxODAyMDUwMVoXDTMzMDUxODAyMDUwMVowDTELMAkGA1UE
+BhMCTkwwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMc4ksXD9HAQCGv4EzXs
+8wEciiUPlYI2HqoelhJVGqz4e3UzC3BXM5zZlfFNTEQ3yL7EoD/kZDzT88kCQz3D
+fFuOeaoJhK6CEzcKv4VpvSo1Ymyx/uSs4EKyQXx75J0nFJssB2uOQz0/bHY6Rpoc
+cA0lnbwIx0D82AI3Yv996/wtAgMBAAGjZTBjMAkGA1UdEwQCMAAwCwYDVR0PBAQD
 AgXgMEkGA1UdEQRCMECCHHd3dy5zaG90b2thbi1icmF1bnNjaHdlaWcuZGWCFHd3
-dy5tYXNzaW1vLWFiYXRlLmV1hwTAqAEBhwTAqEWQMA0GCSqGSIb3DQEBBQUAA4GB
-ABjx1ytrqCyFC5/0cjWnbLK9vsvLny2ZikDewfRxqJ5zAxGWLqHOr1SmUmu2DrvB
-bkT9g5z19+iMhPnzJz1x7Q2m7WTIJTuUPK+hKZJATDLNhZ86h5Nkw8k9YzKcOrPm
-EIqsy55CSgLU0ntljqSBvSb4ifrF1NnIWej2lSfN6r+3
+dy5tYXNzaW1vLWFiYXRlLmV1hwTAqAEBhwTAqEWQMA0GCSqGSIb3DQEBBQUAA4IB
+AQAuomKlMLwSkP3zvGuA9awDdITM/uCzfd77yi60zMNtFHDMu2YZ2npQSl0czab6
+/8fX9goaU8V3cx4KXSLMx7i9AsP1r559Uo3c/4oTZd3xBsElMAn/TXiuujZ2RwdL
+RcMOJerlThOE0dtNdniJj7lPaan70CELP/CUn8KgeWgztQJj4ghfUwnLn6RnpLfl
+YyM/Xq2YbwnQWHXSe3CPTy5RCWalt3SgZf6IDcD6CNq1Q2l14iR78OWnlxGTFmjP
+ez3OzxNT2BZz0AiP0WvTbUtvfuxw9G3fHHe5ClsAopIA3tD246jHOAlqAnOEBC/x
+IABbWjY/briP9U4R6x+mg2ck
 -----END CERTIFICATE-----
diff --git a/tests/data_files/crl-rsa-pss-sha1-badsign.pem b/tests/data_files/crl-rsa-pss-sha1-badsign.pem
index 7e2a596..d236910 100644
--- a/tests/data_files/crl-rsa-pss-sha1-badsign.pem
+++ b/tests/data_files/crl-rsa-pss-sha1-badsign.pem
@@ -1,14 +1,14 @@
 -----BEGIN X509 CRL-----
 MIICJDCCAQYCAQEwEwYJKoZIhvcNAQEKMAaiBAICAOowOzELMAkGA1UEBhMCTkwx
-ETAPBgNVBAoTCFBvbGFyU1NMMRkwFwYDVQQDExBQb2xhclNTTCBUZXN0IENBFw0x
-NDAxMjAxMzQ2MzVaFw0yNDAxMTgxMzQ2MzVaMCgwEgIBChcNMTMwOTI0MTYyODM4
-WjASAgEWFw0xNDAxMjAxMzQzMDVaoGcwZTBjBgNVHSMEXDBagBS0WuSls97SUva5
-1aaVD+s+vMf9/6E/pD0wOzELMAkGA1UEBhMCTkwxETAPBgNVBAoTCFBvbGFyU1NM
-MRkwFwYDVQQDExBQb2xhclNTTCBUZXN0IENBggEAMBMGCSqGSIb3DQEBCjAGogQC
-AgDqA4IBAQB8ZBX0BEgRcx0lfk1ctELRu1AYoJ5BnsmQpq23Ca4YIP2yb2kTN1ZS
-4fR4SgYcNctgo2JJiNiUkCu1ZnRUOJUy8UlEio0+aeumTNz6CbeJEDhr5NC3oiV0
-MzvLn9rJVLPetOT9UrvvIy8iz5Pn1d8mu5rkt9BKQRq9NQx8riKnSIoTc91NLCMo
-mkCCB55DVbazODSWK19e6yQ0JS454RglOsqRtLJ/EDbi6lCsLXotFt3GEGMrob1O
-7Qck1Z59boaHxGYFEVnx90+4M3/qikVtwZdcBjLEmfuwYvszFw8J2y6Xwmg/HtUa
-y6li0JzWNHtkKUlCv2+SESZbD3NU8GQY
+ETAPBgNVBAoMCFBvbGFyU1NMMRkwFwYDVQQDDBBQb2xhclNTTCBUZXN0IENBFw0y
+MzA1MTcwODA3NDlaFw0zMzA1MTcwODA3NDlaMCgwEgIBChcNMjMwNTE3MDgwNzQ5
+WjASAgEWFw0yMzA1MTcwODA3NDlaoGcwZTBjBgNVHSMEXDBagBS0WuSls97SUva5
+1aaVD+s+vMf9/6E/pD0wOzELMAkGA1UEBhMCTkwxETAPBgNVBAoMCFBvbGFyU1NM
+MRkwFwYDVQQDDBBQb2xhclNTTCBUZXN0IENBggEDMBMGCSqGSIb3DQEBCjAGogQC
+AgDqA4IBAQCMUepEfAXs1G3hDE7rcIPT/AFv/oLQSVwRE8O2G5r4j0CgzN6CSGNi
+8qfFVX6f7ds+QM4pxAXk5FH4QJJkev0ZBQxmA/ZDLEFmmCEfPMsA69nG//Xeq+Xz
+ZOqJpAewmXoP2UUxV5rRpAIr9g9NvDkTT012eQEpoGkJlpxOln1VW+Dk24PCZFWf
+Nf8GMUzUsXfXm7ZdCeuc8ZDYNma0nWAMR9Jw6qaEhyH4Fd/scFvXiF/i4cpVp8Rk
+M71wSrCC0pkFzw4/bYMnf0aHle/lNg5e78SAT+/6PA8pXL7Urc0IufOfxCGwqY27
+IXSTrZJj4WeQMk289pIccMHj5DUSo4u0
 -----END X509 CRL-----
diff --git a/tests/data_files/crl-rsa-pss-sha1.pem b/tests/data_files/crl-rsa-pss-sha1.pem
index 59ca4f7..c129c0c 100644
--- a/tests/data_files/crl-rsa-pss-sha1.pem
+++ b/tests/data_files/crl-rsa-pss-sha1.pem
@@ -1,14 +1,14 @@
 -----BEGIN X509 CRL-----
 MIICJDCCAQYCAQEwEwYJKoZIhvcNAQEKMAaiBAICAOowOzELMAkGA1UEBhMCTkwx
-ETAPBgNVBAoTCFBvbGFyU1NMMRkwFwYDVQQDExBQb2xhclNTTCBUZXN0IENBFw0x
-NDAxMjAxMzQ2MzVaFw0yNDAxMTgxMzQ2MzVaMCgwEgIBChcNMTMwOTI0MTYyODM4
-WjASAgEWFw0xNDAxMjAxMzQzMDVaoGcwZTBjBgNVHSMEXDBagBS0WuSls97SUva5
-1aaVD+s+vMf9/6E/pD0wOzELMAkGA1UEBhMCTkwxETAPBgNVBAoTCFBvbGFyU1NM
-MRkwFwYDVQQDExBQb2xhclNTTCBUZXN0IENBggEAMBMGCSqGSIb3DQEBCjAGogQC
-AgDqA4IBAQB8ZBX0BEgRcx0lfk1ctELRu1AYoJ5BnsmQpq23Ca4YIP2yb2kTN1ZS
-4fR4SgYcNctgo2JJiNiUkCu1ZnRUOJUy8UlEio0+aeumTNz6CbeJEDhr5NC3oiV0
-MzvLn9rJVLPetOT9UrvvIy8iz5Pn1d8mu5rkt9BKQRq9NQx8riKnSIoTc91NLCMo
-mkCCB55DVbazODSWK19e6yQ0JS454RglOsqRtLJ/EDbi6lCsLXotFt3GEGMrob1O
-7Qck1Z59boaHxGYFEVnx90+4M3/qikVtwZdcBjLEmfuwYvszFw8J2y6Xwmg/HtUa
-y6li0JzWNHtkKUlCv2+SESZbD3NU8GQZ
+ETAPBgNVBAoMCFBvbGFyU1NMMRkwFwYDVQQDDBBQb2xhclNTTCBUZXN0IENBFw0y
+MzA1MTcwODA3NDlaFw0zMzA1MTcwODA3NDlaMCgwEgIBChcNMjMwNTE3MDgwNzQ5
+WjASAgEWFw0yMzA1MTcwODA3NDlaoGcwZTBjBgNVHSMEXDBagBS0WuSls97SUva5
+1aaVD+s+vMf9/6E/pD0wOzELMAkGA1UEBhMCTkwxETAPBgNVBAoMCFBvbGFyU1NM
+MRkwFwYDVQQDDBBQb2xhclNTTCBUZXN0IENBggEDMBMGCSqGSIb3DQEBCjAGogQC
+AgDqA4IBAQCMUepEfAXs1G3hDE7rcIPT/AFv/oLQSVwRE8O2G5r4j0CgzN6CSGNi
+8qfFVX6f7ds+QM4pxAXk5FH4QJJkev0ZBQxmA/ZDLEFmmCEfPMsA69nG//Xeq+Xz
+ZOqJpAewmXoP2UUxV5rRpAIr9g9NvDkTT012eQEpoGkJlpxOln1VW+Dk24PCZFWf
+Nf8GMUzUsXfXm7ZdCeuc8ZDYNma0nWAMR9Jw6qaEhyH4Fd/scFvXiF/i4cpVp8Rk
+M71wSrCC0pkFzw4/bYMnf0aHle/lNg5e78SAT+/6PA8pXL7Urc0IufOfxCGwqY27
+IXSTrZJj4WeQMk289pIccMHj5DUSo4uO
 -----END X509 CRL-----
diff --git a/tests/data_files/crl-rsa-pss-sha224.pem b/tests/data_files/crl-rsa-pss-sha224.pem
index a51d5d9..1108b3d 100644
--- a/tests/data_files/crl-rsa-pss-sha224.pem
+++ b/tests/data_files/crl-rsa-pss-sha224.pem
@@ -1,16 +1,16 @@
 -----BEGIN X509 CRL-----
-MIICejCCATECAQEwPgYJKoZIhvcNAQEKMDGgDTALBglghkgBZQMEAgShGjAYBgkq
-hkiG9w0BAQgwCwYJYIZIAWUDBAIEogQCAgDiMDsxCzAJBgNVBAYTAk5MMREwDwYD
-VQQKEwhQb2xhclNTTDEZMBcGA1UEAxMQUG9sYXJTU0wgVGVzdCBDQRcNMTQwMTIw
-MTM1NjA2WhcNMjQwMTE4MTM1NjA2WjAoMBICAQoXDTEzMDkyNDE2MjgzOFowEgIB
-FhcNMTQwMTIwMTM0MzA1WqBnMGUwYwYDVR0jBFwwWoAUtFrkpbPe0lL2udWmlQ/r
-PrzH/f+hP6Q9MDsxCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xhclNTTDEZMBcG
-A1UEAxMQUG9sYXJTU0wgVGVzdCBDQYIBADA+BgkqhkiG9w0BAQowMaANMAsGCWCG
-SAFlAwQCBKEaMBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgSiBAICAOIDggEBAEJI
-i9sQOzMvvOTksN48+X+kk/wkLMKRGI222lqU6y6tP1LX3OE/+KN8gPXR+lCC+e0v
-TsRTJkpKEcmHZoP/8kOtZnLb9PdITKGMQnZ+dmn5MFEzZI/zyrYWuJTuK1Q83w0e
-Mc88cAhu8i4PTk/WnsWDphK1Q2YRupmmwWSUpp1Z2rpR+YSCedC01TVrtSUJUBw9
-NSqKDhyWYJIbS6/bFaERswC8xlMRhyLHUvikjmAK36TbIdhTnEffHOPW75sEOEEB
-f0A3VtlZ7y5yt2/a6vOauJCivxKt/PutdHfBqH43QQmoVLWC2FmT9ADTJwcsZB3D
-a6JSqCIMRCQY2JOUn0A=
+MIICgjCCATUCAQEwQgYJKoZIhvcNAQEKMDWgDzANBglghkgBZQMEAgQFAKEcMBoG
+CSqGSIb3DQEBCDANBglghkgBZQMEAgQFAKIEAgIA4jA7MQswCQYDVQQGEwJOTDER
+MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EXDTIz
+MDUxNzA4MDc0OVoXDTMzMDUxNzA4MDc0OVowKDASAgEKFw0yMzA1MTcwODA3NDla
+MBICARYXDTIzMDUxNzA4MDc0OVqgZzBlMGMGA1UdIwRcMFqAFLRa5KWz3tJS9rnV
+ppUP6z68x/3/oT+kPTA7MQswCQYDVQQGEwJOTDERMA8GA1UECgwIUG9sYXJTU0wx
+GTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0GCAQMwQgYJKoZIhvcNAQEKMDWgDzAN
+BglghkgBZQMEAgQFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgQFAKIEAgIA
+4gOCAQEANsElK5qMavcgBXsqgysCIIwEPj+dXdBOwXW17HWh2jcSwAssFNRxhiIc
+PoUjj2fNlbOWXLPoxXBitgkJ31UAYCteGSv3j5P3WEuriVwCG889JEoMWn9U4+f9
+f5jSVNfynyiAOiwpA0TrOhZOAs9SEj742S1pzhsb9yaOXeQXNnDv8HYe3uX9/D9w
+ynot+/EwCYEuvK8XQ6qnV6588NHEAd9x+OcV9pxWrmUE8Muz1KffBwD5+SOW+Taj
+4fKQPcKJoRXOKyLXpOz7yMl/6fCf6h3Qj/H4YI/2gsWI0iduKoXDsuQkMEdPTZvk
+7P88YK3/4MReaZS3sDyhhUrojELPXw==
 -----END X509 CRL-----
diff --git a/tests/data_files/crl-rsa-pss-sha256.pem b/tests/data_files/crl-rsa-pss-sha256.pem
index f16a491..26f7935 100644
--- a/tests/data_files/crl-rsa-pss-sha256.pem
+++ b/tests/data_files/crl-rsa-pss-sha256.pem
@@ -1,16 +1,16 @@
 -----BEGIN X509 CRL-----
-MIICejCCATECAQEwPgYJKoZIhvcNAQEKMDGgDTALBglghkgBZQMEAgGhGjAYBgkq
-hkiG9w0BAQgwCwYJYIZIAWUDBAIBogQCAgDeMDsxCzAJBgNVBAYTAk5MMREwDwYD
-VQQKEwhQb2xhclNTTDEZMBcGA1UEAxMQUG9sYXJTU0wgVGVzdCBDQRcNMTQwMTIw
-MTM1NjE2WhcNMjQwMTE4MTM1NjE2WjAoMBICAQoXDTEzMDkyNDE2MjgzOFowEgIB
-FhcNMTQwMTIwMTM0MzA1WqBnMGUwYwYDVR0jBFwwWoAUtFrkpbPe0lL2udWmlQ/r
-PrzH/f+hP6Q9MDsxCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xhclNTTDEZMBcG
-A1UEAxMQUG9sYXJTU0wgVGVzdCBDQYIBADA+BgkqhkiG9w0BAQowMaANMAsGCWCG
-SAFlAwQCAaEaMBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgGiBAICAN4DggEBAEZ4
-oqp9i5eXrN6aCSTaU1j07MVTFW/U1jQAq6GseB6bEvoEXFMUHJsgAObqCK9flfEC
-FEqXqWSo33hhPU7AKKttbDLjUYRNnQAPRUnRIl1/a1+UjqgKchWWD9ityeW8ICxo
-IdATX9reYmPDLIMqTC7zuflYkvrvdEOuBORQP5mn4j8t84MSQF/p4qzaU0XxLo4X
-ckzZCcHpa45AApCDjJMd9onhFVCYsykiYrF9NQFO8TI4lQ5jv79GoufEzvhY1SPB
-r1xz4sMpfyaoPaa3SM2/nD65E5jzXell2u2VWNGKv4zAQP0E5yGel+1rklBltadb
-XLdJyyak33CLBKu+nJc=
+MIICgjCCATUCAQEwQgYJKoZIhvcNAQEKMDWgDzANBglghkgBZQMEAgEFAKEcMBoG
+CSqGSIb3DQEBCDANBglghkgBZQMEAgEFAKIEAgIA3jA7MQswCQYDVQQGEwJOTDER
+MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EXDTIz
+MDUxNzA4MDc0OVoXDTMzMDUxNzA4MDc0OVowKDASAgEKFw0yMzA1MTcwODA3NDla
+MBICARYXDTIzMDUxNzA4MDc0OVqgZzBlMGMGA1UdIwRcMFqAFLRa5KWz3tJS9rnV
+ppUP6z68x/3/oT+kPTA7MQswCQYDVQQGEwJOTDERMA8GA1UECgwIUG9sYXJTU0wx
+GTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0GCAQMwQgYJKoZIhvcNAQEKMDWgDzAN
+BglghkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEFAKIEAgIA
+3gOCAQEAHLzvRF0RVQL48ZGVFnTk1nsOHXVHS0UVMItsILurXJ4XrOgN1I7iTzu2
+wYNtgr+T15jwsPdgU+Gg3127vb2Djm0IUX0dCfYpSFRUv8BjaK962ZPjM0rkWhC6
+JUTWSLMAMy4ScqcoC7e4vuN2h4kPOzlvDBIhzWKA03+taAtuIOWjXZu2/Cyeggxs
+oXARKI8BEv4b94xwiFJMoMuzcYAkuDIH4MRYANVgOS/zncCRS9D5ZerfoBt70LKX
+nzJtT4a0XoxbUJeU8MZ0fR5aAHUQulAPA9CMmBsHkSx7pzAAhCwx/vXbnWPyhA6G
+XG6gCKcDR5PZQvQNgi29SLlhRTT5TA==
 -----END X509 CRL-----
diff --git a/tests/data_files/crl-rsa-pss-sha384.pem b/tests/data_files/crl-rsa-pss-sha384.pem
index 50f7e4c..45431f0 100644
--- a/tests/data_files/crl-rsa-pss-sha384.pem
+++ b/tests/data_files/crl-rsa-pss-sha384.pem
@@ -1,16 +1,16 @@
 -----BEGIN X509 CRL-----
-MIICejCCATECAQEwPgYJKoZIhvcNAQEKMDGgDTALBglghkgBZQMEAgKhGjAYBgkq
-hkiG9w0BAQgwCwYJYIZIAWUDBAICogQCAgDOMDsxCzAJBgNVBAYTAk5MMREwDwYD
-VQQKEwhQb2xhclNTTDEZMBcGA1UEAxMQUG9sYXJTU0wgVGVzdCBDQRcNMTQwMTIw
-MTM1NjI4WhcNMjQwMTE4MTM1NjI4WjAoMBICAQoXDTEzMDkyNDE2MjgzOFowEgIB
-FhcNMTQwMTIwMTM0MzA1WqBnMGUwYwYDVR0jBFwwWoAUtFrkpbPe0lL2udWmlQ/r
-PrzH/f+hP6Q9MDsxCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xhclNTTDEZMBcG
-A1UEAxMQUG9sYXJTU0wgVGVzdCBDQYIBADA+BgkqhkiG9w0BAQowMaANMAsGCWCG
-SAFlAwQCAqEaMBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgKiBAICAM4DggEBAAco
-SntUGDLBOAu0IIZaVea5Nt1NMsMcppC0hWPuH1LKAwyUODBqpT+0+AuALK0eIdYR
-a7mAB+cv2fFwmwxnQWJ1Fvx4ft/N2AAfB83VRKpSo3xR8bxloHfTWKmyxJHmH9j1
-EYmLS86rj3Nhjf4m/YlQQ3Im5HwOgSgBOE8glq5D+0Wmsi9LsNEZXEzMw7TMUgbs
-y9o/ghYF/shKU4mewK3DeM9gQiTcH5A4ISXR87hBQ08AKJRAG1CLvTyzqWiUUY+k
-q8iZDYF17sHrPi2yn8q9c4zdxiaWDGDdL0Lh90wXGTAageoGEq25TMuL5FpX+u1u
-KUH/xf1jEnNzbYNGiZw=
+MIICgjCCATUCAQEwQgYJKoZIhvcNAQEKMDWgDzANBglghkgBZQMEAgIFAKEcMBoG
+CSqGSIb3DQEBCDANBglghkgBZQMEAgIFAKIEAgIAzjA7MQswCQYDVQQGEwJOTDER
+MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EXDTIz
+MDUxNzA4MDc1MFoXDTMzMDUxNzA4MDc1MFowKDASAgEKFw0yMzA1MTcwODA3NTBa
+MBICARYXDTIzMDUxNzA4MDc1MFqgZzBlMGMGA1UdIwRcMFqAFLRa5KWz3tJS9rnV
+ppUP6z68x/3/oT+kPTA7MQswCQYDVQQGEwJOTDERMA8GA1UECgwIUG9sYXJTU0wx
+GTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0GCAQMwQgYJKoZIhvcNAQEKMDWgDzAN
+BglghkgBZQMEAgIFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgIFAKIEAgIA
+zgOCAQEAnZvMo3nmKXPV+q4m1CdMA7jUtdanJBHDAv2+LZLq4T1QpyN+nmLEB1yX
+ARN8/5Px47zm7XyZw6HI1Il34MjblAKIPBVXoswj4YLRceijwiG1bxkh1Kz3lcV0
+GCNPNo7tMPii9iATWlVzWBCzx2rLmt/ys0DtNRCMISOYGW1HkyuO28dwA6nUJwSS
+Ddjr3iilavnBdpzddH9AiN5Fm0sfrFBANx79Qyp0/r8hqrv7rT33maeRKj3S4e9G
+zpO6uHPAh9Obo93DxpKpXoMwxDiHv+bwHPO4J1YOiryy/KZmHhzUMPfvP09pGg9f
+zGO/bOyiHGH0Lf4F9JVMxpfitdbtwg==
 -----END X509 CRL-----
diff --git a/tests/data_files/crl-rsa-pss-sha512.pem b/tests/data_files/crl-rsa-pss-sha512.pem
index 0f1d651..71f2b7c 100644
--- a/tests/data_files/crl-rsa-pss-sha512.pem
+++ b/tests/data_files/crl-rsa-pss-sha512.pem
@@ -1,16 +1,16 @@
 -----BEGIN X509 CRL-----
-MIICejCCATECAQEwPgYJKoZIhvcNAQEKMDGgDTALBglghkgBZQMEAgOhGjAYBgkq
-hkiG9w0BAQgwCwYJYIZIAWUDBAIDogQCAgC+MDsxCzAJBgNVBAYTAk5MMREwDwYD
-VQQKEwhQb2xhclNTTDEZMBcGA1UEAxMQUG9sYXJTU0wgVGVzdCBDQRcNMTQwMTIw
-MTM1NjM4WhcNMjQwMTE4MTM1NjM4WjAoMBICAQoXDTEzMDkyNDE2MjgzOFowEgIB
-FhcNMTQwMTIwMTM0MzA1WqBnMGUwYwYDVR0jBFwwWoAUtFrkpbPe0lL2udWmlQ/r
-PrzH/f+hP6Q9MDsxCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xhclNTTDEZMBcG
-A1UEAxMQUG9sYXJTU0wgVGVzdCBDQYIBADA+BgkqhkiG9w0BAQowMaANMAsGCWCG
-SAFlAwQCA6EaMBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgOiBAICAL4DggEBAB9F
-ywBfxOjetxNbCFhOYoPY2jvFCFVdlowMGuxEhX/LktqiBXqRc2r5naQSzuHqO8Iq
-1zACtiDLri0CvgSHlravBNeY4c2wj//ueFE89tY5pK9E6vZp7cV+RfMx2YfGPAA2
-t7tWZ2rJWzELg8cZ8hpjSwFH7JmgJzjE5gi2gADhBYO6Vv5S3SOgqNjiN1OM31AU
-p6GHK5Y1jurF5Zwzs+w3wXoXgpOxxwEC4eiS86c9kNSudwTLvDTU0bYEQE1cF+K0
-sB8QWABFJfuO5kjD2w3rWgmAiOKsZoxd1xrda+WD3JhDXnoVq3oVBIVlWVz6YID8
-enMfMvwScA5AImzu9xA=
+MIICgjCCATUCAQEwQgYJKoZIhvcNAQEKMDWgDzANBglghkgBZQMEAgMFAKEcMBoG
+CSqGSIb3DQEBCDANBglghkgBZQMEAgMFAKIEAgIAvjA7MQswCQYDVQQGEwJOTDER
+MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EXDTIz
+MDUxNzA4MDc1MFoXDTMzMDUxNzA4MDc1MFowKDASAgEKFw0yMzA1MTcwODA3NTBa
+MBICARYXDTIzMDUxNzA4MDc1MFqgZzBlMGMGA1UdIwRcMFqAFLRa5KWz3tJS9rnV
+ppUP6z68x/3/oT+kPTA7MQswCQYDVQQGEwJOTDERMA8GA1UECgwIUG9sYXJTU0wx
+GTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0GCAQMwQgYJKoZIhvcNAQEKMDWgDzAN
+BglghkgBZQMEAgMFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgMFAKIEAgIA
+vgOCAQEAtMPpQMet9BfMRLg0AW9QfL3QkktV7xk++BqYFOYynBiqxjQH4AKu3wU8
+eiGd3+2xNpQd2/sG7UUNo1Vnl9gCHRiT4bje6+CdvvqaZKSgpmsiztbgBAYORriF
+flKOKOOQTxaikqJ4t7vp727JmstADuyizTgOBE0k3V1glas8B0G122YheeHF02S4
++33Nss4hbfbTilR0RccOaqiXzF9bkFsTlD5KgyUFZbFtdy+1zHZLnRUAJA1HmDeP
+r5p2mJxKwXmZzLnw/FPa8fUH665TKYk08AuIpN+VHdPwiBoYHJ2YZJWgM+1qHq1y
+tlyoAOC6beqsh9OfxcQZaEiWbUI9yQ==
 -----END X509 CRL-----
diff --git a/tests/data_files/parse_input/server5-non-compliant.crt b/tests/data_files/parse_input/server5-non-compliant.crt
new file mode 100644
index 0000000..abea17d
--- /dev/null
+++ b/tests/data_files/parse_input/server5-non-compliant.crt
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIBwjCCAUagAwIBAgIBATAMBggqhkjOPQQDAgUAMD4xCzAJBgNVBAYTAk5MMREw
+DwYDVQQKDAhQb2xhclNTTDEcMBoGA1UEAwwTUG9sYXJzc2wgVGVzdCBFQyBDQTAe
+Fw0wMTAxMDEwMDAwMDBaFw0zMDEyMzEyMzU5NTlaMCQxIjAgBgNVBAMMGVRlc3Qg
+RUMgUkZDIG5vbi1jb21wbGlhbnQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQ3
+zFbZdgkeWnI+x1kt/yBu7nz5BpF00K0UtfdoIllikk7lANgjEf/qL9I0XV0WvYqI
+wmt3DVXNiioO+gHItO3/o00wSzAJBgNVHRMEAjAAMB0GA1UdDgQWBBRQYaWP1AfZ
+14IBDOVlf4xjRqcTvjAfBgNVHSMEGDAWgBSdbSAkSQE/K8t4tRm8fiTJ2/s2fDAM
+BggqhkjOPQQDAgUAA2gAMGUCMAJ3J/DooFSaBG2OhzyWai32q6INDZfoS2bToSKf
+gy6hbJiIX/G9eFts5+BJQ3QpjgIxALRmIgdR91BDdqpeF5JCmhgjbfbgMQ7mrMeS
+ZGfNyFyjS75QnIA6nKryQmgPXo+sCQ==
+-----END CERTIFICATE-----
diff --git a/tests/data_files/server1-nospace.crt b/tests/data_files/server1-nospace.crt
index 932c236..4c3cb90 100644
--- a/tests/data_files/server1-nospace.crt
+++ b/tests/data_files/server1-nospace.crt
@@ -1,21 +1,20 @@
 -----BEGIN CERTIFICATE-----
-MIIDhDCCAmygAwIBAgIBHzANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER
-MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN
-MTQwMzI2MDkyMzEyWhcNMjQwMzIzMDkyMzEyWjA7MQswCQYDVQQGEwJOTDERMA8G
-A1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEHBvbGFyc3NsLmV4YW1wbGUwggEiMA0G
+MIIDPjCCAiagAwIBAgIBHzANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER
+MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN
+MTkwMjEwMTQ0NDA2WhcNMjkwMjEwMTQ0NDA2WjA7MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEHBvbGFyc3NsLmV4YW1wbGUwggEiMA0G
 CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpAh89QGrVVVOL/TbugmUuFWFeib+4
 6EWQ2+6IFlLT8UNQR5YSWWSHa/0r4Eb5c77dz5LhkVvtZqBviSl5RYDQg2rVQUN3
 Xzl8CQRHgrBXOXDto+wVGR6oMwhHwQVCqf1Mw7Tf3QYfTRBRQGdzEw9A+G2BJV8K
 sVPGMH4VOaz5Wu5/kp6mBVvnE5eFtSOS2dQkBtUJJYl1B92mGo8/CRm+rWUsZOuV
 m9z+QV4XptpsW2nMAroULBYknErczdD3Umdz8S2gI/1+9DHKLXDKiQsE2y6mT3Bu
 ns69WIniU1meblqSZeKIPwyUGaPd5eidlRPtKdurcBLcWsprF6tSglSxAgMBAAGj
-gZIwgY8wCQYDVR0TBAIwADAdBgNVHQ4EFgQUH3TWPynBdHRFOwUSLD2ovUNZAqYw
-YwYDVR0jBFwwWoAUtFrkpbPe0lL2udWmlQ/rPrzH/f+hP6Q9MDsxCzAJBgNVBAYT
-Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEZMBcGA1UEAxMQUG9sYXJTU0wgVGVzdCBD
-QYIBADANBgkqhkiG9w0BAQsFAAOCAQEAXs4vQqlIlxrMbE6IwAHLcGJuz17Ru/en
-H9bUnnSh1pxa+NHMKZHBG3GT0iaxsVtXf56/tXH4+HL7ntJjrczGN1PbhMGPyt94
-556ZgDxkHT9k7KjPAIs9BrjFHvl9NyIZzcbwkiC0qGvdzjSfe3AiSYuhXI/9/Hog
-uUwReH+T2U/ICEHQ5O8aV5nvpgqL3EeEmyx3bu+YXtZMWQUYzX+ya4TnKVPdqwbf
-ebr6v1hLXrUFl6rZ3wEJ6MqUW3SGZRkCVNZUOD6Ky3+EiLwYFhuKGdFqSS0JAAD7
-ZO3yPu5hu3BhAQYavK4Yyfi9IQmubBqxopPwyzjG1HPw2lj+oapH0w==
+TTBLMAkGA1UdEwQCMAAwHQYDVR0OBBYEFB901j8pwXR0RTsFEiw9qL1DWQKmMB8G
+A1UdIwQYMBaAFLRa5KWz3tJS9rnVppUP6z68x/3/MA0GCSqGSIb3DQEBCwUAA4IB
+AQC8fX3ZiHu6GoYBB5Vo1l6CXXDhHB6r43Pp+BHoOCouiiy4useiPLu5S84gmNoC
+v8ZR+b9lAaysCMHAbth9vgtW+aXckBY6xKo8CsmGXcqZqujD6qrDif5q6UpXa4Oe
+fr6ITkecY4Z9oN/aN5el5zzUd5zkoyQDI5Bn1gMdvV7AwM7Haq+5gTFwM7HJnphz
+GZ8GLxWU1dWeAfsGm58ey6J28OjIkmfP3yL/kBKMhiQZydbH9Y8Yal7YwhayXxES
+i7YwhNmPcGAgDBm5Sno7BvHiIqsNX1sssC3aZUaZvldJGY+4Y9fFZHenBwTREj/S
+CnEgazC2RJ3kYg3mP/QhE0US
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server1-v1.crt b/tests/data_files/server1-v1.crt
index 47f1fff..8ca9007 100644
--- a/tests/data_files/server1-v1.crt
+++ b/tests/data_files/server1-v1.crt
@@ -1,19 +1,19 @@
 -----BEGIN CERTIFICATE-----
-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
+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
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server1.req.sha256.conf b/tests/data_files/server1.req.sha256.conf
new file mode 100644
index 0000000..0d35818
--- /dev/null
+++ b/tests/data_files/server1.req.sha256.conf
@@ -0,0 +1,17 @@
+req_extensions = req_ext
+
+[req_ext]
+extendedKeyUsage = serverAuth
+subjectAltName = @alt_names
+
+[alt_names]
+email = mail@example.com
+DNS = example.com
+dirName = dirname_sect
+IP = 127.0.0.1
+URI = http://pki.example.com
+
+[dirname_sect]
+C=UK
+O=Mbed TLS
+CN=Mbed TLS directoryName SAN
diff --git a/tests/data_files/server1.req.sha256.ext b/tests/data_files/server1.req.sha256.ext
index c5ff5c5..1bb05da 100644
--- a/tests/data_files/server1.req.sha256.ext
+++ b/tests/data_files/server1.req.sha256.ext
@@ -1,18 +1,20 @@
 -----BEGIN CERTIFICATE REQUEST-----
-MIIC3jCCAcYCAQAwPDELMAkGA1UEBhMCTkwxETAPBgNVBAoMCFBvbGFyU1NMMRow
+MIIDPzCCAicCAQAwPDELMAkGA1UEBhMCTkwxETAPBgNVBAoMCFBvbGFyU1NMMRow
 GAYDVQQDDBFQb2xhclNTTCBTZXJ2ZXIgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
 ADCCAQoCggEBAKkCHz1AatVVU4v9Nu6CZS4VYV6Jv7joRZDb7ogWUtPxQ1BHlhJZ
 ZIdr/SvgRvlzvt3PkuGRW+1moG+JKXlFgNCDatVBQ3dfOXwJBEeCsFc5cO2j7BUZ
 HqgzCEfBBUKp/UzDtN/dBh9NEFFAZ3MTD0D4bYElXwqxU8YwfhU5rPla7n+SnqYF
 W+cTl4W1I5LZ1CQG1QkliXUH3aYajz8JGb6tZSxk65Wb3P5BXhem2mxbacwCuhQs
 FiScStzN0PdSZ3PxLaAj/X70McotcMqJCwTbLqZPcG6ezr1YieJTWZ5uWpJl4og/
-DJQZo93l6J2VE+0p26twEtxaymsXq1KCVLECAwEAAaBdMFsGCSqGSIb3DQEJDjFO
-MEwwEwYDVR0lBAwwCgYIKwYBBQUHAwEwNQYDVR0RBC4wLIYXaHR0cDovL3BraS5l
-eGFtcGxlLmNvbS+HBH8BAQCCC2V4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IB
-AQCGmTIXEUvTqwChkzRtxPIQDDchrMnCXgUrTSxre5nvUOpjVlcIIPGWAwxRovfe
-pW6OaGZ/3xD0dRAcOW08sTD6GRUazFrubPA1eZiNC7vYdWV59qm84N5yRR/s8Hm+
-okwI47m7W9C0pfaNXchgFUQBn16TrZxPXklbCpBJ/TFV+1ODY0sJPHYiCFpYI+Jz
-YuJmadP2BHucl8wv2RyVHywOmV1sDc74i9igVrBCAh8wu+kqImMtrnkGZDxrnj/L
-5P1eDfdqG2cN+s40RnMQMosh3UfqpNV/bTgAqBPP2uluT9L1KpWcjZeuvisOgVTq
-XwFI5s34fen2DUVw6MWNfbDK
+DJQZo93l6J2VE+0p26twEtxaymsXq1KCVLECAwEAAaCBvTCBugYJKoZIhvcNAQkO
+MYGsMIGpMBMGA1UdJQQMMAoGCCsGAQUFBwMBMIGRBgNVHREEgYkwgYaBEG1haWxA
+ZXhhbXBsZS5jb22CC2V4YW1wbGUuY29tpEcwRTELMAkGA1UEBhMCVUsxETAPBgNV
+BAoMCE1iZWQgVExTMSMwIQYDVQQDDBpNYmVkIFRMUyBkaXJlY3RvcnlOYW1lIFNB
+TocEfwAAAYYWaHR0cDovL3BraS5leGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOC
+AQEAclrNmmgAoa4ctwyBwD1T8jbyBeuxTf+ifc+MQ6pE7YuYSlanHE5l/CoVlW14
+lR5gA01pWJJ7T8RBvo25OqXbvMFSafeGXpSHOG69A6p/7YULtbPuS6uvtdR0m3t+
+2IacL0q5FsSmPw07RNfVGDFniKVqD8eAuYnhFztk0+uZVYD4xGezUckb2wTbzFpu
+lUA/NhoWfCyV44TDR5fy23qNXywEhatDU/3nMmSJpBVy4y7J6BQVCl/fbyuKIOqu
+0OVP+FvANSO46twA9+38hI+/nPuVwtbBvg1aLBMbLZ3Egi2uozokYFYL22JYNGJo
+XORQgR66Sdrvfhiug+F5xmldCg==
 -----END CERTIFICATE REQUEST-----
diff --git a/tests/data_files/server2-v1-chain.crt b/tests/data_files/server2-v1-chain.crt
index 84bb6b2..8ac003b 100644
--- a/tests/data_files/server2-v1-chain.crt
+++ b/tests/data_files/server2-v1-chain.crt
@@ -1,38 +1,38 @@
 -----BEGIN CERTIFICATE-----
-MIIDFTCCAf0CDFOittkjXbxFc/m3bDANBgkqhkiG9w0BAQsFADBOMRowGAYDVQQD
-ExFzZXJ2ZXIxL2ludC1jYS12MTEQMA4GA1UECxMHdGVzdGluZzERMA8GA1UEChMI
-UG9sYXJTU0wxCzAJBgNVBAYTAk5MMCIYDzIwMTQwNjE5MTAwOTI5WhgPMjAyNDA2
-MTgxMDA5MjlaMEQxEDAOBgNVBAMTB3NlcnZlcjIxEDAOBgNVBAsTB3Rlc3Rpbmcx
-ETAPBgNVBAoTCFBvbGFyU1NMMQswCQYDVQQGEwJOTDCCASIwDQYJKoZIhvcNAQEB
-BQADggEPADCCAQoCggEBAMFNo93nzR3RBNdJcriZrA545Do8Ss86ExbQWuTNowCI
-p+4ea5anUrSQ7y1yej4kmvy2NKwk9XfgJmSMnLAofaHa6ozmyRyWvP7BBFKzNtSj
-+uGxdtiQwWG0ZlI2oiZTqqt0Xgd9GYLbKtgfoNkNHC1JZvdbJXNG6AuKT2kMtQCQ
-4dqCEGZ9rlQri2V5kaHiYcPNQEkI7mgM8YuG0ka/0LiqEQMef1aoGh5EGA8PhYva
-i0Re4hjGYi/HZo36Xdh98yeJKQHFkA4/J/EwyEoO79bex8cna8cFPXrEAjyaHT4P
-6DSYW8tzS1KW2BGiLICIaTla0w+w3lkvEcf36hIBMJcCAwEAATANBgkqhkiG9w0B
-AQsFAAOCAQEAivCCMBfC5YNeozwp8vAWpiRUakhtO8ysvCfQsZD4tWLlSkrjoUtG
-3RNd9gDVDGb852GswtNMKHJC1AeZuXdh3eBoDBNTXnR/9UkHgWNBy5f+JH2irYrc
-ps5ofpYJZe7K6xQjl+RLc8nfUUaVfS3dJnyLr9k5kg4in48p+hEF6oXDBu2zdufF
-53k/U98FTvFkVisEDFzLXyKX0fAZxfMk4qnEoBflH4fEXfkuuaBUVdoGGIMRLNAW
-GIyRxr+zj+OJL+ZjjAkY4JqtEuUuLjODn//DHI/MkqE0LANOvbb4akpgZsyvSSO3
-o38d1wQHw5+bO+YDqdfIdQXguU5mtS1xAw==
+MIIDETCCAfkCDFOittkjXbxFc/m3bDANBgkqhkiG9w0BAQsFADBOMRowGAYDVQQD
+DBFzZXJ2ZXIxL2ludC1jYS12MTEQMA4GA1UECwwHdGVzdGluZzERMA8GA1UECgwI
+UG9sYXJTU0wxCzAJBgNVBAYTAk5MMB4XDTE5MDIxMDE0NDQwNloXDTI5MDIxMDE0
+NDQwNlowRDEQMA4GA1UEAwwHc2VydmVyMjEQMA4GA1UECwwHdGVzdGluZzERMA8G
+A1UECgwIUG9sYXJTU0wxCzAJBgNVBAYTAk5MMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAwU2j3efNHdEE10lyuJmsDnjkOjxKzzoTFtBa5M2jAIin7h5r
+lqdStJDvLXJ6PiSa/LY0rCT1d+AmZIycsCh9odrqjObJHJa8/sEEUrM21KP64bF2
+2JDBYbRmUjaiJlOqq3ReB30Zgtsq2B+g2Q0cLUlm91slc0boC4pPaQy1AJDh2oIQ
+Zn2uVCuLZXmRoeJhw81ASQjuaAzxi4bSRr/QuKoRAx5/VqgaHkQYDw+Fi9qLRF7i
+GMZiL8dmjfpd2H3zJ4kpAcWQDj8n8TDISg7v1t7HxydrxwU9esQCPJodPg/oNJhb
+y3NLUpbYEaIsgIhpOVrTD7DeWS8Rx/fqEgEwlwIDAQABMA0GCSqGSIb3DQEBCwUA
+A4IBAQBmzdRQV8c0AbT8+IlPf7EpzfdhBwBtDj7N8GPEHL+NqS1hHt7TH3L7jBN3
+CqLUgrAP1LFmQrjW5IPZYNZEA+LxMMjAehvOH71pBsFGvQOpx2CwmqM86s9FIgIa
+zob7L34+xVEZfmR09PsLiT7gF13ht0HkvVZ2haBU0k3vV97aEVvPtbqrlR6RfLrZ
+8nXBFt5CkzGxepS4wBCW4TrGXxpMJ0WnnhcLJVnExUd6YbzGP+ewXCKegD1wDX6z
+UsEVGDQV97u3tszF43kx0nu/Q5DYMCqJV0kpIsMB467xPnNqyMdGtTbZq2Is8oj6
+VA+fctBdN0CW4jo+qkOif0l/F8Az
 -----END CERTIFICATE-----
 -----BEGIN CERTIFICATE-----
-MIIDITCCAgkCDFOitscEzU2OvIALwTANBgkqhkiG9w0BAQsFADBQMRwwGgYDVQQD
-ExNQb2xhclNTTCBUZXN0IENBIHYxMRAwDgYDVQQLEwd0ZXN0aW5nMREwDwYDVQQK
-EwhQb2xhclNTTDELMAkGA1UEBhMCTkwwIhgPMjAxNDA2MTkxMDA5MTFaGA8yMDI0
-MDYxODEwMDkxMVowTjEaMBgGA1UEAxMRc2VydmVyMS9pbnQtY2EtdjExEDAOBgNV
-BAsTB3Rlc3RpbmcxETAPBgNVBAoTCFBvbGFyU1NMMQswCQYDVQQGEwJOTDCCASIw
-DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkCHz1AatVVU4v9Nu6CZS4VYV6J
-v7joRZDb7ogWUtPxQ1BHlhJZZIdr/SvgRvlzvt3PkuGRW+1moG+JKXlFgNCDatVB
-Q3dfOXwJBEeCsFc5cO2j7BUZHqgzCEfBBUKp/UzDtN/dBh9NEFFAZ3MTD0D4bYEl
-XwqxU8YwfhU5rPla7n+SnqYFW+cTl4W1I5LZ1CQG1QkliXUH3aYajz8JGb6tZSxk
-65Wb3P5BXhem2mxbacwCuhQsFiScStzN0PdSZ3PxLaAj/X70McotcMqJCwTbLqZP
-cG6ezr1YieJTWZ5uWpJl4og/DJQZo93l6J2VE+0p26twEtxaymsXq1KCVLECAwEA
-ATANBgkqhkiG9w0BAQsFAAOCAQEAPJl3fbVeTJ6gVAvCoLYM8JY5U7ZhrCCdBghw
-WuZBS/TWwf4WLP0G/ZtTyTOENcT0gWHf0/VnXtNPw2/yBjWsLtTXxN2XQlEVf3j/
-WcQxWgSESYdx/sT/uTW6qihuONPWkTQizmx7OG6vBuGx3g54s9/oeJKXOraNqud3
-G4KBrytOazliMfoKO2hnzaeydpaDtb2tZX8apN/6KqQpTAcXsWrZRW9XEHWq2sNz
-IR1nIE1F/9gnqi9Xy0HQprteLRUvM4tEQ35m4H20eS5Y9gJlE/DqXmMQ7aiU8DgP
-krj+Z18pcrssO+Etv0BOiPjmU9TWWpDMj34ef7U/OH5qJxkSrA==
+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
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server2-v1.crt b/tests/data_files/server2-v1.crt
index 7ef7968..990cd4b 100644
--- a/tests/data_files/server2-v1.crt
+++ b/tests/data_files/server2-v1.crt
@@ -1,19 +1,19 @@
 -----BEGIN CERTIFICATE-----
-MIIDFTCCAf0CDFOittkjXbxFc/m3bDANBgkqhkiG9w0BAQsFADBOMRowGAYDVQQD
-ExFzZXJ2ZXIxL2ludC1jYS12MTEQMA4GA1UECxMHdGVzdGluZzERMA8GA1UEChMI
-UG9sYXJTU0wxCzAJBgNVBAYTAk5MMCIYDzIwMTQwNjE5MTAwOTI5WhgPMjAyNDA2
-MTgxMDA5MjlaMEQxEDAOBgNVBAMTB3NlcnZlcjIxEDAOBgNVBAsTB3Rlc3Rpbmcx
-ETAPBgNVBAoTCFBvbGFyU1NMMQswCQYDVQQGEwJOTDCCASIwDQYJKoZIhvcNAQEB
-BQADggEPADCCAQoCggEBAMFNo93nzR3RBNdJcriZrA545Do8Ss86ExbQWuTNowCI
-p+4ea5anUrSQ7y1yej4kmvy2NKwk9XfgJmSMnLAofaHa6ozmyRyWvP7BBFKzNtSj
-+uGxdtiQwWG0ZlI2oiZTqqt0Xgd9GYLbKtgfoNkNHC1JZvdbJXNG6AuKT2kMtQCQ
-4dqCEGZ9rlQri2V5kaHiYcPNQEkI7mgM8YuG0ka/0LiqEQMef1aoGh5EGA8PhYva
-i0Re4hjGYi/HZo36Xdh98yeJKQHFkA4/J/EwyEoO79bex8cna8cFPXrEAjyaHT4P
-6DSYW8tzS1KW2BGiLICIaTla0w+w3lkvEcf36hIBMJcCAwEAATANBgkqhkiG9w0B
-AQsFAAOCAQEAivCCMBfC5YNeozwp8vAWpiRUakhtO8ysvCfQsZD4tWLlSkrjoUtG
-3RNd9gDVDGb852GswtNMKHJC1AeZuXdh3eBoDBNTXnR/9UkHgWNBy5f+JH2irYrc
-ps5ofpYJZe7K6xQjl+RLc8nfUUaVfS3dJnyLr9k5kg4in48p+hEF6oXDBu2zdufF
-53k/U98FTvFkVisEDFzLXyKX0fAZxfMk4qnEoBflH4fEXfkuuaBUVdoGGIMRLNAW
-GIyRxr+zj+OJL+ZjjAkY4JqtEuUuLjODn//DHI/MkqE0LANOvbb4akpgZsyvSSO3
-o38d1wQHw5+bO+YDqdfIdQXguU5mtS1xAw==
+MIIDETCCAfkCDFOittkjXbxFc/m3bDANBgkqhkiG9w0BAQsFADBOMRowGAYDVQQD
+DBFzZXJ2ZXIxL2ludC1jYS12MTEQMA4GA1UECwwHdGVzdGluZzERMA8GA1UECgwI
+UG9sYXJTU0wxCzAJBgNVBAYTAk5MMB4XDTE5MDIxMDE0NDQwNloXDTI5MDIxMDE0
+NDQwNlowRDEQMA4GA1UEAwwHc2VydmVyMjEQMA4GA1UECwwHdGVzdGluZzERMA8G
+A1UECgwIUG9sYXJTU0wxCzAJBgNVBAYTAk5MMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEAwU2j3efNHdEE10lyuJmsDnjkOjxKzzoTFtBa5M2jAIin7h5r
+lqdStJDvLXJ6PiSa/LY0rCT1d+AmZIycsCh9odrqjObJHJa8/sEEUrM21KP64bF2
+2JDBYbRmUjaiJlOqq3ReB30Zgtsq2B+g2Q0cLUlm91slc0boC4pPaQy1AJDh2oIQ
+Zn2uVCuLZXmRoeJhw81ASQjuaAzxi4bSRr/QuKoRAx5/VqgaHkQYDw+Fi9qLRF7i
+GMZiL8dmjfpd2H3zJ4kpAcWQDj8n8TDISg7v1t7HxydrxwU9esQCPJodPg/oNJhb
+y3NLUpbYEaIsgIhpOVrTD7DeWS8Rx/fqEgEwlwIDAQABMA0GCSqGSIb3DQEBCwUA
+A4IBAQBmzdRQV8c0AbT8+IlPf7EpzfdhBwBtDj7N8GPEHL+NqS1hHt7TH3L7jBN3
+CqLUgrAP1LFmQrjW5IPZYNZEA+LxMMjAehvOH71pBsFGvQOpx2CwmqM86s9FIgIa
+zob7L34+xVEZfmR09PsLiT7gF13ht0HkvVZ2haBU0k3vV97aEVvPtbqrlR6RfLrZ
+8nXBFt5CkzGxepS4wBCW4TrGXxpMJ0WnnhcLJVnExUd6YbzGP+ewXCKegD1wDX6z
+UsEVGDQV97u3tszF43kx0nu/Q5DYMCqJV0kpIsMB467xPnNqyMdGtTbZq2Is8oj6
+VA+fctBdN0CW4jo+qkOif0l/F8Az
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server2.ku-ds.crt b/tests/data_files/server2.ku-ds.crt
index 3bd07d0..d1e1251 100644
--- a/tests/data_files/server2.ku-ds.crt
+++ b/tests/data_files/server2.ku-ds.crt
@@ -1,21 +1,20 @@
 -----BEGIN CERTIFICATE-----
-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
+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
-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
+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
+SdLMa+ns3odRhF0IvENDhz/mKZJvwtoz/NBz
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server2.ku-ds_ke.crt b/tests/data_files/server2.ku-ds_ke.crt
index ebee7e1..eb23245 100644
--- a/tests/data_files/server2.ku-ds_ke.crt
+++ b/tests/data_files/server2.ku-ds_ke.crt
@@ -1,21 +1,20 @@
 -----BEGIN CERTIFICATE-----
-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
+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
-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
+HT4P6DSYW8tzS1KW2BGiLICIaTla0w+w3lkvEcf36hIBMJcCAwEAAaNdMFswCQYD
+VR0TBAIwADAdBgNVHQ4EFgQUpQXoZLjc32APUBJNYKhkr02LQ5MwHwYDVR0jBBgw
+FoAUtFrkpbPe0lL2udWmlQ/rPrzH/f8wDgYDVR0PAQH/BAQDAgWgMA0GCSqGSIb3
+DQEBBQUAA4IBAQB6u7D3tAsB75aZEcUfv2XyeLX4P99mzx2yOBSsPaIDTRyv0XoT
+vbgUA7viX/F7I8b2kc6ihRXSu/98c7Vr/uSm0LfV3VMgoAXBCWNg/5c/N3c0YnZ2
+imuv0yeXw5cJI3iYQJmllawdrGgOslfPuO7kqrFt3uGaylITpVLQ7w7iDpPbAFM8
+kPpO6CMyCFi6miQYoZchTTP9X3dpbpNdB2FlSVT55J6TIvH5x4t7XCFJuvYYJxrf
+8I3UFR3OnBR625zUHXJ6uV8yHG5ze+4K2n9CHcyX7zuZ+bB0e8wIS6Xf99M+1ApF
+ESvXwHI0Fu8s/PJ+leD28CRJQMuAOJIYBMnS
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server2.ku-ka.crt b/tests/data_files/server2.ku-ka.crt
index 90f7c4a..ce97e82 100644
--- a/tests/data_files/server2.ku-ka.crt
+++ b/tests/data_files/server2.ku-ka.crt
@@ -1,21 +1,20 @@
 -----BEGIN CERTIFICATE-----
-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
+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
-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
+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
+vXxv47xT9L+pWtiTosBmsy/ewvWprVJIxLh3
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server2.ku-ke.crt b/tests/data_files/server2.ku-ke.crt
index 8daa0c1..21e6cf0 100644
--- a/tests/data_files/server2.ku-ke.crt
+++ b/tests/data_files/server2.ku-ke.crt
@@ -1,21 +1,20 @@
 -----BEGIN CERTIFICATE-----
-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
+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
-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
+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
+FpyBlfcpj0lSRoaU9x0mCYzqwDYd+4NJZUGT
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server5-selfsigned.crt b/tests/data_files/server5-selfsigned.crt
index cb55647..0eafe70 100644
--- a/tests/data_files/server5-selfsigned.crt
+++ b/tests/data_files/server5-selfsigned.crt
@@ -1,12 +1,12 @@
 -----BEGIN CERTIFICATE-----
-MIIBzTCCAXKgAwIBAgIMU6LLSxJOrYN9qJSyMAoGCCqGSM49BAMCMEcxEzARBgNV
-BAMTCnNlbGZzaWduZWQxEDAOBgNVBAsTB3Rlc3RpbmcxETAPBgNVBAoTCFBvbGFy
-U1NMMQswCQYDVQQGEwJOTDAiGA8yMDE0MDYxOTExMzY0M1oYDzIwMjQwNjE4MTEz
-NjQzWjBHMRMwEQYDVQQDEwpzZWxmc2lnbmVkMRAwDgYDVQQLEwd0ZXN0aW5nMREw
-DwYDVQQKEwhQb2xhclNTTDELMAkGA1UEBhMCTkwwWTATBgcqhkjOPQIBBggqhkjO
-PQMBBwNCAAQ3zFbZdgkeWnI+x1kt/yBu7nz5BpF00K0UtfdoIllikk7lANgjEf/q
-L9I0XV0WvYqIwmt3DVXNiioO+gHItO3/o0AwPjAMBgNVHRMBAf8EAjAAMA8GA1Ud
-DwEB/wQFAwMHgAAwHQYDVR0OBBYEFLZtURgXjmWq8uzV8wHkbFLCNB1bMAoGCCqG
-SM49BAMCA0kAMEYCIQCf/bzFoge0pCOIrtHrABgc1+Cl9kjlsICpduXhdHUMOwIh
-AOJ+nBHfaEGyF4PRJvn/jMDeIaH1zisinVzC2v+JQOWq
+MIIBxzCCAW2gAwIBAgIMU6LLSxJOrYN9qJSyMAoGCCqGSM49BAMCMEcxEzARBgNV
+BAMMCnNlbGZzaWduZWQxEDAOBgNVBAsMB3Rlc3RpbmcxETAPBgNVBAoMCFBvbGFy
+U1NMMQswCQYDVQQGEwJOTDAeFw0yMzA1MDkwMjQ5NTdaFw0zMzA1MDYwMjQ5NTda
+MEcxEzARBgNVBAMMCnNlbGZzaWduZWQxEDAOBgNVBAsMB3Rlc3RpbmcxETAPBgNV
+BAoMCFBvbGFyU1NMMQswCQYDVQQGEwJOTDBZMBMGByqGSM49AgEGCCqGSM49AwEH
+A0IABDfMVtl2CR5acj7HWS3/IG7ufPkGkXTQrRS192giWWKSTuUA2CMR/+ov0jRd
+XRa9iojCa3cNVc2KKg76Aci07f+jPzA9MAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/
+BAQDAgeAMB0GA1UdDgQWBBRQYaWP1AfZ14IBDOVlf4xjRqcTvjAKBggqhkjOPQQD
+AgNIADBFAiAXiJxDrd5aLzGB/Uc3kYBIBuSUIMGvol2c8EvwmF3zmQIhAPFrKMgA
+s2awzo/PBB5gFTkDub88wRYwS1R9JPYCXUO0
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server5-ss-forgeca.crt b/tests/data_files/server5-ss-forgeca.crt
index 2265bf5..cf5bd6d 100644
--- a/tests/data_files/server5-ss-forgeca.crt
+++ b/tests/data_files/server5-ss-forgeca.crt
@@ -1,11 +1,11 @@
 -----BEGIN CERTIFICATE-----
-MIIBlDCCATmgAwIBAgIBTTAKBggqhkjOPQQDAjBKMQswCQYDVQQGEwJVSzERMA8G
+MIIBkzCCATmgAwIBAgIBTTAKBggqhkjOPQQDAjBKMQswCQYDVQQGEwJVSzERMA8G
 A1UECgwIbWJlZCBUTFMxKDAmBgNVBAMMH21iZWQgVExTIFRlc3QgaW50ZXJtZWRp
-YXRlIENBIDMwHhcNMTUwOTAxMTEwODQzWhcNMjUwODI5MTEwODQzWjBKMQswCQYD
+YXRlIENBIDMwHhcNMjMwNTE3MDkxNDIxWhcNMzMwNTE0MDkxNDIxWjBKMQswCQYD
 VQQGEwJVSzERMA8GA1UECgwIbWJlZCBUTFMxKDAmBgNVBAMMH21iZWQgVExTIFRl
 c3QgaW50ZXJtZWRpYXRlIENBIDMwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQ3
 zFbZdgkeWnI+x1kt/yBu7nz5BpF00K0UtfdoIllikk7lANgjEf/qL9I0XV0WvYqI
-wmt3DVXNiioO+gHItO3/oxAwDjAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0kA
-MEYCIQDBFcXh+IloVYbMiHfCFhw6cYJsj7PZXuTdDMMkNbyJNAIhALz7fBVAMYz9
-/g48bLdYT47LOc9QNuaboLIxsq5RseJL
+wmt3DVXNiioO+gHItO3/oxAwDjAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0gA
+MEUCIQD0f3GH9cEJ7cJWPIfwAL/1cGREqO//O/1XggWZv/clnQIgQmlMzGzuUDHq
+/mTgGQ9ceSAB9B9im9rcgY6DRFZULnY=
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server5.eku-cli.crt b/tests/data_files/server5.eku-cli.crt
index 8aa2e44..8d04559 100644
--- a/tests/data_files/server5.eku-cli.crt
+++ b/tests/data_files/server5.eku-cli.crt
@@ -1,13 +1,13 @@
 -----BEGIN CERTIFICATE-----
-MIIB5DCCAWmgAwIBAgIBPDAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G
-A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN
-MTQwNDEwMTcyMTIxWhcNMjQwNDA3MTcyMTIxWjA0MQswCQYDVQQGEwJOTDERMA8G
-A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDBZMBMGByqGSM49AgEG
-CCqGSM49AwEHA0IABDfMVtl2CR5acj7HWS3/IG7ufPkGkXTQrRS192giWWKSTuUA
-2CMR/+ov0jRdXRa9iojCa3cNVc2KKg76Aci07f+jYjBgMAkGA1UdEwQCMAAwHQYD
-VR0OBBYEFFBhpY/UB9nXggEM5WV/jGNGpxO+MB8GA1UdIwQYMBaAFJ1tICRJAT8r
-y3i1Gbx+JMnb+zZ8MBMGA1UdJQQMMAoGCCsGAQUFBwMCMAoGCCqGSM49BAMCA2kA
-MGYCMQCzHyEvd56zm1AzfDBi3psz3rDL/m0RN2WnbRBQJxIJqjwEXOrKazko9m9q
-owgau88CMQDuI0fsq5tnyiHPaDSAE21/6hlrCR6deNbwzB94OuPIbx1wIas9D1jc
-//iSmKtbl8Y=
+MIIB6zCCAW6gAwIBAgIBPDAMBggqhkjOPQQDAgUAMD4xCzAJBgNVBAYTAk5MMREw
+DwYDVQQKDAhQb2xhclNTTDEcMBoGA1UEAwwTUG9sYXJzc2wgVGVzdCBFQyBDQTAe
+Fw0xOTAyMTAxNDQ0MDZaFw0yOTAyMTAxNDQ0MDZaMDQxCzAJBgNVBAYTAk5MMREw
+DwYDVQQKDAhQb2xhclNTTDESMBAGA1UEAwwJbG9jYWxob3N0MFkwEwYHKoZIzj0C
+AQYIKoZIzj0DAQcDQgAEN8xW2XYJHlpyPsdZLf8gbu58+QaRdNCtFLX3aCJZYpJO
+5QDYIxH/6i/SNF1dFr2KiMJrdw1VzYoqDvoByLTt/6NlMGMwCQYDVR0TBAIwADAd
+BgNVHQ4EFgQUUGGlj9QH2deCAQzlZX+MY0anE74wHwYDVR0jBBgwFoAUnW0gJEkB
+PyvLeLUZvH4kydv7NnwwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDAYIKoZIzj0E
+AwIFAANpADBmAjEAoC1Xxg8Xt3tvM2ZER4jCRv7iSYPWGgNtcYNJj3G0lb0PYi1l
+Nd0cqdGxydhm7RJLAjEApAE8koD1ccIPnSFTagT7shOSz1/lOU4wwAWswcwolzt3
+xrvFlMoTeJx3sS3Zqdr8
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server5.eku-cs.crt b/tests/data_files/server5.eku-cs.crt
index db97b40..c00bc3b 100644
--- a/tests/data_files/server5.eku-cs.crt
+++ b/tests/data_files/server5.eku-cs.crt
@@ -1,13 +1,13 @@
 -----BEGIN CERTIFICATE-----
-MIIB4zCCAWmgAwIBAgIBOjAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G
-A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN
-MTQwNDEwMTcyMDQxWhcNMjQwNDA3MTcyMDQxWjA0MQswCQYDVQQGEwJOTDERMA8G
-A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDBZMBMGByqGSM49AgEG
-CCqGSM49AwEHA0IABDfMVtl2CR5acj7HWS3/IG7ufPkGkXTQrRS192giWWKSTuUA
-2CMR/+ov0jRdXRa9iojCa3cNVc2KKg76Aci07f+jYjBgMAkGA1UdEwQCMAAwHQYD
-VR0OBBYEFFBhpY/UB9nXggEM5WV/jGNGpxO+MB8GA1UdIwQYMBaAFJ1tICRJAT8r
-y3i1Gbx+JMnb+zZ8MBMGA1UdJQQMMAoGCCsGAQUFBwMDMAoGCCqGSM49BAMCA2gA
-MGUCMQC294oVK6fUjH/abI1xzytTusi8dl7518L0Y19q8zi9K19OtxzPK09h7xyy
-gaJRvpUCMFS6hYhrht38yqwwhSVlnmTMVtira58mEUhL6v7Qzw1sz/Dm4aXkW3s6
-JQV1kqqbRw==
+MIIB6jCCAW6gAwIBAgIBOjAMBggqhkjOPQQDAgUAMD4xCzAJBgNVBAYTAk5MMREw
+DwYDVQQKDAhQb2xhclNTTDEcMBoGA1UEAwwTUG9sYXJzc2wgVGVzdCBFQyBDQTAe
+Fw0xOTAyMTAxNDQ0MDZaFw0yOTAyMTAxNDQ0MDZaMDQxCzAJBgNVBAYTAk5MMREw
+DwYDVQQKDAhQb2xhclNTTDESMBAGA1UEAwwJbG9jYWxob3N0MFkwEwYHKoZIzj0C
+AQYIKoZIzj0DAQcDQgAEN8xW2XYJHlpyPsdZLf8gbu58+QaRdNCtFLX3aCJZYpJO
+5QDYIxH/6i/SNF1dFr2KiMJrdw1VzYoqDvoByLTt/6NlMGMwCQYDVR0TBAIwADAd
+BgNVHQ4EFgQUUGGlj9QH2deCAQzlZX+MY0anE74wHwYDVR0jBBgwFoAUnW0gJEkB
+PyvLeLUZvH4kydv7NnwwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwMwDAYIKoZIzj0E
+AwIFAANoADBlAjBlMU7Fh18cel20P3rY7esvtPLDHQQKWSCO91XHHkZi1zRPq2px
+nwVHayXnOS3CPRsCMQCQDYTyVMS8oEIrm0XPI6HrbCMUq2bhPwaYpelU/asOzYI3
+gOjGCDFHtyedJHVK0rs=
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server5.eku-cs_any.crt b/tests/data_files/server5.eku-cs_any.crt
index 8fa8632..912d929 100644
--- a/tests/data_files/server5.eku-cs_any.crt
+++ b/tests/data_files/server5.eku-cs_any.crt
@@ -1,13 +1,13 @@
 -----BEGIN CERTIFICATE-----
-MIIB6TCCAW+gAwIBAgIBOzAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G
-A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN
-MTQwNDEwMTcyMDU4WhcNMjQwNDA3MTcyMDU4WjA0MQswCQYDVQQGEwJOTDERMA8G
-A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDBZMBMGByqGSM49AgEG
-CCqGSM49AwEHA0IABDfMVtl2CR5acj7HWS3/IG7ufPkGkXTQrRS192giWWKSTuUA
-2CMR/+ov0jRdXRa9iojCa3cNVc2KKg76Aci07f+jaDBmMAkGA1UdEwQCMAAwHQYD
-VR0OBBYEFFBhpY/UB9nXggEM5WV/jGNGpxO+MB8GA1UdIwQYMBaAFJ1tICRJAT8r
-y3i1Gbx+JMnb+zZ8MBkGA1UdJQQSMBAGCCsGAQUFBwMDBgRVHSUAMAoGCCqGSM49
-BAMCA2gAMGUCMQCSYaq/9IKOTkzIrU/eOtpha/3af3JwT6vKh4N3cSX62ksMz0GT
-Uxmq4UGMBt4VmBkCMBGpYqof6hS1o92ltNRpDSHuVQ+nke1lOsoQ1plZp4SI+bY1
-bUD/WrUSLlwikZAeng==
+MIIB8DCCAXSgAwIBAgIBOzAMBggqhkjOPQQDAgUAMD4xCzAJBgNVBAYTAk5MMREw
+DwYDVQQKDAhQb2xhclNTTDEcMBoGA1UEAwwTUG9sYXJzc2wgVGVzdCBFQyBDQTAe
+Fw0xOTAyMTAxNDQ0MDZaFw0yOTAyMTAxNDQ0MDZaMDQxCzAJBgNVBAYTAk5MMREw
+DwYDVQQKDAhQb2xhclNTTDESMBAGA1UEAwwJbG9jYWxob3N0MFkwEwYHKoZIzj0C
+AQYIKoZIzj0DAQcDQgAEN8xW2XYJHlpyPsdZLf8gbu58+QaRdNCtFLX3aCJZYpJO
+5QDYIxH/6i/SNF1dFr2KiMJrdw1VzYoqDvoByLTt/6NrMGkwCQYDVR0TBAIwADAd
+BgNVHQ4EFgQUUGGlj9QH2deCAQzlZX+MY0anE74wHwYDVR0jBBgwFoAUnW0gJEkB
+PyvLeLUZvH4kydv7NnwwHAYDVR0lAQH/BBIwEAYIKwYBBQUHAwMGBFUdJQAwDAYI
+KoZIzj0EAwIFAANoADBlAjEA89+l8gNC0H75Tzdz/75W6EjGSzZ3m50S4cK5jD6+
+ZZLpRcbIqPqMT2MNkCm7ImNpAjAlTkFLVCGnTNX/q7QWOrx8aPXXAeZtY5NFxd66
+EJJb+YHTQ80hZhLWX8/QaAJjniU=
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server5.eku-srv.crt b/tests/data_files/server5.eku-srv.crt
index 64312f6..b173afc 100644
--- a/tests/data_files/server5.eku-srv.crt
+++ b/tests/data_files/server5.eku-srv.crt
@@ -1,13 +1,13 @@
 -----BEGIN CERTIFICATE-----
-MIIB5DCCAWmgAwIBAgIBPjAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G
-A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN
-MTQwNDEwMTcyMTU0WhcNMjQwNDA3MTcyMTU0WjA0MQswCQYDVQQGEwJOTDERMA8G
-A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDBZMBMGByqGSM49AgEG
-CCqGSM49AwEHA0IABDfMVtl2CR5acj7HWS3/IG7ufPkGkXTQrRS192giWWKSTuUA
-2CMR/+ov0jRdXRa9iojCa3cNVc2KKg76Aci07f+jYjBgMAkGA1UdEwQCMAAwHQYD
-VR0OBBYEFFBhpY/UB9nXggEM5WV/jGNGpxO+MB8GA1UdIwQYMBaAFJ1tICRJAT8r
-y3i1Gbx+JMnb+zZ8MBMGA1UdJQQMMAoGCCsGAQUFBwMBMAoGCCqGSM49BAMCA2kA
-MGYCMQDQzjWB0xZs/8IsqJb7owYYtCiT17939Uuc/1yBF69pJRy7KV/qJlHNvlVu
-qwWVTx0CMQDNW/0dlX1gU6ashrZv5Ly4sijg/g645fFpfMKCNXysEb9xiBeEj5de
-2x5sX/0OSx4=
+MIIB6jCCAW6gAwIBAgIBPjAMBggqhkjOPQQDAgUAMD4xCzAJBgNVBAYTAk5MMREw
+DwYDVQQKDAhQb2xhclNTTDEcMBoGA1UEAwwTUG9sYXJzc2wgVGVzdCBFQyBDQTAe
+Fw0xOTAyMTAxNDQ0MDZaFw0yOTAyMTAxNDQ0MDZaMDQxCzAJBgNVBAYTAk5MMREw
+DwYDVQQKDAhQb2xhclNTTDESMBAGA1UEAwwJbG9jYWxob3N0MFkwEwYHKoZIzj0C
+AQYIKoZIzj0DAQcDQgAEN8xW2XYJHlpyPsdZLf8gbu58+QaRdNCtFLX3aCJZYpJO
+5QDYIxH/6i/SNF1dFr2KiMJrdw1VzYoqDvoByLTt/6NlMGMwCQYDVR0TBAIwADAd
+BgNVHQ4EFgQUUGGlj9QH2deCAQzlZX+MY0anE74wHwYDVR0jBBgwFoAUnW0gJEkB
+PyvLeLUZvH4kydv7NnwwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwEwDAYIKoZIzj0E
+AwIFAANoADBlAjEAh+l47FmXR/nUxD8bfnS3sT+QTgc8pXUEqh/gXUs2xINVSoL+
+ZewgcNb2UanzCNheAjAnUY4b0M9YHp/eJjls5RzGX6JXtcWwn9JvO1HqMQnHthcy
+hPEQ3lW7XG0DIQS1drk=
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server5.eku-srv_cli.crt b/tests/data_files/server5.eku-srv_cli.crt
index 9f58fed..be2531e 100644
--- a/tests/data_files/server5.eku-srv_cli.crt
+++ b/tests/data_files/server5.eku-srv_cli.crt
@@ -1,13 +1,13 @@
 -----BEGIN CERTIFICATE-----
-MIIB7DCCAXOgAwIBAgIBPTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G
-A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN
-MTQwNDEwMTcyMTQyWhcNMjQwNDA3MTcyMTQyWjA0MQswCQYDVQQGEwJOTDERMA8G
-A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDBZMBMGByqGSM49AgEG
-CCqGSM49AwEHA0IABDfMVtl2CR5acj7HWS3/IG7ufPkGkXTQrRS192giWWKSTuUA
-2CMR/+ov0jRdXRa9iojCa3cNVc2KKg76Aci07f+jbDBqMAkGA1UdEwQCMAAwHQYD
-VR0OBBYEFFBhpY/UB9nXggEM5WV/jGNGpxO+MB8GA1UdIwQYMBaAFJ1tICRJAT8r
-y3i1Gbx+JMnb+zZ8MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAKBggq
-hkjOPQQDAgNnADBkAjAmQjJxxC82ZhBpH/GQkOQXDmaaV/JHRHGok1cWn3j3Xj8A
-fqRZkp8JihpGIMse208CMFCMdNAfNd1tv+oPuynoK5Oh6/YlASX/otJT68voEIAN
-SmsT1m9VPQMIyUo/3RtYjg==
+MIIB8zCCAXigAwIBAgIBPTAMBggqhkjOPQQDAgUAMD4xCzAJBgNVBAYTAk5MMREw
+DwYDVQQKDAhQb2xhclNTTDEcMBoGA1UEAwwTUG9sYXJzc2wgVGVzdCBFQyBDQTAe
+Fw0xOTAyMTAxNDQ0MDZaFw0yOTAyMTAxNDQ0MDZaMDQxCzAJBgNVBAYTAk5MMREw
+DwYDVQQKDAhQb2xhclNTTDESMBAGA1UEAwwJbG9jYWxob3N0MFkwEwYHKoZIzj0C
+AQYIKoZIzj0DAQcDQgAEN8xW2XYJHlpyPsdZLf8gbu58+QaRdNCtFLX3aCJZYpJO
+5QDYIxH/6i/SNF1dFr2KiMJrdw1VzYoqDvoByLTt/6NvMG0wCQYDVR0TBAIwADAd
+BgNVHQ4EFgQUUGGlj9QH2deCAQzlZX+MY0anE74wHwYDVR0jBBgwFoAUnW0gJEkB
+PyvLeLUZvH4kydv7NnwwIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
+MAwGCCqGSM49BAMCBQADZwAwZAIwHu/xjSqHK91yEM+KgEFGU8Xc3o9rEVrCBFeW
+ChIa3slZZdG4OuIm06Tsabf0pBLHAjBYKjoUwWEuDOOQKbbJZG8gKDzMAgEpe/RW
+wAjY7i6CzZ1NKfFQ9fQdwA+yjq2fnlg=
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server5.ku-ds.crt b/tests/data_files/server5.ku-ds.crt
index 58dd071..dafff9b 100644
--- a/tests/data_files/server5.ku-ds.crt
+++ b/tests/data_files/server5.ku-ds.crt
@@ -1,14 +1,13 @@
 -----BEGIN CERTIFICATE-----
-MIICLTCCAbKgAwIBAgIBLTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G
-A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN
-MTQwNDA5MDg0ODM1WhcNMjQwNDA2MDg0ODM1WjA0MQswCQYDVQQGEwJOTDERMA8G
-A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDBZMBMGByqGSM49AgEG
-CCqGSM49AwEHA0IABDfMVtl2CR5acj7HWS3/IG7ufPkGkXTQrRS192giWWKSTuUA
-2CMR/+ov0jRdXRa9iojCa3cNVc2KKg76Aci07f+jgaowgacwCQYDVR0TBAIwADAd
-BgNVHQ4EFgQUUGGlj9QH2deCAQzlZX+MY0anE74wbgYDVR0jBGcwZYAUnW0gJEkB
-PyvLeLUZvH4kydv7NnyhQqRAMD4xCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xh
-clNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBFQyBDQYIJAMFD4n5iQ8zoMAsG
-A1UdDwQEAwIHgDAKBggqhkjOPQQDAgNpADBmAjEAzp4DkFMq7eDB0x5FeS9gYDaG
-Ol8rVnWlRTLQzHZBQjKp+TcBdHZaBPoi8LyXtWA4AjEA6OWhsuTcv/qXOscQT0rL
-eEh8wcCQeJK1uNd78lNvx3W0Pcxdb6cd7AhaAKgXL+r4
+MIIB4zCCAWagAwIBAgIBLTAMBggqhkjOPQQDAgUAMD4xCzAJBgNVBAYTAk5MMREw
+DwYDVQQKDAhQb2xhclNTTDEcMBoGA1UEAwwTUG9sYXJzc2wgVGVzdCBFQyBDQTAe
+Fw0xOTAyMTAxNDQ0MDZaFw0yOTAyMTAxNDQ0MDZaMDQxCzAJBgNVBAYTAk5MMREw
+DwYDVQQKDAhQb2xhclNTTDESMBAGA1UEAwwJbG9jYWxob3N0MFkwEwYHKoZIzj0C
+AQYIKoZIzj0DAQcDQgAEN8xW2XYJHlpyPsdZLf8gbu58+QaRdNCtFLX3aCJZYpJO
+5QDYIxH/6i/SNF1dFr2KiMJrdw1VzYoqDvoByLTt/6NdMFswCQYDVR0TBAIwADAd
+BgNVHQ4EFgQUUGGlj9QH2deCAQzlZX+MY0anE74wHwYDVR0jBBgwFoAUnW0gJEkB
+PyvLeLUZvH4kydv7NnwwDgYDVR0PAQH/BAQDAgeAMAwGCCqGSM49BAMCBQADaQAw
+ZgIxALHO0QR+4vz+fj4WwBQMa55oJDlp1J0PpqoJYKTf6DRx5rNuZxSbNu2wJQWz
+MJ9ekQIxAMPo/Rhu4e9KRkEf9rYU9Ynd7t9/PCsXw4JZuxZfToURDsrAI/Pnqc0H
+4+FA/EuPJA==
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server5.ku-ka.crt b/tests/data_files/server5.ku-ka.crt
index 2447326..74a4235 100644
--- a/tests/data_files/server5.ku-ka.crt
+++ b/tests/data_files/server5.ku-ka.crt
@@ -1,14 +1,13 @@
 -----BEGIN CERTIFICATE-----
-MIICKzCCAbKgAwIBAgIBLjAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G
-A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN
-MTQwNDA5MDg0ODUwWhcNMjQwNDA2MDg0ODUwWjA0MQswCQYDVQQGEwJOTDERMA8G
-A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDBZMBMGByqGSM49AgEG
-CCqGSM49AwEHA0IABDfMVtl2CR5acj7HWS3/IG7ufPkGkXTQrRS192giWWKSTuUA
-2CMR/+ov0jRdXRa9iojCa3cNVc2KKg76Aci07f+jgaowgacwCQYDVR0TBAIwADAd
-BgNVHQ4EFgQUUGGlj9QH2deCAQzlZX+MY0anE74wbgYDVR0jBGcwZYAUnW0gJEkB
-PyvLeLUZvH4kydv7NnyhQqRAMD4xCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xh
-clNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBFQyBDQYIJAMFD4n5iQ8zoMAsG
-A1UdDwQEAwIDCDAKBggqhkjOPQQDAgNnADBkAjACzKQ88/NvngMQBFc9rC484+gO
-BRkXP28BqRcj8sBt3EfmEGH23BuhkZuB1OFZuMICMC4/pHgbOQtaY9WZPUROUVVZ
-OuO6XsVbhiE0rb/mumqmUwuOrCtC/KFdvFZol4BNGA==
+MIIB4jCCAWagAwIBAgIBLjAMBggqhkjOPQQDAgUAMD4xCzAJBgNVBAYTAk5MMREw
+DwYDVQQKDAhQb2xhclNTTDEcMBoGA1UEAwwTUG9sYXJzc2wgVGVzdCBFQyBDQTAe
+Fw0xOTAyMTAxNDQ0MDZaFw0yOTAyMTAxNDQ0MDZaMDQxCzAJBgNVBAYTAk5MMREw
+DwYDVQQKDAhQb2xhclNTTDESMBAGA1UEAwwJbG9jYWxob3N0MFkwEwYHKoZIzj0C
+AQYIKoZIzj0DAQcDQgAEN8xW2XYJHlpyPsdZLf8gbu58+QaRdNCtFLX3aCJZYpJO
+5QDYIxH/6i/SNF1dFr2KiMJrdw1VzYoqDvoByLTt/6NdMFswCQYDVR0TBAIwADAd
+BgNVHQ4EFgQUUGGlj9QH2deCAQzlZX+MY0anE74wHwYDVR0jBBgwFoAUnW0gJEkB
+PyvLeLUZvH4kydv7NnwwDgYDVR0PAQH/BAQDAgMIMAwGCCqGSM49BAMCBQADaAAw
+ZQIwCVbbPiS8MJUOz8JBmgLHojKDaJOd4lSfSak0GSl02UjT8OiNyRzA+FlFWO94
+YMjyAjEA14/ubZ1ZW3/0hkiFHzhTD2SXbTfYbhDZSq2PR+9sBlUrrx1GhzWw/cOD
+3jZd4DQO
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server5.ku-ke.crt b/tests/data_files/server5.ku-ke.crt
index 41ae5ad..6b4e74e 100644
--- a/tests/data_files/server5.ku-ke.crt
+++ b/tests/data_files/server5.ku-ke.crt
@@ -1,14 +1,13 @@
 -----BEGIN CERTIFICATE-----
-MIICKzCCAbKgAwIBAgIBLzAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G
-A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN
-MTQwNDA5MDg0OTA0WhcNMjQwNDA2MDg0OTA0WjA0MQswCQYDVQQGEwJOTDERMA8G
-A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDBZMBMGByqGSM49AgEG
-CCqGSM49AwEHA0IABDfMVtl2CR5acj7HWS3/IG7ufPkGkXTQrRS192giWWKSTuUA
-2CMR/+ov0jRdXRa9iojCa3cNVc2KKg76Aci07f+jgaowgacwCQYDVR0TBAIwADAd
-BgNVHQ4EFgQUUGGlj9QH2deCAQzlZX+MY0anE74wbgYDVR0jBGcwZYAUnW0gJEkB
-PyvLeLUZvH4kydv7NnyhQqRAMD4xCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xh
-clNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBFQyBDQYIJAMFD4n5iQ8zoMAsG
-A1UdDwQEAwIFIDAKBggqhkjOPQQDAgNnADBkAjAMl0Cjv9f45bHeJTul5XpYeJeT
-52ZaOLTa/uTLy948EnEIi6sj3nFb9fvsUbsOOjECMAXAMY64KOqzixefz3y3XS/d
-9miyeArPOmXU2JJ3LGuNbqqj9IbABawB1OD8v8gRmg==
+MIIB4TCCAWagAwIBAgIBLzAMBggqhkjOPQQDAgUAMD4xCzAJBgNVBAYTAk5MMREw
+DwYDVQQKDAhQb2xhclNTTDEcMBoGA1UEAwwTUG9sYXJzc2wgVGVzdCBFQyBDQTAe
+Fw0xOTAyMTAxNDQ0MDZaFw0yOTAyMTAxNDQ0MDZaMDQxCzAJBgNVBAYTAk5MMREw
+DwYDVQQKDAhQb2xhclNTTDESMBAGA1UEAwwJbG9jYWxob3N0MFkwEwYHKoZIzj0C
+AQYIKoZIzj0DAQcDQgAEN8xW2XYJHlpyPsdZLf8gbu58+QaRdNCtFLX3aCJZYpJO
+5QDYIxH/6i/SNF1dFr2KiMJrdw1VzYoqDvoByLTt/6NdMFswCQYDVR0TBAIwADAd
+BgNVHQ4EFgQUUGGlj9QH2deCAQzlZX+MY0anE74wHwYDVR0jBBgwFoAUnW0gJEkB
+PyvLeLUZvH4kydv7NnwwDgYDVR0PAQH/BAQDAgUgMAwGCCqGSM49BAMCBQADZwAw
+ZAIwezTY0tigIg6u1dFl90LHYcZ+lJK4BO5Y6U9pn952NFo24NsL8qnG4nxwsL3M
+VvV7AjBQ+oZyKSyNp8XRAHYC6lERH7/Gh7HrVWyTRo9iPPL6tE4x/jE7jL9ifgl+
+F6982sk=
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server5.req.ku.sha1 b/tests/data_files/server5.req.ku.sha1
index 3281c94..c73a0e2 100644
--- a/tests/data_files/server5.req.ku.sha1
+++ b/tests/data_files/server5.req.ku.sha1
@@ -1,8 +1,8 @@
 -----BEGIN CERTIFICATE REQUEST-----
-MIIBFjCBvAIBADA8MQswCQYDVQQGEwJOTDERMA8GA1UECgwIUG9sYXJTU0wxGjAY
+MIIBFDCBvAIBADA8MQswCQYDVQQGEwJOTDERMA8GA1UECgwIUG9sYXJTU0wxGjAY
 BgNVBAMMEVBvbGFyU1NMIFNlcnZlciAxMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD
 QgAEN8xW2XYJHlpyPsdZLf8gbu58+QaRdNCtFLX3aCJZYpJO5QDYIxH/6i/SNF1d
 Fr2KiMJrdw1VzYoqDvoByLTt/6AeMBwGCSqGSIb3DQEJDjEPMA0wCwYDVR0PBAQD
-AgbAMAsGByqGSM49BAEFAANIADBFAiEAnIKF+xKk0iEuN4MHd4FZWNvrznLQgkeg
-2n8ejjreTzcCIAH34z2TycuMpWQRhpV+YT988pBWR67LAg7REyZnjSAB
+AgbAMAkGByqGSM49BAEDSAAwRQIhAJyChfsSpNIhLjeDB3eBWVjb685y0IJHoNp/
+Ho463k83AiAB9+M9k8nLjKVkEYaVfmE/fPKQVkeuywIO0RMmZ40gAQ==
 -----END CERTIFICATE REQUEST-----
diff --git a/tests/data_files/server6-ss-child.crt b/tests/data_files/server6-ss-child.crt
index 3c6fd4d..fc28f34 100644
--- a/tests/data_files/server6-ss-child.crt
+++ b/tests/data_files/server6-ss-child.crt
@@ -1,13 +1,13 @@
 -----BEGIN CERTIFICATE-----
-MIIB8jCCAZmgAwIBAgIMU6LLWCI5lHSn7HnsMAoGCCqGSM49BAMCMEcxEzARBgNV
-BAMTCnNlbGZzaWduZWQxEDAOBgNVBAsTB3Rlc3RpbmcxETAPBgNVBAoTCFBvbGFy
-U1NMMQswCQYDVQQGEwJOTDAiGA8yMDE0MDYxOTExMzY1NloYDzIwMjQwNjE4MTEz
-NjU2WjBNMRkwFwYDVQQDExBzZWxmc2lnbmVkLWNoaWxkMRAwDgYDVQQLEwd0ZXN0
-aW5nMREwDwYDVQQKEwhQb2xhclNTTDELMAkGA1UEBhMCTkwwWTATBgcqhkjOPQIB
-BggqhkjOPQMBBwNCAASBWTF2SST6Fa2roDFuDu0zEfqRJVXBsMGcA3I+mLotpHI3
-iR9DN40fjjrY8FfoL0/JAKT323MPssYElNFAOzjjo2EwXzAMBgNVHRMBAf8EAjAA
-MA8GA1UdDwEB/wQFAwMHgAAwHQYDVR0OBBYEFDxZrEo+LvwCNi/afcvLnHqyiZlT
-MB8GA1UdIwQYMBaAFLZtURgXjmWq8uzV8wHkbFLCNB1bMAoGCCqGSM49BAMCA0cA
-MEQCIAMlQ59/NW7S0hP1cu5OTD2zqT087bEmnIfOTBYfj8UFAiBBrrz2dipODVYx
-vvTsQmSCzjrm+JtQQoWa+cdnAG3w5g==
+MIIB7jCCAZSgAwIBAgIMU6LLWCI5lHSn7HnsMAoGCCqGSM49BAMCMEcxEzARBgNV
+BAMMCnNlbGZzaWduZWQxEDAOBgNVBAsMB3Rlc3RpbmcxETAPBgNVBAoMCFBvbGFy
+U1NMMQswCQYDVQQGEwJOTDAeFw0yMzA1MDkwNjA2NDJaFw0zMzA1MDYwNjA2NDJa
+ME0xGTAXBgNVBAMMEHNlbGZzaWduZWQtY2hpbGQxEDAOBgNVBAsMB3Rlc3Rpbmcx
+ETAPBgNVBAoMCFBvbGFyU1NMMQswCQYDVQQGEwJOTDBZMBMGByqGSM49AgEGCCqG
+SM49AwEHA0IABIFZMXZJJPoVraugMW4O7TMR+pElVcGwwZwDcj6Yui2kcjeJH0M3
+jR+OOtjwV+gvT8kApPfbcw+yxgSU0UA7OOOjYDBeMAwGA1UdEwEB/wQCMAAwDgYD
+VR0PAQH/BAQDAgeAMB0GA1UdDgQWBBR+ZY8+MwMU5eG+YLLghX+M52ArezAfBgNV
+HSMEGDAWgBRQYaWP1AfZ14IBDOVlf4xjRqcTvjAKBggqhkjOPQQDAgNIADBFAiAl
+Y2yXg5sZunmo+McUBzvSao1wRxw+9XBSM+Dph5gfhgIhAPlI+lSvD4mzlBzn01Mg
+0tMpKHbY34iadcMWBUgibMiA
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server6-ss-child.crt.openssl.v3_ext b/tests/data_files/server6-ss-child.crt.openssl.v3_ext
new file mode 100644
index 0000000..dd9cdaa
--- /dev/null
+++ b/tests/data_files/server6-ss-child.crt.openssl.v3_ext
@@ -0,0 +1,4 @@
+basicConstraints = critical,CA:false
+keyUsage=critical,digitalSignature
+subjectKeyIdentifier=hash
+
diff --git a/tests/data_files/server9-bad-mgfhash.crt b/tests/data_files/server9-bad-mgfhash.crt
index 34ef69e..ad29942 100644
--- a/tests/data_files/server9-bad-mgfhash.crt
+++ b/tests/data_files/server9-bad-mgfhash.crt
@@ -1,20 +1,21 @@
 -----BEGIN CERTIFICATE-----
-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
+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
+QcCjGyCAIg==
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server9-bad-saltlen.crt b/tests/data_files/server9-bad-saltlen.crt
index f4da883..45bf20e 100644
--- a/tests/data_files/server9-bad-saltlen.crt
+++ b/tests/data_files/server9-bad-saltlen.crt
@@ -1,20 +1,21 @@
 -----BEGIN CERTIFICATE-----
-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
+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
+yKuEQkKKyA==
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server9-badsign.crt b/tests/data_files/server9-badsign.crt
index 9e56541..8656b1a 100644
--- a/tests/data_files/server9-badsign.crt
+++ b/tests/data_files/server9-badsign.crt
@@ -1,19 +1,19 @@
 -----BEGIN CERTIFICATE-----
 MIIDBTCCAeegAwIBAgIBFjATBgkqhkiG9w0BAQowBqIEAgIA6jA7MQswCQYDVQQG
-EwJOTDERMA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3Qg
-Q0EwHhcNMTQwMTIwMTMzODE2WhcNMjQwMTE4MTMzODE2WjA0MQswCQYDVQQGEwJO
-TDERMA8GA1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkq
+EwJOTDERMA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3Qg
+Q0EwHhcNMjMwNTE3MDgwNDAwWhcNMzMwNTE3MDgwNDAwWjA0MQswCQYDVQQGEwJO
+TDERMA8GA1UECgwIUG9sYXJTU0wxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkq
 hkiG9w0BAQEFAAOBjQAwgYkCgYEA3RGKn5m6sGjKKuo7am1Zl+1OyVTkDe7OoH2g
 HqroDsK7E0DbihKOiRMkpcX1+tj1kNfIysvF/pMdr9oSI3NSeUYauqBXK3YWMbOo
 r+c4mwiLY5k6CiXuRdIYWLq5kxrt1FiaYxs3/PcUCJ+FZUnzWTJt0eDobd5S7Wa0
-qQvaQJUCAwEAAaOBkjCBjzAJBgNVHRMEAjAAMB0GA1UdDgQWBBTu88f1HxWlTUeJ
-wdMiY7Lfp869UTBjBgNVHSMEXDBagBS0WuSls97SUva51aaVD+s+vMf9/6E/pD0w
-OzELMAkGA1UEBhMCTkwxETAPBgNVBAoTCFBvbGFyU1NMMRkwFwYDVQQDExBQb2xh
-clNTTCBUZXN0IENBggEAMBMGCSqGSIb3DQEBCjAGogQCAgDqA4IBAQDAog/jXydR
-vDIugTzBXtfVK0CEX8iyQ4cVzQmXWSne8204v943K5D2hktSBkjdQUdcnVvVgLR6
-te50jV89ptN/NofX+fo9fhSRN9vGgQVWzOOFiO0zcThy749pirJu1Kq5OJdthIyW
-Pu0UCz5G0k3kTp0JPevGlsNc8S9Ak1tFuB0IPJjrbfODWHS2LDuO+dB6gpkNTdrj
-88ogYtBsN4D5gsXBRUfobXokUwejBwLrD6XwyQx+0bMwSCxgHEhxvuUkx1vdlXGw
-JG3aF92u8mIxoKSAPaPdqy930mQvmpUWcN5Y1IMbtEGoQCKMYgosFcazJpJcjnX1
-o4Hl/lqjwCFG
+qQvaQJUCAwEAAaOBkjCBjzAdBgNVHQ4EFgQU7vPH9R8VpU1HicHTImOy36fOvVEw
+YwYDVR0jBFwwWoAUtFrkpbPe0lL2udWmlQ/rPrzH/f+hP6Q9MDsxCzAJBgNVBAYT
+Ak5MMREwDwYDVQQKDAhQb2xhclNTTDEZMBcGA1UEAwwQUG9sYXJTU0wgVGVzdCBD
+QYIBAzAJBgNVHRMEAjAAMBMGCSqGSIb3DQEBCjAGogQCAgDqA4IBAQC2DLHQ05x6
+imJNztE/Tnk/lPQ01Pw6Girdbk4bgxcGwGj+1u5wAIHNpJ50TOggg3HxTyb7p344
+/tVMxz7nrHZQ5ASdn2kDCyCmEqhmj48isWAIml+7J9cBeImJoEfYqjtqtoVkGxFy
+SuoZAQWkkqDpyFhKhIjLQ8JuSE6wWMX/kc6TFSSxepnZU1SFOXfCiaVr5tFQzBP7
+loppIANLjKeMjpOdU86PmRQ2LyzaCH1OMnjVndeqNmZt0NyzZ18cFPvm6+DVVVuP
+Q+6nReShCdAlU+dJqsqj8JsQneNMTxjv4OBoXVmE/kZTj/DBTtwmxkVi7K4aYMFi
+UYUZ4RiwG1/0
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server9-defaults.crt b/tests/data_files/server9-defaults.crt
index 4ce5c87..8613f52 100644
--- a/tests/data_files/server9-defaults.crt
+++ b/tests/data_files/server9-defaults.crt
@@ -1,19 +1,18 @@
 -----BEGIN CERTIFICATE-----
-MIIDBjCCAe6gAwIBAgIBSDANBgkqhkiG9w0BAQowADA7MQswCQYDVQQGEwJOTDER
-MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN
-MTQwNjA1MTU1NjUzWhcNMjQwNjAyMTU1NjUzWjA0MQswCQYDVQQGEwJOTDERMA8G
-A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0B
+MIIC+TCCAeGgAwIBAgIBSDANBgkqhkiG9w0BAQowADA7MQswCQYDVQQGEwJOTDER
+MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN
+MjMwNTE3MDcxMDM3WhcNMzMwNTE3MDcxMDM3WjA0MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0B
 AQEFAAOBjQAwgYkCgYEA3RGKn5m6sGjKKuo7am1Zl+1OyVTkDe7OoH2gHqroDsK7
 E0DbihKOiRMkpcX1+tj1kNfIysvF/pMdr9oSI3NSeUYauqBXK3YWMbOor+c4mwiL
 Y5k6CiXuRdIYWLq5kxrt1FiaYxs3/PcUCJ+FZUnzWTJt0eDobd5S7Wa0qQvaQJUC
-AwEAAaOBnzCBnDAJBgNVHRMEAjAAMB0GA1UdDgQWBBTu88f1HxWlTUeJwdMiY7Lf
-p869UTBjBgNVHSMEXDBagBS0WuSls97SUva51aaVD+s+vMf9/6E/pD0wOzELMAkG
-A1UEBhMCTkwxETAPBgNVBAoTCFBvbGFyU1NMMRkwFwYDVQQDExBQb2xhclNTTCBU
-ZXN0IENBggEAMAsGA1UdDwQEAwIFoDANBgkqhkiG9w0BAQowAAOCAQEAGUdim4uy
-/rBDFMF8qhjH1qsv0o8ON4HgP3YXbdKdIMfd+p5KtoqHQnrkixWxaIvfORnR4mGm
-f8H5BimwIkNLxy7zS88TVDOYel8g7B2yl0nq4biki83NStNBYZJjxKT0ud5O5mGd
-jHdy9vTEc7h8q+SHzRdgpNFXyKY5OQYng1LHco8h1UR8/nmPMuDtocHMnmMXu68a
-69+TtZxx90/V4gJZOoL1iCi8HEsKoJzm/L8ji54OYt7FxgFfE3VmLsXeMaWYO8GS
-BUxh5kqZ25O8hQXK5ywfuVK83Do/SsoClbgx9mboybseGVFIJaxs9e66GFDMoI3B
-09JqWv4DoLNnwg==
+AwEAAaOBkjCBjzAdBgNVHQ4EFgQU7vPH9R8VpU1HicHTImOy36fOvVEwYwYDVR0j
+BFwwWoAUtFrkpbPe0lL2udWmlQ/rPrzH/f+hP6Q9MDsxCzAJBgNVBAYTAk5MMREw
+DwYDVQQKDAhQb2xhclNTTDEZMBcGA1UEAwwQUG9sYXJTU0wgVGVzdCBDQYIBAzAJ
+BgNVHRMEAjAAMA0GCSqGSIb3DQEBCjAAA4IBAQASsc5y7sDP4prOLGAl2EB5d+Gg
+w/Vk9+g3KXpeIUCL6gmECNLENmmBe6zZR8/Ax6R1hUe/Cbflepxsx627Eg29NCZK
+Bo/AQoz658kwEzr4jhF8M6y9sdsf5/OauoRxDLcMEywIkgmuFvZIpyEwXix6arsK
+mNWnW0FwSr2NaXozD7OquGwTEAvAbtei+5JAeVvvGi1u32D2JPVHk3zv05LXtx8b
+8bEmzZLthFk3GbSkGHC3K5rjNgTMwY0BhNBW6qFyY5mL0bHVDbZQxD9RRwDifGty
+fTo7odJDAHU1xucWF6dOU5nAqiFKlc3eITdBKt+d10yBSr7qXciHkHpAzCvh
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server9-sha224.crt b/tests/data_files/server9-sha224.crt
index 1b05f31..ed648c8 100644
--- a/tests/data_files/server9-sha224.crt
+++ b/tests/data_files/server9-sha224.crt
@@ -1,20 +1,21 @@
 -----BEGIN CERTIFICATE-----
-MIIDWzCCAhKgAwIBAgIBFzA+BgkqhkiG9w0BAQowMaANMAsGCWCGSAFlAwQCBKEa
-MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgSiBAICAOIwOzELMAkGA1UEBhMCTkwx
-ETAPBgNVBAoTCFBvbGFyU1NMMRkwFwYDVQQDExBQb2xhclNTTCBUZXN0IENBMB4X
-DTE0MDEyMDEzNTczNloXDTI0MDExODEzNTczNlowNDELMAkGA1UEBhMCTkwxETAP
-BgNVBAoTCFBvbGFyU1NMMRIwEAYDVQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcN
-AQEBBQADgY0AMIGJAoGBAN0Rip+ZurBoyirqO2ptWZftTslU5A3uzqB9oB6q6A7C
-uxNA24oSjokTJKXF9frY9ZDXyMrLxf6THa/aEiNzUnlGGrqgVyt2FjGzqK/nOJsI
-i2OZOgol7kXSGFi6uZMa7dRYmmMbN/z3FAifhWVJ81kybdHg6G3eUu1mtKkL2kCV
-AgMBAAGjgZIwgY8wCQYDVR0TBAIwADAdBgNVHQ4EFgQU7vPH9R8VpU1HicHTImOy
-36fOvVEwYwYDVR0jBFwwWoAUtFrkpbPe0lL2udWmlQ/rPrzH/f+hP6Q9MDsxCzAJ
-BgNVBAYTAk5MMREwDwYDVQQKEwhQb2xhclNTTDEZMBcGA1UEAxMQUG9sYXJTU0wg
-VGVzdCBDQYIBADA+BgkqhkiG9w0BAQowMaANMAsGCWCGSAFlAwQCBKEaMBgGCSqG
-SIb3DQEBCDALBglghkgBZQMEAgSiBAICAOIDggEBADJExjfWWvL28lgj+GGgviqo
-PHZLxI0pLQUnFJQ9Kpu6jxfICseBF00Z6BJE/RcYDpIie5GDt/8u/i6xB6Li29Pm
-g5nANgd/Y3fFnW7d0ydVjiSnetlPuf/jTlWQl6mQTH2xqYu8J8d3JRxQdRiDYbVm
-uywW2d6rksiqm6dPD5l4A5DcemcYo8f/1Ifj5WNDCV8/OHex+AnW2ccDvWAnVgSR
-B2VpOXJzVFuBsuf4tGVm/2TUMSB6NcvFc6TeJk1kzbZxii4QjKXtH1SfrVP59iEe
-l17NYAEWARjBpQWBiutRG+QM2et0sNiUBuWxTkvd0eSgencNysVAOsZqrqaX3CY=
+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
+3egYnUY/9g==
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server9-sha256.crt b/tests/data_files/server9-sha256.crt
index 7d0aa39..ef37b3f 100644
--- a/tests/data_files/server9-sha256.crt
+++ b/tests/data_files/server9-sha256.crt
@@ -1,20 +1,21 @@
 -----BEGIN CERTIFICATE-----
-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
+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
+a8P+xLLmug==
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server9-sha384.crt b/tests/data_files/server9-sha384.crt
index aaa63e6..2ea0108 100644
--- a/tests/data_files/server9-sha384.crt
+++ b/tests/data_files/server9-sha384.crt
@@ -1,20 +1,21 @@
 -----BEGIN CERTIFICATE-----
-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
+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
+RidkcXFMxQ==
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server9-sha512.crt b/tests/data_files/server9-sha512.crt
index a211b92..4abdf68 100644
--- a/tests/data_files/server9-sha512.crt
+++ b/tests/data_files/server9-sha512.crt
@@ -1,20 +1,21 @@
 -----BEGIN CERTIFICATE-----
-MIIDWzCCAhKgAwIBAgIBGjA+BgkqhkiG9w0BAQowMaANMAsGCWCGSAFlAwQCA6Ea
-MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgOiBAICAL4wOzELMAkGA1UEBhMCTkwx
-ETAPBgNVBAoTCFBvbGFyU1NMMRkwFwYDVQQDExBQb2xhclNTTCBUZXN0IENBMB4X
-DTE0MDEyMDEzNTgxMloXDTI0MDExODEzNTgxMlowNDELMAkGA1UEBhMCTkwxETAP
-BgNVBAoTCFBvbGFyU1NMMRIwEAYDVQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcN
-AQEBBQADgY0AMIGJAoGBAN0Rip+ZurBoyirqO2ptWZftTslU5A3uzqB9oB6q6A7C
-uxNA24oSjokTJKXF9frY9ZDXyMrLxf6THa/aEiNzUnlGGrqgVyt2FjGzqK/nOJsI
-i2OZOgol7kXSGFi6uZMa7dRYmmMbN/z3FAifhWVJ81kybdHg6G3eUu1mtKkL2kCV
-AgMBAAGjgZIwgY8wCQYDVR0TBAIwADAdBgNVHQ4EFgQU7vPH9R8VpU1HicHTImOy
-36fOvVEwYwYDVR0jBFwwWoAUtFrkpbPe0lL2udWmlQ/rPrzH/f+hP6Q9MDsxCzAJ
-BgNVBAYTAk5MMREwDwYDVQQKEwhQb2xhclNTTDEZMBcGA1UEAxMQUG9sYXJTU0wg
-VGVzdCBDQYIBADA+BgkqhkiG9w0BAQowMaANMAsGCWCGSAFlAwQCA6EaMBgGCSqG
-SIb3DQEBCDALBglghkgBZQMEAgOiBAICAL4DggEBACdVozFq6rUiXo+ib5Y2oPsR
-6xxl4Ydn3LpUoYrPpTOrhcXJWW/tOLHGuCF/mSRfUzKaMIfL418cZHYnvumvuttu
-6z3tp5E1VsiZCU2MWJnzjKSxFBOss43AmpJHHoapGFZu2pxObBPqegAKHYkKWOLk
-tJDj47PurWgEek9j1nL7Pc1tVf59fm/ySp4fWkXLLvQiKid1516VioLyacUvK3zU
-6Egz8jMt7D5c9KpaExLRTANVsThqO5/dmR36bOwm3Hpbde7DNdgxru41tiLMqJs/
-5pX3ceaJ1XQ/l0idj5/9ipvqHHUguyk7H22HwQHQdSD9oIha8kEM3P6CjpfE7yY=
+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
+O1z3OQn3+w==
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server9-with-ca.crt b/tests/data_files/server9-with-ca.crt
index 0478cff..51c0ada 100644
--- a/tests/data_files/server9-with-ca.crt
+++ b/tests/data_files/server9-with-ca.crt
@@ -1,99 +1,39 @@
 -----BEGIN CERTIFICATE-----
 MIIDBTCCAeegAwIBAgIBFjATBgkqhkiG9w0BAQowBqIEAgIA6jA7MQswCQYDVQQG
-EwJOTDERMA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3Qg
-Q0EwHhcNMTQwMTIwMTMzODE2WhcNMjQwMTE4MTMzODE2WjA0MQswCQYDVQQGEwJO
-TDERMA8GA1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkq
+EwJOTDERMA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3Qg
+Q0EwHhcNMjMwNTE3MDgwNDAwWhcNMzMwNTE3MDgwNDAwWjA0MQswCQYDVQQGEwJO
+TDERMA8GA1UECgwIUG9sYXJTU0wxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkq
 hkiG9w0BAQEFAAOBjQAwgYkCgYEA3RGKn5m6sGjKKuo7am1Zl+1OyVTkDe7OoH2g
 HqroDsK7E0DbihKOiRMkpcX1+tj1kNfIysvF/pMdr9oSI3NSeUYauqBXK3YWMbOo
 r+c4mwiLY5k6CiXuRdIYWLq5kxrt1FiaYxs3/PcUCJ+FZUnzWTJt0eDobd5S7Wa0
-qQvaQJUCAwEAAaOBkjCBjzAJBgNVHRMEAjAAMB0GA1UdDgQWBBTu88f1HxWlTUeJ
-wdMiY7Lfp869UTBjBgNVHSMEXDBagBS0WuSls97SUva51aaVD+s+vMf9/6E/pD0w
-OzELMAkGA1UEBhMCTkwxETAPBgNVBAoTCFBvbGFyU1NMMRkwFwYDVQQDExBQb2xh
-clNTTCBUZXN0IENBggEAMBMGCSqGSIb3DQEBCjAGogQCAgDqA4IBAQDAog/jXydR
-vDIugTzBXtfVK0CEX8iyQ4cVzQmXWSne8204v943K5D2hktSBkjdQUdcnVvVgLR6
-te50jV89ptN/NofX+fo9fhSRN9vGgQVWzOOFiO0zcThy749pirJu1Kq5OJdthIyW
-Pu0UCz5G0k3kTp0JPevGlsNc8S9Ak1tFuB0IPJjrbfODWHS2LDuO+dB6gpkNTdrj
-88ogYtBsN4D5gsXBRUfobXokUwejBwLrD6XwyQx+0bMwSCxgHEhxvuUkx1vdlXGw
-JG3aF92u8mIxoKSAPaPdqy930mQvmpUWcN5Y1IMbtEGoQCKMYgosFcazJpJcjnX1
-o4Hl/lqjwCEG
+qQvaQJUCAwEAAaOBkjCBjzAdBgNVHQ4EFgQU7vPH9R8VpU1HicHTImOy36fOvVEw
+YwYDVR0jBFwwWoAUtFrkpbPe0lL2udWmlQ/rPrzH/f+hP6Q9MDsxCzAJBgNVBAYT
+Ak5MMREwDwYDVQQKDAhQb2xhclNTTDEZMBcGA1UEAwwQUG9sYXJTU0wgVGVzdCBD
+QYIBAzAJBgNVHRMEAjAAMBMGCSqGSIb3DQEBCjAGogQCAgDqA4IBAQC2DLHQ05x6
+imJNztE/Tnk/lPQ01Pw6Girdbk4bgxcGwGj+1u5wAIHNpJ50TOggg3HxTyb7p344
+/tVMxz7nrHZQ5ASdn2kDCyCmEqhmj48isWAIml+7J9cBeImJoEfYqjtqtoVkGxFy
+SuoZAQWkkqDpyFhKhIjLQ8JuSE6wWMX/kc6TFSSxepnZU1SFOXfCiaVr5tFQzBP7
+loppIANLjKeMjpOdU86PmRQ2LyzaCH1OMnjVndeqNmZt0NyzZ18cFPvm6+DVVVuP
+Q+6nReShCdAlU+dJqsqj8JsQneNMTxjv4OBoXVmE/kZTj/DBTtwmxkVi7K4aYMFi
+UYUZ4RiwG1/7
 -----END CERTIFICATE-----
-Certificate:
-    Data:
-        Version: 3 (0x2)
-        Serial Number: 0 (0x0)
-        Signature Algorithm: sha1WithRSAEncryption
-        Issuer: C=NL, O=PolarSSL, CN=PolarSSL Test CA
-        Validity
-            Not Before: Feb 12 14:44:00 2011 GMT
-            Not After : Feb 12 14:44:00 2021 GMT
-        Subject: C=NL, O=PolarSSL, CN=PolarSSL Test CA
-        Subject Public Key Info:
-            Public Key Algorithm: rsaEncryption
-            RSA Public Key: (2048 bit)
-                Modulus (2048 bit):
-                    00:c0:df:37:fc:17:bb:e0:96:9d:3f:86:de:96:32:
-                    7d:44:a5:16:a0:cd:21:f1:99:d4:ec:ea:cb:7c:18:
-                    58:08:94:a5:ec:9b:c5:8b:df:1a:1e:99:38:99:87:
-                    1e:7b:c0:8d:39:df:38:5d:70:78:07:d3:9e:d9:93:
-                    e8:b9:72:51:c5:ce:a3:30:52:a9:f2:e7:40:70:14:
-                    cb:44:a2:72:0b:c2:e5:40:f9:3e:e5:a6:0e:b3:f9:
-                    ec:4a:63:c0:b8:29:00:74:9c:57:3b:a8:a5:04:90:
-                    71:f1:bd:83:d9:3f:d6:a5:e2:3c:2a:8f:ef:27:60:
-                    c3:c6:9f:cb:ba:ec:60:7d:b7:e6:84:32:be:4f:fb:
-                    58:26:22:03:5b:d4:b4:d5:fb:f5:e3:96:2e:70:c0:
-                    e4:2e:bd:fc:2e:ee:e2:41:55:c0:34:2e:7d:24:72:
-                    69:cb:47:b1:14:40:83:7d:67:f4:86:f6:31:ab:f1:
-                    79:a4:b2:b5:2e:12:f9:84:17:f0:62:6f:27:3e:13:
-                    58:b1:54:0d:21:9a:73:37:a1:30:cf:6f:92:dc:f6:
-                    e9:fc:ac:db:2e:28:d1:7e:02:4b:23:a0:15:f2:38:
-                    65:64:09:ea:0c:6e:8e:1b:17:a0:71:c8:b3:9b:c9:
-                    ab:e9:c3:f2:cf:87:96:8f:80:02:32:9e:99:58:6f:
-                    a2:d5
-                Exponent: 65537 (0x10001)
-        X509v3 extensions:
-            X509v3 Basic Constraints: 
-                CA:TRUE
-            X509v3 Subject Key Identifier: 
-                B4:5A:E4:A5:B3:DE:D2:52:F6:B9:D5:A6:95:0F:EB:3E:BC:C7:FD:FF
-            X509v3 Authority Key Identifier: 
-                keyid:B4:5A:E4:A5:B3:DE:D2:52:F6:B9:D5:A6:95:0F:EB:3E:BC:C7:FD:FF
-                DirName:/C=NL/O=PolarSSL/CN=PolarSSL Test CA
-                serial:00
-
-    Signature Algorithm: sha1WithRSAEncryption
-        b8:fd:54:d8:00:54:90:8b:25:b0:27:dd:95:cd:a2:f7:84:07:
-        1d:87:89:4a:c4:78:11:d8:07:b5:d7:22:50:8e:48:eb:62:7a:
-        32:89:be:63:47:53:ff:b6:be:f1:2e:8c:54:c0:99:3f:a0:b9:
-        37:23:72:5f:0d:46:59:8f:d8:47:cd:97:4c:9f:07:0c:12:62:
-        09:3a:24:e4:36:d9:e9:2c:da:38:d0:73:75:61:d7:c1:6c:26:
-        8b:9b:e0:d5:dc:67:ed:8c:6b:33:d7:74:22:3c:4c:db:b5:8d:
-        2a:ce:2c:0d:08:59:05:09:05:a6:39:9f:b3:67:1b:e2:83:e5:
-        e1:8f:53:f6:67:93:c7:f9:6f:76:44:58:12:e8:3a:d4:97:e7:
-        e9:c0:3e:a8:7a:72:3d:87:53:1f:e5:2c:84:84:e7:9a:9e:7f:
-        66:d9:1f:9b:f5:13:48:b0:4d:14:d1:de:b2:24:d9:78:7d:f5:
-        35:cc:58:19:d1:d2:99:ef:4d:73:f8:1f:89:d4:5a:d0:52:ce:
-        09:f5:b1:46:51:6a:00:8e:3b:cc:6f:63:01:00:99:ed:9d:a6:
-        08:60:cd:32:18:d0:73:e0:58:71:d9:e5:d2:53:d7:8d:d0:ca:
-        e9:5d:2a:0a:0d:5d:55:ec:21:50:17:16:e6:06:4a:cd:5e:de:
-        f7:e0:e9:54
 -----BEGIN CERTIFICATE-----
-MIIDhzCCAm+gAwIBAgIBADANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER
-MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN
-MTEwMjEyMTQ0NDAwWhcNMjEwMjEyMTQ0NDAwWjA7MQswCQYDVQQGEwJOTDERMA8G
-A1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G
+MIIDRDCCAiygAwIBAgIBAzANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER
+MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN
+MTkwMjEwMTQ0NDAwWhcNMjkwMjEwMTQ0NDAwWjA7MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G
 CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3zf8F7vglp0/ht6WMn1EpRagzSHx
 mdTs6st8GFgIlKXsm8WL3xoemTiZhx57wI053zhdcHgH057Zk+i5clHFzqMwUqny
 50BwFMtEonILwuVA+T7lpg6z+exKY8C4KQB0nFc7qKUEkHHxvYPZP9al4jwqj+8n
 YMPGn8u67GB9t+aEMr5P+1gmIgNb1LTV+/Xjli5wwOQuvfwu7uJBVcA0Ln0kcmnL
 R7EUQIN9Z/SG9jGr8XmksrUuEvmEF/Bibyc+E1ixVA0hmnM3oTDPb5Lc9un8rNsu
 KNF+AksjoBXyOGVkCeoMbo4bF6BxyLObyavpw/LPh5aPgAIynplYb6LVAgMBAAGj
-gZUwgZIwDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQUtFrkpbPe0lL2udWmlQ/rPrzH
-/f8wYwYDVR0jBFwwWoAUtFrkpbPe0lL2udWmlQ/rPrzH/f+hP6Q9MDsxCzAJBgNV
-BAYTAk5MMREwDwYDVQQKEwhQb2xhclNTTDEZMBcGA1UEAxMQUG9sYXJTU0wgVGVz
-dCBDQYIBADANBgkqhkiG9w0BAQUFAAOCAQEAuP1U2ABUkIslsCfdlc2i94QHHYeJ
-SsR4EdgHtdciUI5I62J6Mom+Y0dT/7a+8S6MVMCZP6C5NyNyXw1GWY/YR82XTJ8H
-DBJiCTok5DbZ6SzaONBzdWHXwWwmi5vg1dxn7YxrM9d0IjxM27WNKs4sDQhZBQkF
-pjmfs2cb4oPl4Y9T9meTx/lvdkRYEug61Jfn6cA+qHpyPYdTH+UshITnmp5/Ztkf
-m/UTSLBNFNHesiTZeH31NcxYGdHSme9Nc/gfidRa0FLOCfWxRlFqAI47zG9jAQCZ
-7Z2mCGDNMhjQc+BYcdnl0lPXjdDK6V0qCg1dVewhUBcW5gZKzV7e9+DpVA==
+UzBRMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLRa5KWz3tJS9rnVppUP6z68
+x/3/MB8GA1UdIwQYMBaAFLRa5KWz3tJS9rnVppUP6z68x/3/MA0GCSqGSIb3DQEB
+BQUAA4IBAQCz557ZZmWv5UTTHebzTyVzku5ldpcicJPqKHP3xZ4tPPY52JQyJg/T
+hsRB44yTyNo3/jo9or2KgVnc+/nCmnlvTq22a/j26DtKZ7wD9MWxunpkqRwExtA/
+G816msrl6X6m50WwdLXTvaVJGXCYp8TPVLx5YY3WPIVoX0CPN7Hs9iNJNiEWo4Qf
+7dAqjWBB/QpusmWhjaDSc4+cFhT24Yo9HuS1yrkUTrBtJaj0AykTsiyFm6SBVDNH
+9XIxCgYy9QrYbDKNtJXhuevpN0yUMV/aUnIkU2wTTouhOzZisjNk0sS1guqmSHzf
+hlf8qotOhNvFXpEsCGwZUywayo7c4DtO
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server9.crt b/tests/data_files/server9.crt
index a6f9fbc..26567ae 100644
--- a/tests/data_files/server9.crt
+++ b/tests/data_files/server9.crt
@@ -1,19 +1,19 @@
 -----BEGIN CERTIFICATE-----
 MIIDBTCCAeegAwIBAgIBFjATBgkqhkiG9w0BAQowBqIEAgIA6jA7MQswCQYDVQQG
-EwJOTDERMA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3Qg
-Q0EwHhcNMTQwMTIwMTMzODE2WhcNMjQwMTE4MTMzODE2WjA0MQswCQYDVQQGEwJO
-TDERMA8GA1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkq
+EwJOTDERMA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3Qg
+Q0EwHhcNMjMwNTE3MDgwNDAwWhcNMzMwNTE3MDgwNDAwWjA0MQswCQYDVQQGEwJO
+TDERMA8GA1UECgwIUG9sYXJTU0wxEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkq
 hkiG9w0BAQEFAAOBjQAwgYkCgYEA3RGKn5m6sGjKKuo7am1Zl+1OyVTkDe7OoH2g
 HqroDsK7E0DbihKOiRMkpcX1+tj1kNfIysvF/pMdr9oSI3NSeUYauqBXK3YWMbOo
 r+c4mwiLY5k6CiXuRdIYWLq5kxrt1FiaYxs3/PcUCJ+FZUnzWTJt0eDobd5S7Wa0
-qQvaQJUCAwEAAaOBkjCBjzAJBgNVHRMEAjAAMB0GA1UdDgQWBBTu88f1HxWlTUeJ
-wdMiY7Lfp869UTBjBgNVHSMEXDBagBS0WuSls97SUva51aaVD+s+vMf9/6E/pD0w
-OzELMAkGA1UEBhMCTkwxETAPBgNVBAoTCFBvbGFyU1NMMRkwFwYDVQQDExBQb2xh
-clNTTCBUZXN0IENBggEAMBMGCSqGSIb3DQEBCjAGogQCAgDqA4IBAQDAog/jXydR
-vDIugTzBXtfVK0CEX8iyQ4cVzQmXWSne8204v943K5D2hktSBkjdQUdcnVvVgLR6
-te50jV89ptN/NofX+fo9fhSRN9vGgQVWzOOFiO0zcThy749pirJu1Kq5OJdthIyW
-Pu0UCz5G0k3kTp0JPevGlsNc8S9Ak1tFuB0IPJjrbfODWHS2LDuO+dB6gpkNTdrj
-88ogYtBsN4D5gsXBRUfobXokUwejBwLrD6XwyQx+0bMwSCxgHEhxvuUkx1vdlXGw
-JG3aF92u8mIxoKSAPaPdqy930mQvmpUWcN5Y1IMbtEGoQCKMYgosFcazJpJcjnX1
-o4Hl/lqjwCEG
+qQvaQJUCAwEAAaOBkjCBjzAdBgNVHQ4EFgQU7vPH9R8VpU1HicHTImOy36fOvVEw
+YwYDVR0jBFwwWoAUtFrkpbPe0lL2udWmlQ/rPrzH/f+hP6Q9MDsxCzAJBgNVBAYT
+Ak5MMREwDwYDVQQKDAhQb2xhclNTTDEZMBcGA1UEAwwQUG9sYXJTU0wgVGVzdCBD
+QYIBAzAJBgNVHRMEAjAAMBMGCSqGSIb3DQEBCjAGogQCAgDqA4IBAQC2DLHQ05x6
+imJNztE/Tnk/lPQ01Pw6Girdbk4bgxcGwGj+1u5wAIHNpJ50TOggg3HxTyb7p344
+/tVMxz7nrHZQ5ASdn2kDCyCmEqhmj48isWAIml+7J9cBeImJoEfYqjtqtoVkGxFy
+SuoZAQWkkqDpyFhKhIjLQ8JuSE6wWMX/kc6TFSSxepnZU1SFOXfCiaVr5tFQzBP7
+loppIANLjKeMjpOdU86PmRQ2LyzaCH1OMnjVndeqNmZt0NyzZ18cFPvm6+DVVVuP
+Q+6nReShCdAlU+dJqsqj8JsQneNMTxjv4OBoXVmE/kZTj/DBTtwmxkVi7K4aYMFi
+UYUZ4RiwG1/7
 -----END CERTIFICATE-----
diff --git a/tests/data_files/test-ca-v1.crt b/tests/data_files/test-ca-v1.crt
index e5a3b1c..2f10f6d 100644
--- a/tests/data_files/test-ca-v1.crt
+++ b/tests/data_files/test-ca-v1.crt
@@ -1,19 +1,19 @@
 -----BEGIN CERTIFICATE-----
-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
+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
 -----END CERTIFICATE-----
diff --git a/tests/data_files/test-ca.opensslconf b/tests/data_files/test-ca.opensslconf
index 434876c..0340e9e 100644
--- a/tests/data_files/test-ca.opensslconf
+++ b/tests/data_files/test-ca.opensslconf
@@ -41,6 +41,11 @@
 [multiple_san]
 subjectAltName=@alt_names
 
+[ext_multi_nocn]
+basicConstraints = CA:false
+keyUsage = digitalSignature, nonRepudiation, keyEncipherment
+subjectAltName = DNS:www.shotokan-braunschweig.de,DNS:www.massimo-abate.eu,IP:192.168.1.1,IP:192.168.69.144
+
 [hw_module_name]
 hwtype = OID:1.3.6.1.4.1.17.3
 hwserial = OCT:123456
diff --git a/tests/data_files/test-ca2.ku-crl.crt b/tests/data_files/test-ca2.ku-crl.crt
index 4fb4083..303a2c0 100644
--- a/tests/data_files/test-ca2.ku-crl.crt
+++ b/tests/data_files/test-ca2.ku-crl.crt
@@ -1,12 +1,12 @@
 -----BEGIN CERTIFICATE-----
-MIIBzDCCAVOgAwIBAgIJAP6mZLzh0IPSMAoGCCqGSM49BAMCMD4xCzAJBgNVBAYT
-Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF
-QyBDQTAeFw0xNDA0MDkxMTIzMzhaFw0yNDA0MDYxMTIzMzhaMD4xCzAJBgNVBAYT
-Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF
-QyBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMPaKzRBN1gvh1b+/Im6KUNLTuBu
-ww5XUzM5WNRStJGVOQsj318XJGJI/BqVKc4sLYfCiFKAr9ZqqyHduNMcbli4yuiy
-aY7zQa0pw7RfdadHb9UZKVVpmlM7ILRmFmAzHqMdMBswDAYDVR0TBAUwAwEB/zAL
-BgNVHQ8EBAMCAQIwCgYIKoZIzj0EAwIDZwAwZAIwZOCKY0EHXYzI4cQsFnfOrxm1
-ufvNeZ4ZcSZWrkTBazW2OBCuCP9SLznec3SFOUvvAjAKe/qycfxkHivjieCEG1Kt
-m2D4QKSJELUhTHr4zdkeqbzgui0y3iouaoyWsKvetNg=
+MIIB2DCCAV6gAwIBAgIUN3DAVq0Kn9k3FPUPZGW2d3rZn28wCgYIKoZIzj0EAwIw
+PjELMAkGA1UEBhMCTkwxETAPBgNVBAoMCFBvbGFyU1NMMRwwGgYDVQQDDBNQb2xh
+cnNzbCBUZXN0IEVDIENBMB4XDTIzMDUxNzA3MTAzN1oXDTMzMDUxNzA3MTAzN1ow
+PjELMAkGA1UEBhMCTkwxETAPBgNVBAoMCFBvbGFyU1NMMRwwGgYDVQQDDBNQb2xh
+cnNzbCBUZXN0IEVDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEw9orNEE3WC+H
+Vv78ibopQ0tO4G7DDldTMzlY1FK0kZU5CyPfXxckYkj8GpUpziwth8KIUoCv1mqr
+Id240xxuWLjK6LJpjvNBrSnDtF91p0dv1RkpVWmaUzsgtGYWYDMeox0wGzAMBgNV
+HRMEBTADAQH/MAsGA1UdDwQEAwIBAjAKBggqhkjOPQQDAgNoADBlAjAxoq/Q4PEA
+8SDd3cQaVIwx8oJVEzfJo1BB2w1LnjvUXZrQydjNXMU4Jgorm/2/uLgCMQCyI6cZ
+EAIgKPYlT6/zJHBj45qejs527OfI4Xn+kQ7OvHQtHaCAzQw4h7Jfx+gXaUo=
 -----END CERTIFICATE-----
diff --git a/tests/data_files/test-ca2.ku-crl.crt.openssl.v3_ext b/tests/data_files/test-ca2.ku-crl.crt.openssl.v3_ext
new file mode 100644
index 0000000..4bc5d3c
--- /dev/null
+++ b/tests/data_files/test-ca2.ku-crl.crt.openssl.v3_ext
@@ -0,0 +1,4 @@
+basicConstraints = CA:true
+subjectKeyIdentifier=none
+keyUsage = cRLSign
+
diff --git a/tests/data_files/test-ca2.ku-crt.crt b/tests/data_files/test-ca2.ku-crt.crt
index edacc64..5cad7b2 100644
--- a/tests/data_files/test-ca2.ku-crt.crt
+++ b/tests/data_files/test-ca2.ku-crt.crt
@@ -1,12 +1,12 @@
 -----BEGIN CERTIFICATE-----
-MIIBzTCCAVOgAwIBAgIJAODh6PAeD9/vMAoGCCqGSM49BAMCMD4xCzAJBgNVBAYT
-Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF
-QyBDQTAeFw0xNDA0MDkxMTIzNTRaFw0yNDA0MDYxMTIzNTRaMD4xCzAJBgNVBAYT
-Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF
-QyBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMPaKzRBN1gvh1b+/Im6KUNLTuBu
-ww5XUzM5WNRStJGVOQsj318XJGJI/BqVKc4sLYfCiFKAr9ZqqyHduNMcbli4yuiy
-aY7zQa0pw7RfdadHb9UZKVVpmlM7ILRmFmAzHqMdMBswDAYDVR0TBAUwAwEB/zAL
-BgNVHQ8EBAMCAgQwCgYIKoZIzj0EAwIDaAAwZQIwGGlbynd1jU3WkUx6Irhk9Lob
-z2B+1eIO6+eu3En8B3rh8Ipfxo0e0hpfaRFYP1MUAjEAjxxBchRWJAzZ6/47Wg/7
-UoasRINgP5B/uJhTnftS1bqyuWHastb4LW5/YLOvPbMQ
+MIIB2DCCAV6gAwIBAgIUYDcYIJ6EBbKafKeXLgPLE+RsJZowCgYIKoZIzj0EAwIw
+PjELMAkGA1UEBhMCTkwxETAPBgNVBAoMCFBvbGFyU1NMMRwwGgYDVQQDDBNQb2xh
+cnNzbCBUZXN0IEVDIENBMB4XDTIzMDUxMjEwMzEwNVoXDTMzMDUxMjEwMzEwNVow
+PjELMAkGA1UEBhMCTkwxETAPBgNVBAoMCFBvbGFyU1NMMRwwGgYDVQQDDBNQb2xh
+cnNzbCBUZXN0IEVDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEw9orNEE3WC+H
+Vv78ibopQ0tO4G7DDldTMzlY1FK0kZU5CyPfXxckYkj8GpUpziwth8KIUoCv1mqr
+Id240xxuWLjK6LJpjvNBrSnDtF91p0dv1RkpVWmaUzsgtGYWYDMeox0wGzAMBgNV
+HRMEBTADAQH/MAsGA1UdDwQEAwICBDAKBggqhkjOPQQDAgNoADBlAjBwsfyYiZB6
+PpDgIbYRbZ4VT9GGFNE3L4C1IH8RNwzvywLvQfVp3ocRAkzEoRpmKAsCMQDOGm48
+d7zKl7IzmBuOWXYlukWDDWwpNI67z7g0JawfypKIxcPTZFiQXVtDdTdkrGY=
 -----END CERTIFICATE-----
diff --git a/tests/data_files/test-ca2.ku-crt.crt.openssl.v3_ext b/tests/data_files/test-ca2.ku-crt.crt.openssl.v3_ext
new file mode 100644
index 0000000..997c893
--- /dev/null
+++ b/tests/data_files/test-ca2.ku-crt.crt.openssl.v3_ext
@@ -0,0 +1,4 @@
+basicConstraints = CA:true
+subjectKeyIdentifier=none
+keyUsage = keyCertSign
+
diff --git a/tests/data_files/test-ca2.ku-crt_crl.crt b/tests/data_files/test-ca2.ku-crt_crl.crt
index ac74e40..4c69582 100644
--- a/tests/data_files/test-ca2.ku-crt_crl.crt
+++ b/tests/data_files/test-ca2.ku-crt_crl.crt
@@ -1,12 +1,12 @@
 -----BEGIN CERTIFICATE-----
-MIIBzDCCAVOgAwIBAgIJAPejOupCJS65MAoGCCqGSM49BAMCMD4xCzAJBgNVBAYT
-Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF
-QyBDQTAeFw0xNDA0MDkxMTIyMjVaFw0yNDA0MDYxMTIyMjVaMD4xCzAJBgNVBAYT
-Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF
-QyBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMPaKzRBN1gvh1b+/Im6KUNLTuBu
-ww5XUzM5WNRStJGVOQsj318XJGJI/BqVKc4sLYfCiFKAr9ZqqyHduNMcbli4yuiy
-aY7zQa0pw7RfdadHb9UZKVVpmlM7ILRmFmAzHqMdMBswDAYDVR0TBAUwAwEB/zAL
-BgNVHQ8EBAMCAQYwCgYIKoZIzj0EAwIDZwAwZAIwMKLVXB4YBQ0Ha4dEvFPcJtau
-TS5Vd4UqG3xQ10YcJogweuqaGHSFgdnEUfoX+4p5AjApMnYXFfUjSmlyfJmTaswO
-gaR5sUnnw33NA9j1ercem3asCYz6a8T0zo8/rR33XVU=
+MIIB2TCCAV6gAwIBAgIUd5f42F4ahjkx9AIN035pcF4WFikwCgYIKoZIzj0EAwIw
+PjELMAkGA1UEBhMCTkwxETAPBgNVBAoMCFBvbGFyU1NMMRwwGgYDVQQDDBNQb2xh
+cnNzbCBUZXN0IEVDIENBMB4XDTIzMDUxNzA3MTAzN1oXDTMzMDUxNzA3MTAzN1ow
+PjELMAkGA1UEBhMCTkwxETAPBgNVBAoMCFBvbGFyU1NMMRwwGgYDVQQDDBNQb2xh
+cnNzbCBUZXN0IEVDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEw9orNEE3WC+H
+Vv78ibopQ0tO4G7DDldTMzlY1FK0kZU5CyPfXxckYkj8GpUpziwth8KIUoCv1mqr
+Id240xxuWLjK6LJpjvNBrSnDtF91p0dv1RkpVWmaUzsgtGYWYDMeox0wGzAMBgNV
+HRMEBTADAQH/MAsGA1UdDwQEAwIBBjAKBggqhkjOPQQDAgNpADBmAjEA6IUvQwSw
+vEkHjU9YNsPcUsJf0UTHUW1T8mNbgk+zCl6fzeU73oCXH6zoi5q6vLgjAjEAv63C
+xknmJJ4H3Zlc+O5GlcX9VQNZDn1xV7hf2yW1Gf7wLTnSWTf5bXATaIQ6QLO1
 -----END CERTIFICATE-----
diff --git a/tests/data_files/test-ca2.ku-crt_crl.crt.openssl.v3_ext b/tests/data_files/test-ca2.ku-crt_crl.crt.openssl.v3_ext
new file mode 100644
index 0000000..0fd73a2
--- /dev/null
+++ b/tests/data_files/test-ca2.ku-crt_crl.crt.openssl.v3_ext
@@ -0,0 +1,4 @@
+basicConstraints = CA:true
+subjectKeyIdentifier=none
+keyUsage = keyCertSign, cRLSign
+
diff --git a/tests/data_files/test-ca2.ku-ds.crt b/tests/data_files/test-ca2.ku-ds.crt
index c28e17b..2907aa7 100644
--- a/tests/data_files/test-ca2.ku-ds.crt
+++ b/tests/data_files/test-ca2.ku-ds.crt
@@ -1,12 +1,12 @@
 -----BEGIN CERTIFICATE-----
-MIIBzDCCAVOgAwIBAgIJAPOkPR3wsvm5MAoGCCqGSM49BAMCMD4xCzAJBgNVBAYT
-Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF
-QyBDQTAeFw0xNDA0MDkxMTI0MTNaFw0yNDA0MDYxMTI0MTNaMD4xCzAJBgNVBAYT
-Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF
-QyBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMPaKzRBN1gvh1b+/Im6KUNLTuBu
-ww5XUzM5WNRStJGVOQsj318XJGJI/BqVKc4sLYfCiFKAr9ZqqyHduNMcbli4yuiy
-aY7zQa0pw7RfdadHb9UZKVVpmlM7ILRmFmAzHqMdMBswDAYDVR0TBAUwAwEB/zAL
-BgNVHQ8EBAMCB4AwCgYIKoZIzj0EAwIDZwAwZAIwGRCmU/rWNjW13g8ITuq3pMXb
-jgwTFJHVlbMDiFJwUrRvytPV9doJOfzJ8nAQ0cZ1AjAbJ8QAV2e+DmYZpWc/p6Ug
-nQdac59ev+lH+ju6wET3jNDjUthUPrdgqa54+UWQ5r4=
+MIIB2TCCAV6gAwIBAgIUb5xsO6FEmAz+XpGFHpW7ODFvup0wCgYIKoZIzj0EAwIw
+PjELMAkGA1UEBhMCTkwxETAPBgNVBAoMCFBvbGFyU1NMMRwwGgYDVQQDDBNQb2xh
+cnNzbCBUZXN0IEVDIENBMB4XDTIzMDUxNzA3MTAzN1oXDTMzMDUxNzA3MTAzN1ow
+PjELMAkGA1UEBhMCTkwxETAPBgNVBAoMCFBvbGFyU1NMMRwwGgYDVQQDDBNQb2xh
+cnNzbCBUZXN0IEVDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEw9orNEE3WC+H
+Vv78ibopQ0tO4G7DDldTMzlY1FK0kZU5CyPfXxckYkj8GpUpziwth8KIUoCv1mqr
+Id240xxuWLjK6LJpjvNBrSnDtF91p0dv1RkpVWmaUzsgtGYWYDMeox0wGzAMBgNV
+HRMEBTADAQH/MAsGA1UdDwQEAwIHgDAKBggqhkjOPQQDAgNpADBmAjEA44HVvGYv
+meA3SpaNJmubLKjsQlGNnEUUo1IO0NBP5yWG0dRFkX8NQ0bzH/1n6FJcAjEAm9wj
+xdmEPUr6PY54c0IQJNeeF76L1/+EszXrSDQ7TLv1YC4d4uMNmqwR9EGuUX+/
 -----END CERTIFICATE-----
diff --git a/tests/data_files/test-ca2.ku-ds.crt.openssl.v3_ext b/tests/data_files/test-ca2.ku-ds.crt.openssl.v3_ext
new file mode 100644
index 0000000..08e49d4
--- /dev/null
+++ b/tests/data_files/test-ca2.ku-ds.crt.openssl.v3_ext
@@ -0,0 +1,4 @@
+basicConstraints = CA:true
+subjectKeyIdentifier=none
+keyUsage = digitalSignature
+
diff --git a/tests/include/test/drivers/config_test_driver.h b/tests/include/test/drivers/config_test_driver.h
index 2585fd9..81f9883 100644
--- a/tests/include/test/drivers/config_test_driver.h
+++ b/tests/include/test/drivers/config_test_driver.h
@@ -53,7 +53,4 @@
 //#define MBEDTLS_PEM_PARSE_C
 //#define MBEDTLS_BASE64_C
 
-#include "mbedtls/config_psa.h"
-#include "mbedtls/check_config.h"
-
 #endif /* MBEDTLS_CONFIG_H */
diff --git a/tests/include/test/macros.h b/tests/include/test/macros.h
index eb3bcb8..7edc991 100644
--- a/tests/include/test/macros.h
+++ b/tests/include/test/macros.h
@@ -61,6 +61,16 @@
         }                                                    \
     } while (0)
 
+/** This macro asserts fails the test with given output message.
+ *
+ * \param   MESSAGE The message to be outputed on assertion
+ */
+#define TEST_FAIL(MESSAGE)                           \
+    do {                                                  \
+        mbedtls_test_fail(MESSAGE, __LINE__, __FILE__);   \
+        goto exit;                                        \
+    } while (0)
+
 /** Evaluate two integer expressions and fail the test case if they have
  * different values.
  *
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 386a949..c3c1275 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -192,6 +192,10 @@
     # default to -O2, use -Ox _after_ this if you want another level
     ASAN_CFLAGS='-O2 -Werror -fsanitize=address,undefined -fno-sanitize-recover=all'
 
+    # Platform tests have an allocation that returns null
+    export ASAN_OPTIONS="allocator_may_return_null=1"
+    export MSAN_OPTIONS="allocator_may_return_null=1"
+
     # Gather the list of available components. These are the functions
     # defined in this script whose name starts with "component_".
     ALL_COMPONENTS=$(compgen -A function component_ | sed 's/component_//')
@@ -1507,30 +1511,6 @@
     make test
 }
 
-component_test_crypto_full_no_cipher () {
-    msg "build: crypto_full minus CIPHER"
-    scripts/config.py crypto_full
-    scripts/config.py unset MBEDTLS_CIPHER_C
-    # Direct dependencies
-    scripts/config.py unset MBEDTLS_CCM_C
-    scripts/config.py unset MBEDTLS_CMAC_C
-    scripts/config.py unset MBEDTLS_GCM_C
-    scripts/config.py unset MBEDTLS_NIST_KW_C
-    scripts/config.py unset MBEDTLS_PKCS12_C
-    scripts/config.py unset MBEDTLS_PKCS5_C
-    scripts/config.py unset MBEDTLS_PSA_CRYPTO_C
-    # Indirect dependencies
-    scripts/config.py unset MBEDTLS_PSA_CRYPTO_SE_C
-    scripts/config.py unset MBEDTLS_PSA_CRYPTO_STORAGE_C
-    scripts/config.py unset MBEDTLS_USE_PSA_CRYPTO
-    scripts/config.py unset MBEDTLS_LMS_C
-    scripts/config.py unset MBEDTLS_LMS_PRIVATE
-    make
-
-    msg "test: crypto_full minus CIPHER"
-    make test
-}
-
 component_test_full_no_bignum () {
     msg "build: full minus bignum"
     scripts/config.py full
@@ -1796,9 +1776,7 @@
     scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
     scripts/config.py unset MBEDTLS_ECJPAKE_C
     # Disable all curves
-    for c in $(sed -n 's/#define \(MBEDTLS_ECP_DP_[0-9A-Z_a-z]*_ENABLED\).*/\1/p' <"$CONFIG_H"); do
-        scripts/config.py unset "$c"
-    done
+    scripts/config.py unset-all "MBEDTLS_ECP_DP_[0-9A-Z_a-z]*_ENABLED"
     scripts/config.py set MBEDTLS_ECP_DP_CURVE25519_ENABLED
 
     make CFLAGS="$ASAN_CFLAGS -O2" LDFLAGS="$ASAN_CFLAGS"
@@ -1894,6 +1872,16 @@
     export SKIP_TEST_SUITES
 }
 
+skip_all_except_given_suite () {
+    # Skip all but the given test suite
+    SKIP_TEST_SUITES=$(
+        ls -1 tests/suites/test_suite_*.function |
+        grep -v $1.function |
+         sed 's/tests.suites.test_suite_//; s/\.function$//' |
+        tr '\n' ,)
+    export SKIP_TEST_SUITES
+}
+
 component_test_memsan_constant_flow () {
     # This tests both (1) accesses to undefined memory, and (2) branches or
     # memory access depending on secret values. To distinguish between those:
@@ -1953,6 +1941,16 @@
     # details are left in Testing/<date>/DynamicAnalysis.xml
     msg "test: some suites (full minus MBEDTLS_USE_PSA_CRYPTO, valgrind + constant flow)"
     make memcheck
+
+    # Test asm path in constant time module - by default, it will test the plain C
+    # path under Valgrind or Memsan. Running only the constant_time tests is fast (<1s)
+    msg "test: valgrind asm constant_time"
+    scripts/config.py --force set MBEDTLS_TEST_CONSTANT_FLOW_ASM
+    skip_all_except_given_suite test_suite_constant_time
+    cmake -D CMAKE_BUILD_TYPE:String=Release .
+    make clean
+    make
+    make memcheck
 }
 
 component_test_valgrind_constant_flow_psa () {
@@ -2559,8 +2557,6 @@
     # start with full config for maximum coverage (also enables USE_PSA)
     helper_libtestdriver1_adjust_config "full"
 
-    # enable support for drivers and configuring PSA-only algorithms
-    scripts/config.py set MBEDTLS_PSA_CRYPTO_CONFIG
     if [ "$DRIVER_ONLY" -eq 1 ]; then
         # Disable modules that are accelerated
         scripts/config.py unset MBEDTLS_ECDSA_C
@@ -2650,6 +2646,138 @@
     tests/ssl-opt.sh
 }
 
+# This function is really similar to config_psa_crypto_no_ecp_at_all() above so
+# its description is basically the same. The main difference in this case is
+# that when the EC built-in implementation is disabled, then also Bignum module
+# and its dependencies are disabled as well.
+#
+# This is the common helper between:
+# - component_test_psa_crypto_config_accel_ecc_no_bignum
+# - component_test_psa_crypto_config_reference_ecc_no_bignum
+config_psa_crypto_config_accel_ecc_no_bignum() {
+    DRIVER_ONLY="$1"
+    # start with full config for maximum coverage (also enables USE_PSA)
+    helper_libtestdriver1_adjust_config "full"
+
+    if [ "$DRIVER_ONLY" -eq 1 ]; then
+        # Disable modules that are accelerated
+        scripts/config.py unset MBEDTLS_ECDSA_C
+        scripts/config.py unset MBEDTLS_ECDH_C
+        scripts/config.py unset MBEDTLS_ECJPAKE_C
+        # Disable ECP module (entirely)
+        scripts/config.py unset MBEDTLS_ECP_C
+        # Also disable bignum
+        scripts/config.py unset MBEDTLS_BIGNUM_C
+    fi
+
+    # Disable all the features that auto-enable ECP_LIGHT (see build_info.h)
+    scripts/config.py unset MBEDTLS_PK_PARSE_EC_EXTENDED
+    scripts/config.py unset MBEDTLS_PK_PARSE_EC_COMPRESSED
+    scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE
+
+    # RSA support is intentionally disabled on this test because RSA_C depends
+    # on BIGNUM_C.
+    scripts/config.py -f "$CRYPTO_CONFIG_H" unset-all "PSA_WANT_KEY_TYPE_RSA_[0-9A-Z_a-z]*"
+    scripts/config.py -f "$CRYPTO_CONFIG_H" unset-all "PSA_WANT_ALG_RSA_[0-9A-Z_a-z]*"
+    scripts/config.py unset MBEDTLS_RSA_C
+    scripts/config.py unset MBEDTLS_PKCS1_V15
+    scripts/config.py unset MBEDTLS_PKCS1_V21
+    scripts/config.py unset MBEDTLS_X509_RSASSA_PSS_SUPPORT
+    # Also disable key exchanges that depend on RSA
+    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED
+    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
+    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED
+    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED
+    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED
+
+    # Disable FFDH because it also depends on BIGNUM.
+    scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_FFDH
+    scripts/config.py -f "$CRYPTO_CONFIG_H" unset-all "PSA_WANT_KEY_TYPE_DH_[0-9A-Z_a-z]*"
+    scripts/config.py unset MBEDTLS_DHM_C
+    # Also disable key exchanges that depend on FFDH
+    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED
+    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED
+
+    # Restartable feature is not yet supported by PSA. Once it will in
+    # the future, the following line could be removed (see issues
+    # 6061, 6332 and following ones)
+    scripts/config.py unset MBEDTLS_ECP_RESTARTABLE
+}
+
+# Build and test a configuration where driver accelerates all EC algs while
+# all support and dependencies from ECP and ECP_LIGHT are removed on the library
+# side.
+#
+# Keep in sync with component_test_psa_crypto_config_reference_ecc_no_bignum()
+component_test_psa_crypto_config_accel_ecc_no_bignum () {
+    msg "build: full + accelerated EC algs + USE_PSA - ECP - BIGNUM"
+
+    # Algorithms and key types to accelerate
+    loc_accel_list="ALG_ECDSA ALG_DETERMINISTIC_ECDSA \
+                    ALG_ECDH \
+                    ALG_JPAKE \
+                    KEY_TYPE_ECC_KEY_PAIR_BASIC \
+                    KEY_TYPE_ECC_KEY_PAIR_IMPORT \
+                    KEY_TYPE_ECC_KEY_PAIR_EXPORT \
+                    KEY_TYPE_ECC_KEY_PAIR_GENERATE \
+                    KEY_TYPE_ECC_PUBLIC_KEY"
+
+    # Configure
+    # ---------
+
+    # Set common configurations between library's and driver's builds
+    config_psa_crypto_config_accel_ecc_no_bignum 1
+
+    # Build
+    # -----
+
+    # Things we wanted supported in libtestdriver1, but not accelerated in the main library:
+    # SHA-1 and all SHA-2 variants, as they are used by ECDSA deterministic.
+    loc_extra_list="ALG_SHA_1 ALG_SHA_224 ALG_SHA_256 ALG_SHA_384 ALG_SHA_512"
+
+    helper_libtestdriver1_make_drivers "$loc_accel_list" "$loc_extra_list"
+
+    helper_libtestdriver1_make_main "$loc_accel_list"
+
+    # Make sure any built-in EC alg was not re-enabled by accident (additive config)
+    not grep mbedtls_ecdsa_ library/ecdsa.o
+    not grep mbedtls_ecdh_ library/ecdh.o
+    not grep mbedtls_ecjpake_ library/ecjpake.o
+    # Also ensure that ECP, RSA, DHM or BIGNUM modules were not re-enabled
+    not grep mbedtls_ecp_ library/ecp.o
+    not grep mbedtls_rsa_ library/rsa.o
+    not grep mbedtls_dhm_ library/dhm.o
+    not grep mbedtls_mpi_ library/bignum.o
+
+    # Run the tests
+    # -------------
+
+    msg "test suites: full + accelerated EC algs + USE_PSA - ECP - BIGNUM"
+    make test
+
+    # The following will be enabled in #7756
+    msg "ssl-opt: full + accelerated EC algs + USE_PSA - ECP - BIGNUM"
+    tests/ssl-opt.sh
+}
+
+# Reference function used for driver's coverage analysis in analyze_outcomes.py
+# in conjunction with component_test_psa_crypto_config_accel_ecc_no_bignum().
+# Keep in sync with its accelerated counterpart.
+component_test_psa_crypto_config_reference_ecc_no_bignum () {
+    msg "build: full + non accelerated EC algs + USE_PSA"
+
+    config_psa_crypto_config_accel_ecc_no_bignum 0
+
+    make
+
+    msg "test suites: full + non accelerated EC algs + USE_PSA"
+    make test
+
+    # The following will be enabled in #7756
+    msg "ssl-opt: full + non accelerated EC algs + USE_PSA"
+    tests/ssl-opt.sh
+}
+
 # Helper function used in:
 # - component_test_psa_crypto_config_accel_all_curves_except_p192
 # - component_test_psa_crypto_config_accel_all_curves_except_x25519
@@ -2691,14 +2819,8 @@
     scripts/config.py unset MBEDTLS_PKCS1_V21
     scripts/config.py unset MBEDTLS_X509_RSASSA_PSS_SUPPORT
     # Disable RSA on the PSA side too
-    scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC
-    scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT
-    scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_EXPORT
-    scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE
-    scripts/config.py -f "$CRYPTO_CONFIG_H" unset PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY
-    for ALG in $(sed -n 's/^#define \(PSA_WANT_ALG_RSA_[0-9A-Z_a-z]*\).*/\1/p' <"$CRYPTO_CONFIG_H"); do
-        scripts/config.py -f "$CRYPTO_CONFIG_H" unset $ALG
-    done
+    scripts/config.py -f "$CRYPTO_CONFIG_H" unset-all "PSA_WANT_KEY_TYPE_RSA_[0-9A-Z_a-z]*"
+    scripts/config.py -f "$CRYPTO_CONFIG_H" unset-all "PSA_WANT_ALG_RSA_[0-9A-Z_a-z]*"
     # Also disable key exchanges that depend on RSA
     scripts/config.py unset MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED
     scripts/config.py unset MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
@@ -2707,9 +2829,7 @@
     scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED
 
     # Explicitly disable all SW implementation for elliptic curves
-    for CURVE in $(sed -n 's/#define \(MBEDTLS_ECP_DP_[0-9A-Z_a-z]*_ENABLED\).*/\1/p' <"$CONFIG_H"); do
-        scripts/config.py unset "$CURVE"
-    done
+    scripts/config.py unset-all "MBEDTLS_ECP_DP_[0-9A-Z_a-z]*_ENABLED"
     # Just leave SW implementation for the specified curve for allowing to
     # build with ECP_C.
     scripts/config.py set $BUILTIN_CURVE
@@ -3854,7 +3974,7 @@
     # We can only grep /proc/cpuinfo on Linux, so this also checks for Linux
     (gcc -v 2>&1 | grep Target | grep -q x86_64) &&
         [[ "$HOSTTYPE" == "x86_64" && "$OSTYPE" == "linux-gnu" ]] &&
-        (grep '^flags' /proc/cpuinfo | grep -qw aes)
+        (lscpu | grep -qw aes)
 }
 
 component_test_aesni () { # ~ 60s
@@ -3867,29 +3987,136 @@
 
     msg "build: default config with different AES implementations"
     scripts/config.py set MBEDTLS_AESNI_C
+    scripts/config.py unset MBEDTLS_AES_USE_HARDWARE_ONLY
     scripts/config.py set MBEDTLS_HAVE_ASM
 
     # test the intrinsics implementation
     msg "AES tests, test intrinsics"
     make clean
-    make test programs/test/selftest CC=gcc CFLAGS='-Werror -Wall -Wextra -mpclmul -msse2 -maes'
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -mpclmul -msse2 -maes'
     # check that we built intrinsics - this should be used by default when supported by the compiler
-    ./programs/test/selftest | grep "AESNI code" | grep -q "intrinsics"
+    ./programs/test/selftest aes | grep "AESNI code" | grep -q "intrinsics"
 
     # test the asm implementation
     msg "AES tests, test assembly"
     make clean
-    make test programs/test/selftest CC=gcc CFLAGS='-Werror -Wall -Wextra -mno-pclmul -mno-sse2 -mno-aes'
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -mno-pclmul -mno-sse2 -mno-aes'
     # check that we built assembly - this should be built if the compiler does not support intrinsics
-    ./programs/test/selftest | grep "AESNI code" | grep -q "assembly"
+    ./programs/test/selftest aes | grep "AESNI code" | grep -q "assembly"
 
     # test the plain C implementation
     scripts/config.py unset MBEDTLS_AESNI_C
+    scripts/config.py unset MBEDTLS_AES_USE_HARDWARE_ONLY
     msg "AES tests, plain C"
     make clean
-    make test programs/test/selftest CC=gcc CFLAGS='-O2 -Werror'
+    make CC=gcc CFLAGS='-O2 -Werror'
     # check that there is no AESNI code present
-    ./programs/test/selftest | not grep -q "AESNI code"
+    ./programs/test/selftest aes | not grep -q "AESNI code"
+    not grep -q "AES note: using AESNI" ./programs/test/selftest
+    grep -q "AES note: built-in implementation." ./programs/test/selftest
+
+    # test the intrinsics implementation
+    scripts/config.py set MBEDTLS_AESNI_C
+    scripts/config.py set MBEDTLS_AES_USE_HARDWARE_ONLY
+    msg "AES tests, test AESNI only"
+    make clean
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -mpclmul -msse2 -maes'
+    ./programs/test/selftest aes | grep -q "AES note: using AESNI"
+    ./programs/test/selftest aes | not grep -q "AES note: built-in implementation."
+    grep -q "AES note: using AESNI" ./programs/test/selftest
+    not grep -q "AES note: built-in implementation." ./programs/test/selftest
+}
+
+
+
+support_test_aesni_m32() {
+    support_test_m32_o0 && (lscpu | grep -qw aes)
+}
+
+component_test_aesni_m32 () { # ~ 60s
+    # This tests are duplicated from component_test_aesni for i386 target
+    #
+    # AESNI intrinsic code supports i386 and assembly code does not support it.
+
+    msg "build: default config with different AES implementations"
+    scripts/config.py set MBEDTLS_AESNI_C
+    scripts/config.py set MBEDTLS_PADLOCK_C
+    scripts/config.py unset MBEDTLS_AES_USE_HARDWARE_ONLY
+    scripts/config.py set MBEDTLS_HAVE_ASM
+
+    # test the intrinsics implementation
+    msg "AES tests, test intrinsics"
+    make clean
+    make CC=gcc CFLAGS='-m32 -Werror -Wall -Wextra -mpclmul -msse2 -maes' LDFLAGS='-m32'
+    # check that we built intrinsics - this should be used by default when supported by the compiler
+    ./programs/test/selftest aes | grep "AESNI code" | grep -q "intrinsics"
+    grep -q "AES note: using AESNI" ./programs/test/selftest
+    grep -q "AES note: built-in implementation." ./programs/test/selftest
+    grep -q "AES note: using VIA Padlock" ./programs/test/selftest
+    grep -q mbedtls_aesni_has_support ./programs/test/selftest
+
+    scripts/config.py set MBEDTLS_AESNI_C
+    scripts/config.py unset MBEDTLS_PADLOCK_C
+    scripts/config.py set MBEDTLS_AES_USE_HARDWARE_ONLY
+    msg "AES tests, test AESNI only"
+    make clean
+    make CC=gcc CFLAGS='-m32 -Werror -Wall -Wextra -mpclmul -msse2 -maes' LDFLAGS='-m32'
+    ./programs/test/selftest aes | grep -q "AES note: using AESNI"
+    ./programs/test/selftest aes | not grep -q "AES note: built-in implementation."
+    grep -q "AES note: using AESNI" ./programs/test/selftest
+    not grep -q "AES note: built-in implementation." ./programs/test/selftest
+    not grep -q "AES note: using VIA Padlock" ./programs/test/selftest
+    not grep -q mbedtls_aesni_has_support ./programs/test/selftest
+}
+
+# For timebeing, no aarch64 gcc available in CI and no arm64 CI node.
+component_build_aes_aesce_armcc () {
+    msg "Build: AESCE test on arm64 platform without plain C."
+    scripts/config.py baremetal
+
+    # armc[56] don't support SHA-512 intrinsics
+    scripts/config.py unset MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT
+
+    # Stop armclang warning about feature detection for A64_CRYPTO.
+    # With this enabled, the library does build correctly under armclang,
+    # but in baremetal builds (as tested here), feature detection is
+    # unavailable, and the user is notified via a #warning. So enabling
+    # this feature would prevent us from building with -Werror on
+    # armclang. Tracked in #7198.
+    scripts/config.py unset MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT
+    scripts/config.py set MBEDTLS_HAVE_ASM
+
+    msg "AESCE, build with default configuration."
+    scripts/config.py set MBEDTLS_AESCE_C
+    scripts/config.py unset MBEDTLS_AES_USE_HARDWARE_ONLY
+    armc6_build_test "-O1 --target=aarch64-arm-none-eabi -march=armv8-a+crypto"
+
+    msg "AESCE, build AESCE only"
+    scripts/config.py set MBEDTLS_AESCE_C
+    scripts/config.py set MBEDTLS_AES_USE_HARDWARE_ONLY
+    armc6_build_test "-O1 --target=aarch64-arm-none-eabi -march=armv8-a+crypto"
+}
+
+# For timebeing, no VIA Padlock platform available.
+component_build_aes_via_padlock () {
+
+    msg "AES:VIA PadLock, build with default configuration."
+    scripts/config.py unset MBEDTLS_AESNI_C
+    scripts/config.py set MBEDTLS_PADLOCK_C
+    scripts/config.py unset MBEDTLS_AES_USE_HARDWARE_ONLY
+    make CC=gcc CFLAGS="$ASAN_CFLAGS -m32 -O2" LDFLAGS="-m32 $ASAN_CFLAGS"
+    grep -q mbedtls_padlock_has_support ./programs/test/selftest
+
+}
+
+support_build_aes_via_padlock_only () {
+    ( [ "$MBEDTLS_TEST_PLATFORM" == "Linux-x86_64" ] || \
+        [ "$MBEDTLS_TEST_PLATFORM" == "Linux-amd64" ] ) && \
+    [ "`dpkg --print-foreign-architectures`" == "i386" ]
+}
+
+support_build_aes_aesce_armcc () {
+    support_build_armcc
 }
 
 component_test_aes_only_128_bit_keys () {
@@ -4157,6 +4384,7 @@
     # build) and not the i386-specific inline assembly.
     msg "build: i386, make, gcc -O0 (ASan build)" # ~ 30s
     scripts/config.py full
+    scripts/config.py unset MBEDTLS_AESNI_C # AESNI depends on cpu modifiers
     make CC=gcc CFLAGS="$ASAN_CFLAGS -m32 -O0" LDFLAGS="-m32 $ASAN_CFLAGS"
 
     msg "test: i386, make, gcc -O0 (ASan build)"
@@ -4174,6 +4402,7 @@
     # and go faster for tests.
     msg "build: i386, make, gcc -O2 (ASan build)" # ~ 30s
     scripts/config.py full
+    scripts/config.py unset MBEDTLS_AESNI_C # AESNI depends on cpu modifiers
     make CC=gcc CFLAGS="$ASAN_CFLAGS -m32 -O2" LDFLAGS="-m32 $ASAN_CFLAGS"
 
     msg "test: i386, make, gcc -O2 (ASan build)"
@@ -4189,6 +4418,7 @@
 component_test_m32_everest () {
     msg "build: i386, Everest ECDH context (ASan build)" # ~ 6 min
     scripts/config.py set MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED
+    scripts/config.py unset MBEDTLS_AESNI_C # AESNI depends on cpu modifiers
     make CC=gcc CFLAGS="$ASAN_CFLAGS -m32 -O2" LDFLAGS="-m32 $ASAN_CFLAGS"
 
     msg "test: i386, Everest ECDH context - main suites (inc. selftests) (ASan build)" # ~ 50s
@@ -4642,6 +4872,7 @@
 
 component_build_mingw () {
     msg "build: Windows cross build - mingw64, make (Link Library)" # ~ 30s
+    scripts/config.py unset MBEDTLS_AESNI_C # AESNI depends on cpu modifiers
     make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 lib programs
 
     # note Make tests only builds the tests, but doesn't run them
@@ -4946,6 +5177,7 @@
     python3 -m unittest tests/scripts/translate_ciphers.py 2>&1
 }
 
+
 ################################################################
 #### Termination
 ################################################################
diff --git a/tests/scripts/analyze_outcomes.py b/tests/scripts/analyze_outcomes.py
index f3a14a9..3b91bfb 100755
--- a/tests/scripts/analyze_outcomes.py
+++ b/tests/scripts/analyze_outcomes.py
@@ -73,15 +73,22 @@
         Results.log("Error: failed to run reference/driver components")
         sys.exit(ret_val)
 
-def analyze_coverage(results, outcomes):
+def analyze_coverage(results, outcomes, allow_list, full_coverage):
     """Check that all available test cases are executed at least once."""
     available = check_test_cases.collect_available_test_cases()
     for key in available:
         hits = outcomes[key].hits() if key in outcomes else 0
-        if hits == 0:
-            # Make this a warning, not an error, as long as we haven't
-            # fixed this branch to have full coverage of test cases.
-            results.warning('Test case not executed: {}', key)
+        if hits == 0 and key not in allow_list:
+            if full_coverage:
+                results.error('Test case not executed: {}', key)
+            else:
+                results.warning('Test case not executed: {}', key)
+        elif hits != 0 and key in allow_list:
+            # Test Case should be removed from the allow list.
+            if full_coverage:
+                results.error('Allow listed test case was executed: {}', key)
+            else:
+                results.warning('Allow listed test case was executed: {}', key)
 
 def analyze_driver_vs_reference(outcomes, component_ref, component_driver,
                                 ignored_suites, ignored_test=None):
@@ -122,10 +129,11 @@
             result = False
     return result
 
-def analyze_outcomes(outcomes):
+def analyze_outcomes(outcomes, args):
     """Run all analyses on the given outcome collection."""
     results = Results()
-    analyze_coverage(results, outcomes)
+    analyze_coverage(results, outcomes, args['allow_list'],
+                     args['full_coverage'])
     return results
 
 def read_outcome_file(outcome_file):
@@ -151,10 +159,9 @@
 
 def do_analyze_coverage(outcome_file, args):
     """Perform coverage analysis."""
-    del args # unused
     outcomes = read_outcome_file(outcome_file)
     Results.log("\n*** Analyze coverage ***\n")
-    results = analyze_outcomes(outcomes)
+    results = analyze_outcomes(outcomes, args)
     return results.error_count == 0
 
 def do_analyze_driver_vs_reference(outcome_file, args):
@@ -175,8 +182,16 @@
 TASKS = {
     'analyze_coverage':                 {
         'test_function': do_analyze_coverage,
-        'args': {}
-        },
+        'args': {
+            'allow_list': [
+                # Algorithm not supported yet
+                'test_suite_psa_crypto_metadata;Asymmetric signature: pure EdDSA',
+                # Algorithm not supported yet
+                'test_suite_psa_crypto_metadata;Cipher: XTS',
+            ],
+            'full_coverage': False,
+        }
+    },
     # There are 2 options to use analyze_driver_vs_reference_xxx locally:
     # 1. Run tests and then analysis:
     #   - tests/scripts/all.sh --outcome-file "$PWD/out.csv" <component_ref> <component_driver>
@@ -310,6 +325,99 @@
             }
         }
     },
+    'analyze_driver_vs_reference_no_bignum': {
+        'test_function': do_analyze_driver_vs_reference,
+        'args': {
+            'component_ref': 'test_psa_crypto_config_reference_ecc_no_bignum',
+            'component_driver': 'test_psa_crypto_config_accel_ecc_no_bignum',
+            'ignored_suites': [
+                # Ignore test suites for the modules that are disabled in the
+                # accelerated test case.
+                'ecp',
+                'ecdsa',
+                'ecdh',
+                'ecjpake',
+                'bignum_core',
+                'bignum_random',
+                'bignum_mod',
+                'bignum_mod_raw',
+                'bignum.generated',
+                'bignum.misc',
+            ],
+            'ignored_tests': {
+                'test_suite_random': [
+                    'PSA classic wrapper: ECDSA signature (SECP256R1)',
+                ],
+                'test_suite_psa_crypto': [
+                    'PSA key derivation: HKDF-SHA-256 -> ECC secp256r1',
+                    'PSA key derivation: HKDF-SHA-256 -> ECC secp256r1 (1 redraw)',
+                    'PSA key derivation: HKDF-SHA-256 -> ECC secp256r1, exercise ECDSA',
+                    'PSA key derivation: HKDF-SHA-256 -> ECC secp384r1',
+                    'PSA key derivation: HKDF-SHA-256 -> ECC secp521r1 #0',
+                    'PSA key derivation: HKDF-SHA-256 -> ECC secp521r1 #1',
+                    'PSA key derivation: bits=7 invalid for ECC BRAINPOOL_P_R1 (ECC enabled)',
+                    'PSA key derivation: bits=7 invalid for ECC SECP_K1 (ECC enabled)',
+                    'PSA key derivation: bits=7 invalid for ECC SECP_R1 (ECC enabled)',
+                    'PSA key derivation: bits=7 invalid for ECC SECP_R2 (ECC enabled)',
+                    'PSA key derivation: bits=7 invalid for ECC SECT_K1 (ECC enabled)',
+                    'PSA key derivation: bits=7 invalid for ECC SECT_R1 (ECC enabled)',
+                    'PSA key derivation: bits=7 invalid for ECC SECT_R2 (ECC enabled)',
+                ],
+                'test_suite_pkparse': [
+                    # See the description provided above in the
+                    # analyze_driver_vs_reference_no_ecp_at_all component.
+                    'Parse EC Key #10a (SEC1 PEM, secp384r1, compressed)',
+                    'Parse EC Key #11a (SEC1 PEM, secp521r1, compressed)',
+                    'Parse EC Key #12a (SEC1 PEM, bp256r1, compressed)',
+                    'Parse EC Key #13a (SEC1 PEM, bp384r1, compressed)',
+                    'Parse EC Key #14a (SEC1 PEM, bp512r1, compressed)',
+                    'Parse EC Key #2a (SEC1 PEM, secp192r1, compressed)',
+                    'Parse EC Key #8a (SEC1 PEM, secp224r1, compressed)',
+                    'Parse EC Key #9a (SEC1 PEM, secp256r1, compressed)',
+                    'Parse Public EC Key #2a (RFC 5480, PEM, secp192r1, compressed)',
+                    'Parse Public EC Key #3a (RFC 5480, secp224r1, compressed)',
+                    'Parse Public EC Key #4a (RFC 5480, secp256r1, compressed)',
+                    'Parse Public EC Key #5a (RFC 5480, secp384r1, compressed)',
+                    'Parse Public EC Key #6a (RFC 5480, secp521r1, compressed)',
+                    'Parse Public EC Key #7a (RFC 5480, brainpoolP256r1, compressed)',
+                    'Parse Public EC Key #8a (RFC 5480, brainpoolP384r1, compressed)',
+                    'Parse Public EC Key #9a (RFC 5480, brainpoolP512r1, compressed)',
+                ],
+                'test_suite_asn1parse': [
+                    # This test depends on BIGNUM_C
+                    'INTEGER too large for mpi',
+                ],
+                'test_suite_asn1write': [
+                    # Following tests depends on BIGNUM_C
+                    'ASN.1 Write mpi 0 (1 limb)',
+                    'ASN.1 Write mpi 0 (null)',
+                    'ASN.1 Write mpi 0x100',
+                    'ASN.1 Write mpi 0x7f',
+                    'ASN.1 Write mpi 0x7f with leading 0 limb',
+                    'ASN.1 Write mpi 0x80',
+                    'ASN.1 Write mpi 0x80 with leading 0 limb',
+                    'ASN.1 Write mpi 0xff',
+                    'ASN.1 Write mpi 1',
+                    'ASN.1 Write mpi, 127*8 bits',
+                    'ASN.1 Write mpi, 127*8+1 bits',
+                    'ASN.1 Write mpi, 127*8-1 bits',
+                    'ASN.1 Write mpi, 255*8 bits',
+                    'ASN.1 Write mpi, 255*8-1 bits',
+                    'ASN.1 Write mpi, 256*8-1 bits',
+                ],
+                'test_suite_debug': [
+                    # Following tests depends on BIGNUM_C
+                    'Debug print mbedtls_mpi #2: 3 bits',
+                    'Debug print mbedtls_mpi: 0 (empty representation)',
+                    'Debug print mbedtls_mpi: 0 (non-empty representation)',
+                    'Debug print mbedtls_mpi: 49 bits',
+                    'Debug print mbedtls_mpi: 759 bits',
+                    'Debug print mbedtls_mpi: 764 bits #1',
+                    'Debug print mbedtls_mpi: 764 bits #2',
+                ],
+            }
+        }
+    },
     'analyze_driver_vs_reference_ffdh_alg': {
         'test_function': do_analyze_driver_vs_reference,
         'args': {
@@ -333,6 +441,11 @@
                                  'comma/space-separated list of tasks. ')
         parser.add_argument('--list', action='store_true',
                             help='List all available tasks and exit.')
+        parser.add_argument('--require-full-coverage', action='store_true',
+                            dest='full_coverage', help="Require all available "
+                            "test cases to be executed and issue an error "
+                            "otherwise. This flag is ignored if 'task' is "
+                            "neither 'all' nor 'analyze_coverage'")
         options = parser.parse_args()
 
         if options.list:
@@ -352,6 +465,9 @@
                     Results.log('Error: invalid task: {}'.format(task))
                     sys.exit(1)
 
+        TASKS['analyze_coverage']['args']['full_coverage'] = \
+            options.full_coverage
+
         for task in TASKS:
             if task in tasks:
                 if not TASKS[task]['test_function'](options.outcomes, TASKS[task]['args']):
diff --git a/tests/scripts/audit-validity-dates.py b/tests/scripts/audit-validity-dates.py
index 5506e40..623fd23 100755
--- a/tests/scripts/audit-validity-dates.py
+++ b/tests/scripts/audit-validity-dates.py
@@ -24,7 +24,6 @@
 """
 
 import os
-import sys
 import re
 import typing
 import argparse
@@ -43,6 +42,7 @@
 
 import scripts_path # pylint: disable=unused-import
 from mbedtls_dev import build_tree
+from mbedtls_dev import logging_util
 
 def check_cryptography_version():
     match = re.match(r'^[0-9]+', cryptography.__version__)
@@ -393,38 +393,6 @@
             loc))
 
 
-def configure_logger(logger: logging.Logger) -> None:
-    """
-    Configure the logging.Logger instance so that:
-        - Format is set to "[%(levelname)s]: %(message)s".
-        - loglevel >= WARNING are printed to stderr.
-        - loglevel <  WARNING are printed to stdout.
-    """
-    class MaxLevelFilter(logging.Filter):
-        # pylint: disable=too-few-public-methods
-        def __init__(self, max_level, name=''):
-            super().__init__(name)
-            self.max_level = max_level
-
-        def filter(self, record: logging.LogRecord) -> bool:
-            return record.levelno <= self.max_level
-
-    log_formatter = logging.Formatter("[%(levelname)s]: %(message)s")
-
-    # set loglevel >= WARNING to be printed to stderr
-    stderr_hdlr = logging.StreamHandler(sys.stderr)
-    stderr_hdlr.setLevel(logging.WARNING)
-    stderr_hdlr.setFormatter(log_formatter)
-
-    # set loglevel <= INFO to be printed to stdout
-    stdout_hdlr = logging.StreamHandler(sys.stdout)
-    stdout_hdlr.addFilter(MaxLevelFilter(logging.INFO))
-    stdout_hdlr.setFormatter(log_formatter)
-
-    logger.addHandler(stderr_hdlr)
-    logger.addHandler(stdout_hdlr)
-
-
 def main():
     """
     Perform argument parsing.
@@ -457,7 +425,7 @@
     # start main routine
     # setup logger
     logger = logging.getLogger()
-    configure_logger(logger)
+    logging_util.configure_logger(logger)
     logger.setLevel(logging.DEBUG if args.verbose else logging.ERROR)
 
     td_auditor = TestDataAuditor(logger)
diff --git a/tests/scripts/check_test_cases.py b/tests/scripts/check_test_cases.py
index d84ed04..1395d4d 100755
--- a/tests/scripts/check_test_cases.py
+++ b/tests/scripts/check_test_cases.py
@@ -25,6 +25,7 @@
 import glob
 import os
 import re
+import subprocess
 import sys
 
 class Results:
@@ -111,6 +112,19 @@
                 self.process_test_case(descriptions,
                                        file_name, line_number, description)
 
+    def walk_compat_sh(self, file_name):
+        """Iterate over the test cases compat.sh with a similar format."""
+        descriptions = self.new_per_file_state() # pylint: disable=assignment-from-none
+        compat_cmd = ['sh', file_name, '--list-test-case']
+        compat_output = subprocess.check_output(compat_cmd)
+        # Assume compat.sh is responsible for printing identical format of
+        # test case description between --list-test-case and its OUTCOME.CSV
+        description = compat_output.strip().split(b'\n')
+        # idx indicates the number of test case since there is no line number
+        # in `compat.sh` for each test case.
+        for idx, descrip in enumerate(description):
+            self.process_test_case(descriptions, file_name, idx, descrip)
+
     @staticmethod
     def collect_test_directories():
         """Get the relative path for the TLS and Crypto test directories."""
@@ -136,6 +150,9 @@
             for ssl_opt_file_name in glob.glob(os.path.join(directory, 'opt-testcases',
                                                             '*.sh')):
                 self.walk_ssl_opt_sh(ssl_opt_file_name)
+            compat_sh = os.path.join(directory, 'compat.sh')
+            if os.path.exists(compat_sh):
+                self.walk_compat_sh(compat_sh)
 
 class TestDescriptions(TestDescriptionExplorer):
     """Collect the available test cases."""
diff --git a/tests/scripts/generate_psa_tests.py b/tests/scripts/generate_psa_tests.py
index 9934578..b6f83c1 100755
--- a/tests/scripts/generate_psa_tests.py
+++ b/tests/scripts/generate_psa_tests.py
@@ -26,151 +26,15 @@
 from typing import Callable, Dict, FrozenSet, Iterable, Iterator, List, Optional
 
 import scripts_path # pylint: disable=unused-import
+from mbedtls_dev import crypto_data_tests
 from mbedtls_dev import crypto_knowledge
-from mbedtls_dev import macro_collector
+from mbedtls_dev import macro_collector #pylint: disable=unused-import
+from mbedtls_dev import psa_information
 from mbedtls_dev import psa_storage
 from mbedtls_dev import test_case
 from mbedtls_dev import test_data_generation
 
 
-def psa_want_symbol(name: str) -> str:
-    """Return the PSA_WANT_xxx symbol associated with a PSA crypto feature."""
-    if name.startswith('PSA_'):
-        return name[:4] + 'WANT_' + name[4:]
-    else:
-        raise ValueError('Unable to determine the PSA_WANT_ symbol for ' + name)
-
-def finish_family_dependency(dep: str, bits: int) -> str:
-    """Finish dep if it's a family dependency symbol prefix.
-
-    A family dependency symbol prefix is a PSA_WANT_ symbol that needs to be
-    qualified by the key size. If dep is such a symbol, finish it by adjusting
-    the prefix and appending the key size. Other symbols are left unchanged.
-    """
-    return re.sub(r'_FAMILY_(.*)', r'_\1_' + str(bits), dep)
-
-def finish_family_dependencies(dependencies: List[str], bits: int) -> List[str]:
-    """Finish any family dependency symbol prefixes.
-
-    Apply `finish_family_dependency` to each element of `dependencies`.
-    """
-    return [finish_family_dependency(dep, bits) for dep in dependencies]
-
-SYMBOLS_WITHOUT_DEPENDENCY = frozenset([
-    'PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG', # modifier, only in policies
-    'PSA_ALG_AEAD_WITH_SHORTENED_TAG', # modifier
-    'PSA_ALG_ANY_HASH', # only in policies
-    'PSA_ALG_AT_LEAST_THIS_LENGTH_MAC', # modifier, only in policies
-    'PSA_ALG_KEY_AGREEMENT', # chaining
-    'PSA_ALG_TRUNCATED_MAC', # modifier
-])
-def automatic_dependencies(*expressions: str) -> List[str]:
-    """Infer dependencies of a test case by looking for PSA_xxx symbols.
-
-    The arguments are strings which should be C expressions. Do not use
-    string literals or comments as this function is not smart enough to
-    skip them.
-    """
-    used = set()
-    for expr in expressions:
-        used.update(re.findall(r'PSA_(?:ALG|ECC_FAMILY|KEY_TYPE)_\w+', expr))
-    used.difference_update(SYMBOLS_WITHOUT_DEPENDENCY)
-    return sorted(psa_want_symbol(name) for name in used)
-
-# Define set of regular expressions and dependencies to optionally append
-# extra dependencies for test case.
-AES_128BIT_ONLY_DEP_REGEX = r'AES\s(192|256)'
-AES_128BIT_ONLY_DEP = ["!MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH"]
-
-DEPENDENCY_FROM_KEY = {
-    AES_128BIT_ONLY_DEP_REGEX: AES_128BIT_ONLY_DEP
-}#type: Dict[str, List[str]]
-def generate_key_dependencies(description: str) -> List[str]:
-    """Return additional dependencies based on pairs of REGEX and dependencies.
-    """
-    deps = []
-    for regex, dep in DEPENDENCY_FROM_KEY.items():
-        if re.search(regex, description):
-            deps += dep
-
-    return deps
-
-# A temporary hack: at the time of writing, not all dependency symbols
-# are implemented yet. Skip test cases for which the dependency symbols are
-# not available. Once all dependency symbols are available, this hack must
-# be removed so that a bug in the dependency symbols properly leads to a test
-# failure.
-def read_implemented_dependencies(filename: str) -> FrozenSet[str]:
-    return frozenset(symbol
-                     for line in open(filename)
-                     for symbol in re.findall(r'\bPSA_WANT_\w+\b', line))
-_implemented_dependencies = None #type: Optional[FrozenSet[str]] #pylint: disable=invalid-name
-def hack_dependencies_not_implemented(dependencies: List[str]) -> None:
-    global _implemented_dependencies #pylint: disable=global-statement,invalid-name
-    if _implemented_dependencies is None:
-        _implemented_dependencies = \
-            read_implemented_dependencies('include/psa/crypto_config.h')
-    if not all((dep.lstrip('!') in _implemented_dependencies or
-                not dep.lstrip('!').startswith('PSA_WANT'))
-               for dep in dependencies):
-        dependencies.append('DEPENDENCY_NOT_IMPLEMENTED_YET')
-
-def tweak_key_pair_dependency(dep: str, usage: str):
-    """
-    This helper function add the proper suffix to PSA_WANT_KEY_TYPE_xxx_KEY_PAIR
-    symbols according to the required usage.
-    """
-    ret_list = list()
-    if dep.endswith('KEY_PAIR'):
-        if usage == "BASIC":
-            # BASIC automatically includes IMPORT and EXPORT for test purposes (see
-            # config_psa.h).
-            ret_list.append(re.sub(r'KEY_PAIR', r'KEY_PAIR_BASIC', dep))
-            ret_list.append(re.sub(r'KEY_PAIR', r'KEY_PAIR_IMPORT', dep))
-            ret_list.append(re.sub(r'KEY_PAIR', r'KEY_PAIR_EXPORT', dep))
-        elif usage == "GENERATE":
-            ret_list.append(re.sub(r'KEY_PAIR', r'KEY_PAIR_GENERATE', dep))
-    else:
-        # No replacement to do in this case
-        ret_list.append(dep)
-    return ret_list
-
-def fix_key_pair_dependencies(dep_list: List[str], usage: str):
-    new_list = [new_deps
-                for dep in dep_list
-                for new_deps in tweak_key_pair_dependency(dep, usage)]
-
-    return new_list
-
-class Information:
-    """Gather information about PSA constructors."""
-
-    def __init__(self) -> None:
-        self.constructors = self.read_psa_interface()
-
-    @staticmethod
-    def remove_unwanted_macros(
-            constructors: macro_collector.PSAMacroEnumerator
-    ) -> None:
-        # Mbed TLS does not support finite-field DSA.
-        # Don't attempt to generate any related test case.
-        constructors.key_types.discard('PSA_KEY_TYPE_DSA_KEY_PAIR')
-        constructors.key_types.discard('PSA_KEY_TYPE_DSA_PUBLIC_KEY')
-
-    def read_psa_interface(self) -> macro_collector.PSAMacroEnumerator:
-        """Return the list of known key types, algorithms, etc."""
-        constructors = macro_collector.InputsForTest()
-        header_file_names = ['include/psa/crypto_values.h',
-                             'include/psa/crypto_extra.h']
-        test_suites = ['tests/suites/test_suite_psa_crypto_metadata.data']
-        for header_file_name in header_file_names:
-            constructors.parse_header(header_file_name)
-        for test_cases in test_suites:
-            constructors.parse_test_cases(test_cases)
-        self.remove_unwanted_macros(constructors)
-        constructors.gather_arguments()
-        return constructors
-
 
 def test_case_for_key_type_not_supported(
         verb: str, key_type: str, bits: int,
@@ -181,7 +45,7 @@
     """Return one test case exercising a key creation method
     for an unsupported key type or size.
     """
-    hack_dependencies_not_implemented(dependencies)
+    psa_information.hack_dependencies_not_implemented(dependencies)
     tc = test_case.TestCase()
     short_key_type = crypto_knowledge.short_expression(key_type)
     adverb = 'not' if dependencies else 'never'
@@ -197,7 +61,7 @@
 class KeyTypeNotSupported:
     """Generate test cases for when a key type is not supported."""
 
-    def __init__(self, info: Information) -> None:
+    def __init__(self, info: psa_information.Information) -> None:
         self.constructors = info.constructors
 
     ALWAYS_SUPPORTED = frozenset([
@@ -224,20 +88,22 @@
             # They would be skipped in all configurations, which is noise.
             return
         import_dependencies = [('!' if param is None else '') +
-                               psa_want_symbol(kt.name)]
+                               psa_information.psa_want_symbol(kt.name)]
         if kt.params is not None:
             import_dependencies += [('!' if param == i else '') +
-                                    psa_want_symbol(sym)
+                                    psa_information.psa_want_symbol(sym)
                                     for i, sym in enumerate(kt.params)]
         if kt.name.endswith('_PUBLIC_KEY'):
             generate_dependencies = []
         else:
-            generate_dependencies = fix_key_pair_dependencies(import_dependencies, 'GENERATE')
-            import_dependencies = fix_key_pair_dependencies(import_dependencies, 'BASIC')
+            generate_dependencies = \
+                psa_information.fix_key_pair_dependencies(import_dependencies, 'GENERATE')
+            import_dependencies = \
+                psa_information.fix_key_pair_dependencies(import_dependencies, 'BASIC')
         for bits in kt.sizes_to_test():
             yield test_case_for_key_type_not_supported(
                 'import', kt.expression, bits,
-                finish_family_dependencies(import_dependencies, bits),
+                psa_information.finish_family_dependencies(import_dependencies, bits),
                 test_case.hex_string(kt.key_material(bits)),
                 param_descr=param_descr,
             )
@@ -251,7 +117,7 @@
             if not kt.is_public():
                 yield test_case_for_key_type_not_supported(
                     'generate', kt.expression, bits,
-                    finish_family_dependencies(generate_dependencies, bits),
+                    psa_information.finish_family_dependencies(generate_dependencies, bits),
                     str(bits),
                     param_descr=param_descr,
                 )
@@ -294,7 +160,7 @@
 ) -> test_case.TestCase:
     """Return one test case exercising a key generation.
     """
-    hack_dependencies_not_implemented(dependencies)
+    psa_information.hack_dependencies_not_implemented(dependencies)
     tc = test_case.TestCase()
     short_key_type = crypto_knowledge.short_expression(key_type)
     tc.set_description('PSA {} {}-bit'
@@ -308,7 +174,7 @@
 class KeyGenerate:
     """Generate positive and negative (invalid argument) test cases for key generation."""
 
-    def __init__(self, info: Information) -> None:
+    def __init__(self, info: psa_information.Information) -> None:
         self.constructors = info.constructors
 
     ECC_KEY_TYPES = ('PSA_KEY_TYPE_ECC_KEY_PAIR',
@@ -327,9 +193,9 @@
         """
         result = 'PSA_SUCCESS'
 
-        import_dependencies = [psa_want_symbol(kt.name)]
+        import_dependencies = [psa_information.psa_want_symbol(kt.name)]
         if kt.params is not None:
-            import_dependencies += [psa_want_symbol(sym)
+            import_dependencies += [psa_information.psa_want_symbol(sym)
                                     for i, sym in enumerate(kt.params)]
         if kt.name.endswith('_PUBLIC_KEY'):
             # The library checks whether the key type is a public key generically,
@@ -338,7 +204,8 @@
             generate_dependencies = []
             result = 'PSA_ERROR_INVALID_ARGUMENT'
         else:
-            generate_dependencies = fix_key_pair_dependencies(import_dependencies, 'GENERATE')
+            generate_dependencies = \
+                psa_information.fix_key_pair_dependencies(import_dependencies, 'GENERATE')
         for bits in kt.sizes_to_test():
             if kt.name == 'PSA_KEY_TYPE_RSA_KEY_PAIR':
                 size_dependency = "PSA_VENDOR_RSA_GENERATE_MIN_KEY_BITS <= " +  str(bits)
@@ -347,7 +214,7 @@
                 test_dependencies = generate_dependencies
             yield test_case_for_key_generation(
                 kt.expression, bits,
-                finish_family_dependencies(test_dependencies, bits),
+                psa_information.finish_family_dependencies(test_dependencies, bits),
                 str(bits),
                 result
             )
@@ -380,7 +247,7 @@
         INCOMPATIBLE = 2
         PUBLIC = 3
 
-    def __init__(self, info: Information) -> None:
+    def __init__(self, info: psa_information.Information) -> None:
         self.constructors = info.constructors
         key_type_expressions = self.constructors.generate_expressions(
             sorted(self.constructors.key_types)
@@ -417,8 +284,8 @@
                                    pretty_alg,
                                    pretty_reason,
                                    ' with ' + pretty_type if pretty_type else ''))
-        dependencies = automatic_dependencies(alg.base_expression, key_type)
-        dependencies = fix_key_pair_dependencies(dependencies, 'BASIC')
+        dependencies = psa_information.automatic_dependencies(alg.base_expression, key_type)
+        dependencies = psa_information.fix_key_pair_dependencies(dependencies, 'BASIC')
         for i, dep in enumerate(dependencies):
             if dep in not_deps:
                 dependencies[i] = '!' + dep
@@ -445,7 +312,7 @@
         """Generate failure test cases for keyless operations with the specified algorithm."""
         if alg.can_do(category):
             # Compatible operation, unsupported algorithm
-            for dep in automatic_dependencies(alg.base_expression):
+            for dep in psa_information.automatic_dependencies(alg.base_expression):
                 yield self.make_test_case(alg, category,
                                           self.Reason.NOT_SUPPORTED,
                                           not_deps=frozenset([dep]))
@@ -463,7 +330,7 @@
             key_is_compatible = kt.can_do(alg)
             if key_is_compatible and alg.can_do(category):
                 # Compatible key and operation, unsupported algorithm
-                for dep in automatic_dependencies(alg.base_expression):
+                for dep in psa_information.automatic_dependencies(alg.base_expression):
                     yield self.make_test_case(alg, category,
                                               self.Reason.NOT_SUPPORTED,
                                               kt=kt, not_deps=frozenset([dep]))
@@ -569,7 +436,7 @@
 class StorageFormat:
     """Storage format stability test cases."""
 
-    def __init__(self, info: Information, version: int, forward: bool) -> None:
+    def __init__(self, info: psa_information.Information, version: int, forward: bool) -> None:
         """Prepare to generate test cases for storage format stability.
 
         * `info`: information about the API. See the `Information` class.
@@ -636,13 +503,13 @@
         verb = 'save' if self.forward else 'read'
         tc = test_case.TestCase()
         tc.set_description(verb + ' ' + key.description)
-        dependencies = automatic_dependencies(
+        dependencies = psa_information.automatic_dependencies(
             key.lifetime.string, key.type.string,
             key.alg.string, key.alg2.string,
         )
-        dependencies = finish_family_dependencies(dependencies, key.bits)
-        dependencies += generate_key_dependencies(key.description)
-        dependencies = fix_key_pair_dependencies(dependencies, 'BASIC')
+        dependencies = psa_information.finish_family_dependencies(dependencies, key.bits)
+        dependencies += psa_information.generate_key_dependencies(key.description)
+        dependencies = psa_information.fix_key_pair_dependencies(dependencies, 'BASIC')
         tc.set_dependencies(dependencies)
         tc.set_function('key_storage_' + verb)
         if self.forward:
@@ -847,13 +714,13 @@
 class StorageFormatForward(StorageFormat):
     """Storage format stability test cases for forward compatibility."""
 
-    def __init__(self, info: Information, version: int) -> None:
+    def __init__(self, info: psa_information.Information, version: int) -> None:
         super().__init__(info, version, True)
 
 class StorageFormatV0(StorageFormat):
     """Storage format stability test cases for version 0 compatibility."""
 
-    def __init__(self, info: Information) -> None:
+    def __init__(self, info: psa_information.Information) -> None:
         super().__init__(info, 0, False)
 
     def all_keys_for_usage_flags(self) -> Iterator[StorageTestData]:
@@ -963,6 +830,7 @@
         yield from super().generate_all_keys()
         yield from self.all_keys_for_implicit_usage()
 
+
 class PSATestGenerator(test_data_generation.TestGenerator):
     """Test generator subclass including PSA targets and info."""
     # Note that targets whose names contain 'test_format' have their content
@@ -972,20 +840,23 @@
         lambda info: KeyGenerate(info).test_cases_for_key_generation(),
         'test_suite_psa_crypto_not_supported.generated':
         lambda info: KeyTypeNotSupported(info).test_cases_for_not_supported(),
+        'test_suite_psa_crypto_low_hash.generated':
+        lambda info: crypto_data_tests.HashPSALowLevel(info).all_test_cases(),
         'test_suite_psa_crypto_op_fail.generated':
         lambda info: OpFail(info).all_test_cases(),
         'test_suite_psa_crypto_storage_format.current':
         lambda info: StorageFormatForward(info, 0).all_test_cases(),
         'test_suite_psa_crypto_storage_format.v0':
         lambda info: StorageFormatV0(info).all_test_cases(),
-    } #type: Dict[str, Callable[[Information], Iterable[test_case.TestCase]]]
+    } #type: Dict[str, Callable[[psa_information.Information], Iterable[test_case.TestCase]]]
 
     def __init__(self, options):
         super().__init__(options)
-        self.info = Information()
+        self.info = psa_information.Information()
 
     def generate_target(self, name: str, *target_args) -> None:
         super().generate_target(name, self.info)
 
+
 if __name__ == '__main__':
     test_data_generation.main(sys.argv[1:], __doc__, PSATestGenerator)
diff --git a/tests/src/bignum_helpers.c b/tests/src/bignum_helpers.c
index efb2eca..214530d 100644
--- a/tests/src/bignum_helpers.c
+++ b/tests/src/bignum_helpers.c
@@ -86,6 +86,7 @@
     return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
 }
 
+#if defined(MBEDTLS_ECP_WITH_MPI_UINT)
 int mbedtls_test_read_mpi_modulus(mbedtls_mpi_mod_modulus *N,
                                   const char *s,
                                   mbedtls_mpi_mod_rep_selector int_rep)
@@ -122,6 +123,7 @@
     mbedtls_free((mbedtls_mpi_uint *) N->p);
     mbedtls_mpi_mod_modulus_free(N);
 }
+#endif /* MBEDTLS_ECP_WITH_MPI_UINT */
 
 int mbedtls_test_read_mpi(mbedtls_mpi *X, const char *s)
 {
diff --git a/tests/src/psa_exercise_key.c b/tests/src/psa_exercise_key.c
index ef1d261..9ff408c 100644
--- a/tests/src/psa_exercise_key.c
+++ b/tests/src/psa_exercise_key.c
@@ -309,7 +309,7 @@
             hash_alg = KNOWN_SUPPORTED_HASH_ALG;
             alg ^= PSA_ALG_ANY_HASH ^ hash_alg;
     #else
-            TEST_ASSERT(!"No hash algorithm for hash-and-sign testing");
+            TEST_FAIL("No hash algorithm for hash-and-sign testing");
     #endif
         }
 
@@ -438,7 +438,7 @@
                                                   PSA_KEY_DERIVATION_INPUT_LABEL,
                                                   input2, input2_length));
     } else {
-        TEST_ASSERT(!"Key derivation algorithm not supported");
+        TEST_FAIL("Key derivation algorithm not supported");
     }
 
     if (capacity != SIZE_MAX) {
@@ -798,7 +798,7 @@
                     PSA_EXPORT_PUBLIC_KEY_MAX_SIZE);
     } else {
         (void) exported;
-        TEST_ASSERT(!"Sanity check not implemented for this key type");
+        TEST_FAIL("Sanity check not implemented for this key type");
     }
 
 #if defined(MBEDTLS_DES_C)
@@ -943,7 +943,7 @@
     } else if (PSA_ALG_IS_KEY_AGREEMENT(alg)) {
         ok = exercise_key_agreement_key(key, usage, alg);
     } else {
-        TEST_ASSERT(!"No code to exercise this category of algorithm");
+        TEST_FAIL("No code to exercise this category of algorithm");
     }
 
     ok = ok && exercise_export_key(key, usage);
diff --git a/tests/src/test_helpers/ssl_helpers.c b/tests/src/test_helpers/ssl_helpers.c
index 701577a..9144d85 100644
--- a/tests/src/test_helpers/ssl_helpers.c
+++ b/tests/src/test_helpers/ssl_helpers.c
@@ -1759,8 +1759,8 @@
             break;
 
         default:
-            TEST_ASSERT(
-                !"Version check not implemented for this protocol version");
+            TEST_FAIL(
+                "Version check not implemented for this protocol version");
     }
 
     return 1;
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 6113eeb..0164b45 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -435,6 +435,13 @@
             ;;
     esac
 
+    case "$CMD_LINE" in
+        *server2*|\
+        *server7*)
+            # server2 and server7 certificates use RSA encryption
+            requires_config_enabled "MBEDTLS_RSA_C"
+    esac
+
     unset tmp
 }
 
diff --git a/tests/suites/test_suite_alignment.function b/tests/suites/test_suite_alignment.function
index eefbaa5..842101f 100644
--- a/tests/suites/test_suite_alignment.function
+++ b/tests/suites/test_suite_alignment.function
@@ -121,7 +121,7 @@
             r = MBEDTLS_BSWAP64(input);
             break;
         default:
-            TEST_ASSERT(!"size must be 16, 32 or 64");
+            TEST_FAIL("size must be 16, 32 or 64");
     }
     TEST_EQUAL(r, expected);
 
diff --git a/tests/suites/test_suite_asn1write.function b/tests/suites/test_suite_asn1write.function
index a7330d0..469b971 100644
--- a/tests/suites/test_suite_asn1write.function
+++ b/tests/suites/test_suite_asn1write.function
@@ -316,7 +316,7 @@
                 buf_complete[data_len + 2] = (unsigned char) (expected_params_len >> 8);
                 buf_complete[data_len + 3] = (unsigned char) (expected_params_len);
             } else {
-                TEST_ASSERT(!"Bad test data: invalid length of ASN.1 element");
+                TEST_FAIL("Bad test data: invalid length of ASN.1 element");
             }
             unsigned char *p = buf_complete;
             TEST_EQUAL(mbedtls_asn1_get_alg(&p, end_complete,
diff --git a/tests/suites/test_suite_base64.data b/tests/suites/test_suite_base64.data
index 5556668..3999e73 100644
--- a/tests/suites/test_suite_base64.data
+++ b/tests/suites/test_suite_base64.data
@@ -1,27 +1,3 @@
-mask_of_range empty (1..0)
-mask_of_range:1:0
-
-mask_of_range empty (255..0)
-mask_of_range:255:0
-
-mask_of_range empty (42..7)
-mask_of_range:42:7
-
-mask_of_range 0..0
-mask_of_range:0:0
-
-mask_of_range 42..42
-mask_of_range:42:42
-
-mask_of_range 255..255
-mask_of_range:255:255
-
-mask_of_range 0..255
-mask_of_range:0:255
-
-mask_of_range 'A'..'Z'
-mask_of_range:65:90
-
 enc_char (all digits)
 enc_chars:
 
diff --git a/tests/suites/test_suite_base64.function b/tests/suites/test_suite_base64.function
index ce6bd42..e351ad8 100644
--- a/tests/suites/test_suite_base64.function
+++ b/tests/suites/test_suite_base64.function
@@ -1,7 +1,7 @@
 /* BEGIN_HEADER */
 #include "mbedtls/base64.h"
+#include "base64_internal.h"
 #include "constant_time_internal.h"
-#include "constant_time_invasive.h"
 #include <test/constant_flow.h>
 
 #if defined(MBEDTLS_TEST_HOOKS)
@@ -17,26 +17,6 @@
  */
 
 /* BEGIN_CASE depends_on:MBEDTLS_TEST_HOOKS */
-void mask_of_range(int low_arg, int high_arg)
-{
-    unsigned char low = low_arg, high = high_arg;
-    unsigned c;
-    for (c = 0; c <= 0xff; c++) {
-        mbedtls_test_set_step(c);
-        TEST_CF_SECRET(&c, sizeof(c));
-        unsigned char m = mbedtls_ct_uchar_mask_of_range(low, high, c);
-        TEST_CF_PUBLIC(&c, sizeof(c));
-        TEST_CF_PUBLIC(&m, sizeof(m));
-        if (low <= c && c <= high) {
-            TEST_EQUAL(m, 0xff);
-        } else {
-            TEST_EQUAL(m, 0);
-        }
-    }
-}
-/* END_CASE */
-
-/* BEGIN_CASE depends_on:MBEDTLS_TEST_HOOKS */
 void enc_chars()
 {
     for (unsigned value = 0; value < 64; value++) {
diff --git a/tests/suites/test_suite_bignum.function b/tests/suites/test_suite_bignum.function
index 7f858e5..c90f1bb 100644
--- a/tests/suites/test_suite_bignum.function
+++ b/tests/suites/test_suite_bignum.function
@@ -438,7 +438,7 @@
 
     TEST_ASSERT(mbedtls_mpi_lt_mpi_ct(&X, &Y, &ret) == input_err);
     if (input_err == 0) {
-        TEST_ASSERT(ret == input_uret);
+        TEST_EQUAL(ret, input_uret);
     }
 
 exit:
@@ -834,7 +834,7 @@
     } else if (strcmp(result_comparison, "!=") == 0) {
         TEST_ASSERT(mbedtls_mpi_cmp_mpi(&Z, &A) != 0);
     } else {
-        TEST_ASSERT("unknown operator" == 0);
+        TEST_FAIL("unknown operator");
     }
 
 exit:
diff --git a/tests/suites/test_suite_bignum_core.function b/tests/suites/test_suite_bignum_core.function
index 3ede6b2..db84d62 100644
--- a/tests/suites/test_suite_bignum_core.function
+++ b/tests/suites/test_suite_bignum_core.function
@@ -358,7 +358,7 @@
     TEST_CF_SECRET(Y, X_limbs * sizeof(mbedtls_mpi_uint));
 
     ret = mbedtls_mpi_core_lt_ct(X, Y, X_limbs);
-    TEST_EQUAL(ret, exp_ret);
+    TEST_EQUAL(!!ret, exp_ret);
 
 exit:
     mbedtls_free(X);
@@ -384,25 +384,25 @@
 
     TEST_CF_SECRET(A, A_limbs * sizeof(*A));
 
-    TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi(0, A, A_limbs), 1);
-    TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi(A[0], A, A_limbs), 1);
+    TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi(0, A, A_limbs), 1);
+    TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi(A[0], A, A_limbs), 1);
 
     if (is_large) {
-        TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi(A[0] + 1,
-                                                A, A_limbs), 1);
-        TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1) >> 1,
-                                                A, A_limbs), 1);
-        TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1),
-                                                A, A_limbs), 1);
+        TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi(A[0] + 1,
+                                                  A, A_limbs), 1);
+        TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1) >> 1,
+                                                  A, A_limbs), 1);
+        TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1),
+                                                  A, A_limbs), 1);
     } else {
-        TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi(A[0] + 1,
-                                                A, A_limbs),
+        TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi(A[0] + 1,
+                                                  A, A_limbs),
                    A[0] + 1 <= A[0]);
-        TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1) >> 1,
-                                                A, A_limbs),
+        TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1) >> 1,
+                                                  A, A_limbs),
                    (mbedtls_mpi_uint) (-1) >> 1 <= A[0]);
-        TEST_EQUAL(mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1),
-                                                A, A_limbs),
+        TEST_EQUAL(!!mbedtls_mpi_core_uint_le_mpi((mbedtls_mpi_uint) (-1),
+                                                  A, A_limbs),
                    (mbedtls_mpi_uint) (-1) <= A[0]);
     }
 
@@ -447,7 +447,7 @@
     TEST_CF_SECRET(X, bytes);
     TEST_CF_SECRET(Y, bytes);
 
-    mbedtls_mpi_core_cond_assign(X, Y, copy_limbs, 1);
+    mbedtls_mpi_core_cond_assign(X, Y, copy_limbs, mbedtls_ct_bool(1));
 
     TEST_CF_PUBLIC(X, bytes);
     TEST_CF_PUBLIC(Y, bytes);
@@ -515,7 +515,7 @@
     TEST_CF_SECRET(X, bytes);
     TEST_CF_SECRET(Y, bytes);
 
-    mbedtls_mpi_core_cond_swap(X, Y, copy_limbs, 1);
+    mbedtls_mpi_core_cond_swap(X, Y, copy_limbs, mbedtls_ct_bool(1));
 
     TEST_CF_PUBLIC(X, bytes);
     TEST_CF_PUBLIC(Y, bytes);
diff --git a/tests/suites/test_suite_bignum_mod.function b/tests/suites/test_suite_bignum_mod.function
index 7015284..9d0fe93 100644
--- a/tests/suites/test_suite_bignum_mod.function
+++ b/tests/suites/test_suite_bignum_mod.function
@@ -35,7 +35,7 @@
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
- * depends_on:MBEDTLS_BIGNUM_C
+ * depends_on:MBEDTLS_BIGNUM_C:MBEDTLS_ECP_WITH_MPI_UINT
  * END_DEPENDENCIES
  */
 
@@ -737,5 +737,6 @@
     mbedtls_free(R);
     mbedtls_free(R_COPY);
     mbedtls_free(obuf);
+    mbedtls_free(ref_buf);
 }
 /* END_CASE */
diff --git a/tests/suites/test_suite_bignum_mod_raw.function b/tests/suites/test_suite_bignum_mod_raw.function
index 6b953f5..f7f8a59 100644
--- a/tests/suites/test_suite_bignum_mod_raw.function
+++ b/tests/suites/test_suite_bignum_mod_raw.function
@@ -11,7 +11,7 @@
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
- * depends_on:MBEDTLS_BIGNUM_C
+ * depends_on:MBEDTLS_BIGNUM_C:MBEDTLS_ECP_WITH_MPI_UINT
  * END_DEPENDENCIES
  */
 
diff --git a/tests/suites/test_suite_bignum_random.function b/tests/suites/test_suite_bignum_random.function
index 9ea773c..b43b1e7 100644
--- a/tests/suites/test_suite_bignum_random.function
+++ b/tests/suites/test_suite_bignum_random.function
@@ -134,7 +134,7 @@
 
     if (expected_ret == 0) {
         TEST_EQUAL(0, mbedtls_mpi_core_lt_ct(result, lower_bound, limbs));
-        TEST_EQUAL(1, mbedtls_mpi_core_lt_ct(result, upper_bound, limbs));
+        TEST_ASSERT(0 != mbedtls_mpi_core_lt_ct(result, upper_bound, limbs));
     }
 
 exit:
@@ -192,7 +192,7 @@
 }
 /* END_CASE */
 
-/* BEGIN_CASE */
+/* BEGIN_CASE depends_on:MBEDTLS_ECP_WITH_MPI_UINT */
 void mpi_mod_random_values(int min, char *max_hex, int rep)
 {
     /* Same RNG as in mpi_core_random_basic */
@@ -403,7 +403,7 @@
 }
 /* END_CASE */
 
-/* BEGIN_CASE */
+/* BEGIN_CASE depends_on:MBEDTLS_ECP_WITH_MPI_UINT */
 void mpi_mod_random_validation(int min, char *bound_hex,
                                int result_limbs_delta,
                                int expected_ret)
@@ -429,8 +429,7 @@
          * size as the modulus, otherwise it's a mistake in the test data. */
         TEST_EQUAL(result_limbs, N.limbs);
         /* Sanity check: check that the result is in range */
-        TEST_EQUAL(mbedtls_mpi_core_lt_ct(result_digits, N.p, N.limbs),
-                   1);
+        TEST_ASSERT(0 != mbedtls_mpi_core_lt_ct(result_digits, N.p, N.limbs));
         /* Check result >= min (changes result) */
         TEST_EQUAL(mbedtls_mpi_core_sub_int(result_digits, result_digits, min,
                                             result_limbs),
@@ -444,8 +443,7 @@
                                               mbedtls_test_rnd_std_rand, NULL),
                    expected_ret);
         if (expected_ret == 0) {
-            TEST_EQUAL(mbedtls_mpi_core_lt_ct(result_digits, N.p, N.limbs),
-                       1);
+            TEST_ASSERT(0 != mbedtls_mpi_core_lt_ct(result_digits, N.p, N.limbs));
             TEST_EQUAL(mbedtls_mpi_core_sub_int(result_digits, result.p, min,
                                                 result_limbs),
                        0);
diff --git a/tests/suites/test_suite_common.function b/tests/suites/test_suite_common.function
index a583e46..5c5700c 100644
--- a/tests/suites/test_suite_common.function
+++ b/tests/suites/test_suite_common.function
@@ -1,5 +1,5 @@
 /* BEGIN_HEADER */
-#include "../library/common.h"
+#include "common.h"
 
 void fill_arrays(unsigned char *a, unsigned char *b, unsigned char *r1, unsigned char *r2, size_t n)
 {
diff --git a/tests/suites/test_suite_constant_time.data b/tests/suites/test_suite_constant_time.data
index 91a25fa..1b0b964 100644
--- a/tests/suites/test_suite_constant_time.data
+++ b/tests/suites/test_suite_constant_time.data
@@ -1,14 +1,14 @@
 # these are the numbers we'd get with an empty plaintext and truncated HMAC
 Constant-flow memcpy from offset: small
-ssl_cf_memcpy_offset:0:5:10
+mbedtls_ct_memcpy_offset:0:5:10
 
 # we could get this with 255-bytes plaintext and untruncated SHA-256
 Constant-flow memcpy from offset: medium
-ssl_cf_memcpy_offset:0:255:32
+mbedtls_ct_memcpy_offset:0:255:32
 
 # we could get this with 255-bytes plaintext and untruncated SHA-384
 Constant-flow memcpy from offset: large
-ssl_cf_memcpy_offset:100:339:48
+mbedtls_ct_memcpy_offset:100:339:48
 
 mbedtls_ct_memcmp NULL
 mbedtls_ct_memcmp_null
@@ -91,47 +91,611 @@
 mbedtls_ct_memcmp len 17 offset 3
 mbedtls_ct_memcmp:-1:17:3
 
-mbedtls_ct_memcpy_if_eq len 1 offset 0
-mbedtls_ct_memcpy_if_eq:1:1:0
+mbedtls_ct_memcpy_if len 1 offset 0
+mbedtls_ct_memcpy_if:1:1:0
 
-mbedtls_ct_memcpy_if_eq len 1 offset 1
-mbedtls_ct_memcpy_if_eq:1:1:1
+mbedtls_ct_memcpy_if len 1 offset 1
+mbedtls_ct_memcpy_if:1:1:1
 
-mbedtls_ct_memcpy_if_eq len 4 offset 0
-mbedtls_ct_memcpy_if_eq:1:1:0
+mbedtls_ct_memcpy_if len 4 offset 0
+mbedtls_ct_memcpy_if:1:1:0
 
-mbedtls_ct_memcpy_if_eq len 4 offset 1
-mbedtls_ct_memcpy_if_eq:1:1:1
+mbedtls_ct_memcpy_if len 4 offset 1
+mbedtls_ct_memcpy_if:1:1:1
 
-mbedtls_ct_memcpy_if_eq len 4 offset 2
-mbedtls_ct_memcpy_if_eq:1:1:2
+mbedtls_ct_memcpy_if len 4 offset 2
+mbedtls_ct_memcpy_if:1:1:2
 
-mbedtls_ct_memcpy_if_eq len 4 offset 3
-mbedtls_ct_memcpy_if_eq:1:1:3
+mbedtls_ct_memcpy_if len 4 offset 3
+mbedtls_ct_memcpy_if:1:1:3
 
-mbedtls_ct_memcpy_if_eq len 15 offset 0
-mbedtls_ct_memcpy_if_eq:1:15:0
+mbedtls_ct_memcpy_if len 15 offset 0
+mbedtls_ct_memcpy_if:1:15:0
 
-mbedtls_ct_memcpy_if_eq len 15 offset 1
-mbedtls_ct_memcpy_if_eq:1:15:1
+mbedtls_ct_memcpy_if len 15 offset 1
+mbedtls_ct_memcpy_if:1:15:1
 
-mbedtls_ct_memcpy_if_eq len 16 offset 0
-mbedtls_ct_memcpy_if_eq:1:16:0
+mbedtls_ct_memcpy_if len 16 offset 0
+mbedtls_ct_memcpy_if:1:16:0
 
-mbedtls_ct_memcpy_if_eq len 16 offset 1
-mbedtls_ct_memcpy_if_eq:1:16:1
+mbedtls_ct_memcpy_if len 16 offset 1
+mbedtls_ct_memcpy_if:1:16:1
 
-mbedtls_ct_memcpy_if_eq len 17 offset 0
-mbedtls_ct_memcpy_if_eq:1:17:0
+mbedtls_ct_memcpy_if len 17 offset 0
+mbedtls_ct_memcpy_if:1:17:0
 
-mbedtls_ct_memcpy_if_eq len 17 offset 1
-mbedtls_ct_memcpy_if_eq:1:17:1
+mbedtls_ct_memcpy_if len 17 offset 1
+mbedtls_ct_memcpy_if:1:17:1
 
-mbedtls_ct_memcpy_if_eq len 0 not eq
-mbedtls_ct_memcpy_if_eq:0:17:0
+mbedtls_ct_memcpy_if len 0 not eq
+mbedtls_ct_memcpy_if:0:17:0
 
-mbedtls_ct_memcpy_if_eq len 5 offset 1 not eq
-mbedtls_ct_memcpy_if_eq:0:5:1
+mbedtls_ct_memcpy_if len 5 offset 1 not eq
+mbedtls_ct_memcpy_if:0:5:1
 
-mbedtls_ct_memcpy_if_eq len 17 offset 3 not eq
-mbedtls_ct_memcpy_if_eq:0:17:3
+mbedtls_ct_memcpy_if len 17 offset 3 not eq
+mbedtls_ct_memcpy_if:0:17:3
+
+mbedtls_ct_bool 0
+mbedtls_ct_bool:"0x0"
+
+mbedtls_ct_bool 1
+mbedtls_ct_bool:"0x1"
+
+mbedtls_ct_bool 4
+mbedtls_ct_bool:"0x4"
+
+mbedtls_ct_bool 0xfffffff
+mbedtls_ct_bool:"0xfffffff"
+
+mbedtls_ct_bool 0x7fffffff
+mbedtls_ct_bool:"0x7fffffff"
+
+mbedtls_ct_bool 0xfffffffe
+mbedtls_ct_bool:"0xfffffffe"
+
+mbedtls_ct_bool 0xffffffff
+mbedtls_ct_bool:"0xffffffff"
+
+mbedtls_ct_bool 0x0fffffffffffffff
+mbedtls_ct_bool:"0x0fffffffffffffff"
+
+mbedtls_ct_bool 0x7fffffffffffffff
+mbedtls_ct_bool:"0x7fffffffffffffff"
+
+mbedtls_ct_bool 0xffffffffffffffff
+mbedtls_ct_bool:"0xffffffffffffffff"
+
+mbedtls_ct_bool_xxx 0x0 0x0
+mbedtls_ct_bool_xxx:"0x0":"0x0"
+
+mbedtls_ct_bool_xxx 0x0 0x1
+mbedtls_ct_bool_xxx:"0x0":"0x1"
+
+mbedtls_ct_bool_xxx 0x0 0x7fffffff
+mbedtls_ct_bool_xxx:"0x0":"0x7fffffff"
+
+mbedtls_ct_bool_xxx 0x0 0xffffffff
+mbedtls_ct_bool_xxx:"0x0":"0xffffffff"
+
+mbedtls_ct_bool_xxx 0x0 0x7fffffffffffffff
+mbedtls_ct_bool_xxx:"0x0":"0x7fffffffffffffff"
+
+mbedtls_ct_bool_xxx 0x0 0xffffffffffffffff
+mbedtls_ct_bool_xxx:"0x0":"0xffffffffffffffff"
+
+mbedtls_ct_bool_xxx 0x1 0x0
+mbedtls_ct_bool_xxx:"0x1":"0x0"
+
+mbedtls_ct_bool_xxx 0x1 0x1
+mbedtls_ct_bool_xxx:"0x1":"0x1"
+
+mbedtls_ct_bool_xxx 0x1 0x7fffffff
+mbedtls_ct_bool_xxx:"0x1":"0x7fffffff"
+
+mbedtls_ct_bool_xxx 0x1 0xffffffff
+mbedtls_ct_bool_xxx:"0x1":"0xffffffff"
+
+mbedtls_ct_bool_xxx 0x1 0x7fffffffffffffff
+mbedtls_ct_bool_xxx:"0x1":"0x7fffffffffffffff"
+
+mbedtls_ct_bool_xxx 0x1 0xffffffffffffffff
+mbedtls_ct_bool_xxx:"0x1":"0xffffffffffffffff"
+
+mbedtls_ct_bool_xxx 0x7fffffff 0x0
+mbedtls_ct_bool_xxx:"0x7fffffff":"0x0"
+
+mbedtls_ct_bool_xxx 0x7fffffff 0x1
+mbedtls_ct_bool_xxx:"0x7fffffff":"0x1"
+
+mbedtls_ct_bool_xxx 0x7fffffff 0x7fffffff
+mbedtls_ct_bool_xxx:"0x7fffffff":"0x7fffffff"
+
+mbedtls_ct_bool_xxx 0x7fffffff 0xffffffff
+mbedtls_ct_bool_xxx:"0x7fffffff":"0xffffffff"
+
+mbedtls_ct_bool_xxx 0x7fffffff 0x7fffffffffffffff
+mbedtls_ct_bool_xxx:"0x7fffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_bool_xxx 0x7fffffff 0xffffffffffffffff
+mbedtls_ct_bool_xxx:"0x7fffffff":"0xffffffffffffffff"
+
+mbedtls_ct_bool_xxx 0xffffffff 0x0
+mbedtls_ct_bool_xxx:"0xffffffff":"0x0"
+
+mbedtls_ct_bool_xxx 0xffffffff 0x1
+mbedtls_ct_bool_xxx:"0xffffffff":"0x1"
+
+mbedtls_ct_bool_xxx 0xffffffff 0x7fffffff
+mbedtls_ct_bool_xxx:"0xffffffff":"0x7fffffff"
+
+mbedtls_ct_bool_xxx 0xffffffff 0xffffffff
+mbedtls_ct_bool_xxx:"0xffffffff":"0xffffffff"
+
+mbedtls_ct_bool_xxx 0xffffffff 0x7fffffffffffffff
+mbedtls_ct_bool_xxx:"0xffffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_bool_xxx 0xffffffff 0xffffffffffffffff
+mbedtls_ct_bool_xxx:"0xffffffff":"0xffffffffffffffff"
+
+mbedtls_ct_bool_xxx 0x7fffffffffffffff 0x0
+mbedtls_ct_bool_xxx:"0x7fffffffffffffff":"0x0"
+
+mbedtls_ct_bool_xxx 0x7fffffffffffffff 0x1
+mbedtls_ct_bool_xxx:"0x7fffffffffffffff":"0x1"
+
+mbedtls_ct_bool_xxx 0x7fffffffffffffff 0x7fffffff
+mbedtls_ct_bool_xxx:"0x7fffffffffffffff":"0x7fffffff"
+
+mbedtls_ct_bool_xxx 0x7fffffffffffffff 0xffffffff
+mbedtls_ct_bool_xxx:"0x7fffffffffffffff":"0xffffffff"
+
+mbedtls_ct_bool_xxx 0x7fffffffffffffff 0x7fffffffffffffff
+mbedtls_ct_bool_xxx:"0x7fffffffffffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_bool_xxx 0x7fffffffffffffff 0xffffffffffffffff
+mbedtls_ct_bool_xxx:"0x7fffffffffffffff":"0xffffffffffffffff"
+
+mbedtls_ct_bool_xxx 0xffffffffffffffff 0x0
+mbedtls_ct_bool_xxx:"0xffffffffffffffff":"0x0"
+
+mbedtls_ct_bool_xxx 0xffffffffffffffff 0x1
+mbedtls_ct_bool_xxx:"0xffffffffffffffff":"0x1"
+
+mbedtls_ct_bool_xxx 0xffffffffffffffff 0x7fffffff
+mbedtls_ct_bool_xxx:"0xffffffffffffffff":"0x7fffffff"
+
+mbedtls_ct_bool_xxx 0xffffffffffffffff 0xffffffff
+mbedtls_ct_bool_xxx:"0xffffffffffffffff":"0xffffffff"
+
+mbedtls_ct_bool_xxx 0xffffffffffffffff 0x7fffffffffffffff
+mbedtls_ct_bool_xxx:"0xffffffffffffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_bool_xxx 0xffffffffffffffff 0xffffffffffffffff
+mbedtls_ct_bool_xxx:"0xffffffffffffffff":"0xffffffffffffffff"
+
+mbedtls_ct_bool_xxx 138 256
+mbedtls_ct_bool_xxx:"138":"256"
+
+mbedtls_ct_bool_xxx 256 138
+mbedtls_ct_bool_xxx:"256":"138"
+
+mbedtls_ct_bool_xxx 6 6
+mbedtls_ct_bool_xxx:"0x6":"0x6"
+
+mbedtls_ct_uchar_in_range_if 0 0 0
+mbedtls_ct_uchar_in_range_if:0:0:0
+
+mbedtls_ct_uchar_in_range_if 0 0 100
+mbedtls_ct_uchar_in_range_if:0:0:100
+
+mbedtls_ct_uchar_in_range_if 0 0 255
+mbedtls_ct_uchar_in_range_if:0:0:255
+
+mbedtls_ct_uchar_in_range_if 0 65 0
+mbedtls_ct_uchar_in_range_if:0:65:0
+
+mbedtls_ct_uchar_in_range_if 0 65 100
+mbedtls_ct_uchar_in_range_if:0:65:100
+
+mbedtls_ct_uchar_in_range_if 0 65 255
+mbedtls_ct_uchar_in_range_if:0:65:255
+
+mbedtls_ct_uchar_in_range_if 0 90 0
+mbedtls_ct_uchar_in_range_if:0:90:0
+
+mbedtls_ct_uchar_in_range_if 0 90 100
+mbedtls_ct_uchar_in_range_if:0:90:100
+
+mbedtls_ct_uchar_in_range_if 0 90 255
+mbedtls_ct_uchar_in_range_if:0:90:255
+
+mbedtls_ct_uchar_in_range_if 0 255 0
+mbedtls_ct_uchar_in_range_if:0:255:0
+
+mbedtls_ct_uchar_in_range_if 0 255 100
+mbedtls_ct_uchar_in_range_if:0:255:100
+
+mbedtls_ct_uchar_in_range_if 0 255 255
+mbedtls_ct_uchar_in_range_if:0:255:255
+
+mbedtls_ct_uchar_in_range_if 65 0 0
+mbedtls_ct_uchar_in_range_if:65:0:0
+
+mbedtls_ct_uchar_in_range_if 65 0 100
+mbedtls_ct_uchar_in_range_if:65:0:100
+
+mbedtls_ct_uchar_in_range_if 65 0 255
+mbedtls_ct_uchar_in_range_if:65:0:255
+
+mbedtls_ct_uchar_in_range_if 65 65 0
+mbedtls_ct_uchar_in_range_if:65:65:0
+
+mbedtls_ct_uchar_in_range_if 65 65 100
+mbedtls_ct_uchar_in_range_if:65:65:100
+
+mbedtls_ct_uchar_in_range_if 65 65 255
+mbedtls_ct_uchar_in_range_if:65:65:255
+
+mbedtls_ct_uchar_in_range_if 65 90 0
+mbedtls_ct_uchar_in_range_if:65:90:0
+
+mbedtls_ct_uchar_in_range_if 65 90 100
+mbedtls_ct_uchar_in_range_if:65:90:100
+
+mbedtls_ct_uchar_in_range_if 65 90 255
+mbedtls_ct_uchar_in_range_if:65:90:255
+
+mbedtls_ct_uchar_in_range_if 65 255 0
+mbedtls_ct_uchar_in_range_if:65:255:0
+
+mbedtls_ct_uchar_in_range_if 65 255 100
+mbedtls_ct_uchar_in_range_if:65:255:100
+
+mbedtls_ct_uchar_in_range_if 65 255 255
+mbedtls_ct_uchar_in_range_if:65:255:255
+
+mbedtls_ct_uchar_in_range_if 90 0 0
+mbedtls_ct_uchar_in_range_if:90:0:0
+
+mbedtls_ct_uchar_in_range_if 90 0 100
+mbedtls_ct_uchar_in_range_if:90:0:100
+
+mbedtls_ct_uchar_in_range_if 90 0 255
+mbedtls_ct_uchar_in_range_if:90:0:255
+
+mbedtls_ct_uchar_in_range_if 90 65 0
+mbedtls_ct_uchar_in_range_if:90:65:0
+
+mbedtls_ct_uchar_in_range_if 90 65 100
+mbedtls_ct_uchar_in_range_if:90:65:100
+
+mbedtls_ct_uchar_in_range_if 90 65 255
+mbedtls_ct_uchar_in_range_if:90:65:255
+
+mbedtls_ct_uchar_in_range_if 90 90 0
+mbedtls_ct_uchar_in_range_if:90:90:0
+
+mbedtls_ct_uchar_in_range_if 90 90 100
+mbedtls_ct_uchar_in_range_if:90:90:100
+
+mbedtls_ct_uchar_in_range_if 90 90 255
+mbedtls_ct_uchar_in_range_if:90:90:255
+
+mbedtls_ct_uchar_in_range_if 90 255 0
+mbedtls_ct_uchar_in_range_if:90:255:0
+
+mbedtls_ct_uchar_in_range_if 90 255 100
+mbedtls_ct_uchar_in_range_if:90:255:100
+
+mbedtls_ct_uchar_in_range_if 90 255 255
+mbedtls_ct_uchar_in_range_if:90:255:255
+
+mbedtls_ct_uchar_in_range_if 255 0 0
+mbedtls_ct_uchar_in_range_if:255:0:0
+
+mbedtls_ct_uchar_in_range_if 255 0 100
+mbedtls_ct_uchar_in_range_if:255:0:100
+
+mbedtls_ct_uchar_in_range_if 255 0 255
+mbedtls_ct_uchar_in_range_if:255:0:255
+
+mbedtls_ct_uchar_in_range_if 255 65 0
+mbedtls_ct_uchar_in_range_if:255:65:0
+
+mbedtls_ct_uchar_in_range_if 255 65 100
+mbedtls_ct_uchar_in_range_if:255:65:100
+
+mbedtls_ct_uchar_in_range_if 255 65 255
+mbedtls_ct_uchar_in_range_if:255:65:255
+
+mbedtls_ct_uchar_in_range_if 255 90 0
+mbedtls_ct_uchar_in_range_if:255:90:0
+
+mbedtls_ct_uchar_in_range_if 255 90 100
+mbedtls_ct_uchar_in_range_if:255:90:100
+
+mbedtls_ct_uchar_in_range_if 255 90 255
+mbedtls_ct_uchar_in_range_if:255:90:255
+
+mbedtls_ct_uchar_in_range_if 255 255 0
+mbedtls_ct_uchar_in_range_if:255:255:0
+
+mbedtls_ct_uchar_in_range_if 255 255 100
+mbedtls_ct_uchar_in_range_if:255:255:100
+
+mbedtls_ct_uchar_in_range_if 255 255 255
+mbedtls_ct_uchar_in_range_if:255:255:255
+
+mbedtls_ct_if 0x0 0x0 0x0
+mbedtls_ct_if:"0x0":"0x0":"0x0"
+
+mbedtls_ct_if 0x0 0x0 0x1
+mbedtls_ct_if:"0x0":"0x0":"0x1"
+
+mbedtls_ct_if 0x0 0x0 0x7fffffff
+mbedtls_ct_if:"0x0":"0x0":"0x7fffffff"
+
+mbedtls_ct_if 0x0 0x0 0xffffffff
+mbedtls_ct_if:"0x0":"0x0":"0xffffffff"
+
+mbedtls_ct_if 0x0 0x0 0x7fffffffffffffff
+mbedtls_ct_if:"0x0":"0x0":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0x0 0x0 0xffffffffffffffff
+mbedtls_ct_if:"0x0":"0x0":"0xffffffffffffffff"
+
+mbedtls_ct_if 0x0 0x1 0x0
+mbedtls_ct_if:"0x0":"0x1":"0x0"
+
+mbedtls_ct_if 0x0 0x1 0x1
+mbedtls_ct_if:"0x0":"0x1":"0x1"
+
+mbedtls_ct_if 0x0 0x1 0x7fffffff
+mbedtls_ct_if:"0x0":"0x1":"0x7fffffff"
+
+mbedtls_ct_if 0x0 0x1 0xffffffff
+mbedtls_ct_if:"0x0":"0x1":"0xffffffff"
+
+mbedtls_ct_if 0x0 0x1 0x7fffffffffffffff
+mbedtls_ct_if:"0x0":"0x1":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0x0 0x1 0xffffffffffffffff
+mbedtls_ct_if:"0x0":"0x1":"0xffffffffffffffff"
+
+mbedtls_ct_if 0x0 0x7fffffff 0x0
+mbedtls_ct_if:"0x0":"0x7fffffff":"0x0"
+
+mbedtls_ct_if 0x0 0x7fffffff 0x1
+mbedtls_ct_if:"0x0":"0x7fffffff":"0x1"
+
+mbedtls_ct_if 0x0 0x7fffffff 0x7fffffff
+mbedtls_ct_if:"0x0":"0x7fffffff":"0x7fffffff"
+
+mbedtls_ct_if 0x0 0x7fffffff 0xffffffff
+mbedtls_ct_if:"0x0":"0x7fffffff":"0xffffffff"
+
+mbedtls_ct_if 0x0 0x7fffffff 0x7fffffffffffffff
+mbedtls_ct_if:"0x0":"0x7fffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0x0 0x7fffffff 0xffffffffffffffff
+mbedtls_ct_if:"0x0":"0x7fffffff":"0xffffffffffffffff"
+
+mbedtls_ct_if 0x0 0xffffffff 0x0
+mbedtls_ct_if:"0x0":"0xffffffff":"0x0"
+
+mbedtls_ct_if 0x0 0xffffffff 0x1
+mbedtls_ct_if:"0x0":"0xffffffff":"0x1"
+
+mbedtls_ct_if 0x0 0xffffffff 0x7fffffff
+mbedtls_ct_if:"0x0":"0xffffffff":"0x7fffffff"
+
+mbedtls_ct_if 0x0 0xffffffff 0xffffffff
+mbedtls_ct_if:"0x0":"0xffffffff":"0xffffffff"
+
+mbedtls_ct_if 0x0 0xffffffff 0x7fffffffffffffff
+mbedtls_ct_if:"0x0":"0xffffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0x0 0xffffffff 0xffffffffffffffff
+mbedtls_ct_if:"0x0":"0xffffffff":"0xffffffffffffffff"
+
+mbedtls_ct_if 0x0 0x7fffffffffffffff 0x0
+mbedtls_ct_if:"0x0":"0x7fffffffffffffff":"0x0"
+
+mbedtls_ct_if 0x0 0x7fffffffffffffff 0x1
+mbedtls_ct_if:"0x0":"0x7fffffffffffffff":"0x1"
+
+mbedtls_ct_if 0x0 0x7fffffffffffffff 0x7fffffff
+mbedtls_ct_if:"0x0":"0x7fffffffffffffff":"0x7fffffff"
+
+mbedtls_ct_if 0x0 0x7fffffffffffffff 0xffffffff
+mbedtls_ct_if:"0x0":"0x7fffffffffffffff":"0xffffffff"
+
+mbedtls_ct_if 0x0 0x7fffffffffffffff 0x7fffffffffffffff
+mbedtls_ct_if:"0x0":"0x7fffffffffffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0x0 0x7fffffffffffffff 0xffffffffffffffff
+mbedtls_ct_if:"0x0":"0x7fffffffffffffff":"0xffffffffffffffff"
+
+mbedtls_ct_if 0x0 0xffffffffffffffff 0x0
+mbedtls_ct_if:"0x0":"0xffffffffffffffff":"0x0"
+
+mbedtls_ct_if 0x0 0xffffffffffffffff 0x1
+mbedtls_ct_if:"0x0":"0xffffffffffffffff":"0x1"
+
+mbedtls_ct_if 0x0 0xffffffffffffffff 0x7fffffff
+mbedtls_ct_if:"0x0":"0xffffffffffffffff":"0x7fffffff"
+
+mbedtls_ct_if 0x0 0xffffffffffffffff 0xffffffff
+mbedtls_ct_if:"0x0":"0xffffffffffffffff":"0xffffffff"
+
+mbedtls_ct_if 0x0 0xffffffffffffffff 0x7fffffffffffffff
+mbedtls_ct_if:"0x0":"0xffffffffffffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0x0 0xffffffffffffffff 0xffffffffffffffff
+mbedtls_ct_if:"0x0":"0xffffffffffffffff":"0xffffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x0 0x0
+mbedtls_ct_if:"0xffffffffffffffff":"0x0":"0x0"
+
+mbedtls_ct_if 0xffffffffffffffff 0x0 0x1
+mbedtls_ct_if:"0xffffffffffffffff":"0x0":"0x1"
+
+mbedtls_ct_if 0xffffffffffffffff 0x0 0x7fffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x0":"0x7fffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x0 0xffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x0":"0xffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x0 0x7fffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x0":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x0 0xffffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x0":"0xffffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x1 0x0
+mbedtls_ct_if:"0xffffffffffffffff":"0x1":"0x0"
+
+mbedtls_ct_if 0xffffffffffffffff 0x1 0x1
+mbedtls_ct_if:"0xffffffffffffffff":"0x1":"0x1"
+
+mbedtls_ct_if 0xffffffffffffffff 0x1 0x7fffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x1":"0x7fffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x1 0xffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x1":"0xffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x1 0x7fffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x1":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x1 0xffffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x1":"0xffffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffff 0x0
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffff":"0x0"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffff 0x1
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffff":"0x1"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffff 0x7fffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffff":"0x7fffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffff 0xffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffff":"0xffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffff 0x7fffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffff 0xffffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffff":"0xffffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffff 0x0
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffff":"0x0"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffff 0x1
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffff":"0x1"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffff 0x7fffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffff":"0x7fffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffff 0xffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffff":"0xffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffff 0x7fffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffff 0xffffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffff":"0xffffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffffffffffff 0x0
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffffffffffff":"0x0"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffffffffffff 0x1
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffffffffffff":"0x1"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffffffffffff 0x7fffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffffffffffff":"0x7fffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffffffffffff 0xffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffffffffffff":"0xffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffffffffffff 0x7fffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffffffffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0x7fffffffffffffff 0xffffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0x7fffffffffffffff":"0xffffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffffffffffff 0x0
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffffffffffff":"0x0"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffffffffffff 0x1
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffffffffffff":"0x1"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffffffffffff 0x7fffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffffffffffff":"0x7fffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffffffffffff 0xffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffffffffffff":"0xffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffffffffffff 0x7fffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffffffffffff":"0x7fffffffffffffff"
+
+mbedtls_ct_if 0xffffffffffffffff 0xffffffffffffffff 0xffffffffffffffff
+mbedtls_ct_if:"0xffffffffffffffff":"0xffffffffffffffff":"0xffffffffffffffff"
+
+mbedtls_ct_zeroize_if 0x0 0
+mbedtls_ct_zeroize_if:"0x0":0
+
+mbedtls_ct_zeroize_if 0x0 1
+mbedtls_ct_zeroize_if:"0x0":1
+
+mbedtls_ct_zeroize_if 0x0 1024
+mbedtls_ct_zeroize_if:"0x0":1024
+
+mbedtls_ct_zeroize_if 0xffffffffffffffff 0
+mbedtls_ct_zeroize_if:"0xffffffffffffffff":0
+
+mbedtls_ct_zeroize_if 0xffffffffffffffff 1
+mbedtls_ct_zeroize_if:"0xffffffffffffffff":1
+
+mbedtls_ct_zeroize_if 0xffffffffffffffff 4
+mbedtls_ct_zeroize_if:"0xffffffffffffffff":4
+
+mbedtls_ct_zeroize_if 0xffffffffffffffff 5
+mbedtls_ct_zeroize_if:"0xffffffffffffffff":5
+
+mbedtls_ct_zeroize_if 0xffffffffffffffff 7
+mbedtls_ct_zeroize_if:"0xffffffffffffffff":7
+
+mbedtls_ct_zeroize_if 0xffffffffffffffff 8
+mbedtls_ct_zeroize_if:"0xffffffffffffffff":8
+
+mbedtls_ct_zeroize_if 0xffffffffffffffff 9
+mbedtls_ct_zeroize_if:"0xffffffffffffffff":9
+
+mbedtls_ct_zeroize_if 0xffffffffffffffff 1024
+mbedtls_ct_zeroize_if:"0xffffffffffffffff":1024
+
+mbedtls_ct_memmove_left 0 0
+mbedtls_ct_memmove_left:0:0
+
+mbedtls_ct_memmove_left 1 0
+mbedtls_ct_memmove_left:1:0
+
+mbedtls_ct_memmove_left 1 1
+mbedtls_ct_memmove_left:1:1
+
+mbedtls_ct_memmove_left 16 0
+mbedtls_ct_memmove_left:16:0
+
+mbedtls_ct_memmove_left 16 1
+mbedtls_ct_memmove_left:16:1
+
+mbedtls_ct_memmove_left 16 4
+mbedtls_ct_memmove_left:16:4
+
+mbedtls_ct_memmove_left 16 15
+mbedtls_ct_memmove_left:16:15
+
+mbedtls_ct_memmove_left 16 16
+mbedtls_ct_memmove_left:16:16
diff --git a/tests/suites/test_suite_constant_time.function b/tests/suites/test_suite_constant_time.function
index bd0eec5..0e2cfdc 100644
--- a/tests/suites/test_suite_constant_time.function
+++ b/tests/suites/test_suite_constant_time.function
@@ -8,9 +8,15 @@
  * under MSan or Valgrind will detect a non-constant-time implementation.
  */
 
+#include <stdio.h>
+
+#include <limits.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <mbedtls/bignum.h>
 #include <mbedtls/constant_time.h>
 #include <constant_time_internal.h>
-#include <constant_time_invasive.h>
 
 #include <test/constant_flow.h>
 /* END_HEADER */
@@ -26,15 +32,153 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
+void mbedtls_ct_bool(char *input)
+{
+    mbedtls_ct_uint_t v = (mbedtls_ct_uint_t) strtoull(input, NULL, 16);
+    TEST_ASSERT(errno == 0);
+
+    mbedtls_ct_condition_t expected = (v != 0) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE;
+    TEST_CF_SECRET(&v, sizeof(v));
+    TEST_EQUAL(mbedtls_ct_bool(v), expected);
+    TEST_CF_PUBLIC(&v, sizeof(v));
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mbedtls_ct_bool_xxx(char *x_str, char *y_str)
+{
+    mbedtls_ct_uint_t x = strtoull(x_str, NULL, 0);
+    mbedtls_ct_uint_t y = strtoull(y_str, NULL, 0);
+
+    mbedtls_ct_uint_t x1 = x;
+    mbedtls_ct_uint_t y1 = y;
+
+    TEST_CF_SECRET(&x, sizeof(x));
+    TEST_CF_SECRET(&y, sizeof(y));
+
+    mbedtls_ct_condition_t expected = x1 ? MBEDTLS_CT_FALSE : MBEDTLS_CT_TRUE;
+    TEST_EQUAL(mbedtls_ct_bool_not(mbedtls_ct_bool(x)), expected);
+
+    expected = x1 != y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE;
+    TEST_EQUAL(mbedtls_ct_uint_ne(x, y), expected);
+
+    expected = x1 == y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE;
+    TEST_EQUAL(mbedtls_ct_uint_eq(x, y), expected);
+
+    expected = x1 > y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE;
+    TEST_EQUAL(mbedtls_ct_uint_gt(x, y), expected);
+
+    expected = x1 < y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE;
+    TEST_EQUAL(mbedtls_ct_uint_lt(x, y), expected);
+
+    expected = x1 >= y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE;
+    TEST_EQUAL(mbedtls_ct_uint_ge(x, y), expected);
+
+    expected = x1 <= y1 ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE;
+    TEST_EQUAL(mbedtls_ct_uint_le(x, y), expected);
+
+    expected = (!!x1) ^ (!!y1) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE;
+    TEST_EQUAL(mbedtls_ct_bool_xor(mbedtls_ct_bool(x), mbedtls_ct_bool(y)), expected);
+
+    expected = (!!x1) && (!!y1) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE;
+    TEST_EQUAL(mbedtls_ct_bool_and(mbedtls_ct_bool(x), mbedtls_ct_bool(y)), expected);
+
+    expected = (!!x1) || (!!y1) ? MBEDTLS_CT_TRUE : MBEDTLS_CT_FALSE;
+    TEST_EQUAL(mbedtls_ct_bool_or(mbedtls_ct_bool(x), mbedtls_ct_bool(y)), expected);
+
+    TEST_CF_PUBLIC(&x, sizeof(x));
+    TEST_CF_PUBLIC(&y, sizeof(y));
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_BASE64_C */
+void mbedtls_ct_uchar_in_range_if(int li, int hi, int ti)
+{
+    unsigned char l = li, h = hi, t = ti;
+
+    for (unsigned x = 0; x <= 255; x++) {
+        unsigned char expected = (x >= l) && (x <= h) ? t : 0;
+
+        TEST_CF_SECRET(&x, sizeof(x));
+        TEST_CF_SECRET(&l, sizeof(l));
+        TEST_CF_SECRET(&h, sizeof(h));
+        TEST_CF_SECRET(&t, sizeof(t));
+
+        TEST_EQUAL(mbedtls_ct_uchar_in_range_if(l, h, (unsigned char) x, t), expected);
+
+        TEST_CF_PUBLIC(&x, sizeof(x));
+        TEST_CF_PUBLIC(&l, sizeof(l));
+        TEST_CF_PUBLIC(&h, sizeof(h));
+        TEST_CF_PUBLIC(&t, sizeof(t));
+    }
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mbedtls_ct_if(char *c_str, char *t_str, char *f_str)
+{
+    mbedtls_ct_condition_t c = mbedtls_ct_bool(strtoull(c_str, NULL, 16));
+    mbedtls_ct_uint_t t = (mbedtls_ct_uint_t) strtoull(t_str, NULL, 16);
+    mbedtls_ct_uint_t f = (mbedtls_ct_uint_t) strtoull(f_str, NULL, 16);
+
+    mbedtls_ct_uint_t expected = c ? t : f;
+    mbedtls_ct_uint_t expected0 = c ? t : 0;
+
+    TEST_CF_SECRET(&c, sizeof(c));
+    TEST_CF_SECRET(&t, sizeof(t));
+    TEST_CF_SECRET(&f, sizeof(f));
+
+    TEST_EQUAL(mbedtls_ct_if(c, t, f), expected);
+    TEST_EQUAL(mbedtls_ct_size_if(c, t, f), (size_t) expected);
+    TEST_EQUAL(mbedtls_ct_uint_if(c, t, f), (unsigned) expected);
+#if defined(MBEDTLS_BIGNUM_C)
+    TEST_EQUAL(mbedtls_ct_mpi_uint_if(c, t, f), (mbedtls_mpi_uint) expected);
+#endif
+
+    TEST_EQUAL(mbedtls_ct_uint_if_else_0(c, t), (unsigned) expected0);
+    TEST_EQUAL(mbedtls_ct_size_if_else_0(c, (size_t) t), (size_t) expected0);
+#if defined(MBEDTLS_BIGNUM_C)
+    TEST_EQUAL(mbedtls_ct_mpi_uint_if_else_0(c, t), (mbedtls_mpi_uint) expected0);
+#endif
+
+    TEST_CF_PUBLIC(&c, sizeof(c));
+    TEST_CF_PUBLIC(&t, sizeof(t));
+    TEST_CF_PUBLIC(&f, sizeof(f));
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PKCS1_V15:MBEDTLS_RSA_C:!MBEDTLS_RSA_ALT */
+void mbedtls_ct_zeroize_if(char *c_str, int len)
+{
+    uint8_t *buf = NULL;
+    mbedtls_ct_condition_t c = mbedtls_ct_bool(strtoull(c_str, NULL, 16));
+
+    TEST_CALLOC(buf, len);
+    for (size_t i = 0; i < (size_t) len; i++) {
+        buf[i] = 1;
+    }
+
+    TEST_CF_SECRET(&c, sizeof(c));
+    TEST_CF_SECRET(buf, len);
+    mbedtls_ct_zeroize_if(c, buf, len);
+    TEST_CF_PUBLIC(&c, sizeof(c));
+    TEST_CF_PUBLIC(buf, len);
+
+    for (size_t i = 0; i < (size_t) len; i++) {
+        TEST_EQUAL(buf[i], c != 0 ? 0 : 1);
+    }
+exit:
+    mbedtls_free(buf);
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
 void mbedtls_ct_memcmp(int same, int size, int offset)
 {
     uint8_t *a = NULL, *b = NULL;
     TEST_CALLOC(a, size + offset);
     TEST_CALLOC(b, size + offset);
 
-    TEST_CF_SECRET(a + offset, size);
-    TEST_CF_SECRET(b + offset, size);
-
     /* Construct data that matches, if same == -1, otherwise
      * same gives the number of bytes (after the initial offset)
      * that will match; after that it will differ.
@@ -49,9 +193,15 @@
     }
 
     int reference = memcmp(a + offset, b + offset, size);
+
+    TEST_CF_SECRET(a, size + offset);
+    TEST_CF_SECRET(b, size + offset);
+
     int actual = mbedtls_ct_memcmp(a + offset, b + offset, size);
-    TEST_CF_PUBLIC(a + offset, size);
-    TEST_CF_PUBLIC(b + offset, size);
+
+    TEST_CF_PUBLIC(a, size + offset);
+    TEST_CF_PUBLIC(b, size + offset);
+    TEST_CF_PUBLIC(&actual, sizeof(actual));
 
     if (same == -1 || same >= size) {
         TEST_ASSERT(reference == 0);
@@ -66,59 +216,139 @@
 }
 /* END_CASE */
 
-/* BEGIN_CASE depends_on:MBEDTLS_SSL_SOME_SUITES_USE_MAC */
-void mbedtls_ct_memcpy_if_eq(int eq, int size, int offset)
+/* BEGIN_CASE */
+void mbedtls_ct_memcpy_if(int eq, int size, int offset)
 {
-    uint8_t *src = NULL, *result = NULL, *expected = NULL;
+    uint8_t *src = NULL, *src2 = NULL, *result = NULL, *expected = NULL;
     TEST_CALLOC(src, size + offset);
+    TEST_CALLOC(src2, size + offset);
     TEST_CALLOC(result, size + offset);
     TEST_CALLOC(expected, size + offset);
 
+    /* Apply offset to result only */
     for (int i = 0; i < size + offset; i++) {
-        src[i]    = 1;
-        result[i] = 0xff;
+        src[i]      = 1;
+        result[i]   = 0xff;
         expected[i] = eq ? 1 : 0xff;
     }
 
-    int one, secret_eq;
-    TEST_CF_SECRET(&one, sizeof(one));
-    TEST_CF_SECRET(&secret_eq,  sizeof(secret_eq));
-    one = 1;
-    secret_eq = eq;
+    int secret_eq = eq;
+    TEST_CF_SECRET(&secret_eq, sizeof(secret_eq));
+    TEST_CF_SECRET(src, size + offset);
+    TEST_CF_SECRET(result, size + offset);
 
-    mbedtls_ct_memcpy_if_eq(result + offset, src, size, secret_eq, one);
+    mbedtls_ct_memcpy_if(mbedtls_ct_bool(secret_eq), result + offset, src, NULL, size);
 
-    TEST_CF_PUBLIC(&one, sizeof(one));
     TEST_CF_PUBLIC(&secret_eq, sizeof(secret_eq));
+    TEST_CF_PUBLIC(src, size + offset);
+    TEST_CF_PUBLIC(result, size + offset);
 
     TEST_MEMORY_COMPARE(expected, size, result + offset, size);
 
+
+    /* Apply offset to src only */
     for (int i = 0; i < size + offset; i++) {
         src[i]    = 1;
         result[i] = 0xff;
         expected[i] = eq ? 1 : 0xff;
     }
 
-    TEST_CF_SECRET(&one, sizeof(one));
-    TEST_CF_SECRET(&secret_eq,  sizeof(secret_eq));
-    one = 1;
-    secret_eq = eq;
+    TEST_CF_SECRET(&secret_eq, sizeof(secret_eq));
+    TEST_CF_SECRET(src, size + offset);
+    TEST_CF_SECRET(result, size + offset);
 
-    mbedtls_ct_memcpy_if_eq(result, src + offset, size, secret_eq, one);
+    mbedtls_ct_memcpy_if(mbedtls_ct_bool(secret_eq), result, src + offset, NULL, size);
 
-    TEST_CF_PUBLIC(&one, sizeof(one));
     TEST_CF_PUBLIC(&secret_eq, sizeof(secret_eq));
+    TEST_CF_PUBLIC(src, size + offset);
+    TEST_CF_PUBLIC(result, size + offset);
 
     TEST_MEMORY_COMPARE(expected, size, result, size);
+
+
+    /* Apply offset to src and src2 */
+    for (int i = 0; i < size + offset; i++) {
+        src[i]      = 1;
+        src2[i]     = 2;
+        result[i]   = 0xff;
+        expected[i] = eq ? 1 : 2;
+    }
+
+    TEST_CF_SECRET(&secret_eq, sizeof(secret_eq));
+    TEST_CF_SECRET(src, size + offset);
+    TEST_CF_SECRET(src2, size + offset);
+    TEST_CF_SECRET(result, size + offset);
+
+    mbedtls_ct_memcpy_if(mbedtls_ct_bool(secret_eq), result, src + offset, src2 + offset, size);
+
+    TEST_CF_PUBLIC(&secret_eq, sizeof(secret_eq));
+    TEST_CF_PUBLIC(src, size + offset);
+    TEST_CF_SECRET(src2, size + offset);
+    TEST_CF_PUBLIC(result, size + offset);
+
+    TEST_MEMORY_COMPARE(expected, size, result, size);
+
+
+    /* result == src == dest */
+    for (int i = 0; i < size + offset; i++) {
+        src[i]      = 2;
+        expected[i] = 2;
+    }
+
+    TEST_CF_SECRET(&secret_eq, sizeof(secret_eq));
+    TEST_CF_SECRET(src, size + offset);
+    TEST_CF_SECRET(result, size + offset);
+
+    mbedtls_ct_memcpy_if(mbedtls_ct_bool(secret_eq), src + offset, src + offset, src + offset,
+                         size);
+
+    TEST_CF_PUBLIC(&secret_eq, sizeof(secret_eq));
+    TEST_CF_PUBLIC(src, size + offset);
+    TEST_CF_PUBLIC(result, size + offset);
+
+    TEST_MEMORY_COMPARE(expected, size, src + offset, size);
 exit:
     mbedtls_free(src);
+    mbedtls_free(src2);
     mbedtls_free(result);
     mbedtls_free(expected);
 }
 /* END_CASE */
 
-/* BEGIN_CASE depends_on:MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC:MBEDTLS_TEST_HOOKS */
-void ssl_cf_memcpy_offset(int offset_min, int offset_max, int len)
+/* BEGIN_CASE depends_on:MBEDTLS_PKCS1_V15:MBEDTLS_RSA_C:!MBEDTLS_RSA_ALT */
+void mbedtls_ct_memmove_left(int len, int offset)
+{
+    size_t l = (size_t) len;
+    size_t o = (size_t) offset;
+
+    uint8_t *buf = NULL, *buf_expected = NULL;
+    TEST_CALLOC(buf, l);
+    TEST_CALLOC(buf_expected, l);
+
+    for (size_t i = 0; i < l; i++) {
+        buf[i] = (uint8_t) i;
+        buf_expected[i] = buf[i];
+    }
+
+    TEST_CF_SECRET(&o, sizeof(o));
+    TEST_CF_SECRET(buf, l);
+    mbedtls_ct_memmove_left(buf, l, o);
+    TEST_CF_PUBLIC(&o, sizeof(o));
+    TEST_CF_PUBLIC(buf, l);
+
+    if (l > 0) {
+        memmove(buf_expected, buf_expected + o, l - o);
+        memset(buf_expected + (l - o), 0, o);
+        TEST_ASSERT(memcmp(buf, buf_expected, l) == 0);
+    }
+exit:
+    mbedtls_free(buf);
+    mbedtls_free(buf_expected);
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mbedtls_ct_memcpy_offset(int offset_min, int offset_max, int len)
 {
     unsigned char *dst = NULL;
     unsigned char *src = NULL;
@@ -135,9 +365,12 @@
         mbedtls_test_set_step((int) secret);
 
         TEST_CF_SECRET(&secret, sizeof(secret));
+        TEST_CF_SECRET(src, len);
+        TEST_CF_SECRET(dst, len);
         mbedtls_ct_memcpy_offset(dst, src, secret,
                                  offset_min, offset_max, len);
         TEST_CF_PUBLIC(&secret, sizeof(secret));
+        TEST_CF_PUBLIC(src, len);
         TEST_CF_PUBLIC(dst, len);
 
         TEST_MEMORY_COMPARE(dst, len, src + secret, len);
diff --git a/tests/suites/test_suite_constant_time_hmac.function b/tests/suites/test_suite_constant_time_hmac.function
index d7bbe04..435e4b9 100644
--- a/tests/suites/test_suite_constant_time_hmac.function
+++ b/tests/suites/test_suite_constant_time_hmac.function
@@ -8,7 +8,7 @@
 #include <test/constant_flow.h>
 /* END_HEADER */
 
-/* BEGIN_CASE depends_on:MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC:MBEDTLS_TEST_HOOKS */
+/* BEGIN_CASE depends_on:MBEDTLS_SSL_SOME_SUITES_USE_MAC:MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC:MBEDTLS_TEST_HOOKS */
 void ssl_cf_hmac(int hash)
 {
     /*
diff --git a/tests/suites/test_suite_ecp.data b/tests/suites/test_suite_ecp.data
index f10e572..1002991 100644
--- a/tests/suites/test_suite_ecp.data
+++ b/tests/suites/test_suite_ecp.data
@@ -677,55 +677,55 @@
 mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"70076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c6a":0:1
 
 ECP mod p192 small (more than 192 bits, less limbs than 2 * 192 bits)
-depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
+depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED:MBEDTLS_ECP_NIST_OPTIM
 ecp_fast_mod:MBEDTLS_ECP_DP_SECP192R1:"0100000000000103010000000000010201000000000001010100000000000100"
 
 ECP mod p192 readable
-depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
+depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED:MBEDTLS_ECP_NIST_OPTIM
 ecp_fast_mod:MBEDTLS_ECP_DP_SECP192R1:"010000000000010501000000000001040100000000000103010000000000010201000000000001010100000000000100"
 
 ECP mod p192 readable with carry
-depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
+depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED:MBEDTLS_ECP_NIST_OPTIM
 ecp_fast_mod:MBEDTLS_ECP_DP_SECP192R1:"FF00000000010500FF00000000010400FF00000000010300FF00000000010200FF00000000010100FF00000000010000"
 
 ECP mod p192 random
-depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
+depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED:MBEDTLS_ECP_NIST_OPTIM
 ecp_fast_mod:MBEDTLS_ECP_DP_SECP192R1:"36CF96B45D706A0954D89E52CE5F38517A2270E0175849B6F3740151D238CCABEF921437E475881D83BB69E4AA258EBD"
 
 ECP mod p192 (from a past failure case)
-depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
+depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED:MBEDTLS_ECP_NIST_OPTIM
 ecp_fast_mod:MBEDTLS_ECP_DP_SECP192R1:"1AC2D6F96A2A425E9DD1776DD8368D4BBC86BF4964E79FEA713583BF948BBEFF0939F96FB19EC48C585BDA6A2D35C750"
 
 ECP mod p224 readable without carry
-depends_on:MBEDTLS_ECP_DP_SECP224R1_ENABLED
+depends_on:MBEDTLS_ECP_DP_SECP224R1_ENABLED:MBEDTLS_ECP_NIST_OPTIM
 ecp_fast_mod:MBEDTLS_ECP_DP_SECP224R1:"0000000D0000000C0000000B0000000A0000000900000008000000070000FF060000FF050000FF040000FF03000FF0020000FF010000FF00"
 
 ECP mod p224 readable with negative carry
-depends_on:MBEDTLS_ECP_DP_SECP224R1_ENABLED
+depends_on:MBEDTLS_ECP_DP_SECP224R1_ENABLED:MBEDTLS_ECP_NIST_OPTIM
 ecp_fast_mod:MBEDTLS_ECP_DP_SECP224R1:"0000000D0000000C0000000B0000000A00000009000000080000000700000006000000050000000400000003000000020000000100000000"
 
 ECP mod p224 readable with positive carry
-depends_on:MBEDTLS_ECP_DP_SECP224R1_ENABLED
+depends_on:MBEDTLS_ECP_DP_SECP224R1_ENABLED:MBEDTLS_ECP_NIST_OPTIM
 ecp_fast_mod:MBEDTLS_ECP_DP_SECP224R1:"0000000D0000000C0000000BFFFFFF0AFFFFFF09FFFFFF08FFFFFF070000FF060000FF050000FF040000FF03000FF0020000FF010000FF00"
 
 ECP mod p224 readable with final negative carry
-depends_on:MBEDTLS_ECP_DP_SECP224R1_ENABLED
+depends_on:MBEDTLS_ECP_DP_SECP224R1_ENABLED:MBEDTLS_ECP_NIST_OPTIM
 ecp_fast_mod:MBEDTLS_ECP_DP_SECP224R1:"FF00000D0000000C0000000B0000000A00000009000000080000000700000006000000050000000400000003000000020000000100000000"
 
 ECP mod p521 very small
-depends_on:MBEDTLS_ECP_DP_SECP521R1_ENABLED
+depends_on:MBEDTLS_ECP_DP_SECP521R1_ENABLED:MBEDTLS_ECP_NIST_OPTIM
 ecp_fast_mod:MBEDTLS_ECP_DP_SECP521R1:"01"
 
 ECP mod p521 small (522 bits)
-depends_on:MBEDTLS_ECP_DP_SECP521R1_ENABLED
+depends_on:MBEDTLS_ECP_DP_SECP521R1_ENABLED:MBEDTLS_ECP_NIST_OPTIM
 ecp_fast_mod:MBEDTLS_ECP_DP_SECP521R1:"030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
 
 ECP mod p521 readable
-depends_on:MBEDTLS_ECP_DP_SECP521R1_ENABLED
+depends_on:MBEDTLS_ECP_DP_SECP521R1_ENABLED:MBEDTLS_ECP_NIST_OPTIM
 ecp_fast_mod:MBEDTLS_ECP_DP_SECP521R1:"03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
 
 ECP mod p521 readable with carry
-depends_on:MBEDTLS_ECP_DP_SECP521R1_ENABLED
+depends_on:MBEDTLS_ECP_DP_SECP521R1_ENABLED:MBEDTLS_ECP_NIST_OPTIM
 ecp_fast_mod:MBEDTLS_ECP_DP_SECP521R1:"03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"
 
 ECP test vectors secp192r1 rfc 5114
diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function
index cf16ae9..619a5dd 100644
--- a/tests/suites/test_suite_ecp.function
+++ b/tests/suites/test_suite_ecp.function
@@ -1622,7 +1622,7 @@
     TEST_EQUAL(0, mbedtls_mpi_mod_random(&rX, 1, &m,
                                          mbedtls_test_rnd_std_rand, NULL));
 
-    TEST_ASSERT(mbedtls_mpi_core_lt_ct(rX.p, m.p, limbs) == 1);
+    TEST_ASSERT(mbedtls_mpi_core_lt_ct(rX.p, m.p, limbs) == MBEDTLS_CT_TRUE);
 
 exit:
     mbedtls_mpi_mod_modulus_free(&m);
diff --git a/tests/suites/test_suite_md.function b/tests/suites/test_suite_md.function
index fadb362..866ff58 100644
--- a/tests/suites/test_suite_md.function
+++ b/tests/suites/test_suite_md.function
@@ -2,6 +2,9 @@
 #include "mbedtls/md.h"
 #include "md_psa.h"
 
+#include "mbedtls/oid.h"
+#include "mbedtls/asn1.h"
+
 #define MD_PSA(md, psa) \
     TEST_EQUAL(mbedtls_md_psa_alg_from_type(md), psa);  \
     TEST_EQUAL(mbedtls_md_type_from_psa_alg(psa), md);
@@ -33,6 +36,24 @@
         TEST_EQUAL(0, mbedtls_md_starts(&ctx));
         TEST_EQUAL(0, mbedtls_md_finish(&ctx, out));
         mbedtls_md_free(&ctx);
+
+#if defined(MBEDTLS_PSA_CRYPTO_C)
+        /* Ensure that we can convert to and from a psa_algorithm_t */
+        psa_algorithm_t p = mbedtls_md_psa_alg_from_type(*md_type_ptr);
+        TEST_ASSERT(p != PSA_ALG_NONE);
+        TEST_EQUAL(*md_type_ptr, mbedtls_md_type_from_psa_alg(p));
+#endif
+
+#if defined(MBEDTLS_OID_C)
+        mbedtls_asn1_buf asn1;
+        /* Check that we have an OID definition */
+        TEST_EQUAL(mbedtls_oid_get_oid_by_md((mbedtls_md_type_t) *md_type_ptr,
+                                             (const char **) &asn1.p, &asn1.len), 0);
+        /* Check that this OID definition maps back to the correct mbedtls_md_type_t */
+        mbedtls_md_type_t m;
+        TEST_EQUAL(mbedtls_oid_get_md_alg(&asn1, &m), 0);
+        TEST_EQUAL(m, *md_type_ptr);
+#endif
     }
 
 exit:
@@ -406,7 +427,6 @@
 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);
-    TEST_ASSERT(md_info != NULL);
     mbedtls_md_context_t ctx1, ctx2;
 
     /* Intentionally no PSA init here! (Will be done later.) */
@@ -414,6 +434,8 @@
     mbedtls_md_init(&ctx1);
     mbedtls_md_init(&ctx2);
 
+    TEST_ASSERT(md_info != NULL);
+
     /* Before PSA crypto init */
     TEST_EQUAL(pre_psa_ret, mbedtls_md_setup(&ctx1, md_info, 0));
     TEST_EQUAL(pre_psa_ret, mbedtls_md_setup(&ctx2, md_info, 0));
diff --git a/tests/suites/test_suite_md.psa.data b/tests/suites/test_suite_md.psa.data
index 5266f18..cd24add 100644
--- a/tests/suites/test_suite_md.psa.data
+++ b/tests/suites/test_suite_md.psa.data
@@ -85,3 +85,51 @@
 PSA dispatch SHA512 legacy+driver
 depends_on:MBEDTLS_SHA512_C:MBEDTLS_MD_SHA512_VIA_PSA
 md_psa_dynamic_dispatch:MBEDTLS_MD_SHA512:0:MBEDTLS_MD_ENGINE_PSA
+
+PSA dispatch SHA3-224 legacy only
+depends_on:MBEDTLS_SHA3_224_C:!MBEDTLS_MD_SHA3_224_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA3_224:0:MBEDTLS_MD_ENGINE_LEGACY
+
+PSA dispatch SHA3-224 driver only
+depends_on:!MBEDTLS_SHA3_224_C:MBEDTLS_MD_SHA3_224_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA3_224:MBEDTLS_ERR_MD_BAD_INPUT_DATA:MBEDTLS_MD_ENGINE_PSA
+
+PSA dispatch SHA3-224 legacy+driver
+depends_on:MBEDTLS_SHA3_224_C:MBEDTLS_MD_SHA3_224_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA3_224:0:MBEDTLS_MD_ENGINE_PSA
+
+PSA dispatch SHA3-256 legacy only
+depends_on:MBEDTLS_SHA3_256_C:!MBEDTLS_MD_SHA3_256_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA3_256:0:MBEDTLS_MD_ENGINE_LEGACY
+
+PSA dispatch SHA3-256 driver only
+depends_on:!MBEDTLS_SHA3_256_C:MBEDTLS_MD_SHA3_256_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA3_256:MBEDTLS_ERR_MD_BAD_INPUT_DATA:MBEDTLS_MD_ENGINE_PSA
+
+PSA dispatch SHA3-256 legacy+driver
+depends_on:MBEDTLS_SHA3_256_C:MBEDTLS_MD_SHA3_256_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA3_256:0:MBEDTLS_MD_ENGINE_PSA
+
+PSA dispatch SHA3-384 legacy only
+depends_on:MBEDTLS_SHA3_384_C:!MBEDTLS_MD_SHA3_384_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA3_384:0:MBEDTLS_MD_ENGINE_LEGACY
+
+PSA dispatch SHA3-384 driver only
+depends_on:!MBEDTLS_SHA3_384_C:MBEDTLS_MD_SHA3_384_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA3_384:MBEDTLS_ERR_MD_BAD_INPUT_DATA:MBEDTLS_MD_ENGINE_PSA
+
+PSA dispatch SHA3-384 legacy+driver
+depends_on:MBEDTLS_SHA3_384_C:MBEDTLS_MD_SHA3_384_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA3_384:0:MBEDTLS_MD_ENGINE_PSA
+
+PSA dispatch SHA3-512 legacy only
+depends_on:MBEDTLS_SHA3_512_C:!MBEDTLS_MD_SHA3_512_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA3_512:0:MBEDTLS_MD_ENGINE_LEGACY
+
+PSA dispatch SHA3-512 driver only
+depends_on:!MBEDTLS_SHA3_512_C:MBEDTLS_MD_SHA3_512_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA3_512:MBEDTLS_ERR_MD_BAD_INPUT_DATA:MBEDTLS_MD_ENGINE_PSA
+
+PSA dispatch SHA3-512 legacy+driver
+depends_on:MBEDTLS_SHA3_512_C:MBEDTLS_MD_SHA3_512_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA3_512:0:MBEDTLS_MD_ENGINE_PSA
diff --git a/tests/suites/test_suite_oid.data b/tests/suites/test_suite_oid.data
index 00f6e0b..f8f1d43 100644
--- a/tests/suites/test_suite_oid.data
+++ b/tests/suites/test_suite_oid.data
@@ -82,6 +82,22 @@
 depends_on:MBEDTLS_MD_CAN_SHA512
 oid_get_md_alg_id:"608648016503040203":MBEDTLS_MD_SHA512
 
+OID hash id - id-sha3-224
+depends_on:MBEDTLS_MD_CAN_SHA3_224
+oid_get_md_alg_id:"608648016503040207":MBEDTLS_MD_SHA3_224
+
+OID hash id - id-sha3-256
+depends_on:MBEDTLS_MD_CAN_SHA3_256
+oid_get_md_alg_id:"608648016503040208":MBEDTLS_MD_SHA3_256
+
+OID hash id - id-sha3-384
+depends_on:MBEDTLS_MD_CAN_SHA3_384
+oid_get_md_alg_id:"608648016503040209":MBEDTLS_MD_SHA3_384
+
+OID hash id - id-sha3-512
+depends_on:MBEDTLS_MD_CAN_SHA3_512
+oid_get_md_alg_id:"60864801650304020a":MBEDTLS_MD_SHA3_512
+
 OID hash id - id-ripemd160
 depends_on:MBEDTLS_MD_CAN_RIPEMD160
 oid_get_md_alg_id:"2b24030201":MBEDTLS_MD_RIPEMD160
@@ -185,3 +201,43 @@
 
 OID from numeric string - OID with overflowing subidentifier
 oid_from_numeric_string:"2.4294967216":MBEDTLS_ERR_ASN1_INVALID_DATA:""
+
+mbedtls_oid_get_md_hmac - RIPEMD160
+depends_on:MBEDTLS_MD_CAN_RIPEMD160
+mbedtls_oid_get_md_hmac:"2B06010505080104":MBEDTLS_MD_RIPEMD160
+
+mbedtls_oid_get_md_hmac - SHA1
+depends_on:MBEDTLS_MD_CAN_SHA1
+mbedtls_oid_get_md_hmac:"2A864886F70D0207":MBEDTLS_MD_SHA1
+
+mbedtls_oid_get_md_hmac - SHA224
+depends_on:MBEDTLS_MD_CAN_SHA224
+mbedtls_oid_get_md_hmac:"2A864886F70D0208":MBEDTLS_MD_SHA224
+
+mbedtls_oid_get_md_hmac - SHA256
+depends_on:MBEDTLS_MD_CAN_SHA256
+mbedtls_oid_get_md_hmac:"2A864886F70D0209":MBEDTLS_MD_SHA256
+
+mbedtls_oid_get_md_hmac - SHA384
+depends_on:MBEDTLS_MD_CAN_SHA384
+mbedtls_oid_get_md_hmac:"2A864886F70D020A":MBEDTLS_MD_SHA384
+
+mbedtls_oid_get_md_hmac - SHA512
+depends_on:MBEDTLS_MD_CAN_SHA512
+mbedtls_oid_get_md_hmac:"2A864886F70D020B":MBEDTLS_MD_SHA512
+
+mbedtls_oid_get_md_hmac - SHA3_224
+depends_on:MBEDTLS_MD_CAN_SHA3_224
+mbedtls_oid_get_md_hmac:"60864801650304020D":MBEDTLS_MD_SHA3_224
+
+mbedtls_oid_get_md_hmac - SHA3_256
+depends_on:MBEDTLS_MD_CAN_SHA3_256
+mbedtls_oid_get_md_hmac:"60864801650304020E":MBEDTLS_MD_SHA3_256
+
+mbedtls_oid_get_md_hmac - SHA3_384
+depends_on:MBEDTLS_MD_CAN_SHA3_384
+mbedtls_oid_get_md_hmac:"60864801650304020F":MBEDTLS_MD_SHA3_384
+
+mbedtls_oid_get_md_hmac - SHA3_512
+depends_on:MBEDTLS_MD_CAN_SHA3_512
+mbedtls_oid_get_md_hmac:"608648016503040210":MBEDTLS_MD_SHA3_512
diff --git a/tests/suites/test_suite_oid.function b/tests/suites/test_suite_oid.function
index 3adc6af..337f843 100644
--- a/tests/suites/test_suite_oid.function
+++ b/tests/suites/test_suite_oid.function
@@ -97,6 +97,29 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
+void mbedtls_oid_get_md_hmac(data_t *oid, int exp_md_id)
+{
+    mbedtls_asn1_buf md_oid = { 0, 0, NULL };
+    int ret;
+    mbedtls_md_type_t md_id = 0;
+
+    md_oid.tag = MBEDTLS_ASN1_OID;
+    md_oid.p = oid->x;
+    md_oid.len = oid->len;
+
+    ret = mbedtls_oid_get_md_hmac(&md_oid, &md_id);
+
+    if (exp_md_id < 0) {
+        TEST_ASSERT(ret == MBEDTLS_ERR_OID_NOT_FOUND);
+        TEST_ASSERT(md_id == 0);
+    } else {
+        TEST_ASSERT(ret == 0);
+        TEST_ASSERT((mbedtls_md_type_t) exp_md_id == md_id);
+    }
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
 void oid_get_numeric_string(data_t *oid, int error_ret, char *result_str)
 {
     char buf[256];
diff --git a/tests/suites/test_suite_pkparse.function b/tests/suites/test_suite_pkparse.function
index 7947d3c..0d9a0c8 100644
--- a/tests/suites/test_suite_pkparse.function
+++ b/tests/suites/test_suite_pkparse.function
@@ -8,7 +8,7 @@
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
- * depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_BIGNUM_C
+ * depends_on:MBEDTLS_PK_PARSE_C
  * END_DEPENDENCIES
  */
 
diff --git a/tests/suites/test_suite_pkwrite.function b/tests/suites/test_suite_pkwrite.function
index e1be52e..37c06c8 100644
--- a/tests/suites/test_suite_pkwrite.function
+++ b/tests/suites/test_suite_pkwrite.function
@@ -144,7 +144,7 @@
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
- * depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_PK_WRITE_C:MBEDTLS_BIGNUM_C:MBEDTLS_FS_IO
+ * depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_PK_WRITE_C:MBEDTLS_FS_IO
  * END_DEPENDENCIES
  */
 
diff --git a/tests/suites/test_suite_platform.data b/tests/suites/test_suite_platform.data
index 4276b8f..4d57450 100644
--- a/tests/suites/test_suite_platform.data
+++ b/tests/suites/test_suite_platform.data
@@ -4,3 +4,6 @@
 
 Time: get seconds
 time_get_seconds:
+
+Check mbedtls_calloc overallocation
+check_mbedtls_calloc_overallocation:SIZE_MAX/2:SIZE_MAX/2
diff --git a/tests/suites/test_suite_platform.function b/tests/suites/test_suite_platform.function
index 61681b8..c65d011 100644
--- a/tests/suites/test_suite_platform.function
+++ b/tests/suites/test_suite_platform.function
@@ -120,3 +120,17 @@
     goto exit;
 }
 /* END_CASE */
+
+/* BEGIN_CASE */
+void check_mbedtls_calloc_overallocation(intmax_t num, intmax_t size)
+{
+    unsigned char *buf;
+    buf = mbedtls_calloc((size_t) num, (size_t) size);
+    /* Dummy usage of the pointer to prevent optimizing it */
+    mbedtls_printf("calloc pointer : %p\n", buf);
+    TEST_ASSERT(buf == NULL);
+
+exit:
+    mbedtls_free(buf);
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data
index e03bac8..410ae64 100644
--- a/tests/suites/test_suite_psa_crypto.data
+++ b/tests/suites/test_suite_psa_crypto.data
@@ -5543,6 +5543,82 @@
 depends_on:PSA_WANT_ALG_PBKDF2_HMAC:PSA_WANT_ALG_SHA_256
 derive_input_invalid_cost:PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_256):PSA_VENDOR_PBKDF2_MAX_ITERATIONS+1ULL
 
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, good case, direct output
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_input:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:INPUT_INTEGER:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:PSA_KEY_TYPE_NONE:"":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:PSA_KEY_TYPE_PASSWORD:"706173737764":PSA_SUCCESS:PSA_KEY_TYPE_NONE:PSA_SUCCESS
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, good case, key output
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_input:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:INPUT_INTEGER:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:PSA_KEY_TYPE_NONE:"":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:PSA_KEY_TYPE_PASSWORD:"706173737764":PSA_SUCCESS:PSA_KEY_TYPE_DERIVE:PSA_SUCCESS
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, good case, DERIVE key as password, key output
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_input:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:INPUT_INTEGER:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:PSA_KEY_TYPE_NONE:"":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:PSA_KEY_TYPE_DERIVE:"706173737764":PSA_SUCCESS:PSA_KEY_TYPE_DERIVE:PSA_SUCCESS
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, salt missing
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_input:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:INPUT_INTEGER:"01":PSA_SUCCESS:0:UNUSED:"":UNUSED:PSA_KEY_DERIVATION_INPUT_PASSWORD:PSA_KEY_TYPE_PASSWORD:"706173737764":PSA_ERROR_BAD_STATE:PSA_KEY_TYPE_NONE:PSA_ERROR_BAD_STATE
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, password missing
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_input:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:INPUT_INTEGER:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:PSA_KEY_TYPE_NONE:"73616c74":PSA_SUCCESS:0:UNUSED:"":UNUSED:PSA_KEY_TYPE_NONE:PSA_ERROR_BAD_STATE
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, salt and password before cost
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_input:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_SALT:PSA_KEY_TYPE_NONE:"73616c74":PSA_ERROR_BAD_STATE:PSA_KEY_DERIVATION_INPUT_PASSWORD:PSA_KEY_TYPE_PASSWORD:"706173737764":PSA_ERROR_BAD_STATE:PSA_KEY_DERIVATION_INPUT_COST:INPUT_INTEGER:"01":PSA_ERROR_INVALID_ARGUMENT:PSA_KEY_TYPE_NONE:PSA_ERROR_BAD_STATE
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, password before cost
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_input:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_PASSWORD:PSA_KEY_TYPE_PASSWORD:"706173737764":PSA_ERROR_BAD_STATE:PSA_KEY_DERIVATION_INPUT_COST:INPUT_INTEGER:"01":PSA_ERROR_INVALID_ARGUMENT:PSA_KEY_DERIVATION_INPUT_SALT:PSA_KEY_TYPE_NONE:"73616c74":PSA_ERROR_BAD_STATE:PSA_KEY_TYPE_NONE:PSA_ERROR_BAD_STATE
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, password bad key type
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_input:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:INPUT_INTEGER:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:PSA_KEY_TYPE_NONE:"73616c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:PSA_KEY_TYPE_RAW_DATA:"706173737764":PSA_ERROR_INVALID_ARGUMENT:PSA_KEY_TYPE_NONE:PSA_ERROR_BAD_STATE
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, direct password, direct output
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_input:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:INPUT_INTEGER:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:PSA_KEY_TYPE_NONE:"73616c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:PSA_KEY_TYPE_NONE:"706173737764":PSA_SUCCESS:PSA_KEY_TYPE_NONE:PSA_SUCCESS
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, direct empty password, direct output
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_input:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:INPUT_INTEGER:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:PSA_KEY_TYPE_NONE:"73616c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:PSA_KEY_TYPE_NONE:"":PSA_SUCCESS:PSA_KEY_TYPE_NONE:PSA_SUCCESS
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, direct password, key output
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_input:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:INPUT_INTEGER:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:PSA_KEY_TYPE_NONE:"73616c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:PSA_KEY_TYPE_NONE:"706173737764":PSA_SUCCESS:PSA_KEY_TYPE_RAW_DATA:PSA_ERROR_NOT_PERMITTED
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, DERIVE key as salt
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_input:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:INPUT_INTEGER:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:PSA_KEY_TYPE_DERIVE:"73616c74":PSA_ERROR_INVALID_ARGUMENT:PSA_KEY_DERIVATION_INPUT_PASSWORD:PSA_KEY_TYPE_NONE:"706173737764":PSA_ERROR_BAD_STATE:PSA_KEY_TYPE_NONE:PSA_ERROR_BAD_STATE
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, duplicate cost step
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_input:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:INPUT_INTEGER:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_COST:INPUT_INTEGER:"01":PSA_ERROR_BAD_STATE:PSA_KEY_DERIVATION_INPUT_PASSWORD:PSA_KEY_TYPE_NONE:"706173737764":PSA_ERROR_BAD_STATE:PSA_KEY_TYPE_NONE:PSA_ERROR_BAD_STATE
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, duplicate salt step
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_input:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:INPUT_INTEGER:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:PSA_KEY_TYPE_NONE:"7361":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:PSA_KEY_TYPE_NONE:"6c74":PSA_SUCCESS:PSA_KEY_TYPE_NONE:PSA_ERROR_BAD_STATE
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, reject secret step
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_input:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_SECRET:PSA_KEY_TYPE_NONE:"":PSA_ERROR_INVALID_ARGUMENT:PSA_KEY_DERIVATION_INPUT_SALT:PSA_KEY_TYPE_NONE:"73616c74":PSA_ERROR_BAD_STATE:PSA_KEY_DERIVATION_INPUT_PASSWORD:PSA_KEY_TYPE_NONE:"706173737764":PSA_ERROR_BAD_STATE:PSA_KEY_TYPE_NONE:PSA_ERROR_BAD_STATE
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, reject label step
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_input:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_LABEL:PSA_KEY_TYPE_NONE:"":PSA_ERROR_INVALID_ARGUMENT:PSA_KEY_DERIVATION_INPUT_SALT:PSA_KEY_TYPE_NONE:"73616c74":PSA_ERROR_BAD_STATE:PSA_KEY_DERIVATION_INPUT_PASSWORD:PSA_KEY_TYPE_NONE:"706173737764":PSA_ERROR_BAD_STATE:PSA_KEY_TYPE_NONE:PSA_ERROR_BAD_STATE
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, reject seed step
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_input:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_SEED:PSA_KEY_TYPE_NONE:"":PSA_ERROR_INVALID_ARGUMENT:PSA_KEY_DERIVATION_INPUT_SALT:PSA_KEY_TYPE_NONE:"73616c74":PSA_ERROR_BAD_STATE:PSA_KEY_DERIVATION_INPUT_PASSWORD:PSA_KEY_TYPE_NONE:"706173737764":PSA_ERROR_BAD_STATE:PSA_KEY_TYPE_NONE:PSA_ERROR_BAD_STATE
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, reject zero input cost
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_input:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:INPUT_INTEGER:"00":PSA_ERROR_INVALID_ARGUMENT:PSA_KEY_DERIVATION_INPUT_SALT:PSA_KEY_TYPE_NONE:"73616c74":PSA_ERROR_BAD_STATE:PSA_KEY_DERIVATION_INPUT_PASSWORD:PSA_KEY_TYPE_NONE:"706173737764":PSA_ERROR_BAD_STATE:PSA_KEY_TYPE_NONE:PSA_ERROR_BAD_STATE
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, reject cost greater than PSA_VENDOR_PBKDF2_MAX_ITERATIONS
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_input_invalid_cost:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_VENDOR_PBKDF2_MAX_ITERATIONS+1ULL
+
 PSA key derivation over capacity: HKDF
 depends_on:PSA_WANT_ALG_HKDF:PSA_WANT_ALG_SHA_256
 derive_over_capacity:PSA_ALG_HKDF(PSA_ALG_SHA_256)
@@ -6315,7 +6391,7 @@
 
 PSA key derivation: PBKDF2-HMAC(SHA-256), RFC7914 #1, password as bytes, derive key
 depends_on:PSA_WANT_ALG_PBKDF2_HMAC:PSA_WANT_ALG_SHA_256
-derive_output:PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_256):PSA_KEY_DERIVATION_INPUT_COST:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"73616c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:"706173737764":PSA_SUCCESS:0:"":PSA_SUCCESS:"":64:"":"":0:0:1
+derive_output:PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_256):PSA_KEY_DERIVATION_INPUT_COST:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"73616c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:"706173737764":PSA_SUCCESS:0:"":PSA_SUCCESS:"":64:"55ac046e56e3089fec1691c22544b605f94185216dde0465e68b9d57c20dacbc49ca9cccf179b645991664b39d77ef317c71b845b1e30bd509112041d3a19783":"":0:0:1
 
 PSA key derivation: PBKDF2-HMAC(SHA-1), RFC6070 #1, salt before cost
 depends_on:PSA_WANT_ALG_PBKDF2_HMAC:PSA_WANT_ALG_SHA_1
@@ -6325,6 +6401,64 @@
 depends_on:PSA_WANT_ALG_PBKDF2_HMAC:PSA_WANT_ALG_SHA_1
 derive_output:PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_1):PSA_KEY_DERIVATION_INPUT_COST:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"73616c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:"70617373776f7264":PSA_SUCCESS:0:"":PSA_SUCCESS:"":20:"0c60c80f961f0e71f3a9b524af6012062fe037a6":"00":0:1:0
 
+#The following test vectors were generated by a python script. Details can be found in the commit message.
+#The input cost, salt and password are the same as PBKDF2-HMAC test vectors
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, Test Vector 1, 20+0
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_output:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"73616c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:"70617373776f7264":PSA_SUCCESS:0:"":PSA_SUCCESS:"":20:"1b72f6419173a06e27777606a315876ec71227de":"":0:1:0
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, Test Vector 1, 10+10
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_output:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"73616c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:"70617373776f7264":PSA_SUCCESS:0:"":PSA_SUCCESS:"":20:"1b72f6419173a06e2777":"7606a315876ec71227de":0:1:0
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, Test Vector 1, 0+20
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_output:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"73616c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:"70617373776f7264":PSA_SUCCESS:0:"":PSA_SUCCESS:"":20:"":"1b72f6419173a06e27777606a315876ec71227de":0:1:0
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, Test Vector 2
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_output:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:"02":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"73616c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:"70617373776f7264":PSA_SUCCESS:0:"":PSA_SUCCESS:"":20:"160597e28021fb3dd9cf088b007b688360fed438":"":0:1:0
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, Test Vector 3
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_output:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:"1000":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"73616c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:"70617373776f7264":PSA_SUCCESS:0:"":PSA_SUCCESS:"":20:"38ba9795fe87e47d519eacb77e82e35daa795870":"":0:1:0
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, Test Vector 4
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_output:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:"1000":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"73616c7453414c5473616c7453414c5473616c7453414c5473616c7453414c5473616c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:"70617373776f726450415353574f524470617373776f7264":PSA_SUCCESS:0:"":PSA_SUCCESS:"":25:"25e7c43283d2e98cb6d9537a783e93153a45595a876779e00d":"":0:1:0
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, Test Vector 5
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_output:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:"1000":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"7361006c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:"7061737300776f7264":PSA_SUCCESS:0:"":PSA_SUCCESS:"":16:"3d2828c5a437d781e7733ca353c40579":"":0:1:0
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, Test Vector 6
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_output:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"73616c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:"706173737764":PSA_SUCCESS:0:"":PSA_SUCCESS:"":64:"28e288c6345bb5ecf7ca70274208a3ba0f1148b5868537d5e09d3ee6813b1f524d9ecbf864eb814a46cda50ad5ec4c0dc03578c6c5fb4a3f9880deb5cab537e4":"":0:1:0
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, empty direct password
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_output:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:"1000":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"73616c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:"":PSA_SUCCESS:0:"":PSA_SUCCESS:"":16:"db00f3996d041b415eb273362d8c8c83":"":0:0:0
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, 16 byte password
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_output:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:"1000":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"73616c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:"70617373776f726470617373776f7264":PSA_SUCCESS:0:"":PSA_SUCCESS:"":16:"c4c112c6e1e3b8757640603dec78825f":"":0:1:0
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, Test vector 1, salt in two step
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_output:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"7361":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"6c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:"70617373776f7264":PSA_SUCCESS:"":20:"1b72f6419173a06e27777606a315876ec71227de":"":0:1:0
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, Test vector 1, password as key, derive key
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_output:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"73616c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:"70617373776f7264":PSA_SUCCESS:0:"":PSA_SUCCESS:"":20:"1b72f6419173a06e27777606a315876ec71227de":"":0:1:1
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, Test vector 1, password as bytes
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_output:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"73616c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:"70617373776f7264":PSA_SUCCESS:0:"":PSA_SUCCESS:"":20:"1b72f6419173a06e27777606a315876ec71227de":"":0:0:0
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, Test vector 1, password as bytes, derive key
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_output:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:"01":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"73616c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:"70617373776f7264":PSA_SUCCESS:0:"":PSA_SUCCESS:"":20:"1b72f6419173a06e27777606a315876ec71227de":"":0:0:1
+
 PSA key derivation: ECJPAKE to PMS, no input
 depends_on:PSA_WANT_ALG_SHA_256
 derive_ecjpake_to_pms:"":PSA_ERROR_INVALID_ARGUMENT:PSA_KEY_DERIVATION_INPUT_SECRET:32:PSA_SUCCESS:"":PSA_ERROR_INVALID_ARGUMENT
diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function
index 01f20af..2396590 100644
--- a/tests/suites/test_suite_psa_crypto.function
+++ b/tests/suites/test_suite_psa_crypto.function
@@ -8784,7 +8784,7 @@
                         }
                         break;
                     default:
-                        TEST_ASSERT(!"default case not supported");
+                        TEST_FAIL("default case not supported");
                         break;
                 }
                 break;
@@ -8834,7 +8834,7 @@
                                        key_agreement_peer_key->len), statuses[i]);
                         break;
                     default:
-                        TEST_ASSERT(!"default case not supported");
+                        TEST_FAIL("default case not supported");
                         break;
                 }
 
@@ -9826,7 +9826,7 @@
             break;
 
         default:
-            TEST_ASSERT(!"generation_method not implemented in test");
+            TEST_FAIL("generation_method not implemented in test");
             break;
     }
     psa_reset_key_attributes(&attributes);
diff --git a/tests/suites/test_suite_psa_crypto.pbkdf2.data b/tests/suites/test_suite_psa_crypto.pbkdf2.data
new file mode 100644
index 0000000..3b8e7e0
--- /dev/null
+++ b/tests/suites/test_suite_psa_crypto.pbkdf2.data
@@ -0,0 +1,16 @@
+PSA key derivation: PBKDF2-HMAC(SHA-1), RFC6070 #4
+depends_on:PSA_WANT_ALG_PBKDF2_HMAC:PSA_WANT_ALG_SHA_1
+derive_output:PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_1):PSA_KEY_DERIVATION_INPUT_COST:"01000000":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"73616c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:"70617373776f7264":PSA_SUCCESS:0:"":PSA_SUCCESS:"":20:"eefe3d61cd4da4e4e9945b3d6ba2158c2634e984":"":0:1:0
+
+PSA key derivation: PBKDF2-HMAC(SHA-256), RFC7914 #2
+depends_on:PSA_WANT_ALG_PBKDF2_HMAC:PSA_WANT_ALG_SHA_256
+derive_output:PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_256):PSA_KEY_DERIVATION_INPUT_COST:"013880":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"4e61436c":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:"50617373776f7264":PSA_SUCCESS:0:"":PSA_SUCCESS:"":64:"4ddcd8f60b98be21830cee5ef22701f9641a4418d04c0414aeff08876b34ab56a1d425a1225833549adb841b51c9b3176a272bdebba1d078478f62b397f33c8d":"":0:1:0
+
+# For PBKDF2_AES_CMAC_PRF_128 the output for the test vectors was generated using a python script. Refer commit message for details.
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, inputs from RFC6070 #4
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_output:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:"01000000":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"73616c74":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:"70617373776f7264":PSA_SUCCESS:0:"":PSA_SUCCESS:"":20:"c19b71d2daf483abc9e04fbc78928b4204398d1e":"":0:1:0
+
+PSA key derivation: PBKDF2-AES-CMAC-PRF-128, inputs from RFC7914 #2
+depends_on:PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_WANT_ALG_CMAC:PSA_WANT_KEY_TYPE_AES
+derive_output:PSA_ALG_PBKDF2_AES_CMAC_PRF_128:PSA_KEY_DERIVATION_INPUT_COST:"013880":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SALT:"4e61436c":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_PASSWORD:"50617373776f7264":PSA_SUCCESS:0:"":PSA_SUCCESS:"":64:"3298e89bc3560e61b59aef2c104f93380b5fa26e2e011cb5ac5895fcd5a3bd5a92e617d7cae020fa2c6ef895182d9ffa0cc8f9c22778beb02856127719d95570":"":0:1:0
diff --git a/tests/suites/test_suite_psa_crypto_driver_wrappers.function b/tests/suites/test_suite_psa_crypto_driver_wrappers.function
index 98a7662..1d96f72 100644
--- a/tests/suites/test_suite_psa_crypto_driver_wrappers.function
+++ b/tests/suites/test_suite_psa_crypto_driver_wrappers.function
@@ -466,7 +466,7 @@
         TEST_EQUAL(buf[0], 0x00);
         /* The rest is too hard to check */
     } else {
-        TEST_ASSERT(!"Encryption result sanity check not implemented for RSA algorithm");
+        TEST_FAIL("Encryption result sanity check not implemented for RSA algorithm");
     }
 #endif /* MBEDTLS_BIGNUM_C */
 
@@ -2755,7 +2755,7 @@
             {
                 (void) modulus;
                 (void) private_exponent;
-                TEST_ASSERT(!"Encryption sanity checks not implemented for this key type");
+                TEST_FAIL("Encryption sanity checks not implemented for this key type");
             }
         }
     }
diff --git a/tests/suites/test_suite_psa_crypto_hash.data b/tests/suites/test_suite_psa_crypto_hash.data
index 9f51339..0a5f876 100644
--- a/tests/suites/test_suite_psa_crypto_hash.data
+++ b/tests/suites/test_suite_psa_crypto_hash.data
@@ -158,6 +158,70 @@
 depends_on:PSA_WANT_ALG_SHA_512
 hash_finish:PSA_ALG_SHA_512:"990d1ae71a62d7bda9bfdaa1762a68d296eee72a4cd946f287a898fbabc002ea941fd8d4d991030b4d27a637cce501a834bb95eab1b7889a3e784c7968e67cbf552006b206b68f76d9191327524fcc251aeb56af483d10b4e0c6c5e599ee8c0fe4faeca8293844a8547c6a9a90d093f2526873a19ad4a5e776794c68c742fb834793d2dfcb7fea46c63af4b70fd11cb6e41834e72ee40edb067b292a794990c288d5007e73f349fb383af6a756b8301ad6e5e0aa8cd614399bb3a452376b1575afa6bdaeaafc286cb064bb91edef97c632b6c1113d107fa93a0905098a105043c2f05397f702514439a08a9e5ddc196100721d45c8fc17d2ed659376f8a00bd5cb9a0860e26d8a29d8d6aaf52de97e9346033d6db501a35dbbaf97c20b830cd2d18c2532f3a59cc497ee64c0e57d8d060e5069b28d86edf1adcf59144b221ce3ddaef134b3124fbc7dd000240eff0f5f5f41e83cd7f5bb37c9ae21953fe302b0f6e8b68fa91c6ab99265c64b2fd9cd4942be04321bb5d6d71932376c6f2f88e02422ba6a5e2cb765df93fd5dd0728c6abdaf03bce22e0678a544e2c3636f741b6f4447ee58a8fc656b43ef817932176adbfc2e04b2c812c273cd6cbfa4098f0be036a34221fa02643f5ee2e0b38135f2a18ecd2f16ebc45f8eb31b8ab967a1567ee016904188910861ca1fa205c7adaa194b286893ffe2f4fbe0384c2aef72a4522aeafd3ebc71f9db71eeeef86c48394a1c86d5b36c352cc33a0a2c800bc99e62fd65b3a2fd69e0b53996ec13d8ce483ce9319efd9a85acefabdb5342226febb83fd1daf4b24265f50c61c6de74077ef89b6fecf9f29a1f871af1e9f89b2d345cda7499bd45c42fa5d195a1e1a6ba84851889e730da3b2b916e96152ae0c92154b49719841db7e7cc707ba8a5d7b101eb4ac7b629bb327817910fff61580b59aab78182d1a2e33473d05b00b170b29e331870826cfe45af206aa7d0246bbd8566ca7cfb2d3c10bfa1db7dd48dd786036469ce7282093d78b5e1a5b0fc81a54c8ed4ceac1e5305305e78284ac276f5d7862727aff246e17addde50c670028d572cbfc0be2e4f8b2eb28fa68ad7b4c6c2a239c460441bfb5ea049f23b08563b4e47729a59e5986a61a6093dbd54f8c36ebe87edae01f251cb060ad1364ce677d7e8d5a4a4ca966a7241cc360bc2acb280e5f9e9c1b032ad6a180a35e0c5180b9d16d026c865b252098cc1d99ba7375ca31c7702c0d943d5e3dd2f6861fa55bd46d94b67ed3e52eccd8dd06d968e01897d6de97ed3058d91dd":"8e4bc6f8b8c60fe4d68c61d9b159c8693c3151c46749af58da228442d927f23359bd6ccd6c2ec8fa3f00a86cecbfa728e1ad60b821ed22fcd309ba91a4138bc9"
 
+PSA hash finish: SHA3-224 Test Vector NIST ""
+depends_on:PSA_WANT_ALG_SHA3_224
+hash_finish:PSA_ALG_SHA3_224:"":"6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7"
+
+PSA hash finish: SHA3-256 Test Vector NIST ""
+depends_on:PSA_WANT_ALG_SHA3_256
+hash_finish:PSA_ALG_SHA3_256:"":"a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"
+
+PSA hash finish: SHA3-384 Test Vector NIST ""
+depends_on:PSA_WANT_ALG_SHA3_384
+hash_finish:PSA_ALG_SHA3_384:"":"0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004"
+
+PSA hash finish: SHA3-512 Test Vector NIST ""
+depends_on:PSA_WANT_ALG_SHA3_512
+hash_finish:PSA_ALG_SHA3_512:"":"a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"
+
+PSA hash finish: SHA3-224 Test Vector NIST "abc"
+depends_on:PSA_WANT_ALG_SHA3_224
+hash_finish:PSA_ALG_SHA3_224:"616263":"e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf"
+
+PSA hash finish: SHA3-256 Test Vector NIST "abc"
+depends_on:PSA_WANT_ALG_SHA3_256
+hash_finish:PSA_ALG_SHA3_256:"616263":"3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"
+
+PSA hash finish: SHA3-384 Test Vector NIST "abc"
+depends_on:PSA_WANT_ALG_SHA3_384
+hash_finish:PSA_ALG_SHA3_384:"616263":"ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25"
+
+PSA hash finish: SHA3-512 Test Vector NIST "abc"
+depends_on:PSA_WANT_ALG_SHA3_512
+hash_finish:PSA_ALG_SHA3_512:"616263":"b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"
+
+PSA hash finish: SHA3-224 Test Vector NIST 448 bits: "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+depends_on:PSA_WANT_ALG_SHA3_224
+hash_finish:PSA_ALG_SHA3_224:"6162636462636465636465666465666765666768666768696768696a68696a6b696a6b6c6a6b6c6d6b6c6d6e6c6d6e6f6d6e6f706e6f7071":"8a24108b154ada21c9fd5574494479ba5c7e7ab76ef264ead0fcce33"
+
+PSA hash finish: SHA3-256 Test Vector NIST 448 bits: "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+depends_on:PSA_WANT_ALG_SHA3_256
+hash_finish:PSA_ALG_SHA3_256:"6162636462636465636465666465666765666768666768696768696a68696a6b696a6b6c6a6b6c6d6b6c6d6e6c6d6e6f6d6e6f706e6f7071":"41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376"
+
+PSA hash finish: SHA3-384 Test Vector NIST 448 bits: "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+depends_on:PSA_WANT_ALG_SHA3_384
+hash_finish:PSA_ALG_SHA3_384:"6162636462636465636465666465666765666768666768696768696a68696a6b696a6b6c6a6b6c6d6b6c6d6e6c6d6e6f6d6e6f706e6f7071":"991c665755eb3a4b6bbdfb75c78a492e8c56a22c5c4d7e429bfdbc32b9d4ad5aa04a1f076e62fea19eef51acd0657c22"
+
+PSA hash finish: SHA3-512 Test Vector NIST 448 bits: "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+depends_on:PSA_WANT_ALG_SHA3_512
+hash_finish:PSA_ALG_SHA3_512:"6162636462636465636465666465666765666768666768696768696a68696a6b696a6b6c6a6b6c6d6b6c6d6e6c6d6e6f6d6e6f706e6f7071":"04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e"
+
+PSA hash finish: SHA3-224 Test Vector NIST 896 bits: "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
+depends_on:PSA_WANT_ALG_SHA3_224
+hash_finish:PSA_ALG_SHA3_224:"61626364656667686263646566676869636465666768696a6465666768696a6b65666768696a6b6c666768696a6b6c6d6768696a6b6c6d6e68696a6b6c6d6e6f696a6b6c6d6e6f706a6b6c6d6e6f70716b6c6d6e6f7071726c6d6e6f707172736d6e6f70717273746e6f707172737475":"543e6868e1666c1a643630df77367ae5a62a85070a51c14cbf665cbc"
+
+PSA hash finish: SHA3-256 Test Vector NIST 896 bits: "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
+depends_on:PSA_WANT_ALG_SHA3_256
+hash_finish:PSA_ALG_SHA3_256:"61626364656667686263646566676869636465666768696a6465666768696a6b65666768696a6b6c666768696a6b6c6d6768696a6b6c6d6e68696a6b6c6d6e6f696a6b6c6d6e6f706a6b6c6d6e6f70716b6c6d6e6f7071726c6d6e6f707172736d6e6f70717273746e6f707172737475":"916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18"
+
+PSA hash finish: SHA3-384 Test Vector NIST 896 bits: "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
+depends_on:PSA_WANT_ALG_SHA3_384
+hash_finish:PSA_ALG_SHA3_384:"61626364656667686263646566676869636465666768696a6465666768696a6b65666768696a6b6c666768696a6b6c6d6768696a6b6c6d6e68696a6b6c6d6e6f696a6b6c6d6e6f706a6b6c6d6e6f70716b6c6d6e6f7071726c6d6e6f707172736d6e6f70717273746e6f707172737475":"79407d3b5916b59c3e30b09822974791c313fb9ecc849e406f23592d04f625dc8c709b98b43b3852b337216179aa7fc7"
+
+PSA hash finish: SHA3-512 Test Vector NIST 896 bits: "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
+depends_on:PSA_WANT_ALG_SHA3_512
+hash_finish:PSA_ALG_SHA3_512:"61626364656667686263646566676869636465666768696a6465666768696a6b65666768696a6b6c666768696a6b6c6d6768696a6b6c6d6e68696a6b6c6d6e6f696a6b6c6d6e6f706a6b6c6d6e6f70716b6c6d6e6f7071726c6d6e6f707172736d6e6f70717273746e6f707172737475":"afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185"
+
 PSA hash finish: MD5 Test vector RFC1321 #1
 depends_on:PSA_WANT_ALG_MD5
 hash_finish:PSA_ALG_MD5:"":"d41d8cd98f00b204e9800998ecf8427e"
@@ -246,6 +310,22 @@
 depends_on:PSA_WANT_ALG_RIPEMD160
 hash_verify:PSA_ALG_RIPEMD160:"bd":"5089265ee5d9af75d12dbf7ea2f27dbdee435b37"
 
+PSA hash verify: SHA3-224
+depends_on:PSA_WANT_ALG_SHA3_224
+hash_verify:PSA_ALG_SHA3_224:"bd":"79bd1a58a357d1a0ac15b43400bc396d17bdc6d3d90369f16f650b25"
+
+PSA hash verify: SHA3-256
+depends_on:PSA_WANT_ALG_SHA3_256
+hash_verify:PSA_ALG_SHA3_256:"bd":"b389fa0f45f21196cc2736e8de396497a2414be31e7a500a499918b8cf3257b2"
+
+PSA hash verify: SHA3-384
+depends_on:PSA_WANT_ALG_SHA3_384
+hash_verify:PSA_ALG_SHA3_384:"bd":"5a337b67965736040c5b1f2d4df7f9ca76cf01866c7d64ed8dd812b97995da9b14ef07f9c4d9190888e4b15c4df2203d"
+
+PSA hash verify: SHA3-512
+depends_on:PSA_WANT_ALG_SHA3_512
+hash_verify:PSA_ALG_SHA3_512:"bd":"72bacd82495cb72a44523cda462f0f02c9f33b6312e24e44f5c40deed2bbc37854b606cb2f62cce6a394b4157d8e6e89b22682380dc129dddd402693ffa98a6c"
+
 PSA hash multi part: SHA-1 Test Vector NIST CAVS #1
 depends_on:PSA_WANT_ALG_SHA_1
 hash_multi_part:PSA_ALG_SHA_1:"":"da39a3ee5e6b4b0d3255bfef95601890afd80709"
@@ -465,3 +545,126 @@
 PSA hash multi part: RIPEMD160 Test vector from paper #8
 depends_on:PSA_WANT_ALG_RIPEMD160
 hash_multi_part:PSA_ALG_RIPEMD160:"3132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930":"9b752e45573d4b39f4dbd3323cab82bf63326bfb"
+
+PSA hash multi part: SHA3-224 Test Vector NIST ""
+depends_on:PSA_WANT_ALG_SHA3_224
+hash_multi_part:PSA_ALG_SHA3_224:"":"6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7"
+
+PSA hash multi part: SHA3-256 Test Vector NIST ""
+depends_on:PSA_WANT_ALG_SHA3_256
+hash_multi_part:PSA_ALG_SHA3_256:"":"a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"
+
+PSA hash multi part: SHA3-384 Test Vector NIST ""
+depends_on:PSA_WANT_ALG_SHA3_384
+hash_multi_part:PSA_ALG_SHA3_384:"":"0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004"
+
+PSA hash multi part: SHA3-512 Test Vector NIST ""
+depends_on:PSA_WANT_ALG_SHA3_512
+hash_multi_part:PSA_ALG_SHA3_512:"":"a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"
+
+PSA hash multi part: SHA3-224 Test Vector NIST "abc"
+depends_on:PSA_WANT_ALG_SHA3_224
+hash_multi_part:PSA_ALG_SHA3_224:"616263":"e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf"
+
+PSA hash multi part: SHA3-256 Test Vector NIST "abc"
+depends_on:PSA_WANT_ALG_SHA3_256
+hash_multi_part:PSA_ALG_SHA3_256:"616263":"3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"
+
+PSA hash multi part: SHA3-384 Test Vector NIST "abc"
+depends_on:PSA_WANT_ALG_SHA3_384
+hash_multi_part:PSA_ALG_SHA3_384:"616263":"ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25"
+
+PSA hash multi part: SHA3-512 Test Vector NIST "abc"
+depends_on:PSA_WANT_ALG_SHA3_512
+hash_multi_part:PSA_ALG_SHA3_512:"616263":"b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"
+
+PSA hash multi part: SHA3-224 Test Vector NIST 448 bits: "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+depends_on:PSA_WANT_ALG_SHA3_224
+hash_multi_part:PSA_ALG_SHA3_224:"6162636462636465636465666465666765666768666768696768696a68696a6b696a6b6c6a6b6c6d6b6c6d6e6c6d6e6f6d6e6f706e6f7071":"8a24108b154ada21c9fd5574494479ba5c7e7ab76ef264ead0fcce33"
+
+PSA hash multi part: SHA3-256 Test Vector NIST 448 bits: "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+depends_on:PSA_WANT_ALG_SHA3_256
+hash_multi_part:PSA_ALG_SHA3_256:"6162636462636465636465666465666765666768666768696768696a68696a6b696a6b6c6a6b6c6d6b6c6d6e6c6d6e6f6d6e6f706e6f7071":"41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376"
+
+PSA hash multi part: SHA3-384 Test Vector NIST 448 bits: "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+depends_on:PSA_WANT_ALG_SHA3_384
+hash_multi_part:PSA_ALG_SHA3_384:"6162636462636465636465666465666765666768666768696768696a68696a6b696a6b6c6a6b6c6d6b6c6d6e6c6d6e6f6d6e6f706e6f7071":"991c665755eb3a4b6bbdfb75c78a492e8c56a22c5c4d7e429bfdbc32b9d4ad5aa04a1f076e62fea19eef51acd0657c22"
+
+PSA hash multi part: SHA3-512 Test Vector NIST 448 bits: "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+depends_on:PSA_WANT_ALG_SHA3_512
+hash_multi_part:PSA_ALG_SHA3_512:"6162636462636465636465666465666765666768666768696768696a68696a6b696a6b6c6a6b6c6d6b6c6d6e6c6d6e6f6d6e6f706e6f7071":"04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e"
+
+PSA hash multi part: SHA3-224 Test Vector NIST 896 bits: "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
+depends_on:PSA_WANT_ALG_SHA3_224
+hash_multi_part:PSA_ALG_SHA3_224:"61626364656667686263646566676869636465666768696a6465666768696a6b65666768696a6b6c666768696a6b6c6d6768696a6b6c6d6e68696a6b6c6d6e6f696a6b6c6d6e6f706a6b6c6d6e6f70716b6c6d6e6f7071726c6d6e6f707172736d6e6f70717273746e6f707172737475":"543e6868e1666c1a643630df77367ae5a62a85070a51c14cbf665cbc"
+
+PSA hash multi part: SHA3-256 Test Vector NIST 896 bits: "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
+depends_on:PSA_WANT_ALG_SHA3_256
+hash_multi_part:PSA_ALG_SHA3_256:"61626364656667686263646566676869636465666768696a6465666768696a6b65666768696a6b6c666768696a6b6c6d6768696a6b6c6d6e68696a6b6c6d6e6f696a6b6c6d6e6f706a6b6c6d6e6f70716b6c6d6e6f7071726c6d6e6f707172736d6e6f70717273746e6f707172737475":"916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18"
+
+PSA hash multi part: SHA3-384 Test Vector NIST 896 bits: "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
+depends_on:PSA_WANT_ALG_SHA3_384
+hash_multi_part:PSA_ALG_SHA3_384:"61626364656667686263646566676869636465666768696a6465666768696a6b65666768696a6b6c666768696a6b6c6d6768696a6b6c6d6e68696a6b6c6d6e6f696a6b6c6d6e6f706a6b6c6d6e6f70716b6c6d6e6f7071726c6d6e6f707172736d6e6f70717273746e6f707172737475":"79407d3b5916b59c3e30b09822974791c313fb9ecc849e406f23592d04f625dc8c709b98b43b3852b337216179aa7fc7"
+
+PSA hash multi part: SHA3-512 Test Vector NIST 896 bits: "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
+depends_on:PSA_WANT_ALG_SHA3_512
+hash_multi_part:PSA_ALG_SHA3_512:"61626364656667686263646566676869636465666768696a6465666768696a6b65666768696a6b6c666768696a6b6c6d6768696a6b6c6d6e68696a6b6c6d6e6f696a6b6c6d6e6f706a6b6c6d6e6f70716b6c6d6e6f7071726c6d6e6f707172736d6e6f70717273746e6f707172737475":"afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185"
+
+# HMAC test vectors generated in python with e.g.
+# import hmac; hmac.new(bytes([0xaa]*32), b'abc', 'SHA3-224').hexdigest()
+
+PSA HMAC SHA3-224
+depends_on:PSA_WANT_ALG_SHA3_224
+hmac:PSA_ALG_SHA3_224:"abc":"bf0905154ad610b6a3d6d0b9a1c692494e987337d956624a066d7a1f"
+
+PSA HMAC SHA3-256
+depends_on:PSA_WANT_ALG_SHA3_256
+hmac:PSA_ALG_SHA3_256:"abc":"a986419a162b6d4731a8e96e44a2c6e784d50137907b457c9fb77c62705dc4d9"
+
+PSA HMAC SHA3-384
+depends_on:PSA_WANT_ALG_SHA3_384
+hmac:PSA_ALG_SHA3_384:"abc":"87b864ee25f8bfebd516eddd7cdd400d3c368a09e4b1fabaee5636da8a9c876c3f802c366537663910f2e6c5a8426381"
+
+PSA HMAC SHA3-512
+depends_on:PSA_WANT_ALG_SHA3_512
+hmac:PSA_ALG_SHA3_512:"abc":"2cef45b6950e41a70bc85cb431b2161d47c9e2932187fa15d80e3b7af1da38aa8fe823a72efd7e536e5236a5b0798418d8c8f08b0de5fc262867bb3752b6482d"
+
+PSA HMAC SHA-1
+depends_on:PSA_WANT_ALG_SHA_1
+hmac:PSA_ALG_SHA_1:"abc":"0b3a7f96afea3e14a0835f7c9468a24649f85596"
+
+PSA HMAC SHA-224
+depends_on:PSA_WANT_ALG_SHA_224
+hmac:PSA_ALG_SHA_224:"abc":"249c405cef8bcd3ceeafdb9a933179739fb9b1d7f174df4667ec82f3"
+
+PSA HMAC SHA-256
+depends_on:PSA_WANT_ALG_SHA_256
+hmac:PSA_ALG_SHA_256:"abc":"b89a1b878289c739595104da55b6f7a8afec3e0757fc166080dc267c09c46841"
+
+PSA HMAC SHA-384
+depends_on:PSA_WANT_ALG_SHA_384
+hmac:PSA_ALG_SHA_384:"abc":"25a8b55c884bc38286305f76332631726498f5586280b88bc6179cd00c6878fb7d1bb3ee1643fcd2fb02b95823ff1af2"
+
+PSA HMAC SHA-512
+depends_on:PSA_WANT_ALG_SHA_512
+hmac:PSA_ALG_SHA_512:"abc":"d6e5eebb5cf27f5b686fefc416ee8c431bb10770216aa3c6ba13897ef3fc040b98abc53b95039f2c50622473f958af64a3cae1afbea8ffffa8d35ca24f31e222"
+
+PSA HMAC RIPEMD160
+depends_on:PSA_WANT_ALG_RIPEMD160
+hmac:PSA_ALG_RIPEMD160:"abc":"114a5cf4637f57c044472e1a0b87cce9137190b2"
+
+PSA HMAC MD5
+depends_on:PSA_WANT_ALG_MD5
+hmac:PSA_ALG_MD5:"abc":"39677b12b80118927387aa4a65d16a5e"
+
+PSA HMAC input length 0
+depends_on:PSA_WANT_ALG_SHA_256
+hmac:PSA_ALG_SHA_256:"":"63210aee265762634fa3db8c1aa920dcd07d31ec297309580394a21412f83372"
+
+PSA HMAC input length 1
+depends_on:PSA_WANT_ALG_SHA_256
+hmac:PSA_ALG_SHA_256:"x":"f61c11d66441e3c0b9902a8491caa2da5a0d0d95ef0fc61d8a3b5ea5e0416f5c"
+
+PSA HMAC input length 2890
+depends_on:PSA_WANT_ALG_SHA_256
+hmac:PSA_ALG_SHA_256:"0123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999":"dd2e08786029097be5f634fda74a7e20e3e1638e71282892c4fd21d9a71ae418"
diff --git a/tests/suites/test_suite_psa_crypto_hash.function b/tests/suites/test_suite_psa_crypto_hash.function
index 0405c1d..20167fd 100644
--- a/tests/suites/test_suite_psa_crypto_hash.function
+++ b/tests/suites/test_suite_psa_crypto_hash.function
@@ -1,6 +1,7 @@
 /* BEGIN_HEADER */
 
 #include <stdint.h>
+#include "psa/crypto.h"
 
 /* END_HEADER */
 
@@ -35,6 +36,52 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
+void hmac(int alg_arg, char *input, data_t *expected_mac)
+{
+    psa_algorithm_t alg = PSA_ALG_HMAC(alg_arg);
+
+    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
+    psa_key_type_t key_type = PSA_KEY_TYPE_HMAC;
+    const uint8_t key_data[] = { // 32 bytes of 0xaa
+        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+    };
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+    PSA_ASSERT(psa_crypto_init());
+
+    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE);
+    psa_set_key_algorithm(&attributes, alg);
+    psa_set_key_type(&attributes, key_type);
+    PSA_ASSERT(psa_import_key(&attributes, key_data, sizeof(key_data), &key));
+
+    uint8_t mac[PSA_MAC_MAX_SIZE + 10] = { 0 };
+    size_t mac_length = 0;
+
+    size_t input_len = strlen(input);
+    PSA_ASSERT(psa_mac_compute(key, alg, (uint8_t const *) input, input_len, mac, sizeof(mac),
+                               &mac_length));
+
+    // manual comparison against expected MAC
+    ASSERT_COMPARE(expected_mac->x, expected_mac->len, mac, mac_length);
+
+    // use psa_mac_verify to compare to expected MAC
+    PSA_ASSERT(psa_mac_verify(key, alg, (uint8_t const *) input, input_len, expected_mac->x,
+                              expected_mac->len));
+
+    // corrupt the MAC and check that psa_mac_verify fails
+    expected_mac->x[0] ^= 0x7f;
+    TEST_EQUAL(psa_mac_verify(key, alg, (uint8_t const *) input, input_len, expected_mac->x,
+                              expected_mac->len), PSA_ERROR_INVALID_SIGNATURE);
+
+    PSA_ASSERT(psa_destroy_key(key));
+exit:
+    PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
 void hash_verify(int alg_arg, data_t *input, data_t *expected_hash)
 {
     psa_algorithm_t alg = alg_arg;
diff --git a/tests/suites/test_suite_psa_crypto_low_hash.function b/tests/suites/test_suite_psa_crypto_low_hash.function
new file mode 100644
index 0000000..6dabcef
--- /dev/null
+++ b/tests/suites/test_suite_psa_crypto_low_hash.function
@@ -0,0 +1,209 @@
+/* BEGIN_HEADER */
+/*
+ * Test suite for the PSA hash built-in driver
+ *
+ * This test suite exercises some aspects of the built-in PSA driver for
+ * hash algorithms (psa_crypto_hash.c). This code is mostly tested via
+ * the application interface (above the PSA API layer) and via tests of
+ * individual hash modules. The goal of this test suite is to ensure that
+ * the driver dispatch layer behaves correctly even when not invoked via
+ * the API layer, but directly from another driver.
+ *
+ * This test suite is currently incomplete. It focuses on non-regression
+ * tests for past bugs or near misses.
+ */
+
+#include <psa_crypto_hash.h>
+
+/* END_HEADER */
+
+/* BEGIN_DEPENDENCIES
+ * depends_on:MBEDTLS_PSA_BUILTIN_HASH
+ * END_DEPENDENCIES
+ */
+
+/* BEGIN_CASE */
+void hash_valid_one_shot(int alg_arg, data_t *input,
+                         data_t *expected)
+{
+    psa_algorithm_t alg = alg_arg;
+    uint8_t *output = NULL;
+    size_t output_size = expected->len;
+    size_t length = SIZE_MAX;
+
+    /* Nominal case */
+    ASSERT_ALLOC(output, output_size);
+    TEST_EQUAL(mbedtls_psa_hash_compute(alg, input->x, input->len,
+                                        output, output_size, &length),
+               PSA_SUCCESS);
+    ASSERT_COMPARE(expected->x, expected->len, output, length);
+    mbedtls_free(output);
+    output = NULL;
+
+    /* Larger output buffer */
+    output_size = expected->len + 1;
+    ASSERT_ALLOC(output, output_size);
+    TEST_EQUAL(mbedtls_psa_hash_compute(alg, input->x, input->len,
+                                        output, output_size, &length),
+               PSA_SUCCESS);
+    ASSERT_COMPARE(expected->x, expected->len, output, length);
+    mbedtls_free(output);
+    output = NULL;
+
+    /* We don't test with a smaller output buffer because this isn't
+     * guaranteed to work: the core must pass a sufficiently large
+     * output buffer to the driver. */
+
+exit:
+    mbedtls_free(output);
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void hash_valid_multipart(int alg_arg,
+                          data_t *input1, data_t *expected1,
+                          data_t *input2, data_t *expected2)
+{
+    psa_algorithm_t alg = alg_arg;
+    uint8_t *output = NULL;
+    size_t output_size = expected1->len;
+    size_t length = SIZE_MAX;
+    mbedtls_psa_hash_operation_t operation0; // original
+    memset(&operation0, 0, sizeof(operation0));
+    mbedtls_psa_hash_operation_t clone_start; // cloned after setup
+    memset(&clone_start, 0, sizeof(clone_start));
+    mbedtls_psa_hash_operation_t clone_middle; // cloned between updates
+    memset(&clone_middle, 0, sizeof(clone_middle));
+    mbedtls_psa_hash_operation_t clone_end; // cloned before finish
+    memset(&clone_end, 0, sizeof(clone_end));
+    mbedtls_psa_hash_operation_t clone_more; // cloned before finish
+    memset(&clone_more, 0, sizeof(clone_more));
+
+    /* Nominal case with two update calls */
+    ASSERT_ALLOC(output, output_size);
+    TEST_EQUAL(mbedtls_psa_hash_setup(&operation0, alg),
+               PSA_SUCCESS);
+    TEST_EQUAL(mbedtls_psa_hash_clone(&operation0, &clone_start),
+               PSA_SUCCESS);
+    TEST_EQUAL(mbedtls_psa_hash_update(&operation0, input1->x, input1->len),
+               PSA_SUCCESS);
+    TEST_EQUAL(mbedtls_psa_hash_clone(&operation0, &clone_middle),
+               PSA_SUCCESS);
+    TEST_EQUAL(mbedtls_psa_hash_update(&operation0, input2->x, input2->len),
+               PSA_SUCCESS);
+    TEST_EQUAL(mbedtls_psa_hash_clone(&operation0, &clone_end),
+               PSA_SUCCESS);
+    TEST_EQUAL(mbedtls_psa_hash_finish(&operation0,
+                                       output, output_size, &length),
+               PSA_SUCCESS);
+    ASSERT_COMPARE(expected2->x, expected2->len, output, length);
+
+    /* Nominal case with an operation cloned after setup */
+    memset(output, 0, output_size);
+    TEST_EQUAL(mbedtls_psa_hash_update(&clone_start, input1->x, input1->len),
+               PSA_SUCCESS);
+    TEST_EQUAL(mbedtls_psa_hash_finish(&clone_start,
+                                       output, output_size, &length),
+               PSA_SUCCESS);
+    ASSERT_COMPARE(expected1->x, expected1->len, output, length);
+
+    /* Nominal case with an operation cloned between updates */
+    memset(output, 0, output_size);
+    TEST_EQUAL(mbedtls_psa_hash_update(&clone_middle, input2->x, input2->len),
+               PSA_SUCCESS);
+    TEST_EQUAL(mbedtls_psa_hash_finish(&clone_middle,
+                                       output, output_size, &length),
+               PSA_SUCCESS);
+    ASSERT_COMPARE(expected2->x, expected2->len, output, length);
+
+    /* Nominal case with an operation cloned before finish */
+    TEST_EQUAL(mbedtls_psa_hash_clone(&clone_end, &clone_more),
+               PSA_SUCCESS);
+    memset(output, 0, output_size);
+    TEST_EQUAL(mbedtls_psa_hash_finish(&clone_end,
+                                       output, output_size, &length),
+               PSA_SUCCESS);
+    ASSERT_COMPARE(expected2->x, expected2->len, output, length);
+    mbedtls_free(output);
+    output = NULL;
+
+    /* Larger output buffer */
+    TEST_EQUAL(mbedtls_psa_hash_clone(&clone_more, &clone_end),
+               PSA_SUCCESS);
+    output_size = expected2->len + 1;
+    ASSERT_ALLOC(output, output_size);
+    TEST_EQUAL(mbedtls_psa_hash_finish(&clone_end,
+                                       output, output_size, &length),
+               PSA_SUCCESS);
+    ASSERT_COMPARE(expected2->x, expected2->len, output, length);
+    mbedtls_free(output);
+    output = NULL;
+
+    /* We don't test with a smaller output buffer because this isn't
+     * guaranteed to work: the core must pass a sufficiently large
+     * output buffer to the driver. */
+
+    /* Nominal case again after an error in a cloned operation */
+    output_size = expected2->len;
+    ASSERT_ALLOC(output, output_size);
+    TEST_EQUAL(mbedtls_psa_hash_finish(&clone_more,
+                                       output, output_size, &length),
+               PSA_SUCCESS);
+    ASSERT_COMPARE(expected2->x, expected2->len, output, length);
+    mbedtls_free(output);
+    output = NULL;
+
+exit:
+    mbedtls_free(output);
+    mbedtls_psa_hash_abort(&operation0);
+    mbedtls_psa_hash_abort(&clone_start);
+    mbedtls_psa_hash_abort(&clone_middle);
+    mbedtls_psa_hash_abort(&clone_end);
+    mbedtls_psa_hash_abort(&clone_more);
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void hash_empty(int alg_arg, data_t *expected)
+{
+    psa_algorithm_t alg = alg_arg;
+    uint8_t *output = NULL;
+    size_t output_size = expected->len;
+    size_t length = SIZE_MAX;
+    mbedtls_psa_hash_operation_t operation;
+    memset(&operation, 0, sizeof(operation));
+
+    ASSERT_ALLOC(output, output_size);
+
+    /* One-shot */
+    TEST_EQUAL(mbedtls_psa_hash_compute(alg, NULL, 0,
+                                        output, output_size, &length),
+               PSA_SUCCESS);
+    ASSERT_COMPARE(expected->x, expected->len, output, length);
+
+    /* Multipart, no update */
+    memset(output, 0, output_size);
+    TEST_EQUAL(mbedtls_psa_hash_setup(&operation, alg),
+               PSA_SUCCESS);
+    TEST_EQUAL(mbedtls_psa_hash_finish(&operation,
+                                       output, output_size, &length),
+               PSA_SUCCESS);
+    ASSERT_COMPARE(expected->x, expected->len, output, length);
+
+    /* Multipart, one update */
+    memset(output, 0, output_size);
+    memset(&operation, 0, sizeof(operation));
+    TEST_EQUAL(mbedtls_psa_hash_setup(&operation, alg),
+               PSA_SUCCESS);
+    TEST_EQUAL(mbedtls_psa_hash_update(&operation, NULL, 0),
+               PSA_SUCCESS);
+    TEST_EQUAL(mbedtls_psa_hash_finish(&operation,
+                                       output, output_size, &length),
+               PSA_SUCCESS);
+    ASSERT_COMPARE(expected->x, expected->len, output, length);
+
+exit:
+    mbedtls_free(output);
+    mbedtls_psa_hash_abort(&operation);
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_psa_crypto_metadata.data b/tests/suites/test_suite_psa_crypto_metadata.data
index fef0bab..b1672ec 100644
--- a/tests/suites/test_suite_psa_crypto_metadata.data
+++ b/tests/suites/test_suite_psa_crypto_metadata.data
@@ -26,6 +26,22 @@
 depends_on:PSA_WANT_ALG_SHA_512
 hash_algorithm:PSA_ALG_SHA_512:64
 
+Hash: SHA-3 SHA3-224
+depends_on:PSA_WANT_ALG_SHA3_224
+hash_algorithm:PSA_ALG_SHA3_224:28
+
+Hash: SHA-3 SHA3-256
+depends_on:PSA_WANT_ALG_SHA3_256
+hash_algorithm:PSA_ALG_SHA3_256:32
+
+Hash: SHA-3 SHA3-384
+depends_on:PSA_WANT_ALG_SHA3_384
+hash_algorithm:PSA_ALG_SHA3_384:48
+
+Hash: SHA-3 SHA3-512
+depends_on:PSA_WANT_ALG_SHA3_512
+hash_algorithm:PSA_ALG_SHA3_512:64
+
 MAC: HMAC-MD5
 depends_on:PSA_WANT_ALG_HMAC:PSA_WANT_ALG_MD5
 hmac_algorithm:PSA_ALG_HMAC( PSA_ALG_MD5 ):16:64
diff --git a/tests/suites/test_suite_psa_crypto_se_driver_hal.function b/tests/suites/test_suite_psa_crypto_se_driver_hal.function
index 979db59..9c5ef23 100644
--- a/tests/suites/test_suite_psa_crypto_se_driver_hal.function
+++ b/tests/suites/test_suite_psa_crypto_se_driver_hal.function
@@ -1328,7 +1328,7 @@
             key_management.p_export_public = ram_export_public;
             break;
         default:
-            TEST_ASSERT(!"unsupported flow (should be SIGN_IN_xxx)");
+            TEST_FAIL("unsupported flow (should be SIGN_IN_xxx)");
             break;
     }
     asymmetric.p_verify = ram_verify;
diff --git a/tests/suites/test_suite_psa_crypto_slot_management.function b/tests/suites/test_suite_psa_crypto_slot_management.function
index a8fe46f..5bd12eb 100644
--- a/tests/suites/test_suite_psa_crypto_slot_management.function
+++ b/tests/suites/test_suite_psa_crypto_slot_management.function
@@ -775,7 +775,7 @@
                 mbedtls_svc_key_id_make(0, PSA_KEY_ID_VENDOR_MAX + 1);
             break;
         default:
-            TEST_ASSERT(!"unknown handle construction");
+            TEST_FAIL("unknown handle construction");
     }
 
     /* Attempt to use the invalid handle. */
diff --git a/tests/suites/test_suite_psa_its.function b/tests/suites/test_suite_psa_its.function
index cb11f18..0f66c79 100644
--- a/tests/suites/test_suite_psa_its.function
+++ b/tests/suites/test_suite_psa_its.function
@@ -10,7 +10,7 @@
  * before changing how test data is constructed or validated.
  */
 
-#include "../library/psa_crypto_its.h"
+#include "psa_crypto_its.h"
 
 #include "test/psa_helpers.h"
 
diff --git a/tests/suites/test_suite_shax.function b/tests/suites/test_suite_shax.function
index c02853b..629e281 100644
--- a/tests/suites/test_suite_shax.function
+++ b/tests/suites/test_suite_shax.function
@@ -176,9 +176,12 @@
     TEST_EQUAL(mbedtls_sha3_starts(&ctx, MBEDTLS_SHA3_NONE), MBEDTLS_ERR_SHA3_BAD_INPUT_DATA);
 
     TEST_EQUAL(mbedtls_sha3_starts(&ctx, MBEDTLS_SHA3_256), 0);
-
     TEST_EQUAL(mbedtls_sha3_finish(&ctx, output, 0), MBEDTLS_ERR_SHA3_BAD_INPUT_DATA);
+
+    TEST_EQUAL(mbedtls_sha3_starts(&ctx, MBEDTLS_SHA3_256), 0);
     TEST_EQUAL(mbedtls_sha3_finish(&ctx, output, 31), MBEDTLS_ERR_SHA3_BAD_INPUT_DATA);
+
+    TEST_EQUAL(mbedtls_sha3_starts(&ctx, MBEDTLS_SHA3_256), 0);
     TEST_EQUAL(mbedtls_sha3_finish(&ctx, output, 32), 0);
 
 exit:
@@ -275,14 +278,14 @@
         case 32: type1 = MBEDTLS_SHA3_256; break;
         case 48: type1 = MBEDTLS_SHA3_384; break;
         case 64: type1 = MBEDTLS_SHA3_512; break;
-        default: TEST_ASSERT(!"hash1->len validity"); break;
+        default: TEST_FAIL("hash1->len validity"); break;
     }
     switch (hash2->len) {
         case 28: type2 = MBEDTLS_SHA3_224; break;
         case 32: type2 = MBEDTLS_SHA3_256; break;
         case 48: type2 = MBEDTLS_SHA3_384; break;
         case 64: type2 = MBEDTLS_SHA3_512; break;
-        default: TEST_ASSERT(!"hash2->len validity"); break;
+        default: TEST_FAIL("hash2->len validity"); break;
     }
 
     /* Round 1 */
diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data
index 3d092db..7af9de9 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -3115,6 +3115,14 @@
 depends_on:MBEDTLS_MD_CAN_SHA256:MBEDTLS_RSA_C
 mbedtls_x509_crt_parse_file:"data_files/parse_input/cli-rsa-sha256-badalg.crt.der":MBEDTLS_ERR_X509_SIG_MISMATCH:0
 
+X509 File parse (does not conform to RFC 5480 / RFC 5758 - AlgorithmIdentifier's parameters field is present, mbedTLS generated before bugfix, OK)
+depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_MD_CAN_SHA256
+x509parse_crt_file:"data_files/parse_input/server5-non-compliant.crt":0
+
+X509 File parse (conforms to RFC 5480 / RFC 5758 - AlgorithmIdentifier's parameters field must be absent for ECDSA)
+depends_on:MBEDTLS_PK_CAN_ECDSA_SOME:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_MD_CAN_SHA256
+x509parse_crt_file:"data_files/parse_input/server5.crt":0
+
 X509 Get time (UTC no issues)
 depends_on:MBEDTLS_X509_USE_C
 x509_get_time:MBEDTLS_ASN1_UTC_TIME:"500101000000Z":0:1950:1:1:0:0:0
diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function
index 88ca28c..1b08bc3 100644
--- a/tests/suites/test_suite_x509parse.function
+++ b/tests/suites/test_suite_x509parse.function
@@ -415,11 +415,6 @@
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 /* END_HEADER */
 
-/* BEGIN_DEPENDENCIES
- * depends_on:MBEDTLS_BIGNUM_C
- * END_DEPENDENCIES
- */
-
 /* BEGIN_CASE depends_on:MBEDTLS_X509_CRT_PARSE_C */
 void x509_accessor_ext_types(int ext_type, int has_ext_type)
 {
@@ -702,7 +697,7 @@
     } else if (strcmp(profile_str, "all") == 0) {
         profile = &profile_all;
     } else {
-        TEST_ASSERT("Unknown algorithm profile" == 0);
+        TEST_FAIL("Unknown algorithm profile");
     }
 
     if (strcmp(verify_callback, "NULL") == 0) {
@@ -712,7 +707,7 @@
     } else if (strcmp(verify_callback, "verify_all") == 0) {
         f_vrfy = verify_all;
     } else {
-        TEST_ASSERT("No known verify callback selected" == 0);
+        TEST_FAIL("No known verify callback selected");
     }
 
     TEST_EQUAL(mbedtls_x509_crt_parse_file(&crt, crt_file), 0);
@@ -881,7 +876,7 @@
     } else if (strcmp(entity, "issuer") == 0) {
         res =  mbedtls_x509_dn_gets(buf, 2000, &crt.issuer);
     } else {
-        TEST_ASSERT("Unknown entity" == 0);
+        TEST_FAIL("Unknown entity");
     }
 
     TEST_ASSERT(res != -1);
@@ -1006,7 +1001,7 @@
     } else if (strcmp(entity, "valid_to") == 0) {
         TEST_EQUAL(mbedtls_x509_time_is_past(&crt.valid_to), result);
     } else {
-        TEST_ASSERT("Unknown entity" == 0);
+        TEST_FAIL("Unknown entity");
     }
 
 exit:
@@ -1030,7 +1025,7 @@
     } else if (strcmp(entity, "valid_to") == 0) {
         TEST_EQUAL(mbedtls_x509_time_is_future(&crt.valid_to), result);
     } else {
-        TEST_ASSERT("Unknown entity" == 0);
+        TEST_FAIL("Unknown entity");
     }
 
 exit:
diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function
index ab4a2d0..26988ce 100644
--- a/tests/suites/test_suite_x509write.function
+++ b/tests/suites/test_suite_x509write.function
@@ -128,7 +128,7 @@
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
- * depends_on:MBEDTLS_BIGNUM_C:MBEDTLS_FS_IO:MBEDTLS_PK_PARSE_C
+ * depends_on:MBEDTLS_FS_IO:MBEDTLS_PK_PARSE_C
  * END_DEPENDENCIES
  */
 
@@ -153,24 +153,44 @@
     mbedtls_x509_san_list san_ip;
     mbedtls_x509_san_list san_dns;
     mbedtls_x509_san_list san_uri;
+    mbedtls_x509_san_list san_mail;
+    mbedtls_x509_san_list san_dn;
     mbedtls_x509_san_list *san_list = NULL;
-    const char san_ip_name[] = { 0x7f, 0x01, 0x01, 0x00 }; // 127.1.1.0
+    mbedtls_asn1_named_data *ext_san_dirname = NULL;
+
+    const char san_ip_name[] = { 0x7f, 0x00, 0x00, 0x01 }; // 127.0.0.1
     const char *san_dns_name = "example.com";
-    const char *san_uri_name = "http://pki.example.com/";
+    const char *san_dn_name = "C=UK,O=Mbed TLS,CN=Mbed TLS directoryName SAN";
+    const char *san_mail_name = "mail@example.com";
+    const char *san_uri_name = "http://pki.example.com";
+
+    san_mail.node.type = MBEDTLS_X509_SAN_RFC822_NAME;
+    san_mail.node.san.unstructured_name.p = (unsigned char *) san_mail_name;
+    san_mail.node.san.unstructured_name.len = strlen(san_mail_name);
+    san_mail.next = NULL;
+
+    san_dns.node.type = MBEDTLS_X509_SAN_DNS_NAME;
+    san_dns.node.san.unstructured_name.p = (unsigned char *) san_dns_name;
+    san_dns.node.san.unstructured_name.len = strlen(san_dns_name);
+    san_dns.next = &san_mail;
+
+    san_dn.node.type = MBEDTLS_X509_SAN_DIRECTORY_NAME;
+    TEST_ASSERT(mbedtls_x509_string_to_names(&ext_san_dirname,
+                                             san_dn_name) == 0);
+    san_dn.node.san.directory_name = *ext_san_dirname;
+    san_dn.next = &san_dns;
+
+    san_ip.node.type = MBEDTLS_X509_SAN_IP_ADDRESS;
+    san_ip.node.san.unstructured_name.p = (unsigned char *) san_ip_name;
+    san_ip.node.san.unstructured_name.len = sizeof(san_ip_name);
+    san_ip.next = &san_dn;
 
     san_uri.node.type = MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER;
     san_uri.node.san.unstructured_name.p = (unsigned char *) san_uri_name;
     san_uri.node.san.unstructured_name.len = strlen(san_uri_name);
-    san_uri.next = NULL;
-    san_ip.node.type = MBEDTLS_X509_SAN_IP_ADDRESS;
-    san_ip.node.san.unstructured_name.p = (unsigned char *) san_ip_name;
-    san_ip.node.san.unstructured_name.len = sizeof(san_ip_name);
-    san_ip.next = &san_uri;
-    san_dns.node.type = MBEDTLS_X509_SAN_DNS_NAME;
-    san_dns.node.san.unstructured_name.p = (unsigned char *) san_dns_name;
-    san_dns.node.san.unstructured_name.len = strlen(san_dns_name);
-    san_dns.next = &san_ip;
-    san_list = &san_dns;
+    san_uri.next = &san_ip;
+
+    san_list = &san_uri;
 
     memset(&rnd_info, 0x2a, sizeof(mbedtls_test_rnd_pseudo_info));
 
@@ -244,6 +264,7 @@
     TEST_ASSERT(ret == MBEDTLS_ERR_ASN1_BUF_TOO_SMALL);
 
 exit:
+    mbedtls_asn1_free_named_data_list(&ext_san_dirname);
     mbedtls_x509write_csr_free(&req);
     mbedtls_pk_free(&key);
     MD_OR_USE_PSA_DONE();
diff --git a/visualc/VS2013/.gitignore b/visualc/VS2013/.gitignore
index d3da304..a9ded4a 100644
--- a/visualc/VS2013/.gitignore
+++ b/visualc/VS2013/.gitignore
@@ -1,7 +1,3 @@
-# Files automatically generated by generate_visualc_files.pl
-/mbedTLS.sln
-/*.vcxproj
-
 # Files that may be left over from check-generated-files.sh
 /*.bak
 
@@ -12,3 +8,9 @@
 /Release/
 /*.vcxproj.filters
 /*.vcxproj.user
+
+###START_GENERATED_FILES###
+# Files automatically generated by generate_visualc_files.pl
+/mbedTLS.sln
+/*.vcxproj
+###END_GENERATED_FILES###