Merge pull request #6595 from mfischer/lms_heap

lms: Move merkle tree generation to heap allocation
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 94fb020..50a4901 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -14,6 +14,6 @@
 
 ## Notes for the submitter
 
-Please refer to the [contributing guidelines](../CONTRIBUTING.md), especially the
+Please refer to the [contributing guidelines](https://github.com/Mbed-TLS/mbedtls/blob/development/CONTRIBUTING.md), especially the
 checklist for PR contributors.
 
diff --git a/.pylintrc b/.pylintrc
index 10c93f8..f395fb9 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -1,5 +1,6 @@
 [MASTER]
 init-hook='import sys; sys.path.append("scripts")'
+min-similarity-lines=10
 
 [BASIC]
 # We're ok with short funtion argument names.
diff --git a/.travis.yml b/.travis.yml
index 67cb3ca..eaf817a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -25,8 +25,40 @@
         - tests/scripts/all.sh -k build_arm_linux_gnueabi_gcc_arm5vte build_arm_none_eabi_gcc_m0plus
 
     - name: full configuration
+      os: linux
+      dist: focal
+      addons:
+        apt:
+          packages:
+          - clang-10
+          - gnutls-bin
       script:
-        - tests/scripts/all.sh -k test_full_cmake_gcc_asan
+        # Do a manual build+test sequence rather than using all.sh,
+        # because there's no all.sh component that does what we want,
+        # which is a build with Clang >= 10 and ASan, running all the SSL
+        # testing.
+        #   - The clang executable in the default PATH is Clang 7 on
+        #     Travis's focal instances, but we want Clang >= 10.
+        #   - Running all the SSL testing requires a specific set of
+        #     OpenSSL and GnuTLS versions and we don't want to bother
+        #     with those on Travis.
+        # So we explicitly select clang-10 as the compiler, and we
+        # have ad hoc restrictions on SSL testing based on what is
+        # passing at the time of writing. We will remove these limitations
+        # gradually.
+        - make generated_files
+        - make CC=clang-10 CFLAGS='-Werror -Wall -Wextra -fsanitize=address,undefined -fno-sanitize-recover=all -O2' LDFLAGS='-Werror -Wall -Wextra -fsanitize=address,undefined -fno-sanitize-recover=all'
+        - make test
+        - programs/test/selftest
+        - tests/scripts/test_psa_constant_names.py
+        - tests/ssl-opt.sh
+        # Modern OpenSSL does not support fixed ECDH or null ciphers.
+        - tests/compat.sh -p OpenSSL -e 'NULL\|ECDH-'
+        - tests/scripts/travis-log-failure.sh
+        # GnuTLS supports CAMELLIA but compat.sh doesn't properly enable it.
+        - tests/compat.sh -p GnuTLS -e 'CAMELLIA'
+        - tests/scripts/travis-log-failure.sh
+        - tests/context-info.sh
 
     - name: Windows
       os: windows
diff --git a/.uncrustify.cfg b/.uncrustify.cfg
new file mode 100644
index 0000000..7ce0905
--- /dev/null
+++ b/.uncrustify.cfg
@@ -0,0 +1,254 @@
+# Configuration options for Uncrustify specifying the Mbed TLS code style.
+#
+# Note: The code style represented by this file has not yet been introduced
+# to Mbed TLS.
+#
+# 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.
+
+
+# Line length options
+
+# Wrap lines at 100 characters
+code_width = 100
+
+# Allow splitting long for statements between the condition statements
+ls_for_split_full = true
+
+# Allow splitting function calls between arguments
+ls_func_split_full = true
+
+input_tab_size = 4
+
+# Spaces-only indentation
+indent_with_tabs = 0
+
+indent_columns = 4
+
+# Indent 'case' 1 level from 'switch'
+indent_switch_case = indent_columns
+
+# Line-up strings broken by '\'
+indent_align_string = true
+
+# Braces on the same line (Egyptian-style braces)
+nl_enum_brace = remove
+nl_union_brace = remove
+nl_struct_brace = remove
+nl_do_brace = remove
+nl_if_brace = remove
+nl_for_brace = remove
+nl_else_brace = remove
+nl_while_brace = remove
+nl_switch_brace = remove
+
+# Braces on same line as keywords that follow them - 'else' and the 'while' in 'do {} while ()';
+nl_brace_else = remove
+nl_brace_while = remove
+# Space before else on the same line
+sp_brace_else = add
+# If else is on the same line as '{', force exactly 1 space between them
+sp_else_brace = force
+
+# Functions are the exception and have braces on the next line
+nl_fcall_brace = add
+nl_fdef_brace = add
+
+# Force exactly one space between ')' and '{' in statements
+sp_sparen_brace = force
+
+# At least 1 space around assignment
+sp_assign = add
+
+# Remove spaces around the preprocessor '##' token-concatenate
+sp_pp_concat = ignore
+
+# At least 1 space around '||' and '&&'
+sp_bool = add
+
+# But no space after the '!' operator
+sp_not = remove
+
+# No space after the bitwise-not '~' operator
+sp_inv = remove
+
+# No space after the addressof '&' operator
+sp_addr = remove
+
+# No space around the member '.' and '->' operators
+sp_member = remove
+
+# No space after the dereference '*' operator
+sp_deref = remove
+
+# No space after a unary negation '-'
+sp_sign = remove
+
+# No space between the '++'/'--' operator and its operand
+sp_incdec = remove
+
+# At least 1 space around comparison operators
+sp_compare = add
+
+# Remove spaces inside all kinds of parentheses:
+
+# Remove spaces inside parentheses
+sp_inside_paren = remove
+
+# No spaces inside statement parentheses
+sp_inside_sparen = remove
+
+# No spaces inside cast parentheses '( char )x' -> '(char)x'
+sp_inside_paren_cast = remove
+
+# No spaces inside function parentheses
+sp_inside_fparen = remove
+# (The case where the function has no parameters/arguments)
+sp_inside_fparens = remove
+
+# No spaces inside the first parentheses in a function type
+sp_inside_tparen = remove
+
+# (Uncrustify >= 0.74.0) No spaces inside parens in for statements
+sp_inside_for = remove
+
+# Remove spaces between nested parentheses '( (' -> '(('
+sp_paren_paren = remove
+# (Uncrustify >= 0.74.0)
+sp_sparen_paren = remove
+
+# Remove spaces between ')' and adjacent '('
+sp_cparen_oparen = remove
+
+# (Uncrustify >= 0.73.0) space between 'do' and '{'
+sp_do_brace_open = force
+
+# (Uncrustify >= 0.73.0) space between '}' and 'while'
+sp_brace_close_while = force
+
+# At least 1 space before a '*' pointer star
+sp_before_ptr_star = add
+
+# Remove spaces between pointer stars
+sp_between_ptr_star = remove
+
+# No space after a pointer star
+sp_after_ptr_star = remove
+
+# But allow a space in the case of e.g. char * const x;
+sp_after_ptr_star_qualifier = ignore
+
+# Remove space after star in a function return type
+sp_after_ptr_star_func = remove
+
+# At least 1 space after a type in variable definition etc
+sp_after_type = add
+
+# Force exactly 1 space between a statement keyword (e.g. 'if') and an opening parenthesis
+sp_before_sparen = force
+
+# Remove a space before a ';'
+sp_before_semi = remove
+# (Uncrustify >= 0.73.0) Remove space before a semi in a non-empty for
+sp_before_semi_for = remove
+# (Uncrustify >= 0.73.0) Remove space in empty first statement of a for
+sp_before_semi_for_empty = remove
+# (Uncrustify >= 0.74.0) Remove space in empty middle statement of a for
+sp_between_semi_for_empty = remove
+
+# Add a space after a ';' (unless a comment follows)
+sp_after_semi = add
+# (Uncrustify >= 0.73.0) Add a space after a semi in non-empty for statements
+sp_after_semi_for = add
+# (Uncrustify >= 0.73.0) No space after final semi in empty for statements
+sp_after_semi_for_empty = remove
+
+# Remove spaces on the inside of square brackets '[]'
+sp_inside_square = remove
+
+# Must have at least 1 space after a comma
+sp_after_comma = add
+
+# Must not have a space before a comma
+sp_before_comma = remove
+
+# No space before the ':' in a case statement
+sp_before_case_colon = remove
+
+# Must have space after a cast - '(char)x' -> '(char) x'
+sp_after_cast = add
+
+# No space between 'sizeof' and '('
+sp_sizeof_paren = remove
+
+# At least 1 space inside '{ }'
+sp_inside_braces = add
+
+# At least 1 space inside '{ }' in an enum
+sp_inside_braces_enum = add
+
+# At least 1 space inside '{ }' in a struct
+sp_inside_braces_struct = add
+
+# At least 1 space between a function return type and the function name
+sp_type_func = add
+
+# No space between a function name and its arguments/parameters
+sp_func_proto_paren = remove
+sp_func_def_paren = remove
+sp_func_call_paren = remove
+
+# No space between '__attribute__' and '('
+sp_attribute_paren = remove
+
+# No space between 'defined' and '(' in preprocessor conditions
+sp_defined_paren = remove
+
+# At least 1 space between a macro's name and its definition
+sp_macro = add
+sp_macro_func = add
+
+# Force exactly 1 space between a '}' and the name of a typedef if on the same line
+sp_brace_typedef = force
+
+# At least 1 space before a '\' line continuation
+sp_before_nl_cont = add
+
+# At least 1 space around '?' and ':' in ternary statements
+sp_cond_colon = add
+sp_cond_question = add
+
+# Space between #else/#endif and comment afterwards
+sp_endif_cmt = add
+
+# Remove newlines at the start of a file
+nl_start_of_file = remove
+
+# At least 1 newline at the end of a file
+nl_end_of_file = add
+nl_end_of_file_min = 1
+
+# Add braces in single-line statements
+mod_full_brace_do = add
+mod_full_brace_for = add
+mod_full_brace_if = add
+mod_full_brace_while = add
+
+# Remove parentheses from return statements
+mod_paren_on_return = remove
+
+# Disable removal of leading spaces in a multi-line comment if the first and
+# last lines are the same length
+cmt_multi_check_last = false
diff --git a/BRANCHES.md b/BRANCHES.md
index 6240023..c7a6082 100644
--- a/BRANCHES.md
+++ b/BRANCHES.md
@@ -101,6 +101,6 @@
 - [`development`](https://github.com/Mbed-TLS/mbedtls/)
 - [`mbedtls-2.28`](https://github.com/Mbed-TLS/mbedtls/tree/mbedtls-2.28)
  maintained until at least the end of 2024, see
-  <https://github.com/Mbed-TLS/mbedtls/releases/tag/v2.28.0>.
+  <https://github.com/Mbed-TLS/mbedtls/releases/tag/v2.28.2>.
 
 Users are urged to always use the latest version of a maintained branch.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 59a960a..519604b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -304,22 +304,15 @@
     # additional convenience targets for Unix only
     if(UNIX)
 
-        ADD_CUSTOM_TARGET(covtest
-            COMMAND make test
-            COMMAND programs/test/selftest
-            COMMAND tests/compat.sh
-            COMMAND tests/ssl-opt.sh
-        )
-
+        # For coverage testing:
+        # 1. Build with:
+        #         cmake -D CMAKE_BUILD_TYPE=Coverage /path/to/source && make
+        # 2. Run the relevant tests for the part of the code you're interested in.
+        #    For the reference coverage measurement, see
+        #    tests/scripts/basic-build-test.sh
+        # 3. Run scripts/lcov.sh to generate an HTML report.
         ADD_CUSTOM_TARGET(lcov
-            COMMAND rm -rf Coverage
-            COMMAND lcov --capture --initial --directory library/CMakeFiles/mbedtls.dir -o files.info
-            COMMAND lcov --capture --directory library/CMakeFiles/mbedtls.dir -o tests.info
-            COMMAND lcov --add-tracefile files.info --add-tracefile tests.info -o all.info
-            COMMAND lcov --remove all.info -o final.info '*.h'
-            COMMAND gendesc tests/Descriptions.txt -o descriptions
-            COMMAND genhtml --title "mbed TLS" --description-file descriptions --keep-descriptions --legend --no-branch-coverage -o Coverage final.info
-            COMMAND rm -f files.info tests.info all.info final.info descriptions
+            COMMAND scripts/lcov.sh
         )
 
         ADD_CUSTOM_TARGET(memcheck
@@ -350,12 +343,12 @@
     write_basic_package_version_file(
         "cmake/MbedTLSConfigVersion.cmake"
             COMPATIBILITY SameMajorVersion
-            VERSION 3.2.1)
+            VERSION 3.3.0)
 
     install(
         FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/MbedTLSConfig.cmake"
               "${CMAKE_CURRENT_BINARY_DIR}/cmake/MbedTLSConfigVersion.cmake"
-        DESTINATION "cmake")
+        DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/MbedTLS")
 
     export(
         EXPORT MbedTLSTargets
@@ -365,7 +358,7 @@
     install(
         EXPORT MbedTLSTargets
         NAMESPACE MbedTLS::
-        DESTINATION "cmake"
+        DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/MbedTLS"
         FILE "MbedTLSTargets.cmake")
 
     if(CMAKE_VERSION VERSION_GREATER 3.15 OR CMAKE_VERSION VERSION_EQUAL 3.15)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d19fe57..fc79e49 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -32,13 +32,9 @@
 
 The project aims to minimise the impact on users upgrading to newer versions of the library and it should not be necessary for a user to make any changes to their own code to work with a newer version of the library. Unless the user has made an active decision to use newer features, a newer generation of the library or a change has been necessary due to a security issue or other significant software defect, no modifications to their own code should be necessary. To achieve this, API compatibility is maintained between different versions of Mbed TLS on the main development branch and in LTS (Long Term Support) branches, as described in [BRANCHES.md](BRANCHES.md).
 
-To minimise such disruption to users, where a change to the interface is required, all changes to the ABI or API, even on the main development branch where new features are added, need to be justifiable by either being a significant enhancement, new feature or bug fix which is best resolved by an interface change. If there is an API change, the contribution, if accepted, will be merged only when there will be a major release.
+To minimise such disruption to users, where a change to the interface is required, all changes to the ABI or API, even on the main development branch where new features are added, need to be justifiable by either being a significant enhancement, new feature or bug fix which is best resolved by an interface change. If there is an API change, the contribution, if accepted, will be merged only when there is a major release.
 
-Where changes to an existing interface are necessary, functions in the public interface which need to be changed, are marked as 'deprecated'. This is done with the preprocessor symbols `MBEDTLS_DEPRECATED_WARNING` and `MBEDTLS_DEPRECATED_REMOVED`. Then, a new function with a new name but similar if not identical behaviour to the original function containing the necessary changes should be created alongside the existing deprecated function.
-
-When a build is made with the deprecation preprocessor symbols defined, a compiler warning will be generated to warn a user that the function will be removed at some point in the future, notifying users that they should change from the older deprecated function to the newer function at their own convenience.
-
-Therefore, no changes are permitted to the definition of functions in the public interface which will change the API. Instead the interface can only be changed by its extension. As described above, if a function needs to be changed, a new function needs to be created alongside it, with a new name, and whatever change is necessary, such as a new parameter or the addition of a return value.
+No changes are permitted to the definition of functions in the public interface which will change the API. Instead the interface can only be changed by its extension. Where changes to an existing interface are necessary, functions in the public interface which need to be changed are marked as 'deprecated'. If there is a strong reason to replace an existing function with one that has a slightly different interface (different prototype, or different documented behavior), create a new function with a new name with the desired interface. Keep the old function, but mark it as deprecated.
 
 Periodically, the library will remove deprecated functions from the library which will be a breaking change in the API, but such changes will be made only in a planned, structured way that gives sufficient notice to users of the library.
 
diff --git a/ChangeLog b/ChangeLog
index 80b8617..1404d36 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,9 +1,213 @@
 Mbed TLS ChangeLog (Sorted per branch, date)
 
+= Mbed TLS 3.3.0 branch released 2022-12-14
+
+Default behavior changes
+   * Previously the macro MBEDTLS_SSL_DTLS_CONNECTION_ID implemented version 05
+     of the IETF draft, and was marked experimental and disabled by default.
+     It is now no longer experimental, and implements the final version from
+     RFC 9146, which is not interoperable with the draft-05 version.
+     If you need to communicate with peers that use earlier versions of
+     Mbed TLS, then you need to define MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT
+     to 1, but then you won't be able to communicate with peers that use the
+     standard (non-draft) version.
+     If you need to interoperate with both classes of peers with the
+     same build of Mbed TLS, please let us know about your situation on the
+     mailing list or GitHub.
+
+Requirement changes
+   * When building with PSA drivers using generate_driver_wrappers.py, or
+     when building the library from the development branch rather than
+     from a release, the Python module jsonschema is now necessary, in
+     addition to jinja2. The official list of required Python modules is
+     maintained in scripts/basic.requirements.txt and may change again
+     in the future.
+
+New deprecations
+   * Deprecate mbedtls_asn1_free_named_data().
+     Use mbedtls_asn1_free_named_data_list()
+     or mbedtls_asn1_free_named_data_list_shallow().
+
+Features
+   * Support rsa_pss_rsae_* signature algorithms in TLS 1.2.
+   * make: enable building unversioned shared library, with e.g.:
+     "SHARED=1 SOEXT_TLS=so SOEXT_X509=so SOEXT_CRYPTO=so make lib"
+     resulting in library names like "libmbedtls.so" rather than
+     "libmbedcrypto.so.11".
+   * Expose the EC J-PAKE functionality through the Draft PSA PAKE Crypto API.
+     Only the ECC primitive with secp256r1 curve and SHA-256 hash algorithm
+     are supported in this implementation.
+   * Some modules can now use PSA drivers for hashes, including with no
+     built-in implementation present, but only in some configurations.
+     - RSA OAEP and PSS (PKCS#1 v2.1), PKCS5, PKCS12 and EC J-PAKE now use
+       hashes from PSA when (and only when) MBEDTLS_MD_C is disabled.
+     - PEM parsing of encrypted files now uses MD-5 from PSA when (and only
+       when) MBEDTLS_MD5_C is disabled.
+     See the documentation of the corresponding macros in mbedtls_config.h for
+     details.
+     Note that some modules are not able to use hashes from PSA yet, including
+     the entropy module. As a consequence, for now the only way to build with
+     all hashes only provided by drivers (no built-in hash) is to use
+     MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG.
+   * When MBEDTLS_USE_PSA_CRYPTO is enabled, X.509, TLS 1.2 and TLS 1.3 now
+     properly negotiate/accept hashes based on their availability in PSA.
+     As a consequence, they now work in configurations where the built-in
+     implementations of (some) hashes are excluded and those hashes are only
+     provided by PSA drivers. (See previous entry for limitation on RSA-PSS
+     though: that module only use hashes from PSA when MBEDTLS_MD_C is off).
+   * Add support for opaque keys as the private keys associated to certificates
+     for authentication in TLS 1.3.
+   * Add the LMS post-quantum-safe stateful-hash asymmetric signature scheme.
+     Signature verification is production-ready, but generation is for testing
+     purposes only. This currently only supports one parameter set
+     (LMS_SHA256_M32_H10), meaning that each private key can be used to sign
+     1024 messages. As such, it is not intended for use in TLS, but instead
+     for verification of assets transmitted over an insecure channel,
+     particularly firmware images.
+   * Add the LM-OTS post-quantum-safe one-time signature scheme, which is
+     required for LMS. This can be used independently, but each key can only
+     be used to sign one message so is impractical for most circumstances.
+   * Mbed TLS now supports TLS 1.3 key establishment via pre-shared keys.
+     The pre-shared keys can be provisioned externally or via the ticket
+     mechanism (session resumption).
+     The ticket mechanism is supported when the configuration option
+     MBEDTLS_SSL_SESSION_TICKETS is enabled.
+     New options MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_xxx_ENABLED
+     control the support for the three possible TLS 1.3 key exchange modes.
+   * cert_write: support for setting extended key usage attributes. A
+     corresponding new public API call has been added in the library,
+     mbedtls_x509write_crt_set_ext_key_usage().
+   * cert_write: support for writing certificate files in either PEM
+     or DER format.
+   * The PSA driver wrapper generator generate_driver_wrappers.py now
+     supports a subset of the driver description language, including
+     the following entry points: import_key, export_key, export_public_key,
+     get_builtin_key, copy_key.
+   * The new functions mbedtls_asn1_free_named_data_list() and
+     mbedtls_asn1_free_named_data_list_shallow() simplify the management
+     of memory in named data lists in X.509 structures.
+   * The TLS 1.2 EC J-PAKE key exchange can now use the PSA Crypto API.
+     Additional PSA key slots will be allocated in the process of such key
+     exchange for builds that enable MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED and
+     MBEDTLS_USE_PSA_CRYPTO.
+   * Add support for DTLS Connection ID as defined by RFC 9146, controlled by
+     MBEDTLS_SSL_DTLS_CONNECTION_ID (enabled by default) and configured with
+     mbedtls_ssl_set_cid().
+   * Add a driver dispatch layer for raw key agreement, enabling alternative
+     implementations of raw key agreement through the key_agreement driver
+     entry point. This entry point is specified in the proposed PSA driver
+     interface, but had not yet been implemented.
+   * Add an ad-hoc key derivation function handling EC J-PAKE to PMS
+     calculation that can be used to derive the session secret in TLS 1.2,
+     as described in draft-cragie-tls-ecjpake-01. This can be achieved by
+     using PSA_ALG_TLS12_ECJPAKE_TO_PMS as the key derivation algorithm.
+
+Security
+   * Fix potential heap buffer overread and overwrite in DTLS if
+     MBEDTLS_SSL_DTLS_CONNECTION_ID is enabled and
+     MBEDTLS_SSL_CID_IN_LEN_MAX > 2 * MBEDTLS_SSL_CID_OUT_LEN_MAX.
+   * An adversary with access to precise enough information about memory
+     accesses (typically, an untrusted operating system attacking a secure
+     enclave) could recover an RSA private key after observing the victim
+     performing a single private-key operation if the window size used for the
+     exponentiation was 3 or smaller. Found and reported by Zili KOU,
+     Wenjian HE, Sharad Sinha, and Wei ZHANG. See "Cache Side-channel Attacks
+     and Defenses of the Sliding Window Algorithm in TEEs" - Design, Automation
+     and Test in Europe 2023.
+
+Bugfix
+   * Refactor mbedtls_aes_context to support shallow-copying. Fixes #2147.
+   * Fix an issue with in-tree CMake builds in releases with GEN_FILES
+     turned off: if a shipped file was missing from the working directory,
+     it could be turned into a symbolic link to itself.
+   * Fix a long-standing build failure when building x86 PIC code with old
+     gcc (4.x). The code will be slower, but will compile. We do however
+     recommend upgrading to a more recent compiler instead. Fixes #1910.
+   * Fix support for little-endian Microblaze when MBEDTLS_HAVE_ASM is defined.
+     Contributed by Kazuyuki Kimura to fix #2020.
+   * Use double quotes to include private header file psa_crypto_cipher.h.
+     Fixes 'file not found with <angled> include' error
+     when building with Xcode.
+   * Fix handling of broken symlinks when loading certificates using
+     mbedtls_x509_crt_parse_path(). Instead of returning an error as soon as a
+     broken link is encountered, skip the broken link and continue parsing
+     other certificate files. Contributed by Eduardo Silva in #2602.
+   * Fix an interoperability failure between an Mbed TLS client with both
+     TLS 1.2 and TLS 1.3 support, and a TLS 1.2 server that supports
+     rsa_pss_rsae_* signature algorithms. This failed because Mbed TLS
+     advertised support for PSS in both TLS 1.2 and 1.3, but only
+     actually supported PSS in TLS 1.3.
+   * Fix a compilation error when using CMake with an IAR toolchain.
+     Fixes #5964.
+   * Fix a build error due to a missing prototype warning when
+     MBEDTLS_DEPRECATED_REMOVED is enabled.
+   * Fix mbedtls_ctr_drbg_free() on an initialized but unseeded context. When
+     MBEDTLS_AES_ALT is enabled, it could call mbedtls_aes_free() on an
+     uninitialized context.
+   * Fix a build issue on Windows using CMake where the source and build
+     directories could not be on different drives. Fixes #5751.
+   * Fix bugs and missing dependencies when building and testing
+     configurations with only one encryption type enabled in TLS 1.2.
+   * Provide the missing definition of mbedtls_setbuf() in some configurations
+     with MBEDTLS_PLATFORM_C disabled. Fixes #6118, #6196.
+   * Fix compilation errors when trying to build with
+     PSA drivers for AEAD (GCM, CCM, Chacha20-Poly1305).
+   * Fix memory leak in ssl_parse_certificate_request() caused by
+     mbedtls_x509_get_name() not freeing allocated objects in case of error.
+     Change mbedtls_x509_get_name() to clean up allocated objects on error.
+   * Fix build failure with MBEDTLS_RSA_C and MBEDTLS_PSA_CRYPTO_C but not
+     MBEDTLS_USE_PSA_CRYPTO or MBEDTLS_PK_WRITE_C. Fixes #6408.
+   * Fix build failure with MBEDTLS_RSA_C and MBEDTLS_PSA_CRYPTO_C but not
+     MBEDTLS_PK_PARSE_C. Fixes #6409.
+   * Fix ECDSA verification, where it was not always validating the
+     public key. This bug meant that it was possible to verify a
+     signature with an invalid public key, in some cases. Reported by
+     Guido Vranken using Cryptofuzz in #4420.
+   * Fix a possible null pointer dereference if a memory allocation fails
+     in TLS PRF code. Reported by Michael Madsen in #6516.
+   * Fix TLS 1.3 session resumption. Fixes #6488.
+   * Add a configuration check to exclude optional client authentication
+     in TLS 1.3 (where it is forbidden).
+   * Fix a bug in which mbedtls_x509_crt_info() would produce non-printable
+     bytes when parsing certificates containing a binary RFC 4108
+     HardwareModuleName as a Subject Alternative Name extension. Hardware
+     serial numbers are now rendered in hex format. Fixes #6262.
+   * Fix bug in error reporting in dh_genprime.c where upon failure,
+     the error code returned by mbedtls_mpi_write_file() is overwritten
+     and therefore not printed.
+   * In the bignum module, operations of the form (-A) - (+A) or (-A) - (-A)
+     with A > 0 created an unintended representation of the value 0 which was
+     not processed correctly by some bignum operations. Fix this. This had no
+     consequence on cryptography code, but might affect applications that call
+     bignum directly and use negative numbers.
+   * Fix a bug whereby the list of signature algorithms sent as part of
+     the TLS 1.2 server certificate request would get corrupted, meaning the
+     first algorithm would not get sent and an entry consisting of two random
+     bytes would be sent instead. Found by Serban Bejan and Dudek Sebastian.
+   * Fix undefined behavior (typically harmless in practice) of
+     mbedtls_mpi_add_mpi(), mbedtls_mpi_add_abs() and mbedtls_mpi_add_int()
+     when both operands are 0 and the left operand is represented with 0 limbs.
+   * Fix undefined behavior (typically harmless in practice) when some bignum
+     functions receive the most negative value of mbedtls_mpi_sint. Credit
+     to OSS-Fuzz. Fixes #6597.
+   * Fix undefined behavior (typically harmless in practice) in PSA ECB
+     encryption and decryption.
+   * Move some SSL-specific code out of libmbedcrypto where it had been placed
+     accidentally.
+   * Fix a build error when compiling the bignum module for some Arm platforms.
+     Fixes #6089, #6124, #6217.
+
+Changes
+   * Add the ability to query PSA_WANT_xxx macros to query_compile_time_config.
+   * Calling AEAD tag-specific functions for non-AEAD algorithms (which
+     should not be done - they are documented for use only by AES-GCM and
+     ChaCha20+Poly1305) now returns MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE
+     instead of success (0).
+
 = Mbed TLS 3.2.1 branch released 2022-07-12
 
 Bugfix
-   *  Re-add missing generated file library/ssl_debug_helpers_generated.c
+   *  Re-add missing generated file library/psa_crypto_driver_wrappers.c
 
 = Mbed TLS 3.2.0 branch released 2022-07-11
 
@@ -249,7 +453,7 @@
      make to break on a clean checkout. Fixes #5340.
    * Work around an MSVC ARM64 compiler bug causing incorrect behaviour
      in mbedtls_mpi_exp_mod(). Reported by Tautvydas Žilys in #5467.
-   * Removed the prompt to exit from all windows build programs that was causing
+   * Removed the prompt to exit from all windows build programs, which was causing
      issues in CI/CD environments.
 
 Changes
diff --git a/ChangeLog.d/LMS.txt b/ChangeLog.d/LMS.txt
deleted file mode 100644
index 6de374f..0000000
--- a/ChangeLog.d/LMS.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-Features
-    * Add the LMS post-quantum-safe stateful-hash asymmetric signature scheme.
-      Signature verification is production-ready, but generation is for testing
-      purposes only. This currently only supports one parameter set
-      (LMS_SHA256_M32_H10), meaning that each private key can be used to sign
-      1024 messages. As such, it is not intended for use in TLS, but instead for
-      verification of assets transmitted over an insecure channel, particularly
-      firmware images.
-    * Add the LM-OTS post-quantum-safe one-time signature scheme, which is
-      required for LMS. This can be used independently, but each key can only be
-      used to sign one message so is impractical for most circumstances.
diff --git a/ChangeLog.d/add-rsa-pss-rsae-support-for-tls12.txt b/ChangeLog.d/add-rsa-pss-rsae-support-for-tls12.txt
deleted file mode 100644
index f88eb9e..0000000
--- a/ChangeLog.d/add-rsa-pss-rsae-support-for-tls12.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-Features
-   * When GnuTLS/Openssl server is configured in TLS 1.2 mode with a certificate
-     declaring an RSA public key and Mbed TLS is configured in hybrid mode, if
-     `rsa_pss_rsae_*` algorithms are before `rsa_pkcs1_*` ones in this list then
-     the GnuTLS/Openssl server chooses an `rsa_pss_rsae_*` signature algorithm
-     for its signature in the key exchange message. As Mbed TLS 1.2 does not
-     support them, the handshake fails. Add `rsa_pss_rsae_*` support for TLS 1.2
-     to resolve the compitablity issue.
diff --git a/ChangeLog.d/alignment-perf.txt b/ChangeLog.d/alignment-perf.txt
new file mode 100644
index 0000000..7a8e6fb
--- /dev/null
+++ b/ChangeLog.d/alignment-perf.txt
@@ -0,0 +1,8 @@
+Features
+   * General performance improvements by accessing multiple bytes at a time.
+     Fixes #1666.
+   * Improvements to use of unaligned and byte-swapped memory, reducing code
+     size and improving performance (depending on compiler and target
+     architecture).
+Changes
+   * Mixed-endian systems are explicitly not supported any more.
diff --git a/ChangeLog.d/bn_mul-fix-x86-pic-compilation-for-gcc-4.txt b/ChangeLog.d/bn_mul-fix-x86-pic-compilation-for-gcc-4.txt
deleted file mode 100644
index 1d59c22..0000000
--- a/ChangeLog.d/bn_mul-fix-x86-pic-compilation-for-gcc-4.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Bugfix
-   * Fix a long-standing build failure when building x86 PIC code with old
-     gcc (4.x). The code will be slower, but will compile. We do however
-     recommend upgrading to a more recent compiler instead. Fixes #1910.
diff --git a/ChangeLog.d/cert_write-set-extended-key-usages.txt b/ChangeLog.d/cert_write-set-extended-key-usages.txt
deleted file mode 100644
index 18b7b04..0000000
--- a/ChangeLog.d/cert_write-set-extended-key-usages.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Features
-   * cert_write: support for setting extended key usage attributes. A
-     corresponding new public API call has been added in the library,
-     mbedtls_x509write_crt_set_ext_key_usage().
-   * cert_write: support for writing certificate files in either PEM
-     or DER format.
diff --git a/ChangeLog.d/cmake-install.txt b/ChangeLog.d/cmake-install.txt
new file mode 100644
index 0000000..d8eb72e
--- /dev/null
+++ b/ChangeLog.d/cmake-install.txt
@@ -0,0 +1,3 @@
+Changes
+  * Install the .cmake files into CMAKE_INSTALL_LIBDIR/cmake/MbedTLS,
+    typically /usr/lib/cmake/MbedTLS.
diff --git a/ChangeLog.d/driver-only-hashes.txt b/ChangeLog.d/driver-only-hashes.txt
deleted file mode 100644
index 2062bcb..0000000
--- a/ChangeLog.d/driver-only-hashes.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-Features
-   * Some crypto modules that previously depended on MD or a low-level hash
-     module, either unconditionally (RSA, PK, PKCS5, PKCS12, EC J-PAKE), or
-     for some features (PEM for encrypted files), are now able to use PSA
-     Crypto instead when the legacy API is not available. This means it is
-     now possible to use all features from those modules in configurations
-     where the built-in implementations of hashes are excluded and the hashes
-     are only provided by PSA drivers. In these configurations, you need to
-     call `psa_crypto_init()` before you call any function from those
-     modules; this is not required in configurations where the built-in
-     implementation is still available. Note that some crypto modules and
-     features still depend on the built-in implementation of hashes:
-     MBEDTLS_HKDF_C (but the PSA HKDF function do not depend on it),
-     MBEDTLS_ENTROPY_C, MBEDTLS_HMAC_DRBG_C and MBEDTLS_ECDSA_DETERMINISTIC.
-     In particular, for now, compiling without built-in hashes requires use
-     of MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG.
-   * When MBEDTLS_USE_PSA_CRYPTO is enabled, X.509, TLS 1.2 and TLS 1.3 no
-     longer depend on MD. This means it is now possible to use them in
-     configurations where the built-in implementations of hashes are excluded
-     and the hashes are only provided by PSA drivers.
diff --git a/ChangeLog.d/ecdsa-verify-fixes.txt b/ChangeLog.d/ecdsa-verify-fixes.txt
deleted file mode 100644
index b41b046..0000000
--- a/ChangeLog.d/ecdsa-verify-fixes.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Bugfix
-   * Fix ECDSA verification, where it was not always validating the
-     public key. This bug meant that it was possible to verify a
-     signature with an invalid public key, in some cases. Reported by
-     Guido Vranken using Cryptofuzz in #4420.
diff --git a/ChangeLog.d/ecjpake_to_pms.txt b/ChangeLog.d/ecjpake_to_pms.txt
deleted file mode 100644
index 4dd2075..0000000
--- a/ChangeLog.d/ecjpake_to_pms.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-API changes
-   * Add an ad-hoc key derivation function handling ECJPAKE to PMS
-     calculation that can be used to derive the session secret in TLS 1.2,
-     as described in draft-cragie-tls-ecjpake-01. This can be achieved by
-     using PSA_ALG_TLS12_ECJPAKE_TO_PMS as the key derivation algorithm.
diff --git a/ChangeLog.d/extend-query_compile_time_config-to-psa_want.txt b/ChangeLog.d/extend-query_compile_time_config-to-psa_want.txt
deleted file mode 100644
index b268fd4..0000000
--- a/ChangeLog.d/extend-query_compile_time_config-to-psa_want.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Changes
-   * Add the ability to query PSA_WANT_xxx macros to query_compile_time_config
diff --git a/ChangeLog.d/fix-aes-shallow-copying.txt b/ChangeLog.d/fix-aes-shallow-copying.txt
deleted file mode 100644
index 0c119d6..0000000
--- a/ChangeLog.d/fix-aes-shallow-copying.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Bugfix
-   * Refactor mbedtls_aes_context to support shallow-copying. Fixes #2147.
diff --git a/ChangeLog.d/fix-ctr-drbg-may-free-invalid-aes-context.txt b/ChangeLog.d/fix-ctr-drbg-may-free-invalid-aes-context.txt
deleted file mode 100644
index fe62c28..0000000
--- a/ChangeLog.d/fix-ctr-drbg-may-free-invalid-aes-context.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Bugfix
-    * Fix mbedtls_ctr_drbg_free() on an initialized but unseeded context. When
-      MBEDTLS_AES_ALT is enabled, it could call mbedtls_aes_free() on an
-      uninitialized context.
diff --git a/ChangeLog.d/fix-gettimeofday-overflow.txt b/ChangeLog.d/fix-gettimeofday-overflow.txt
new file mode 100644
index 0000000..b7e10d2
--- /dev/null
+++ b/ChangeLog.d/fix-gettimeofday-overflow.txt
@@ -0,0 +1,3 @@
+Bugfix
+   * Fix possible integer overflow in mbedtls_timing_hardclock(), which
+     could cause a crash in programs/test/benchmark.
diff --git a/ChangeLog.d/fix_aead_psa_driver_build.txt b/ChangeLog.d/fix_aead_psa_driver_build.txt
deleted file mode 100644
index a6d11d3..0000000
--- a/ChangeLog.d/fix_aead_psa_driver_build.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix compilation errors when trying to build with
-     PSA drivers for AEAD (GCM, CCM, Chacha20-Poly1305).
diff --git a/ChangeLog.d/fix_build_error_for_mbedtls_deprecated_removed.txt b/ChangeLog.d/fix_build_error_for_mbedtls_deprecated_removed.txt
deleted file mode 100644
index a70521a..0000000
--- a/ChangeLog.d/fix_build_error_for_mbedtls_deprecated_removed.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-    * Fix build error due to missing prototype
-      warning when MBEDTLS_DEPRECATED_REMOVED is enabled
diff --git a/ChangeLog.d/fix_build_tls1_2_with_single_encryption_type.txt b/ChangeLog.d/fix_build_tls1_2_with_single_encryption_type.txt
deleted file mode 100644
index bac4910..0000000
--- a/ChangeLog.d/fix_build_tls1_2_with_single_encryption_type.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Bugfix
-    * Fix bugs and missing dependencies when
-      building and testing configurations with
-      only one encryption type enabled in TLS 1.2.
diff --git a/ChangeLog.d/fix_cmake_gen_files b/ChangeLog.d/fix_cmake_gen_files
deleted file mode 100644
index 3b2c099..0000000
--- a/ChangeLog.d/fix_cmake_gen_files
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix an issue in releases with GEN_FILES turned off whereby missing
-     generated files could be turned into symlinks to themselves.
diff --git a/ChangeLog.d/fix_cmake_using_iar_toolchain.txt b/ChangeLog.d/fix_cmake_using_iar_toolchain.txt
deleted file mode 100644
index ecc09c2..0000000
--- a/ChangeLog.d/fix_cmake_using_iar_toolchain.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fixed an issue that cause compile error using CMake IAR toolchain.
-     Fixes #5964.
diff --git a/ChangeLog.d/fix_hard_link_across_drives b/ChangeLog.d/fix_hard_link_across_drives
deleted file mode 100644
index 0c55c30..0000000
--- a/ChangeLog.d/fix_hard_link_across_drives
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix a build issue on Windows where the source and build directory could not be on
-     different drives (#5751).
diff --git a/ChangeLog.d/fix_psa_crypto_cipher_h_include.txt b/ChangeLog.d/fix_psa_crypto_cipher_h_include.txt
deleted file mode 100644
index bf2e65d..0000000
--- a/ChangeLog.d/fix_psa_crypto_cipher_h_include.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Bugfix
-   * Use double quotes to include private header file psa_crypto_cipher.h.
-     Fixes 'file not found with <angled> include' error
-     when building with Xcode.
diff --git a/ChangeLog.d/fix_tls13_session_resumption_fail_when_hostname_is_not_localhost.txt b/ChangeLog.d/fix_tls13_session_resumption_fail_when_hostname_is_not_localhost.txt
deleted file mode 100644
index 5797f48..0000000
--- a/ChangeLog.d/fix_tls13_session_resumption_fail_when_hostname_is_not_localhost.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Bugfix
-    * Fix TLS 1.3 session resumption fail. Fixes #6488.
-    * Add configuration check to exclude TLS 1.3 optional authentication of
-      client.
diff --git a/ChangeLog.d/fix_x509_get_name_mem_leak.txt b/ChangeLog.d/fix_x509_get_name_mem_leak.txt
deleted file mode 100644
index 358d1af..0000000
--- a/ChangeLog.d/fix_x509_get_name_mem_leak.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Bugfix
-    * Fix memory leak in ssl_parse_certificate_request() caused by
-      mbedtls_x509_get_name() not freeing allocated objects in case of error.
-      Change mbedtls_x509_get_name() to clean up allocated objects on error.
diff --git a/ChangeLog.d/fix_x509_info_hwmodulename.txt b/ChangeLog.d/fix_x509_info_hwmodulename.txt
deleted file mode 100644
index 8b227ce..0000000
--- a/ChangeLog.d/fix_x509_info_hwmodulename.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Bugfix
-   * Fix a bug in which mbedtls_x509_crt_info() would produce non-printable
-     bytes when parsing certificates containing a binary RFC 4108
-     HardwareModuleName as a Subject Alternative Name extension. Hardware
-     serial numbers are now rendered in hex format. Fixes #6262.
diff --git a/ChangeLog.d/fix_zeroization.txt b/ChangeLog.d/fix_zeroization.txt
deleted file mode 100644
index ad74d9c..0000000
--- a/ChangeLog.d/fix_zeroization.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix possible crash in TLS PRF code, if a failure to allocate memory occurs.
-     Reported by Michael Madsen in #6516.
diff --git a/ChangeLog.d/mbedtls_asn1_type_free.txt b/ChangeLog.d/mbedtls_asn1_type_free.txt
deleted file mode 100644
index 81f3a20..0000000
--- a/ChangeLog.d/mbedtls_asn1_type_free.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Features
-   * Shared code to free x509 structs like mbedtls_x509_named_data
-New deprecations
-   * Deprecate mbedtls_asn1_free_named_data().
-     Use mbedtls_asn1_free_named_data_list()
-     or mbedtls_asn1_free_named_data_list_shallow()
diff --git a/ChangeLog.d/mbedtls_ecp_point_read_binary-compressed-fmt.txt b/ChangeLog.d/mbedtls_ecp_point_read_binary-compressed-fmt.txt
new file mode 100644
index 0000000..44253dd
--- /dev/null
+++ b/ChangeLog.d/mbedtls_ecp_point_read_binary-compressed-fmt.txt
@@ -0,0 +1,6 @@
+Features
+   * Add support for reading points in compressed format
+     (MBEDTLS_ECP_PF_COMPRESSED) with mbedtls_ecp_point_read_binary()
+     (and callers) for Short Weierstrass curves with prime p where p = 3 mod 4
+     (all mbedtls MBEDTLS_ECP_DP_SECP* and MBEDTLS_ECP_DP_BP* curves
+      except MBEDTLS_ECP_DP_SECP224R1 and MBEDTLS_ECP_DP_SECP224K1)
diff --git a/ChangeLog.d/muladdc_microblaze.txt b/ChangeLog.d/muladdc_microblaze.txt
deleted file mode 100644
index 70fdff0..0000000
--- a/ChangeLog.d/muladdc_microblaze.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix support for little-endian Microblaze when MBEDTLS_HAVE_ASM is defined.
-     Contributed by Kazuyuki Kimura to fix #2020.
diff --git a/ChangeLog.d/nonversioned-library-soname.txt b/ChangeLog.d/nonversioned-library-soname.txt
deleted file mode 100644
index 8d83a2d..0000000
--- a/ChangeLog.d/nonversioned-library-soname.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Features
-   * make: enable building unversioned shared library, with e.g.:
-     "SHARED=1 SOEXT_TLS=so SOEXT_X509=so SOEXT_CRYPTO=so make lib"
-     resulting in library names like "libmbedtls.so" rather than
-     "libmbedcrypto.so.11".
diff --git a/ChangeLog.d/pk-sign-restartable.txt b/ChangeLog.d/pk-sign-restartable.txt
new file mode 100644
index 0000000..35da2be
--- /dev/null
+++ b/ChangeLog.d/pk-sign-restartable.txt
@@ -0,0 +1,5 @@
+Changes
+   * When MBEDTLS_USE_PSA_CRYPTO and MBEDTLS_ECDSA_DETERMINISTIC are both
+     defined, mbedtls_pk_sign() now use deterministic ECDSA for ECDSA
+     signatures. This aligns the behaviour with MBEDTLS_USE_PSA_CRYPTO to
+     the behaviour without it, where deterministic ECDSA was already used.
diff --git a/ChangeLog.d/platform-setbuf.txt b/ChangeLog.d/platform-setbuf.txt
deleted file mode 100644
index 844f70c..0000000
--- a/ChangeLog.d/platform-setbuf.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Provide the missing definition of mbedtls_setbuf() in some configurations
-     with MBEDTLS_PLATFORM_C disabled. Fixes #6118, #6196.
diff --git a/ChangeLog.d/psa_crypto_code_gen_1_1.txt b/ChangeLog.d/psa_crypto_code_gen_1_1.txt
deleted file mode 100644
index 2c18e6f..0000000
--- a/ChangeLog.d/psa_crypto_code_gen_1_1.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Features
-    * Brought in PSA code geneneration JSON driver list.
-      Added auto generated templating support for key management.
-      Added Support for transparent and opaque keys (import/export/copy).
-      Included some general JSON validation for the given entry points.
-      Addresses version 1.1 of #5137.
diff --git a/ChangeLog.d/psa_crypto_pake.txt b/ChangeLog.d/psa_crypto_pake.txt
deleted file mode 100644
index e0ae046..0000000
--- a/ChangeLog.d/psa_crypto_pake.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Features
-    * Expose the EC J-PAKE functionality through the Draft PSA PAKE Crypto API.
-      Only the ECC primitive with secp256r1 curve and SHA-256 hash algorithm
-      are supported in this implementation.
diff --git a/ChangeLog.d/psa_rsa_needs_pk.txt b/ChangeLog.d/psa_rsa_needs_pk.txt
deleted file mode 100644
index 995963d..0000000
--- a/ChangeLog.d/psa_rsa_needs_pk.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Bugfix
-   * Fix build failure with MBEDTLS_RSA_C and MBEDTLS_PSA_CRYPTO_C but not
-     MBEDTLS_USE_PSA_CRYPTO or MBEDTLS_PK_WRITE_C. Fixes #6408.
-   * Fix build failure with MBEDTLS_RSA_C and MBEDTLS_PSA_CRYPTO_C but not
-     MBEDTLS_PK_PARSE_C. Fixes #6409.
diff --git a/ChangeLog.d/remove_ssl_session_compression.txt b/ChangeLog.d/remove_ssl_session_compression.txt
deleted file mode 100644
index dc59f1c..0000000
--- a/ChangeLog.d/remove_ssl_session_compression.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Removals
-   * Remove compression property from SSL session struct.
-     MBEDTLS_SSL_COMPRESS_NULL is now the only supported
-     compression option and can be used for compatibility
-     reasons. Changes requested in #4223.
diff --git a/ChangeLog.d/tls13-misc.txt b/ChangeLog.d/tls13-misc.txt
deleted file mode 100644
index 497ed38..0000000
--- a/ChangeLog.d/tls13-misc.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-Features
-   * Mbed TLS supports TLS 1.3 key establishment via pre-shared keys,
-     pre-shared keys provisioned externally or via the ticket mechanism
-     (session resumption).
-     The MBEDTLS_SSL_SESSION_TICKETS configuration option controls the support
-     for the ticket mechanism.
-     MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_xxx_ENABLED configuration options
-     have been introduced to control the support for the three possible
-     TLS 1.3 key exchange modes.
diff --git a/ChangeLog.d/tls13_sig_alg_selection.txt b/ChangeLog.d/tls13_sig_alg_selection.txt
deleted file mode 100644
index 8857750..0000000
--- a/ChangeLog.d/tls13_sig_alg_selection.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Features
-   * Add support for opaque keys as the private keys associated to certificates
-     for authentication in TLS 1.3.
diff --git a/ChangeLog.d/x509-broken-symlink-handling.txt b/ChangeLog.d/x509-broken-symlink-handling.txt
deleted file mode 100644
index 52288dc..0000000
--- a/ChangeLog.d/x509-broken-symlink-handling.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Bugfix
-   * Fix handling of broken symlinks when loading certificates using
-     mbedtls_x509_crt_parse_path(). Instead of returning an error as soon as a
-     broken link is encountered, skip the broken link and continue parsing
-     other certificate files. Contributed by Eduardo Silva in #2602.
diff --git a/Makefile b/Makefile
index 5b2ad16..2f1be65 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
 
 .SILENT:
 
-.PHONY: all no_test programs lib tests install uninstall clean test check covtest lcov apidoc apidoc_clean
+.PHONY: all no_test programs lib tests install uninstall clean test check lcov apidoc apidoc_clean
 
 all: programs tests
 	$(MAKE) post_build
@@ -136,23 +136,15 @@
 test: check
 
 ifndef WINDOWS
-# note: for coverage testing, build with:
-# make CFLAGS='--coverage -g3 -O0'
-covtest:
-	$(MAKE) check
-	programs/test/selftest
-	tests/compat.sh
-	tests/ssl-opt.sh
-
+# For coverage testing:
+# 1. Build with:
+#         make CFLAGS='--coverage -g3 -O0' LDFLAGS='--coverage'
+# 2. Run the relevant tests for the part of the code you're interested in.
+#    For the reference coverage measurement, see
+#    tests/scripts/basic-build-test.sh
+# 3. Run scripts/lcov.sh to generate an HTML report.
 lcov:
-	rm -rf Coverage
-	lcov --capture --initial --directory library -o files.info
-	lcov --rc lcov_branch_coverage=1 --capture --directory library -o tests.info
-	lcov --rc lcov_branch_coverage=1 --add-tracefile files.info --add-tracefile tests.info -o all.info
-	lcov --rc lcov_branch_coverage=1 --remove all.info -o final.info '*.h'
-	gendesc tests/Descriptions.txt -o descriptions
-	genhtml --title "mbed TLS" --description-file descriptions --keep-descriptions --legend --branch-coverage -o Coverage final.info
-	rm -f files.info tests.info all.info final.info descriptions
+	scripts/lcov.sh
 
 apidoc:
 	mkdir -p apidoc
diff --git a/README.md b/README.md
index 1a4edb0..cc70f56 100644
--- a/README.md
+++ b/README.md
@@ -245,6 +245,8 @@
 -   `tests/scripts/depends.py` test builds in configurations with a single curve, key exchange, hash, cipher, or pkalg on.
 -   `tests/scripts/all.sh` runs a combination of the above tests, plus some more, with various build options (such as ASan, full `mbedtls_config.h`, etc).
 
+Instead of manually installing the required versions of all tools required for testing, it is possible to use the Docker images from our CI systems, as explained in [our testing infrastructure repository](https://github.com/Mbed-TLS/mbedtls-test/blob/master/README.md#quick-start).
+
 Porting Mbed TLS
 ----------------
 
@@ -261,6 +263,7 @@
 - Signed integers must be represented using two's complement.
 - `int` and `size_t` must be at least 32 bits wide.
 - The types `uint8_t`, `uint16_t`, `uint32_t` and their signed equivalents must be available.
+- Mixed-endian platforms are not supported.
 
 PSA cryptography API
 --------------------
diff --git a/docs/architecture/psa-migration/outcome-analysis.sh b/docs/architecture/psa-migration/outcome-analysis.sh
index 81ab691..9084685 100755
--- a/docs/architecture/psa-migration/outcome-analysis.sh
+++ b/docs/architecture/psa-migration/outcome-analysis.sh
@@ -13,6 +13,7 @@
 # - the set of tests skipped in the driver-only build is the same as in an
 #   equivalent software-based configuration, or the difference is small enough,
 #   justified, and a github issue is created to track it.
+#   This part is verified by tests/scripts/analyze_outcomes.py
 #
 # WARNING: this script checks out a commit other than the head of the current
 # branch; it checks out the current branch again when running successfully,
@@ -26,30 +27,12 @@
 # re-running this script (for example "get numbers before this PR").
 
 # ----- BEGIN edit this -----
-# The component in all.sh that builds and tests with drivers.
-DRIVER_COMPONENT=test_psa_crypto_config_accel_hash_use_psa
-# A similar configuration to that of the component, except without drivers,
-# for comparison.
-reference_config () {
-    # start with full
-    scripts/config.py full
-    # use PSA config and disable driver-less algs as in the component
-    scripts/config.py set MBEDTLS_PSA_CRYPTO_CONFIG
-    scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_STREAM_CIPHER
-    scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_ECB_NO_PADDING
-    # disable options as in the component
-    # (no need to disable whole modules, we'll just skip their test suite)
-    scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC
-    scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_DETERMINISTIC_ECDSA
-}
 # Space-separated list of test suites to ignore:
 # if SSS is in that list, test_suite_SSS and test_suite_SSS.* are ignored.
 IGNORE="md mdx shax" # accelerated
 IGNORE="$IGNORE entropy hmac_drbg random" # disabled (ext. RNG)
 IGNORE="$IGNORE psa_crypto_init" # needs internal RNG
 IGNORE="$IGNORE hkdf" # disabled in the all.sh component tested
-# Compare only "reference vs driver" or also "before vs after"?
-BEFORE_AFTER=1 # 0 or 1
 # ----- END edit this -----
 
 set -eu
@@ -65,38 +48,27 @@
     make check
 }
 
-if [ "$BEFORE_AFTER" -eq 1 ]; then
-    # save current HEAD
-    HEAD=$(git branch --show-current)
+# save current HEAD
+HEAD=$(git branch --show-current)
 
-    # get the numbers before this PR for default and full
-    cleanup
-    git checkout $(git merge-base HEAD development)
-    record "before-default"
-
-    cleanup
-    scripts/config.py full
-    record "before-full"
-
-    # get the numbers now for default and full
-    cleanup
-    git checkout $HEAD
-    record "after-default"
-
-    cleanup
-    scripts/config.py full
-    record "after-full"
-fi
-
-# get the numbers now for driver-only and reference
+# get the numbers before this PR for default and full
 cleanup
-reference_config
-record "reference"
+git checkout $(git merge-base HEAD development)
+record "before-default"
 
 cleanup
-export MBEDTLS_TEST_OUTCOME_FILE="$PWD/outcome-drivers.csv"
-export SKIP_SSL_OPT_COMPAT_SH=1
-tests/scripts/all.sh -k test_psa_crypto_config_accel_hash_use_psa
+scripts/config.py full
+record "before-full"
+
+# get the numbers now for default and full
+cleanup
+git checkout $HEAD
+record "after-default"
+
+cleanup
+scripts/config.py full
+record "after-full"
+
 
 # analysis
 
@@ -156,8 +128,5 @@
 }
 
 populate_suites
-if [ "$BEFORE_AFTER" -eq 1 ]; then
-    compare_builds before-default after-default
-    compare_builds before-full after-full
-fi
-compare_builds reference drivers
+compare_builds before-default after-default
+compare_builds before-full after-full
diff --git a/docs/architecture/psa-migration/psa-limitations.md b/docs/architecture/psa-migration/psa-limitations.md
index e565b28..c368023 100644
--- a/docs/architecture/psa-migration/psa-limitations.md
+++ b/docs/architecture/psa-migration/psa-limitations.md
@@ -17,8 +17,11 @@
 There is currently no support for that in PSA at all, but it will be added at
 some point, see <https://github.com/orgs/Mbed-TLS/projects/1#column-18816849>.
 
-Currently, `MBEDTLS_USE_PSA_CRYPTO` is simply incompatible with
-`MBEDTLS_ECP_RESTARTABLE`.
+Currently, when `MBEDTLS_USE_PSA_CRYPTO` and `MBEDTLS_ECP_RESTARTABLE` are
+both enabled, some operations that should be restartable are not (ECDH in TLS
+1.2 clients using ECDHE-ECDSA), as they are using PSA instead, and some
+operations that should use PSA do not (signature generation & verification) as
+they use the legacy API instead, in order to get restartable behaviour.
 
 Things that are in the API but not implemented yet
 --------------------------------------------------
diff --git a/docs/architecture/tls13-support.md b/docs/architecture/tls13-support.md
index f30590b..85482ba 100644
--- a/docs/architecture/tls13-support.md
+++ b/docs/architecture/tls13-support.md
@@ -478,3 +478,175 @@
 
 * state change: the state change is done in the main state handler to ease
 the navigation of the state machine transitions.
+
+
+Writing and reading early or 0-RTT data
+---------------------------------------
+
+An application function to write and send a buffer of data to a server through
+TLS may plausibly look like:
+
+```
+int write_data( mbedtls_ssl_context *ssl,
+                const unsigned char *data_to_write,
+                size_t data_to_write_len,
+                size_t *data_written )
+{
+    *data_written = 0;
+
+    while( *data_written < data_to_write_len )
+    {
+        ret = mbedtls_ssl_write( ssl, data_to_write + *data_written,
+                                 data_to_write_len - *data_written );
+
+        if( ret < 0 &&
+            ret != MBEDTLS_ERR_SSL_WANT_READ &&
+            ret != MBEDTLS_ERR_SSL_WANT_WRITE )
+        {
+            return( ret );
+        }
+
+        *data_written += ret;
+    }
+
+    return( 0 );
+}
+```
+where ssl is the SSL context to use, data_to_write the address of the data
+buffer and data_to_write_len the number of data bytes. The handshake may
+not be completed, not even started for the SSL context ssl when the function is
+called and in that case the mbedtls_ssl_write() API takes care transparently of
+completing the handshake before to write and send data to the server. The
+mbedtls_ssl_write() may not been able to write and send all data in one go thus
+the need for a loop calling it as long as there are still data to write and
+send.
+
+An application function to write and send early data and only early data,
+data sent during the first flight of client messages while the handshake is in
+its initial phase, would look completely similar but the call to
+mbedtls_ssl_write_early_data() instead of mbedtls_ssl_write().
+```
+int write_early_data( mbedtls_ssl_context *ssl,
+                      const unsigned char *data_to_write,
+                      size_t data_to_write_len,
+                      size_t *data_written )
+{
+    *data_written = 0;
+
+    while( *data_written < data_to_write_len )
+    {
+        ret = mbedtls_ssl_write_early_data( ssl, data_to_write + *data_written,
+                                            data_to_write_len - *data_written );
+
+        if( ret < 0 &&
+            ret != MBEDTLS_ERR_SSL_WANT_READ &&
+            ret != MBEDTLS_ERR_SSL_WANT_WRITE )
+        {
+            return( ret );
+        }
+
+        *data_written += ret;
+    }
+
+    return( 0 );
+}
+```
+Note that compared to write_data(), write_early_data() can also return
+MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA and that should be handled
+specifically by the user of write_early_data(). A fresh SSL context (typically
+just after a call to mbedtls_ssl_setup() or mbedtls_ssl_session_reset()) would
+be expected when calling `write_early_data`.
+
+All together, code to write and send a buffer of data as long as possible as
+early data and then as standard post-handshake application data could
+plausibly look like:
+
+```
+ret = write_early_data( ssl, data_to_write, data_to_write_len,
+                        &early_data_written );
+if( ret < 0 &&
+    ret != MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA )
+{
+    goto error;
+}
+
+ret = write_data( ssl, data_to_write + early_data_written,
+                  data_to_write_len - early_data_written, &data_written );
+if( ret < 0 )
+    goto error;
+
+data_written += early_data_written;
+```
+
+Finally, taking into account that the server may reject early data, application
+code to write and send a buffer of data could plausibly look like:
+```
+ret = write_early_data( ssl, data_to_write, data_to_write_len,
+                        &early_data_written );
+if( ret < 0 &&
+    ret != MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA )
+{
+    goto error;
+}
+
+/*
+ * Make sure the handshake is completed as it is a requisite to
+ * mbedtls_ssl_get_early_data_status().
+ */
+while( !mbedtls_ssl_is_handshake_over( ssl ) )
+{
+    ret = mbedtls_ssl_handshake( ssl );
+    if( ret < 0 &&
+        ret != MBEDTLS_ERR_SSL_WANT_READ &&
+        ret != MBEDTLS_ERR_SSL_WANT_WRITE )
+    {
+        goto error;
+    }
+}
+
+ret = mbedtls_ssl_get_early_data_status( ssl );
+if( ret < 0 )
+    goto error;
+
+if( ret == MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED )
+   early_data_written = 0;
+
+ret = write_data( ssl, data_to_write + early_data_written,
+                  data_to_write_len - early_data_written, &data_written );
+if( ret < 0 )
+    goto error;
+
+data_written += early_data_written;
+```
+
+Basically, the same holds for reading early data on the server side without the
+complication of possible rejection. An application function to read early data
+into a given buffer could plausibly look like:
+```
+int read_early_data( mbedtls_ssl_context *ssl,
+                     unsigned char *buffer,
+                     size_t buffer_size,
+                     size_t *data_len )
+{
+    *data_len = 0;
+
+    while( *data_len < buffer_size )
+    {
+        ret = mbedtls_ssl_read_early_data( ssl, buffer + *data_len,
+                                           buffer_size - *data_len );
+
+        if( ret < 0 &&
+            ret != MBEDTLS_ERR_SSL_WANT_READ &&
+            ret != MBEDTLS_ERR_SSL_WANT_WRITE )
+        {
+            return( ret );
+        }
+
+        *data_len += ret;
+    }
+
+    return( 0 );
+}
+```
+with again calls to read_early_data() expected to be done with a fresh SSL
+context.
diff --git a/docs/use-psa-crypto.md b/docs/use-psa-crypto.md
index b22d37f..194d96f 100644
--- a/docs/use-psa-crypto.md
+++ b/docs/use-psa-crypto.md
@@ -7,9 +7,6 @@
 General considerations
 ----------------------
 
-**Compile-time:** enabling `MBEDTLS_USE_PSA_CRYPTO` requires
-`MBEDTLS_ECP_RESTARTABLE` to be disabled.
-
 **Application code:** when this option is enabled, you need to call
 `psa_crypto_init()` before calling any function from the SSL/TLS, X.509 or PK
 module.
@@ -86,29 +83,34 @@
 
 Current exceptions:
 
-- EC J-PAKE (when `MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED` is defined)
-- finite-field (non-EC) Diffie-Hellman (used in key exchanges: DHE-RSA,
-  DHE-PSK)
+- Finite-field (non-EC) Diffie-Hellman (used in key exchanges: DHE-RSA,
+  DHE-PSK).
+- Restartable operations when `MBEDTLS_ECP_RESTARTABLE` is also enabled (see
+  the documentation of that option).
 
 Other than the above exceptions, all crypto operations are based on PSA when
 `MBEDTLS_USE_PSA_CRYPTO` is enabled.
 
 ### X.509: most crypto operations based on PSA
 
-Current exception:
+Current exceptions:
 
-- verification of RSA-PSS signatures with a salt length that is different from
+- Verification of RSA-PSS signatures with a salt length that is different from
   the hash length.
+- Restartable operations when `MBEDTLS_ECP_RESTARTABLE` is also enabled (see
+  the documentation of that option).
 
 Other than the above exception, all crypto operations are based on PSA when
 `MBEDTLS_USE_PSA_CRYPTO` is enabled.
 
 ### PK layer: most crypto operations based on PSA
 
-Current exception:
+Current exceptions:
 
-- verification of RSA-PSS signatures with a salt length that is different from
+- Verification of RSA-PSS signatures with a salt length that is different from
   the hash length, or with an MGF hash that's different from the message hash.
+- Restartable operations when `MBEDTLS_ECP_RESTARTABLE` is also enabled (see
+  the documentation of that option).
 
 Other than the above exception, all crypto operations are based on PSA when
 `MBEDTLS_USE_PSA_CRYPTO` is enabled.
diff --git a/doxygen/input/doc_encdec.h b/doxygen/input/doc_encdec.h
index 96734bd..ec149ae 100644
--- a/doxygen/input/doc_encdec.h
+++ b/doxygen/input/doc_encdec.h
@@ -38,7 +38,7 @@
  * All symmetric encryption algorithms are accessible via the generic cipher layer
  * (see \c mbedtls_cipher_setup()).
  *
- * The asymmetric encryptrion algorithms are accessible via the generic public
+ * The asymmetric encryption algorithms are accessible via the generic public
  * key layer (see \c mbedtls_pk_init()).
  *
  * The following algorithms are provided:
diff --git a/doxygen/input/doc_mainpage.h b/doxygen/input/doc_mainpage.h
index c05042b..7c6464f 100644
--- a/doxygen/input/doc_mainpage.h
+++ b/doxygen/input/doc_mainpage.h
@@ -22,7 +22,7 @@
  */
 
 /**
- * @mainpage mbed TLS v3.2.1 source code documentation
+ * @mainpage mbed TLS v3.3.0 source code documentation
  *
  * This documentation describes the internal structure of mbed TLS.  It was
  * automatically generated from specially formatted comment blocks in
diff --git a/doxygen/mbedtls.doxyfile b/doxygen/mbedtls.doxyfile
index f722d28..0c744da 100644
--- a/doxygen/mbedtls.doxyfile
+++ b/doxygen/mbedtls.doxyfile
@@ -1,4 +1,4 @@
-PROJECT_NAME           = "mbed TLS v3.2.1"
+PROJECT_NAME           = "mbed TLS v3.3.0"
 OUTPUT_DIRECTORY       = ../apidoc/
 FULL_PATH_NAMES        = NO
 OPTIMIZE_OUTPUT_FOR_C  = YES
diff --git a/include/mbedtls/aes.h b/include/mbedtls/aes.h
index c359011..1cd20fe 100644
--- a/include/mbedtls/aes.h
+++ b/include/mbedtls/aes.h
@@ -61,11 +61,6 @@
 /** Invalid input data. */
 #define MBEDTLS_ERR_AES_BAD_INPUT_DATA                    -0x0021
 
-#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
-    !defined(inline) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/include/mbedtls/asn1.h b/include/mbedtls/asn1.h
index 8b66ee2..5e3f387 100644
--- a/include/mbedtls/asn1.h
+++ b/include/mbedtls/asn1.h
@@ -39,8 +39,9 @@
 
 /**
  * \name ASN1 Error codes
- * These error codes are OR'ed to X509 error codes for
+ * These error codes are combined with other error codes for
  * higher error granularity.
+ * e.g. X.509 and PKCS #7 error codes
  * ASN1 is a standard to specify data structures.
  * \{
  */
diff --git a/include/mbedtls/asn1write.h b/include/mbedtls/asn1write.h
index 5554720..e6f0479 100644
--- a/include/mbedtls/asn1write.h
+++ b/include/mbedtls/asn1write.h
@@ -352,7 +352,7 @@
  *                  the existing buffer to fit \p val_len.
  *
  * \return          A pointer to the new / existing entry on success.
- * \return          \c NULL if if there was a memory allocation error.
+ * \return          \c NULL if there was a memory allocation error.
  */
 mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( mbedtls_asn1_named_data **list,
                                         const char *oid, size_t oid_len,
diff --git a/include/mbedtls/bignum.h b/include/mbedtls/bignum.h
index 9d15955..877fbc7 100644
--- a/include/mbedtls/bignum.h
+++ b/include/mbedtls/bignum.h
@@ -179,6 +179,20 @@
     #endif /* !MBEDTLS_NO_UDBL_DIVISION */
 #endif /* !MBEDTLS_HAVE_INT64 */
 
+/** \typedef mbedtls_mpi_uint
+ * \brief The type of machine digits in a bignum, called _limbs_.
+ *
+ * This is always an unsigned integer type with no padding bits. The size
+ * is platform-dependent.
+ */
+
+/** \typedef mbedtls_mpi_sint
+ * \brief The signed type corresponding to #mbedtls_mpi_uint.
+ *
+ * This is always an signed integer type with no padding bits. The size
+ * is platform-dependent.
+ */
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -188,9 +202,27 @@
  */
 typedef struct mbedtls_mpi
 {
-    int MBEDTLS_PRIVATE(s);              /*!<  Sign: -1 if the mpi is negative, 1 otherwise */
-    size_t MBEDTLS_PRIVATE(n);           /*!<  total # of limbs  */
-    mbedtls_mpi_uint *MBEDTLS_PRIVATE(p);          /*!<  pointer to limbs  */
+    /** Sign: -1 if the mpi is negative, 1 otherwise.
+     *
+     * The number 0 must be represented with `s = +1`. Although many library
+     * functions treat all-limbs-zero as equivalent to a valid representation
+     * of 0 regardless of the sign bit, there are exceptions, so bignum
+     * functions and external callers must always set \c s to +1 for the
+     * number zero.
+     *
+     * Note that this implies that calloc() or `... = {0}` does not create
+     * a valid MPI representation. You must call mbedtls_mpi_init().
+     */
+    int MBEDTLS_PRIVATE(s);
+
+    /** Total number of limbs in \c p.  */
+    size_t MBEDTLS_PRIVATE(n);
+
+    /** Pointer to limbs.
+     *
+     * This may be \c NULL if \c n is 0.
+     */
+    mbedtls_mpi_uint *MBEDTLS_PRIVATE(p);
 }
 mbedtls_mpi;
 
diff --git a/include/mbedtls/build_info.h b/include/mbedtls/build_info.h
index 170cbeb..049a120 100644
--- a/include/mbedtls/build_info.h
+++ b/include/mbedtls/build_info.h
@@ -37,22 +37,28 @@
  * Major, Minor, Patchlevel
  */
 #define MBEDTLS_VERSION_MAJOR  3
-#define MBEDTLS_VERSION_MINOR  2
-#define MBEDTLS_VERSION_PATCH  1
+#define MBEDTLS_VERSION_MINOR  3
+#define MBEDTLS_VERSION_PATCH  0
 
 /**
  * The single version number has the following structure:
  *    MMNNPP00
  *    Major version | Minor version | Patch version
  */
-#define MBEDTLS_VERSION_NUMBER         0x03020100
-#define MBEDTLS_VERSION_STRING         "3.2.1"
-#define MBEDTLS_VERSION_STRING_FULL    "mbed TLS 3.2.1"
+#define MBEDTLS_VERSION_NUMBER         0x03030000
+#define MBEDTLS_VERSION_STRING         "3.3.0"
+#define MBEDTLS_VERSION_STRING_FULL    "mbed TLS 3.3.0"
 
 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
 #define _CRT_SECURE_NO_DEPRECATE 1
 #endif
 
+/* Define `inline` on some non-C99-compliant compilers. */
+#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
+    !defined(inline) && !defined(__cplusplus)
+#define inline __inline
+#endif
+
 #if !defined(MBEDTLS_CONFIG_FILE)
 #include "mbedtls/mbedtls_config.h"
 #else
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index d36db4a..99584c4 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -23,6 +23,7 @@
 #ifndef MBEDTLS_CHECK_CONFIG_H
 #define MBEDTLS_CHECK_CONFIG_H
 
+/* *INDENT-OFF* */
 /*
  * We assume CHAR_BIT is 8 in many places. In practice, this is true on our
  * target platforms, so not an issue, but let's just be extra sure.
@@ -32,6 +33,8 @@
 #error "mbed TLS requires a platform with 8-bit chars"
 #endif
 
+#include <stdint.h>
+
 #if defined(_WIN32)
 #if !defined(MBEDTLS_PLATFORM_C)
 #error "MBEDTLS_PLATFORM_C is required on Windows"
@@ -114,15 +117,19 @@
 #endif
 
 #if defined(MBEDTLS_ECP_RESTARTABLE)           && \
-    ( defined(MBEDTLS_USE_PSA_CRYPTO)          || \
-      defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT) || \
+    ( defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT) || \
       defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT)     || \
       defined(MBEDTLS_ECDSA_SIGN_ALT)          || \
       defined(MBEDTLS_ECDSA_VERIFY_ALT)        || \
       defined(MBEDTLS_ECDSA_GENKEY_ALT)        || \
       defined(MBEDTLS_ECP_INTERNAL_ALT)        || \
       defined(MBEDTLS_ECP_ALT) )
-#error "MBEDTLS_ECP_RESTARTABLE defined, but it cannot coexist with an alternative or PSA-based ECP implementation"
+#error "MBEDTLS_ECP_RESTARTABLE defined, but it cannot coexist with an alternative ECP implementation"
+#endif
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)           && \
+    !defined(MBEDTLS_ECP_C)
+#error "MBEDTLS_ECP_RESTARTABLE defined, but not all prerequisites"
 #endif
 
 #if defined(MBEDTLS_ECDSA_DETERMINISTIC) && !defined(MBEDTLS_HMAC_DRBG_C)
@@ -327,7 +334,7 @@
 
 /* Use of EC J-PAKE in TLS requires SHA-256.
  * This will be taken from MD if it is present, or from PSA if MD is absent.
- * Note: ECJPAKE_C depends on MD_C || PSA_CRYPTO_C. */
+ * Note: MBEDTLS_ECJPAKE_C depends on MBEDTLS_MD_C || MBEDTLS_PSA_CRYPTO_C. */
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) &&                    \
     !( defined(MBEDTLS_MD_C) && defined(MBEDTLS_SHA256_C) ) &&          \
     !( !defined(MBEDTLS_MD_C) && defined(PSA_WANT_ALG_SHA_256) )
@@ -842,13 +849,20 @@
         "but no key exchange methods defined with MBEDTLS_KEY_EXCHANGE_xxxx"
 #endif
 
-/* Early data requires PSK related mode defined */
 #if defined(MBEDTLS_SSL_EARLY_DATA) && \
-        ( !defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED) && \
-          !defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED))
+    ( !defined(MBEDTLS_SSL_SESSION_TICKETS) || \
+      ( !defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED) && \
+        !defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED) ) )
 #error "MBEDTLS_SSL_EARLY_DATA  defined, but not all prerequisites"
 #endif
 
+#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_SRV_C) && \
+    ( !defined(MBEDTLS_SSL_MAX_EARLY_DATA_SIZE)     || \
+      ( MBEDTLS_SSL_MAX_EARLY_DATA_SIZE < 0 )       || \
+      ( MBEDTLS_SSL_MAX_EARLY_DATA_SIZE > UINT32_MAX ) )
+#error "MBEDTLS_SSL_MAX_EARLY_DATA_SIZE MUST be defined and in range(0..UINT32_MAX)"
+#endif
+
 #if defined(MBEDTLS_SSL_PROTO_DTLS)     && \
     !defined(MBEDTLS_SSL_PROTO_TLS1_2)
 #error "MBEDTLS_SSL_PROTO_DTLS defined, but not all prerequisites"
@@ -903,6 +917,19 @@
 #error "MBEDTLS_SSL_CID_OUT_LEN_MAX too large (max 255)"
 #endif
 
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT)     &&                 \
+    !defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+#error "MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT) && MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT != 0
+#if defined(MBEDTLS_DEPRECATED_REMOVED)
+#error "MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT is deprecated and will be removed in a future version of Mbed TLS"
+#elif defined(MBEDTLS_DEPRECATED_WARNING)
+#warning "MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT is deprecated and will be removed in a future version of Mbed TLS"
+#endif
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT && MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT != 0 */
+
 #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) &&   \
     !defined(MBEDTLS_SSL_PROTO_TLS1_2)
 #error "MBEDTLS_SSL_ENCRYPT_THEN_MAC defined, but not all prerequisites"
@@ -1062,6 +1089,14 @@
 #error "MBEDTLS_SSL_TRUNCATED_HMAC was removed in Mbed TLS 3.0. See https://github.com/Mbed-TLS/mbedtls/issues/4341"
 #endif
 
+#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_MD_C) ) )
+#error  "MBEDTLS_PKCS7_C is defined, but not all prerequisites"
+#endif
+
 /*
  * Avoid warning from -pedantic. This is a convenient place for this
  * workaround since this is included by every single file before the
@@ -1069,4 +1104,5 @@
  */
 typedef int mbedtls_iso_c_forbids_empty_translation_units;
 
+/* *INDENT-ON* */
 #endif /* MBEDTLS_CHECK_CONFIG_H */
diff --git a/include/mbedtls/cipher.h b/include/mbedtls/cipher.h
index a3f52ea..151da1d 100644
--- a/include/mbedtls/cipher.h
+++ b/include/mbedtls/cipher.h
@@ -46,11 +46,6 @@
 #define MBEDTLS_CIPHER_MODE_STREAM
 #endif
 
-#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
-    !defined(inline) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
 /** The selected feature is not available. */
 #define MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE  -0x6080
 /** Bad input parameters. */
diff --git a/include/mbedtls/config_psa.h b/include/mbedtls/config_psa.h
index 5b27dda..5727c5e 100644
--- a/include/mbedtls/config_psa.h
+++ b/include/mbedtls/config_psa.h
@@ -7,7 +7,7 @@
  *  those definitions to define symbols used in the library code.
  *
  *  Users and integrators should not edit this file, please edit
- *  include/mbedtls/mbedtls_config.h for MBETLS_XXX settings or
+ *  include/mbedtls/mbedtls_config.h for MBEDTLS_XXX settings or
  *  include/psa/crypto_config.h for PSA_WANT_XXX settings.
  */
 /*
diff --git a/include/mbedtls/ecjpake.h b/include/mbedtls/ecjpake.h
index e7ca1b2..3dd3361 100644
--- a/include/mbedtls/ecjpake.h
+++ b/include/mbedtls/ecjpake.h
@@ -113,7 +113,7 @@
  * \param curve     The identifier of the elliptic curve to use,
  *                  for example #MBEDTLS_ECP_DP_SECP256R1.
  * \param secret    The pre-shared secret (passphrase). This must be
- *                  a readable buffer of length \p len Bytes. It need
+ *                  a readable not empty buffer of length \p len Bytes. It need
  *                  only be valid for the duration of this call.
  * \param len       The length of the pre-shared secret \p secret.
  *
diff --git a/include/mbedtls/error.h b/include/mbedtls/error.h
index eb83913..4a97d65 100644
--- a/include/mbedtls/error.h
+++ b/include/mbedtls/error.h
@@ -26,11 +26,6 @@
 
 #include <stddef.h>
 
-#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
-    !defined(inline) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
 /**
  * Error code layout.
  *
@@ -96,6 +91,7 @@
  * ECP       4   10 (Started from top)
  * MD        5   5
  * HKDF      5   1 (Started from top)
+ * PKCS7     5   12 (Started from 0x5300)
  * SSL       5   2 (Started from 0x5F00)
  * CIPHER    6   8 (Started from 0x6080)
  * SSL       6   22 (Started from top, plus 0x6000)
diff --git a/include/mbedtls/legacy_or_psa.h b/include/mbedtls/legacy_or_psa.h
index f872dda..35798a5 100644
--- a/include/mbedtls/legacy_or_psa.h
+++ b/include/mbedtls/legacy_or_psa.h
@@ -64,7 +64,7 @@
  * The naming scheme for these macros is:
  *      MBEDTLS_HAS_feature_VIA_legacy_OR_PSA(_condition)
  * where:
- * - feature is expressed the same way as in PSA_WANT macros, for example:
+ * - feature is expressed the same way as in PSA_WANT_xxx macros, for example:
  *   KEY_TYPE_AES, ALG_SHA_256, ECC_SECP_R1_256;
  * - legacy is either LOWLEVEL or the name of the layer: MD, CIPHER;
  * - condition is omitted if it's based on availability, else it's
diff --git a/include/mbedtls/lms.h b/include/mbedtls/lms.h
index fe87d40..1179cd1 100644
--- a/include/mbedtls/lms.h
+++ b/include/mbedtls/lms.h
@@ -58,7 +58,7 @@
 #define MBEDTLS_LMS_TYPE_LEN            (4)
 #define MBEDTLS_LMS_H_TREE_HEIGHT(type) ((type) == MBEDTLS_LMS_SHA256_M32_H10 ? 10u : 0)
 
-/* The length of a hash output, Currently only imlemented for SHA256.
+/* The length of a hash output, Currently only implemented for SHA256.
  * Max is 32 bytes.
  */
 #define MBEDTLS_LMS_M_NODE_BYTES(type) ((type) == MBEDTLS_LMS_SHA256_M32_H10 ? 32 : 0)
@@ -82,7 +82,7 @@
 
 /** The Identifier of the LMS parameter set, as per
  * https://www.iana.org/assignments/leighton-micali-signatures/leighton-micali-signatures.xhtml
- * We are only implementing a subset of the types, particularly H10, for the sake of simplicty.
+ * We are only implementing a subset of the types, particularly H10, for the sake of simplicity.
  */
 typedef enum {
     MBEDTLS_LMS_SHA256_M32_H10 = 0x6,
@@ -90,7 +90,7 @@
 
 /** The Identifier of the LMOTS parameter set, as per
  *  https://www.iana.org/assignments/leighton-micali-signatures/leighton-micali-signatures.xhtml.
- *  We are only implementing a subset of the types, particularly N32_W8, for the sake of simplicty.
+ *  We are only implementing a subset of the types, particularly N32_W8, for the sake of simplicity.
  */
 typedef enum {
     MBEDTLS_LMOTS_SHA256_N32_W8 = 4
diff --git a/include/mbedtls/mbedtls_config.h b/include/mbedtls/mbedtls_config.h
index b4c8635..b9c896f 100644
--- a/include/mbedtls/mbedtls_config.h
+++ b/include/mbedtls/mbedtls_config.h
@@ -690,11 +690,42 @@
  * This is useful in non-threaded environments if you want to avoid blocking
  * for too long on ECC (and, hence, X.509 or SSL/TLS) operations.
  *
- * Uncomment this macro to enable restartable ECC computations.
+ * This option:
+ * - Adds xxx_restartable() variants of existing operations in the
+ *   following modules, with corresponding restart context types:
+ *   - ECP (for Short Weierstrass curves only): scalar multiplication (mul),
+ *     linear combination (muladd);
+ *   - ECDSA: signature generation & verification;
+ *   - PK: signature generation & verification;
+ *   - X509: certificate chain verification.
+ * - Adds mbedtls_ecdh_enable_restart() in the ECDH module.
+ * - Changes the behaviour of TLS 1.2 clients (not servers) when using the
+ *   ECDHE-ECDSA key exchange (not other key exchanges) to make all ECC
+ *   computations restartable:
+ *   - ECDH operations from the key exchange, only for Short Weierstass
+ *     curves, only when MBEDTLS_USE_PSA_CRYPTO is not enabled.
+ *   - verification of the server's key exchange signature;
+ *   - verification of the server's certificate chain;
+ *   - generation of the client's signature if client authentication is used,
+ *     with an ECC key/certificate.
+ *
+ * \note  In the cases above, the usual SSL/TLS functions, such as
+ *        mbedtls_ssl_handshake(), can now return
+ *        MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS.
+ *
+ * \note  When this option and MBEDTLS_USE_PSA_CRYPTO are both enabled,
+ *        restartable operations in PK, X.509 and TLS (see above) are not
+ *        using PSA. On the other hand, ECDH computations in TLS are using
+ *        PSA, and are not restartable. These are temporary limitations that
+ *        should be lifted in the future.
  *
  * \note  This option only works with the default software implementation of
  *        elliptic curve functionality. It is incompatible with
  *        MBEDTLS_ECP_ALT, MBEDTLS_ECDH_XXX_ALT, MBEDTLS_ECDSA_XXX_ALT.
+ *
+ * Requires: MBEDTLS_ECP_C
+ *
+ * Uncomment this macro to enable restartable ECC computations.
  */
 //#define MBEDTLS_ECP_RESTARTABLE
 
@@ -1146,6 +1177,11 @@
  * \warning If building without MBEDTLS_MD_C, you must call psa_crypto_init()
  * before doing any PKCS#1 v2.1 operation.
  *
+ * \warning When building with MBEDTLS_MD_C, all hashes used with this
+ * need to be available as built-ins (that is, for SHA-256, MBEDTLS_SHA256_C,
+ * etc.) as opposed to just PSA drivers. So far, PSA drivers are only used by
+ * this module in builds where MBEDTLS_MD_C is disabled.
+ *
  * This enables support for RSAES-OAEP and RSASSA-PSS operations.
  */
 #define MBEDTLS_PKCS1_V21
@@ -1320,21 +1356,16 @@
 /**
  * \def MBEDTLS_SSL_DTLS_CONNECTION_ID
  *
- * Enable support for the DTLS Connection ID extension
- * (version draft-ietf-tls-dtls-connection-id-05,
- * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05)
+ * Enable support for the DTLS Connection ID (CID) extension,
  * which allows to identify DTLS connections across changes
- * in the underlying transport.
+ * in the underlying transport. The CID functionality is described
+ * in RFC 9146.
  *
  * Setting this option enables the SSL APIs `mbedtls_ssl_set_cid()`,
  * mbedtls_ssl_get_own_cid()`, `mbedtls_ssl_get_peer_cid()` and
  * `mbedtls_ssl_conf_cid()`. See the corresponding documentation for
  * more information.
  *
- * \warning The Connection ID extension is still in draft state.
- *          We make no stability promises for the availability
- *          or the shape of the API controlled by this option.
- *
  * The maximum lengths of outgoing and incoming CIDs can be configured
  * through the options
  * - MBEDTLS_SSL_CID_OUT_LEN_MAX
@@ -1344,7 +1375,30 @@
  *
  * Uncomment to enable the Connection ID extension.
  */
-//#define MBEDTLS_SSL_DTLS_CONNECTION_ID
+#define MBEDTLS_SSL_DTLS_CONNECTION_ID
+
+
+/**
+ * \def MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT
+ *
+ * Defines whether RFC 9146 (default) or the legacy version
+ * (version draft-ietf-tls-dtls-connection-id-05,
+ * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05)
+ * is used.
+ *
+ * Set the value to 0 for the standard version, and
+ * 1 for the legacy draft version.
+ *
+ * \deprecated Support for the legacy version of the DTLS
+ *             Connection ID feature is deprecated. Please
+ *             switch to the standardized version defined
+ *             in RFC 9146 enabled by utilizing
+ *             MBEDTLS_SSL_DTLS_CONNECTION_ID without use
+ *             of MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT.
+ *
+ * Requires: MBEDTLS_SSL_DTLS_CONNECTION_ID
+ */
+#define MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT 0
 
 /**
  * \def MBEDTLS_SSL_ASYNC_PRIVATE
@@ -1520,7 +1574,7 @@
  * Requires: MBEDTLS_SSL_KEEP_PEER_CERTIFICATE
  * Requires: MBEDTLS_PSA_CRYPTO_C
  *
- * Note: even though TLS 1.3 depends on PSA Crypto, and uses it unconditonally
+ * Note: even though TLS 1.3 depends on PSA Crypto, and uses it unconditionally
  * for most operations, if you want it to only use PSA for all crypto
  * operations, you need to also enable MBEDTLS_USE_PSA_CRYPTO; otherwise X.509
  * operations, and functions that are common with TLS 1.2 (record protection,
@@ -1637,7 +1691,8 @@
 *
 * Enable support for RFC 8446 TLS 1.3 early data.
 *
-* Requires: MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED or
+* Requires: MBEDTLS_SSL_SESSION_TICKETS and either
+*           MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED or
 *           MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
 *
 * Comment this to disable support for early data. If MBEDTLS_SSL_PROTO_TLS1_3
@@ -1650,6 +1705,23 @@
 //#define MBEDTLS_SSL_EARLY_DATA
 
 /**
+ * \def MBEDTLS_SSL_MAX_EARLY_DATA_SIZE
+ *
+ * The default maximum amount of 0-RTT data. See the documentation of
+ * \c mbedtls_ssl_tls13_conf_max_early_data_size() for more information.
+ *
+ * It must be positive and smaller than UINT32_MAX.
+ *
+ * If MBEDTLS_SSL_EARLY_DATA is not defined, this default value does not
+ * have any impact on the build.
+ *
+ * This feature is experimental, not completed and thus not ready for
+ * production.
+ *
+ */
+#define MBEDTLS_SSL_MAX_EARLY_DATA_SIZE        1024
+
+/**
  * \def MBEDTLS_SSL_PROTO_DTLS
  *
  * Enable support for DTLS (all available versions).
@@ -1882,7 +1954,6 @@
  * before calling any function from the SSL/TLS, X.509 or PK modules.
  *
  * Requires: MBEDTLS_PSA_CRYPTO_C.
- * Conflicts with: MBEDTLS_ECP_RESTARTABLE
  *
  * Uncomment this to enable internal use of PSA Crypto and new associated APIs.
  */
@@ -2432,6 +2503,11 @@
  *
  * \warning If building without MBEDTLS_MD_C, you must call psa_crypto_init()
  * before doing any EC J-PAKE operations.
+ *
+ * \warning When building with MBEDTLS_MD_C, all hashes used with this
+ * need to be available as built-ins (that is, for SHA-256, MBEDTLS_SHA256_C,
+ * etc.) as opposed to just PSA drivers. So far, PSA drivers are only used by
+ * this module in builds where MBEDTLS_MD_C is disabled.
  */
 #define MBEDTLS_ECJPAKE_C
 
@@ -2776,11 +2852,36 @@
  * \warning If building without MBEDTLS_MD_C, you must call psa_crypto_init()
  * before doing any PKCS5 operation.
  *
+ * \warning When building with MBEDTLS_MD_C, all hashes used with this
+ * need to be available as built-ins (that is, for SHA-256, MBEDTLS_SHA256_C,
+ * etc.) as opposed to just PSA drivers. So far, PSA drivers are only used by
+ * this module in builds where MBEDTLS_MD_C is disabled.
+ *
  * This module adds support for the PKCS#5 functions.
  */
 #define MBEDTLS_PKCS5_C
 
 /**
+ * \def MBEDTLS_PKCS7_C
+ *
+ * This feature is a work in progress and not ready for production. Testing and
+ * validation is incomplete, and handling of malformed inputs may not be robust.
+ * The API may change.
+ *
+ * Enable PKCS7 core for using PKCS7 formatted signatures.
+ * RFC Link - https://tools.ietf.org/html/rfc2315
+ *
+ * Module:  library/pkcs7.c
+ *
+ * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_OID_C, MBEDTLS_PK_PARSE_C,
+ *           MBEDTLS_X509_CRT_PARSE_C MBEDTLS_X509_CRL_PARSE_C,
+ *           MBEDTLS_BIGNUM_C, MBEDTLS_MD_C
+ *
+ * This module is required for the PKCS7 parsing modules.
+ */
+//#define MBEDTLS_PKCS7_C
+
+/**
  * \def MBEDTLS_PKCS12_C
  *
  * Enable PKCS#12 PBE functions.
@@ -2795,6 +2896,11 @@
  * \warning If building without MBEDTLS_MD_C, you must call psa_crypto_init()
  * before doing any PKCS12 operation.
  *
+ * \warning When building with MBEDTLS_MD_C, all hashes used with this
+ * need to be available as built-ins (that is, for SHA-256, MBEDTLS_SHA256_C,
+ * etc.) as opposed to just PSA drivers. So far, PSA drivers are only used by
+ * this module in builds where MBEDTLS_MD_C is disabled.
+ *
  * This module enables PKCS#12 functions.
  */
 #define MBEDTLS_PKCS12_C
@@ -3660,17 +3766,6 @@
 //#define MBEDTLS_PSK_MAX_LEN               32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */
 //#define MBEDTLS_SSL_COOKIE_TIMEOUT        60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */
 
-/** \def MBEDTLS_TLS_EXT_CID
- *
- * At the time of writing, the CID extension has not been assigned its
- * final value. Set this configuration option to make Mbed TLS use a
- * different value.
- *
- * A future minor revision of Mbed TLS may change the default value of
- * this option to match evolving standards and usage.
- */
-//#define MBEDTLS_TLS_EXT_CID                        254
-
 /**
  * Complete list of ciphersuites to use, in order of preference.
  *
diff --git a/include/mbedtls/oid.h b/include/mbedtls/oid.h
index 4ee3f93..e5c4b92 100644
--- a/include/mbedtls/oid.h
+++ b/include/mbedtls/oid.h
@@ -220,6 +220,7 @@
 #define MBEDTLS_OID_PKCS                MBEDTLS_OID_RSA_COMPANY "\x01" /**< pkcs OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) 1 } */
 #define MBEDTLS_OID_PKCS1               MBEDTLS_OID_PKCS "\x01" /**< pkcs-1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } */
 #define MBEDTLS_OID_PKCS5               MBEDTLS_OID_PKCS "\x05" /**< pkcs-5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 } */
+#define MBEDTLS_OID_PKCS7               MBEDTLS_OID_PKCS "\x07" /**< pkcs-7 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 7 } */
 #define MBEDTLS_OID_PKCS9               MBEDTLS_OID_PKCS "\x09" /**< pkcs-9 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 } */
 #define MBEDTLS_OID_PKCS12              MBEDTLS_OID_PKCS "\x0c" /**< pkcs-12 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 } */
 
@@ -301,6 +302,16 @@
 #define MBEDTLS_OID_PKCS5_PBE_SHA1_RC2_CBC      MBEDTLS_OID_PKCS5 "\x0b" /**< pbeWithSHA1AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 11} */
 
 /*
+ * PKCS#7 OIDs
+ */
+#define MBEDTLS_OID_PKCS7_DATA                        MBEDTLS_OID_PKCS7 "\x01" /**< Content type is Data OBJECT IDENTIFIER ::= {pkcs-7 1} */
+#define MBEDTLS_OID_PKCS7_SIGNED_DATA                 MBEDTLS_OID_PKCS7 "\x02" /**< Content type is Signed Data OBJECT IDENTIFIER ::= {pkcs-7 2} */
+#define MBEDTLS_OID_PKCS7_ENVELOPED_DATA              MBEDTLS_OID_PKCS7 "\x03" /**< Content type is Enveloped Data OBJECT IDENTIFIER ::= {pkcs-7 3} */
+#define MBEDTLS_OID_PKCS7_SIGNED_AND_ENVELOPED_DATA   MBEDTLS_OID_PKCS7 "\x04" /**< Content type is Signed and Enveloped Data OBJECT IDENTIFIER ::= {pkcs-7 4} */
+#define MBEDTLS_OID_PKCS7_DIGESTED_DATA               MBEDTLS_OID_PKCS7 "\x05" /**< Content type is Digested Data OBJECT IDENTIFIER ::= {pkcs-7 5} */
+#define MBEDTLS_OID_PKCS7_ENCRYPTED_DATA              MBEDTLS_OID_PKCS7 "\x06" /**< Content type is Encrypted Data OBJECT IDENTIFIER ::= {pkcs-7 6} */
+
+/*
  * PKCS#8 OIDs
  */
 #define MBEDTLS_OID_PKCS9_CSR_EXT_REQ           MBEDTLS_OID_PKCS9 "\x0e" /**< extensionRequest OBJECT IDENTIFIER ::= {pkcs-9 14} */
diff --git a/include/mbedtls/pem.h b/include/mbedtls/pem.h
index c75a124..a4c6fb8 100644
--- a/include/mbedtls/pem.h
+++ b/include/mbedtls/pem.h
@@ -27,11 +27,6 @@
 
 #include <stddef.h>
 
-#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
-    !defined(inline) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
 /**
  * \name PEM Error codes
  * These error codes are returned in case of errors reading the
diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h
index 867961d..db0bfac 100644
--- a/include/mbedtls/pk.h
+++ b/include/mbedtls/pk.h
@@ -44,11 +44,6 @@
 #include "psa/crypto.h"
 #endif
 
-#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
-    !defined(inline) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
 /** Memory allocation failed. */
 #define MBEDTLS_ERR_PK_ALLOC_FAILED        -0x3F80
 /** Type mismatch, eg attempt to encrypt with an ECDSA key */
diff --git a/include/mbedtls/pkcs12.h b/include/mbedtls/pkcs12.h
index 1b87aea..327996a 100644
--- a/include/mbedtls/pkcs12.h
+++ b/include/mbedtls/pkcs12.h
@@ -94,7 +94,7 @@
  *                   no byte order mark and with a null terminator (i.e. the
  *                   last two bytes should be 0x00 0x00).
  * \param pwdlen     length of the password (may be 0).
- * \param salt       Salt buffer to use This may only be \c NULL when
+ * \param salt       Salt buffer to use. This may only be \c NULL when
  *                   \p saltlen is 0.
  * \param saltlen    length of the salt (may be zero)
  * \param mbedtls_md mbedtls_md type to use during the derivation
diff --git a/include/mbedtls/pkcs7.h b/include/mbedtls/pkcs7.h
new file mode 100644
index 0000000..bf61a63
--- /dev/null
+++ b/include/mbedtls/pkcs7.h
@@ -0,0 +1,268 @@
+/**
+ * \file pkcs7.h
+ *
+ * \brief PKCS7 generic defines and structures
+ *  https://tools.ietf.org/html/rfc2315
+ */
+/*
+ *  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.
+ */
+
+/**
+ * This feature is a work in progress and not ready for production. The API may
+ * change. Furthermore, please note that the implementation has only been
+ * validated with well-formed inputs, not yet with untrusted inputs (which is
+ * almost always the case in practice).
+ *
+ * Note: For the time being, this implementation of the PKCS7 cryptographic
+ * message syntax is a partial implementation of RFC 2315.
+ * Differences include:
+ *  - The RFC specifies 6 different content types. The only type currently
+ *    supported in Mbed TLS is the signed data content type.
+ *  - The only supported PKCS7 Signed Data syntax version is version 1
+ *  - The RFC specifies support for BER. This implementation is limited to
+ *    DER only.
+ *  - The RFC specifies that multiple digest algorithms can be specified
+ *    in the Signed Data type. Only one digest algorithm is supported in Mbed TLS.
+ *  - The RFC specifies the Signed Data type can contain multiple X509 or PKCS6
+ *    certificates. In Mbed TLS, this list can only contain 0 or 1 certificates
+ *    and they must be in X509 format.
+ *  - The RFC specifies the Signed Data type can contain
+ *    certificate-revocation lists (crls). This implementation has no support
+ *    for crls so it is assumed to be an empty list.
+ *  - The RFC allows for SignerInfo structure to optionally contain
+ *    unauthenticatedAttributes and authenticatedAttributes. In Mbed TLS it is
+ *    assumed these fields are empty.
+ */
+
+#ifndef MBEDTLS_PKCS7_H
+#define MBEDTLS_PKCS7_H
+
+#include "mbedtls/private_access.h"
+
+#include "mbedtls/build_info.h"
+
+#include "mbedtls/asn1.h"
+#include "mbedtls/x509.h"
+#include "mbedtls/x509_crt.h"
+
+/**
+ * \name PKCS7 Module Error codes
+ * \{
+ */
+#define MBEDTLS_ERR_PKCS7_INVALID_FORMAT                   -0x5300  /**< The format is invalid, e.g. different type expected. */
+#define MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE              -0x5380  /**< Unavailable feature, e.g. anything other than signed data. */
+#define MBEDTLS_ERR_PKCS7_INVALID_VERSION                  -0x5400  /**< The PKCS7 version element is invalid or cannot be parsed. */
+#define MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO             -0x5480  /**< The PKCS7 content info invalid or cannot be parsed. */
+#define MBEDTLS_ERR_PKCS7_INVALID_ALG                      -0x5500  /**< The algorithm tag or value is invalid or cannot be parsed. */
+#define MBEDTLS_ERR_PKCS7_INVALID_CERT                     -0x5580  /**< The certificate tag or value is invalid or cannot be parsed. */
+#define MBEDTLS_ERR_PKCS7_INVALID_SIGNATURE                -0x5600  /**< Error parsing the signature */
+#define MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO              -0x5680  /**< Error parsing the signer's info */
+#define MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA                   -0x5700  /**< Input invalid. */
+#define MBEDTLS_ERR_PKCS7_ALLOC_FAILED                     -0x5780  /**< Allocation of memory failed. */
+#define MBEDTLS_ERR_PKCS7_VERIFY_FAIL                      -0x5800  /**< Verification Failed */
+#define MBEDTLS_ERR_PKCS7_CERT_DATE_INVALID                -0x5880  /**< The PKCS7 date issued/expired dates are invalid */
+/* \} name */
+
+/**
+ * \name PKCS7 Supported Version
+ * \{
+ */
+#define MBEDTLS_PKCS7_SUPPORTED_VERSION                           0x01
+/* \} name */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Type-length-value structure that allows for ASN1 using DER.
+ */
+typedef mbedtls_asn1_buf mbedtls_pkcs7_buf;
+
+/**
+ * Container for ASN1 named information objects.
+ * It allows for Relative Distinguished Names (e.g. cn=localhost,ou=code,etc.).
+ */
+typedef mbedtls_asn1_named_data mbedtls_pkcs7_name;
+
+/**
+ * Container for a sequence of ASN.1 items
+ */
+typedef mbedtls_asn1_sequence mbedtls_pkcs7_sequence;
+
+/**
+ * PKCS7 types
+ */
+typedef enum {
+    MBEDTLS_PKCS7_NONE=0,
+    MBEDTLS_PKCS7_DATA,
+    MBEDTLS_PKCS7_SIGNED_DATA,
+    MBEDTLS_PKCS7_ENVELOPED_DATA,
+    MBEDTLS_PKCS7_SIGNED_AND_ENVELOPED_DATA,
+    MBEDTLS_PKCS7_DIGESTED_DATA,
+    MBEDTLS_PKCS7_ENCRYPTED_DATA,
+}
+mbedtls_pkcs7_type;
+
+/**
+ * Structure holding PKCS7 signer info
+ */
+typedef struct mbedtls_pkcs7_signer_info
+{
+    int MBEDTLS_PRIVATE(version);
+    mbedtls_x509_buf MBEDTLS_PRIVATE(serial);
+    mbedtls_x509_name MBEDTLS_PRIVATE(issuer);
+    mbedtls_x509_buf MBEDTLS_PRIVATE(issuer_raw);
+    mbedtls_x509_buf MBEDTLS_PRIVATE(alg_identifier);
+    mbedtls_x509_buf MBEDTLS_PRIVATE(sig_alg_identifier);
+    mbedtls_x509_buf MBEDTLS_PRIVATE(sig);
+    struct mbedtls_pkcs7_signer_info *MBEDTLS_PRIVATE(next);
+}
+mbedtls_pkcs7_signer_info;
+
+/**
+ * Structure holding attached data as part of PKCS7 signed data format
+ */
+typedef struct mbedtls_pkcs7_data
+{
+    mbedtls_pkcs7_buf MBEDTLS_PRIVATE(oid);
+    mbedtls_pkcs7_buf MBEDTLS_PRIVATE(data);
+}
+mbedtls_pkcs7_data;
+
+/**
+ * Structure holding the signed data section
+ */
+typedef struct mbedtls_pkcs7_signed_data
+{
+    int MBEDTLS_PRIVATE(version);
+    mbedtls_pkcs7_buf MBEDTLS_PRIVATE(digest_alg_identifiers);
+    struct mbedtls_pkcs7_data MBEDTLS_PRIVATE(content);
+    int MBEDTLS_PRIVATE(no_of_certs);
+    mbedtls_x509_crt MBEDTLS_PRIVATE(certs);
+    int MBEDTLS_PRIVATE(no_of_crls);
+    mbedtls_x509_crl MBEDTLS_PRIVATE(crl);
+    int MBEDTLS_PRIVATE(no_of_signers);
+    mbedtls_pkcs7_signer_info MBEDTLS_PRIVATE(signers);
+}
+mbedtls_pkcs7_signed_data;
+
+/**
+ * Structure holding PKCS7 structure, only signed data for now
+ */
+typedef struct mbedtls_pkcs7
+{
+    mbedtls_pkcs7_buf MBEDTLS_PRIVATE(raw);
+    mbedtls_pkcs7_buf MBEDTLS_PRIVATE(content_type_oid);
+    mbedtls_pkcs7_signed_data MBEDTLS_PRIVATE(signed_data);
+}
+mbedtls_pkcs7;
+
+/**
+ * \brief          Initialize pkcs7 structure.
+ *
+ * \param pkcs7    pkcs7 structure.
+ */
+void mbedtls_pkcs7_init( mbedtls_pkcs7 *pkcs7 );
+
+/**
+ * \brief          Parse a single DER formatted pkcs7 content.
+ *
+ * \param pkcs7    The pkcs7 structure to be filled by parser for the output.
+ * \param buf      The buffer holding the DER encoded pkcs7.
+ * \param buflen   The size in bytes of \p buf.
+ *
+ * \note           This function makes an internal copy of the PKCS7 buffer
+ *                 \p buf. In particular, \p buf may be destroyed or reused
+ *                 after this call returns.
+ *
+ * \return         The \c mbedtls_pkcs7_type of \p buf, if successful.
+ * \return         A negative error code on failure.
+ */
+int mbedtls_pkcs7_parse_der( mbedtls_pkcs7 *pkcs7, const unsigned char *buf,
+                             const size_t buflen );
+
+/**
+ * \brief          Verification of PKCS7 signature against a caller-supplied
+ *                 certificate.
+ *
+ *                 For each signer in the PKCS structure, this function computes
+ *                 a signature over the supplied data, using the supplied
+ *                 certificate and the same digest algorithm as specified by the
+ *                 signer. It then compares this signature against the
+ *                 signer's signature; verification succeeds if any comparison
+ *                 matches.
+ *
+ *                 This function does not use the certificates held within the
+ *                 PKCS7 structure itself.
+ *
+ * \param pkcs7    PKCS7 structure containing signature.
+ * \param cert     Certificate containing key to verify signature.
+ * \param data     Plain data on which signature has to be verified.
+ * \param datalen  Length of the data.
+ *
+ * \note           This function internally calculates the hash on the supplied
+ *                 plain data for signature verification.
+ *
+ * \return         0 if the signature verifies, or a negative error code on failure.
+ */
+int mbedtls_pkcs7_signed_data_verify( mbedtls_pkcs7 *pkcs7,
+                                      const mbedtls_x509_crt *cert,
+                                      const unsigned char *data,
+                                      size_t datalen );
+
+/**
+ * \brief          Verification of PKCS7 signature against a caller-supplied
+ *                 certificate.
+ *
+ *                 For each signer in the PKCS structure, this function computes
+ *                 a signature over the supplied hash, using the supplied
+ *                 certificate and the same digest algorithm as specified by the
+ *                 signer. It then compares this signature against the
+ *                 signer's signature; verification succeeds if any comparison
+ *                 matches.
+ *
+ *                 This function does not use the certificates held within the
+ *                 PKCS7 structure itself.
+ *
+ * \param pkcs7    PKCS7 structure containing signature.
+ * \param cert     Certificate containing key to verify signature.
+ * \param hash     Hash of the plain data on which signature has to be verified.
+ * \param hashlen  Length of the hash.
+ *
+ * \note           This function is different from mbedtls_pkcs7_signed_data_verify()
+ *                 in a way that it directly receives the hash of the data.
+ *
+ * \return         0 if the signature verifies, or a negative error code on failure.
+ */
+int mbedtls_pkcs7_signed_hash_verify( mbedtls_pkcs7 *pkcs7,
+                                      const mbedtls_x509_crt *cert,
+                                      const unsigned char *hash, size_t hashlen);
+
+/**
+ * \brief          Unallocate all PKCS7 data and zeroize the memory.
+ *                 It doesn't free pkcs7 itself. It should be done by the caller.
+ *
+ * \param pkcs7    PKCS7 structure to free.
+ */
+void mbedtls_pkcs7_free( mbedtls_pkcs7 *pkcs7 );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* pkcs7.h */
diff --git a/include/mbedtls/rsa.h b/include/mbedtls/rsa.h
index 002551f..2bfaf8f 100644
--- a/include/mbedtls/rsa.h
+++ b/include/mbedtls/rsa.h
@@ -239,7 +239,7 @@
  * \param N        The RSA modulus. This may be \c NULL.
  * \param N_len    The Byte length of \p N; it is ignored if \p N == NULL.
  * \param P        The first prime factor of \p N. This may be \c NULL.
- * \param P_len    The Byte length of \p P; it ns ignored if \p P == NULL.
+ * \param P_len    The Byte length of \p P; it is ignored if \p P == NULL.
  * \param Q        The second prime factor of \p N. This may be \c NULL.
  * \param Q_len    The Byte length of \p Q; it is ignored if \p Q == NULL.
  * \param D        The private exponent. This may be \c NULL.
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 01ede40..7751560 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -96,12 +96,16 @@
 /* Error space gap */
 /** Processing of the Certificate handshake message failed. */
 #define MBEDTLS_ERR_SSL_BAD_CERTIFICATE                   -0x7A00
-/** Received NewSessionTicket Post Handshake Message */
+/* Error space gap */
+/**
+ * Received NewSessionTicket Post Handshake Message.
+ * This error code is experimental and may be changed or removed without notice.
+ */
 #define MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET       -0x7B00
-/* Error space gap */
-/* Error space gap */
-/* Error space gap */
-/* Error space gap */
+/** Not possible to read early data */
+#define MBEDTLS_ERR_SSL_CANNOT_READ_EARLY_DATA            -0x7B80
+/** Not possible to write early data */
+#define MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA           -0x7C00
 /* Error space gap */
 /* Error space gap */
 /* Error space gap */
@@ -405,6 +409,14 @@
 /** \} name SECTION: Module settings */
 
 /*
+ * Default to standard CID mode
+ */
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) && \
+    !defined(MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT)
+#define MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT 0
+#endif
+
+/*
  * Length of the verify data for secure renegotiation
  */
 #define MBEDTLS_SSL_VERIFY_DATA_MAX_LEN 12
@@ -572,15 +584,10 @@
 #define MBEDTLS_TLS_EXT_SIG_ALG_CERT                50 /* RFC 8446 TLS 1.3 */
 #define MBEDTLS_TLS_EXT_KEY_SHARE                   51 /* RFC 8446 TLS 1.3 */
 
-/* The value of the CID extension is still TBD as of
- * draft-ietf-tls-dtls-connection-id-05
- * (https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05).
- *
- * A future minor revision of Mbed TLS may change the default value of
- * this option to match evolving standards and usage.
- */
-#if !defined(MBEDTLS_TLS_EXT_CID)
-#define MBEDTLS_TLS_EXT_CID                        254 /* TBD */
+#if MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT == 0
+#define MBEDTLS_TLS_EXT_CID                         54 /* RFC 9146 DTLS 1.2 CID */
+#else
+#define MBEDTLS_TLS_EXT_CID                        254 /* Pre-RFC 9146 DTLS 1.2 CID */
 #endif
 
 #define MBEDTLS_TLS_EXT_ECJPAKE_KKPP               256 /* experimental */
@@ -661,7 +668,7 @@
     MBEDTLS_SSL_SERVER_FINISHED,
     MBEDTLS_SSL_FLUSH_BUFFERS,
     MBEDTLS_SSL_HANDSHAKE_WRAPUP,
-    MBEDTLS_SSL_HANDSHAKE_OVER,
+
     MBEDTLS_SSL_NEW_SESSION_TICKET,
     MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT,
     MBEDTLS_SSL_HELLO_RETRY_REQUEST,
@@ -671,7 +678,9 @@
     MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO,
     MBEDTLS_SSL_SERVER_CCS_AFTER_SERVER_HELLO,
     MBEDTLS_SSL_SERVER_CCS_AFTER_HELLO_RETRY_REQUEST,
-    MBEDTLS_SSL_NEW_SESSION_TICKET_FLUSH,
+    MBEDTLS_SSL_HANDSHAKE_OVER,
+    MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET,
+    MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET_FLUSH,
 }
 mbedtls_ssl_states;
 
@@ -801,6 +810,21 @@
 typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item;
 #endif
 
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_SESSION_TICKETS)
+typedef uint8_t mbedtls_ssl_tls13_ticket_flags;
+
+#define MBEDTLS_SSL_TLS1_3_TICKET_ALLOW_PSK_RESUMPTION                          \
+            MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK                /* 1U << 0 */
+#define MBEDTLS_SSL_TLS1_3_TICKET_ALLOW_PSK_EPHEMERAL_RESUMPTION                \
+            MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL      /* 1U << 2 */
+#define MBEDTLS_SSL_TLS1_3_TICKET_ALLOW_EARLY_DATA                  ( 1U << 3 )
+
+#define MBEDTLS_SSL_TLS1_3_TICKET_FLAGS_MASK                                    \
+            ( MBEDTLS_SSL_TLS1_3_TICKET_ALLOW_PSK_RESUMPTION             |      \
+              MBEDTLS_SSL_TLS1_3_TICKET_ALLOW_PSK_EPHEMERAL_RESUMPTION   |      \
+              MBEDTLS_SSL_TLS1_3_TICKET_ALLOW_EARLY_DATA )
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 && MBEDTLS_SSL_SESSION_TICKETS */
+
 /**
  * \brief          Callback type: server-side session cache getter
  *
@@ -1503,6 +1527,12 @@
     int MBEDTLS_PRIVATE(early_data_enabled);     /*!< Early data enablement:
                                                   *   - MBEDTLS_SSL_EARLY_DATA_DISABLED,
                                                   *   - MBEDTLS_SSL_EARLY_DATA_ENABLED */
+
+#if defined(MBEDTLS_SSL_SRV_C)
+    /* The maximum amount of 0-RTT data. RFC 8446 section 4.6.1 */
+    uint32_t MBEDTLS_PRIVATE(max_early_data_size);
+#endif /* MBEDTLS_SSL_SRV_C */
+
 #endif /* MBEDTLS_SSL_EARLY_DATA */
 
 #if defined(MBEDTLS_SSL_ALPN)
@@ -1783,6 +1813,10 @@
                             *   and #MBEDTLS_SSL_CID_DISABLED. */
 #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
 
+#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C)
+    int MBEDTLS_PRIVATE(early_data_status);
+#endif /* MBEDTLS_SSL_EARLY_DATA && MBEDTLS_SSL_CLI_C */
+
     /** Callback to export key block and master secret                      */
     mbedtls_ssl_export_keys_t *MBEDTLS_PRIVATE(f_export_keys);
     void *MBEDTLS_PRIVATE(p_export_keys);            /*!< context for key export callback    */
@@ -1936,6 +1970,35 @@
 */
 void mbedtls_ssl_tls13_conf_early_data( mbedtls_ssl_config *conf,
                                         int early_data_enabled );
+
+#if defined(MBEDTLS_SSL_SRV_C)
+/**
+ * \brief Set the maximum amount of 0-RTT data in bytes
+ *        Default:  #MBEDTLS_SSL_MAX_EARLY_DATA_SIZE
+ *
+ *        This function sets the value of the max_early_data_size
+ *        field of the early data indication extension included in
+ *        the NewSessionTicket messages that the server may send.
+ *
+ *        The value defines the maximum amount of 0-RTT data
+ *        in bytes that a client will be allowed to send when using
+ *        one of the tickets defined by the NewSessionTicket messages.
+ *
+ * \note When resuming a session using a ticket, if the server receives more
+ *       early data than allowed for the ticket, it terminates the connection.
+ *       The maximum amount of 0-RTT data should thus be large enough
+ *       to allow a minimum of early data to be exchanged.
+ *
+ * \param[in] conf                  The SSL configuration to use.
+ * \param[in] max_early_data_size   The maximum amount of 0-RTT data.
+ *
+ * \warning This interface is experimental and may change without notice.
+ *
+ */
+void mbedtls_ssl_tls13_conf_max_early_data_size(
+         mbedtls_ssl_config *conf, uint32_t max_early_data_size );
+#endif /* MBEDTLS_SSL_SRV_C */
+
 #endif /* MBEDTLS_SSL_PROTO_TLS1_3 && MBEDTLS_SSL_EARLY_DATA */
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
@@ -2049,8 +2112,9 @@
  * \brief             Configure the use of the Connection ID (CID)
  *                    extension in the next handshake.
  *
- *                    Reference: draft-ietf-tls-dtls-connection-id-05
+ *                    Reference: RFC 9146 (or draft-ietf-tls-dtls-connection-id-05
  *                    https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05
+ *                    for legacy version)
  *
  *                    The DTLS CID extension allows the reliable association of
  *                    DTLS records to DTLS connections across changes in the
@@ -2107,7 +2171,7 @@
  *                      the `ServerHello` contains the CID extension, too,
  *                      the CID extension will actually be put to use.
  *                    - On the Server, enabling the use of the CID through
- *                      this call implies that that the server will look for
+ *                      this call implies that the server will look for
  *                      the CID extension in a `ClientHello` from the client,
  *                      and, if present, reply with a CID extension in its
  *                      `ServerHello`.
@@ -2553,7 +2617,7 @@
  * \note The library stores \c p without accessing it. It is the responsibility
  *       of the caller to ensure that the pointer remains valid.
  *
- * \param ssl            The SSL context context to modify.
+ * \param ssl            The SSL context to modify.
  * \param p              The new value of the user data.
  */
 static inline void mbedtls_ssl_set_user_data_p(
@@ -2567,7 +2631,7 @@
  *
  * You can retrieve this value later with mbedtls_ssl_get_user_data_n().
  *
- * \param ssl            The SSL context context to modify.
+ * \param ssl            The SSL context to modify.
  * \param n              The new value of the user data.
  */
 static inline void mbedtls_ssl_set_user_data_n(
@@ -2584,7 +2648,7 @@
  * called. The value is undefined if mbedtls_ssl_set_user_data_n() has
  * been called without a subsequent call to mbedtls_ssl_set_user_data_p().
  *
- * \param ssl            The SSL context context to modify.
+ * \param ssl            The SSL context to modify.
  * \return               The current value of the user data.
  */
 static inline void *mbedtls_ssl_get_user_data_p(
@@ -2600,7 +2664,7 @@
  * called. The value is undefined if mbedtls_ssl_set_user_data_p() has
  * been called without a subsequent call to mbedtls_ssl_set_user_data_n().
  *
- * \param ssl            The SSL context context to modify.
+ * \param ssl            The SSL context to modify.
  * \return               The current value of the user data.
  */
 static inline uintptr_t mbedtls_ssl_get_user_data_n(
@@ -3824,9 +3888,10 @@
  * \note           The SSL context needs to be already set up. The right place
  *                 to call this function is between \c mbedtls_ssl_setup() or
  *                 \c mbedtls_ssl_reset() and \c mbedtls_ssl_handshake().
+ *                 Password cannot be empty (see RFC 8236).
  *
  * \param ssl      SSL context
- * \param pw       EC J-PAKE password (pre-shared secret)
+ * \param pw       EC J-PAKE password (pre-shared secret). It cannot be empty
  * \param pw_len   length of pw in bytes
  *
  * \return         0 on success, or a negative error code.
@@ -3834,6 +3899,23 @@
 int mbedtls_ssl_set_hs_ecjpake_password( mbedtls_ssl_context *ssl,
                                          const unsigned char *pw,
                                          size_t pw_len );
+
+/**
+ * \brief          Set the EC J-PAKE opaque password for current handshake.
+ *
+ * \note           The key must remain valid until the handshake is over.
+ *
+ * \note           The SSL context needs to be already set up. The right place
+ *                 to call this function is between \c mbedtls_ssl_setup() or
+ *                 \c mbedtls_ssl_reset() and \c mbedtls_ssl_handshake().
+ *
+ * \param ssl      SSL context
+ * \param pwd      EC J-PAKE opaque password
+ *
+ * \return         0 on success, or a negative error code.
+ */
+int mbedtls_ssl_set_hs_ecjpake_password_opaque( mbedtls_ssl_context *ssl,
+                                                mbedtls_svc_key_id_t pwd );
 #endif /*MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
 
 #if defined(MBEDTLS_SSL_ALPN)
@@ -4624,7 +4706,7 @@
  */
 static inline int mbedtls_ssl_is_handshake_over( mbedtls_ssl_context *ssl )
 {
-    return( ssl->MBEDTLS_PRIVATE( state ) == MBEDTLS_SSL_HANDSHAKE_OVER );
+    return( ssl->MBEDTLS_PRIVATE( state ) >= MBEDTLS_SSL_HANDSHAKE_OVER );
 }
 
 /**
@@ -4864,6 +4946,151 @@
  */
 int mbedtls_ssl_close_notify( mbedtls_ssl_context *ssl );
 
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+
+#if defined(MBEDTLS_SSL_SRV_C)
+/**
+ * \brief          Read at most 'len' application data bytes while performing
+ *                 the handshake (early data).
+ *
+ * \note           This function behaves mainly as mbedtls_ssl_read(). The
+ *                 specification of mbedtls_ssl_read() relevant to TLS 1.3
+ *                 (thus not the parts specific to (D)TLS 1.2) applies to this
+ *                 function and the present documentation is restricted to the
+ *                 differences with mbedtls_ssl_read().
+ *
+ * \param ssl      SSL context
+ * \param buf      buffer that will hold the data
+ * \param len      maximum number of bytes to read
+ *
+ * \return         One additional specific return value:
+ *                 #MBEDTLS_ERR_SSL_CANNOT_READ_EARLY_DATA.
+ *
+ *                 #MBEDTLS_ERR_SSL_CANNOT_READ_EARLY_DATA is returned when it
+ *                 is not possible to read early data for the SSL context
+ *                 \p ssl.
+ *
+ *                 It may have been possible and it is not possible
+ *                 anymore because the server received the End of Early Data
+ *                 message or the maximum number of allowed early data for the
+ *                 PSK in use has been reached.
+ *
+ *                 It may never have been possible and will never be possible
+ *                 for the SSL context \p ssl because the use of early data
+ *                 is disabled for that context or more generally the context
+ *                 is not suitably configured to enable early data or the
+ *                 client does not use early data or the first call to the
+ *                 function was done while the handshake was already too
+ *                 advanced to gather and accept early data.
+ *
+ *                 It is not possible to read early data for the SSL context
+ *                 \p ssl but this does not preclude for using it with
+ *                 mbedtls_ssl_write(), mbedtls_ssl_read() or
+ *                 mbedtls_ssl_handshake().
+ *
+ * \note           When a server wants to retrieve early data, it is expected
+ *                 that this function starts the handshake for the SSL context
+ *                 \p ssl. But this is not mandatory.
+ *
+ */
+int mbedtls_ssl_read_early_data( mbedtls_ssl_context *ssl,
+                                 unsigned char *buf, size_t len );
+#endif /* MBEDTLS_SSL_SRV_C */
+
+#if defined(MBEDTLS_SSL_CLI_C)
+/**
+ * \brief          Try to write exactly 'len' application data bytes while
+ *                 performing the handshake (early data).
+ *
+ * \note           This function behaves mainly as mbedtls_ssl_write(). The
+ *                 specification of mbedtls_ssl_write() relevant to TLS 1.3
+ *                 (thus not the parts specific to (D)TLS1.2) applies to this
+ *                 function and the present documentation is restricted to the
+ *                 differences with mbedtls_ssl_write().
+ *
+ * \param ssl      SSL context
+ * \param buf      buffer holding the data
+ * \param len      how many bytes must be written
+ *
+ * \return         One additional specific return value:
+ *                 #MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA.
+ *
+ *                 #MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA is returned when it
+ *                 is not possible to write early data for the SSL context
+ *                 \p ssl.
+ *
+ *                 It may have been possible and it is not possible
+ *                 anymore because the client received the server Finished
+ *                 message, the server rejected early data or the maximum
+ *                 number of allowed early data for the PSK in use has been
+ *                 reached.
+ *
+ *                 It may never have been possible and will never be possible
+ *                 for the SSL context \p ssl because the use of early data
+ *                 is disabled for that context or more generally the context
+ *                 is not suitably configured to enable early data or the first
+ *                 call to the function was done while the handshake was
+ *                 already completed.
+ *
+ *                 It is not possible to write early data for the SSL context
+ *                 \p ssl but this does not preclude for using it with
+ *                 mbedtls_ssl_write(), mbedtls_ssl_read() or
+ *                 mbedtls_ssl_handshake().
+ *
+ * \note           This function may write early data only if the SSL context
+ *                 has been configured for the handshake with a PSK for which
+ *                 early data is allowed.
+ *
+ * \note           To maximize the number of early data that can be written in
+ *                 the course of the handshake, it is expected that this
+ *                 function starts the handshake for the SSL context \p ssl.
+ *                 But this is not mandatory.
+ *
+ * \note           This function does not provide any information on whether
+ *                 the server has accepted or will accept early data or not.
+ *                 When it returns a positive value, it just means that it
+ *                 has written early data to the server. To know whether the
+ *                 server has accepted early data or not, you should call
+ *                 mbedtls_ssl_get_early_data_status() with the handshake
+ *                 completed.
+ */
+int mbedtls_ssl_write_early_data( mbedtls_ssl_context *ssl,
+                                  const unsigned char *buf, size_t len );
+
+#define MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT  0
+#define MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED  1
+#define MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED  2
+/**
+ * \brief Get the status of the negotiation of the use of early data.
+ *
+ * \param ssl      The SSL context to query
+ *
+ * \return         #MBEDTLS_ERR_SSL_BAD_INPUT_DATA if this function is called
+ *                 from the server-side.
+ *
+ * \return         #MBEDTLS_ERR_SSL_BAD_INPUT_DATA if this function is called
+ *                 prior to completion of the handshake.
+ *
+ * \return         #MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT if the client has
+ *                 not indicated the use of early data to the server.
+ *
+ * \return         #MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED if the client has
+ *                 indicated the use of early data and the server has accepted
+ *                 it.
+ *
+ * \return         #MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED if the client has
+ *                 indicated the use of early data but the server has rejected
+ *                 it. In this situation, the client may want to re-send the
+ *                 early data it may have tried to send by calling
+ *                 mbedtls_ssl_write_early_data() as ordinary post-handshake
+ *                 application data by calling mbedtls_ssl_write().
+ *
+ */
+int mbedtls_ssl_get_early_data_status( mbedtls_ssl_context *ssl );
+#endif /* MBEDTLS_SSL_CLI_C */
+
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
 /**
  * \brief          Free referenced items in an SSL context and clear memory
  *
diff --git a/include/psa/crypto.h b/include/psa/crypto.h
index a71ca3f..03181ed 100644
--- a/include/psa/crypto.h
+++ b/include/psa/crypto.h
@@ -525,7 +525,7 @@
  *
  * This function destroys a key from both volatile
  * memory and, if applicable, non-volatile storage. Implementations shall
- * make a best effort to ensure that that the key material cannot be recovered.
+ * make a best effort to ensure that the key material cannot be recovered.
  *
  * This function also erases any metadata such as policies and frees
  * resources associated with the key.
@@ -3823,7 +3823,7 @@
  * compares those bytes to an expected value, provided as key of type
  * #PSA_KEY_TYPE_PASSWORD_HASH.
  * If you view the key derivation's output as a stream of bytes, this
- * function destructively reads the number of bytes corresponding the the
+ * function destructively reads the number of bytes corresponding to the
  * length of the expected value from the stream before comparing them.
  * The operation's capacity decreases by the number of bytes read.
  *
diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h
index 4f65398..33e2e77 100644
--- a/include/psa/crypto_extra.h
+++ b/include/psa/crypto_extra.h
@@ -1829,7 +1829,7 @@
  */
 #if defined(MBEDTLS_PSA_BUILTIN_PAKE)
 #define PSA_PAKE_OPERATION_INIT {PSA_ALG_NONE, 0, 0, 0, 0,              \
-                                 MBEDTLS_SVC_KEY_ID_INIT,               \
+                                 NULL, 0                ,               \
                                  PSA_PAKE_ROLE_NONE, {0}, 0, 0,         \
                                  {.dummy = 0}}
 #else
@@ -1920,7 +1920,8 @@
 #if defined(MBEDTLS_PSA_BUILTIN_PAKE)
     unsigned int MBEDTLS_PRIVATE(input_step);
     unsigned int MBEDTLS_PRIVATE(output_step);
-    mbedtls_svc_key_id_t MBEDTLS_PRIVATE(password);
+    uint8_t* MBEDTLS_PRIVATE(password);
+    size_t MBEDTLS_PRIVATE(password_len);
     psa_pake_role_t MBEDTLS_PRIVATE(role);
     uint8_t MBEDTLS_PRIVATE(buffer[MBEDTLS_PSA_PAKE_BUFFER_SIZE]);
     size_t MBEDTLS_PRIVATE(buffer_length);
diff --git a/include/psa/crypto_platform.h b/include/psa/crypto_platform.h
index 47ab1cf..573b33c 100644
--- a/include/psa/crypto_platform.h
+++ b/include/psa/crypto_platform.h
@@ -45,11 +45,6 @@
 /* PSA requires several types which C99 provides in stdint.h. */
 #include <stdint.h>
 
-#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
-    !defined(inline) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
 #if defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER)
 
 /* Building for the PSA Crypto service on a PSA platform, a key owner is a PSA
diff --git a/include/psa/crypto_se_driver.h b/include/psa/crypto_se_driver.h
index f0252c8..225fb17 100644
--- a/include/psa/crypto_se_driver.h
+++ b/include/psa/crypto_se_driver.h
@@ -226,7 +226,7 @@
  * operation by comparing the resulting MAC against a provided value
  *
  * \param[in,out] op_context    A hardware-specific structure for the previously
- *                              started MAC operation to be fiinished
+ *                              started MAC operation to be finished
  * \param[in] p_mac             The MAC value against which the resulting MAC
  *                              will be compared against
  * \param[in] mac_length        The size in bytes of the value stored in `p_mac`
@@ -337,7 +337,7 @@
     /** Function that completes a MAC operation with a verify check
      */
     psa_drv_se_mac_finish_verify_t  MBEDTLS_PRIVATE(p_finish_verify);
-    /** Function that aborts a previoustly started MAC operation
+    /** Function that aborts a previously started MAC operation
      */
     psa_drv_se_mac_abort_t          MBEDTLS_PRIVATE(p_abort);
     /** Function that performs a MAC operation in one call
@@ -746,7 +746,7 @@
                                                   size_t ciphertext_size,
                                                   size_t *p_ciphertext_length);
 
-/** A function that peforms a secure element authenticated decryption operation
+/** A function that performs a secure element authenticated decryption operation
  *
  * \param[in,out] drv_context           The driver context structure.
  * \param[in] key_slot                  Slot containing the key to use
@@ -1157,7 +1157,7 @@
  *
  * Different key derivation algorithms require a different number of inputs.
  * Instead of having an API that takes as input variable length arrays, which
- * can be problemmatic to manage on embedded platforms, the inputs are passed
+ * can be problematic to manage on embedded platforms, the inputs are passed
  * to the driver via a function, `psa_drv_se_key_derivation_collateral`, that
  * is called multiple times with different `collateral_id`s. Thus, for a key
  * derivation algorithm that required 3 parameter inputs, the flow would look
@@ -1271,7 +1271,7 @@
     psa_drv_se_key_derivation_collateral_t MBEDTLS_PRIVATE(p_collateral);
     /** Function that performs a final key derivation step */
     psa_drv_se_key_derivation_derive_t     MBEDTLS_PRIVATE(p_derive);
-    /** Function that perforsm a final key derivation or agreement and
+    /** Function that performs a final key derivation or agreement and
      * exports the key */
     psa_drv_se_key_derivation_export_t     MBEDTLS_PRIVATE(p_export);
 } psa_drv_se_key_derivation_t;
diff --git a/include/psa/crypto_sizes.h b/include/psa/crypto_sizes.h
index 231ea62..b42b2df 100644
--- a/include/psa/crypto_sizes.h
+++ b/include/psa/crypto_sizes.h
@@ -717,7 +717,7 @@
     (PSA_KEY_EXPORT_ASN1_INTEGER_MAX_SIZE(key_bits) + 11)
 
 /* Maximum size of the export encoding of an RSA key pair.
- * Assumes thatthe public exponent is less than 2^32 and that the size
+ * Assumes that the public exponent is less than 2^32 and that the size
  * difference between the two primes is at most 1 bit.
  *
  * RSAPrivateKey ::= SEQUENCE {
diff --git a/include/psa/crypto_types.h b/include/psa/crypto_types.h
index 739062d..af61aea 100644
--- a/include/psa/crypto_types.h
+++ b/include/psa/crypto_types.h
@@ -297,7 +297,7 @@
 
 #else /* MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER */
 /* Implementation-specific: The Mbed Cryptography library can be built as
- * part of a multi-client service that exposes the PSA Cryptograpy API in each
+ * part of a multi-client service that exposes the PSA Cryptography API in each
  * client and encodes the client identity in the key identifier argument of
  * functions such as psa_open_key().
  */
diff --git a/include/psa/crypto_values.h b/include/psa/crypto_values.h
index b465ddb..cf8a7b2 100644
--- a/include/psa/crypto_values.h
+++ b/include/psa/crypto_values.h
@@ -1760,7 +1760,7 @@
 #define PSA_ALG_HKDF_BASE                       ((psa_algorithm_t)0x08000100)
 /** Macro to build an HKDF algorithm.
  *
- * For example, `PSA_ALG_HKDF(PSA_ALG_SHA256)` is HKDF using HMAC-SHA-256.
+ * For example, `PSA_ALG_HKDF(PSA_ALG_SHA_256)` is HKDF using HMAC-SHA-256.
  *
  * This key derivation algorithm uses the following inputs:
  * - #PSA_KEY_DERIVATION_INPUT_SALT is the salt used in the "extract" step.
@@ -1805,7 +1805,7 @@
 #define PSA_ALG_HKDF_EXTRACT_BASE                       ((psa_algorithm_t)0x08000400)
 /** Macro to build an HKDF-Extract algorithm.
  *
- * For example, `PSA_ALG_HKDF_EXTRACT(PSA_ALG_SHA256)` is
+ * For example, `PSA_ALG_HKDF_EXTRACT(PSA_ALG_SHA_256)` is
  * HKDF-Extract using HMAC-SHA-256.
  *
  * This key derivation algorithm uses the following inputs:
@@ -1854,7 +1854,7 @@
 #define PSA_ALG_HKDF_EXPAND_BASE                       ((psa_algorithm_t)0x08000500)
 /** Macro to build an HKDF-Expand algorithm.
  *
- * For example, `PSA_ALG_HKDF_EXPAND(PSA_ALG_SHA256)` is
+ * For example, `PSA_ALG_HKDF_EXPAND(PSA_ALG_SHA_256)` is
  * HKDF-Expand using HMAC-SHA-256.
  *
  * This key derivation algorithm uses the following inputs:
@@ -1925,7 +1925,7 @@
  * concatenation of ServerHello.Random + ClientHello.Random,
  * and the label is "key expansion".
  *
- * For example, `PSA_ALG_TLS12_PRF(PSA_ALG_SHA256)` represents the
+ * For example, `PSA_ALG_TLS12_PRF(PSA_ALG_SHA_256)` represents the
  * TLS 1.2 PRF using HMAC-SHA-256.
  *
  * \param hash_alg      A hash algorithm (\c PSA_ALG_XXX value such that
@@ -1995,7 +1995,7 @@
  *   PSA_ALG_RSA_PKCS1V15_CRYPT, passed to the key derivation operation
  *   with `psa_key_derivation_input_bytes()`.
  *
- * For example, `PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA256)` represents the
+ * For example, `PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256)` represents the
  * TLS-1.2 PSK to MasterSecret derivation PRF using HMAC-SHA-256.
  *
  * \param hash_alg      A hash algorithm (\c PSA_ALG_XXX value such that
@@ -2050,7 +2050,7 @@
  * PBKDF2 is defined by PKCS#5, republished as RFC 8018 (section 5.2).
  * This macro specifies the PBKDF2 algorithm constructed using a PRF based on
  * HMAC with the specified hash.
- * For example, `PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA256)` specifies PBKDF2
+ * For example, `PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_256)` specifies PBKDF2
  * using the PRF HMAC-SHA-256.
  *
  * This key derivation algorithm uses the following inputs, which must be
@@ -2577,7 +2577,7 @@
  *
  * This flag allows the key to be used for a MAC verification operation
  * or for an asymmetric signature verification operation,
- * if otherwise permitted by by the key's type and policy.
+ * if otherwise permitted by the key's type and policy.
  *
  * For a key pair, this concerns the public key.
  */
@@ -2587,7 +2587,7 @@
  * hash.
  *
  * This flag allows the key to be used for a key derivation operation or for
- * a key agreement operation, if otherwise permitted by by the key's type and
+ * a key agreement operation, if otherwise permitted by the key's type and
  * policy.
  *
  * If this flag is present on all keys used in calls to
@@ -2603,7 +2603,7 @@
  * This flag allows the key to be used:
  *
  * This flag allows the key to be used in a key derivation operation, if
- * otherwise permitted by by the key's type and policy.
+ * otherwise permitted by the key's type and policy.
  *
  * If this flag is present on all keys used in calls to
  * psa_key_derivation_input_key() for a key derivation operation, then it
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index 7c325f7..c9714bb 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -49,8 +49,6 @@
     md.c
     md5.c
     memory_buffer_alloc.c
-    mps_reader.c
-    mps_trace.c
     nist_kw.c
     oid.c
     padlock.c
@@ -84,7 +82,6 @@
     sha1.c
     sha256.c
     sha512.c
-    ssl_debug_helpers_generated.c
     threading.c
     timing.c
     version.c
@@ -92,6 +89,7 @@
 )
 
 set(src_x509
+    pkcs7.c
     x509.c
     x509_create.c
     x509_crl.c
@@ -103,11 +101,14 @@
 
 set(src_tls
     debug.c
+    mps_reader.c
+    mps_trace.c
     net_sockets.c
     ssl_cache.c
     ssl_ciphersuites.c
     ssl_client.c
     ssl_cookie.c
+    ssl_debug_helpers_generated.c
     ssl_msg.c
     ssl_ticket.c
     ssl_tls.c
@@ -281,7 +282,7 @@
 if(USE_SHARED_MBEDTLS_LIBRARY)
     set(CMAKE_LIBRARY_PATH ${CMAKE_CURRENT_BINARY_DIR})
     add_library(${mbedcrypto_target} SHARED ${src_crypto})
-    set_target_properties(${mbedcrypto_target} PROPERTIES VERSION 3.2.1 SOVERSION 12)
+    set_target_properties(${mbedcrypto_target} PROPERTIES VERSION 3.3.0 SOVERSION 13)
     target_link_libraries(${mbedcrypto_target} PUBLIC ${libs})
 
     if(TARGET everest)
@@ -289,11 +290,11 @@
     endif()
 
     add_library(${mbedx509_target} SHARED ${src_x509})
-    set_target_properties(${mbedx509_target} PROPERTIES VERSION 3.2.1 SOVERSION 4)
+    set_target_properties(${mbedx509_target} PROPERTIES VERSION 3.3.0 SOVERSION 4)
     target_link_libraries(${mbedx509_target} PUBLIC ${libs} ${mbedcrypto_target})
 
     add_library(${mbedtls_target} SHARED ${src_tls})
-    set_target_properties(${mbedtls_target} PROPERTIES VERSION 3.2.1 SOVERSION 18)
+    set_target_properties(${mbedtls_target} PROPERTIES VERSION 3.3.0 SOVERSION 19)
     target_link_libraries(${mbedtls_target} PUBLIC ${libs} ${mbedx509_target})
 endif(USE_SHARED_MBEDTLS_LIBRARY)
 
diff --git a/library/Makefile b/library/Makefile
index b1cdc7f..dd16d06 100644
--- a/library/Makefile
+++ b/library/Makefile
@@ -47,9 +47,9 @@
 endif
 endif
 
-SOEXT_TLS?=so.18
+SOEXT_TLS?=so.19
 SOEXT_X509?=so.4
-SOEXT_CRYPTO?=so.12
+SOEXT_CRYPTO?=so.13
 
 # Set AR_DASH= (empty string) to use an ar implementation that does not accept
 # the - prefix for command line options (e.g. llvm-ar)
@@ -114,8 +114,6 @@
 	     md.o \
 	     md5.o \
 	     memory_buffer_alloc.o \
-	     mps_reader.o \
-	     mps_trace.o \
 	     nist_kw.o \
 	     oid.o \
 	     padlock.o \
@@ -149,7 +147,6 @@
 	     sha1.o \
 	     sha256.o \
 	     sha512.o \
-	     ssl_debug_helpers_generated.o \
 	     threading.o \
 	     timing.o \
 	     version.o \
@@ -168,15 +165,19 @@
 	   x509_csr.o \
 	   x509write_crt.o \
 	   x509write_csr.o \
+	   pkcs7.o \
 	   # This line is intentionally left blank
 
 OBJS_TLS= \
 	  debug.o \
+	  mps_reader.o \
+	  mps_trace.o \
 	  net_sockets.o \
 	  ssl_cache.o \
 	  ssl_ciphersuites.o \
 	  ssl_client.o \
 	  ssl_cookie.o \
+	  ssl_debug_helpers_generated.o \
 	  ssl_msg.o \
 	  ssl_ticket.o \
 	  ssl_tls.o \
diff --git a/library/aes.c b/library/aes.c
index 7d03524..56dc5cf 100644
--- a/library/aes.c
+++ b/library/aes.c
@@ -978,7 +978,6 @@
                     const unsigned char *input,
                     unsigned char *output )
 {
-    int i;
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     unsigned char temp[16];
 
@@ -1009,8 +1008,7 @@
             if( ret != 0 )
                 goto exit;
 
-            for( i = 0; i < 16; i++ )
-                output[i] = (unsigned char)( output[i] ^ iv[i] );
+            mbedtls_xor( output, output, iv, 16 );
 
             memcpy( iv, temp, 16 );
 
@@ -1023,8 +1021,7 @@
     {
         while( length > 0 )
         {
-            for( i = 0; i < 16; i++ )
-                output[i] = (unsigned char)( input[i] ^ iv[i] );
+            mbedtls_xor( output, input, iv, 16 );
 
             ret = mbedtls_aes_crypt_ecb( ctx, mode, output, output );
             if( ret != 0 )
@@ -1106,28 +1103,24 @@
 
     while( blocks-- )
     {
-        size_t i;
-
         if( leftover && ( mode == MBEDTLS_AES_DECRYPT ) && blocks == 0 )
         {
             /* We are on the last block in a decrypt operation that has
              * leftover bytes, so we need to use the next tweak for this block,
-             * and this tweak for the lefover bytes. Save the current tweak for
+             * and this tweak for the leftover bytes. Save the current tweak for
              * the leftovers and then update the current tweak for use on this,
              * the last full block. */
             memcpy( prev_tweak, tweak, sizeof( tweak ) );
             mbedtls_gf128mul_x_ble( tweak, tweak );
         }
 
-        for( i = 0; i < 16; i++ )
-            tmp[i] = input[i] ^ tweak[i];
+        mbedtls_xor( tmp, input, tweak, 16 );
 
         ret = mbedtls_aes_crypt_ecb( &ctx->crypt, mode, tmp, tmp );
         if( ret != 0 )
             return( ret );
 
-        for( i = 0; i < 16; i++ )
-            output[i] = tmp[i] ^ tweak[i];
+        mbedtls_xor( output, tmp, tweak, 16 );
 
         /* Update the tweak for the next block. */
         mbedtls_gf128mul_x_ble( tweak, tweak );
@@ -1148,19 +1141,18 @@
         unsigned char *prev_output = output - 16;
 
         /* Copy ciphertext bytes from the previous block to our output for each
-         * byte of ciphertext we won't steal. At the same time, copy the
-         * remainder of the input for this final round (since the loop bounds
-         * are the same). */
+         * byte of ciphertext we won't steal. */
         for( i = 0; i < leftover; i++ )
         {
             output[i] = prev_output[i];
-            tmp[i] = input[i] ^ t[i];
         }
 
+        /* Copy the remainder of the input for this final round. */
+        mbedtls_xor( tmp, input, t, leftover );
+
         /* Copy ciphertext bytes from the previous block for input in this
          * round. */
-        for( ; i < 16; i++ )
-            tmp[i] = prev_output[i] ^ t[i];
+        mbedtls_xor( tmp + i, prev_output + i, t + i, 16 - i );
 
         ret = mbedtls_aes_crypt_ecb( &ctx->crypt, mode, tmp, tmp );
         if( ret != 0 )
@@ -1168,8 +1160,7 @@
 
         /* Write the result back to the previous block, overriding the previous
          * output we copied. */
-        for( i = 0; i < 16; i++ )
-            prev_output[i] = tmp[i] ^ t[i];
+        mbedtls_xor( prev_output, tmp, t, 16 );
     }
 
     return( 0 );
diff --git a/library/alignment.h b/library/alignment.h
new file mode 100644
index 0000000..3c5fa23
--- /dev/null
+++ b/library/alignment.h
@@ -0,0 +1,494 @@
+/**
+ * \file alignment.h
+ *
+ * \brief Utility code for dealing with unaligned memory accesses
+ */
+/*
+ *  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_LIBRARY_ALIGNMENT_H
+#define MBEDTLS_LIBRARY_ALIGNMENT_H
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "mbedtls/build_info.h"
+
+/**
+ * Read the unsigned 16 bits integer from the given address, which need not
+ * be aligned.
+ *
+ * \param   p pointer to 2 bytes of data
+ * \return  Data at the given address
+ */
+inline uint16_t mbedtls_get_unaligned_uint16( const void *p )
+{
+    uint16_t r;
+    memcpy( &r, p, sizeof( r ) );
+    return r;
+}
+
+/**
+ * Write the unsigned 16 bits integer to the given address, which need not
+ * be aligned.
+ *
+ * \param   p pointer to 2 bytes of data
+ * \param   x data to write
+ */
+inline void mbedtls_put_unaligned_uint16( void *p, uint16_t x )
+{
+    memcpy( p, &x, sizeof( x ) );
+}
+
+/**
+ * Read the unsigned 32 bits integer from the given address, which need not
+ * be aligned.
+ *
+ * \param   p pointer to 4 bytes of data
+ * \return  Data at the given address
+ */
+inline uint32_t mbedtls_get_unaligned_uint32( const void *p )
+{
+    uint32_t r;
+    memcpy( &r, p, sizeof( r ) );
+    return r;
+}
+
+/**
+ * Write the unsigned 32 bits integer to the given address, which need not
+ * be aligned.
+ *
+ * \param   p pointer to 4 bytes of data
+ * \param   x data to write
+ */
+inline void mbedtls_put_unaligned_uint32( void *p, uint32_t x )
+{
+    memcpy( p, &x, sizeof( x ) );
+}
+
+/**
+ * Read the unsigned 64 bits integer from the given address, which need not
+ * be aligned.
+ *
+ * \param   p pointer to 8 bytes of data
+ * \return  Data at the given address
+ */
+inline uint64_t mbedtls_get_unaligned_uint64( const void *p )
+{
+    uint64_t r;
+    memcpy( &r, p, sizeof( r ) );
+    return r;
+}
+
+/**
+ * Write the unsigned 64 bits integer to the given address, which need not
+ * be aligned.
+ *
+ * \param   p pointer to 8 bytes of data
+ * \param   x data to write
+ */
+inline void mbedtls_put_unaligned_uint64( void *p, uint64_t x )
+{
+    memcpy( p, &x, sizeof( x ) );
+}
+
+/** Byte Reading Macros
+ *
+ * Given a multi-byte integer \p x, MBEDTLS_BYTE_n retrieves the n-th
+ * byte from x, where byte 0 is the least significant byte.
+ */
+#define MBEDTLS_BYTE_0( x ) ( (uint8_t) (   ( x )         & 0xff ) )
+#define MBEDTLS_BYTE_1( x ) ( (uint8_t) ( ( ( x ) >> 8  ) & 0xff ) )
+#define MBEDTLS_BYTE_2( x ) ( (uint8_t) ( ( ( x ) >> 16 ) & 0xff ) )
+#define MBEDTLS_BYTE_3( x ) ( (uint8_t) ( ( ( x ) >> 24 ) & 0xff ) )
+#define MBEDTLS_BYTE_4( x ) ( (uint8_t) ( ( ( x ) >> 32 ) & 0xff ) )
+#define MBEDTLS_BYTE_5( x ) ( (uint8_t) ( ( ( x ) >> 40 ) & 0xff ) )
+#define MBEDTLS_BYTE_6( x ) ( (uint8_t) ( ( ( x ) >> 48 ) & 0xff ) )
+#define MBEDTLS_BYTE_7( x ) ( (uint8_t) ( ( ( x ) >> 56 ) & 0xff ) )
+
+/*
+ * Detect GCC built-in byteswap routines
+ */
+#if defined(__GNUC__) && defined(__GNUC_PREREQ)
+#if __GNUC_PREREQ(4,8)
+#define MBEDTLS_BSWAP16 __builtin_bswap16
+#endif /* __GNUC_PREREQ(4,8) */
+#if __GNUC_PREREQ(4,3)
+#define MBEDTLS_BSWAP32 __builtin_bswap32
+#define MBEDTLS_BSWAP64 __builtin_bswap64
+#endif /* __GNUC_PREREQ(4,3) */
+#endif /* defined(__GNUC__) && defined(__GNUC_PREREQ) */
+
+/*
+ * Detect Clang built-in byteswap routines
+ */
+#if defined(__clang__) && defined(__has_builtin)
+#if __has_builtin(__builtin_bswap16)
+#define MBEDTLS_BSWAP16 __builtin_bswap16
+#endif /* __has_builtin(__builtin_bswap16) */
+#if __has_builtin(__builtin_bswap32)
+#define MBEDTLS_BSWAP32 __builtin_bswap32
+#endif /* __has_builtin(__builtin_bswap32) */
+#if __has_builtin(__builtin_bswap64)
+#define MBEDTLS_BSWAP64 __builtin_bswap64
+#endif /* __has_builtin(__builtin_bswap64) */
+#endif /* defined(__clang__) && defined(__has_builtin) */
+
+/*
+ * Detect MSVC built-in byteswap routines
+ */
+#if defined(_MSC_VER)
+#define MBEDTLS_BSWAP16 _byteswap_ushort
+#define MBEDTLS_BSWAP32 _byteswap_ulong
+#define MBEDTLS_BSWAP64 _byteswap_uint64
+#endif /* defined(_MSC_VER) */
+
+/* Detect armcc built-in byteswap routine */
+#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 410000)
+#define MBEDTLS_BSWAP32 __rev
+#endif
+
+/*
+ * Where compiler built-ins are not present, fall back to C code that the
+ * compiler may be able to detect and transform into the relevant bswap or
+ * similar instruction.
+ */
+#if !defined(MBEDTLS_BSWAP16)
+static inline uint16_t mbedtls_bswap16( uint16_t x ) {
+    return
+         ( x & 0x00ff ) << 8 |
+         ( x & 0xff00 ) >> 8;
+}
+#define MBEDTLS_BSWAP16 mbedtls_bswap16
+#endif /* !defined(MBEDTLS_BSWAP16) */
+
+#if !defined(MBEDTLS_BSWAP32)
+static inline uint32_t mbedtls_bswap32( uint32_t x ) {
+    return
+         ( x & 0x000000ff ) << 24 |
+         ( x & 0x0000ff00 ) <<  8 |
+         ( x & 0x00ff0000 ) >>  8 |
+         ( x & 0xff000000 ) >> 24;
+}
+#define MBEDTLS_BSWAP32 mbedtls_bswap32
+#endif /* !defined(MBEDTLS_BSWAP32) */
+
+#if !defined(MBEDTLS_BSWAP64)
+static inline uint64_t mbedtls_bswap64( uint64_t x ) {
+    return
+         ( x & 0x00000000000000ff ) << 56 |
+         ( x & 0x000000000000ff00 ) << 40 |
+         ( x & 0x0000000000ff0000 ) << 24 |
+         ( x & 0x00000000ff000000 ) <<  8 |
+         ( x & 0x000000ff00000000 ) >>  8 |
+         ( x & 0x0000ff0000000000 ) >> 24 |
+         ( x & 0x00ff000000000000 ) >> 40 |
+         ( x & 0xff00000000000000 ) >> 56;
+}
+#define MBEDTLS_BSWAP64 mbedtls_bswap64
+#endif /* !defined(MBEDTLS_BSWAP64) */
+
+#if !defined(__BYTE_ORDER__)
+static const uint16_t mbedtls_byte_order_detector = { 0x100 };
+#define MBEDTLS_IS_BIG_ENDIAN (*((unsigned char *) (&mbedtls_byte_order_detector)) == 0x01)
+#else
+#define MBEDTLS_IS_BIG_ENDIAN ((__BYTE_ORDER__) == (__ORDER_BIG_ENDIAN__))
+#endif /* !defined(__BYTE_ORDER__) */
+
+/**
+ * Get the unsigned 32 bits integer corresponding to four bytes in
+ * big-endian order (MSB first).
+ *
+ * \param   data    Base address of the memory to get the four bytes from.
+ * \param   offset  Offset from \p data of the first and most significant
+ *                  byte of the four bytes to build the 32 bits unsigned
+ *                  integer from.
+ */
+#define MBEDTLS_GET_UINT32_BE( data, offset )                              \
+    ( ( MBEDTLS_IS_BIG_ENDIAN )                                            \
+        ? mbedtls_get_unaligned_uint32((data) + (offset))                  \
+        : MBEDTLS_BSWAP32(mbedtls_get_unaligned_uint32((data) + (offset))) \
+    )
+
+/**
+ * Put in memory a 32 bits unsigned integer in big-endian order.
+ *
+ * \param   n       32 bits unsigned integer to put in memory.
+ * \param   data    Base address of the memory where to put the 32
+ *                  bits unsigned integer in.
+ * \param   offset  Offset from \p data where to put the most significant
+ *                  byte of the 32 bits unsigned integer \p n.
+ */
+#define MBEDTLS_PUT_UINT32_BE( n, data, offset )                             \
+{                                                                            \
+    if ( MBEDTLS_IS_BIG_ENDIAN )                                             \
+    {                                                                        \
+        mbedtls_put_unaligned_uint32((data) + (offset), (uint32_t)(n));      \
+    }                                                                        \
+    else                                                                     \
+    {                                                                        \
+        mbedtls_put_unaligned_uint32((data) + (offset), MBEDTLS_BSWAP32((uint32_t)(n))); \
+    }                                                                        \
+}
+
+/**
+ * Get the unsigned 32 bits integer corresponding to four bytes in
+ * little-endian order (LSB first).
+ *
+ * \param   data    Base address of the memory to get the four bytes from.
+ * \param   offset  Offset from \p data of the first and least significant
+ *                  byte of the four bytes to build the 32 bits unsigned
+ *                  integer from.
+ */
+#define MBEDTLS_GET_UINT32_LE( data, offset )                              \
+    ( ( MBEDTLS_IS_BIG_ENDIAN )                                            \
+        ? MBEDTLS_BSWAP32(mbedtls_get_unaligned_uint32((data) + (offset))) \
+        : mbedtls_get_unaligned_uint32((data) + (offset))                  \
+    )
+
+
+/**
+ * Put in memory a 32 bits unsigned integer in little-endian order.
+ *
+ * \param   n       32 bits unsigned integer to put in memory.
+ * \param   data    Base address of the memory where to put the 32
+ *                  bits unsigned integer in.
+ * \param   offset  Offset from \p data where to put the least significant
+ *                  byte of the 32 bits unsigned integer \p n.
+ */
+#define MBEDTLS_PUT_UINT32_LE( n, data, offset )                             \
+{                                                                            \
+    if ( MBEDTLS_IS_BIG_ENDIAN )                                             \
+    {                                                                        \
+        mbedtls_put_unaligned_uint32((data) + (offset), MBEDTLS_BSWAP32((uint32_t)(n))); \
+    }                                                                        \
+    else                                                                     \
+    {                                                                        \
+        mbedtls_put_unaligned_uint32((data) + (offset), ((uint32_t)(n)));      \
+    }                                                                        \
+}
+
+/**
+ * Get the unsigned 16 bits integer corresponding to two bytes in
+ * little-endian order (LSB first).
+ *
+ * \param   data    Base address of the memory to get the two bytes from.
+ * \param   offset  Offset from \p data of the first and least significant
+ *                  byte of the two bytes to build the 16 bits unsigned
+ *                  integer from.
+ */
+#define MBEDTLS_GET_UINT16_LE( data, offset )                              \
+    ( ( MBEDTLS_IS_BIG_ENDIAN )                                            \
+        ? MBEDTLS_BSWAP16(mbedtls_get_unaligned_uint16((data) + (offset))) \
+        : mbedtls_get_unaligned_uint16((data) + (offset))                  \
+    )
+
+/**
+ * Put in memory a 16 bits unsigned integer in little-endian order.
+ *
+ * \param   n       16 bits unsigned integer to put in memory.
+ * \param   data    Base address of the memory where to put the 16
+ *                  bits unsigned integer in.
+ * \param   offset  Offset from \p data where to put the least significant
+ *                  byte of the 16 bits unsigned integer \p n.
+ */
+#define MBEDTLS_PUT_UINT16_LE( n, data, offset )                             \
+{                                                                            \
+    if ( MBEDTLS_IS_BIG_ENDIAN )                                             \
+    {                                                                        \
+        mbedtls_put_unaligned_uint16((data) + (offset), MBEDTLS_BSWAP16((uint16_t)(n))); \
+    }                                                                        \
+    else                                                                     \
+    {                                                                        \
+        mbedtls_put_unaligned_uint16((data) + (offset), (uint16_t)(n));      \
+    }                                                                        \
+}
+
+/**
+ * Get the unsigned 16 bits integer corresponding to two bytes in
+ * big-endian order (MSB first).
+ *
+ * \param   data    Base address of the memory to get the two bytes from.
+ * \param   offset  Offset from \p data of the first and most significant
+ *                  byte of the two bytes to build the 16 bits unsigned
+ *                  integer from.
+ */
+#define MBEDTLS_GET_UINT16_BE( data, offset )                              \
+    ( ( MBEDTLS_IS_BIG_ENDIAN )                                            \
+        ? mbedtls_get_unaligned_uint16((data) + (offset))                  \
+        : MBEDTLS_BSWAP16(mbedtls_get_unaligned_uint16((data) + (offset))) \
+    )
+
+/**
+ * Put in memory a 16 bits unsigned integer in big-endian order.
+ *
+ * \param   n       16 bits unsigned integer to put in memory.
+ * \param   data    Base address of the memory where to put the 16
+ *                  bits unsigned integer in.
+ * \param   offset  Offset from \p data where to put the most significant
+ *                  byte of the 16 bits unsigned integer \p n.
+ */
+#define MBEDTLS_PUT_UINT16_BE( n, data, offset )                             \
+{                                                                            \
+    if ( MBEDTLS_IS_BIG_ENDIAN )                                             \
+    {                                                                        \
+        mbedtls_put_unaligned_uint16((data) + (offset), (uint16_t)(n));      \
+    }                                                                        \
+    else                                                                     \
+    {                                                                        \
+        mbedtls_put_unaligned_uint16((data) + (offset), MBEDTLS_BSWAP16((uint16_t)(n))); \
+    }                                                                        \
+}
+
+/**
+ * Get the unsigned 24 bits integer corresponding to three bytes in
+ * big-endian order (MSB first).
+ *
+ * \param   data    Base address of the memory to get the three bytes from.
+ * \param   offset  Offset from \p data of the first and most significant
+ *                  byte of the three bytes to build the 24 bits unsigned
+ *                  integer from.
+ */
+#define MBEDTLS_GET_UINT24_BE( data , offset )                  \
+    (                                                           \
+          ( (uint32_t) ( data )[( offset )    ] << 16 )         \
+        | ( (uint32_t) ( data )[( offset ) + 1] << 8  )         \
+        | ( (uint32_t) ( data )[( offset ) + 2]       )         \
+    )
+
+/**
+ * Put in memory a 24 bits unsigned integer in big-endian order.
+ *
+ * \param   n       24 bits unsigned integer to put in memory.
+ * \param   data    Base address of the memory where to put the 24
+ *                  bits unsigned integer in.
+ * \param   offset  Offset from \p data where to put the most significant
+ *                  byte of the 24 bits unsigned integer \p n.
+ */
+#define MBEDTLS_PUT_UINT24_BE( n, data, offset )                \
+{                                                               \
+    ( data )[( offset )    ] = MBEDTLS_BYTE_2( n );             \
+    ( data )[( offset ) + 1] = MBEDTLS_BYTE_1( n );             \
+    ( data )[( offset ) + 2] = MBEDTLS_BYTE_0( n );             \
+}
+
+/**
+ * Get the unsigned 24 bits integer corresponding to three bytes in
+ * little-endian order (LSB first).
+ *
+ * \param   data    Base address of the memory to get the three bytes from.
+ * \param   offset  Offset from \p data of the first and least significant
+ *                  byte of the three bytes to build the 24 bits unsigned
+ *                  integer from.
+ */
+#define MBEDTLS_GET_UINT24_LE( data, offset )                   \
+    (                                                           \
+          ( (uint32_t) ( data )[( offset )    ]       )         \
+        | ( (uint32_t) ( data )[( offset ) + 1] <<  8 )         \
+        | ( (uint32_t) ( data )[( offset ) + 2] << 16 )         \
+    )
+
+/**
+ * Put in memory a 24 bits unsigned integer in little-endian order.
+ *
+ * \param   n       24 bits unsigned integer to put in memory.
+ * \param   data    Base address of the memory where to put the 24
+ *                  bits unsigned integer in.
+ * \param   offset  Offset from \p data where to put the least significant
+ *                  byte of the 24 bits unsigned integer \p n.
+ */
+#define MBEDTLS_PUT_UINT24_LE( n, data, offset )                \
+{                                                               \
+    ( data )[( offset )    ] = MBEDTLS_BYTE_0( n );             \
+    ( data )[( offset ) + 1] = MBEDTLS_BYTE_1( n );             \
+    ( data )[( offset ) + 2] = MBEDTLS_BYTE_2( n );             \
+}
+
+/**
+ * Get the unsigned 64 bits integer corresponding to eight bytes in
+ * big-endian order (MSB first).
+ *
+ * \param   data    Base address of the memory to get the eight bytes from.
+ * \param   offset  Offset from \p data of the first and most significant
+ *                  byte of the eight bytes to build the 64 bits unsigned
+ *                  integer from.
+ */
+#define MBEDTLS_GET_UINT64_BE( data, offset )                              \
+    ( ( MBEDTLS_IS_BIG_ENDIAN )                                            \
+        ? mbedtls_get_unaligned_uint64((data) + (offset))                  \
+        : MBEDTLS_BSWAP64(mbedtls_get_unaligned_uint64((data) + (offset))) \
+    )
+
+/**
+ * Put in memory a 64 bits unsigned integer in big-endian order.
+ *
+ * \param   n       64 bits unsigned integer to put in memory.
+ * \param   data    Base address of the memory where to put the 64
+ *                  bits unsigned integer in.
+ * \param   offset  Offset from \p data where to put the most significant
+ *                  byte of the 64 bits unsigned integer \p n.
+ */
+#define MBEDTLS_PUT_UINT64_BE( n, data, offset )                             \
+{                                                                            \
+    if ( MBEDTLS_IS_BIG_ENDIAN )                                             \
+    {                                                                        \
+        mbedtls_put_unaligned_uint64((data) + (offset), (uint64_t)(n));      \
+    }                                                                        \
+    else                                                                     \
+    {                                                                        \
+        mbedtls_put_unaligned_uint64((data) + (offset), MBEDTLS_BSWAP64((uint64_t)(n))); \
+    }                                                                        \
+}
+
+/**
+ * Get the unsigned 64 bits integer corresponding to eight bytes in
+ * little-endian order (LSB first).
+ *
+ * \param   data    Base address of the memory to get the eight bytes from.
+ * \param   offset  Offset from \p data of the first and least significant
+ *                  byte of the eight bytes to build the 64 bits unsigned
+ *                  integer from.
+ */
+#define MBEDTLS_GET_UINT64_LE( data, offset )                              \
+    ( ( MBEDTLS_IS_BIG_ENDIAN )                                            \
+        ? MBEDTLS_BSWAP64(mbedtls_get_unaligned_uint64((data) + (offset))) \
+        : mbedtls_get_unaligned_uint64((data) + (offset))                  \
+    )
+
+/**
+ * Put in memory a 64 bits unsigned integer in little-endian order.
+ *
+ * \param   n       64 bits unsigned integer to put in memory.
+ * \param   data    Base address of the memory where to put the 64
+ *                  bits unsigned integer in.
+ * \param   offset  Offset from \p data where to put the least significant
+ *                  byte of the 64 bits unsigned integer \p n.
+ */
+#define MBEDTLS_PUT_UINT64_LE( n, data, offset )                             \
+{                                                                            \
+    if ( MBEDTLS_IS_BIG_ENDIAN )                                             \
+    {                                                                        \
+        mbedtls_put_unaligned_uint64((data) + (offset), MBEDTLS_BSWAP64((uint64_t)(n))); \
+    }                                                                        \
+    else                                                                     \
+    {                                                                        \
+        mbedtls_put_unaligned_uint64((data) + (offset), (uint64_t)(n));      \
+    }                                                                        \
+}
+
+#endif /* MBEDTLS_LIBRARY_ALIGNMENT_H */
diff --git a/library/aria.c b/library/aria.c
index 924f952..517e10a 100644
--- a/library/aria.c
+++ b/library/aria.c
@@ -37,11 +37,6 @@
 
 #include "mbedtls/platform_util.h"
 
-#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
-    !defined(inline) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
 /* Parameter validation macros */
 #define ARIA_VALIDATE_RET( cond )                                       \
     MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ARIA_BAD_INPUT_DATA )
@@ -103,47 +98,8 @@
  * modify byte order: ( A B C D ) -> ( D C B A ), i.e. change endianness
  *
  * This is submatrix P3 in [1] Appendix B.1
- *
- * Some compilers fail to translate this to a single instruction,
- * so let's provide asm versions for common platforms with C fallback.
  */
-#if defined(MBEDTLS_HAVE_ASM)
-#if defined(__arm__) /* rev available from v6 up */
-/* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */
-#if defined(__GNUC__) && \
-    ( !defined(__ARMCC_VERSION) || __ARMCC_VERSION >= 6000000 ) && \
-    __ARM_ARCH >= 6
-static inline uint32_t aria_p3( uint32_t x )
-{
-    uint32_t r;
-    __asm( "rev %0, %1" : "=l" (r) : "l" (x) );
-    return( r );
-}
-#define ARIA_P3 aria_p3
-#elif defined(__ARMCC_VERSION) && __ARMCC_VERSION < 6000000 && \
-    ( __TARGET_ARCH_ARM >= 6 || __TARGET_ARCH_THUMB >= 3 )
-static inline uint32_t aria_p3( uint32_t x )
-{
-    uint32_t r;
-    __asm( "rev r, x" );
-    return( r );
-}
-#define ARIA_P3 aria_p3
-#endif
-#endif /* arm */
-#if defined(__GNUC__) && \
-    defined(__i386__) || defined(__amd64__) || defined( __x86_64__)
-static inline uint32_t aria_p3( uint32_t x )
-{
-    __asm( "bswap %0" : "=r" (x) : "0" (x) );
-    return( x );
-}
-#define ARIA_P3 aria_p3
-#endif /* x86 gnuc */
-#endif /* MBEDTLS_HAVE_ASM && GNUC */
-#if !defined(ARIA_P3)
-#define ARIA_P3(x) ARIA_P2( ARIA_P1 ( x ) )
-#endif
+#define ARIA_P3(x) MBEDTLS_BSWAP32(x)
 
 /*
  * ARIA Affine Transform
@@ -588,7 +544,6 @@
                             const unsigned char *input,
                             unsigned char *output )
 {
-    int i;
     unsigned char temp[MBEDTLS_ARIA_BLOCKSIZE];
 
     ARIA_VALIDATE_RET( ctx != NULL );
@@ -608,8 +563,7 @@
             memcpy( temp, input, MBEDTLS_ARIA_BLOCKSIZE );
             mbedtls_aria_crypt_ecb( ctx, input, output );
 
-            for( i = 0; i < MBEDTLS_ARIA_BLOCKSIZE; i++ )
-                output[i] = (unsigned char)( output[i] ^ iv[i] );
+            mbedtls_xor( output, output, iv, MBEDTLS_ARIA_BLOCKSIZE );
 
             memcpy( iv, temp, MBEDTLS_ARIA_BLOCKSIZE );
 
@@ -622,8 +576,7 @@
     {
         while( length > 0 )
         {
-            for( i = 0; i < MBEDTLS_ARIA_BLOCKSIZE; i++ )
-                output[i] = (unsigned char)( input[i] ^ iv[i] );
+            mbedtls_xor( output, input, iv, MBEDTLS_ARIA_BLOCKSIZE );
 
             mbedtls_aria_crypt_ecb( ctx, output, output );
             memcpy( iv, output, MBEDTLS_ARIA_BLOCKSIZE );
diff --git a/library/bignum.c b/library/bignum.c
index 521787d..fc4ddf6 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -252,6 +252,17 @@
     memcpy(  Y, &T, sizeof( mbedtls_mpi ) );
 }
 
+static inline mbedtls_mpi_uint mpi_sint_abs( mbedtls_mpi_sint z )
+{
+    if( z >= 0 )
+        return( z );
+    /* Take care to handle the most negative value (-2^(biL-1)) correctly.
+     * A naive -z would have undefined behavior.
+     * Write this in a way that makes popular compilers happy (GCC, Clang,
+     * MSVC). */
+    return( (mbedtls_mpi_uint) 0 - (mbedtls_mpi_uint) z );
+}
+
 /*
  * Set value from integer
  */
@@ -263,7 +274,7 @@
     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, 1 ) );
     memset( X->p, 0, X->n * ciL );
 
-    X->p[0] = ( z < 0 ) ? -z : z;
+    X->p[0] = mpi_sint_abs( z );
     X->s    = ( z < 0 ) ? -1 : 1;
 
 cleanup:
@@ -853,7 +864,7 @@
     mbedtls_mpi_uint p[1];
     MPI_VALIDATE_RET( X != NULL );
 
-    *p  = ( z < 0 ) ? -z : z;
+    *p  = mpi_sint_abs( z );
     Y.s = ( z < 0 ) ? -1 : 1;
     Y.n = 1;
     Y.p = p;
@@ -889,6 +900,11 @@
         if( B->p[j - 1] != 0 )
             break;
 
+    /* Exit early to avoid undefined behavior on NULL+0 when X->n == 0
+     * and B is 0 (of any size). */
+    if( j == 0 )
+        return( 0 );
+
     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
 
     /* j is the number of non-zero limbs of B. Add those to X. */
@@ -952,17 +968,15 @@
     carry = mbedtls_mpi_core_sub( X->p, A->p, B->p, n );
     if( carry != 0 )
     {
-        /* Propagate the carry to the first nonzero limb of X. */
-        for( ; n < X->n && X->p[n] == 0; n++ )
-            --X->p[n];
-        /* If we ran out of space for the carry, it means that the result
-         * is negative. */
-        if( n == X->n )
+        /* Propagate the carry through the rest of X. */
+        carry = mbedtls_mpi_core_sub_int( X->p + n, X->p + n, carry, X->n - n );
+
+        /* If we have further carry/borrow, the result is negative. */
+        if( carry != 0 )
         {
             ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
             goto cleanup;
         }
-        --X->p[n];
     }
 
     /* X should always be positive as a result of unsigned subtractions. */
@@ -972,10 +986,12 @@
     return( ret );
 }
 
-/*
- * Signed addition: X = A + B
+/* Common function for signed addition and subtraction.
+ * Calculate A + B * flip_B where flip_B is 1 or -1.
  */
-int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
+static int add_sub_mpi( mbedtls_mpi *X,
+                        const mbedtls_mpi *A, const mbedtls_mpi *B,
+                        int flip_B )
 {
     int ret, s;
     MPI_VALIDATE_RET( X != NULL );
@@ -983,16 +999,21 @@
     MPI_VALIDATE_RET( B != NULL );
 
     s = A->s;
-    if( A->s * B->s < 0 )
+    if( A->s * B->s * flip_B < 0 )
     {
-        if( mbedtls_mpi_cmp_abs( A, B ) >= 0 )
+        int cmp = mbedtls_mpi_cmp_abs( A, B );
+        if( cmp >= 0 )
         {
             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) );
-            X->s =  s;
+            /* If |A| = |B|, the result is 0 and we must set the sign bit
+             * to +1 regardless of which of A or B was negative. Otherwise,
+             * since |A| > |B|, the sign is the sign of A. */
+            X->s = cmp == 0 ? 1 : s;
         }
         else
         {
             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) );
+            /* Since |A| < |B|, the sign is the opposite of A. */
             X->s = -s;
         }
     }
@@ -1008,38 +1029,19 @@
 }
 
 /*
+ * Signed addition: X = A + B
+ */
+int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
+{
+    return( add_sub_mpi( X, A, B, 1 ) );
+}
+
+/*
  * Signed subtraction: X = A - B
  */
 int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
 {
-    int ret, s;
-    MPI_VALIDATE_RET( X != NULL );
-    MPI_VALIDATE_RET( A != NULL );
-    MPI_VALIDATE_RET( B != NULL );
-
-    s = A->s;
-    if( A->s * B->s > 0 )
-    {
-        if( mbedtls_mpi_cmp_abs( A, B ) >= 0 )
-        {
-            MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) );
-            X->s =  s;
-        }
-        else
-        {
-            MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) );
-            X->s = -s;
-        }
-    }
-    else
-    {
-        MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) );
-        X->s = s;
-    }
-
-cleanup:
-
-    return( ret );
+    return( add_sub_mpi( X, A, B, -1 ) );
 }
 
 /*
@@ -1052,7 +1054,7 @@
     MPI_VALIDATE_RET( X != NULL );
     MPI_VALIDATE_RET( A != NULL );
 
-    p[0] = ( b < 0 ) ? -b : b;
+    p[0] = mpi_sint_abs( b );
     B.s = ( b < 0 ) ? -1 : 1;
     B.n = 1;
     B.p = p;
@@ -1070,7 +1072,7 @@
     MPI_VALIDATE_RET( X != NULL );
     MPI_VALIDATE_RET( A != NULL );
 
-    p[0] = ( b < 0 ) ? -b : b;
+    p[0] = mpi_sint_abs( b );
     B.s = ( b < 0 ) ? -1 : 1;
     B.n = 1;
     B.p = p;
@@ -1408,7 +1410,7 @@
     mbedtls_mpi_uint p[1];
     MPI_VALIDATE_RET( A != NULL );
 
-    p[0] = ( b < 0 ) ? -b : b;
+    p[0] = mpi_sint_abs( b );
     B.s = ( b < 0 ) ? -1 : 1;
     B.n = 1;
     B.p = p;
@@ -1588,11 +1590,11 @@
                          mbedtls_mpi *prec_RR )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    size_t wbits, wsize, one = 1;
+    size_t window_bitsize;
     size_t i, j, nblimbs;
     size_t bufsize, nbits;
     mbedtls_mpi_uint ei, mm, state;
-    mbedtls_mpi RR, T, W[ 1 << MBEDTLS_MPI_WINDOW_SIZE ], WW, Apos;
+    mbedtls_mpi RR, T, W[ (size_t) 1 << MBEDTLS_MPI_WINDOW_SIZE ], WW, Apos;
     int neg;
 
     MPI_VALIDATE_RET( X != NULL );
@@ -1621,21 +1623,59 @@
 
     i = mbedtls_mpi_bitlen( E );
 
-    wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
+    window_bitsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
             ( i >  79 ) ? 4 : ( i >  23 ) ? 3 : 1;
 
 #if( MBEDTLS_MPI_WINDOW_SIZE < 6 )
-    if( wsize > MBEDTLS_MPI_WINDOW_SIZE )
-        wsize = MBEDTLS_MPI_WINDOW_SIZE;
+    if( window_bitsize > MBEDTLS_MPI_WINDOW_SIZE )
+        window_bitsize = MBEDTLS_MPI_WINDOW_SIZE;
 #endif
 
+    const size_t w_table_used_size = (size_t) 1 << window_bitsize;
+
+    /*
+     * This function is not constant-trace: its memory accesses depend on the
+     * exponent value. To defend against timing attacks, callers (such as RSA
+     * and DHM) should use exponent blinding. However this is not enough if the
+     * adversary can find the exponent in a single trace, so this function
+     * takes extra precautions against adversaries who can observe memory
+     * access patterns.
+     *
+     * This function performs a series of multiplications by table elements and
+     * squarings, and we want the prevent the adversary from finding out which
+     * table element was used, and from distinguishing between multiplications
+     * 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.
+     *
+     * This way, all multiplications take the form of a lookup-and-multiply.
+     * The number of lookup-and-multiply operations inside each iteration of
+     * the main loop still depends on the bits of the exponent, but since the
+     * other operations in the loop don't have an easily recognizable memory
+     * trace, an adversary is unlikely to be able to observe the exact
+     * patterns.
+     *
+     * An adversary may still be able to recover the exponent if they can
+     * 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!
      */
-    MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
+    MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[x_index], j ) );
     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[1],  j ) );
     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T, j * 2 ) );
 
@@ -1684,28 +1724,36 @@
     mpi_montmul( &W[1], &RR, N, mm, &T );
 
     /*
-     * X = R^2 * R^-1 mod N = R mod N
+     * W[x_index] = R^2 * R^-1 mod N = R mod N
      */
-    MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &RR ) );
-    mpi_montred( X, N, mm, &T );
+    MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[x_index], &RR ) );
+    mpi_montred( &W[x_index], N, mm, &T );
 
-    if( wsize > 1 )
+
+    if( window_bitsize > 1 )
     {
         /*
-         * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1)
+         * W[i] = W[1] ^ i
+         *
+         * The first bit of the sliding window is always 1 and therefore we
+         * only need to store the second half of the table.
+         *
+         * (There are two special elements in the table: W[0] for the
+         * accumulator/result and W[1] for A in Montgomery form. Both of these
+         * are already set at this point.)
          */
-        j =  one << ( wsize - 1 );
+        j = w_table_used_size / 2;
 
         MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[j], N->n + 1 ) );
         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[j], &W[1]    ) );
 
-        for( i = 0; i < wsize - 1; i++ )
+        for( i = 0; i < window_bitsize - 1; i++ )
             mpi_montmul( &W[j], &W[j], N, mm, &T );
 
         /*
          * W[i] = W[i - 1] * W[1]
          */
-        for( i = j + 1; i < ( one << wsize ); i++ )
+        for( i = j + 1; i < w_table_used_size; i++ )
         {
             MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[i], N->n + 1 ) );
             MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[i], &W[i - 1] ) );
@@ -1717,7 +1765,7 @@
     nblimbs = E->n;
     bufsize = 0;
     nbits   = 0;
-    wbits   = 0;
+    size_t exponent_bits_in_window = 0;
     state   = 0;
 
     while( 1 )
@@ -1745,9 +1793,10 @@
         if( ei == 0 && state == 1 )
         {
             /*
-             * out of window, square X
+             * out of window, square W[x_index]
              */
-            mpi_montmul( X, X, N, mm, &T );
+            MBEDTLS_MPI_CHK( mpi_select( &WW, W, w_table_used_size, x_index ) );
+            mpi_montmul( &W[x_index], &WW, N, mm, &T );
             continue;
         }
 
@@ -1757,25 +1806,30 @@
         state = 2;
 
         nbits++;
-        wbits |= ( ei << ( wsize - nbits ) );
+        exponent_bits_in_window |= ( ei << ( window_bitsize - nbits ) );
 
-        if( nbits == wsize )
+        if( nbits == window_bitsize )
         {
             /*
-             * X = X^wsize R^-1 mod N
+             * W[x_index] = W[x_index]^window_bitsize R^-1 mod N
              */
-            for( i = 0; i < wsize; i++ )
-                mpi_montmul( X, X, N, mm, &T );
+            for( i = 0; i < window_bitsize; i++ )
+            {
+                MBEDTLS_MPI_CHK( mpi_select( &WW, W, w_table_used_size,
+                                             x_index ) );
+                mpi_montmul( &W[x_index], &WW, N, mm, &T );
+            }
 
             /*
-             * X = X * W[wbits] R^-1 mod N
+             * W[x_index] = W[x_index] * W[exponent_bits_in_window] R^-1 mod N
              */
-            MBEDTLS_MPI_CHK( mpi_select( &WW, W, (size_t) 1 << wsize, wbits ) );
-            mpi_montmul( X, &WW, N, mm, &T );
+            MBEDTLS_MPI_CHK( mpi_select( &WW, W, w_table_used_size,
+                                         exponent_bits_in_window ) );
+            mpi_montmul( &W[x_index], &WW, N, mm, &T );
 
             state--;
             nbits = 0;
-            wbits = 0;
+            exponent_bits_in_window = 0;
         }
     }
 
@@ -1784,31 +1838,45 @@
      */
     for( i = 0; i < nbits; i++ )
     {
-        mpi_montmul( X, X, N, mm, &T );
+        MBEDTLS_MPI_CHK( mpi_select( &WW, W, w_table_used_size, x_index ) );
+        mpi_montmul( &W[x_index], &WW, N, mm, &T );
 
-        wbits <<= 1;
+        exponent_bits_in_window <<= 1;
 
-        if( ( wbits & ( one << wsize ) ) != 0 )
-            mpi_montmul( X, &W[1], N, mm, &T );
+        if( ( exponent_bits_in_window & ( (size_t) 1 << window_bitsize ) ) != 0 )
+        {
+            MBEDTLS_MPI_CHK( mpi_select( &WW, W, w_table_used_size, 1 ) );
+            mpi_montmul( &W[x_index], &WW, N, mm, &T );
+        }
     }
 
     /*
-     * X = A^E * R * R^-1 mod N = A^E mod N
+     * W[x_index] = A^E * R * R^-1 mod N = A^E mod N
      */
-    mpi_montred( X, N, mm, &T );
+    mpi_montred( &W[x_index], N, mm, &T );
 
     if( neg && E->n != 0 && ( E->p[0] & 1 ) != 0 )
     {
-        X->s = -1;
-        MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( X, N, X ) );
+        W[x_index].s = -1;
+        MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &W[x_index], N, &W[x_index] ) );
     }
 
+    /*
+     * Load the result in the output variable.
+     */
+    mbedtls_mpi_copy( X, &W[x_index] );
+
 cleanup:
 
-    for( i = ( one << ( wsize - 1 ) ); i < ( one << wsize ); i++ )
+    /* The first bit of the sliding window is always 1 and therefore the first
+     * half of the table was unused. */
+    for( i = w_table_used_size/2; i < w_table_used_size; i++ )
         mbedtls_mpi_free( &W[i] );
 
-    mbedtls_mpi_free( &W[1] ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &Apos );
+    mbedtls_mpi_free( &W[x_index] );
+    mbedtls_mpi_free( &W[1] );
+    mbedtls_mpi_free( &T );
+    mbedtls_mpi_free( &Apos );
     mbedtls_mpi_free( &WW );
 
     if( prec_RR == NULL || prec_RR->p == NULL )
@@ -1964,75 +2032,19 @@
                         int (*f_rng)(void *, unsigned char *, size_t),
                         void *p_rng )
 {
-    int ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
-    int count;
-    unsigned lt_lower = 1, lt_upper = 0;
-    size_t n_bits = mbedtls_mpi_bitlen( N );
-    size_t n_bytes = ( n_bits + 7 ) / 8;
-    mbedtls_mpi lower_bound;
-
     if( min < 0 )
         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
     if( mbedtls_mpi_cmp_int( N, min ) <= 0 )
         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
 
-    /*
-     * When min == 0, each try has at worst a probability 1/2 of failing
-     * (the msb has a probability 1/2 of being 0, and then the result will
-     * be < N), so after 30 tries failure probability is a most 2**(-30).
-     *
-     * When N is just below a power of 2, as is the case when generating
-     * a random scalar on most elliptic curves, 1 try is enough with
-     * overwhelming probability. When N is just above a power of 2,
-     * as when generating a random scalar on secp224k1, each try has
-     * a probability of failing that is almost 1/2.
-     *
-     * The probabilities are almost the same if min is nonzero but negligible
-     * compared to N. This is always the case when N is crypto-sized, but
-     * it's convenient to support small N for testing purposes. When N
-     * is small, use a higher repeat count, otherwise the probability of
-     * failure is macroscopic.
-     */
-    count = ( n_bytes > 4 ? 30 : 250 );
-
-    mbedtls_mpi_init( &lower_bound );
-
     /* Ensure that target MPI has exactly the same number of limbs
      * as the upper bound, even if the upper bound has leading zeros.
-     * This is necessary for the mbedtls_mpi_lt_mpi_ct() check. */
-    MBEDTLS_MPI_CHK( mbedtls_mpi_resize_clear( X, N->n ) );
-    MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &lower_bound, N->n ) );
-    MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &lower_bound, min ) );
+     * This is necessary for mbedtls_mpi_core_random. */
+    int ret = mbedtls_mpi_resize_clear( X, N->n );
+    if( ret != 0 )
+        return( ret );
 
-    /*
-     * Match the procedure given in RFC 6979 §3.3 (deterministic ECDSA)
-     * when f_rng is a suitably parametrized instance of HMAC_DRBG:
-     * - use the same byte ordering;
-     * - keep the leftmost n_bits bits of the generated octet string;
-     * - try until result is in the desired range.
-     * This also avoids any bias, which is especially important for ECDSA.
-     */
-    do
-    {
-        MBEDTLS_MPI_CHK( mbedtls_mpi_core_fill_random( X->p, X->n,
-                                                       n_bytes,
-                                                       f_rng, p_rng ) );
-        MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( X, 8 * n_bytes - n_bits ) );
-
-        if( --count == 0 )
-        {
-            ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
-            goto cleanup;
-        }
-
-        MBEDTLS_MPI_CHK( mbedtls_mpi_lt_mpi_ct( X, &lower_bound, &lt_lower ) );
-        MBEDTLS_MPI_CHK( mbedtls_mpi_lt_mpi_ct( X, N, &lt_upper ) );
-    }
-    while( lt_lower != 0 || lt_upper == 0 );
-
-cleanup:
-    mbedtls_mpi_free( &lower_bound );
-    return( ret );
+    return( mbedtls_mpi_core_random( X->p, min, N->p, X->n, f_rng, p_rng ) );
 }
 
 /*
diff --git a/library/bignum_core.c b/library/bignum_core.c
index 34aecda..bda62f2 100644
--- a/library/bignum_core.c
+++ b/library/bignum_core.c
@@ -83,45 +83,25 @@
 
 static mbedtls_mpi_uint mpi_bigendian_to_host( mbedtls_mpi_uint a )
 {
-#if defined(__BYTE_ORDER__)
-
-/* Nothing to do on bigendian systems. */
-#if ( __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ )
-    return( a );
-#endif /* __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ */
-
-#if ( __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ )
-
-/* For GCC and Clang, have builtins for byte swapping. */
-#if defined(__GNUC__) && defined(__GNUC_PREREQ)
-#if __GNUC_PREREQ(4,3)
-#define have_bswap
-#endif
-#endif
-
-#if defined(__clang__) && defined(__has_builtin)
-#if __has_builtin(__builtin_bswap32)  &&                 \
-    __has_builtin(__builtin_bswap64)
-#define have_bswap
-#endif
-#endif
-
-#if defined(have_bswap)
-    /* The compiler is hopefully able to statically evaluate this! */
-    switch( sizeof(mbedtls_mpi_uint) )
+    if ( MBEDTLS_IS_BIG_ENDIAN )
     {
-        case 4:
-            return( __builtin_bswap32(a) );
-        case 8:
-            return( __builtin_bswap64(a) );
+        /* Nothing to do on bigendian systems. */
+        return( a );
     }
-#endif
-#endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */
-#endif /* __BYTE_ORDER__ */
+    else
+    {
+        switch( sizeof(mbedtls_mpi_uint) )
+        {
+            case 4:
+                return (mbedtls_mpi_uint) MBEDTLS_BSWAP32( (uint32_t)a );
+            case 8:
+                return (mbedtls_mpi_uint) MBEDTLS_BSWAP64( (uint64_t)a );
+        }
 
-    /* Fall back to C-based reordering if we don't know the byte order
-     * or we couldn't use a compiler-specific builtin. */
-    return( mpi_bigendian_to_host_c( a ) );
+        /* Fall back to C-based reordering if we don't know the byte order
+        * or we couldn't use a compiler-specific builtin. */
+        return( mpi_bigendian_to_host_c( a ) );
+    }
 }
 
 void mbedtls_mpi_core_bigendian_to_host( mbedtls_mpi_uint *A,
@@ -154,6 +134,27 @@
     }
 }
 
+/* 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 )
+{
+    /* min <= least significant limb? */
+    unsigned min_le_lsl = 1 ^ mbedtls_ct_mpi_uint_lt( A[0], min );
+
+    /* limbs other than the least significant one are all zero? */
+    mbedtls_mpi_uint msll_mask = 0;
+    for( size_t i = 1; i < A_limbs; i++ )
+        msll_mask |= 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 );
+}
+
 void mbedtls_mpi_core_cond_assign( mbedtls_mpi_uint *X,
                                    const mbedtls_mpi_uint *A,
                                    size_t limbs,
@@ -540,6 +541,7 @@
     return( ret );
 }
 
+MBEDTLS_STATIC_TESTABLE
 void mbedtls_mpi_core_ct_uint_table_lookup( mbedtls_mpi_uint *dest,
                                             const mbedtls_mpi_uint *table,
                                             size_t limbs,
@@ -580,8 +582,224 @@
     return( ret );
 }
 
+int mbedtls_mpi_core_random( mbedtls_mpi_uint *X,
+                             mbedtls_mpi_uint min,
+                             const mbedtls_mpi_uint *N,
+                             size_t limbs,
+                             int (*f_rng)(void *, unsigned char *, size_t),
+                             void *p_rng )
+{
+    unsigned ge_lower = 1, lt_upper = 0;
+    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;
+
+    /*
+     * When min == 0, each try has at worst a probability 1/2 of failing
+     * (the msb has a probability 1/2 of being 0, and then the result will
+     * be < N), so after 30 tries failure probability is a most 2**(-30).
+     *
+     * When N is just below a power of 2, as is the case when generating
+     * a random scalar on most elliptic curves, 1 try is enough with
+     * overwhelming probability. When N is just above a power of 2,
+     * as when generating a random scalar on secp224k1, each try has
+     * a probability of failing that is almost 1/2.
+     *
+     * The probabilities are almost the same if min is nonzero but negligible
+     * compared to N. This is always the case when N is crypto-sized, but
+     * it's convenient to support small N for testing purposes. When N
+     * is small, use a higher repeat count, otherwise the probability of
+     * failure is macroscopic.
+     */
+    int count = ( n_bytes > 4 ? 30 : 250 );
+
+    /*
+     * Match the procedure given in RFC 6979 §3.3 (deterministic ECDSA)
+     * when f_rng is a suitably parametrized instance of HMAC_DRBG:
+     * - use the same byte ordering;
+     * - keep the leftmost n_bits bits of the generated octet string;
+     * - try until result is in the desired range.
+     * This also avoids any bias, which is especially important for ECDSA.
+     */
+    do
+    {
+        MBEDTLS_MPI_CHK( mbedtls_mpi_core_fill_random( X, limbs,
+                                                       n_bytes,
+                                                       f_rng, p_rng ) );
+        mbedtls_mpi_core_shift_r( X, limbs, 8 * n_bytes - n_bits );
+
+        if( --count == 0 )
+        {
+            ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
+            goto cleanup;
+        }
+
+        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 );
+
+cleanup:
+    return( ret );
+}
+
 /* BEGIN MERGE SLOT 1 */
 
+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;
+#endif
+
+    return( wsize );
+}
+
+size_t mbedtls_mpi_core_exp_mod_working_limbs( size_t AN_limbs, size_t E_limbs )
+{
+    const size_t wsize = exp_mod_get_window_size( E_limbs * biL );
+    const size_t welem = ( (size_t) 1 ) << wsize;
+
+    /* How big does each part of the working memory pool need to be? */
+    const size_t table_limbs   = welem * AN_limbs;
+    const size_t select_limbs  = AN_limbs;
+    const size_t temp_limbs    = 2 * AN_limbs + 1;
+
+    return( table_limbs + select_limbs + temp_limbs );
+}
+
+static void exp_mod_precompute_window( const mbedtls_mpi_uint *A,
+                                       const mbedtls_mpi_uint *N,
+                                       size_t AN_limbs,
+                                       mbedtls_mpi_uint mm,
+                                       const mbedtls_mpi_uint *RR,
+                                       size_t welem,
+                                       mbedtls_mpi_uint *Wtable,
+                                       mbedtls_mpi_uint *temp )
+{
+    /* W[0] = 1 (in Montgomery presentation) */
+    memset( Wtable, 0, AN_limbs * ciL );
+    Wtable[0] = 1;
+    mbedtls_mpi_core_montmul( Wtable, Wtable, RR, AN_limbs, N, AN_limbs, mm, temp );
+
+    /* W[1] = A (already in Montgomery presentation) */
+    mbedtls_mpi_uint *W1 = Wtable + AN_limbs;
+    memcpy( W1, A, AN_limbs * ciL );
+
+    /* W[i+1] = W[i] * W[1], i >= 2 */
+    mbedtls_mpi_uint *Wprev = W1;
+    for( size_t i = 2; i < welem; i++ )
+    {
+        mbedtls_mpi_uint *Wcur = Wprev + AN_limbs;
+        mbedtls_mpi_core_montmul( Wcur, Wprev, W1, AN_limbs, N, AN_limbs, mm, temp );
+        Wprev = Wcur;
+    }
+}
+
+/* Exponentiation: X := A^E mod N.
+ *
+ * A must already be in Montgomery form.
+ *
+ * As in other bignum functions, assume that AN_limbs and E_limbs are nonzero.
+ *
+ * RR must contain 2^{2*biL} mod N.
+ *
+ * The algorithm is a variant of Left-to-right k-ary exponentiation: HAC 14.82
+ * (The difference is that the body in our loop processes a single bit instead
+ * of a full window.)
+ */
+void mbedtls_mpi_core_exp_mod( mbedtls_mpi_uint *X,
+                               const mbedtls_mpi_uint *A,
+                               const mbedtls_mpi_uint *N,
+                               size_t AN_limbs,
+                               const mbedtls_mpi_uint *E,
+                               size_t E_limbs,
+                               const mbedtls_mpi_uint *RR,
+                               mbedtls_mpi_uint *T )
+{
+    const size_t wsize = exp_mod_get_window_size( E_limbs * biL );
+    const size_t welem = ( (size_t) 1 ) << wsize;
+
+    /* This is how we will use the temporary storage T, which must have space
+     * for table_limbs, select_limbs and (2 * AN_limbs + 1) for montmul. */
+    const size_t table_limbs  = welem * AN_limbs;
+    const size_t select_limbs = AN_limbs;
+
+    /* Pointers to specific parts of the temporary working memory pool */
+    mbedtls_mpi_uint *const Wtable  = T;
+    mbedtls_mpi_uint *const Wselect = Wtable  +  table_limbs;
+    mbedtls_mpi_uint *const temp    = Wselect + select_limbs;
+
+    /*
+     * Window precomputation
+     */
+
+    const mbedtls_mpi_uint mm = mbedtls_mpi_core_montmul_init( N );
+
+    /* Set Wtable[i] = A^(2^i) (in Montgomery representation) */
+    exp_mod_precompute_window( A, N, AN_limbs,
+                               mm, RR,
+                               welem, Wtable, temp );
+
+    /*
+     * Fixed window exponentiation
+     */
+
+    /* X = 1 (in Montgomery presentation) initially */
+    memcpy( X, Wtable, AN_limbs * ciL );
+
+    /* We'll process the bits of E from most significant
+     * (limb_index=E_limbs-1, E_bit_index=biL-1) to least significant
+     * (limb_index=0, E_bit_index=0). */
+    size_t E_limb_index = E_limbs;
+    size_t E_bit_index = 0;
+    /* At any given time, window contains window_bits bits from E.
+     * window_bits can go up to wsize. */
+    size_t window_bits = 0;
+    mbedtls_mpi_uint window = 0;
+
+    do
+    {
+        /* Square */
+        mbedtls_mpi_core_montmul( X, X, X, AN_limbs, N, AN_limbs, mm, temp );
+
+        /* Move to the next bit of the exponent */
+        if( E_bit_index == 0 )
+        {
+            --E_limb_index;
+            E_bit_index = biL - 1;
+        }
+        else
+        {
+            --E_bit_index;
+        }
+        /* Insert next exponent bit into window */
+        ++window_bits;
+        window <<= 1;
+        window |= ( E[E_limb_index] >> E_bit_index ) & 1;
+
+        /* Clear window if it's full. Also clear the window at the end,
+         * when we've finished processing the exponent. */
+        if( window_bits == wsize ||
+            ( E_bit_index == 0 && E_limb_index == 0 ) )
+        {
+            /* Select Wtable[window] without leaking window through
+             * memory access patterns. */
+            mbedtls_mpi_core_ct_uint_table_lookup( Wselect, Wtable,
+                                                   AN_limbs, welem, window );
+            /* Multiply X by the selected element. */
+            mbedtls_mpi_core_montmul( X, X, Wselect, AN_limbs, N, AN_limbs, mm,
+                                      temp );
+            window = 0;
+            window_bits = 0;
+        }
+    }
+    while( ! ( E_bit_index == 0 && E_limb_index == 0 ) );
+}
+
 /* END MERGE SLOT 1 */
 
 /* BEGIN MERGE SLOT 2 */
@@ -590,6 +808,56 @@
 
 /* BEGIN MERGE SLOT 3 */
 
+mbedtls_mpi_uint mbedtls_mpi_core_sub_int( mbedtls_mpi_uint *X,
+                                           const mbedtls_mpi_uint *A,
+                                           mbedtls_mpi_uint c, /* doubles as carry */
+                                           size_t limbs )
+{
+    for( size_t i = 0; i < limbs; i++ )
+    {
+        mbedtls_mpi_uint s = A[i];
+        mbedtls_mpi_uint t = s - c;
+        c = ( t > s );
+        X[i] = t;
+    }
+
+    return( c );
+}
+
+mbedtls_mpi_uint mbedtls_mpi_core_check_zero_ct( const mbedtls_mpi_uint *A,
+                                                 size_t limbs )
+{
+    mbedtls_mpi_uint bits = 0;
+
+    for( size_t i = 0; i < limbs; i++ )
+        bits |= A[i];
+
+    return( bits );
+}
+
+void mbedtls_mpi_core_to_mont_rep( mbedtls_mpi_uint *X,
+                                   const mbedtls_mpi_uint *A,
+                                   const mbedtls_mpi_uint *N,
+                                   size_t AN_limbs,
+                                   mbedtls_mpi_uint mm,
+                                   const mbedtls_mpi_uint *rr,
+                                   mbedtls_mpi_uint *T )
+{
+    mbedtls_mpi_core_montmul( X, A, rr, AN_limbs, N, AN_limbs, mm, T );
+}
+
+void mbedtls_mpi_core_from_mont_rep( mbedtls_mpi_uint *X,
+                                     const mbedtls_mpi_uint *A,
+                                     const mbedtls_mpi_uint *N,
+                                     size_t AN_limbs,
+                                     mbedtls_mpi_uint mm,
+                                     mbedtls_mpi_uint *T )
+{
+    const mbedtls_mpi_uint Rinv = 1;    /* 1/R in Mont. rep => 1 */
+
+    mbedtls_mpi_core_montmul( X, A, &Rinv, 1, N, AN_limbs, mm, T );
+}
+
 /* END MERGE SLOT 3 */
 
 /* BEGIN MERGE SLOT 4 */
diff --git a/library/bignum_core.h b/library/bignum_core.h
index ad04e08..771f208 100644
--- a/library/bignum_core.h
+++ b/library/bignum_core.h
@@ -129,6 +129,22 @@
 void mbedtls_mpi_core_bigendian_to_host( mbedtls_mpi_uint *A,
                                          size_t A_limbs );
 
+/** \brief         Compare a machine integer with an MPI.
+ *
+ *                 This function operates in constant time with respect
+ *                 to the values of \p min and \p A.
+ *
+ * \param min      A machine integer.
+ * \param[in] A    An MPI.
+ * \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.
+ */
+unsigned mbedtls_mpi_core_uint_le_mpi( mbedtls_mpi_uint min,
+                                       const mbedtls_mpi_uint *A,
+                                       size_t A_limbs );
+
 /**
  * \brief   Perform a safe conditional copy of an MPI which doesn't reveal
  *          whether assignment was done or not.
@@ -452,6 +468,7 @@
 int mbedtls_mpi_core_get_mont_r2_unsafe( mbedtls_mpi *X,
                                          const mbedtls_mpi *N );
 
+#if defined(MBEDTLS_TEST_HOOKS)
 /**
  * Copy an MPI from a table without leaking the index.
  *
@@ -469,6 +486,7 @@
                                             size_t limbs,
                                             size_t count,
                                             size_t index );
+#endif /* MBEDTLS_TEST_HOOKS */
 
 /**
  * \brief          Fill an integer with a number of random bytes.
@@ -494,8 +512,98 @@
                                   int (*f_rng)(void *, unsigned char *, size_t),
                                   void *p_rng );
 
+/** Generate a random number uniformly in a range.
+ *
+ * This function generates a random number between \p min inclusive and
+ * \p N exclusive.
+ *
+ * The procedure complies with RFC 6979 §3.3 (deterministic ECDSA)
+ * when the RNG is a suitably parametrized instance of HMAC_DRBG
+ * and \p min is \c 1.
+ *
+ * \note           There are `N - min` possible outputs. The lower bound
+ *                 \p min can be reached, but the upper bound \p N cannot.
+ *
+ * \param X        The destination MPI, with \p limbs limbs.
+ *                 It must not be aliased with \p N or otherwise overlap it.
+ * \param min      The minimum value to return.
+ * \param N        The upper bound of the range, exclusive, with \p limbs limbs.
+ *                 In other words, this is one plus the maximum value to return.
+ *                 \p N must be strictly larger than \p min.
+ * \param limbs    The number of limbs of \p N and \p X.
+ *                 This must not be 0.
+ * \param f_rng    The RNG function to use. This must not be \c NULL.
+ * \param p_rng    The RNG parameter to be passed to \p f_rng.
+ *
+ * \return         \c 0 if successful.
+ * \return         #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if the implementation was
+ *                 unable to find a suitable value within a limited number
+ *                 of attempts. This has a negligible probability if \p N
+ *                 is significantly larger than \p min, which is the case
+ *                 for all usual cryptographic applications.
+ */
+int mbedtls_mpi_core_random( mbedtls_mpi_uint *X,
+                             mbedtls_mpi_uint min,
+                             const mbedtls_mpi_uint *N,
+                             size_t limbs,
+                             int (*f_rng)(void *, unsigned char *, size_t),
+                             void *p_rng );
+
 /* BEGIN MERGE SLOT 1 */
 
+/**
+ * \brief          Returns the number of limbs of working memory required for
+ *                 a call to `mbedtls_mpi_core_exp_mod()`.
+ *
+ * \note           This will always be at least
+ *                 `mbedtls_mpi_core_montmul_working_limbs(AN_limbs)`,
+ *                 i.e. sufficient for a call to `mbedtls_mpi_core_montmul()`.
+ *
+ * \param AN_limbs The number of limbs in the input `A` and the modulus `N`
+ *                 (they must be the same size) that will be given to
+ *                 `mbedtls_mpi_core_exp_mod()`.
+ * \param E_limbs  The number of limbs in the exponent `E` that will be given
+ *                 to `mbedtls_mpi_core_exp_mod()`.
+ *
+ * \return         The number of limbs of working memory required by
+ *                 `mbedtls_mpi_core_exp_mod()`.
+ */
+size_t mbedtls_mpi_core_exp_mod_working_limbs( size_t AN_limbs, size_t E_limbs );
+
+/**
+ * \brief            Perform a modular exponentiation with secret exponent:
+ *                   X = A^E mod N, where \p A is already in Montgomery form.
+ *
+ * \p X may be aliased to \p A, but not to \p RR or \p E, even if \p E_limbs ==
+ * \p AN_limbs.
+ *
+ * \param[out] X     The destination MPI, as a little endian array of length
+ *                   \p AN_limbs.
+ * \param[in] A      The base MPI, as a little endian array of length \p AN_limbs.
+ *                   Must be in Montgomery form.
+ * \param[in] N      The modulus, as a little endian array of length \p AN_limbs.
+ * \param AN_limbs   The number of limbs in \p X, \p A, \p N, \p RR.
+ * \param[in] E      The exponent, as a little endian array of length \p E_limbs.
+ * \param E_limbs    The number of limbs in \p E.
+ * \param[in] RR     The precomputed residue of 2^{2*biL} modulo N, as a little
+ *                   endian array of length \p AN_limbs.
+ * \param[in,out] T  Temporary storage of at least the number of limbs returned
+ *                   by `mbedtls_mpi_core_exp_mod_working_limbs()`.
+ *                   Its initial content is unused and its final content is
+ *                   indeterminate.
+ *                   It must not alias or otherwise overlap any of the other
+ *                   parameters.
+ *                   It is up to the caller to zeroize \p T when it is no
+ *                   longer needed, and before freeing it if it was dynamically
+ *                   allocated.
+ */
+void mbedtls_mpi_core_exp_mod( mbedtls_mpi_uint *X,
+                               const mbedtls_mpi_uint *A,
+                               const mbedtls_mpi_uint *N, size_t AN_limbs,
+                               const mbedtls_mpi_uint *E, size_t E_limbs,
+                               const mbedtls_mpi_uint *RR,
+                               mbedtls_mpi_uint *T );
+
 /* END MERGE SLOT 1 */
 
 /* BEGIN MERGE SLOT 2 */
@@ -504,6 +612,128 @@
 
 /* BEGIN MERGE SLOT 3 */
 
+/**
+ * \brief Subtract unsigned integer from known-size large unsigned integers.
+ *        Return the borrow.
+ *
+ * \param[out] X    The result of the subtraction.
+ * \param[in] A     The left operand.
+ * \param b         The unsigned scalar to subtract.
+ * \param limbs     Number of limbs of \p X and \p A.
+ *
+ * \return          1 if `A < b`.
+ *                  0 if `A >= b`.
+ */
+mbedtls_mpi_uint mbedtls_mpi_core_sub_int( mbedtls_mpi_uint *X,
+                                           const mbedtls_mpi_uint *A,
+                                           mbedtls_mpi_uint b,
+                                           size_t limbs );
+
+/**
+ * \brief Determine if a given MPI has the value \c 0 in constant time with
+ *        respect to the value (but not with respect to the number of limbs).
+ *
+ * \param[in] A   The MPI to test.
+ * \param limbs   Number of limbs in \p A.
+ *
+ * \return        0 if `A == 0`
+ *                non-0 (may be any value) if `A != 0`.
+ */
+mbedtls_mpi_uint mbedtls_mpi_core_check_zero_ct( const mbedtls_mpi_uint *A,
+                                                 size_t limbs );
+
+/**
+ * \brief          Returns the number of limbs of working memory required for
+ *                 a call to `mbedtls_mpi_core_montmul()`.
+ *
+ * \param AN_limbs The number of limbs in the input `A` and the modulus `N`
+ *                 (they must be the same size) that will be given to
+ *                 `mbedtls_mpi_core_montmul()` or one of the other functions
+ *                 that specifies this as the amount of working memory needed.
+ *
+ * \return         The number of limbs of working memory required by
+ *                 `mbedtls_mpi_core_montmul()` (or other similar function).
+ */
+static inline size_t mbedtls_mpi_core_montmul_working_limbs( size_t AN_limbs )
+{
+    return( 2 * AN_limbs + 1 );
+}
+
+/** Convert an MPI into Montgomery form.
+ *
+ * \p X may be aliased to \p A, but may not otherwise overlap it.
+ *
+ * \p X may not alias \p N (it is in canonical form, so must be stricly less
+ * than \p N). Nor may it alias or overlap \p rr (this is unlikely to be
+ * required in practice.)
+ *
+ * This function is a thin wrapper around `mbedtls_mpi_core_montmul()` that is
+ * an alternative to calling `mbedtls_mpi_mod_raw_to_mont_rep()` when we
+ * don't want to allocate memory.
+ *
+ * \param[out]    X         The result of the conversion.
+ *                          Must have the same number of limbs as \p A.
+ * \param[in]     A         The MPI to convert into Montgomery form.
+ *                          Must have the same number of limbs as the modulus.
+ * \param[in]     N         The address of the modulus, which gives the size of
+ *                          the base `R` = 2^(biL*N->limbs).
+ * \param[in]     AN_limbs  The number of limbs in \p X, \p A, \p N and \p rr.
+ * \param         mm        The Montgomery constant for \p N: -N^-1 mod 2^biL.
+ *                          This can be determined by calling
+ *                          `mbedtls_mpi_core_montmul_init()`.
+ * \param[in]     rr        The residue for `2^{2*n*biL} mod N`.
+ * \param[in,out] T         Temporary storage of size at least
+ *                          `mbedtls_mpi_core_montmul_working_limbs(AN_limbs)`
+ *                          limbs.
+ *                          Its initial content is unused and
+ *                          its final content is indeterminate.
+ *                          It must not alias or otherwise overlap any of the
+ *                          other parameters.
+ */
+void mbedtls_mpi_core_to_mont_rep( mbedtls_mpi_uint *X,
+                                   const mbedtls_mpi_uint *A,
+                                   const mbedtls_mpi_uint *N,
+                                   size_t AN_limbs,
+                                   mbedtls_mpi_uint mm,
+                                   const mbedtls_mpi_uint *rr,
+                                   mbedtls_mpi_uint *T );
+
+/** Convert an MPI from Montgomery form.
+ *
+ * \p X may be aliased to \p A, but may not otherwise overlap it.
+ *
+ * \p X may not alias \p N (it is in canonical form, so must be stricly less
+ * than \p N).
+ *
+ * This function is a thin wrapper around `mbedtls_mpi_core_montmul()` that is
+ * an alternative to calling `mbedtls_mpi_mod_raw_from_mont_rep()` when we
+ * don't want to allocate memory.
+ *
+ * \param[out]    X         The result of the conversion.
+ *                          Must have the same number of limbs as \p A.
+ * \param[in]     A         The MPI to convert from Montgomery form.
+ *                          Must have the same number of limbs as the modulus.
+ * \param[in]     N         The address of the modulus, which gives the size of
+ *                          the base `R` = 2^(biL*N->limbs).
+ * \param[in]     AN_limbs  The number of limbs in \p X, \p A and \p N.
+ * \param         mm        The Montgomery constant for \p N: -N^-1 mod 2^biL.
+ *                          This can be determined by calling
+ *                          `mbedtls_mpi_core_montmul_init()`.
+ * \param[in,out] T         Temporary storage of size at least
+ *                          `mbedtls_mpi_core_montmul_working_limbs(AN_limbs)`
+ *                          limbs.
+ *                          Its initial content is unused and
+ *                          its final content is indeterminate.
+ *                          It must not alias or otherwise overlap any of the
+ *                          other parameters.
+ */
+void mbedtls_mpi_core_from_mont_rep( mbedtls_mpi_uint *X,
+                                     const mbedtls_mpi_uint *A,
+                                     const mbedtls_mpi_uint *N,
+                                     size_t AN_limbs,
+                                     mbedtls_mpi_uint mm,
+                                     mbedtls_mpi_uint *T );
+
 /* END MERGE SLOT 3 */
 
 /* BEGIN MERGE SLOT 4 */
diff --git a/library/bignum_mod.c b/library/bignum_mod.c
index 13108c5..bd67241 100644
--- a/library/bignum_mod.c
+++ b/library/bignum_mod.c
@@ -39,7 +39,7 @@
                                    mbedtls_mpi_uint *p,
                                    size_t p_limbs )
 {
-    if( p_limbs < m->limbs || !mbedtls_mpi_core_lt_ct( m->p, p, p_limbs ) )
+    if( p_limbs != m->limbs || !mbedtls_mpi_core_lt_ct( p, m->p, m->limbs ) )
         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
 
     r->limbs = m->limbs;
@@ -50,7 +50,7 @@
 
 void mbedtls_mpi_mod_residue_release( mbedtls_mpi_mod_residue *r )
 {
-    if ( r == NULL )
+    if( r == NULL )
         return;
 
     r->limbs = 0;
@@ -59,19 +59,18 @@
 
 void mbedtls_mpi_mod_modulus_init( mbedtls_mpi_mod_modulus *m )
 {
-    if ( m == NULL )
+    if( m == NULL )
         return;
 
     m->p = NULL;
     m->limbs = 0;
     m->bits = 0;
-    m->ext_rep = MBEDTLS_MPI_MOD_EXT_REP_INVALID;
     m->int_rep = MBEDTLS_MPI_MOD_REP_INVALID;
 }
 
 void mbedtls_mpi_mod_modulus_free( mbedtls_mpi_mod_modulus *m )
 {
-    if ( m == NULL )
+    if( m == NULL )
         return;
 
     switch( m->int_rep )
@@ -80,7 +79,7 @@
             if (m->rep.mont.rr != NULL)
             {
                 mbedtls_platform_zeroize( (mbedtls_mpi_uint *) m->rep.mont.rr,
-                                           m->limbs );
+                                           m->limbs * sizeof(mbedtls_mpi_uint) );
                 mbedtls_free( (mbedtls_mpi_uint *)m->rep.mont.rr );
                 m->rep.mont.rr = NULL;
             }
@@ -96,7 +95,6 @@
     m->p = NULL;
     m->limbs = 0;
     m->bits = 0;
-    m->ext_rep = MBEDTLS_MPI_MOD_EXT_REP_INVALID;
     m->int_rep = MBEDTLS_MPI_MOD_REP_INVALID;
 }
 
@@ -112,17 +110,17 @@
     mbedtls_mpi_init( &N );
     mbedtls_mpi_init( &RR );
 
-    if ( A == NULL || limbs == 0 || limbs >= ( MBEDTLS_MPI_MAX_LIMBS / 2 ) - 2 )
+    if( A == NULL || limbs == 0 || limbs >= ( MBEDTLS_MPI_MAX_LIMBS / 2 ) - 2 )
         goto cleanup;
 
-    if ( mbedtls_mpi_grow( &N, limbs ) )
+    if( mbedtls_mpi_grow( &N, limbs ) )
         goto cleanup;
 
     memcpy( N.p, A, sizeof(mbedtls_mpi_uint) * limbs );
 
     ret = mbedtls_mpi_core_get_mont_r2_unsafe(&RR, &N);
 
-    if ( ret == 0 )
+    if( ret == 0 )
     {
         *X = RR.p;
         RR.p = NULL;
@@ -138,7 +136,6 @@
 int mbedtls_mpi_mod_modulus_setup( mbedtls_mpi_mod_modulus *m,
                                    const mbedtls_mpi_uint *p,
                                    size_t p_limbs,
-                                   mbedtls_mpi_mod_ext_rep ext_rep,
                                    mbedtls_mpi_mod_rep_selector int_rep )
 {
     int ret = 0;
@@ -147,17 +144,6 @@
     m->limbs = p_limbs;
     m->bits = mbedtls_mpi_core_bitlen( p, p_limbs );
 
-    switch( ext_rep )
-    {
-        case MBEDTLS_MPI_MOD_EXT_REP_LE:
-        case MBEDTLS_MPI_MOD_EXT_REP_BE:
-            m->ext_rep = ext_rep;
-            break;
-        default:
-            ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
-            goto exit;
-    }
-
     switch( int_rep )
     {
         case MBEDTLS_MPI_MOD_REP_MONTGOMERY:
@@ -190,10 +176,132 @@
 
 /* BEGIN MERGE SLOT 2 */
 
+int mbedtls_mpi_mod_mul( mbedtls_mpi_mod_residue *X,
+                         const mbedtls_mpi_mod_residue *A,
+                         const mbedtls_mpi_mod_residue *B,
+                         const mbedtls_mpi_mod_modulus *N )
+{
+    if( N->limbs == 0 )
+        return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
+
+    if( X->limbs != N->limbs || A->limbs != N->limbs || B->limbs != N->limbs )
+        return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
+
+    mbedtls_mpi_uint *T = mbedtls_calloc( N->limbs * 2 + 1, ciL );
+    if( T == NULL )
+        return MBEDTLS_ERR_MPI_ALLOC_FAILED;
+
+    mbedtls_mpi_mod_raw_mul( X->p, A->p, B->p, N, T );
+
+    mbedtls_free( T );
+
+    return( 0 );
+}
+
 /* END MERGE SLOT 2 */
 
 /* BEGIN MERGE SLOT 3 */
+int mbedtls_mpi_mod_sub( mbedtls_mpi_mod_residue *X,
+                         const mbedtls_mpi_mod_residue *A,
+                         const mbedtls_mpi_mod_residue *B,
+                         const mbedtls_mpi_mod_modulus *N )
+{
+    if( X->limbs != N->limbs || A->limbs != N->limbs || B->limbs != N->limbs )
+        return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
 
+    mbedtls_mpi_mod_raw_sub( X->p, A->p, B->p, N );
+
+    return( 0 );
+}
+
+static int mbedtls_mpi_mod_inv_mont( mbedtls_mpi_mod_residue *X,
+                                     const mbedtls_mpi_mod_residue *A,
+                                     const mbedtls_mpi_mod_modulus *N,
+                                     mbedtls_mpi_uint *working_memory )
+{
+    /* Input already in Montgomery form, so there's little to do */
+    mbedtls_mpi_mod_raw_inv_prime( X->p, A->p,
+                                   N->p, N->limbs,
+                                   N->rep.mont.rr,
+                                   working_memory );
+    return( 0 );
+}
+
+static int mbedtls_mpi_mod_inv_non_mont( mbedtls_mpi_mod_residue *X,
+                                         const mbedtls_mpi_mod_residue *A,
+                                         const mbedtls_mpi_mod_modulus *N,
+                                         mbedtls_mpi_uint *working_memory )
+{
+    /* Need to convert input into Montgomery form */
+
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+    mbedtls_mpi_mod_modulus Nmont;
+    mbedtls_mpi_mod_modulus_init( &Nmont );
+
+    MBEDTLS_MPI_CHK( mbedtls_mpi_mod_modulus_setup( &Nmont, N->p, N->limbs,
+                                         MBEDTLS_MPI_MOD_REP_MONTGOMERY ) );
+
+    /* We'll use X->p to hold the Montgomery form of the input A->p */
+    mbedtls_mpi_core_to_mont_rep( X->p, A->p, Nmont.p, Nmont.limbs,
+                                  Nmont.rep.mont.mm, Nmont.rep.mont.rr,
+                                  working_memory );
+
+    mbedtls_mpi_mod_raw_inv_prime( X->p, X->p,
+                                   Nmont.p, Nmont.limbs,
+                                   Nmont.rep.mont.rr,
+                                   working_memory );
+
+    /* And convert back from Montgomery form */
+
+    mbedtls_mpi_core_from_mont_rep( X->p, X->p, Nmont.p, Nmont.limbs,
+                                    Nmont.rep.mont.mm, working_memory );
+
+cleanup:
+    mbedtls_mpi_mod_modulus_free( &Nmont );
+    return( ret );
+}
+
+int mbedtls_mpi_mod_inv( mbedtls_mpi_mod_residue *X,
+                         const mbedtls_mpi_mod_residue *A,
+                         const mbedtls_mpi_mod_modulus *N )
+{
+    if( X->limbs != N->limbs || A->limbs != N->limbs )
+        return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+
+    /* Zero has the same value regardless of Montgomery form or not */
+    if( mbedtls_mpi_core_check_zero_ct( A->p, A->limbs ) == 0 )
+        return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+
+    size_t working_limbs =
+                    mbedtls_mpi_mod_raw_inv_prime_working_limbs( N->limbs );
+
+    mbedtls_mpi_uint *working_memory = mbedtls_calloc( working_limbs,
+                                                     sizeof(mbedtls_mpi_uint) );
+    if( working_memory == NULL )
+        return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
+
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+    switch( N->int_rep )
+    {
+        case MBEDTLS_MPI_MOD_REP_MONTGOMERY:
+            ret = mbedtls_mpi_mod_inv_mont( X, A, N, working_memory );
+            break;
+        case MBEDTLS_MPI_MOD_REP_OPT_RED:
+            ret = mbedtls_mpi_mod_inv_non_mont( X, A, N, working_memory );
+            break;
+        default:
+            ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
+            break;
+    }
+
+    mbedtls_platform_zeroize( working_memory,
+                              working_limbs * sizeof(mbedtls_mpi_uint) );
+    mbedtls_free( working_memory );
+
+    return ret;
+}
 /* END MERGE SLOT 3 */
 
 /* BEGIN MERGE SLOT 4 */
@@ -201,15 +309,100 @@
 /* END MERGE SLOT 4 */
 
 /* BEGIN MERGE SLOT 5 */
+int mbedtls_mpi_mod_add( mbedtls_mpi_mod_residue *X,
+                         const mbedtls_mpi_mod_residue *A,
+                         const mbedtls_mpi_mod_residue *B,
+                         const mbedtls_mpi_mod_modulus *N )
+{
+    if( X->limbs != N->limbs || A->limbs != N->limbs || B->limbs != N->limbs )
+        return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
 
+    mbedtls_mpi_mod_raw_add(X->p, A->p, B->p, N);
+
+    return( 0 );
+}
 /* END MERGE SLOT 5 */
 
 /* BEGIN MERGE SLOT 6 */
 
+int mbedtls_mpi_mod_random( mbedtls_mpi_mod_residue *X,
+                            mbedtls_mpi_uint min,
+                            const mbedtls_mpi_mod_modulus *N,
+                            int (*f_rng)(void *, unsigned char *, size_t),
+                            void *p_rng )
+{
+    if( X->limbs != N->limbs )
+        return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+    return( mbedtls_mpi_mod_raw_random( X->p, min, N, f_rng, p_rng ) );
+}
+
 /* END MERGE SLOT 6 */
 
 /* BEGIN MERGE SLOT 7 */
+int mbedtls_mpi_mod_read( mbedtls_mpi_mod_residue *r,
+                          const mbedtls_mpi_mod_modulus *m,
+                          const unsigned char *buf,
+                          size_t buflen,
+                          mbedtls_mpi_mod_ext_rep ext_rep )
+{
+    int ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
 
+    /* Do our best to check if r and m have been set up */
+    if( r->limbs == 0 || m->limbs == 0 )
+        goto cleanup;
+    if( r->limbs != m->limbs )
+        goto cleanup;
+
+    ret = mbedtls_mpi_mod_raw_read( r->p, m, buf, buflen, ext_rep );
+    if( ret != 0 )
+        goto cleanup;
+
+    r->limbs = m->limbs;
+
+    ret = mbedtls_mpi_mod_raw_canonical_to_modulus_rep( r->p, m );
+
+cleanup:
+    return ( ret );
+}
+
+int mbedtls_mpi_mod_write( const mbedtls_mpi_mod_residue *r,
+                           const mbedtls_mpi_mod_modulus *m,
+                           unsigned char *buf,
+                           size_t buflen,
+                           mbedtls_mpi_mod_ext_rep ext_rep )
+{
+    int ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
+
+    /* Do our best to check if r and m have been set up */
+    if( r->limbs == 0 || m->limbs == 0 )
+        goto cleanup;
+    if( r->limbs != m->limbs )
+        goto cleanup;
+
+    if( m->int_rep == MBEDTLS_MPI_MOD_REP_MONTGOMERY )
+    {
+        ret = mbedtls_mpi_mod_raw_from_mont_rep( r->p, m );
+        if( ret != 0 )
+            goto cleanup;
+    }
+
+    ret = mbedtls_mpi_mod_raw_write( r->p, m, buf, buflen, ext_rep );
+
+    if( m->int_rep == MBEDTLS_MPI_MOD_REP_MONTGOMERY )
+    {
+        /* If this fails, the value of r is corrupted and we want to return
+         * this error (as opposed to the error code from the write above) to
+         * let the caller know. If it succeeds, we want to return the error
+         * code from write above. */
+        int conv_ret = mbedtls_mpi_mod_raw_to_mont_rep( r->p, m );
+        if( ret == 0 )
+            ret = conv_ret;
+    }
+
+cleanup:
+
+    return ( ret );
+}
 /* END MERGE SLOT 7 */
 
 /* BEGIN MERGE SLOT 8 */
diff --git a/library/bignum_mod.h b/library/bignum_mod.h
index 29c26f2..1b1e920 100644
--- a/library/bignum_mod.h
+++ b/library/bignum_mod.h
@@ -2,6 +2,63 @@
  *  Modular bignum functions
  *
  * This module implements operations on integers modulo some fixed modulus.
+ *
+ * The functions in this module obey the following conventions unless
+ * explicitly indicated otherwise:
+ *
+ * - **Modulus parameters**: the modulus is passed as a pointer to a structure
+ *   of type #mbedtls_mpi_mod_modulus. The structure must be set up with an
+ *   array of limbs storing the bignum value of the modulus. The modulus must
+ *   be odd and is assumed to have no leading zeroes. The modulus is usually
+ *   named \c N and is usually input-only. Functions which take a parameter
+ *   of type \c const #mbedtls_mpi_mod_modulus* must not modify its value.
+ * - **Bignum parameters**: Bignums are passed as pointers to an array of
+ *   limbs or to a #mbedtls_mpi_mod_residue structure. A limb has the type
+ *   #mbedtls_mpi_uint. Residues must be initialized before use, and must be
+ *   associated with the modulus \c N. Unless otherwise specified:
+ *     - Bignum parameters called \c A, \c B, ... are inputs and are not
+ *       modified by the function. Functions which take a parameter of
+ *       type \c const #mbedtls_mpi_mod_residue* must not modify its value.
+ *     - Bignum parameters called \c X, \c Y, ... are outputs or input-output.
+ *       The initial bignum value of output-only parameters is ignored, but
+ *       they must be set up and associated with the modulus \c N. Some
+ *       functions (typically constant-flow) require that the limbs in an
+ *       output residue are initialized.
+ *     - Bignum parameters called \c p are inputs used to set up a modulus or
+ *       residue. These must be pointers to an array of limbs.
+ *     - \c T is a temporary storage area. The initial content of such a
+ *       parameter is ignored and the final content is unspecified.
+ *     - Some functions use different names, such as \c r for the residue.
+ * - **Bignum sizes**: bignum sizes are always expressed in limbs. Both
+ *   #mbedtls_mpi_mod_modulus and #mbedtls_mpi_mod_residue have a \c limbs
+ *   member storing its size. All bignum parameters must have the same
+ *   number of limbs as the modulus. All bignum sizes must be at least 1 and
+ *   must be significantly less than #SIZE_MAX. The behavior if a size is 0 is
+ *   undefined.
+ * - **Bignum representation**: the representation of inputs and outputs is
+ *   specified by the \c int_rep field of the modulus.
+ * - **Parameter ordering**: for bignum parameters, outputs come before inputs.
+ *   The modulus is passed after residues. Temporaries come last.
+ * - **Aliasing**: in general, output bignums may be aliased to one or more
+ *   inputs. Modulus values may not be aliased to any other parameter. Outputs
+ *   may not be aliased to one another. Temporaries may not be aliased to any
+ *   other parameter.
+ * - **Overlap**: apart from aliasing of residue pointers (where two residue
+ *   arguments are equal pointers), overlap is not supported and may result
+ *   in undefined behavior.
+ * - **Error handling**: functions generally check compatibility of input
+ *   sizes. Most functions will not check that input values are in canonical
+ *   form (i.e. that \c A < \c N), this is only checked during setup of a
+ *   residue structure.
+ * - **Modular representatives**: all functions expect inputs to be in the
+ *   range [0, \c N - 1] and guarantee outputs in the range [0, \c N - 1].
+ *   Residues are set up with an associated modulus, and operations are only
+ *   guaranteed to work if the modulus is associated with all residue
+ *   parameters. If a residue is passed with a modulus other than the one it
+ *   is associated with, then it may be out of range. If an input is out of
+ *   range, outputs are fully unspecified, though bignum values out of range
+ *   should not cause buffer overflows (beware that this is not extensively
+ *   tested).
  */
 
 /*
@@ -30,12 +87,23 @@
 #include "mbedtls/bignum.h"
 #endif
 
-/* Skip 1 as it is slightly easier to accidentally pass to functions. */
+/** How residues associated with a modulus are represented.
+ *
+ * This also determines which fields of the modulus structure are valid and
+ * what their contents are (see #mbedtls_mpi_mod_modulus).
+ */
 typedef enum
 {
+    /** Representation not chosen (makes the modulus structure invalid). */
     MBEDTLS_MPI_MOD_REP_INVALID    = 0,
+    /* Skip 1 as it is slightly easier to accidentally pass to functions. */
+    /** Montgomery representation. */
     MBEDTLS_MPI_MOD_REP_MONTGOMERY = 2,
-    MBEDTLS_MPI_MOD_REP_OPT_RED
+    /** TODO: document this.
+     *
+     * Residues are in canonical representation.
+     */
+    MBEDTLS_MPI_MOD_REP_OPT_RED,
 } mbedtls_mpi_mod_rep_selector;
 
 /* Make mbedtls_mpi_mod_rep_selector and mbedtls_mpi_mod_ext_rep disjoint to
@@ -64,27 +132,39 @@
     const mbedtls_mpi_uint *p;
     size_t limbs;                            // number of limbs
     size_t bits;                             // bitlen of p
-    mbedtls_mpi_mod_ext_rep ext_rep;         // signals external representation (eg. byte order)
     mbedtls_mpi_mod_rep_selector int_rep;    // selector to signal the active member of the union
     union rep
     {
+        /* if int_rep == #MBEDTLS_MPI_MOD_REP_MONTGOMERY */
         mbedtls_mpi_mont_struct mont;
+        /* if int_rep == #MBEDTLS_MPI_MOD_REP_OPT_RED */
         mbedtls_mpi_opt_red_struct ored;
     } rep;
 } mbedtls_mpi_mod_modulus;
 
 /** Setup a residue structure.
  *
- * \param[out] r    The address of residue to setup. The size is determined by
- *                  \p m.
- *                  (In particular, it must have at least as many limbs as the
- *                  modulus \p m.)
+ * The residue will be set up with the buffer \p p and modulus \p m.
+ *
+ * The memory pointed to by \p p will be used by the resulting residue structure.
+ * The value at the pointed-to memory will be the initial value of \p r and must
+ * hold a value that is less than the modulus. This value will be used as-is
+ * and interpreted according to the value of the `m->int_rep` field.
+ *
+ * The modulus \p m will be the modulus associated with \p r. The residue \p r
+ * should only be used in operations where the modulus is \p m.
+ *
+ * \param[out] r    The address of the residue to setup.
  * \param[in] m     The address of the modulus related to \p r.
- * \param[in] p     The address of the limb array storing the value of \p r.
+ * \param[in] p     The address of the limb array containing the value of \p r.
  *                  The memory pointed to by \p p will be used by \p r and must
  *                  not be modified in any way until after
- *                  mbedtls_mpi_mod_residue_release() is called.
- * \param p_limbs   The number of limbs of \p p.
+ *                  mbedtls_mpi_mod_residue_release() is called. The data
+ *                  pointed to by \p p must be less than the modulus (the value
+ *                  pointed to by `m->p`) and already in the representation
+ *                  indicated by `m->int_rep`.
+ * \param p_limbs   The number of limbs of \p p. Must be the same as the number
+ *                  of limbs in the modulus \p m.
  *
  * \return      \c 0 if successful.
  * \return      #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \p p_limbs is less than the
@@ -121,19 +201,15 @@
  *                  not be modified in any way until after
  *                  mbedtls_mpi_mod_modulus_free() is called.
  * \param p_limbs   The number of limbs of \p p.
- * \param ext_rep   The external representation to be used for residues
- *                  associated with \p m (see #mbedtls_mpi_mod_ext_rep).
  * \param int_rep   The internal representation to be used for residues
  *                  associated with \p m (see #mbedtls_mpi_mod_rep_selector).
  *
  * \return      \c 0 if successful.
- * \return      #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \p ext_rep or \p int_rep is
- *              invalid.
+ * \return      #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \p int_rep is invalid.
  */
 int mbedtls_mpi_mod_modulus_setup( mbedtls_mpi_mod_modulus *m,
                                    const mbedtls_mpi_uint *p,
                                    size_t p_limbs,
-                                   mbedtls_mpi_mod_ext_rep ext_rep,
                                    mbedtls_mpi_mod_rep_selector int_rep );
 
 /** Free elements of a modulus structure.
@@ -154,10 +230,101 @@
 
 /* BEGIN MERGE SLOT 2 */
 
+/** \brief  Multiply two residues, returning the residue modulo the specified
+ *          modulus.
+ *
+ * \note Currently handles the case when `N->int_rep` is
+ * MBEDTLS_MPI_MOD_REP_MONTGOMERY.
+ *
+ * The size of the operation is determined by \p N. \p A, \p B and \p X must
+ * all be associated with the modulus \p N and must all have the same number
+ * of limbs as \p N.
+ *
+ * \p X may be aliased to \p A or \p B, or even both, but may not overlap
+ * either otherwise. They may not alias \p N (since they must be in canonical
+ * form, they cannot == \p N).
+ *
+ * \param[out] X        The address of the result MPI. Must have the same
+ *                      number of limbs as \p N.
+ *                      On successful completion, \p X contains the result of
+ *                      the multiplication `A * B * R^-1` mod N where
+ *                      `R = 2^(biL * N->limbs)`.
+ * \param[in]  A        The address of the first MPI.
+ * \param[in]  B        The address of the second MPI.
+ * \param[in]  N        The address of the modulus. Used to perform a modulo
+ *                      operation on the result of the multiplication.
+ *
+ * \return      \c 0 if successful.
+ * \return      #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if all the parameters do not
+ *              have the same number of limbs or \p N is invalid.
+ * \return      #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure.
+ */
+int mbedtls_mpi_mod_mul( mbedtls_mpi_mod_residue *X,
+                         const mbedtls_mpi_mod_residue *A,
+                         const mbedtls_mpi_mod_residue *B,
+                         const mbedtls_mpi_mod_modulus *N );
+
 /* END MERGE SLOT 2 */
 
 /* BEGIN MERGE SLOT 3 */
+/**
+ * \brief Perform a fixed-size modular subtraction.
+ *
+ * Calculate `A - B modulo N`.
+ *
+ * \p A, \p B and \p X must all have the same number of limbs as \p N.
+ *
+ * \p X may be aliased to \p A or \p B, or even both, but may not overlap
+ * either otherwise.
+ *
+ * \note This function does not check that \p A or \p B are in canonical
+ *       form (that is, are < \p N) - that will have been done by
+ *       mbedtls_mpi_mod_residue_setup().
+ *
+ * \param[out] X    The address of the result MPI. Must be initialized.
+ *                  Must have the same number of limbs as the modulus \p N.
+ * \param[in]  A    The address of the first MPI.
+ * \param[in]  B    The address of the second MPI.
+ * \param[in]  N    The address of the modulus. Used to perform a modulo
+ *                  operation on the result of the subtraction.
+ *
+ * \return          \c 0 if successful.
+ * \return          #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if the given MPIs do not
+ *                  have the correct number of limbs.
+ */
+int mbedtls_mpi_mod_sub( mbedtls_mpi_mod_residue *X,
+                         const mbedtls_mpi_mod_residue *A,
+                         const mbedtls_mpi_mod_residue *B,
+                         const mbedtls_mpi_mod_modulus *N );
 
+/**
+ * \brief Perform modular inversion of an MPI with respect to a modulus \p N.
+ *
+ * \p A and \p X must be associated with the modulus \p N and will therefore
+ * have the same number of limbs as \p N.
+ *
+ * \p X may be aliased to \p A.
+ *
+ * \warning  Currently only supports prime moduli, but does not check for them.
+ *
+ * \param[out] X   The modular inverse of \p A with respect to \p N.
+ * \param[in] A    The number to calculate the modular inverse of.
+ *                 Must not be 0.
+ * \param[in] N    The modulus to use.
+ *
+ * \return         \c 0 if successful.
+ * \return         #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \p A and \p N do not
+ *                 have the same number of limbs.
+ * \return         #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \p A is zero.
+ * \return         #MBEDTLS_ERR_MPI_ALLOC_FAILED if couldn't allocate enough
+ *                 memory (needed for conversion to and from Mongtomery form
+ *                 when not in Montgomery form already, and for temporary use
+ *                 by the inversion calculation itself).
+ */
+
+int mbedtls_mpi_mod_inv( mbedtls_mpi_mod_residue *X,
+                         const mbedtls_mpi_mod_residue *A,
+                         const mbedtls_mpi_mod_modulus *N );
 /* END MERGE SLOT 3 */
 
 /* BEGIN MERGE SLOT 4 */
@@ -165,15 +332,142 @@
 /* END MERGE SLOT 4 */
 
 /* BEGIN MERGE SLOT 5 */
-
+/**
+ * \brief Perform a fixed-size modular addition.
+ *
+ * Calculate `A + B modulo N`.
+ *
+ * \p A, \p B and \p X must all be associated with the modulus \p N and must
+ * all have the same number of limbs as \p N.
+ *
+ * \p X may be aliased to \p A or \p B, or even both, but may not overlap
+ * either otherwise.
+ *
+ * \note This function does not check that \p A or \p B are in canonical
+ *       form (that is, are < \p N) - that will have been done by
+ *       mbedtls_mpi_mod_residue_setup().
+ *
+ * \param[out] X    The address of the result residue. Must be initialized.
+ *                  Must have the same number of limbs as the modulus \p N.
+ * \param[in]  A    The address of the first input residue.
+ * \param[in]  B    The address of the second input residue.
+ * \param[in]  N    The address of the modulus. Used to perform a modulo
+ *                  operation on the result of the addition.
+ *
+ * \return          \c 0 if successful.
+ * \return          #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if the given MPIs do not
+ *                  have the correct number of limbs.
+ */
+int mbedtls_mpi_mod_add( mbedtls_mpi_mod_residue *X,
+                         const mbedtls_mpi_mod_residue *A,
+                         const mbedtls_mpi_mod_residue *B,
+                         const mbedtls_mpi_mod_modulus *N );
 /* END MERGE SLOT 5 */
 
 /* BEGIN MERGE SLOT 6 */
 
+/** Generate a random number uniformly in a range.
+ *
+ * This function generates a random number between \p min inclusive and
+ * \p N exclusive.
+ *
+ * The procedure complies with RFC 6979 §3.3 (deterministic ECDSA)
+ * when the RNG is a suitably parametrized instance of HMAC_DRBG
+ * and \p min is \c 1.
+ *
+ * \note           There are `N - min` possible outputs. The lower bound
+ *                 \p min can be reached, but the upper bound \p N cannot.
+ *
+ * \param X        The destination residue.
+ * \param min      The minimum value to return. It must be strictly smaller
+ *                 than \b N.
+ * \param N        The modulus.
+ *                 This is the upper bound of the output range, exclusive.
+ * \param f_rng    The RNG function to use. This must not be \c NULL.
+ * \param p_rng    The RNG parameter to be passed to \p f_rng.
+ *
+ * \return         \c 0 if successful.
+ * \return         #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if the implementation was
+ *                 unable to find a suitable value within a limited number
+ *                 of attempts. This has a negligible probability if \p N
+ *                 is significantly larger than \p min, which is the case
+ *                 for all usual cryptographic applications.
+ */
+int mbedtls_mpi_mod_random( mbedtls_mpi_mod_residue *X,
+                            mbedtls_mpi_uint min,
+                            const mbedtls_mpi_mod_modulus *N,
+                            int (*f_rng)(void *, unsigned char *, size_t),
+                            void *p_rng );
+
 /* END MERGE SLOT 6 */
 
 /* BEGIN MERGE SLOT 7 */
+/** Read a residue from a byte buffer.
+ *
+ * The residue will be automatically converted to the internal representation
+ * based on the value of the `m->int_rep` field.
+ *
+ * The modulus \p m will be the modulus associated with \p r. The residue \p r
+ * should only be used in operations where the modulus is \p m or a modulus
+ * equivalent to \p m (in the sense that all their fields or memory pointed by
+ * their fields hold the same value).
+ *
+ * \param[out] r    The address of the residue. It must have exactly the same
+ *                  number of limbs as the modulus \p m.
+ * \param[in] m     The address of the modulus.
+ * \param[in] buf   The input buffer to import from.
+ * \param buflen    The length in bytes of \p buf.
+ * \param ext_rep   The endianness of the number in the input buffer.
+ *
+ * \return       \c 0 if successful.
+ * \return       #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p r isn't
+ *               large enough to hold the value in \p buf.
+ * \return       #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \p ext_rep
+ *               is invalid or the value in the buffer is not less than \p m.
+ */
+int mbedtls_mpi_mod_read( mbedtls_mpi_mod_residue *r,
+                          const mbedtls_mpi_mod_modulus *m,
+                          const unsigned char *buf,
+                          size_t buflen,
+                          mbedtls_mpi_mod_ext_rep ext_rep );
 
+/** Write a residue into a byte buffer.
+ *
+ * The modulus \p m must be the modulus associated with \p r (see
+ * mbedtls_mpi_mod_residue_setup() and mbedtls_mpi_mod_read()).
+ *
+ * The residue will be automatically converted from the internal representation
+ * based on the value of `m->int_rep` field.
+ *
+ * \warning     If the buffer is smaller than `m->bits`, the number of
+ *              leading zeroes is leaked through timing. If \p r is
+ *              secret, the caller must ensure that \p buflen is at least
+ *              (`m->bits`+7)/8.
+ *
+ * \param[in] r     The address of the residue. It must have the same number of
+ *                  limbs as the modulus \p m. (\p r is an input parameter, but
+ *                  its value will be modified during execution and restored
+ *                  before the function returns.)
+ * \param[in] m     The address of the modulus associated with \r.
+ * \param[out] buf  The output buffer to export to.
+ * \param buflen    The length in bytes of \p buf.
+ * \param ext_rep   The endianness in which the number should be written into
+ *                  the output buffer.
+ *
+ * \return       \c 0 if successful.
+ * \return       #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p buf isn't
+ *               large enough to hold the value of \p r (without leading
+ *               zeroes).
+ * \return       #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \p ext_rep is invalid.
+ * \return       #MBEDTLS_ERR_MPI_ALLOC_FAILED if couldn't allocate enough
+ *               memory for conversion. Can occur only for moduli with
+ *               MBEDTLS_MPI_MOD_REP_MONTGOMERY.
+ */
+int mbedtls_mpi_mod_write( const mbedtls_mpi_mod_residue *r,
+                           const mbedtls_mpi_mod_modulus *m,
+                           unsigned char *buf,
+                           size_t buflen,
+                           mbedtls_mpi_mod_ext_rep ext_rep );
 /* END MERGE SLOT 7 */
 
 /* BEGIN MERGE SLOT 8 */
diff --git a/library/bignum_mod_raw.c b/library/bignum_mod_raw.c
index a329e86..18599c3 100644
--- a/library/bignum_mod_raw.c
+++ b/library/bignum_mod_raw.c
@@ -52,11 +52,12 @@
 int mbedtls_mpi_mod_raw_read( mbedtls_mpi_uint *X,
                               const mbedtls_mpi_mod_modulus *m,
                               const unsigned char *input,
-                              size_t input_length )
+                              size_t input_length,
+                              mbedtls_mpi_mod_ext_rep ext_rep )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
 
-    switch( m->ext_rep )
+    switch( ext_rep )
     {
         case MBEDTLS_MPI_MOD_EXT_REP_LE:
             ret = mbedtls_mpi_core_read_le( X, m->limbs,
@@ -87,9 +88,10 @@
 int mbedtls_mpi_mod_raw_write( const mbedtls_mpi_uint *A,
                                const mbedtls_mpi_mod_modulus *m,
                                unsigned char *output,
-                               size_t output_length )
+                               size_t output_length,
+                               mbedtls_mpi_mod_ext_rep ext_rep )
 {
-    switch( m->ext_rep )
+    switch( ext_rep )
     {
         case MBEDTLS_MPI_MOD_EXT_REP_LE:
             return( mbedtls_mpi_core_write_le( A, m->limbs,
@@ -108,10 +110,61 @@
 
 /* BEGIN MERGE SLOT 2 */
 
+void mbedtls_mpi_mod_raw_sub( mbedtls_mpi_uint *X,
+                              const mbedtls_mpi_uint *A,
+                              const mbedtls_mpi_uint *B,
+                              const mbedtls_mpi_mod_modulus *N )
+{
+    mbedtls_mpi_uint c = mbedtls_mpi_core_sub( X, A, B, N->limbs );
+
+    (void) mbedtls_mpi_core_add_if( X, N->p, N->limbs, (unsigned) c );
+}
+
+void mbedtls_mpi_mod_raw_mul( mbedtls_mpi_uint *X,
+                              const mbedtls_mpi_uint *A,
+                              const mbedtls_mpi_uint *B,
+                              const mbedtls_mpi_mod_modulus *N,
+                              mbedtls_mpi_uint *T )
+{
+    mbedtls_mpi_core_montmul( X, A, B, N->limbs, N->p, N->limbs,
+                              N->rep.mont.mm, T );
+}
+
 /* END MERGE SLOT 2 */
 
 /* BEGIN MERGE SLOT 3 */
 
+size_t mbedtls_mpi_mod_raw_inv_prime_working_limbs( size_t AN_limbs )
+{
+    /* mbedtls_mpi_mod_raw_inv_prime() needs a temporary for the exponent,
+     * which will be the same size as the modulus and input (AN_limbs),
+     * and additional space to pass to mbedtls_mpi_core_exp_mod(). */
+    return( AN_limbs +
+            mbedtls_mpi_core_exp_mod_working_limbs( AN_limbs, AN_limbs ) );
+}
+
+void mbedtls_mpi_mod_raw_inv_prime( mbedtls_mpi_uint *X,
+                                    const mbedtls_mpi_uint *A,
+                                    const mbedtls_mpi_uint *N,
+                                    size_t AN_limbs,
+                                    const mbedtls_mpi_uint *RR,
+                                    mbedtls_mpi_uint *T )
+{
+    /* Inversion by power: g^|G| = 1 => g^(-1) = g^(|G|-1), and
+     *                       |G| = N - 1, so we want
+     *                 g^(|G|-1) = g^(N - 2)
+     */
+
+    /* Use the first AN_limbs of T to hold N - 2 */
+    mbedtls_mpi_uint *Nminus2 = T;
+    (void) mbedtls_mpi_core_sub_int( Nminus2, N, 2, AN_limbs );
+
+    /* Rest of T is given to exp_mod for its working space */
+    mbedtls_mpi_core_exp_mod( X,
+                              A, N, AN_limbs, Nminus2, AN_limbs,
+                              RR, T + AN_limbs );
+}
+
 /* END MERGE SLOT 3 */
 
 /* BEGIN MERGE SLOT 4 */
@@ -119,15 +172,109 @@
 /* END MERGE SLOT 4 */
 
 /* BEGIN MERGE SLOT 5 */
-
+void mbedtls_mpi_mod_raw_add( mbedtls_mpi_uint *X,
+                              const mbedtls_mpi_uint *A,
+                              const mbedtls_mpi_uint *B,
+                              const mbedtls_mpi_mod_modulus *N )
+{
+    mbedtls_mpi_uint carry, borrow;
+    carry  = mbedtls_mpi_core_add( X, A, B, N->limbs );
+    borrow = mbedtls_mpi_core_sub( X, X, N->p, N->limbs );
+    (void) mbedtls_mpi_core_add_if( X, N->p, N->limbs, (unsigned) ( carry ^ borrow ) );
+}
 /* END MERGE SLOT 5 */
 
 /* BEGIN MERGE SLOT 6 */
 
+int mbedtls_mpi_mod_raw_canonical_to_modulus_rep(
+    mbedtls_mpi_uint *X,
+    const mbedtls_mpi_mod_modulus *N )
+{
+    switch( N->int_rep )
+    {
+        case MBEDTLS_MPI_MOD_REP_MONTGOMERY:
+            return( mbedtls_mpi_mod_raw_to_mont_rep( X, N ) );
+        case MBEDTLS_MPI_MOD_REP_OPT_RED:
+            return( 0 );
+        default:
+            return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+    }
+}
+
+int mbedtls_mpi_mod_raw_modulus_to_canonical_rep(
+    mbedtls_mpi_uint *X,
+    const mbedtls_mpi_mod_modulus *N )
+{
+    switch( N->int_rep )
+    {
+        case MBEDTLS_MPI_MOD_REP_MONTGOMERY:
+            return( mbedtls_mpi_mod_raw_from_mont_rep( X, N ) );
+        case MBEDTLS_MPI_MOD_REP_OPT_RED:
+            return( 0 );
+        default:
+            return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+    }
+}
+
+int mbedtls_mpi_mod_raw_random( mbedtls_mpi_uint *X,
+                                mbedtls_mpi_uint min,
+                                const mbedtls_mpi_mod_modulus *N,
+                                int (*f_rng)(void *, unsigned char *, size_t),
+                                void *p_rng )
+{
+    int ret = mbedtls_mpi_core_random( X, min, N->p, N->limbs, f_rng, p_rng );
+    if( ret != 0 )
+        return( ret );
+    return( mbedtls_mpi_mod_raw_canonical_to_modulus_rep( X, N ) );
+}
+
 /* END MERGE SLOT 6 */
 
 /* BEGIN MERGE SLOT 7 */
+int mbedtls_mpi_mod_raw_to_mont_rep( mbedtls_mpi_uint *X,
+                                     const mbedtls_mpi_mod_modulus *m )
+{
+    mbedtls_mpi_uint *T;
+    const size_t t_limbs = mbedtls_mpi_core_montmul_working_limbs( m->limbs );
 
+    if( ( T = (mbedtls_mpi_uint *) mbedtls_calloc( t_limbs, ciL ) ) == NULL )
+        return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
+
+    mbedtls_mpi_core_to_mont_rep( X, X, m->p, m->limbs,
+                                  m->rep.mont.mm, m->rep.mont.rr, T );
+
+    mbedtls_platform_zeroize( T, t_limbs * ciL );
+    mbedtls_free( T );
+    return( 0 );
+}
+
+int mbedtls_mpi_mod_raw_from_mont_rep( mbedtls_mpi_uint *X,
+                                       const mbedtls_mpi_mod_modulus *m )
+{
+    const size_t t_limbs = mbedtls_mpi_core_montmul_working_limbs( m->limbs );
+    mbedtls_mpi_uint *T;
+
+    if( ( T = (mbedtls_mpi_uint *) mbedtls_calloc( t_limbs, ciL ) ) == NULL )
+        return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
+
+    mbedtls_mpi_core_from_mont_rep( X, X, m->p, m->limbs, m->rep.mont.mm, T );
+
+    mbedtls_platform_zeroize( T, t_limbs * ciL );
+    mbedtls_free( T );
+    return( 0 );
+}
+
+void mbedtls_mpi_mod_raw_neg( mbedtls_mpi_uint *X,
+                              const mbedtls_mpi_uint *A,
+                              const mbedtls_mpi_mod_modulus *m )
+{
+    mbedtls_mpi_core_sub( X, m->p, A, m->limbs );
+
+    /* If A=0 initially, then X=N now. Detect this by
+     * subtracting N and catching the carry. */
+    mbedtls_mpi_uint borrow = mbedtls_mpi_core_sub( X, X, m->p, m->limbs );
+    (void) mbedtls_mpi_core_add_if( X, m->p, m->limbs, (unsigned) borrow  );
+}
 /* END MERGE SLOT 7 */
 
 /* BEGIN MERGE SLOT 8 */
diff --git a/library/bignum_mod_raw.h b/library/bignum_mod_raw.h
index 30648d3..ea3207f 100644
--- a/library/bignum_mod_raw.h
+++ b/library/bignum_mod_raw.h
@@ -11,6 +11,51 @@
  * the wrong size. The functions in bignum_mod.h provide a higher-level
  * interface that includes protections against accidental misuse, at the
  * expense of code size and sometimes more cumbersome memory management.
+ *
+ * The functions in this module obey the following conventions unless
+ * explicitly indicated otherwise:
+ * - **Modulus parameters**: the modulus is passed as a pointer to a structure
+ *   of type #mbedtls_mpi_mod_modulus. The structure must be set up with an
+ *   array of limbs storing the bignum value of the modulus. The modulus must
+ *   be odd and is assumed to have no leading zeroes. The modulus is usually
+ *   named \c N and is usually input-only.
+ * - **Bignum parameters**: Bignums are passed as pointers to an array of
+ *   limbs. A limb has the type #mbedtls_mpi_uint. Unless otherwise specified:
+ *     - Bignum parameters called \c A, \c B, ... are inputs, and are not
+ *       modified by the function.
+ *     - Bignum parameters called \c X, \c Y are outputs or input-output.
+ *       The initial content of output-only parameters is ignored.
+ *     - \c T is a temporary storage area. The initial content of such a
+ *       parameter is ignored and the final content is unspecified.
+ * - **Bignum sizes**: bignum sizes are usually expressed by the \c limbs
+ *   member of the modulus argument. All bignum parameters must have the same
+ *   number of limbs as the modulus. All bignum sizes must be at least 1 and
+ *   must be significantly less than #SIZE_MAX. The behavior if a size is 0 is
+ *   undefined.
+ * - **Bignum representation**: the representation of inputs and outputs is
+ *   specified by the \c int_rep field of the modulus for arithmetic
+ *   functions. Utility functions may allow for different representation.
+ * - **Parameter ordering**: for bignum parameters, outputs come before inputs.
+ *   The modulus is passed after other bignum input parameters. Temporaries
+ *   come last.
+ * - **Aliasing**: in general, output bignums may be aliased to one or more
+ *   inputs. Modulus values may not be aliased to any other parameter. Outputs
+ *   may not be aliased to one another. Temporaries may not be aliased to any
+ *   other parameter.
+ * - **Overlap**: apart from aliasing of limb array pointers (where two
+ *   arguments are equal pointers), overlap is not supported and may result
+ *   in undefined behavior.
+ * - **Error handling**: This is a low-level module. Functions generally do not
+ *   try to protect against invalid arguments such as nonsensical sizes or
+ *   null pointers. Note that passing bignums with a different size than the
+ *   modulus may lead to buffer overflows. Some functions which allocate
+ *   memory or handle reading/writing of bignums will return an error if
+ *   memory allocation fails or if buffer sizes are invalid.
+ * - **Modular representatives**: all functions expect inputs to be in the
+ *   range [0, \c N - 1] and guarantee outputs in the range [0, \c N - 1]. If
+ *   an input is out of range, outputs are fully unspecified, though bignum
+ *   values out of range should not cause buffer overflows (beware that this is
+ *   not extensively tested).
  */
 
 /*
@@ -106,6 +151,7 @@
  * \param[in] m         The address of the modulus related to \p X.
  * \param[in] input     The input buffer to import from.
  * \param input_length  The length in bytes of \p input.
+ * \param ext_rep       The endianness of the number in the input buffer.
  *
  * \return       \c 0 if successful.
  * \return       #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p X isn't
@@ -116,7 +162,8 @@
 int mbedtls_mpi_mod_raw_read( mbedtls_mpi_uint *X,
                               const mbedtls_mpi_mod_modulus *m,
                               const unsigned char *input,
-                              size_t input_length );
+                              size_t input_length,
+                              mbedtls_mpi_mod_ext_rep ext_rep );
 
 /** Export A into unsigned binary data.
  *
@@ -126,6 +173,7 @@
  * \param[in] m         The address of the modulus related to \p A.
  * \param[out] output   The output buffer to export to.
  * \param output_length The length in bytes of \p output.
+ * \param ext_rep       The endianness in which the number should be written into the output buffer.
  *
  * \return       \c 0 if successful.
  * \return       #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p output isn't
@@ -136,7 +184,8 @@
 int mbedtls_mpi_mod_raw_write( const mbedtls_mpi_uint *A,
                                const mbedtls_mpi_mod_modulus *m,
                                unsigned char *output,
-                               size_t output_length );
+                               size_t output_length,
+                               mbedtls_mpi_mod_ext_rep ext_rep );
 
 /* BEGIN MERGE SLOT 1 */
 
@@ -144,10 +193,116 @@
 
 /* BEGIN MERGE SLOT 2 */
 
+/** \brief  Subtract two MPIs, returning the residue modulo the specified
+ *          modulus.
+ *
+ * The size of the operation is determined by \p N. \p A and \p B must have
+ * the same number of limbs as \p N.
+ *
+ * \p X may be aliased to \p A or \p B, or even both, but may not overlap
+ * either otherwise.
+ *
+ * \param[out] X        The address of the result MPI.
+ *                      This must be initialized. Must have enough limbs to
+ *                      store the full value of the result.
+ * \param[in]  A        The address of the first MPI. This must be initialized.
+ * \param[in]  B        The address of the second MPI. This must be initialized.
+ * \param[in]  N        The address of the modulus. Used to perform a modulo
+ *                      operation on the result of the subtraction.
+ */
+void mbedtls_mpi_mod_raw_sub( mbedtls_mpi_uint *X,
+                              const mbedtls_mpi_uint *A,
+                              const mbedtls_mpi_uint *B,
+                              const mbedtls_mpi_mod_modulus *N );
+
+/** \brief  Multiply two MPIs, returning the residue modulo the specified
+ *          modulus.
+ *
+ * \note Currently handles the case when `N->int_rep` is
+ * MBEDTLS_MPI_MOD_REP_MONTGOMERY.
+ *
+ * The size of the operation is determined by \p N. \p A, \p B and \p X must
+ * all be associated with the modulus \p N and must all have the same number
+ * of limbs as \p N.
+ *
+ * \p X may be aliased to \p A or \p B, or even both, but may not overlap
+ * either otherwise. They may not alias \p N (since they must be in canonical
+ * form, they cannot == \p N).
+ *
+ * \param[out] X        The address of the result MPI. Must have the same
+ *                      number of limbs as \p N.
+ *                      On successful completion, \p X contains the result of
+ *                      the multiplication `A * B * R^-1` mod N where
+ *                      `R = 2^(biL * N->limbs)`.
+ * \param[in]  A        The address of the first MPI.
+ * \param[in]  B        The address of the second MPI.
+ * \param[in]  N        The address of the modulus. Used to perform a modulo
+ *                      operation on the result of the multiplication.
+ * \param[in,out] T     Temporary storage of size at least 2 * N->limbs + 1
+ *                      limbs. Its initial content is unused and
+ *                      its final content is indeterminate.
+ *                      It must not alias or otherwise overlap any of the
+ *                      other parameters.
+ */
+void mbedtls_mpi_mod_raw_mul( mbedtls_mpi_uint *X,
+                              const mbedtls_mpi_uint *A,
+                              const mbedtls_mpi_uint *B,
+                              const mbedtls_mpi_mod_modulus *N,
+                              mbedtls_mpi_uint *T );
+
 /* END MERGE SLOT 2 */
 
 /* BEGIN MERGE SLOT 3 */
 
+/**
+ * \brief          Returns the number of limbs of working memory required for
+ *                 a call to `mbedtls_mpi_mod_raw_inv_prime()`.
+ *
+ * \note           This will always be at least
+ *                 `mbedtls_mpi_core_montmul_working_limbs(AN_limbs)`,
+ *                 i.e. sufficient for a call to `mbedtls_mpi_core_montmul()`.
+ *
+ * \param AN_limbs The number of limbs in the input `A` and the modulus `N`
+ *                 (they must be the same size) that will be given to
+ *                 `mbedtls_mpi_mod_raw_inv_prime()`.
+ *
+ * \return         The number of limbs of working memory required by
+ *                 `mbedtls_mpi_mod_raw_inv_prime()`.
+ */
+size_t mbedtls_mpi_mod_raw_inv_prime_working_limbs( size_t AN_limbs );
+
+/**
+ * \brief Perform fixed-width modular inversion of a Montgomery-form MPI with
+ *        respect to a modulus \p N that must be prime.
+ *
+ * \p X may be aliased to \p A, but not to \p N or \p RR.
+ *
+ * \param[out] X     The modular inverse of \p A with respect to \p N.
+ *                   Will be in Montgomery form.
+ * \param[in] A      The number to calculate the modular inverse of.
+ *                   Must be in Montgomery form. Must not be 0.
+ * \param[in] N      The modulus, as a little-endian array of length \p AN_limbs.
+ *                   Must be prime.
+ * \param AN_limbs   The number of limbs in \p A, \p N and \p RR.
+ * \param[in] RR     The precomputed residue of 2^{2*biL} modulo N, as a little-
+ *                   endian array of length \p AN_limbs.
+ * \param[in,out] T  Temporary storage of at least the number of limbs returned
+ *                   by `mbedtls_mpi_mod_raw_inv_prime_working_limbs()`.
+ *                   Its initial content is unused and its final content is
+ *                   indeterminate.
+ *                   It must not alias or otherwise overlap any of the other
+ *                   parameters.
+ *                   It is up to the caller to zeroize \p T when it is no
+ *                   longer needed, and before freeing it if it was dynamically
+ *                   allocated.
+ */
+void mbedtls_mpi_mod_raw_inv_prime( mbedtls_mpi_uint *X,
+                                    const mbedtls_mpi_uint *A,
+                                    const mbedtls_mpi_uint *N,
+                                    size_t AN_limbs,
+                                    const mbedtls_mpi_uint *RR,
+                                    mbedtls_mpi_uint *T );
+
 /* END MERGE SLOT 3 */
 
 /* BEGIN MERGE SLOT 4 */
@@ -155,15 +310,143 @@
 /* END MERGE SLOT 4 */
 
 /* BEGIN MERGE SLOT 5 */
-
+/**
+ * \brief Perform a known-size modular addition.
+ *
+ * Calculate `A + B modulo N`.
+ *
+ * The number of limbs in each operand, and the result, is given by the
+ * modulus \p N.
+ *
+ * \p X may be aliased to \p A or \p B, or even both, but may not overlap
+ * either otherwise.
+ *
+ * \param[out] X    The result of the modular addition.
+ * \param[in] A     Little-endian presentation of the left operand. This
+ *                  must be smaller than \p N.
+ * \param[in] B     Little-endian presentation of the right operand. This
+ *                  must be smaller than \p N.
+ * \param[in] N     The address of the modulus.
+ */
+void mbedtls_mpi_mod_raw_add( mbedtls_mpi_uint *X,
+                              const mbedtls_mpi_uint *A,
+                              const mbedtls_mpi_uint *B,
+                              const mbedtls_mpi_mod_modulus *N );
 /* END MERGE SLOT 5 */
 
 /* BEGIN MERGE SLOT 6 */
 
+/** Convert an MPI from canonical representation (little-endian limb array)
+ * to the representation associated with the modulus.
+ *
+ * \param[in,out] X The limb array to convert.
+ *                  It must have as many limbs as \p N.
+ *                  It is converted in place.
+ *                  If this function returns an error, the content of \p X
+ *                  is unspecified.
+ * \param[in] N     The modulus structure.
+ *
+ *\ return          \c 0 if successful.
+ *                  Otherwise an \c MBEDTLS_ERR_MPI_xxx error code.
+ */
+int mbedtls_mpi_mod_raw_canonical_to_modulus_rep(
+    mbedtls_mpi_uint *X,
+    const mbedtls_mpi_mod_modulus *N );
+
+/** Convert an MPI from the representation associated with the modulus
+ * to canonical representation (little-endian limb array).
+ *
+ * \param[in,out] X The limb array to convert.
+ *                  It must have as many limbs as \p N.
+ *                  It is converted in place.
+ *                  If this function returns an error, the content of \p X
+ *                  is unspecified.
+ * \param[in] N     The modulus structure.
+ *
+ *\ return          \c 0 if successful.
+ *                  Otherwise an \c MBEDTLS_ERR_MPI_xxx error code.
+ */
+int mbedtls_mpi_mod_raw_modulus_to_canonical_rep(
+    mbedtls_mpi_uint *X,
+    const mbedtls_mpi_mod_modulus *N );
+
+/** Generate a random number uniformly in a range.
+ *
+ * This function generates a random number between \p min inclusive and
+ * \p N exclusive.
+ *
+ * The procedure complies with RFC 6979 §3.3 (deterministic ECDSA)
+ * when the RNG is a suitably parametrized instance of HMAC_DRBG
+ * and \p min is \c 1.
+ *
+ * \note           There are `N - min` possible outputs. The lower bound
+ *                 \p min can be reached, but the upper bound \p N cannot.
+ *
+ * \param X        The destination MPI, in canonical representation modulo \p N.
+ *                 It must not be aliased with \p N or otherwise overlap it.
+ * \param min      The minimum value to return. It must be strictly smaller
+ *                 than \b N.
+ * \param N        The modulus.
+ *                 This is the upper bound of the output range, exclusive.
+ * \param f_rng    The RNG function to use. This must not be \c NULL.
+ * \param p_rng    The RNG parameter to be passed to \p f_rng.
+ *
+ * \return         \c 0 if successful.
+ * \return         #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if the implementation was
+ *                 unable to find a suitable value within a limited number
+ *                 of attempts. This has a negligible probability if \p N
+ *                 is significantly larger than \p min, which is the case
+ *                 for all usual cryptographic applications.
+ */
+int mbedtls_mpi_mod_raw_random( mbedtls_mpi_uint *X,
+                                mbedtls_mpi_uint min,
+                                const mbedtls_mpi_mod_modulus *N,
+                                int (*f_rng)(void *, unsigned char *, size_t),
+                                void *p_rng );
+
 /* END MERGE SLOT 6 */
 
 /* BEGIN MERGE SLOT 7 */
+/** Convert an MPI into Montgomery form.
+ *
+ * \param X      The address of the MPI.
+ *               Must have the same number of limbs as \p m.
+ * \param m      The address of the modulus, which gives the size of
+ *               the base `R` = 2^(biL*m->limbs).
+ *
+ * \return       \c 0 if successful.
+ */
+int mbedtls_mpi_mod_raw_to_mont_rep( mbedtls_mpi_uint *X,
+                                     const mbedtls_mpi_mod_modulus *m );
 
+/** Convert an MPI back from Montgomery representation.
+ *
+ * \param X      The address of the MPI.
+ *               Must have the same number of limbs as \p m.
+ * \param m      The address of the modulus, which gives the size of
+ *               the base `R`= 2^(biL*m->limbs).
+ *
+ * \return       \c 0 if successful.
+ */
+int mbedtls_mpi_mod_raw_from_mont_rep( mbedtls_mpi_uint *X,
+                                       const mbedtls_mpi_mod_modulus *m );
+
+/** \brief  Perform fixed width modular negation.
+ *
+ * The size of the operation is determined by \p m. \p A must have
+ * the same number of limbs as \p m.
+ *
+ * \p X may be aliased to \p A.
+ *
+ * \param[out] X        The result of the modular negation.
+ *                      This must be initialized.
+ * \param[in] A         Little-endian presentation of the input operand. This
+ *                      must be less than or equal to \p m.
+ * \param[in] m         The modulus to use.
+ */
+void mbedtls_mpi_mod_raw_neg( mbedtls_mpi_uint *X,
+                              const mbedtls_mpi_uint *A,
+                              const mbedtls_mpi_mod_modulus *m);
 /* END MERGE SLOT 7 */
 
 /* BEGIN MERGE SLOT 8 */
diff --git a/library/camellia.c b/library/camellia.c
index 5dd6c56..6e781c7 100644
--- a/library/camellia.c
+++ b/library/camellia.c
@@ -526,7 +526,6 @@
                                 const unsigned char *input,
                                 unsigned char *output )
 {
-    int i;
     unsigned char temp[16];
     if( mode != MBEDTLS_CAMELLIA_ENCRYPT && mode != MBEDTLS_CAMELLIA_DECRYPT )
         return MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA;
@@ -541,8 +540,7 @@
             memcpy( temp, input, 16 );
             mbedtls_camellia_crypt_ecb( ctx, mode, input, output );
 
-            for( i = 0; i < 16; i++ )
-                output[i] = (unsigned char)( output[i] ^ iv[i] );
+            mbedtls_xor( output, output, iv, 16 );
 
             memcpy( iv, temp, 16 );
 
@@ -555,8 +553,7 @@
     {
         while( length > 0 )
         {
-            for( i = 0; i < 16; i++ )
-                output[i] = (unsigned char)( input[i] ^ iv[i] );
+            mbedtls_xor( output, input, iv, 16 );
 
             mbedtls_camellia_crypt_ecb( ctx, mode, output, output );
             memcpy( iv, output, 16 );
diff --git a/library/ccm.c b/library/ccm.c
index 3edfba3..065eb60 100644
--- a/library/ccm.c
+++ b/library/ccm.c
@@ -112,7 +112,6 @@
                               const unsigned char *input,
                               unsigned char *output )
 {
-    size_t i;
     size_t olen = 0;
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     unsigned char tmp_buf[16] = {0};
@@ -125,8 +124,7 @@
         return ret;
     }
 
-    for( i = 0; i < use_len; i++ )
-        output[i] = input[i] ^ tmp_buf[offset + i];
+    mbedtls_xor( output, input, tmp_buf + offset, use_len );
 
     mbedtls_platform_zeroize(tmp_buf, sizeof(tmp_buf));
     return ret;
@@ -144,7 +142,7 @@
     unsigned char i;
     size_t len_left, olen;
 
-    /* length calulcation can be done only after both
+    /* length calculation can be done only after both
      * mbedtls_ccm_starts() and mbedtls_ccm_set_lengths() have been executed
      */
     if( !(ctx->state & CCM_STATE__STARTED) || !(ctx->state & CCM_STATE__LENGTHS_SET) )
@@ -269,7 +267,6 @@
                            size_t add_len )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    unsigned char i;
     size_t olen, use_len, offset;
 
     if( ctx->state & CCM_STATE__ERROR )
@@ -310,8 +307,7 @@
             if( use_len > add_len )
                 use_len = add_len;
 
-            for( i = 0; i < use_len; i++ )
-                ctx->y[i + offset] ^= add[i];
+            mbedtls_xor( ctx->y + offset, ctx->y + offset, add, use_len );
 
             ctx->processed += use_len;
             add_len -= use_len;
@@ -381,8 +377,7 @@
         if( ctx->mode == MBEDTLS_CCM_ENCRYPT || \
             ctx->mode == MBEDTLS_CCM_STAR_ENCRYPT )
         {
-            for( i = 0; i < use_len; i++ )
-                ctx->y[i + offset] ^= input[i];
+            mbedtls_xor( ctx->y + offset, ctx->y + offset, input, use_len );
 
             if( use_len + offset == 16 || ctx->processed == ctx->plaintext_len )
             {
@@ -411,8 +406,7 @@
             if( ret != 0 )
                 goto exit;
 
-            for( i = 0; i < use_len; i++ )
-                ctx->y[i + offset] ^= local_output[i];
+            mbedtls_xor( ctx->y + offset, ctx->y + offset, local_output, use_len );
 
             memcpy( output, local_output, use_len );
             mbedtls_platform_zeroize( local_output, 16 );
diff --git a/library/chacha20.c b/library/chacha20.c
index e53eb82..d17c58c 100644
--- a/library/chacha20.c
+++ b/library/chacha20.c
@@ -36,11 +36,6 @@
 
 #if !defined(MBEDTLS_CHACHA20_ALT)
 
-#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
-    !defined(inline) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
 #define ROTL32( value, amount ) \
     ( (uint32_t) ( (value) << (amount) ) | ( (value) >> ( 32 - (amount) ) ) )
 
@@ -222,7 +217,6 @@
                               unsigned char *output )
 {
     size_t offset = 0U;
-    size_t i;
 
     /* Use leftover keystream bytes, if available */
     while( size > 0U && ctx->keystream_bytes_used < CHACHA20_BLOCK_SIZE_BYTES )
@@ -242,17 +236,7 @@
         chacha20_block( ctx->state, ctx->keystream8 );
         ctx->state[CHACHA20_CTR_INDEX]++;
 
-        for( i = 0U; i < 64U; i += 8U )
-        {
-            output[offset + i  ] = input[offset + i  ] ^ ctx->keystream8[i  ];
-            output[offset + i+1] = input[offset + i+1] ^ ctx->keystream8[i+1];
-            output[offset + i+2] = input[offset + i+2] ^ ctx->keystream8[i+2];
-            output[offset + i+3] = input[offset + i+3] ^ ctx->keystream8[i+3];
-            output[offset + i+4] = input[offset + i+4] ^ ctx->keystream8[i+4];
-            output[offset + i+5] = input[offset + i+5] ^ ctx->keystream8[i+5];
-            output[offset + i+6] = input[offset + i+6] ^ ctx->keystream8[i+6];
-            output[offset + i+7] = input[offset + i+7] ^ ctx->keystream8[i+7];
-        }
+        mbedtls_xor( output + offset, input + offset, ctx->keystream8, 64U );
 
         offset += CHACHA20_BLOCK_SIZE_BYTES;
         size   -= CHACHA20_BLOCK_SIZE_BYTES;
@@ -265,10 +249,7 @@
         chacha20_block( ctx->state, ctx->keystream8 );
         ctx->state[CHACHA20_CTR_INDEX]++;
 
-        for( i = 0U; i < size; i++)
-        {
-            output[offset + i] = input[offset + i] ^ ctx->keystream8[i];
-        }
+        mbedtls_xor( output + offset, input + offset, ctx->keystream8, size );
 
         ctx->keystream_bytes_used = size;
 
diff --git a/library/cipher.c b/library/cipher.c
index dfb7329..dffe3ad 100644
--- a/library/cipher.c
+++ b/library/cipher.c
@@ -500,7 +500,7 @@
     }
 #endif
 
-    return( 0 );
+    return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
 }
 #endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */
 
@@ -1129,7 +1129,7 @@
     }
 #endif
 
-    return( 0 );
+    return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
 }
 
 int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx,
@@ -1156,11 +1156,8 @@
     }
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
-    /* Status to return on a non-authenticated algorithm. It would make sense
-     * to return MBEDTLS_ERR_CIPHER_INVALID_CONTEXT or perhaps
-     * MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA, but at the time I write this our
-     * unit tests assume 0. */
-    ret = 0;
+    /* Status to return on a non-authenticated algorithm. */
+    ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
 
 #if defined(MBEDTLS_GCM_C)
     if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
diff --git a/library/cmac.c b/library/cmac.c
index 3cc49d1..9870856 100644
--- a/library/cmac.c
+++ b/library/cmac.c
@@ -148,15 +148,6 @@
 #endif /* !defined(MBEDTLS_CMAC_ALT) || defined(MBEDTLS_SELF_TEST) */
 
 #if !defined(MBEDTLS_CMAC_ALT)
-static void cmac_xor_block( unsigned char *output, const unsigned char *input1,
-                            const unsigned char *input2,
-                            const size_t block_size )
-{
-    size_t idx;
-
-    for( idx = 0; idx < block_size; idx++ )
-        output[ idx ] = input1[ idx ] ^ input2[ idx ];
-}
 
 /*
  * Create padded last block from (partial) last block.
@@ -247,7 +238,7 @@
                 input,
                 block_size - cmac_ctx->unprocessed_len );
 
-        cmac_xor_block( state, cmac_ctx->unprocessed_block, state, block_size );
+        mbedtls_xor( state, cmac_ctx->unprocessed_block, state, block_size );
 
         if( ( ret = mbedtls_cipher_update( ctx, state, block_size, state,
                                            &olen ) ) != 0 )
@@ -267,7 +258,7 @@
      * final partial or complete block */
     for( j = 1; j < n; j++ )
     {
-        cmac_xor_block( state, input, state, block_size );
+        mbedtls_xor( state, input, state, block_size );
 
         if( ( ret = mbedtls_cipher_update( ctx, state, block_size, state,
                                            &olen ) ) != 0 )
@@ -319,16 +310,16 @@
     if( cmac_ctx->unprocessed_len < block_size )
     {
         cmac_pad( M_last, block_size, last_block, cmac_ctx->unprocessed_len );
-        cmac_xor_block( M_last, M_last, K2, block_size );
+        mbedtls_xor( M_last, M_last, K2, block_size );
     }
     else
     {
         /* Last block is complete block */
-        cmac_xor_block( M_last, last_block, K1, block_size );
+        mbedtls_xor( M_last, last_block, K1, block_size );
     }
 
 
-    cmac_xor_block( state, M_last, state, block_size );
+    mbedtls_xor( state, M_last, state, block_size );
     if( ( ret = mbedtls_cipher_update( ctx, state, block_size, state,
                                        &olen ) ) != 0 )
     {
diff --git a/library/common.h b/library/common.h
index a630fcc..9d3b8fe 100644
--- a/library/common.h
+++ b/library/common.h
@@ -24,8 +24,11 @@
 #define MBEDTLS_LIBRARY_COMMON_H
 
 #include "mbedtls/build_info.h"
+#include "alignment.h"
 
+#include <stddef.h>
 #include <stdint.h>
+#include <stddef.h>
 
 /** Helper to define a function as static except when building invasive tests.
  *
@@ -68,327 +71,68 @@
  */
 #define MBEDTLS_ALLOW_PRIVATE_ACCESS
 
-/** Byte Reading Macros
+/** Return an offset into a buffer.
  *
- * Given a multi-byte integer \p x, MBEDTLS_BYTE_n retrieves the n-th
- * byte from x, where byte 0 is the least significant byte.
- */
-#define MBEDTLS_BYTE_0( x ) ( (uint8_t) (   ( x )         & 0xff ) )
-#define MBEDTLS_BYTE_1( x ) ( (uint8_t) ( ( ( x ) >> 8  ) & 0xff ) )
-#define MBEDTLS_BYTE_2( x ) ( (uint8_t) ( ( ( x ) >> 16 ) & 0xff ) )
-#define MBEDTLS_BYTE_3( x ) ( (uint8_t) ( ( ( x ) >> 24 ) & 0xff ) )
-#define MBEDTLS_BYTE_4( x ) ( (uint8_t) ( ( ( x ) >> 32 ) & 0xff ) )
-#define MBEDTLS_BYTE_5( x ) ( (uint8_t) ( ( ( x ) >> 40 ) & 0xff ) )
-#define MBEDTLS_BYTE_6( x ) ( (uint8_t) ( ( ( x ) >> 48 ) & 0xff ) )
-#define MBEDTLS_BYTE_7( x ) ( (uint8_t) ( ( ( x ) >> 56 ) & 0xff ) )
-
-/**
- * Get the unsigned 32 bits integer corresponding to four bytes in
- * big-endian order (MSB first).
+ * This is just the addition of an offset to a pointer, except that this
+ * function also accepts an offset of 0 into a buffer whose pointer is null.
+ * (`p + n` has undefined behavior when `p` is null, even when `n == 0`.
+ * A null pointer is a valid buffer pointer when the size is 0, for example
+ * as the result of `malloc(0)` on some platforms.)
  *
- * \param   data    Base address of the memory to get the four bytes from.
- * \param   offset  Offset from \p data of the first and most significant
- *                  byte of the four bytes to build the 32 bits unsigned
- *                  integer from.
+ * \param p     Pointer to a buffer of at least n bytes.
+ *              This may be \p NULL if \p n is zero.
+ * \param n     An offset in bytes.
+ * \return      Pointer to offset \p n in the buffer \p p.
+ *              Note that this is only a valid pointer if the size of the
+ *              buffer is at least \p n + 1.
  */
-#ifndef MBEDTLS_GET_UINT32_BE
-#define MBEDTLS_GET_UINT32_BE( data , offset )                  \
-    (                                                           \
-          ( (uint32_t) ( data )[( offset )    ] << 24 )         \
-        | ( (uint32_t) ( data )[( offset ) + 1] << 16 )         \
-        | ( (uint32_t) ( data )[( offset ) + 2] <<  8 )         \
-        | ( (uint32_t) ( data )[( offset ) + 3]       )         \
-    )
-#endif
-
-/**
- * Put in memory a 32 bits unsigned integer in big-endian order.
- *
- * \param   n       32 bits unsigned integer to put in memory.
- * \param   data    Base address of the memory where to put the 32
- *                  bits unsigned integer in.
- * \param   offset  Offset from \p data where to put the most significant
- *                  byte of the 32 bits unsigned integer \p n.
- */
-#ifndef MBEDTLS_PUT_UINT32_BE
-#define MBEDTLS_PUT_UINT32_BE( n, data, offset )                \
-{                                                               \
-    ( data )[( offset )    ] = MBEDTLS_BYTE_3( n );             \
-    ( data )[( offset ) + 1] = MBEDTLS_BYTE_2( n );             \
-    ( data )[( offset ) + 2] = MBEDTLS_BYTE_1( n );             \
-    ( data )[( offset ) + 3] = MBEDTLS_BYTE_0( n );             \
+static inline unsigned char *mbedtls_buffer_offset(
+    unsigned char *p, size_t n )
+{
+    return( p == NULL ? NULL : p + n );
 }
-#endif
 
-/**
- * Get the unsigned 32 bits integer corresponding to four bytes in
- * little-endian order (LSB first).
+/** Return an offset into a read-only buffer.
  *
- * \param   data    Base address of the memory to get the four bytes from.
- * \param   offset  Offset from \p data of the first and least significant
- *                  byte of the four bytes to build the 32 bits unsigned
- *                  integer from.
- */
-#ifndef MBEDTLS_GET_UINT32_LE
-#define MBEDTLS_GET_UINT32_LE( data, offset )                   \
-    (                                                           \
-          ( (uint32_t) ( data )[( offset )    ]       )         \
-        | ( (uint32_t) ( data )[( offset ) + 1] <<  8 )         \
-        | ( (uint32_t) ( data )[( offset ) + 2] << 16 )         \
-        | ( (uint32_t) ( data )[( offset ) + 3] << 24 )         \
-    )
-#endif
-
-/**
- * Put in memory a 32 bits unsigned integer in little-endian order.
+ * Similar to mbedtls_buffer_offset(), but for const pointers.
  *
- * \param   n       32 bits unsigned integer to put in memory.
- * \param   data    Base address of the memory where to put the 32
- *                  bits unsigned integer in.
- * \param   offset  Offset from \p data where to put the least significant
- *                  byte of the 32 bits unsigned integer \p n.
+ * \param p     Pointer to a buffer of at least n bytes.
+ *              This may be \p NULL if \p n is zero.
+ * \param n     An offset in bytes.
+ * \return      Pointer to offset \p n in the buffer \p p.
+ *              Note that this is only a valid pointer if the size of the
+ *              buffer is at least \p n + 1.
  */
-#ifndef MBEDTLS_PUT_UINT32_LE
-#define MBEDTLS_PUT_UINT32_LE( n, data, offset )                \
-{                                                               \
-    ( data )[( offset )    ] = MBEDTLS_BYTE_0( n );             \
-    ( data )[( offset ) + 1] = MBEDTLS_BYTE_1( n );             \
-    ( data )[( offset ) + 2] = MBEDTLS_BYTE_2( n );             \
-    ( data )[( offset ) + 3] = MBEDTLS_BYTE_3( n );             \
+static inline const unsigned char *mbedtls_buffer_offset_const(
+    const unsigned char *p, size_t n )
+{
+    return( p == NULL ? NULL : p + n );
 }
-#endif
 
 /**
- * Get the unsigned 16 bits integer corresponding to two bytes in
- * little-endian order (LSB first).
+ * Perform a fast block XOR operation, such that
+ * r[i] = a[i] ^ b[i] where 0 <= i < n
  *
- * \param   data    Base address of the memory to get the two bytes from.
- * \param   offset  Offset from \p data of the first and least significant
- *                  byte of the two bytes to build the 16 bits unsigned
- *                  integer from.
+ * \param   r Pointer to result (buffer of at least \p n bytes). \p r
+ *            may be equal to either \p a or \p b, but behaviour when
+ *            it overlaps in other ways is undefined.
+ * \param   a Pointer to input (buffer of at least \p n bytes)
+ * \param   b Pointer to input (buffer of at least \p n bytes)
+ * \param   n Number of bytes to process.
  */
-#ifndef MBEDTLS_GET_UINT16_LE
-#define MBEDTLS_GET_UINT16_LE( data, offset )                   \
-    (                                                           \
-          ( (uint16_t) ( data )[( offset )    ]       )         \
-        | ( (uint16_t) ( data )[( offset ) + 1] <<  8 )         \
-    )
-#endif
-
-/**
- * Put in memory a 16 bits unsigned integer in little-endian order.
- *
- * \param   n       16 bits unsigned integer to put in memory.
- * \param   data    Base address of the memory where to put the 16
- *                  bits unsigned integer in.
- * \param   offset  Offset from \p data where to put the least significant
- *                  byte of the 16 bits unsigned integer \p n.
- */
-#ifndef MBEDTLS_PUT_UINT16_LE
-#define MBEDTLS_PUT_UINT16_LE( n, data, offset )                \
-{                                                               \
-    ( data )[( offset )    ] = MBEDTLS_BYTE_0( n );             \
-    ( data )[( offset ) + 1] = MBEDTLS_BYTE_1( n );             \
+inline void mbedtls_xor( unsigned char *r, const unsigned char *a, const unsigned char *b, size_t n )
+{
+    size_t i;
+    for ( i = 0; ( i + 4 ) <= n; i += 4 )
+    {
+        uint32_t x = mbedtls_get_unaligned_uint32( a + i ) ^ mbedtls_get_unaligned_uint32( b + i );
+        mbedtls_put_unaligned_uint32( r + i, x );
+    }
+    for ( ; i < n; i++ )
+    {
+        r[i] = a[i] ^ b[i];
+    }
 }
-#endif
-
-/**
- * Get the unsigned 16 bits integer corresponding to two bytes in
- * big-endian order (MSB first).
- *
- * \param   data    Base address of the memory to get the two bytes from.
- * \param   offset  Offset from \p data of the first and most significant
- *                  byte of the two bytes to build the 16 bits unsigned
- *                  integer from.
- */
-#ifndef MBEDTLS_GET_UINT16_BE
-#define MBEDTLS_GET_UINT16_BE( data, offset )                   \
-    (                                                           \
-          ( (uint16_t) ( data )[( offset )    ] << 8 )          \
-        | ( (uint16_t) ( data )[( offset ) + 1]      )          \
-    )
-#endif
-
-/**
- * Put in memory a 16 bits unsigned integer in big-endian order.
- *
- * \param   n       16 bits unsigned integer to put in memory.
- * \param   data    Base address of the memory where to put the 16
- *                  bits unsigned integer in.
- * \param   offset  Offset from \p data where to put the most significant
- *                  byte of the 16 bits unsigned integer \p n.
- */
-#ifndef MBEDTLS_PUT_UINT16_BE
-#define MBEDTLS_PUT_UINT16_BE( n, data, offset )                \
-{                                                               \
-    ( data )[( offset )    ] = MBEDTLS_BYTE_1( n );             \
-    ( data )[( offset ) + 1] = MBEDTLS_BYTE_0( n );             \
-}
-#endif
-
-/**
- * Get the unsigned 24 bits integer corresponding to three bytes in
- * big-endian order (MSB first).
- *
- * \param   data    Base address of the memory to get the three bytes from.
- * \param   offset  Offset from \p data of the first and most significant
- *                  byte of the three bytes to build the 24 bits unsigned
- *                  integer from.
- */
-#ifndef MBEDTLS_GET_UINT24_BE
-#define MBEDTLS_GET_UINT24_BE( data , offset )                  \
-    (                                                           \
-          ( (uint32_t) ( data )[( offset )    ] << 16 )         \
-        | ( (uint32_t) ( data )[( offset ) + 1] << 8  )         \
-        | ( (uint32_t) ( data )[( offset ) + 2]       )         \
-    )
-#endif
-
-/**
- * Put in memory a 24 bits unsigned integer in big-endian order.
- *
- * \param   n       24 bits unsigned integer to put in memory.
- * \param   data    Base address of the memory where to put the 24
- *                  bits unsigned integer in.
- * \param   offset  Offset from \p data where to put the most significant
- *                  byte of the 24 bits unsigned integer \p n.
- */
-#ifndef MBEDTLS_PUT_UINT24_BE
-#define MBEDTLS_PUT_UINT24_BE( n, data, offset )                \
-{                                                               \
-    ( data )[( offset )    ] = MBEDTLS_BYTE_2( n );             \
-    ( data )[( offset ) + 1] = MBEDTLS_BYTE_1( n );             \
-    ( data )[( offset ) + 2] = MBEDTLS_BYTE_0( n );             \
-}
-#endif
-
-/**
- * Get the unsigned 24 bits integer corresponding to three bytes in
- * little-endian order (LSB first).
- *
- * \param   data    Base address of the memory to get the three bytes from.
- * \param   offset  Offset from \p data of the first and least significant
- *                  byte of the three bytes to build the 24 bits unsigned
- *                  integer from.
- */
-#ifndef MBEDTLS_GET_UINT24_LE
-#define MBEDTLS_GET_UINT24_LE( data, offset )                   \
-    (                                                           \
-          ( (uint32_t) ( data )[( offset )    ]       )         \
-        | ( (uint32_t) ( data )[( offset ) + 1] <<  8 )         \
-        | ( (uint32_t) ( data )[( offset ) + 2] << 16 )         \
-    )
-#endif
-
-/**
- * Put in memory a 24 bits unsigned integer in little-endian order.
- *
- * \param   n       24 bits unsigned integer to put in memory.
- * \param   data    Base address of the memory where to put the 24
- *                  bits unsigned integer in.
- * \param   offset  Offset from \p data where to put the least significant
- *                  byte of the 24 bits unsigned integer \p n.
- */
-#ifndef MBEDTLS_PUT_UINT24_LE
-#define MBEDTLS_PUT_UINT24_LE( n, data, offset )                \
-{                                                               \
-    ( data )[( offset )    ] = MBEDTLS_BYTE_0( n );             \
-    ( data )[( offset ) + 1] = MBEDTLS_BYTE_1( n );             \
-    ( data )[( offset ) + 2] = MBEDTLS_BYTE_2( n );             \
-}
-#endif
-
-/**
- * Get the unsigned 64 bits integer corresponding to eight bytes in
- * big-endian order (MSB first).
- *
- * \param   data    Base address of the memory to get the eight bytes from.
- * \param   offset  Offset from \p data of the first and most significant
- *                  byte of the eight bytes to build the 64 bits unsigned
- *                  integer from.
- */
-#ifndef MBEDTLS_GET_UINT64_BE
-#define MBEDTLS_GET_UINT64_BE( data, offset )                   \
-    (                                                           \
-          ( (uint64_t) ( data )[( offset )    ] << 56 )         \
-        | ( (uint64_t) ( data )[( offset ) + 1] << 48 )         \
-        | ( (uint64_t) ( data )[( offset ) + 2] << 40 )         \
-        | ( (uint64_t) ( data )[( offset ) + 3] << 32 )         \
-        | ( (uint64_t) ( data )[( offset ) + 4] << 24 )         \
-        | ( (uint64_t) ( data )[( offset ) + 5] << 16 )         \
-        | ( (uint64_t) ( data )[( offset ) + 6] <<  8 )         \
-        | ( (uint64_t) ( data )[( offset ) + 7]       )         \
-    )
-#endif
-
-/**
- * Put in memory a 64 bits unsigned integer in big-endian order.
- *
- * \param   n       64 bits unsigned integer to put in memory.
- * \param   data    Base address of the memory where to put the 64
- *                  bits unsigned integer in.
- * \param   offset  Offset from \p data where to put the most significant
- *                  byte of the 64 bits unsigned integer \p n.
- */
-#ifndef MBEDTLS_PUT_UINT64_BE
-#define MBEDTLS_PUT_UINT64_BE( n, data, offset )                \
-{                                                               \
-    ( data )[( offset )    ] = MBEDTLS_BYTE_7( n );             \
-    ( data )[( offset ) + 1] = MBEDTLS_BYTE_6( n );             \
-    ( data )[( offset ) + 2] = MBEDTLS_BYTE_5( n );             \
-    ( data )[( offset ) + 3] = MBEDTLS_BYTE_4( n );             \
-    ( data )[( offset ) + 4] = MBEDTLS_BYTE_3( n );             \
-    ( data )[( offset ) + 5] = MBEDTLS_BYTE_2( n );             \
-    ( data )[( offset ) + 6] = MBEDTLS_BYTE_1( n );             \
-    ( data )[( offset ) + 7] = MBEDTLS_BYTE_0( n );             \
-}
-#endif
-
-/**
- * Get the unsigned 64 bits integer corresponding to eight bytes in
- * little-endian order (LSB first).
- *
- * \param   data    Base address of the memory to get the eight bytes from.
- * \param   offset  Offset from \p data of the first and least significant
- *                  byte of the eight bytes to build the 64 bits unsigned
- *                  integer from.
- */
-#ifndef MBEDTLS_GET_UINT64_LE
-#define MBEDTLS_GET_UINT64_LE( data, offset )                   \
-    (                                                           \
-          ( (uint64_t) ( data )[( offset ) + 7] << 56 )         \
-        | ( (uint64_t) ( data )[( offset ) + 6] << 48 )         \
-        | ( (uint64_t) ( data )[( offset ) + 5] << 40 )         \
-        | ( (uint64_t) ( data )[( offset ) + 4] << 32 )         \
-        | ( (uint64_t) ( data )[( offset ) + 3] << 24 )         \
-        | ( (uint64_t) ( data )[( offset ) + 2] << 16 )         \
-        | ( (uint64_t) ( data )[( offset ) + 1] <<  8 )         \
-        | ( (uint64_t) ( data )[( offset )    ]       )         \
-    )
-#endif
-
-/**
- * Put in memory a 64 bits unsigned integer in little-endian order.
- *
- * \param   n       64 bits unsigned integer to put in memory.
- * \param   data    Base address of the memory where to put the 64
- *                  bits unsigned integer in.
- * \param   offset  Offset from \p data where to put the least significant
- *                  byte of the 64 bits unsigned integer \p n.
- */
-#ifndef MBEDTLS_PUT_UINT64_LE
-#define MBEDTLS_PUT_UINT64_LE( n, data, offset )                \
-{                                                               \
-    ( data )[( offset )    ] = MBEDTLS_BYTE_0( n );             \
-    ( data )[( offset ) + 1] = MBEDTLS_BYTE_1( n );             \
-    ( data )[( offset ) + 2] = MBEDTLS_BYTE_2( n );             \
-    ( data )[( offset ) + 3] = MBEDTLS_BYTE_3( n );             \
-    ( data )[( offset ) + 4] = MBEDTLS_BYTE_4( n );             \
-    ( data )[( offset ) + 5] = MBEDTLS_BYTE_5( n );             \
-    ( data )[( offset ) + 6] = MBEDTLS_BYTE_6( n );             \
-    ( data )[( offset ) + 7] = MBEDTLS_BYTE_7( n );             \
-}
-#endif
 
 /* Fix MSVC C99 compatible issue
  *      MSVC support __func__ from visual studio 2015( 1900 )
diff --git a/library/ctr_drbg.c b/library/ctr_drbg.c
index 71c48af..f5c5e7b 100644
--- a/library/ctr_drbg.c
+++ b/library/ctr_drbg.c
@@ -174,8 +174,7 @@
 
         while( use_len > 0 )
         {
-            for( i = 0; i < MBEDTLS_CTR_DRBG_BLOCKSIZE; i++ )
-                chain[i] ^= p[i];
+            mbedtls_xor( chain, chain, p, MBEDTLS_CTR_DRBG_BLOCKSIZE );
             p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
             use_len -= ( use_len >= MBEDTLS_CTR_DRBG_BLOCKSIZE ) ?
                        MBEDTLS_CTR_DRBG_BLOCKSIZE : use_len;
diff --git a/library/debug.c b/library/debug.c
index bdbf6dd..78ce9ce 100644
--- a/library/debug.c
+++ b/library/debug.c
@@ -30,11 +30,6 @@
 #include <stdio.h>
 #include <string.h>
 
-#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
-    !defined(inline) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
 #define DEBUG_BUF_SIZE      512
 
 static int debug_threshold = 0;
@@ -112,7 +107,7 @@
     /*
      * With non-blocking I/O and examples that just retry immediately,
      * the logs would be quickly flooded with WANT_READ, so ignore that.
-     * Don't ignore WANT_WRITE however, since is is usually rare.
+     * Don't ignore WANT_WRITE however, since it is usually rare.
      */
     if( ret == MBEDTLS_ERR_SSL_WANT_READ )
         return;
diff --git a/library/des.c b/library/des.c
index 65f5681..c56d4d4 100644
--- a/library/des.c
+++ b/library/des.c
@@ -635,7 +635,6 @@
                     const unsigned char *input,
                     unsigned char *output )
 {
-    int i;
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     unsigned char temp[8];
 
@@ -646,8 +645,7 @@
     {
         while( length > 0 )
         {
-            for( i = 0; i < 8; i++ )
-                output[i] = (unsigned char)( input[i] ^ iv[i] );
+            mbedtls_xor( output, input, iv, 8 );
 
             ret = mbedtls_des_crypt_ecb( ctx, output, output );
             if( ret != 0 )
@@ -668,8 +666,7 @@
             if( ret != 0 )
                 goto exit;
 
-            for( i = 0; i < 8; i++ )
-                output[i] = (unsigned char)( output[i] ^ iv[i] );
+            mbedtls_xor( output, output, iv, 8 );
 
             memcpy( iv, temp, 8 );
 
@@ -741,7 +738,6 @@
                      const unsigned char *input,
                      unsigned char *output )
 {
-    int i;
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     unsigned char temp[8];
 
@@ -752,8 +748,7 @@
     {
         while( length > 0 )
         {
-            for( i = 0; i < 8; i++ )
-                output[i] = (unsigned char)( input[i] ^ iv[i] );
+            mbedtls_xor( output, input, iv, 8 );
 
             ret = mbedtls_des3_crypt_ecb( ctx, output, output );
             if( ret != 0 )
@@ -774,8 +769,7 @@
             if( ret != 0 )
                 goto exit;
 
-            for( i = 0; i < 8; i++ )
-                output[i] = (unsigned char)( output[i] ^ iv[i] );
+            mbedtls_xor( output, output, iv, 8 );
 
             memcpy( iv, temp, 8 );
 
diff --git a/library/ecp.c b/library/ecp.c
index 37f6090..b6ed60a 100644
--- a/library/ecp.c
+++ b/library/ecp.c
@@ -88,11 +88,6 @@
 
 #include "ecp_internal_alt.h"
 
-#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
-    !defined(inline) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
 #if defined(MBEDTLS_SELF_TEST)
 /*
  * Counts of point addition and doubling, and field multiplications.
@@ -759,6 +754,13 @@
     return( ret );
 }
 
+#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
+static int mbedtls_ecp_sw_derive_y( const mbedtls_ecp_group *grp,
+                                    const mbedtls_mpi *X,
+                                    mbedtls_mpi *Y,
+                                    int parity_bit );
+#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */
+
 /*
  * Import a point from unsigned binary data (SEC1 2.3.4 and RFC7748)
  */
@@ -800,16 +802,29 @@
                 return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
         }
 
-        if( buf[0] != 0x04 )
-            return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE );
-
-        if( ilen != 2 * plen + 1 )
+        if( ilen < 1 + plen )
             return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
 
         MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &pt->X, buf + 1, plen ) );
-        MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &pt->Y,
-                                                  buf + 1 + plen, plen ) );
         MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Z, 1 ) );
+
+        if( buf[0] == 0x04 )
+        {
+            /* format == MBEDTLS_ECP_PF_UNCOMPRESSED */
+            if( ilen != 1 + plen * 2 )
+                return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
+            return( mbedtls_mpi_read_binary( &pt->Y, buf + 1 + plen, plen ) );
+        }
+        else if( buf[0] == 0x02 || buf[0] == 0x03 )
+        {
+            /* format == MBEDTLS_ECP_PF_COMPRESSED */
+            if( ilen != 1 + plen )
+                return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
+            return( mbedtls_ecp_sw_derive_y( grp, &pt->X, &pt->Y,
+                                             ( buf[0] & 1 ) ) );
+        }
+        else
+            return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
     }
 #endif
 
@@ -1196,6 +1211,86 @@
     MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_swap( (X), (Y), (cond) ) )
 
 #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
+
+/*
+ * Computes the right-hand side of the Short Weierstrass equation
+ * RHS = X^3 + A X + B
+ */
+static int ecp_sw_rhs( const mbedtls_ecp_group *grp,
+                       mbedtls_mpi *rhs,
+                       const mbedtls_mpi *X )
+{
+    int ret;
+
+    /* Compute X^3 + A X + B as X (X^2 + A) + B */
+    MPI_ECP_SQR( rhs, X );
+
+    /* Special case for A = -3 */
+    if( grp->A.p == NULL )
+    {
+        MPI_ECP_SUB_INT( rhs, rhs, 3 );
+    }
+    else
+    {
+        MPI_ECP_ADD( rhs, rhs, &grp->A );
+    }
+
+    MPI_ECP_MUL( rhs, rhs, X  );
+    MPI_ECP_ADD( rhs, rhs, &grp->B );
+
+cleanup:
+    return( ret );
+}
+
+/*
+ * Derive Y from X and a parity bit
+ */
+static int mbedtls_ecp_sw_derive_y( const mbedtls_ecp_group *grp,
+                                    const mbedtls_mpi *X,
+                                    mbedtls_mpi *Y,
+                                    int parity_bit )
+{
+    /* w = y^2 = x^3 + ax + b
+     * y = sqrt(w) = w^((p+1)/4) mod p   (for prime p where p = 3 mod 4)
+     *
+     * Note: this method for extracting square root does not validate that w
+     * was indeed a square so this function will return garbage in Y if X
+     * does not correspond to a point on the curve.
+     */
+
+    /* Check prerequisite p = 3 mod 4 */
+    if( mbedtls_mpi_get_bit( &grp->P, 0 ) != 1 ||
+        mbedtls_mpi_get_bit( &grp->P, 1 ) != 1 )
+        return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE );
+
+    int ret;
+    mbedtls_mpi exp;
+    mbedtls_mpi_init( &exp );
+
+    /* use Y to store intermediate result, actually w above */
+    MBEDTLS_MPI_CHK( ecp_sw_rhs( grp, Y, X ) );
+
+    /* w = y^2 */ /* Y contains y^2 intermediate result */
+    /* exp = ((p+1)/4) */
+    MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &exp, &grp->P, 1 ) );
+    MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &exp, 2 ) );
+    /* sqrt(w) = w^((p+1)/4) mod p   (for prime p where p = 3 mod 4) */
+    MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( Y, Y /*y^2*/, &exp, &grp->P, NULL ) );
+
+    /* check parity bit match or else invert Y */
+    /* This quick inversion implementation is valid because Y != 0 for all
+     * Short Weierstrass curves supported by mbedtls, as each supported curve
+     * has an order that is a large prime, so each supported curve does not
+     * have any point of order 2, and a point with Y == 0 would be of order 2 */
+    if( mbedtls_mpi_get_bit( Y, 0 ) != parity_bit )
+        MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( Y, &grp->P, Y ) );
+
+cleanup:
+
+    mbedtls_mpi_free( &exp );
+    return( ret );
+}
+
 /*
  * For curves in short Weierstrass form, we do all the internal operations in
  * Jacobian coordinates.
@@ -2616,23 +2711,10 @@
 
     /*
      * YY = Y^2
-     * RHS = X (X^2 + A) + B = X^3 + A X + B
+     * RHS = X^3 + A X + B
      */
     MPI_ECP_SQR( &YY,  &pt->Y );
-    MPI_ECP_SQR( &RHS, &pt->X );
-
-    /* Special case for A = -3 */
-    if( grp->A.p == NULL )
-    {
-        MPI_ECP_SUB_INT( &RHS, &RHS, 3 );
-    }
-    else
-    {
-        MPI_ECP_ADD( &RHS, &RHS, &grp->A );
-    }
-
-    MPI_ECP_MUL( &RHS, &RHS, &pt->X  );
-    MPI_ECP_ADD( &RHS, &RHS, &grp->B );
+    MBEDTLS_MPI_CHK( ecp_sw_rhs( grp, &RHS, &pt->X ) );
 
     if( MPI_ECP_CMP( &YY, &RHS ) != 0 )
         ret = MBEDTLS_ERR_ECP_INVALID_KEY;
diff --git a/library/ecp_curves.c b/library/ecp_curves.c
index 7b14237..5cd2828 100644
--- a/library/ecp_curves.c
+++ b/library/ecp_curves.c
@@ -39,11 +39,6 @@
 #define ECP_VALIDATE( cond )        \
     MBEDTLS_INTERNAL_VALIDATE( cond )
 
-#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
-    !defined(inline) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
 #define ECP_MPI_INIT(s, n, p) {s, (n), (mbedtls_mpi_uint *)(p)}
 
 #define ECP_MPI_INIT_ARRAY(x)   \
diff --git a/library/entropy.c b/library/entropy.c
index 1e0d9d3..545fd9d 100644
--- a/library/entropy.c
+++ b/library/entropy.c
@@ -564,7 +564,7 @@
 }
 
 /*
- * A test to ensure hat the entropy sources are functioning correctly
+ * A test to ensure that the entropy sources are functioning correctly
  * and there is no obvious failure. The test performs the following checks:
  *  - The entropy source is not providing only 0s (all bits unset) or 1s (all
  *    bits set).
diff --git a/library/gcm.c b/library/gcm.c
index f004a73c..0178b5b 100644
--- a/library/gcm.c
+++ b/library/gcm.c
@@ -235,7 +235,6 @@
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     unsigned char work_buf[16];
-    size_t i;
     const unsigned char *p;
     size_t use_len, olen = 0;
     uint64_t iv_bits;
@@ -268,8 +267,7 @@
         {
             use_len = ( iv_len < 16 ) ? iv_len : 16;
 
-            for( i = 0; i < use_len; i++ )
-                ctx->y[i] ^= p[i];
+            mbedtls_xor( ctx->y, ctx->y, p, use_len );
 
             gcm_mult( ctx, ctx->y, ctx->y );
 
@@ -277,8 +275,7 @@
             p += use_len;
         }
 
-        for( i = 0; i < 16; i++ )
-            ctx->y[i] ^= work_buf[i];
+        mbedtls_xor( ctx->y, ctx->y, work_buf, 16);
 
         gcm_mult( ctx, ctx->y, ctx->y );
     }
@@ -313,7 +310,7 @@
                            const unsigned char *add, size_t add_len )
 {
     const unsigned char *p;
-    size_t use_len, i, offset;
+    size_t use_len, offset;
 
     /* IV is limited to 2^64 bits, so 2^61 bytes */
     if( (uint64_t) add_len >> 61 != 0 )
@@ -328,8 +325,7 @@
         if( use_len > add_len )
             use_len = add_len;
 
-        for( i = 0; i < use_len; i++ )
-            ctx->buf[i+offset] ^= p[i];
+        mbedtls_xor( ctx->buf + offset, ctx->buf + offset, p, use_len );
 
         if( offset + use_len == 16 )
             gcm_mult( ctx, ctx->buf, ctx->buf );
@@ -343,8 +339,7 @@
 
     while( add_len >= 16 )
     {
-        for( i = 0; i < 16; i++ )
-            ctx->buf[i] ^= p[i];
+        mbedtls_xor( ctx->buf, ctx->buf, p, 16 );
 
         gcm_mult( ctx, ctx->buf, ctx->buf );
 
@@ -354,8 +349,7 @@
 
     if( add_len > 0 )
     {
-        for( i = 0; i < add_len; i++ )
-            ctx->buf[i] ^= p[i];
+        mbedtls_xor( ctx->buf, ctx->buf, p, add_len );
     }
 
     return( 0 );
@@ -378,7 +372,6 @@
                      const unsigned char *input,
                      unsigned char *output )
 {
-    size_t i;
     size_t olen = 0;
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
 
@@ -389,14 +382,12 @@
         return( ret );
     }
 
-    for( i = 0; i < use_len; i++ )
-    {
-        if( ctx->mode == MBEDTLS_GCM_DECRYPT )
-            ctx->buf[offset + i] ^= input[i];
-        output[i] = ectr[offset + i] ^ input[i];
-        if( ctx->mode == MBEDTLS_GCM_ENCRYPT )
-            ctx->buf[offset + i] ^= output[i];
-    }
+    if( ctx->mode == MBEDTLS_GCM_DECRYPT )
+        mbedtls_xor( ctx->buf + offset, ctx->buf + offset, input, use_len );
+    mbedtls_xor( output, ectr + offset, input, use_len );
+    if( ctx->mode == MBEDTLS_GCM_ENCRYPT )
+        mbedtls_xor( ctx->buf + offset, ctx->buf + offset, output, use_len );
+
     return( 0 );
 }
 
@@ -489,7 +480,6 @@
                         unsigned char *tag, size_t tag_len )
 {
     unsigned char work_buf[16];
-    size_t i;
     uint64_t orig_len;
     uint64_t orig_add_len;
 
@@ -524,13 +514,11 @@
         MBEDTLS_PUT_UINT32_BE( ( orig_len     >> 32 ), work_buf, 8  );
         MBEDTLS_PUT_UINT32_BE( ( orig_len           ), work_buf, 12 );
 
-        for( i = 0; i < 16; i++ )
-            ctx->buf[i] ^= work_buf[i];
+        mbedtls_xor( ctx->buf, ctx->buf, work_buf, 16 );
 
         gcm_mult( ctx, ctx->buf, ctx->buf );
 
-        for( i = 0; i < tag_len; i++ )
-            tag[i] ^= ctx->buf[i];
+        mbedtls_xor( tag, tag, ctx->buf, tag_len );
     }
 
     return( 0 );
diff --git a/library/lmots.h b/library/lmots.h
index 39e8699..022dcf3 100644
--- a/library/lmots.h
+++ b/library/lmots.h
@@ -139,7 +139,7 @@
  *                           this public key.
  *
  * \param ctx                The initialized LMOTS context that contains the
- *                           publc key.
+ *                           public key.
  * \param key                The buffer into which the key will be output. Must
  *                           be at least #MBEDTLS_LMOTS_PUBLIC_KEY_LEN in size.
  *
diff --git a/library/md.c b/library/md.c
index 8efcf10..9c161a5 100644
--- a/library/md.c
+++ b/library/md.c
@@ -633,7 +633,6 @@
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     unsigned char sum[MBEDTLS_MD_MAX_SIZE];
     unsigned char *ipad, *opad;
-    size_t i;
 
     if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL )
         return( MBEDTLS_ERR_MD_BAD_INPUT_DATA );
@@ -657,11 +656,8 @@
     memset( ipad, 0x36, ctx->md_info->block_size );
     memset( opad, 0x5C, ctx->md_info->block_size );
 
-    for( i = 0; i < keylen; i++ )
-    {
-        ipad[i] = (unsigned char)( ipad[i] ^ key[i] );
-        opad[i] = (unsigned char)( opad[i] ^ key[i] );
-    }
+    mbedtls_xor( ipad, ipad, key, keylen );
+    mbedtls_xor( opad, opad, key, keylen );
 
     if( ( ret = mbedtls_md_starts( ctx ) ) != 0 )
         goto cleanup;
diff --git a/library/mps_reader.c b/library/mps_reader.c
index 36958b4..df97b6c 100644
--- a/library/mps_reader.c
+++ b/library/mps_reader.c
@@ -29,11 +29,6 @@
 
 #include <string.h>
 
-#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
-    !defined(inline) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
 #if defined(MBEDTLS_MPS_ENABLE_TRACE)
 static int mbedtls_mps_trace_id = MBEDTLS_MPS_TRACE_BIT_READER;
 #endif /* MBEDTLS_MPS_ENABLE_TRACE */
@@ -535,7 +530,7 @@
          * of the accumulator. */
         memmove( acc, acc + acc_backup_offset, acc_backup_len );
 
-        /* Copy uncmmitted parts of the current fragment to the
+        /* Copy uncommitted parts of the current fragment to the
          * accumulator. */
         memcpy( acc + acc_backup_len,
                 frag + frag_backup_offset, frag_backup_len );
diff --git a/library/pk_wrap.c b/library/pk_wrap.c
index 5de8fa6..ea7d726 100644
--- a/library/pk_wrap.c
+++ b/library/pk_wrap.c
@@ -1162,8 +1162,12 @@
     size_t key_len;
     unsigned char buf[MBEDTLS_PK_ECP_PRV_DER_MAX_BYTES];
     unsigned char *p;
-    psa_algorithm_t psa_sig_md =
-        PSA_ALG_ECDSA( mbedtls_hash_info_psa_from_md( md_alg ) );
+    psa_algorithm_t psa_hash = mbedtls_hash_info_psa_from_md( md_alg );
+#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
+    psa_algorithm_t psa_sig_md = PSA_ALG_DETERMINISTIC_ECDSA( psa_hash );
+#else
+    psa_algorithm_t psa_sig_md = PSA_ALG_ECDSA( psa_hash );
+#endif
     size_t curve_bits;
     psa_ecc_family_t curve =
         mbedtls_ecc_group_to_psa( ctx->grp.id, &curve_bits );
diff --git a/library/pkcs5.c b/library/pkcs5.c
index ac5945a..1e3b17e 100644
--- a/library/pkcs5.c
+++ b/library/pkcs5.c
@@ -211,7 +211,6 @@
                               uint32_t key_length, unsigned char *output )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    int j;
     unsigned int i;
     unsigned char md1[MBEDTLS_MD_MAX_SIZE];
     unsigned char work[MBEDTLS_MD_MAX_SIZE];
@@ -263,8 +262,7 @@
 
             // U1 xor U2
             //
-            for( j = 0; j < md_size; j++ )
-                work[j] ^= md1[j];
+            mbedtls_xor( work, work, md1, md_size );
         }
 
         use_len = ( key_length < md_size ) ? key_length : md_size;
@@ -324,7 +322,6 @@
     mbedtls_md_free( &md_ctx );
     return( ret );
 #else
-    int j;
     unsigned int i;
     unsigned char md1[PSA_HASH_MAX_SIZE];
     unsigned char work[PSA_HASH_MAX_SIZE];
@@ -396,8 +393,7 @@
 
             // U1 xor U2
             //
-            for( j = 0; j < md_size; j++ )
-                work[j] ^= md1[j];
+            mbedtls_xor( work, work, md1, md_size );
         }
 
         use_len = ( key_length < md_size ) ? key_length : md_size;
diff --git a/library/pkcs7.c b/library/pkcs7.c
new file mode 100644
index 0000000..9100980
--- /dev/null
+++ b/library/pkcs7.c
@@ -0,0 +1,728 @@
+/*
+ *  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"
+
+#include "mbedtls/build_info.h"
+#if defined(MBEDTLS_PKCS7_C)
+#include "mbedtls/pkcs7.h"
+#include "mbedtls/x509.h"
+#include "mbedtls/asn1.h"
+#include "mbedtls/x509_crt.h"
+#include "mbedtls/x509_crl.h"
+#include "mbedtls/oid.h"
+#include "mbedtls/error.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#if defined(MBEDTLS_FS_IO)
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+
+#include "mbedtls/platform.h"
+#include "mbedtls/platform_util.h"
+
+#if defined(MBEDTLS_HAVE_TIME)
+#include "mbedtls/platform_time.h"
+#endif
+#if defined(MBEDTLS_HAVE_TIME_DATE)
+#include <time.h>
+#endif
+
+/**
+ * Initializes the pkcs7 structure.
+ */
+void mbedtls_pkcs7_init( mbedtls_pkcs7 *pkcs7 )
+{
+    memset( pkcs7, 0, sizeof( *pkcs7 ) );
+}
+
+static int pkcs7_get_next_content_len( unsigned char **p, unsigned char *end,
+                                       size_t *len )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+    ret = mbedtls_asn1_get_tag( p, end, len, MBEDTLS_ASN1_CONSTRUCTED
+            | MBEDTLS_ASN1_CONTEXT_SPECIFIC );
+    if( ret != 0 )
+    {
+        ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_FORMAT, ret );
+    }
+
+    return( ret );
+}
+
+/**
+ * version Version
+ * Version ::= INTEGER
+ **/
+static int pkcs7_get_version( unsigned char **p, unsigned char *end, int *ver )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+    ret = mbedtls_asn1_get_int( p, end, ver );
+    if( ret != 0 )
+        ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_VERSION, ret );
+
+    /* If version != 1, return invalid version */
+    if( *ver != MBEDTLS_PKCS7_SUPPORTED_VERSION )
+        ret = MBEDTLS_ERR_PKCS7_INVALID_VERSION;
+
+    return( ret );
+}
+
+/**
+ * ContentInfo ::= SEQUENCE {
+ *      contentType ContentType,
+ *      content
+ *              [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+ **/
+static int pkcs7_get_content_info_type( unsigned char **p, unsigned char *end,
+                                        mbedtls_pkcs7_buf *pkcs7 )
+{
+    size_t len = 0;
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    unsigned char *start = *p;
+
+    ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
+                                            | MBEDTLS_ASN1_SEQUENCE );
+    if( ret != 0 ) {
+        *p = start;
+        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO, ret ) );
+    }
+
+    ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_OID );
+    if( ret != 0 ) {
+        *p = start;
+        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO, ret ) );
+    }
+
+    pkcs7->tag = MBEDTLS_ASN1_OID;
+    pkcs7->len = len;
+    pkcs7->p = *p;
+    *p += len;
+
+    return( ret );
+}
+
+/**
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * This is from x509.h
+ **/
+static int pkcs7_get_digest_algorithm( unsigned char **p, unsigned char *end,
+                                       mbedtls_x509_buf *alg )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+    if( ( ret = mbedtls_asn1_get_alg_null( p, end, alg ) ) != 0 )
+        ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_ALG, ret );
+
+    return( ret );
+}
+
+/**
+ * DigestAlgorithmIdentifiers :: SET of DigestAlgorithmIdentifier
+ **/
+static int pkcs7_get_digest_algorithm_set( unsigned char **p,
+                                           unsigned char *end,
+                                           mbedtls_x509_buf *alg )
+{
+    size_t len = 0;
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+    ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
+                                            | MBEDTLS_ASN1_SET );
+    if( ret != 0 )
+    {
+        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_ALG, ret ) );
+    }
+
+    end = *p + len;
+
+    ret = mbedtls_asn1_get_alg_null( p, end, alg );
+    if( ret != 0 )
+    {
+        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_ALG, ret ) );
+    }
+
+    /** For now, it assumes there is only one digest algorithm specified **/
+    if ( *p != end )
+        return( MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE );
+
+    return( 0 );
+}
+
+/**
+ * certificates :: SET OF ExtendedCertificateOrCertificate,
+ * ExtendedCertificateOrCertificate ::= CHOICE {
+ *      certificate Certificate -- x509,
+ *      extendedCertificate[0] IMPLICIT ExtendedCertificate }
+ * Return number of certificates added to the signed data,
+ * 0 or higher is valid.
+ * Return negative error code for failure.
+ **/
+static int pkcs7_get_certificates( unsigned char **p, unsigned char *end,
+                                   mbedtls_x509_crt *certs )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    size_t len1 = 0;
+    size_t len2 = 0;
+    unsigned char *end_set, *end_cert, *start;
+
+    if( ( ret = mbedtls_asn1_get_tag( p, end, &len1, MBEDTLS_ASN1_CONSTRUCTED
+                    | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ) != 0 )
+    {
+        if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG )
+            return( 0 );
+        else
+            return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_FORMAT, ret ) );
+    }
+    start = *p;
+    end_set = *p + len1;
+
+    ret = mbedtls_asn1_get_tag( p, end_set, &len2, MBEDTLS_ASN1_CONSTRUCTED
+            | MBEDTLS_ASN1_SEQUENCE );
+    if( ret != 0 )
+    {
+        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_CERT, ret ) );
+    }
+
+    end_cert = *p + len2;
+
+    /*
+     * This is to verify that there is only one signer certificate. It seems it is
+     * not easy to differentiate between the chain vs different signer's certificate.
+     * So, we support only the root certificate and the single signer.
+     * The behaviour would be improved with addition of multiple signer support.
+     */
+    if ( end_cert != end_set )
+    {
+        return( MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE );
+    }
+
+    *p = start;
+    if( ( ret = mbedtls_x509_crt_parse_der( certs, *p, len1 ) ) < 0 )
+    {
+        return( MBEDTLS_ERR_PKCS7_INVALID_CERT );
+    }
+
+    *p = *p + len1;
+
+    /*
+     * Since in this version we strictly support single certificate, and reaching
+     * here implies we have parsed successfully, we return 1.
+     */
+    return( 1 );
+}
+
+/**
+ * EncryptedDigest ::= OCTET STRING
+ **/
+static int pkcs7_get_signature( unsigned char **p, unsigned char *end,
+                                mbedtls_pkcs7_buf *signature )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    size_t len = 0;
+
+    ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_OCTET_STRING );
+    if( ret != 0 )
+        return( ret );
+
+    signature->tag = MBEDTLS_ASN1_OCTET_STRING;
+    signature->len = len;
+    signature->p = *p;
+
+    *p = *p + len;
+
+    return( 0 );
+}
+
+static void pkcs7_free_signer_info( mbedtls_pkcs7_signer_info *signer )
+{
+    mbedtls_x509_name *name_cur;
+    mbedtls_x509_name *name_prv;
+
+    if( signer == NULL )
+        return;
+
+    name_cur = signer->issuer.next;
+    while( name_cur != NULL )
+    {
+        name_prv = name_cur;
+        name_cur = name_cur->next;
+        mbedtls_free( name_prv );
+    }
+    signer->issuer.next = NULL;
+}
+
+/**
+ * SignerInfo ::= SEQUENCE {
+ *      version Version;
+ *      issuerAndSerialNumber   IssuerAndSerialNumber,
+ *      digestAlgorithm DigestAlgorithmIdentifier,
+ *      authenticatedAttributes
+ *              [0] IMPLICIT Attributes OPTIONAL,
+ *      digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
+ *      encryptedDigest EncryptedDigest,
+ *      unauthenticatedAttributes
+ *              [1] IMPLICIT Attributes OPTIONAL,
+ * Returns 0 if the signerInfo is valid.
+ * Return negative error code for failure.
+ * Structure must not contain vales for authenticatedAttributes
+ * and unauthenticatedAttributes.
+ **/
+static int pkcs7_get_signer_info( unsigned char **p, unsigned char *end,
+                                  mbedtls_pkcs7_signer_info *signer )
+{
+    unsigned char *end_signer;
+    int asn1_ret = 0, ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    size_t len = 0;
+
+    asn1_ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
+                                | MBEDTLS_ASN1_SEQUENCE );
+    if( asn1_ret != 0 )
+        goto out;
+
+    end_signer = *p + len;
+
+    ret = pkcs7_get_version( p, end_signer, &signer->version );
+    if( ret != 0 )
+        goto out;
+
+    asn1_ret = mbedtls_asn1_get_tag( p, end_signer, &len,
+                MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE );
+    if( asn1_ret != 0 )
+        goto out;
+
+    /* Parsing IssuerAndSerialNumber */
+    signer->issuer_raw.p = *p;
+
+    asn1_ret = mbedtls_asn1_get_tag( p, end_signer, &len,
+                MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE );
+    if( asn1_ret != 0 )
+        goto out;
+
+    ret  = mbedtls_x509_get_name( p, *p + len, &signer->issuer );
+    if( ret != 0 )
+        goto out;
+
+    signer->issuer_raw.len =  *p - signer->issuer_raw.p;
+
+    ret = mbedtls_x509_get_serial( p, end_signer, &signer->serial );
+    if( ret != 0 )
+        goto out;
+
+    ret = pkcs7_get_digest_algorithm( p, end_signer, &signer->alg_identifier );
+    if( ret != 0 )
+        goto out;
+
+    /* Assume authenticatedAttributes is nonexistent */
+
+    ret = pkcs7_get_digest_algorithm( p, end_signer, &signer->sig_alg_identifier );
+    if( ret != 0 )
+        goto out;
+
+    ret = pkcs7_get_signature( p, end_signer, &signer->sig );
+    if( ret != 0 )
+        goto out;
+
+    /* Do not permit any unauthenticated attributes */
+    if( *p != end_signer )
+        ret = MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO;
+
+out:
+    if( asn1_ret != 0 || ret != 0 )
+    {
+        pkcs7_free_signer_info( signer );
+        ret = MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO,
+                                    asn1_ret );
+    }
+
+    return( ret );
+}
+
+/**
+ * SignerInfos ::= SET of SignerInfo
+ * Return number of signers added to the signed data,
+ * 0 or higher is valid.
+ * Return negative error code for failure.
+ **/
+static int pkcs7_get_signers_info_set( unsigned char **p, unsigned char *end,
+                                       mbedtls_pkcs7_signer_info *signers_set )
+{
+    unsigned char *end_set;
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    int count = 0;
+    size_t len = 0;
+
+    ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
+                                | MBEDTLS_ASN1_SET );
+    if( ret != 0 )
+    {
+        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO, ret ) );
+    }
+
+    /* Detect zero signers */
+    if( len == 0 )
+    {
+        return( 0 );
+    }
+
+    end_set = *p + len;
+
+    ret = pkcs7_get_signer_info( p, end_set, signers_set );
+    if( ret != 0 )
+        return( ret );
+    count++;
+
+    mbedtls_pkcs7_signer_info *prev = signers_set;
+    while( *p != end_set )
+    {
+        mbedtls_pkcs7_signer_info *signer =
+            mbedtls_calloc( 1, sizeof( mbedtls_pkcs7_signer_info ) );
+        if( !signer )
+        {
+            ret = MBEDTLS_ERR_PKCS7_ALLOC_FAILED;
+            goto cleanup;
+        }
+
+        ret = pkcs7_get_signer_info( p, end_set, signer );
+        if( ret != 0 ) {
+            mbedtls_free( signer );
+            goto cleanup;
+        }
+        prev->next = signer;
+        prev = signer;
+        count++;
+    }
+
+    return( count );
+
+cleanup:
+    pkcs7_free_signer_info( signers_set );
+    mbedtls_pkcs7_signer_info *signer = signers_set->next;
+    while( signer != NULL )
+    {
+        prev = signer;
+        signer = signer->next;
+        pkcs7_free_signer_info( prev );
+        mbedtls_free( prev );
+    }
+    signers_set->next = NULL;
+    return( ret );
+}
+
+/**
+ * SignedData ::= SEQUENCE {
+ *      version Version,
+ *      digestAlgorithms DigestAlgorithmIdentifiers,
+ *      contentInfo ContentInfo,
+ *      certificates
+ *              [0] IMPLICIT ExtendedCertificatesAndCertificates
+ *                  OPTIONAL,
+ *      crls
+ *              [0] IMPLICIT CertificateRevocationLists OPTIONAL,
+ *      signerInfos SignerInfos }
+ */
+static int pkcs7_get_signed_data( unsigned char *buf, size_t buflen,
+                                  mbedtls_pkcs7_signed_data *signed_data )
+{
+    unsigned char *p = buf;
+    unsigned char *end = buf + buflen;
+    unsigned char *end_set;
+    size_t len = 0;
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    mbedtls_md_type_t md_alg;
+
+    ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED
+                                | MBEDTLS_ASN1_SEQUENCE );
+    if( ret != 0 )
+    {
+        return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PKCS7_INVALID_FORMAT, ret ) );
+    }
+
+    end_set = p + len;
+
+    /* Get version of signed data */
+    ret = pkcs7_get_version( &p, end_set, &signed_data->version );
+    if( ret != 0 )
+        return( ret );
+
+    /* Get digest algorithm */
+    ret = pkcs7_get_digest_algorithm_set( &p, end_set,
+            &signed_data->digest_alg_identifiers );
+    if( ret != 0 )
+        return( ret );
+
+    ret = mbedtls_oid_get_md_alg( &signed_data->digest_alg_identifiers, &md_alg );
+    if( ret != 0 )
+    {
+        return( MBEDTLS_ERR_PKCS7_INVALID_ALG );
+    }
+
+    /* Do not expect any content */
+    ret = pkcs7_get_content_info_type( &p, end_set, &signed_data->content.oid );
+    if( ret != 0 )
+        return( ret );
+
+    if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_DATA, &signed_data->content.oid ) )
+    {
+        return( MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO );
+    }
+
+    /* Look for certificates, there may or may not be any */
+    mbedtls_x509_crt_init( &signed_data->certs );
+    ret = pkcs7_get_certificates( &p, end_set, &signed_data->certs );
+    if( ret < 0 )
+        return( ret );
+
+    signed_data->no_of_certs = ret;
+
+    /*
+     * Currently CRLs are not supported. If CRL exist, the parsing will fail
+     * at next step of getting signers info and return error as invalid
+     * signer info.
+     */
+
+    signed_data->no_of_crls = 0;
+
+    /* Get signers info */
+    ret = pkcs7_get_signers_info_set( &p, end_set, &signed_data->signers );
+    if( ret < 0 )
+        return( ret );
+
+    signed_data->no_of_signers = ret;
+
+    /* Don't permit trailing data */
+    if ( p != end )
+        return( MBEDTLS_ERR_PKCS7_INVALID_FORMAT );
+
+    return( 0 );
+}
+
+int mbedtls_pkcs7_parse_der( mbedtls_pkcs7 *pkcs7, const unsigned char *buf,
+                             const size_t buflen )
+{
+    unsigned char *p;
+    unsigned char *end;
+    size_t len = 0;
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    int isoidset = 0;
+
+    if( pkcs7 == NULL )
+    {
+        return( MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA );
+    }
+
+    /* make an internal copy of the buffer for parsing */
+    pkcs7->raw.p = p = mbedtls_calloc( 1, buflen );
+    if( pkcs7->raw.p == NULL )
+    {
+        ret = MBEDTLS_ERR_PKCS7_ALLOC_FAILED;
+        goto out;
+    }
+    memcpy( p, buf, buflen );
+    pkcs7->raw.len = buflen;
+    end = p + buflen;
+
+    ret = pkcs7_get_content_info_type( &p, end, &pkcs7->content_type_oid );
+    if( ret != 0 )
+    {
+        len = buflen;
+        goto try_data;
+    }
+
+    if( ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_DATA, &pkcs7->content_type_oid )
+     || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_ENCRYPTED_DATA, &pkcs7->content_type_oid )
+     || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_ENVELOPED_DATA, &pkcs7->content_type_oid )
+     || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_SIGNED_AND_ENVELOPED_DATA, &pkcs7->content_type_oid )
+     || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_DIGESTED_DATA, &pkcs7->content_type_oid )
+     || ! MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_ENCRYPTED_DATA, &pkcs7->content_type_oid ) )
+    {
+        ret =  MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE;
+        goto out;
+    }
+
+    if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS7_SIGNED_DATA, &pkcs7->content_type_oid ) )
+    {
+        ret = MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA;
+        goto out;
+    }
+
+    isoidset = 1;
+
+    ret = pkcs7_get_next_content_len( &p, end, &len );
+    if( ret != 0 )
+        goto out;
+
+try_data:
+    ret = pkcs7_get_signed_data( p, len, &pkcs7->signed_data );
+    if ( ret != 0 )
+        goto out;
+
+    if ( !isoidset )
+    {
+        pkcs7->content_type_oid.tag = MBEDTLS_ASN1_OID;
+        pkcs7->content_type_oid.len = MBEDTLS_OID_SIZE( MBEDTLS_OID_PKCS7_SIGNED_DATA );
+        pkcs7->content_type_oid.p = (unsigned char *)MBEDTLS_OID_PKCS7_SIGNED_DATA;
+    }
+
+    ret = MBEDTLS_PKCS7_SIGNED_DATA;
+
+out:
+    if ( ret < 0 )
+        mbedtls_pkcs7_free( pkcs7 );
+
+    return( ret );
+}
+
+static int mbedtls_pkcs7_data_or_hash_verify( mbedtls_pkcs7 *pkcs7,
+                                             const mbedtls_x509_crt *cert,
+                                             const unsigned char *data,
+                                             size_t datalen,
+                                             const int is_data_hash )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    unsigned char *hash;
+    mbedtls_pk_context pk_cxt = cert->pk;
+    const mbedtls_md_info_t *md_info;
+    mbedtls_md_type_t md_alg;
+    mbedtls_pkcs7_signer_info *signer;
+
+    if( pkcs7->signed_data.no_of_signers == 0 )
+    {
+        return( MBEDTLS_ERR_PKCS7_INVALID_CERT );
+    }
+
+    if( mbedtls_x509_time_is_past( &cert->valid_to ) ||
+        mbedtls_x509_time_is_future( &cert->valid_from ))
+    {
+        return( MBEDTLS_ERR_PKCS7_CERT_DATE_INVALID );
+    }
+
+    /*
+     * Potential TODOs
+     * Currently we iterate over all signers and return success if any of them
+     * verify.
+     *
+     * However, we could make this better by checking against the certificate's
+     * identification and SignerIdentifier fields first. That would also allow
+     * us to distinguish between 'no signature for key' and 'signature for key
+     * failed to validate'.
+     *
+     * We could also cache hashes by md, so if there are several sigs all using
+     * the same algo we don't recalculate the hash each time.
+     */
+    for( signer = &pkcs7->signed_data.signers; signer; signer = signer->next )
+    {
+        ret = mbedtls_oid_get_md_alg( &signer->alg_identifier, &md_alg );
+        if( ret != 0 )
+        {
+            ret = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
+            continue;
+        }
+
+        md_info = mbedtls_md_info_from_type( md_alg );
+        if( md_info == NULL )
+        {
+            ret = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
+            continue;
+        }
+
+        hash = mbedtls_calloc( mbedtls_md_get_size( md_info ), 1 );
+        if( hash == NULL ) {
+            return( MBEDTLS_ERR_PKCS7_ALLOC_FAILED );
+        }
+        /* BEGIN must free hash before jumping out */
+        if( is_data_hash )
+        {
+            if( datalen != mbedtls_md_get_size( md_info ))
+                ret = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
+            else
+                memcpy(hash, data, datalen);
+        }
+        else
+        {
+            ret = mbedtls_md( md_info, data, datalen, hash );
+        }
+        if( ret != 0 )
+        {
+            ret = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
+            mbedtls_free( hash );
+            continue;
+        }
+
+        ret = mbedtls_pk_verify( &pk_cxt, md_alg, hash,
+                                 mbedtls_md_get_size( md_info ),
+                                 signer->sig.p, signer->sig.len );
+        mbedtls_free( hash );
+        /* END must free hash before jumping out */
+
+        if( ret == 0 )
+            break;
+    }
+
+    return( ret );
+}
+int mbedtls_pkcs7_signed_data_verify( mbedtls_pkcs7 *pkcs7,
+                                      const mbedtls_x509_crt *cert,
+                                      const unsigned char *data,
+                                      size_t datalen )
+{
+    return( mbedtls_pkcs7_data_or_hash_verify( pkcs7, cert, data, datalen, 0 ) );
+}
+
+int mbedtls_pkcs7_signed_hash_verify( mbedtls_pkcs7 *pkcs7,
+                                      const mbedtls_x509_crt *cert,
+                                      const unsigned char *hash,
+                                      size_t hashlen )
+{
+    return( mbedtls_pkcs7_data_or_hash_verify( pkcs7, cert, hash, hashlen, 1 ) );
+}
+
+/*
+ * Unallocate all pkcs7 data
+ */
+void mbedtls_pkcs7_free( mbedtls_pkcs7 *pkcs7 )
+{
+    mbedtls_pkcs7_signer_info *signer_cur;
+    mbedtls_pkcs7_signer_info *signer_prev;
+
+    if( pkcs7 == NULL || pkcs7->raw.p == NULL )
+        return;
+
+    mbedtls_free( pkcs7->raw.p );
+
+    mbedtls_x509_crt_free( &pkcs7->signed_data.certs );
+    mbedtls_x509_crl_free( &pkcs7->signed_data.crl );
+
+    signer_cur = pkcs7->signed_data.signers.next;
+    pkcs7_free_signer_info( &pkcs7->signed_data.signers );
+    while( signer_cur != NULL )
+    {
+        signer_prev = signer_cur;
+        signer_cur = signer_prev->next;
+        pkcs7_free_signer_info( signer_prev );
+        mbedtls_free( signer_prev );
+    }
+
+    pkcs7->raw.p = NULL;
+}
+
+#endif
diff --git a/library/platform_util.c b/library/platform_util.c
index 916a7f4..2b674f6 100644
--- a/library/platform_util.c
+++ b/library/platform_util.c
@@ -143,3 +143,20 @@
 void (*mbedtls_test_hook_test_fail)( const char *, int, const char *);
 #endif /* MBEDTLS_TEST_HOOKS */
 
+/*
+ * Provide external definitions of some inline functions so that the compiler
+ * has the option to not inline them
+ */
+extern inline void mbedtls_xor( unsigned char *r, const unsigned char *a, const unsigned char *b, size_t n );
+
+extern inline uint16_t mbedtls_get_unaligned_uint16( const void *p );
+
+extern inline void mbedtls_put_unaligned_uint16( void *p, uint16_t x );
+
+extern inline uint32_t mbedtls_get_unaligned_uint32( const void *p );
+
+extern inline void mbedtls_put_unaligned_uint32( void *p, uint32_t x );
+
+extern inline uint64_t mbedtls_get_unaligned_uint64( const void *p );
+
+extern inline void mbedtls_put_unaligned_uint64( void *p, uint64_t x );
diff --git a/library/poly1305.c b/library/poly1305.c
index 0850f66..4d0cdee 100644
--- a/library/poly1305.c
+++ b/library/poly1305.c
@@ -32,11 +32,6 @@
 
 #if !defined(MBEDTLS_POLY1305_ALT)
 
-#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
-    !defined(inline) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
 #define POLY1305_BLOCK_SIZE_BYTES ( 16U )
 
 /*
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 2ce5e43..cb5791f 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -877,20 +877,7 @@
     return( PSA_SUCCESS );
 }
 
-/** Get the description of a key given its identifier and policy constraints
- *  and lock it.
- *
- * The key must have allow all the usage flags set in \p usage. If \p alg is
- * nonzero, the key must allow operations with this algorithm. If \p alg is
- * zero, the algorithm is not checked.
- *
- * In case of a persistent key, the function loads the description of the key
- * into a key slot if not already done.
- *
- * On success, the returned key slot is locked. It is the responsibility of
- * the caller to unlock the key slot when it does not access it anymore.
- */
-static psa_status_t psa_get_and_lock_key_slot_with_policy(
+psa_status_t psa_get_and_lock_key_slot_with_policy(
     mbedtls_svc_key_id_t key,
     psa_key_slot_t **p_slot,
     psa_key_usage_t usage,
@@ -3467,8 +3454,8 @@
     status = psa_driver_wrapper_cipher_encrypt(
         &attributes, slot->key.data, slot->key.bytes,
         alg, local_iv, default_iv_length, input, input_length,
-        output + default_iv_length, output_size - default_iv_length,
-        output_length );
+        mbedtls_buffer_offset( output, default_iv_length ),
+        output_size - default_iv_length, output_length );
 
 exit:
     unlock_status = psa_unlock_key_slot( slot );
@@ -5736,63 +5723,46 @@
 /* Key agreement */
 /****************************************************************/
 
-#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH)
-static psa_status_t psa_key_agreement_ecdh( const uint8_t *peer_key,
+psa_status_t psa_key_agreement_raw_builtin( const psa_key_attributes_t *attributes,
+                                            const uint8_t *key_buffer,
+                                            size_t key_buffer_size,
+                                            psa_algorithm_t alg,
+                                            const uint8_t *peer_key,
                                             size_t peer_key_length,
-                                            const mbedtls_ecp_keypair *our_key,
                                             uint8_t *shared_secret,
                                             size_t shared_secret_size,
                                             size_t *shared_secret_length )
 {
-    mbedtls_ecp_keypair *their_key = NULL;
-    mbedtls_ecdh_context ecdh;
-    psa_status_t status;
-    size_t bits = 0;
-    psa_ecc_family_t curve = mbedtls_ecc_group_to_psa( our_key->grp.id, &bits );
-    mbedtls_ecdh_init( &ecdh );
-
-    status = mbedtls_psa_ecp_load_representation(
-                 PSA_KEY_TYPE_ECC_PUBLIC_KEY(curve),
-                 bits,
-                 peer_key,
-                 peer_key_length,
-                 &their_key );
-    if( status != PSA_SUCCESS )
-        goto exit;
-
-    status = mbedtls_to_psa_error(
-        mbedtls_ecdh_get_params( &ecdh, their_key, MBEDTLS_ECDH_THEIRS ) );
-    if( status != PSA_SUCCESS )
-        goto exit;
-    status = mbedtls_to_psa_error(
-        mbedtls_ecdh_get_params( &ecdh, our_key, MBEDTLS_ECDH_OURS ) );
-    if( status != PSA_SUCCESS )
-        goto exit;
-
-    status = mbedtls_to_psa_error(
-        mbedtls_ecdh_calc_secret( &ecdh,
-                                  shared_secret_length,
-                                  shared_secret, shared_secret_size,
-                                  mbedtls_psa_get_random,
-                                  MBEDTLS_PSA_RANDOM_STATE ) );
-    if( status != PSA_SUCCESS )
-        goto exit;
-    if( PSA_BITS_TO_BYTES( bits ) != *shared_secret_length )
-        status = PSA_ERROR_CORRUPTION_DETECTED;
-
-exit:
-    if( status != PSA_SUCCESS )
-        mbedtls_platform_zeroize( shared_secret, shared_secret_size );
-    mbedtls_ecdh_free( &ecdh );
-    mbedtls_ecp_keypair_free( their_key );
-    mbedtls_free( their_key );
-
-    return( status );
-}
+    switch( alg )
+    {
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH)
+        case PSA_ALG_ECDH:
+            return( mbedtls_psa_key_agreement_ecdh( attributes, key_buffer,
+                                                    key_buffer_size, alg,
+                                                    peer_key, peer_key_length,
+                                                    shared_secret,
+                                                    shared_secret_size,
+                                                    shared_secret_length ) );
 #endif /* MBEDTLS_PSA_BUILTIN_ALG_ECDH */
+        default:
+            (void) attributes;
+            (void) key_buffer;
+            (void) key_buffer_size;
+            (void) peer_key;
+            (void) peer_key_length;
+            (void) shared_secret;
+            (void) shared_secret_size;
+            (void) shared_secret_length;
+            return( PSA_ERROR_NOT_SUPPORTED );
+    }
+}
 
-#define PSA_KEY_AGREEMENT_MAX_SHARED_SECRET_SIZE MBEDTLS_ECP_MAX_BYTES
-
+/** Internal function for raw key agreement
+ *  Calls the driver wrapper which will hand off key agreement task
+ *  to the driver's implementation if a driver is present.
+ *  Fallback specified in the driver wrapper is built-in raw key agreement
+ *  (psa_key_agreement_raw_builtin).
+ */
 static psa_status_t psa_key_agreement_raw_internal( psa_algorithm_t alg,
                                                     psa_key_slot_t *private_key,
                                                     const uint8_t *peer_key,
@@ -5801,38 +5771,20 @@
                                                     size_t shared_secret_size,
                                                     size_t *shared_secret_length )
 {
-    switch( alg )
-    {
-#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH)
-        case PSA_ALG_ECDH:
-            if( ! PSA_KEY_TYPE_IS_ECC_KEY_PAIR( private_key->attr.type ) )
-                return( PSA_ERROR_INVALID_ARGUMENT );
-            mbedtls_ecp_keypair *ecp = NULL;
-            psa_status_t status = mbedtls_psa_ecp_load_representation(
-                                      private_key->attr.type,
-                                      private_key->attr.bits,
-                                      private_key->key.data,
-                                      private_key->key.bytes,
-                                      &ecp );
-            if( status != PSA_SUCCESS )
-                return( status );
-            status = psa_key_agreement_ecdh( peer_key, peer_key_length,
-                                             ecp,
-                                             shared_secret, shared_secret_size,
-                                             shared_secret_length );
-            mbedtls_ecp_keypair_free( ecp );
-            mbedtls_free( ecp );
-            return( status );
-#endif /* MBEDTLS_PSA_BUILTIN_ALG_ECDH */
-        default:
-            (void) private_key;
-            (void) peer_key;
-            (void) peer_key_length;
-            (void) shared_secret;
-            (void) shared_secret_size;
-            (void) shared_secret_length;
-            return( PSA_ERROR_NOT_SUPPORTED );
-    }
+    if( !PSA_ALG_IS_RAW_KEY_AGREEMENT( alg ) )
+        return( PSA_ERROR_NOT_SUPPORTED );
+
+    psa_key_attributes_t attributes = {
+      .core = private_key->attr
+    };
+
+    return( psa_driver_wrapper_key_agreement( &attributes,
+                                              private_key->key.data,
+                                              private_key->key.bytes, alg,
+                                              peer_key, peer_key_length,
+                                              shared_secret,
+                                              shared_secret_size,
+                                              shared_secret_length ) );
 }
 
 /* Note that if this function fails, you must call psa_key_derivation_abort()
@@ -5845,7 +5797,7 @@
                                                 size_t peer_key_length )
 {
     psa_status_t status;
-    uint8_t shared_secret[PSA_KEY_AGREEMENT_MAX_SHARED_SECRET_SIZE];
+    uint8_t shared_secret[PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE];
     size_t shared_secret_length = 0;
     psa_algorithm_t ka_alg = PSA_ALG_KEY_AGREEMENT_GET_BASE( operation->alg );
 
@@ -6046,7 +5998,7 @@
     if( status != PSA_SUCCESS )
         return( status );
     /* Breaking up a request into smaller chunks is currently not supported
-     * for the extrernal RNG interface. */
+     * for the external RNG interface. */
     if( output_length != output_size )
         return( PSA_ERROR_INSUFFICIENT_ENTROPY );
     return( PSA_SUCCESS );
diff --git a/library/psa_crypto_aead.h b/library/psa_crypto_aead.h
index 17b3953..70f714a 100644
--- a/library/psa_crypto_aead.h
+++ b/library/psa_crypto_aead.h
@@ -508,4 +508,4 @@
 psa_status_t mbedtls_psa_aead_abort(
     mbedtls_psa_aead_operation_t *operation );
 
-#endif /* PSA_CRYPTO_AEAD */
+#endif /* PSA_CRYPTO_AEAD_H */
diff --git a/library/psa_crypto_cipher.c b/library/psa_crypto_cipher.c
index 70dc74d..91a0e3b 100644
--- a/library/psa_crypto_cipher.c
+++ b/library/psa_crypto_cipher.c
@@ -516,10 +516,10 @@
     if( status != PSA_SUCCESS )
         goto exit;
 
-    status = mbedtls_psa_cipher_finish( &operation,
-                                        output + update_output_length,
-                                        output_size - update_output_length,
-                                        &finish_output_length );
+    status = mbedtls_psa_cipher_finish(
+        &operation,
+        mbedtls_buffer_offset( output, update_output_length ),
+        output_size - update_output_length, &finish_output_length );
     if( status != PSA_SUCCESS )
         goto exit;
 
@@ -563,17 +563,20 @@
             goto exit;
     }
 
-    status = mbedtls_psa_cipher_update( &operation, input + operation.iv_length,
-                                        input_length - operation.iv_length,
-                                        output, output_size, &olength );
+    status = mbedtls_psa_cipher_update(
+        &operation,
+        mbedtls_buffer_offset_const( input, operation.iv_length ),
+        input_length - operation.iv_length,
+        output, output_size, &olength );
     if( status != PSA_SUCCESS )
         goto exit;
 
     accumulated_length = olength;
 
-    status = mbedtls_psa_cipher_finish( &operation, output + accumulated_length,
-                                        output_size - accumulated_length,
-                                        &olength );
+    status = mbedtls_psa_cipher_finish(
+        &operation,
+        mbedtls_buffer_offset( output, accumulated_length ),
+        output_size - accumulated_length, &olength );
     if( status != PSA_SUCCESS )
         goto exit;
 
diff --git a/library/psa_crypto_core.h b/library/psa_crypto_core.h
index 9863848..614cad1 100644
--- a/library/psa_crypto_core.h
+++ b/library/psa_crypto_core.h
@@ -183,6 +183,24 @@
 }
 #endif
 
+/** Get the description of a key given its identifier and policy constraints
+ *  and lock it.
+ *
+ * The key must have allow all the usage flags set in \p usage. If \p alg is
+ * nonzero, the key must allow operations with this algorithm. If \p alg is
+ * zero, the algorithm is not checked.
+ *
+ * In case of a persistent key, the function loads the description of the key
+ * into a key slot if not already done.
+ *
+ * On success, the returned key slot is locked. It is the responsibility of
+ * the caller to unlock the key slot when it does not access it anymore.
+ */
+psa_status_t psa_get_and_lock_key_slot_with_policy( mbedtls_svc_key_id_t key,
+                                                    psa_key_slot_t **p_slot,
+                                                    psa_key_usage_t usage,
+                                                    psa_algorithm_t alg );
+
 /** Completely wipe a slot in memory, including its policy.
  *
  * Persistent storage is not affected.
@@ -531,4 +549,62 @@
  */
 psa_status_t psa_validate_unstructured_key_bit_size( psa_key_type_t type,
                                                      size_t bits );
+
+/** Perform a key agreement and return the raw shared secret, using
+    built-in raw key agreement functions.
+ *
+ * \note The signature of this function is that of a PSA driver
+ *       key_agreement entry point. This function behaves as a key_agreement
+ *       entry point as defined in the PSA driver interface specification for
+ *       transparent drivers.
+ *
+ * \param[in]  attributes           The attributes of the key to use for the
+ *                                  operation.
+ * \param[in]  key_buffer           The buffer containing the private key
+ *                                  context.
+ * \param[in]  key_buffer_size      Size of the \p key_buffer buffer in
+ *                                  bytes.
+ * \param[in]  alg                  A key agreement algorithm that is
+ *                                  compatible with the type of the key.
+ * \param[in]  peer_key             The buffer containing the key context
+ *                                  of the peer's public key.
+ * \param[in]  peer_key_length      Size of the \p peer_key buffer in
+ *                                  bytes.
+ * \param[out] shared_secret        The buffer to which the shared secret
+ *                                  is to be written.
+ * \param[in]  shared_secret_size   Size of the \p shared_secret buffer in
+ *                                  bytes.
+ * \param[out] shared_secret_length On success, the number of bytes that make
+ *                                  up the returned shared secret.
+ * \retval #PSA_SUCCESS
+ *         Success. Shared secret successfully calculated.
+ * \retval #PSA_ERROR_INVALID_HANDLE
+ * \retval #PSA_ERROR_NOT_PERMITTED
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ *         \p alg is not a key agreement algorithm, or
+ *         \p private_key is not compatible with \p alg,
+ *         or \p peer_key is not valid for \p alg or not compatible with
+ *         \p private_key.
+ * \retval #PSA_ERROR_BUFFER_TOO_SMALL
+ *         \p shared_secret_size is too small
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ *         \p alg is not a supported key agreement algorithm.
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY
+ * \retval #PSA_ERROR_COMMUNICATION_FAILURE
+ * \retval #PSA_ERROR_HARDWARE_FAILURE
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED
+ * \retval #PSA_ERROR_STORAGE_FAILURE
+ * \retval #PSA_ERROR_BAD_STATE
+ */
+psa_status_t psa_key_agreement_raw_builtin(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer,
+    size_t key_buffer_size,
+    psa_algorithm_t alg,
+    const uint8_t *peer_key,
+    size_t peer_key_length,
+    uint8_t *shared_secret,
+    size_t shared_secret_size,
+    size_t *shared_secret_length );
+
 #endif /* PSA_CRYPTO_CORE_H */
diff --git a/library/psa_crypto_driver_wrappers.h b/library/psa_crypto_driver_wrappers.h
index ee23b6f..a19d7ec 100644
--- a/library/psa_crypto_driver_wrappers.h
+++ b/library/psa_crypto_driver_wrappers.h
@@ -357,6 +357,20 @@
     size_t output_size,
     size_t *output_length );
 
+/*
+ * Raw Key Agreement
+ */
+psa_status_t psa_driver_wrapper_key_agreement(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer,
+    size_t key_buffer_size,
+    psa_algorithm_t alg,
+    const uint8_t *peer_key,
+    size_t peer_key_length,
+    uint8_t *shared_secret,
+    size_t shared_secret_size,
+    size_t *shared_secret_length );
+
 #endif /* PSA_CRYPTO_DRIVER_WRAPPERS_H */
 
 /* End of automatically generated file. */
diff --git a/library/psa_crypto_ecp.c b/library/psa_crypto_ecp.c
index 29f53b9..537a748 100644
--- a/library/psa_crypto_ecp.c
+++ b/library/psa_crypto_ecp.c
@@ -33,6 +33,7 @@
 #include "mbedtls/platform.h"
 
 #include <mbedtls/ecdsa.h>
+#include <mbedtls/ecdh.h>
 #include <mbedtls/ecp.h>
 #include <mbedtls/error.h>
 
@@ -464,4 +465,76 @@
 #endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
         * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) */
 
+/****************************************************************/
+/* ECDH Key Agreement */
+/****************************************************************/
+
+#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH)
+psa_status_t mbedtls_psa_key_agreement_ecdh(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer, size_t key_buffer_size,
+    psa_algorithm_t alg, const uint8_t *peer_key, size_t peer_key_length,
+    uint8_t *shared_secret, size_t shared_secret_size,
+    size_t *shared_secret_length )
+{
+    psa_status_t status;
+    if( ! PSA_KEY_TYPE_IS_ECC_KEY_PAIR( attributes->core.type ) ||
+        ! PSA_ALG_IS_ECDH(alg) )
+                return( PSA_ERROR_INVALID_ARGUMENT );
+    mbedtls_ecp_keypair *ecp = NULL;
+    status = mbedtls_psa_ecp_load_representation(
+                attributes->core.type,
+                attributes->core.bits,
+                key_buffer,
+                key_buffer_size,
+                &ecp );
+    if( status != PSA_SUCCESS )
+        return( status );
+    mbedtls_ecp_keypair *their_key = NULL;
+    mbedtls_ecdh_context ecdh;
+    size_t bits = 0;
+    psa_ecc_family_t curve = mbedtls_ecc_group_to_psa( ecp->grp.id, &bits );
+    mbedtls_ecdh_init( &ecdh );
+
+    status = mbedtls_psa_ecp_load_representation(
+                PSA_KEY_TYPE_ECC_PUBLIC_KEY(curve),
+                bits,
+                peer_key,
+                peer_key_length,
+                &their_key );
+    if( status != PSA_SUCCESS )
+        goto exit;
+
+    status = mbedtls_to_psa_error(
+        mbedtls_ecdh_get_params( &ecdh, their_key, MBEDTLS_ECDH_THEIRS ) );
+    if( status != PSA_SUCCESS )
+        goto exit;
+    status = mbedtls_to_psa_error(
+        mbedtls_ecdh_get_params( &ecdh, ecp, MBEDTLS_ECDH_OURS ) );
+    if( status != PSA_SUCCESS )
+        goto exit;
+
+    status = mbedtls_to_psa_error(
+        mbedtls_ecdh_calc_secret( &ecdh,
+                                shared_secret_length,
+                                shared_secret, shared_secret_size,
+                                mbedtls_psa_get_random,
+                                MBEDTLS_PSA_RANDOM_STATE ) );
+    if( status != PSA_SUCCESS )
+        goto exit;
+    if( PSA_BITS_TO_BYTES( bits ) != *shared_secret_length )
+        status = PSA_ERROR_CORRUPTION_DETECTED;
+exit:
+    if( status != PSA_SUCCESS )
+        mbedtls_platform_zeroize( shared_secret, shared_secret_size );
+    mbedtls_ecdh_free( &ecdh );
+    mbedtls_ecp_keypair_free( their_key );
+    mbedtls_free( their_key );
+    mbedtls_ecp_keypair_free( ecp );
+    mbedtls_free( ecp );
+    return( status );
+}
+#endif /* MBEDTLS_PSA_BUILTIN_ALG_ECDH */
+
+
 #endif /* MBEDTLS_PSA_CRYPTO_C */
diff --git a/library/psa_crypto_ecp.h b/library/psa_crypto_ecp.h
index 429c062..386e87a 100644
--- a/library/psa_crypto_ecp.h
+++ b/library/psa_crypto_ecp.h
@@ -218,4 +218,53 @@
     const uint8_t *key_buffer, size_t key_buffer_size,
     psa_algorithm_t alg, const uint8_t *hash, size_t hash_length,
     const uint8_t *signature, size_t signature_length );
+
+
+/** Perform a key agreement and return the raw ECDH shared secret.
+ *
+ * \note The signature of this function is that of a PSA driver
+ *       key_agreement entry point. This function behaves as a key_agreement
+ *       entry point as defined in the PSA driver interface specification for
+ *       transparent drivers.
+ *
+ * \param[in]  attributes           The attributes of the key to use for the
+ *                                  operation.
+ * \param[in]  key_buffer           The buffer containing the private key
+ *                                  context.
+ * \param[in]  key_buffer_size      Size of the \p key_buffer buffer in
+ *                                  bytes.
+ * \param[in]  alg                  A key agreement algorithm that is
+ *                                  compatible with the type of the key.
+ * \param[in]  peer_key             The buffer containing the key context
+ *                                  of the peer's public key.
+ * \param[in]  peer_key_length      Size of the \p peer_key buffer in
+ *                                  bytes.
+ * \param[out] shared_secret        The buffer to which the shared secret
+ *                                  is to be written.
+ * \param[in]  shared_secret_size   Size of the \p shared_secret buffer in
+ *                                  bytes.
+ * \param[out] shared_secret_length On success, the number of bytes that make
+ *                                  up the returned shared secret.
+ * \retval #PSA_SUCCESS
+ *         Success. Shared secret successfully calculated.
+ * \retval #PSA_ERROR_INVALID_HANDLE
+ * \retval #PSA_ERROR_NOT_PERMITTED
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ *         \p alg is not a key agreement algorithm, or
+ *         \p private_key is not compatible with \p alg,
+ *         or \p peer_key is not valid for \p alg or not compatible with
+ *         \p private_key.
+ * \retval #PSA_ERROR_BUFFER_TOO_SMALL
+ *         \p shared_secret_size is too small
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ *         \p alg is not a supported key agreement algorithm.
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED
+ */
+psa_status_t mbedtls_psa_key_agreement_ecdh(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer, size_t key_buffer_size,
+    psa_algorithm_t alg, const uint8_t *peer_key, size_t peer_key_length,
+    uint8_t *shared_secret, size_t shared_secret_size,
+    size_t *shared_secret_length );
 #endif /* PSA_CRYPTO_ECP_H */
diff --git a/library/psa_crypto_its.h b/library/psa_crypto_its.h
index 3a3f49a..1b8dc20 100644
--- a/library/psa_crypto_its.h
+++ b/library/psa_crypto_its.h
@@ -73,7 +73,7 @@
  * \return      A status indicating the success/failure of the operation
  *
  * \retval      #PSA_SUCCESS                     The operation completed successfully
- * \retval      #PSA_ERROR_NOT_PERMITTED         The operation failed because the provided `uid` value was already created with PSA_STORAGE_WRITE_ONCE_FLAG
+ * \retval      #PSA_ERROR_NOT_PERMITTED         The operation failed because the provided `uid` value was already created with PSA_STORAGE_FLAG_WRITE_ONCE
  * \retval      #PSA_ERROR_NOT_SUPPORTED         The operation failed because one or more of the flags provided in `create_flags` is not supported or is not valid
  * \retval      #PSA_ERROR_INSUFFICIENT_STORAGE  The operation failed because there was insufficient space on the storage medium
  * \retval      #PSA_ERROR_STORAGE_FAILURE       The operation failed because the physical storage has failed (Fatal error)
@@ -137,7 +137,7 @@
  *
  * \retval      #PSA_SUCCESS                  The operation completed successfully
  * \retval      #PSA_ERROR_DOES_NOT_EXIST     The operation failed because the provided key value was not found in the storage
- * \retval      #PSA_ERROR_NOT_PERMITTED      The operation failed because the provided key value was created with PSA_STORAGE_WRITE_ONCE_FLAG
+ * \retval      #PSA_ERROR_NOT_PERMITTED      The operation failed because the provided key value was created with PSA_STORAGE_FLAG_WRITE_ONCE
  * \retval      #PSA_ERROR_STORAGE_FAILURE    The operation failed because the physical storage has failed (Fatal error)
  */
 psa_status_t psa_its_remove(psa_storage_uid_t uid);
diff --git a/library/psa_crypto_pake.c b/library/psa_crypto_pake.c
index 870b5b5..da66dae 100644
--- a/library/psa_crypto_pake.c
+++ b/library/psa_crypto_pake.c
@@ -197,9 +197,14 @@
 psa_status_t psa_pake_setup( psa_pake_operation_t *operation,
                              const psa_pake_cipher_suite_t *cipher_suite)
 {
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
     /* A context must be freshly initialized before it can be set up. */
     if( operation->alg != PSA_ALG_NONE )
-        return( PSA_ERROR_BAD_STATE );
+    {
+        status = PSA_ERROR_BAD_STATE;
+        goto error;
+    }
 
     if( cipher_suite == NULL ||
         PSA_ALG_IS_PAKE(cipher_suite->algorithm ) == 0 ||
@@ -207,7 +212,8 @@
           cipher_suite->type != PSA_PAKE_PRIMITIVE_TYPE_DH ) ||
         PSA_ALG_IS_HASH( cipher_suite->hash ) == 0 )
     {
-        return( PSA_ERROR_INVALID_ARGUMENT );
+        status = PSA_ERROR_INVALID_ARGUMENT;
+        goto error;
     }
 
 #if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE)
@@ -218,7 +224,8 @@
             cipher_suite->bits != 256 ||
             cipher_suite->hash != PSA_ALG_SHA_256 )
         {
-            return( PSA_ERROR_NOT_SUPPORTED );
+            status = PSA_ERROR_NOT_SUPPORTED;
+            goto error;
         }
 
         operation->alg = cipher_suite->algorithm;
@@ -238,7 +245,11 @@
     }
     else
 #endif
-    return( PSA_ERROR_NOT_SUPPORTED );
+    status = PSA_ERROR_NOT_SUPPORTED;
+
+error:
+    psa_pake_abort( operation );
+    return status;
 }
 
 psa_status_t psa_pake_set_password_key( psa_pake_operation_t *operation,
@@ -248,16 +259,18 @@
     psa_key_attributes_t attributes = psa_key_attributes_init();
     psa_key_type_t type;
     psa_key_usage_t usage;
+    psa_key_slot_t *slot = NULL;
 
     if( operation->alg == PSA_ALG_NONE ||
         operation->state != PSA_PAKE_STATE_SETUP )
     {
-        return( PSA_ERROR_BAD_STATE );
+        status = PSA_ERROR_BAD_STATE;
+        goto error;
     }
 
     status = psa_get_key_attributes( password, &attributes );
     if( status != PSA_SUCCESS )
-        return( status );
+        goto error;
 
     type = psa_get_key_type( &attributes );
     usage = psa_get_key_usage_flags( &attributes );
@@ -267,56 +280,106 @@
     if( type != PSA_KEY_TYPE_PASSWORD &&
         type != PSA_KEY_TYPE_PASSWORD_HASH )
     {
-        return( PSA_ERROR_INVALID_ARGUMENT );
+        status = PSA_ERROR_INVALID_ARGUMENT;
+        goto error;
     }
 
-    if( ( usage & PSA_KEY_USAGE_DERIVE ) == 0 )
-        return( PSA_ERROR_NOT_PERMITTED );
+    if( ( usage & PSA_KEY_USAGE_DERIVE ) == 0 ) {
+        status = PSA_ERROR_NOT_PERMITTED;
+        goto error;
+    }
 
-    operation->password = password;
+    if( operation->password != NULL )
+        return( PSA_ERROR_BAD_STATE );
+
+    status = psa_get_and_lock_key_slot_with_policy( password, &slot,
+                                                    PSA_KEY_USAGE_DERIVE,
+                                                    PSA_ALG_JPAKE );
+    if( status != PSA_SUCCESS )
+        return( status );
+
+    operation->password = mbedtls_calloc( 1, slot->key.bytes );
+    if( operation->password == NULL )
+    {
+        psa_unlock_key_slot( slot );
+        return( PSA_ERROR_INSUFFICIENT_MEMORY );
+    }
+    memcpy( operation->password, slot->key.data, slot->key.bytes );
+    operation->password_len = slot->key.bytes;
+
+    status = psa_unlock_key_slot( slot );
+    if( status != PSA_SUCCESS )
+        return( status );
 
     return( PSA_SUCCESS );
+
+error:
+    psa_pake_abort(operation);
+    return( status );
 }
 
 psa_status_t psa_pake_set_user( psa_pake_operation_t *operation,
                                 const uint8_t *user_id,
                                 size_t user_id_len )
 {
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
     if( operation->alg == PSA_ALG_NONE ||
         operation->state != PSA_PAKE_STATE_SETUP )
     {
-        return( PSA_ERROR_BAD_STATE );
+        status = PSA_ERROR_BAD_STATE;
+        goto error;
     }
 
     if( user_id_len == 0 || user_id == NULL )
-        return( PSA_ERROR_INVALID_ARGUMENT );
+    {
+        status = PSA_ERROR_INVALID_ARGUMENT;
+        goto error;
+    }
 
-    return( PSA_ERROR_NOT_SUPPORTED );
+    status = PSA_ERROR_NOT_SUPPORTED;
+
+error:
+    psa_pake_abort(operation);
+    return( status );
 }
 
 psa_status_t psa_pake_set_peer( psa_pake_operation_t *operation,
                                 const uint8_t *peer_id,
                                 size_t peer_id_len )
 {
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
     if( operation->alg == PSA_ALG_NONE ||
         operation->state != PSA_PAKE_STATE_SETUP )
     {
-        return( PSA_ERROR_BAD_STATE );
+        status = PSA_ERROR_BAD_STATE;
+        goto error;
     }
 
     if( peer_id_len == 0 || peer_id == NULL )
-        return( PSA_ERROR_INVALID_ARGUMENT );
+    {
+        status = PSA_ERROR_INVALID_ARGUMENT;
+        goto error;
+    }
 
-    return( PSA_ERROR_NOT_SUPPORTED );
+    status = PSA_ERROR_NOT_SUPPORTED;
+
+error:
+    psa_pake_abort(operation);
+    return( status );
 }
 
 psa_status_t psa_pake_set_role( psa_pake_operation_t *operation,
                                 psa_pake_role_t role )
 {
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
     if( operation->alg == PSA_ALG_NONE ||
         operation->state != PSA_PAKE_STATE_SETUP )
     {
-        return( PSA_ERROR_BAD_STATE );
+        status = PSA_ERROR_BAD_STATE;
+        goto error;
     }
 
     if( role != PSA_PAKE_ROLE_NONE &&
@@ -325,7 +388,8 @@
         role != PSA_PAKE_ROLE_CLIENT &&
         role != PSA_PAKE_ROLE_SERVER )
     {
-        return( PSA_ERROR_INVALID_ARGUMENT );
+        status = PSA_ERROR_INVALID_ARGUMENT;
+        goto error;
     }
 
 #if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE)
@@ -341,16 +405,18 @@
     }
     else
 #endif
-        return( PSA_ERROR_NOT_SUPPORTED );
+        status = PSA_ERROR_NOT_SUPPORTED;
+
+error:
+    psa_pake_abort(operation);
+    return( status );
 }
 
 #if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE)
 static psa_status_t psa_pake_ecjpake_setup( psa_pake_operation_t *operation )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     mbedtls_ecjpake_role role;
-    psa_key_slot_t *slot = NULL;
 
     if( operation->role == PSA_PAKE_ROLE_CLIENT )
         role = MBEDTLS_ECJPAKE_CLIENT;
@@ -359,22 +425,20 @@
     else
         return( PSA_ERROR_BAD_STATE );
 
-    if( psa_is_valid_key_id( operation->password, 1 ) == 0 )
+    if( operation->password_len == 0 )
         return( PSA_ERROR_BAD_STATE );
 
-    status = psa_get_and_lock_key_slot( operation->password, &slot );
-    if( status != PSA_SUCCESS )
-        return( status );
-
-
     ret = mbedtls_ecjpake_setup( &operation->ctx.ecjpake,
                                  role,
                                  MBEDTLS_MD_SHA256,
                                  MBEDTLS_ECP_DP_SECP256R1,
-                                 slot->key.data, slot->key.bytes );
+                                 operation->password,
+                                 operation->password_len );
 
-    psa_unlock_key_slot( slot );
-    slot = NULL;
+    mbedtls_platform_zeroize( operation->password, operation->password_len );
+    mbedtls_free( operation->password );
+    operation->password = NULL;
+    operation->password_len = 0;
 
     if( ret != 0 )
         return( mbedtls_ecjpake_to_psa_error( ret ) );
@@ -795,7 +859,10 @@
         operation->state != PSA_PAKE_STATE_READY ||
         operation->input_step != PSA_PAKE_STEP_DERIVE ||
         operation->output_step != PSA_PAKE_STEP_DERIVE )
-        return( PSA_ERROR_BAD_STATE );
+    {
+        status = PSA_ERROR_BAD_STATE;
+        goto error;
+    }
 
 #if defined(MBEDTLS_PSA_BUILTIN_ALG_JPAKE)
     if( operation->alg == PSA_ALG_JPAKE )
@@ -825,7 +892,13 @@
     }
     else
 #endif
-    return( PSA_ERROR_NOT_SUPPORTED );
+    status = PSA_ERROR_NOT_SUPPORTED;
+
+error:
+    psa_key_derivation_abort( output );
+    psa_pake_abort( operation );
+
+    return( status );
 }
 
 psa_status_t psa_pake_abort(psa_pake_operation_t * operation)
@@ -840,7 +913,11 @@
     {
         operation->input_step = PSA_PAKE_STEP_INVALID;
         operation->output_step = PSA_PAKE_STEP_INVALID;
-        operation->password = MBEDTLS_SVC_KEY_ID_INIT;
+        if( operation->password_len > 0 )
+            mbedtls_platform_zeroize( operation->password, operation->password_len );
+        mbedtls_free( operation->password );
+        operation->password = NULL;
+        operation->password_len = 0;
         operation->role = PSA_PAKE_ROLE_NONE;
         mbedtls_platform_zeroize( operation->buffer, MBEDTLS_PSA_PAKE_BUFFER_SIZE );
         operation->buffer_length = 0;
diff --git a/library/psa_crypto_rsa.h b/library/psa_crypto_rsa.h
index 197caa8..5835c6f 100644
--- a/library/psa_crypto_rsa.h
+++ b/library/psa_crypto_rsa.h
@@ -249,7 +249,7 @@
  * \retval #PSA_ERROR_INSUFFICIENT_MEMORY
  * \retval #PSA_ERROR_COMMUNICATION_FAILURE
  * \retval #PSA_ERROR_HARDWARE_FAILURE
- * \retval #PSA_ERROR_TAMPERING_DETECTED
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED
  * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY
  * \retval #PSA_ERROR_BAD_STATE
  *         The library has not been previously initialized by psa_crypto_init().
@@ -306,7 +306,7 @@
  * \retval #PSA_ERROR_INSUFFICIENT_MEMORY
  * \retval #PSA_ERROR_COMMUNICATION_FAILURE
  * \retval #PSA_ERROR_HARDWARE_FAILURE
- * \retval #PSA_ERROR_TAMPERING_DETECTED
+ * \retval #PSA_ERROR_CORRUPTION_DETECTED
  * \retval #PSA_ERROR_INSUFFICIENT_ENTROPY
  * \retval #PSA_ERROR_INVALID_PADDING
  * \retval #PSA_ERROR_BAD_STATE
diff --git a/library/psa_crypto_se.h b/library/psa_crypto_se.h
index 549dfb6..693c3ea 100644
--- a/library/psa_crypto_se.h
+++ b/library/psa_crypto_se.h
@@ -139,7 +139,7 @@
     psa_se_drv_table_entry_t *driver,
     psa_key_slot_number_t *slot_number );
 
-/** Destoy a key in a secure element.
+/** Destroy a key in a secure element.
  *
  * This function calls the relevant driver method to destroy a key
  * and updates the driver's persistent data.
diff --git a/library/ssl_client.c b/library/ssl_client.c
index 0f0ea1d..e838845 100644
--- a/library/ssl_client.c
+++ b/library/ssl_client.c
@@ -518,18 +518,22 @@
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2) && defined(MBEDTLS_SSL_PROTO_DTLS)
     if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
     {
-        unsigned char cookie_len = 0;
+#if !defined(MBEDTLS_SSL_PROTO_TLS1_3)
+        uint8_t cookie_len = 0;
+#else
+        uint16_t cookie_len = 0;
+#endif /* !MBEDTLS_SSL_PROTO_TLS1_3 */
 
         if( handshake->cookie != NULL )
         {
             MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, cookie",
                                    handshake->cookie,
-                                   handshake->verify_cookie_len );
-            cookie_len = handshake->verify_cookie_len;
+                                   handshake->cookie_len );
+            cookie_len = handshake->cookie_len;
         }
 
         MBEDTLS_SSL_CHK_BUF_PTR( p, end, cookie_len + 1 );
-        *p++ = cookie_len;
+        *p++ = ( unsigned char )cookie_len;
         if( cookie_len > 0 )
         {
             memcpy( p, handshake->cookie, cookie_len );
@@ -784,7 +788,7 @@
 
     /*
      * Generate the random bytes, except when responding to a verify request
-     * where we MUST reuse the previoulsy generated random bytes
+     * where we MUST reuse the previously generated random bytes
      * (RFC 6347 4.2.1).
      */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
diff --git a/library/ssl_misc.h b/library/ssl_misc.h
index ad8754c..8254964 100644
--- a/library/ssl_misc.h
+++ b/library/ssl_misc.h
@@ -50,17 +50,13 @@
 #include "mbedtls/sha512.h"
 #endif
 
-#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) && \
+    !defined(MBEDTLS_USE_PSA_CRYPTO)
 #include "mbedtls/ecjpake.h"
 #endif
 
 #include "common.h"
 
-#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
-    !defined(inline) && !defined(__cplusplus)
-#define inline __inline
-#endif
-
 /* Shorthand for restartable ECC */
 #if defined(MBEDTLS_ECP_RESTARTABLE) && \
     defined(MBEDTLS_SSL_CLI_C) && \
@@ -147,7 +143,7 @@
               MBEDTLS_SSL_EXT_MASK( TRUNCATED_HMAC )                         | \
               MBEDTLS_SSL_EXT_MASK( UNRECOGNIZED ) )
 
-/* RFC 8446 section 4.2. Allowed extensions for ClienHello */
+/* RFC 8446 section 4.2. Allowed extensions for ClientHello */
 #define MBEDTLS_SSL_TLS1_3_ALLOWED_EXTS_OF_CH                                  \
             ( MBEDTLS_SSL_EXT_MASK( SERVERNAME )                             | \
               MBEDTLS_SSL_EXT_MASK( MAX_FRAGMENT_LENGTH )                    | \
@@ -776,7 +772,13 @@
 #endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */
 
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    psa_pake_operation_t psa_pake_ctx;        /*!< EC J-PAKE key exchange */
+    mbedtls_svc_key_id_t psa_pake_password;
+    uint8_t psa_pake_ctx_is_ok;
+#else
     mbedtls_ecjpake_context ecjpake_ctx;        /*!< EC J-PAKE key exchange */
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
 #if defined(MBEDTLS_SSL_CLI_C)
     unsigned char *ecjpake_cache;               /*!< Cache for ClientHello ext */
     size_t ecjpake_cache_len;                   /*!< Length of cached data */
@@ -844,19 +846,33 @@
     } buffering;
 
 #if defined(MBEDTLS_SSL_CLI_C) && \
-    ( defined(MBEDTLS_SSL_PROTO_DTLS) || defined(MBEDTLS_SSL_PROTO_TLS1_3) )
-    unsigned char *cookie;              /*!<  HelloVerifyRequest cookie for DTLS
-                                         *    HelloRetryRequest cookie for TLS 1.3 */
+    ( defined(MBEDTLS_SSL_PROTO_DTLS) || \
+      defined(MBEDTLS_SSL_PROTO_TLS1_3) )
+    unsigned char *cookie;              /*!< HelloVerifyRequest cookie for DTLS
+                                         *   HelloRetryRequest cookie for TLS 1.3 */
+#if !defined(MBEDTLS_SSL_PROTO_TLS1_3)
+    /* RFC 6347 page 15
+       ...
+       opaque cookie<0..2^8-1>;
+       ...
+     */
+    uint8_t cookie_len;
+#else
+    /* RFC 8446 page 39
+       ...
+       opaque cookie<0..2^16-1>;
+       ...
+       If TLS1_3 is enabled, the max length is 2^16 - 1
+     */
+    uint16_t cookie_len;                /*!< DTLS: HelloVerifyRequest cookie length
+                                         *   TLS1_3: HelloRetryRequest cookie length */
+#endif
 #endif /* MBEDTLS_SSL_CLI_C &&
-          ( MBEDTLS_SSL_PROTO_DTLS || MBEDTLS_SSL_PROTO_TLS1_3 ) */
-#if defined(MBEDTLS_SSL_PROTO_DTLS)
-    unsigned char verify_cookie_len;    /*!<  Cli: HelloVerifyRequest cookie
-                                         *    length
-                                         *    Srv: flag for sending a cookie */
-#endif /* MBEDTLS_SSL_PROTO_DTLS */
-#if defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_SSL_PROTO_TLS1_3)
-    uint16_t hrr_cookie_len;            /*!<  HelloRetryRequest cookie length */
-#endif /* MBEDTLS_SSL_CLI_C && MBEDTLS_SSL_PROTO_TLS1_3 */
+          ( MBEDTLS_SSL_PROTO_DTLS ||
+            MBEDTLS_SSL_PROTO_TLS1_3 ) */
+#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_PROTO_DTLS)
+    unsigned char cookie_verify_result; /*!< Srv: flag for sending a cookie */
+#endif /* MBEDTLS_SSL_SRV_C && MBEDTLS_SSL_PROTO_DTLS */
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
     unsigned int out_msg_seq;           /*!<  Outgoing handshake sequence number */
@@ -888,13 +904,6 @@
     uint16_t mtu;                       /*!<  Handshake mtu, used to fragment outgoing messages */
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
 
-#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
-    /*! TLS 1.3 transforms for 0-RTT and encrypted handshake messages.
-     *  Those pointers own the transforms they reference. */
-    mbedtls_ssl_transform *transform_handshake;
-    mbedtls_ssl_transform *transform_earlydata;
-#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
-
     /*
      * Checksum contexts
      */
@@ -979,6 +988,8 @@
     unsigned char *certificate_request_context;
 #endif
 
+    /** TLS 1.3 transform for encrypted handshake messages. */
+    mbedtls_ssl_transform *transform_handshake;
     union
     {
         unsigned char early    [MBEDTLS_TLS1_3_MD_MAX_SIZE];
@@ -987,6 +998,11 @@
     } tls13_master_secrets;
 
     mbedtls_ssl_tls13_handshake_secrets tls13_hs_secrets;
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+    mbedtls_ssl_tls13_early_secrets tls13_early_secrets;
+    /** TLS 1.3 transform for early data and handshake messages. */
+    mbedtls_ssl_transform *transform_earlydata;
+#endif
 #endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
 
 #if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
@@ -1133,7 +1149,7 @@
 #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
     uint8_t in_cid_len;
     uint8_t out_cid_len;
-    unsigned char in_cid [ MBEDTLS_SSL_CID_OUT_LEN_MAX ];
+    unsigned char in_cid [ MBEDTLS_SSL_CID_IN_LEN_MAX ];
     unsigned char out_cid[ MBEDTLS_SSL_CID_OUT_LEN_MAX ];
 #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
 
@@ -2046,6 +2062,12 @@
                 size_t *out_len );
 #endif /* MBEDTLS_ECDH_C */
 
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+int mbedtls_ssl_tls13_write_early_data_ext( mbedtls_ssl_context *ssl,
+                                            unsigned char *buf,
+                                            const unsigned char *end,
+                                            size_t *out_len );
+#endif /* MBEDTLS_SSL_EARLY_DATA */
 
 #endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
 
@@ -2487,6 +2509,52 @@
 }
 #endif /* MBEDTLS_USE_PSA_CRYPTO || MBEDTLS_SSL_PROTO_TLS1_3 */
 
+#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) && \
+    defined(MBEDTLS_USE_PSA_CRYPTO)
+
+typedef enum {
+    MBEDTLS_ECJPAKE_ROUND_ONE,
+    MBEDTLS_ECJPAKE_ROUND_TWO
+} mbedtls_ecjpake_rounds_t;
+
+/**
+ * \brief       Parse the provided input buffer for getting the first round
+ *              of key exchange. This code is common between server and client
+ *
+ * \param  pake_ctx [in] the PAKE's operation/context structure
+ * \param  buf      [in] input buffer to parse
+ * \param  len      [in] length of the input buffer
+ * \param  round    [in] either MBEDTLS_ECJPAKE_ROUND_ONE or
+ *                       MBEDTLS_ECJPAKE_ROUND_TWO
+ *
+ * \return               0 on success or a negative error code in case of failure
+ */
+int mbedtls_psa_ecjpake_read_round(
+                                    psa_pake_operation_t *pake_ctx,
+                                    const unsigned char *buf,
+                                    size_t len, mbedtls_ecjpake_rounds_t round );
+
+/**
+ * \brief       Write the first round of key exchange into the provided output
+ *              buffer. This code is common between server and client
+ *
+ * \param  pake_ctx [in] the PAKE's operation/context structure
+ * \param  buf      [out] the output buffer in which data will be written to
+ * \param  len      [in] length of the output buffer
+ * \param  olen     [out] the length of the data really written on the buffer
+ * \param  round    [in] either MBEDTLS_ECJPAKE_ROUND_ONE or
+ *                       MBEDTLS_ECJPAKE_ROUND_TWO
+ *
+ * \return               0 on success or a negative error code in case of failure
+ */
+int mbedtls_psa_ecjpake_write_round(
+                                    psa_pake_operation_t *pake_ctx,
+                                    unsigned char *buf,
+                                    size_t len, size_t *olen,
+                                    mbedtls_ecjpake_rounds_t round );
+
+#endif //MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED && MBEDTLS_USE_PSA_CRYPTO
+
 /**
  * \brief       TLS record protection modes
  */
diff --git a/library/ssl_msg.c b/library/ssl_msg.c
index dbc6391..753998e 100644
--- a/library/ssl_msg.c
+++ b/library/ssl_msg.c
@@ -382,30 +382,80 @@
 }
 #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID || MBEDTLS_SSL_PROTO_TLS1_3 */
 
-/* `add_data` must have size 13 Bytes if the CID extension is disabled,
- * and 13 + 1 + CID-length Bytes if the CID extension is enabled. */
+/* The size of the `add_data` structure depends on various
+ * factors, namely
+ *
+ * 1) CID functionality disabled
+ *
+ * additional_data =
+ *    8:                    seq_num +
+ *    1:                       type +
+ *    2:                    version +
+ *    2:  length of inner plaintext +
+ *
+ * size = 13 bytes
+ *
+ * 2) CID functionality based on RFC 9146 enabled
+ *
+ * size = 8 + 1 + 1 + 1 + 2 + 2 + 6 + 2 + CID-length
+ *      = 23 + CID-length
+ *
+ * 3) CID functionality based on legacy CID version
+    according to draft-ietf-tls-dtls-connection-id-05
+ *  https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05
+ *
+ * size = 13 + 1 + CID-length
+ *
+ * More information about the CID usage:
+ *
+ * Per Section 5.3 of draft-ietf-tls-dtls-connection-id-05 the
+ * size of the additional data structure is calculated as:
+ *
+ * additional_data =
+ *    8:                    seq_num +
+ *    1:                  tls12_cid +
+ *    2:     DTLSCipherText.version +
+ *    n:                        cid +
+ *    1:                 cid_length +
+ *    2: length_of_DTLSInnerPlaintext
+ *
+ * Per RFC 9146 the size of the add_data structure is calculated as:
+ *
+ * additional_data =
+ *    8:        seq_num_placeholder +
+ *    1:                  tls12_cid +
+ *    1:                 cid_length +
+ *    1:                  tls12_cid +
+ *    2:     DTLSCiphertext.version +
+ *    2:                      epoch +
+ *    6:            sequence_number +
+ *    n:                        cid +
+ *    2: length_of_DTLSInnerPlaintext
+ *
+ */
 static void ssl_extract_add_data_from_record( unsigned char* add_data,
                                               size_t *add_data_len,
                                               mbedtls_record *rec,
                                               mbedtls_ssl_protocol_version
-                                                tls_version,
+                                              tls_version,
                                               size_t taglen )
 {
-    /* Quoting RFC 5246 (TLS 1.2):
+    /* Several types of ciphers have been defined for use with TLS and DTLS,
+     * and the MAC calculations for those ciphers differ slightly. Further
+     * variants were added when the CID functionality was added with RFC 9146.
+     * This implementations also considers the use of a legacy version of the
+     * CID specification published in draft-ietf-tls-dtls-connection-id-05,
+     * which is used in deployments.
+     *
+     * We will distinguish between the non-CID and the CID cases below.
+     *
+     * --- Non-CID cases ---
+     *
+     * Quoting RFC 5246 (TLS 1.2):
      *
      *    additional_data = seq_num + TLSCompressed.type +
      *                      TLSCompressed.version + TLSCompressed.length;
      *
-     * For the CID extension, this is extended as follows
-     * (quoting draft-ietf-tls-dtls-connection-id-05,
-     *  https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05):
-     *
-     *       additional_data = seq_num + DTLSPlaintext.type +
-     *                         DTLSPlaintext.version +
-     *                         cid +
-     *                         cid_length +
-     *                         length_of_DTLSInnerPlaintext;
-     *
      * For TLS 1.3, the record sequence number is dropped from the AAD
      * and encoded within the nonce of the AEAD operation instead.
      * Moreover, the additional data involves the length of the TLS
@@ -421,11 +471,72 @@
      *
      *     TLSCiphertext.length = TLSInnerPlaintext.length + taglen.
      *
-     */
+     * --- CID cases ---
+     *
+     * RFC 9146 uses a common pattern when constructing the data
+     * passed into a MAC / AEAD cipher.
+     *
+     * Data concatenation for MACs used with block ciphers with
+     * Encrypt-then-MAC Processing (with CID):
+     *
+     *  data = seq_num_placeholder +
+     *         tls12_cid +
+     *         cid_length +
+     *         tls12_cid +
+     *         DTLSCiphertext.version +
+     *         epoch +
+     *         sequence_number +
+     *         cid +
+     *         DTLSCiphertext.length +
+     *         IV +
+     *         ENC(content + padding + padding_length)
+     *
+     * Data concatenation for MACs used with block ciphers (with CID):
+     *
+     *  data =  seq_num_placeholder +
+     *          tls12_cid +
+     *          cid_length +
+     *          tls12_cid +
+     *          DTLSCiphertext.version +
+     *          epoch +
+     *          sequence_number +
+     *          cid +
+     *          length_of_DTLSInnerPlaintext +
+     *          DTLSInnerPlaintext.content +
+     *          DTLSInnerPlaintext.real_type +
+     *          DTLSInnerPlaintext.zeros
+     *
+     * AEAD ciphers use the following additional data calculation (with CIDs):
+     *
+     *     additional_data = seq_num_placeholder +
+     *                tls12_cid +
+     *                cid_length +
+     *                tls12_cid +
+     *                DTLSCiphertext.version +
+     *                epoch +
+     *                sequence_number +
+     *                cid +
+     *                length_of_DTLSInnerPlaintext
+     *
+     * Section 5.3 of draft-ietf-tls-dtls-connection-id-05 (for legacy CID use)
+     * defines the additional data calculation as follows:
+     *
+     *     additional_data = seq_num +
+     *                tls12_cid +
+     *                DTLSCipherText.version +
+     *                cid +
+     *                cid_length +
+     *                length_of_DTLSInnerPlaintext
+    */
 
     unsigned char *cur = add_data;
     size_t ad_len_field = rec->data_len;
 
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) && \
+    MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT == 0
+    const unsigned char seq_num_placeholder[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+#endif
+
 #if defined(MBEDTLS_SSL_PROTO_TLS1_3)
     if( tls_version == MBEDTLS_SSL_VERSION_TLS1_3 )
     {
@@ -439,25 +550,72 @@
     {
         ((void) tls_version);
         ((void) taglen);
-        memcpy( cur, rec->ctr, sizeof( rec->ctr ) );
-        cur += sizeof( rec->ctr );
+
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) && \
+    MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT == 0
+        if( rec->cid_len != 0 )
+        {
+            // seq_num_placeholder
+            memcpy( cur, seq_num_placeholder, sizeof(seq_num_placeholder) );
+            cur += sizeof( seq_num_placeholder );
+
+            // tls12_cid type
+            *cur = rec->type;
+            cur++;
+
+            // cid_length
+            *cur = rec->cid_len;
+            cur++;
+        }
+        else
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+        {
+            // epoch + sequence number
+            memcpy( cur, rec->ctr, sizeof( rec->ctr ) );
+            cur += sizeof( rec->ctr );
+        }
     }
 
+    // type
     *cur = rec->type;
     cur++;
 
+    // version
     memcpy( cur, rec->ver, sizeof( rec->ver ) );
     cur += sizeof( rec->ver );
 
-#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
-    if( rec->cid_len != 0 )
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) && \
+    MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT == 1
+
+    if (rec->cid_len != 0)
     {
-        memcpy( cur, rec->cid, rec->cid_len );
+        // CID
+        memcpy(cur, rec->cid, rec->cid_len);
         cur += rec->cid_len;
 
+        // cid_length
         *cur = rec->cid_len;
         cur++;
 
+        // length of inner plaintext
+        MBEDTLS_PUT_UINT16_BE(ad_len_field, cur, 0);
+        cur += 2;
+    }
+    else
+#elif defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) && \
+    MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT == 0
+
+    if( rec->cid_len != 0 )
+    {
+        // epoch + sequence number
+        memcpy(cur, rec->ctr, sizeof(rec->ctr));
+        cur += sizeof(rec->ctr);
+
+        // CID
+        memcpy( cur, rec->cid, rec->cid_len );
+        cur += rec->cid_len;
+
+        // length of inner plaintext
         MBEDTLS_PUT_UINT16_BE( ad_len_field, cur, 0 );
         cur += 2;
     }
@@ -511,15 +669,12 @@
                                     unsigned char const *dynamic_iv,
                                     size_t dynamic_iv_len )
 {
-    size_t i;
-
     /* Start with Fixed IV || 0 */
     memset( dst_iv, 0, dst_iv_len );
     memcpy( dst_iv, fixed_iv, fixed_iv_len );
 
     dst_iv += dst_iv_len - dynamic_iv_len;
-    for( i = 0; i < dynamic_iv_len; i++ )
-        dst_iv[i] ^= dynamic_iv[i];
+    mbedtls_xor( dst_iv, dst_iv, dynamic_iv, dynamic_iv_len );
 }
 #endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C || MBEDTLS_CHACHAPOLY_C */
 
@@ -532,7 +687,14 @@
     mbedtls_ssl_mode_t ssl_mode;
     int auth_done = 0;
     unsigned char * data;
-    unsigned char add_data[13 + 1 + MBEDTLS_SSL_CID_OUT_LEN_MAX ];
+    /* For an explanation of the additional data length see
+    * the description of ssl_extract_add_data_from_record().
+    */
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+    unsigned char add_data[23 + MBEDTLS_SSL_CID_OUT_LEN_MAX];
+#else
+    unsigned char add_data[13];
+#endif
     size_t add_data_len;
     size_t post_avail;
 
@@ -1015,13 +1177,7 @@
             size_t sign_mac_length = 0;
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
-            /*
-             * MAC(MAC_write_key, seq_num +
-             *     TLSCipherText.type +
-             *     TLSCipherText.version +
-             *     length_of( (IV +) ENC(...) ) +
-             *     IV +
-             *     ENC(content + padding + padding_length));
+            /* MAC(MAC_write_key, add_data, IV, ENC(content + padding + padding_length))
              */
 
             if( post_avail < transform->maclen)
@@ -1129,7 +1285,14 @@
     size_t padlen = 0, correct = 1;
 #endif
     unsigned char* data;
-    unsigned char add_data[13 + 1 + MBEDTLS_SSL_CID_IN_LEN_MAX ];
+    /* For an explanation of the additional data length see
+    * the description of ssl_extract_add_data_from_record().
+    */
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+    unsigned char add_data[23 + MBEDTLS_SSL_CID_IN_LEN_MAX];
+#else
+    unsigned char add_data[13];
+#endif
     size_t add_data_len;
 
 #if !defined(MBEDTLS_DEBUG_C)
@@ -1907,7 +2070,7 @@
             MBEDTLS_SSL_DEBUG_MSG( 2, ( "timeout" ) );
             mbedtls_ssl_set_timer( ssl, 0 );
 
-            if( mbedtls_ssl_is_handshake_over( ssl ) == 0 )
+            if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER )
             {
                 if( ssl_double_retransmit_timeout( ssl ) != 0 )
                 {
@@ -3481,7 +3644,7 @@
     {
         /* Shift pointers to account for record header including CID
          * struct {
-         *   ContentType special_type = tls12_cid;
+         *   ContentType outer_type = tls12_cid;
          *   ProtocolVersion version;
          *   uint16 epoch;
          *   uint48 sequence_number;
@@ -3932,7 +4095,7 @@
     if( hs == NULL )
         return( -1 );
 
-    MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_load_buffered_messsage" ) );
+    MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_load_buffered_message" ) );
 
     if( ssl->state == MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC ||
         ssl->state == MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC )
@@ -5299,7 +5462,7 @@
 
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "NewSessionTicket received" ) );
     mbedtls_ssl_handshake_set_state( ssl,
-                                     MBEDTLS_SSL_NEW_SESSION_TICKET );
+                                     MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET );
 
     return( MBEDTLS_ERR_SSL_WANT_READ );
 }
@@ -5502,7 +5665,7 @@
     }
 #endif
 
-    if( mbedtls_ssl_is_handshake_over( ssl ) == 0 )
+    if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER )
     {
         ret = mbedtls_ssl_handshake( ssl );
         if( ret != MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO &&
@@ -5758,7 +5921,7 @@
     }
 #endif
 
-    if( mbedtls_ssl_is_handshake_over( ssl ) == 0 )
+    if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER )
     {
         if( ( ret = mbedtls_ssl_handshake( ssl ) ) != 0 )
         {
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index da90b23..b757613 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -907,7 +907,12 @@
     mbedtls_ecdh_init( &handshake->ecdh_ctx );
 #endif
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    handshake->psa_pake_ctx = psa_pake_operation_init();
+    handshake->psa_pake_password = MBEDTLS_SVC_KEY_ID_INIT;
+#else
     mbedtls_ecjpake_init( &handshake->ecjpake_ctx );
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
 #if defined(MBEDTLS_SSL_CLI_C)
     handshake->ecjpake_cache = NULL;
     handshake->ecjpake_cache_len = 0;
@@ -1442,9 +1447,11 @@
 
     if( ssl->handshake != NULL )
     {
+#if defined(MBEDTLS_SSL_EARLY_DATA)
         mbedtls_ssl_transform_free( ssl->handshake->transform_earlydata );
         mbedtls_free( ssl->handshake->transform_earlydata );
         ssl->handshake->transform_earlydata = NULL;
+#endif
 
         mbedtls_ssl_transform_free( ssl->handshake->transform_handshake );
         mbedtls_free( ssl->handshake->transform_handshake );
@@ -1697,6 +1704,15 @@
 {
     conf->early_data_enabled = early_data_enabled;
 }
+
+#if defined(MBEDTLS_SSL_SRV_C)
+void mbedtls_ssl_tls13_conf_max_early_data_size(
+         mbedtls_ssl_config *conf, uint32_t max_early_data_size )
+{
+    conf->max_early_data_size = max_early_data_size;
+}
+#endif /* MBEDTLS_SSL_SRV_C */
+
 #endif /* MBEDTLS_SSL_EARLY_DATA */
 #endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
 
@@ -1847,9 +1863,101 @@
 #endif
 
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
-/*
- * Set EC J-PAKE password for current handshake
- */
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+static psa_status_t mbedtls_ssl_set_hs_ecjpake_password_common(
+                                                mbedtls_ssl_context *ssl,
+                                                mbedtls_svc_key_id_t pwd )
+{
+    psa_status_t status;
+    psa_pake_role_t psa_role;
+    psa_pake_cipher_suite_t cipher_suite = psa_pake_cipher_suite_init();
+
+    psa_pake_cs_set_algorithm( &cipher_suite, PSA_ALG_JPAKE );
+    psa_pake_cs_set_primitive( &cipher_suite,
+                               PSA_PAKE_PRIMITIVE( PSA_PAKE_PRIMITIVE_TYPE_ECC,
+                                                   PSA_ECC_FAMILY_SECP_R1,
+                                                   256) );
+    psa_pake_cs_set_hash( &cipher_suite, PSA_ALG_SHA_256 );
+
+    status = psa_pake_setup( &ssl->handshake->psa_pake_ctx, &cipher_suite );
+    if( status != PSA_SUCCESS )
+        return status;
+
+    if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER )
+        psa_role = PSA_PAKE_ROLE_SERVER;
+    else
+        psa_role = PSA_PAKE_ROLE_CLIENT;
+
+    status = psa_pake_set_role( &ssl->handshake->psa_pake_ctx, psa_role );
+    if( status != PSA_SUCCESS )
+        return status;
+
+    status = psa_pake_set_password_key( &ssl->handshake->psa_pake_ctx, pwd );
+    if( status != PSA_SUCCESS )
+        return status;
+
+    ssl->handshake->psa_pake_ctx_is_ok = 1;
+
+    return ( PSA_SUCCESS );
+}
+
+int mbedtls_ssl_set_hs_ecjpake_password( mbedtls_ssl_context *ssl,
+                                         const unsigned char *pw,
+                                         size_t pw_len )
+{
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_status_t status;
+
+    if( ssl->handshake == NULL || ssl->conf == NULL )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    /* Empty password is not valid  */
+    if( ( pw == NULL) || ( pw_len == 0 ) )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DERIVE );
+    psa_set_key_algorithm( &attributes, PSA_ALG_JPAKE );
+    psa_set_key_type( &attributes, PSA_KEY_TYPE_PASSWORD );
+
+    status = psa_import_key( &attributes, pw, pw_len,
+                                &ssl->handshake->psa_pake_password );
+    if( status != PSA_SUCCESS )
+        return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+
+    status = mbedtls_ssl_set_hs_ecjpake_password_common( ssl,
+                                        ssl->handshake->psa_pake_password );
+    if( status != PSA_SUCCESS )
+    {
+        psa_destroy_key( ssl->handshake->psa_pake_password );
+        psa_pake_abort( &ssl->handshake->psa_pake_ctx );
+        return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+    }
+
+    return( 0 );
+}
+
+int mbedtls_ssl_set_hs_ecjpake_password_opaque( mbedtls_ssl_context *ssl,
+                                                mbedtls_svc_key_id_t pwd )
+{
+    psa_status_t status;
+
+    if( ssl->handshake == NULL || ssl->conf == NULL )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    if( mbedtls_svc_key_id_is_null( pwd ) )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    status = mbedtls_ssl_set_hs_ecjpake_password_common( ssl, pwd );
+    if( status != PSA_SUCCESS )
+    {
+        psa_pake_abort( &ssl->handshake->psa_pake_ctx );
+        return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+    }
+
+    return( 0 );
+}
+#else /* MBEDTLS_USE_PSA_CRYPTO */
 int mbedtls_ssl_set_hs_ecjpake_password( mbedtls_ssl_context *ssl,
                                          const unsigned char *pw,
                                          size_t pw_len )
@@ -1859,6 +1967,10 @@
     if( ssl->handshake == NULL || ssl->conf == NULL )
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
 
+    /* Empty password is not valid  */
+    if( ( pw == NULL) || ( pw_len == 0 ) )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
     if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER )
         role = MBEDTLS_ECJPAKE_SERVER;
     else
@@ -1870,6 +1982,7 @@
                                    MBEDTLS_ECP_DP_SECP256R1,
                                    pw, pw_len ) );
 }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
 #endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
 
 #if defined(MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED)
@@ -3602,7 +3715,7 @@
     if( ssl            == NULL                       ||
         ssl->conf      == NULL                       ||
         ssl->handshake == NULL                       ||
-        mbedtls_ssl_is_handshake_over( ssl ) == 1 )
+        ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER  )
     {
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
     }
@@ -3706,7 +3819,7 @@
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> handshake" ) );
 
     /* Main handshake loop */
-    while( mbedtls_ssl_is_handshake_over( ssl ) == 0 )
+    while( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER )
     {
         ret = mbedtls_ssl_handshake_step( ssl );
 
@@ -3908,8 +4021,23 @@
 #if !defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_ECDH_C)
     mbedtls_ecdh_free( &handshake->ecdh_ctx );
 #endif
+
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    psa_pake_abort( &handshake->psa_pake_ctx );
+    /*
+     * Opaque keys are not stored in the handshake's data and it's the user
+     * responsibility to destroy them. Clear ones, instead, are created by
+     * the TLS library and should be destroyed at the same level
+     */
+    if( ! mbedtls_svc_key_id_is_null( handshake->psa_pake_password ) )
+    {
+        psa_destroy_key( handshake->psa_pake_password );
+    }
+    handshake->psa_pake_password = MBEDTLS_SVC_KEY_ID_INIT;
+#else
     mbedtls_ecjpake_free( &handshake->ecjpake_ctx );
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
 #if defined(MBEDTLS_SSL_CLI_C)
     mbedtls_free( handshake->ecjpake_cache );
     handshake->ecjpake_cache = NULL;
@@ -3987,9 +4115,11 @@
 
 #if defined(MBEDTLS_SSL_PROTO_TLS1_3)
     mbedtls_ssl_transform_free( handshake->transform_handshake );
+    mbedtls_free( handshake->transform_handshake );
+#if defined(MBEDTLS_SSL_EARLY_DATA)
     mbedtls_ssl_transform_free( handshake->transform_earlydata );
     mbedtls_free( handshake->transform_earlydata );
-    mbedtls_free( handshake->transform_handshake );
+#endif
 #endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
 
 
@@ -4157,7 +4287,7 @@
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "There is pending outgoing data" ) );
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
     }
-    /* Protocol must be DLTS, not TLS */
+    /* Protocol must be DTLS, not TLS */
     if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "Only DTLS is supported" ) );
@@ -5033,6 +5163,15 @@
 #endif
 
 #if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+    mbedtls_ssl_tls13_conf_early_data( conf, MBEDTLS_SSL_EARLY_DATA_DISABLED );
+#if defined(MBEDTLS_SSL_SRV_C)
+    mbedtls_ssl_tls13_conf_max_early_data_size(
+        conf, MBEDTLS_SSL_MAX_EARLY_DATA_SIZE );
+#endif
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
 #if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_SESSION_TICKETS)
     mbedtls_ssl_conf_new_session_tickets(
         conf, MBEDTLS_SSL_TLS1_3_DEFAULT_NEW_SESSION_TICKETS );
@@ -6123,6 +6262,55 @@
     else
 #endif
     {
+#if defined(MBEDTLS_USE_PSA_CRYPTO) &&                              \
+    defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+        if( handshake->ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+        {
+            psa_status_t status;
+            psa_algorithm_t alg = PSA_ALG_TLS12_ECJPAKE_TO_PMS;
+            psa_key_derivation_operation_t derivation =
+                PSA_KEY_DERIVATION_OPERATION_INIT;
+
+            MBEDTLS_SSL_DEBUG_MSG( 2, ( "perform PSA-based PMS KDF for ECJPAKE" ) );
+
+            handshake->pmslen = PSA_TLS12_ECJPAKE_TO_PMS_DATA_SIZE;
+
+            status = psa_key_derivation_setup( &derivation, alg );
+            if( status != PSA_SUCCESS )
+                return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+
+            status = psa_key_derivation_set_capacity( &derivation,
+                                            PSA_TLS12_ECJPAKE_TO_PMS_DATA_SIZE );
+            if( status != PSA_SUCCESS )
+            {
+                psa_key_derivation_abort( &derivation );
+                return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+            }
+
+            status = psa_pake_get_implicit_key( &handshake->psa_pake_ctx,
+                                                &derivation );
+            if( status != PSA_SUCCESS )
+            {
+                psa_key_derivation_abort( &derivation );
+                return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+            }
+
+            status = psa_key_derivation_output_bytes( &derivation,
+                                                      handshake->premaster,
+                                                      handshake->pmslen );
+            if( status != PSA_SUCCESS )
+            {
+                psa_key_derivation_abort( &derivation );
+                return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+            }
+
+            status = psa_key_derivation_abort( &derivation );
+            if( status != PSA_SUCCESS )
+            {
+                return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+            }
+        }
+#endif
         ret = handshake->tls_prf( handshake->premaster, handshake->pmslen,
                                   lbl, seed, seed_len,
                                   master,
@@ -7544,7 +7732,7 @@
 #endif
         mbedtls_ssl_handshake_wrapup_free_hs_transform( ssl );
 
-    ssl->state++;
+    ssl->state = MBEDTLS_SSL_HANDSHAKE_OVER;
 
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "<= handshake wrapup" ) );
 }
@@ -8306,6 +8494,99 @@
     return( ret );
 }
 
+#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) && \
+    defined(MBEDTLS_USE_PSA_CRYPTO)
+int mbedtls_psa_ecjpake_read_round(
+                                    psa_pake_operation_t *pake_ctx,
+                                    const unsigned char *buf,
+                                    size_t len, mbedtls_ecjpake_rounds_t round )
+{
+    psa_status_t status;
+    size_t input_offset = 0;
+    /*
+     * At round one repeat the KEY_SHARE, ZK_PUBLIC & ZF_PROOF twice
+     * At round two perform a single cycle
+     */
+    unsigned int remaining_steps = ( round == MBEDTLS_ECJPAKE_ROUND_ONE) ? 2 : 1;
+
+    for( ; remaining_steps > 0; remaining_steps-- )
+    {
+        for( psa_pake_step_t step = PSA_PAKE_STEP_KEY_SHARE;
+             step <= PSA_PAKE_STEP_ZK_PROOF;
+             ++step )
+        {
+            /* Length is stored at the first byte */
+            size_t length = buf[input_offset];
+            input_offset += 1;
+
+            if( input_offset + length > len )
+            {
+                return MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE;
+            }
+
+            status = psa_pake_input( pake_ctx, step,
+                                     buf + input_offset, length );
+            if( status != PSA_SUCCESS)
+            {
+                return psa_ssl_status_to_mbedtls( status );
+            }
+
+            input_offset += length;
+        }
+    }
+
+    if( input_offset != len )
+        return MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE;
+
+    return( 0 );
+}
+
+int mbedtls_psa_ecjpake_write_round(
+                                    psa_pake_operation_t *pake_ctx,
+                                    unsigned char *buf,
+                                    size_t len, size_t *olen,
+                                    mbedtls_ecjpake_rounds_t round )
+{
+    psa_status_t status;
+    size_t output_offset = 0;
+    size_t output_len;
+    /*
+     * At round one repeat the KEY_SHARE, ZK_PUBLIC & ZF_PROOF twice
+     * At round two perform a single cycle
+     */
+    unsigned int remaining_steps = ( round == MBEDTLS_ECJPAKE_ROUND_ONE) ? 2 : 1;
+
+    for( ; remaining_steps > 0; remaining_steps-- )
+    {
+        for( psa_pake_step_t step = PSA_PAKE_STEP_KEY_SHARE;
+            step <= PSA_PAKE_STEP_ZK_PROOF;
+            ++step )
+        {
+            /*
+             * For each step, prepend 1 byte with the length of the data as
+             * given by psa_pake_output().
+             */
+            status = psa_pake_output( pake_ctx, step,
+                                        buf + output_offset + 1,
+                                        len - output_offset - 1,
+                                        &output_len );
+            if( status != PSA_SUCCESS )
+            {
+                return( psa_ssl_status_to_mbedtls( status ) );
+            }
+
+            *(buf + output_offset) = (uint8_t) output_len;
+
+            output_offset += output_len + 1;
+        }
+    }
+
+    *olen = output_offset;
+
+    return( 0 );
+}
+#endif //MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED && MBEDTLS_USE_PSA_CRYPTO
+
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
 int mbedtls_ssl_get_key_exchange_md_tls1_2( mbedtls_ssl_context *ssl,
                                             unsigned char *hash, size_t *hashlen,
@@ -8864,8 +9145,13 @@
 
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2) && defined(MBEDTLS_SSL_CLI_C)
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    if( suite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE &&
+        ssl->handshake->psa_pake_ctx_is_ok != 1 )
+#else
     if( suite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE &&
         mbedtls_ecjpake_check( &ssl->handshake->ecjpake_ctx ) != 0 )
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
     {
         return( -1 );
     }
diff --git a/library/ssl_tls12_client.c b/library/ssl_tls12_client.c
index 1c53a09..76588d3 100644
--- a/library/ssl_tls12_client.c
+++ b/library/ssl_tls12_client.c
@@ -132,13 +132,18 @@
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     unsigned char *p = buf;
-    size_t kkpp_len;
+    size_t kkpp_len = 0;
 
     *olen = 0;
 
     /* Skip costly extension if we can't use EC J-PAKE anyway */
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    if( ssl->handshake->psa_pake_ctx_is_ok != 1 )
+        return( 0 );
+#else
     if( mbedtls_ecjpake_check( &ssl->handshake->ecjpake_ctx ) != 0 )
         return( 0 );
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
 
     MBEDTLS_SSL_DEBUG_MSG( 3,
         ( "client hello, adding ecjpake_kkpp extension" ) );
@@ -158,6 +163,18 @@
     {
         MBEDTLS_SSL_DEBUG_MSG( 3, ( "generating new ecjpake parameters" ) );
 
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+        ret = mbedtls_psa_ecjpake_write_round(&ssl->handshake->psa_pake_ctx,
+                                                p + 2, end - p - 2, &kkpp_len,
+                                                MBEDTLS_ECJPAKE_ROUND_ONE );
+        if ( ret != 0 )
+        {
+            psa_destroy_key( ssl->handshake->psa_pake_password );
+            psa_pake_abort( &ssl->handshake->psa_pake_ctx );
+            MBEDTLS_SSL_DEBUG_RET( 1 , "psa_pake_output", ret );
+            return( ret );
+        }
+#else
         ret = mbedtls_ecjpake_write_round_one( &ssl->handshake->ecjpake_ctx,
                                                p + 2, end - p - 2, &kkpp_len,
                                                ssl->conf->f_rng, ssl->conf->p_rng );
@@ -167,6 +184,7 @@
                 "mbedtls_ecjpake_write_round_one", ret );
             return( ret );
         }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
 
         ssl->handshake->ecjpake_cache = mbedtls_calloc( 1, kkpp_len );
         if( ssl->handshake->ecjpake_cache == NULL )
@@ -208,9 +226,6 @@
     size_t ext_len;
 
     /*
-     * Quoting draft-ietf-tls-dtls-connection-id-05
-     * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05
-     *
      *   struct {
      *      opaque cid<0..2^8-1>;
      *   } ConnectionId;
@@ -849,10 +864,11 @@
             ssl->handshake->ecdh_ctx.point_format = p[0];
 #endif /* !MBEDTLS_USE_PSA_CRYPTO &&
           ( MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C ) */
-#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+#if !defined(MBEDTLS_USE_PSA_CRYPTO) &&                             \
+    defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
             mbedtls_ecjpake_set_point_format( &ssl->handshake->ecjpake_ctx,
                                               p[0] );
-#endif
+#endif /* !MBEDTLS_USE_PSA_CRYPTO && MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
             MBEDTLS_SSL_DEBUG_MSG( 4, ( "point format selected: %d", p[0] ) );
             return( 0 );
         }
@@ -889,6 +905,24 @@
     ssl->handshake->ecjpake_cache = NULL;
     ssl->handshake->ecjpake_cache_len = 0;
 
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    if( ( ret = mbedtls_psa_ecjpake_read_round(
+                            &ssl->handshake->psa_pake_ctx, buf, len,
+                            MBEDTLS_ECJPAKE_ROUND_ONE ) ) != 0 )
+    {
+        psa_destroy_key( ssl->handshake->psa_pake_password );
+        psa_pake_abort( &ssl->handshake->psa_pake_ctx );
+
+        MBEDTLS_SSL_DEBUG_RET( 1, "psa_pake_input round one", ret );
+        mbedtls_ssl_send_alert_message(
+                ssl,
+                MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        return( ret );
+    }
+
+    return( 0 );
+#else
     if( ( ret = mbedtls_ecjpake_read_round_one( &ssl->handshake->ecjpake_ctx,
                                                 buf, len ) ) != 0 )
     {
@@ -901,6 +935,7 @@
     }
 
     return( 0 );
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
 }
 #endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
 
@@ -1102,7 +1137,12 @@
 {
     const unsigned char *p = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl );
     uint16_t dtls_legacy_version;
-    unsigned char cookie_len;
+
+#if !defined(MBEDTLS_SSL_PROTO_TLS1_3)
+    uint8_t cookie_len;
+#else
+    uint16_t cookie_len;
+#endif
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse hello verify request" ) );
 
@@ -1165,7 +1205,7 @@
     }
 
     memcpy( ssl->handshake->cookie, p, cookie_len );
-    ssl->handshake->verify_cookie_len = cookie_len;
+    ssl->handshake->cookie_len = cookie_len;
 
     /* Start over at ClientHello */
     ssl->state = MBEDTLS_SSL_CLIENT_HELLO;
@@ -1249,7 +1289,7 @@
             /* We made it through the verification process */
             mbedtls_free( ssl->handshake->cookie );
             ssl->handshake->cookie = NULL;
-            ssl->handshake->verify_cookie_len = 0;
+            ssl->handshake->cookie_len = 0;
         }
     }
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
@@ -1936,8 +1976,8 @@
     }
 
     /*
-     * Note: we currently ignore the PKS identity hint, as we only allow one
-     * PSK to be provisionned on the client. This could be changed later if
+     * Note: we currently ignore the PSK identity hint, as we only allow one
+     * PSK to be provisioned on the client. This could be changed later if
      * someone needs that feature.
      */
     *p += len;
@@ -2296,6 +2336,47 @@
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
     if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
     {
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+        /*
+         * The first 3 bytes are:
+         * [0] MBEDTLS_ECP_TLS_NAMED_CURVE
+         * [1, 2] elliptic curve's TLS ID
+         *
+         * However since we only support secp256r1 for now, we check only
+         * that TLS ID here
+         */
+        uint16_t read_tls_id = MBEDTLS_GET_UINT16_BE( p, 1 );
+        const mbedtls_ecp_curve_info *curve_info;
+
+        if( ( curve_info = mbedtls_ecp_curve_info_from_grp_id(
+                                MBEDTLS_ECP_DP_SECP256R1 ) ) == NULL )
+        {
+            return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
+        }
+
+        if( ( *p != MBEDTLS_ECP_TLS_NAMED_CURVE ) ||
+            ( read_tls_id != curve_info->tls_id ) )
+        {
+            return( MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER );
+        }
+
+        p += 3;
+
+        if( ( ret = mbedtls_psa_ecjpake_read_round(
+                        &ssl->handshake->psa_pake_ctx, p, end - p,
+                        MBEDTLS_ECJPAKE_ROUND_TWO ) ) != 0 )
+        {
+            psa_destroy_key( ssl->handshake->psa_pake_password );
+            psa_pake_abort( &ssl->handshake->psa_pake_ctx );
+
+            MBEDTLS_SSL_DEBUG_RET( 1, "psa_pake_input round two", ret );
+            mbedtls_ssl_send_alert_message(
+                ssl,
+                MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+            return( MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE );
+        }
+#else
         ret = mbedtls_ecjpake_read_round_two( &ssl->handshake->ecjpake_ctx,
                                               p, end - p );
         if( ret != 0 )
@@ -2307,6 +2388,7 @@
                 MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
             return( MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE );
         }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
     }
     else
 #endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
@@ -2654,7 +2736,7 @@
     for( size_t i = 0; i < sig_alg_len; i += 2 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 3,
-            ( "Supported Signature Algorithm found: %d,%d",
+            ( "Supported Signature Algorithm found: %02x %02x",
               sig_alg[i], sig_alg[i + 1]  ) );
     }
 #endif
@@ -3227,6 +3309,21 @@
     {
         header_len = 4;
 
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+        unsigned char *out_p = ssl->out_msg + header_len;
+        unsigned char *end_p = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN -
+                               header_len;
+        ret = mbedtls_psa_ecjpake_write_round( &ssl->handshake->psa_pake_ctx,
+                                    out_p, end_p - out_p, &content_len,
+                                    MBEDTLS_ECJPAKE_ROUND_TWO );
+        if ( ret != 0 )
+        {
+            psa_destroy_key( ssl->handshake->psa_pake_password );
+            psa_pake_abort( &ssl->handshake->psa_pake_ctx );
+            MBEDTLS_SSL_DEBUG_RET( 1 , "psa_pake_output", ret );
+            return( ret );
+        }
+#else
         ret = mbedtls_ecjpake_write_round_two( &ssl->handshake->ecjpake_ctx,
                 ssl->out_msg + header_len,
                 MBEDTLS_SSL_OUT_CONTENT_LEN - header_len,
@@ -3246,6 +3343,7 @@
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_derive_secret", ret );
             return( ret );
         }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
     }
     else
 #endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */
diff --git a/library/ssl_tls12_server.c b/library/ssl_tls12_server.c
index 71f703c..5cdbcc0 100644
--- a/library/ssl_tls12_server.c
+++ b/library/ssl_tls12_server.c
@@ -268,10 +268,11 @@
             ssl->handshake->ecdh_ctx.point_format = p[0];
 #endif /* !MBEDTLS_USE_PSA_CRYPTO &&
           ( MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C ) */
-#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+#if !defined(MBEDTLS_USE_PSA_CRYPTO) &&                             \
+    defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
             mbedtls_ecjpake_set_point_format( &ssl->handshake->ecjpake_ctx,
                                               p[0] );
-#endif
+#endif /* !MBEDTLS_USE_PSA_CRYPTO && MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
             MBEDTLS_SSL_DEBUG_MSG( 4, ( "point format selected: %d", p[0] ) );
             return( 0 );
         }
@@ -289,16 +290,37 @@
 MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_ecjpake_kkpp( mbedtls_ssl_context *ssl,
                                    const unsigned char *buf,
-                                   size_t len )
+                                   size_t len)
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
 
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    if( ssl->handshake->psa_pake_ctx_is_ok != 1 )
+#else
     if( mbedtls_ecjpake_check( &ssl->handshake->ecjpake_ctx ) != 0 )
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
     {
         MBEDTLS_SSL_DEBUG_MSG( 3, ( "skip ecjpake kkpp extension" ) );
         return( 0 );
     }
 
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    if( ( ret = mbedtls_psa_ecjpake_read_round(
+                        &ssl->handshake->psa_pake_ctx, buf, len,
+                        MBEDTLS_ECJPAKE_ROUND_ONE ) ) != 0 )
+    {
+        psa_destroy_key( ssl->handshake->psa_pake_password );
+        psa_pake_abort( &ssl->handshake->psa_pake_ctx );
+
+        MBEDTLS_SSL_DEBUG_RET( 1, "psa_pake_input round one", ret );
+        mbedtls_ssl_send_alert_message(
+                ssl,
+                MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+
+        return( ret );
+    }
+#else
     if( ( ret = mbedtls_ecjpake_read_round_one( &ssl->handshake->ecjpake_ctx,
                                                 buf, len ) ) != 0 )
     {
@@ -307,6 +329,7 @@
                                         MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
         return( ret );
     }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
 
     /* Only mark the extension as OK when we're sure it is */
     ssl->handshake->cli_exts |= MBEDTLS_TLS_EXT_ECJPAKE_KKPP_OK;
@@ -353,9 +376,6 @@
     }
 
     /*
-     * Quoting draft-ietf-tls-dtls-connection-id-05
-     * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05
-     *
      *   struct {
      *      opaque cid<0..2^8-1>;
      *   } ConnectionId;
@@ -1254,12 +1274,12 @@
                                      ssl->cli_id, ssl->cli_id_len ) != 0 )
             {
                 MBEDTLS_SSL_DEBUG_MSG( 2, ( "cookie verification failed" ) );
-                ssl->handshake->verify_cookie_len = 1;
+                ssl->handshake->cookie_verify_result = 1;
             }
             else
             {
                 MBEDTLS_SSL_DEBUG_MSG( 2, ( "cookie verification passed" ) );
-                ssl->handshake->verify_cookie_len = 0;
+                ssl->handshake->cookie_verify_result = 0;
             }
         }
         else
@@ -1752,9 +1772,6 @@
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding CID extension" ) );
 
     /*
-     * Quoting draft-ietf-tls-dtls-connection-id-05
-     * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05
-     *
      *   struct {
      *      opaque cid<0..2^8-1>;
      *   } ConnectionId;
@@ -1996,6 +2013,18 @@
     MBEDTLS_PUT_UINT16_BE( MBEDTLS_TLS_EXT_ECJPAKE_KKPP, p, 0 );
     p += 2;
 
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    ret = mbedtls_psa_ecjpake_write_round( &ssl->handshake->psa_pake_ctx,
+                                p + 2, end - p - 2, &kkpp_len,
+                                MBEDTLS_ECJPAKE_ROUND_ONE );
+    if ( ret != 0 )
+    {
+        psa_destroy_key( ssl->handshake->psa_pake_password );
+        psa_pake_abort( &ssl->handshake->psa_pake_ctx );
+        MBEDTLS_SSL_DEBUG_RET( 1 , "psa_pake_output", ret );
+        return;
+    }
+#else
     ret = mbedtls_ecjpake_write_round_one( &ssl->handshake->ecjpake_ctx,
                                         p + 2, end - p - 2, &kkpp_len,
                                         ssl->conf->f_rng, ssl->conf->p_rng );
@@ -2004,6 +2033,7 @@
         MBEDTLS_SSL_DEBUG_RET( 1 , "mbedtls_ecjpake_write_round_one", ret );
         return;
     }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
 
     MBEDTLS_PUT_UINT16_BE( kkpp_len, p, 0 );
     p += 2;
@@ -2214,7 +2244,7 @@
 
 #if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY)
     if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
-        ssl->handshake->verify_cookie_len != 0 )
+        ssl->handshake->cookie_verify_result != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "client hello was not authenticated" ) );
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server hello" ) );
@@ -2531,10 +2561,15 @@
         if( ! mbedtls_ssl_sig_alg_is_supported( ssl, *sig_alg ) )
             continue;
 
-        MBEDTLS_PUT_UINT16_BE( *sig_alg, p, sa_len );
+        /* Write elements at offsets starting from 1 (offset 0 is for the
+         * length). Thus the offset of each element is the length of the
+         * partial list including that element. */
         sa_len += 2;
+        MBEDTLS_PUT_UINT16_BE( *sig_alg, p, sa_len );
+
     }
 
+    /* Fill in list length. */
     MBEDTLS_PUT_UINT16_BE( sa_len, p, 0 );
     sa_len += 2;
     p += sa_len;
@@ -2808,6 +2843,46 @@
     if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
     {
         int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+        unsigned char *out_p = ssl->out_msg + ssl->out_msglen;
+        unsigned char *end_p = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN -
+                               ssl->out_msglen;
+        size_t output_offset = 0;
+        size_t output_len = 0;
+        const mbedtls_ecp_curve_info *curve_info;
+
+        /*
+         * The first 3 bytes are:
+         * [0] MBEDTLS_ECP_TLS_NAMED_CURVE
+         * [1, 2] elliptic curve's TLS ID
+         *
+         * However since we only support secp256r1 for now, we hardcode its
+         * TLS ID here
+         */
+        if( ( curve_info = mbedtls_ecp_curve_info_from_grp_id(
+                                    MBEDTLS_ECP_DP_SECP256R1 ) ) == NULL )
+        {
+            return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
+        }
+        *out_p = MBEDTLS_ECP_TLS_NAMED_CURVE;
+        MBEDTLS_PUT_UINT16_BE( curve_info->tls_id, out_p, 1 );
+        output_offset += 3;
+
+        ret = mbedtls_psa_ecjpake_write_round( &ssl->handshake->psa_pake_ctx,
+                                    out_p + output_offset,
+                                    end_p - out_p - output_offset, &output_len,
+                                    MBEDTLS_ECJPAKE_ROUND_TWO );
+        if( ret != 0 )
+        {
+            psa_destroy_key( ssl->handshake->psa_pake_password );
+            psa_pake_abort( &ssl->handshake->psa_pake_ctx );
+            MBEDTLS_SSL_DEBUG_RET( 1 , "psa_pake_output", ret );
+            return( ret );
+        }
+
+        output_offset += output_len;
+        ssl->out_msglen += output_offset;
+#else
         size_t len = 0;
 
         ret = mbedtls_ecjpake_write_round_two(
@@ -2822,6 +2897,7 @@
         }
 
         ssl->out_msglen += len;
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
     }
 #endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
 
@@ -4039,6 +4115,18 @@
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
     if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
     {
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+        if( ( ret = mbedtls_psa_ecjpake_read_round(
+                        &ssl->handshake->psa_pake_ctx, p, end - p,
+                        MBEDTLS_ECJPAKE_ROUND_TWO ) ) != 0 )
+        {
+            psa_destroy_key( ssl->handshake->psa_pake_password );
+            psa_pake_abort( &ssl->handshake->psa_pake_ctx );
+
+            MBEDTLS_SSL_DEBUG_RET( 1, "psa_pake_input round two", ret );
+            return( ret );
+        }
+#else
         ret = mbedtls_ecjpake_read_round_two( &ssl->handshake->ecjpake_ctx,
                                               p, end - p );
         if( ret != 0 )
@@ -4055,6 +4143,7 @@
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_derive_secret", ret );
             return( ret );
         }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
     }
     else
 #endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c
index 9940a0e..839b954 100644
--- a/library/ssl_tls13_client.c
+++ b/library/ssl_tls13_client.c
@@ -553,7 +553,7 @@
     MBEDTLS_SSL_DEBUG_BUF( 3, "cookie extension", p, cookie_len );
 
     mbedtls_free( handshake->cookie );
-    handshake->hrr_cookie_len = 0;
+    handshake->cookie_len = 0;
     handshake->cookie = mbedtls_calloc( 1, cookie_len );
     if( handshake->cookie == NULL )
     {
@@ -564,7 +564,7 @@
     }
 
     memcpy( handshake->cookie, p, cookie_len );
-    handshake->hrr_cookie_len = cookie_len;
+    handshake->cookie_len = cookie_len;
 
     return( 0 );
 }
@@ -587,21 +587,21 @@
 
     MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, cookie",
                            handshake->cookie,
-                           handshake->hrr_cookie_len );
+                           handshake->cookie_len );
 
-    MBEDTLS_SSL_CHK_BUF_PTR( p, end, handshake->hrr_cookie_len + 6 );
+    MBEDTLS_SSL_CHK_BUF_PTR( p, end, handshake->cookie_len + 6 );
 
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding cookie extension" ) );
 
     MBEDTLS_PUT_UINT16_BE( MBEDTLS_TLS_EXT_COOKIE, p, 0 );
-    MBEDTLS_PUT_UINT16_BE( handshake->hrr_cookie_len + 2, p, 2 );
-    MBEDTLS_PUT_UINT16_BE( handshake->hrr_cookie_len, p, 4 );
+    MBEDTLS_PUT_UINT16_BE( handshake->cookie_len + 2, p, 2 );
+    MBEDTLS_PUT_UINT16_BE( handshake->cookie_len, p, 4 );
     p += 6;
 
     /* Cookie */
-    memcpy( p, handshake->cookie, handshake->hrr_cookie_len );
+    memcpy( p, handshake->cookie, handshake->cookie_len );
 
-    *out_len = handshake->hrr_cookie_len + 6;
+    *out_len = handshake->cookie_len + 6;
 
     mbedtls_ssl_tls13_set_hs_sent_ext_mask( ssl, MBEDTLS_TLS_EXT_COOKIE );
 
@@ -700,6 +700,19 @@
             session != NULL && session->ticket != NULL );
 }
 
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+static int ssl_tls13_early_data_has_valid_ticket( mbedtls_ssl_context *ssl )
+{
+    mbedtls_ssl_session *session = ssl->session_negotiate;
+    return( ssl->handshake->resume &&
+            session->tls_version == MBEDTLS_SSL_VERSION_TLS1_3 &&
+            ( session->ticket_flags &
+              MBEDTLS_SSL_TLS1_3_TICKET_ALLOW_EARLY_DATA ) &&
+            mbedtls_ssl_tls13_cipher_suite_is_offered(
+                ssl, session->ciphersuite ) );
+}
+#endif
+
 MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_tls13_ticket_get_identity( mbedtls_ssl_context *ssl,
                                           psa_algorithm_t *hash_alg,
@@ -1160,6 +1173,29 @@
     }
 #endif
 
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+    if( mbedtls_ssl_conf_tls13_some_psk_enabled( ssl ) &&
+        ssl_tls13_early_data_has_valid_ticket( ssl ) &&
+        ssl->conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_ENABLED )
+    {
+        ret = mbedtls_ssl_tls13_write_early_data_ext( ssl, p, end, &ext_len );
+        if( ret != 0 )
+            return( ret );
+        p += ext_len;
+
+        /* Initializes the status to `rejected`. It will be updated to
+         * `accepted` if the EncryptedExtension message contain an early data
+         * indication extension.
+         */
+        ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED;
+    }
+    else
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write early_data extension" ) );
+        ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT;
+    }
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
 #if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_SOME_PSK_ENABLED)
     /* For PSK-based key exchange we need the pre_shared_key extension
      * and the psk_key_exchange_modes extension.
@@ -2024,6 +2060,21 @@
 
                 break;
 #endif /* MBEDTLS_SSL_ALPN */
+
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+            case MBEDTLS_TLS_EXT_EARLY_DATA:
+
+                if( extension_data_len != 0 )
+                {
+                    /* The message must be empty. */
+                    MBEDTLS_SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR,
+                                                  MBEDTLS_ERR_SSL_DECODE_ERROR );
+                    return( MBEDTLS_ERR_SSL_DECODE_ERROR );
+                }
+
+                break;
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
             default:
                 MBEDTLS_SSL_PRINT_EXT(
                     3, MBEDTLS_SSL_HS_ENCRYPTED_EXTENSIONS,
@@ -2066,6 +2117,14 @@
     MBEDTLS_SSL_PROC_CHK(
         ssl_tls13_parse_encrypted_extensions( ssl, buf, buf + buf_len ) );
 
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+    if( ssl->handshake->received_extensions &
+        MBEDTLS_SSL_EXT_MASK( EARLY_DATA ) )
+    {
+        ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED;
+    }
+#endif
+
     mbedtls_ssl_add_hs_msg_to_checksum( ssl, MBEDTLS_SSL_HS_ENCRYPTED_EXTENSIONS,
                                         buf, buf_len );
 
@@ -2505,6 +2564,23 @@
 
         switch( extension_type )
         {
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+            case MBEDTLS_TLS_EXT_EARLY_DATA:
+                if( extension_data_len != 4 )
+                {
+                    MBEDTLS_SSL_PEND_FATAL_ALERT(
+                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR,
+                        MBEDTLS_ERR_SSL_DECODE_ERROR );
+                    return( MBEDTLS_ERR_SSL_DECODE_ERROR );
+                }
+                if( ssl->session != NULL )
+                {
+                    ssl->session->ticket_flags |=
+                            MBEDTLS_SSL_TLS1_3_TICKET_ALLOW_EARLY_DATA;
+                }
+                break;
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
             default:
                 MBEDTLS_SSL_PRINT_EXT(
                     3, MBEDTLS_SSL_HS_NEW_SESSION_TICKET,
@@ -2690,7 +2766,7 @@
 }
 
 /*
- * Handler for MBEDTLS_SSL_NEW_SESSION_TICKET
+ * Handler for MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET
  */
 MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_tls13_process_new_session_ticket( mbedtls_ssl_context *ssl )
@@ -2804,7 +2880,7 @@
 #endif /* MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE */
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
-        case MBEDTLS_SSL_NEW_SESSION_TICKET:
+        case MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET:
             ret = ssl_tls13_process_new_session_ticket( ssl );
             if( ret != 0 )
                 break;
diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c
index f854998..761c00e 100644
--- a/library/ssl_tls13_generic.c
+++ b/library/ssl_tls13_generic.c
@@ -1374,6 +1374,39 @@
 
 #endif /* MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE */
 
+/* Early Data Indication Extension
+ *
+ * struct {
+ *   select ( Handshake.msg_type ) {
+ *     ...
+ *     case client_hello:         Empty;
+ *     case encrypted_extensions: Empty;
+ *   };
+ * } EarlyDataIndication;
+ */
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+int mbedtls_ssl_tls13_write_early_data_ext( mbedtls_ssl_context *ssl,
+                                            unsigned char *buf,
+                                            const unsigned char *end,
+                                            size_t *out_len )
+{
+    unsigned char *p = buf;
+    *out_len = 0;
+    ((void) ssl);
+
+    MBEDTLS_SSL_CHK_BUF_PTR( p, end, 4 );
+
+    MBEDTLS_PUT_UINT16_BE( MBEDTLS_TLS_EXT_EARLY_DATA, p, 0 );
+    MBEDTLS_PUT_UINT16_BE( 0, p, 2 );
+
+    *out_len = 4;
+
+    mbedtls_ssl_tls13_set_hs_sent_ext_mask( ssl, MBEDTLS_TLS_EXT_EARLY_DATA );
+
+    return( 0 );
+}
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
 /* Reset SSL context and update hash for handling HRR.
  *
  * Replace Transcript-Hash(X) by
diff --git a/library/ssl_tls13_keys.c b/library/ssl_tls13_keys.c
index ec84a99..cef6144 100644
--- a/library/ssl_tls13_keys.c
+++ b/library/ssl_tls13_keys.c
@@ -215,6 +215,33 @@
     return( psa_ssl_status_to_mbedtls ( status ) );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
+static int ssl_tls13_make_traffic_key(
+                    psa_algorithm_t hash_alg,
+                    const unsigned char *secret, size_t secret_len,
+                    unsigned char *key, size_t key_len,
+                    unsigned char *iv, size_t iv_len )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+    ret = mbedtls_ssl_tls13_hkdf_expand_label(
+                    hash_alg,
+                    secret, secret_len,
+                    MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( key ),
+                    NULL, 0,
+                    key, key_len );
+    if( ret != 0 )
+        return( ret );
+
+    ret = mbedtls_ssl_tls13_hkdf_expand_label(
+                    hash_alg,
+                    secret, secret_len,
+                    MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( iv ),
+                    NULL, 0,
+                    iv, iv_len );
+    return( ret );
+}
+
 /*
  * The traffic keying material is generated from the following inputs:
  *
@@ -240,35 +267,17 @@
 {
     int ret = 0;
 
-    ret = mbedtls_ssl_tls13_hkdf_expand_label( hash_alg,
-                    client_secret, secret_len,
-                    MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( key ),
-                    NULL, 0,
-                    keys->client_write_key, key_len );
+    ret = ssl_tls13_make_traffic_key(
+            hash_alg, client_secret, secret_len,
+            keys->client_write_key, key_len,
+            keys->client_write_iv, iv_len );
     if( ret != 0 )
         return( ret );
 
-    ret = mbedtls_ssl_tls13_hkdf_expand_label( hash_alg,
-                    server_secret, secret_len,
-                    MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( key ),
-                    NULL, 0,
-                    keys->server_write_key, key_len );
-    if( ret != 0 )
-        return( ret );
-
-    ret = mbedtls_ssl_tls13_hkdf_expand_label( hash_alg,
-                    client_secret, secret_len,
-                    MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( iv ),
-                    NULL, 0,
-                    keys->client_write_iv, iv_len );
-    if( ret != 0 )
-        return( ret );
-
-    ret = mbedtls_ssl_tls13_hkdf_expand_label( hash_alg,
-                    server_secret, secret_len,
-                    MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( iv ),
-                    NULL, 0,
-                    keys->server_write_iv, iv_len );
+    ret = ssl_tls13_make_traffic_key(
+            hash_alg, server_secret, secret_len,
+            keys->server_write_key, key_len,
+            keys->server_write_iv, iv_len );
     if( ret != 0 )
         return( ret );
 
@@ -1052,6 +1061,194 @@
     return( 0 );
 }
 
+MBEDTLS_CHECK_RETURN_CRITICAL
+static int ssl_tls13_get_cipher_key_info(
+                    const mbedtls_ssl_ciphersuite_t *ciphersuite_info,
+                    size_t *key_len, size_t *iv_len )
+{
+    psa_key_type_t key_type;
+    psa_algorithm_t alg;
+    size_t taglen;
+    size_t key_bits;
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+    if( ciphersuite_info->flags & MBEDTLS_CIPHERSUITE_SHORT_TAG )
+        taglen = 8;
+    else
+        taglen = 16;
+
+    status = mbedtls_ssl_cipher_to_psa( ciphersuite_info->cipher, taglen,
+                                        &alg, &key_type, &key_bits );
+    if( status != PSA_SUCCESS )
+        return psa_ssl_status_to_mbedtls( status );
+
+    *key_len = PSA_BITS_TO_BYTES( key_bits );
+
+    /* TLS 1.3 only have AEAD ciphers, IV length is unconditionally 12 bytes */
+    *iv_len = 12;
+
+    return 0;
+}
+
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+/*
+ * ssl_tls13_generate_early_key() generates the key necessary for protecting
+ * the early application data and handshake messages as described in section 7
+ * of RFC 8446.
+ *
+ * NOTE: Only one key is generated, the key for the traffic from the client to
+ *       the server. The TLS 1.3 specification does not define a secret and thus
+ *       a key for server early traffic.
+ */
+MBEDTLS_CHECK_RETURN_CRITICAL
+static int ssl_tls13_generate_early_key( mbedtls_ssl_context *ssl,
+                                         mbedtls_ssl_key_set *traffic_keys )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    mbedtls_md_type_t md_type;
+    psa_algorithm_t hash_alg;
+    size_t hash_len;
+    unsigned char transcript[MBEDTLS_TLS1_3_MD_MAX_SIZE];
+    size_t transcript_len;
+    size_t key_len;
+    size_t iv_len;
+
+    mbedtls_ssl_handshake_params *handshake = ssl->handshake;
+    const mbedtls_ssl_ciphersuite_t *ciphersuite_info = handshake->ciphersuite_info;
+    mbedtls_ssl_tls13_early_secrets *tls13_early_secrets = &handshake->tls13_early_secrets;
+
+    MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_tls13_generate_early_key" ) );
+
+    ret = ssl_tls13_get_cipher_key_info( ciphersuite_info, &key_len, &iv_len );
+    if( ret != 0 )
+    {
+        MBEDTLS_SSL_DEBUG_RET( 1, "ssl_tls13_get_cipher_key_info", ret );
+        goto cleanup;
+    }
+
+    md_type = ciphersuite_info->mac;
+
+    hash_alg = mbedtls_hash_info_psa_from_md( ciphersuite_info->mac );
+    hash_len = PSA_HASH_LENGTH( hash_alg );
+
+    ret = mbedtls_ssl_get_handshake_transcript( ssl, md_type,
+                                                transcript,
+                                                sizeof( transcript ),
+                                                &transcript_len );
+    if( ret != 0 )
+    {
+        MBEDTLS_SSL_DEBUG_RET( 1,
+                               "mbedtls_ssl_get_handshake_transcript",
+                               ret );
+        goto cleanup;
+    }
+
+    ret = mbedtls_ssl_tls13_derive_early_secrets(
+              hash_alg, handshake->tls13_master_secrets.early,
+              transcript, transcript_len, tls13_early_secrets );
+    if( ret != 0 )
+    {
+        MBEDTLS_SSL_DEBUG_RET(
+            1, "mbedtls_ssl_tls13_derive_early_secrets", ret );
+        goto cleanup;
+    }
+
+    MBEDTLS_SSL_DEBUG_BUF(
+        4, "Client early traffic secret",
+        tls13_early_secrets->client_early_traffic_secret, hash_len );
+
+    /*
+     * Export client handshake traffic secret
+     */
+    if( ssl->f_export_keys != NULL )
+    {
+        ssl->f_export_keys(
+            ssl->p_export_keys,
+            MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_EARLY_SECRET,
+            tls13_early_secrets->client_early_traffic_secret,
+            hash_len,
+            handshake->randbytes,
+            handshake->randbytes + MBEDTLS_CLIENT_HELLO_RANDOM_LEN,
+            MBEDTLS_SSL_TLS_PRF_NONE /* TODO: FIX! */ );
+    }
+
+    ret = ssl_tls13_make_traffic_key(
+              hash_alg,
+              tls13_early_secrets->client_early_traffic_secret,
+              hash_len, traffic_keys->client_write_key, key_len,
+              traffic_keys->client_write_iv, iv_len );
+    if( ret != 0 )
+    {
+        MBEDTLS_SSL_DEBUG_RET( 1, "ssl_tls13_make_traffic_key", ret );
+        goto cleanup;
+    }
+    traffic_keys->key_len = key_len;
+    traffic_keys->iv_len = iv_len;
+
+    MBEDTLS_SSL_DEBUG_BUF( 4, "client early write_key",
+                           traffic_keys->client_write_key,
+                           traffic_keys->key_len);
+
+    MBEDTLS_SSL_DEBUG_BUF( 4, "client early write_iv",
+                           traffic_keys->client_write_iv,
+                           traffic_keys->iv_len);
+
+    MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= ssl_tls13_generate_early_key" ) );
+
+cleanup:
+    /* Erase secret and transcript */
+    mbedtls_platform_zeroize(
+        tls13_early_secrets, sizeof( mbedtls_ssl_tls13_early_secrets ) );
+    mbedtls_platform_zeroize( transcript, sizeof( transcript ) );
+    return( ret );
+}
+
+int mbedtls_ssl_tls13_compute_early_transform( mbedtls_ssl_context *ssl )
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    mbedtls_ssl_key_set traffic_keys;
+    mbedtls_ssl_transform *transform_earlydata = NULL;
+    mbedtls_ssl_handshake_params *handshake = ssl->handshake;
+
+    /* Next evolution in key schedule: Establish early_data secret and
+     * key material. */
+    ret = ssl_tls13_generate_early_key( ssl, &traffic_keys );
+    if( ret != 0 )
+    {
+        MBEDTLS_SSL_DEBUG_RET( 1, "ssl_tls13_generate_early_key",
+                               ret );
+        goto cleanup;
+    }
+
+    transform_earlydata = mbedtls_calloc( 1, sizeof( mbedtls_ssl_transform ) );
+    if( transform_earlydata == NULL )
+    {
+        ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
+        goto cleanup;
+    }
+
+    ret = mbedtls_ssl_tls13_populate_transform(
+                                        transform_earlydata,
+                                        ssl->conf->endpoint,
+                                        ssl->session_negotiate->ciphersuite,
+                                        &traffic_keys,
+                                        ssl );
+    if( ret != 0 )
+    {
+        MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls13_populate_transform", ret );
+        goto cleanup;
+    }
+    handshake->transform_earlydata = transform_earlydata;
+
+cleanup:
+    mbedtls_platform_zeroize( &traffic_keys, sizeof( traffic_keys ) );
+    if( ret != 0 )
+        mbedtls_free( transform_earlydata );
+
+    return( ret );
+}
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
 int mbedtls_ssl_tls13_key_schedule_stage_early( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -1098,51 +1295,19 @@
     return( 0 );
 }
 
-MBEDTLS_CHECK_RETURN_CRITICAL
-static int mbedtls_ssl_tls13_get_cipher_key_info(
-                    const mbedtls_ssl_ciphersuite_t *ciphersuite_info,
-                    size_t *key_len, size_t *iv_len )
-{
-    psa_key_type_t key_type;
-    psa_algorithm_t alg;
-    size_t taglen;
-    size_t key_bits;
-    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
-
-    if( ciphersuite_info->flags & MBEDTLS_CIPHERSUITE_SHORT_TAG )
-        taglen = 8;
-    else
-        taglen = 16;
-
-    status = mbedtls_ssl_cipher_to_psa( ciphersuite_info->cipher, taglen,
-                                        &alg, &key_type, &key_bits );
-    if( status != PSA_SUCCESS )
-        return psa_ssl_status_to_mbedtls( status );
-
-    *key_len = PSA_BITS_TO_BYTES( key_bits );
-
-    /* TLS 1.3 only have AEAD ciphers, IV length is unconditionally 12 bytes */
-    *iv_len = 12;
-
-    return 0;
-}
-
 /* mbedtls_ssl_tls13_generate_handshake_keys() generates keys necessary for
  * protecting the handshake messages, as described in Section 7 of TLS 1.3. */
 int mbedtls_ssl_tls13_generate_handshake_keys( mbedtls_ssl_context *ssl,
                                                mbedtls_ssl_key_set *traffic_keys )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-
     mbedtls_md_type_t md_type;
-
     psa_algorithm_t hash_alg;
     size_t hash_len;
-
     unsigned char transcript[MBEDTLS_TLS1_3_MD_MAX_SIZE];
     size_t transcript_len;
-
-    size_t key_len, iv_len;
+    size_t key_len;
+    size_t iv_len;
 
     mbedtls_ssl_handshake_params *handshake = ssl->handshake;
     const mbedtls_ssl_ciphersuite_t *ciphersuite_info = handshake->ciphersuite_info;
@@ -1150,11 +1315,10 @@
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_tls13_generate_handshake_keys" ) );
 
-    ret = mbedtls_ssl_tls13_get_cipher_key_info( ciphersuite_info,
-                                                 &key_len, &iv_len );
+    ret = ssl_tls13_get_cipher_key_info( ciphersuite_info, &key_len, &iv_len );
     if( ret != 0 )
     {
-        MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls13_get_cipher_key_info", ret );
+        MBEDTLS_SSL_DEBUG_RET( 1, "ssl_tls13_get_cipher_key_info", ret );
         return ret;
     }
 
@@ -1370,11 +1534,11 @@
 
     /* Extract basic information about hash and ciphersuite */
 
-    ret = mbedtls_ssl_tls13_get_cipher_key_info( handshake->ciphersuite_info,
-                                                 &key_len, &iv_len );
+    ret = ssl_tls13_get_cipher_key_info( handshake->ciphersuite_info,
+                                         &key_len, &iv_len );
     if( ret != 0 )
     {
-        MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls13_get_cipher_key_info", ret );
+        MBEDTLS_SSL_DEBUG_RET( 1, "ssl_tls13_get_cipher_key_info", ret );
         goto cleanup;
     }
 
diff --git a/library/ssl_tls13_keys.h b/library/ssl_tls13_keys.h
index 966b5c5..fc64737 100644
--- a/library/ssl_tls13_keys.h
+++ b/library/ssl_tls13_keys.h
@@ -667,6 +667,27 @@
                                              size_t *actual_len,
                                              int which );
 
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+/**
+ * \brief Compute TLS 1.3 early transform
+ *
+ * \param ssl  The SSL context to operate on.
+ *
+ * \returns    \c 0 on success.
+ * \returns    A negative error code on failure.
+ *
+ * \warning    The function does not compute the early master secret. Call
+ *             mbedtls_ssl_tls13_key_schedule_stage_early() before to
+ *             call this function to generate the early master secret.
+ * \note       For a client/server endpoint, the function computes only the
+ *             encryption/decryption part of the transform as the decryption/
+ *             encryption part is not defined by the specification (no early
+ *             traffic from the server to the client).
+ */
+MBEDTLS_CHECK_RETURN_CRITICAL
+int mbedtls_ssl_tls13_compute_early_transform( mbedtls_ssl_context *ssl );
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
 /**
  * \brief Compute TLS 1.3 handshake transform
  *
diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c
index 3cd0310..6caae89 100644
--- a/library/ssl_tls13_server.c
+++ b/library/ssl_tls13_server.c
@@ -634,7 +634,7 @@
 
     if( p_identity_len != identities_end || p_binder_len != binders_end )
     {
-        MBEDTLS_SSL_DEBUG_MSG( 3, ( "pre_shared_key extesion decode error" ) );
+        MBEDTLS_SSL_DEBUG_MSG( 3, ( "pre_shared_key extension decode error" ) );
         MBEDTLS_SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR,
                                       MBEDTLS_ERR_SSL_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_DECODE_ERROR );
@@ -2628,7 +2628,7 @@
     mbedtls_ssl_tls13_handshake_wrapup( ssl );
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
-    mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_NEW_SESSION_TICKET );
+    mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET );
 #else
     mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_HANDSHAKE_OVER );
 #endif
@@ -2636,7 +2636,7 @@
 }
 
 /*
- * Handler for MBEDTLS_SSL_NEW_SESSION_TICKET
+ * Handler for MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET
  */
 #define SSL_NEW_SESSION_TICKET_SKIP  0
 #define SSL_NEW_SESSION_TICKET_WRITE 1
@@ -2872,7 +2872,7 @@
 }
 
 /*
- * Handler for MBEDTLS_SSL_NEW_SESSION_TICKET
+ * Handler for MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET
  */
 static int ssl_tls13_write_new_session_ticket( mbedtls_ssl_context *ssl )
 {
@@ -2908,8 +2908,8 @@
         else
             ssl->handshake->new_session_tickets_count--;
 
-        mbedtls_ssl_handshake_set_state( ssl,
-                                         MBEDTLS_SSL_NEW_SESSION_TICKET_FLUSH );
+        mbedtls_ssl_handshake_set_state(
+            ssl, MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET_FLUSH );
     }
     else
     {
@@ -3045,7 +3045,7 @@
 #endif /* MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED */
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
-        case MBEDTLS_SSL_NEW_SESSION_TICKET:
+        case MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET:
             ret = ssl_tls13_write_new_session_ticket( ssl );
             if( ret != 0 )
             {
@@ -3054,9 +3054,9 @@
                                        ret );
             }
             break;
-        case MBEDTLS_SSL_NEW_SESSION_TICKET_FLUSH:
+        case MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET_FLUSH:
             /* This state is necessary to do the flush of the New Session
-             * Ticket message written in MBEDTLS_SSL_NEW_SESSION_TICKET
+             * Ticket message written in MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET
              * as part of ssl_prepare_handshake_step.
              */
             ret = 0;
@@ -3064,7 +3064,7 @@
             if( ssl->handshake->new_session_tickets_count == 0 )
                 mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_HANDSHAKE_OVER );
             else
-                mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_NEW_SESSION_TICKET );
+                mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET );
             break;
 
 #endif /* MBEDTLS_SSL_SESSION_TICKETS */
diff --git a/library/x509.c b/library/x509.c
index 362e036..be87973 100644
--- a/library/x509.c
+++ b/library/x509.c
@@ -233,7 +233,7 @@
  *
  * RFC 4055 (which defines use of RSASSA-PSS in PKIX) states that the value
  * of trailerField MUST be 1, and PKCS#1 v2.2 doesn't even define any other
- * option. Enfore this at parsing time.
+ * option. Enforce this at parsing time.
  */
 int mbedtls_x509_get_rsassa_pss_params( const mbedtls_x509_buf *params,
                                 mbedtls_md_type_t *md_alg, mbedtls_md_type_t *mgf_md,
diff --git a/library/x509_crl.c b/library/x509_crl.c
index d830fcd..dc2d2e3 100644
--- a/library/x509_crl.c
+++ b/library/x509_crl.c
@@ -1,5 +1,5 @@
 /*
- *  X.509 Certidicate Revocation List (CRL) parsing
+ *  X.509 Certificate Revocation List (CRL) parsing
  *
  *  Copyright The Mbed TLS Contributors
  *  SPDX-License-Identifier: Apache-2.0
diff --git a/programs/fuzz/.gitignore b/programs/fuzz/.gitignore
index 5dc0960..34e3ed0 100644
--- a/programs/fuzz/.gitignore
+++ b/programs/fuzz/.gitignore
@@ -1,6 +1,7 @@
 fuzz_client
 fuzz_dtlsclient
 fuzz_dtlsserver
+fuzz_pkcs7
 fuzz_privkey
 fuzz_pubkey
 fuzz_server
diff --git a/programs/fuzz/CMakeLists.txt b/programs/fuzz/CMakeLists.txt
index c7fcd35..7747744 100644
--- a/programs/fuzz/CMakeLists.txt
+++ b/programs/fuzz/CMakeLists.txt
@@ -12,6 +12,7 @@
     fuzz_x509crl
     fuzz_x509crt
     fuzz_x509csr
+    fuzz_pkcs7
 )
 
 set(executables_with_common_c
diff --git a/programs/fuzz/Makefile b/programs/fuzz/Makefile
index 59a2bb7..8477aa8 100644
--- a/programs/fuzz/Makefile
+++ b/programs/fuzz/Makefile
@@ -1,7 +1,9 @@
 MBEDTLS_TEST_PATH:=../../tests/src
 MBEDTLS_TEST_OBJS:=$(patsubst %.c,%.o,$(wildcard ${MBEDTLS_TEST_PATH}/*.c ${MBEDTLS_TEST_PATH}/drivers/*.c))
 
-LOCAL_CFLAGS = -I../../tests/include -I../../include -D_FILE_OFFSET_BITS=64
+CFLAGS ?= -O2
+WARNING_CFLAGS ?= -Wall -Wextra
+LOCAL_CFLAGS = $(WARNING_CFLAGS) -I../../tests/include -I../../include -D_FILE_OFFSET_BITS=64
 LOCAL_LDFLAGS = ${MBEDTLS_TEST_OBJS}		\
 		-L../../library			\
 		-lmbedtls$(SHARED_SUFFIX)	\
diff --git a/programs/fuzz/fuzz_pkcs7.c b/programs/fuzz/fuzz_pkcs7.c
new file mode 100644
index 0000000..960007d
--- /dev/null
+++ b/programs/fuzz/fuzz_pkcs7.c
@@ -0,0 +1,19 @@
+#include <stdint.h>
+#include "mbedtls/pkcs7.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+#ifdef MBEDTLS_PKCS7_C
+    mbedtls_pkcs7 pkcs7;
+
+    mbedtls_pkcs7_init( &pkcs7 );
+
+    mbedtls_pkcs7_parse_der( &pkcs7, Data, Size );
+
+    mbedtls_pkcs7_free( &pkcs7 );
+#else
+    (void) Data;
+    (void) Size;
+#endif
+
+    return 0;
+}
diff --git a/programs/fuzz/fuzz_pkcs7.options b/programs/fuzz/fuzz_pkcs7.options
new file mode 100644
index 0000000..0824b19
--- /dev/null
+++ b/programs/fuzz/fuzz_pkcs7.options
@@ -0,0 +1,2 @@
+[libfuzzer]
+max_len = 65535
diff --git a/programs/pkey/dh_genprime.c b/programs/pkey/dh_genprime.c
index 2e696e5..3e81d13 100644
--- a/programs/pkey/dh_genprime.c
+++ b/programs/pkey/dh_genprime.c
@@ -42,7 +42,7 @@
 
 #define USAGE \
     "\n usage: dh_genprime param=<>...\n"                                   \
-    "\n acceprable parameters:\n"                                           \
+    "\n acceptable parameters:\n"                                           \
     "    bits=%%d           default: 2048\n"
 
 #define DFL_BITS    2048
@@ -157,8 +157,8 @@
         goto exit;
     }
 
-    if( ( ret = mbedtls_mpi_write_file( "P = ", &P, 16, fout ) != 0 ) ||
-        ( ret = mbedtls_mpi_write_file( "G = ", &G, 16, fout ) != 0 ) )
+    if( ( ( ret = mbedtls_mpi_write_file( "P = ", &P, 16, fout ) ) != 0 ) ||
+        ( ( ret = mbedtls_mpi_write_file( "G = ", &G, 16, fout ) ) != 0 ) )
     {
         mbedtls_printf( " failed\n  ! mbedtls_mpi_write_file returned %d\n\n", ret );
         fclose( fout );
diff --git a/programs/psa/aead_demo.c b/programs/psa/aead_demo.c
index c4ed0dd..1efd132 100644
--- a/programs/psa/aead_demo.c
+++ b/programs/psa/aead_demo.c
@@ -104,7 +104,7 @@
 
 /* Run a PSA function and bail out if it fails.
  * The symbolic name of the error code can be recovered using:
- * programs/psa/psa_consant_name status <value> */
+ * programs/psa/psa_constant_name status <value> */
 #define PSA_CHECK( expr )                                       \
     do                                                          \
     {                                                           \
diff --git a/programs/psa/hmac_demo.c b/programs/psa/hmac_demo.c
index 6238892..f949a89 100644
--- a/programs/psa/hmac_demo.c
+++ b/programs/psa/hmac_demo.c
@@ -81,7 +81,7 @@
 
 /* Run a PSA function and bail out if it fails.
  * The symbolic name of the error code can be recovered using:
- * programs/psa/psa_consant_name status <value> */
+ * programs/psa/psa_constant_name status <value> */
 #define PSA_CHECK( expr )                                       \
     do                                                          \
     {                                                           \
diff --git a/programs/psa/key_ladder_demo.c b/programs/psa/key_ladder_demo.c
index 1303719..f40874e 100644
--- a/programs/psa/key_ladder_demo.c
+++ b/programs/psa/key_ladder_demo.c
@@ -713,4 +713,6 @@
     usage( );
     return( EXIT_FAILURE );
 }
-#endif /* MBEDTLS_SHA256_C && MBEDTLS_MD_C && MBEDTLS_AES_C && MBEDTLS_CCM_C && MBEDTLS_PSA_CRYPTO_C && MBEDTLS_FS_IO */
+#endif /* MBEDTLS_SHA256_C && MBEDTLS_MD_C &&
+          MBEDTLS_AES_C && MBEDTLS_CCM_C &&
+          MBEDTLS_PSA_CRYPTO_C && MBEDTLS_FS_IO */
diff --git a/programs/ssl/dtls_client.c b/programs/ssl/dtls_client.c
index 23a34e0..d13ea28 100644
--- a/programs/ssl/dtls_client.c
+++ b/programs/ssl/dtls_client.c
@@ -343,5 +343,5 @@
     mbedtls_exit( ret );
 }
 #endif /* MBEDTLS_SSL_CLI_C && MBEDTLS_SSL_PROTO_DTLS && MBEDTLS_NET_C &&
-          MBEDTLD_TIMING_C && MBEDTLS_ENTROPY_C && MBEDTLS_CTR_DRBG_C &&
+          MBEDTLS_TIMING_C && MBEDTLS_ENTROPY_C && MBEDTLS_CTR_DRBG_C &&
           MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_RSA_C && MBEDTLS_PEM_PARSE_C */
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 56efb3c..02ee7cf 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -64,9 +64,11 @@
 #define DFL_KEY_OPAQUE          0
 #define DFL_KEY_PWD             ""
 #define DFL_PSK                 ""
+#define DFL_EARLY_DATA          MBEDTLS_SSL_EARLY_DATA_DISABLED
 #define DFL_PSK_OPAQUE          0
 #define DFL_PSK_IDENTITY        "Client_identity"
 #define DFL_ECJPAKE_PW          NULL
+#define DFL_ECJPAKE_PW_OPAQUE   0
 #define DFL_EC_MAX_OPS          -1
 #define DFL_FORCE_CIPHER        0
 #define DFL_TLS1_3_KEX_MODES    MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_ALL
@@ -317,11 +319,17 @@
 #endif
 
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
 #define USAGE_ECJPAKE \
-    "    ecjpake_pw=%%s       default: none (disabled)\n"
-#else
+    "    ecjpake_pw=%%s           default: none (disabled)\n"   \
+    "    ecjpake_pw_opaque=%%d    default: 0 (disabled)\n"
+#else /* MBEDTLS_USE_PSA_CRYPTO */
+#define USAGE_ECJPAKE \
+    "    ecjpake_pw=%%s           default: none (disabled)\n"
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+#else /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
 #define USAGE_ECJPAKE ""
-#endif
+#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
 
 #if defined(MBEDTLS_ECP_RESTARTABLE)
 #define USAGE_ECRESTART \
@@ -344,6 +352,14 @@
 #define USAGE_SERIALIZATION ""
 #endif
 
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+#define USAGE_EARLY_DATA \
+    "    early_data=%%d        default: 0 (disabled)\n"      \
+    "                        options: 0 (disabled), 1 (enabled)\n"
+#else
+#define USAGE_EARLY_DATA ""
+#endif /* MBEDTLS_SSL_EARLY_DATA && MBEDTLS_SSL_PROTO_TLS1_3 */
+
 #define USAGE_KEY_OPAQUE_ALGS \
     "    key_opaque_algs=%%s  Allowed opaque key algorithms.\n"                      \
     "                        comma-separated pair of values among the following:\n"    \
@@ -422,6 +438,7 @@
     USAGE_REPRODUCIBLE                                      \
     USAGE_CURVES                                            \
     USAGE_SIG_ALGS                                          \
+    USAGE_EARLY_DATA                                        \
     USAGE_DHMLEN                                            \
     USAGE_KEY_OPAQUE_ALGS                                   \
     "\n"
@@ -482,6 +499,9 @@
     const char *psk;            /* the pre-shared key                       */
     const char *psk_identity;   /* the pre-shared key identity              */
     const char *ecjpake_pw;     /* the EC J-PAKE password                   */
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    int ecjpake_pw_opaque;      /* set to 1 to use the opaque method for setting the password */
+#endif
     int ec_max_ops;             /* EC consecutive operations limit          */
     int force_ciphersuite[2];   /* protocol/ciphersuite to use, or all      */
 #if defined(MBEDTLS_SSL_PROTO_TLS1_3)
@@ -533,6 +553,9 @@
                                  * after renegotiation                      */
     int reproducible;           /* make communication reproducible          */
     int skip_close_notify;      /* skip sending the close_notify alert      */
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+    int early_data;             /* support for early data                   */
+#endif
     int query_config_mode;      /* whether to read config                   */
     int use_srtp;               /* Support SRTP                             */
     int force_srtp_profile;     /* SRTP protection profile to use or all    */
@@ -811,6 +834,10 @@
         MBEDTLS_TLS_SRTP_UNSET
     };
 #endif /* MBEDTLS_SSL_DTLS_SRTP */
+#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) && \
+    defined(MBEDTLS_USE_PSA_CRYPTO)
+    mbedtls_svc_key_id_t ecjpake_pw_slot = MBEDTLS_SVC_KEY_ID_INIT; /* ecjpake password key slot */
+#endif /* MBEDTLS_USE_PSA_CRYPTO && MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
 
 #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
     mbedtls_memory_buffer_alloc_init( alloc_buf, sizeof(alloc_buf) );
@@ -906,6 +933,9 @@
 #endif
     opt.psk_identity        = DFL_PSK_IDENTITY;
     opt.ecjpake_pw          = DFL_ECJPAKE_PW;
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    opt.ecjpake_pw_opaque   = DFL_ECJPAKE_PW_OPAQUE;
+#endif
     opt.ec_max_ops          = DFL_EC_MAX_OPS;
     opt.force_ciphersuite[0]= DFL_FORCE_CIPHER;
 #if defined(MBEDTLS_SSL_PROTO_TLS1_3)
@@ -932,6 +962,9 @@
     opt.alpn_string         = DFL_ALPN_STRING;
     opt.curves              = DFL_CURVES;
     opt.sig_algs            = DFL_SIG_ALGS;
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+    opt.early_data          = DFL_EARLY_DATA;
+#endif
     opt.transport           = DFL_TRANSPORT;
     opt.hs_to_min           = DFL_HS_TO_MIN;
     opt.hs_to_max           = DFL_HS_TO_MAX;
@@ -1078,6 +1111,10 @@
             opt.psk_identity = q;
         else if( strcmp( p, "ecjpake_pw" ) == 0 )
             opt.ecjpake_pw = q;
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+        else if( strcmp( p, "ecjpake_pw_opaque" ) == 0 )
+            opt.ecjpake_pw_opaque = atoi( q );
+#endif
         else if( strcmp( p, "ec_max_ops" ) == 0 )
             opt.ec_max_ops = atoi( q );
         else if( strcmp( p, "force_ciphersuite" ) == 0 )
@@ -1189,7 +1226,24 @@
                 default: goto usage;
             }
         }
+
 #if defined(MBEDTLS_SSL_PROTO_TLS1_3)
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+        else if( strcmp( p, "early_data" ) == 0 )
+        {
+            switch( atoi( q ) )
+            {
+                case 0:
+                    opt.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED;
+                    break;
+                case 1:
+                    opt.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED;
+                    break;
+                default: goto usage;
+            }
+        }
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
         else if( strcmp( p, "tls13_kex_modes" ) == 0 )
         {
             if( strcmp( q, "psk" ) == 0 )
@@ -2091,6 +2145,10 @@
     if( opt.max_version != DFL_MAX_VERSION )
         mbedtls_ssl_conf_max_tls_version( &conf, opt.max_version );
 
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+    mbedtls_ssl_tls13_conf_early_data( &conf, opt.early_data );
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
     if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
     {
         mbedtls_printf( " failed\n  ! mbedtls_ssl_setup returned -0x%x\n\n",
@@ -2129,16 +2187,46 @@
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
     if( opt.ecjpake_pw != DFL_ECJPAKE_PW )
     {
-        if( ( ret = mbedtls_ssl_set_hs_ecjpake_password( &ssl,
-                        (const unsigned char *) opt.ecjpake_pw,
-                                        strlen( opt.ecjpake_pw ) ) ) != 0 )
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+        if ( opt.ecjpake_pw_opaque != DFL_ECJPAKE_PW_OPAQUE )
         {
-            mbedtls_printf( " failed\n  ! mbedtls_ssl_set_hs_ecjpake_password returned %d\n\n",
-                            ret );
-            goto exit;
+            psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+            psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DERIVE );
+            psa_set_key_algorithm( &attributes, PSA_ALG_JPAKE );
+            psa_set_key_type( &attributes, PSA_KEY_TYPE_PASSWORD );
+
+            status = psa_import_key( &attributes,
+                                (const unsigned char *) opt.ecjpake_pw,
+                                strlen( opt.ecjpake_pw ),
+                                &ecjpake_pw_slot );
+            if( status != PSA_SUCCESS )
+            {
+                mbedtls_printf( " failed\n  ! psa_import_key returned %d\n\n",
+                            status );
+                goto exit;
+            }
+            if( ( ret = mbedtls_ssl_set_hs_ecjpake_password_opaque( &ssl,
+                                        ecjpake_pw_slot ) ) != 0 )
+            {
+                mbedtls_printf( " failed\n  ! mbedtls_ssl_set_hs_ecjpake_password_opaque returned %d\n\n", ret );
+                goto exit;
+            }
+            mbedtls_printf( "using opaque password\n");
+        }
+        else
+#endif  /* MBEDTLS_USE_PSA_CRYPTO */
+        {
+            if( ( ret = mbedtls_ssl_set_hs_ecjpake_password( &ssl,
+                                        (const unsigned char *) opt.ecjpake_pw,
+                                        strlen( opt.ecjpake_pw ) ) ) != 0 )
+            {
+                mbedtls_printf( " failed\n  ! mbedtls_ssl_set_hs_ecjpake_password returned %d\n\n", ret );
+                goto exit;
+            }
         }
     }
-#endif
+#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
 
 #if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
     if( opt.context_crt_cb == 1 )
@@ -3239,6 +3327,31 @@
 #endif /* MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED &&
           MBEDTLS_USE_PSA_CRYPTO */
 
+#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) && \
+    defined(MBEDTLS_USE_PSA_CRYPTO)
+    /*
+     * In case opaque keys it's the user responsibility to keep the key valid
+     * for the duration of the handshake and destroy it at the end
+     */
+    if( ( opt.ecjpake_pw_opaque != DFL_ECJPAKE_PW_OPAQUE ) )
+    {
+        psa_key_attributes_t check_attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+        /* Verify that the key is still valid before destroying it */
+        if( psa_get_key_attributes( ecjpake_pw_slot, &check_attributes ) !=
+                PSA_SUCCESS )
+        {
+            if( ret == 0 )
+                ret = 1;
+            mbedtls_printf( "The EC J-PAKE password key has unexpectedly been already destroyed\n" );
+        }
+        else
+        {
+            psa_destroy_key( ecjpake_pw_slot );
+        }
+    }
+#endif  /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED && MBEDTLS_USE_PSA_CRYPTO */
+
 #if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)
     const char* message = mbedtls_test_helper_is_psa_leaking();
     if( message )
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 1b4a94a..802beb2 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -98,6 +98,7 @@
 #define DFL_PSK_LIST_OPAQUE     0
 #define DFL_PSK_IDENTITY        "Client_identity"
 #define DFL_ECJPAKE_PW          NULL
+#define DFL_ECJPAKE_PW_OPAQUE   0
 #define DFL_PSK_LIST            NULL
 #define DFL_FORCE_CIPHER        0
 #define DFL_TLS1_3_KEX_MODES    MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_ALL
@@ -129,6 +130,7 @@
 #define DFL_SNI                 NULL
 #define DFL_ALPN_STRING         NULL
 #define DFL_CURVES              NULL
+#define DFL_MAX_EARLY_DATA_SIZE 0
 #define DFL_SIG_ALGS            NULL
 #define DFL_DHM_FILE            NULL
 #define DFL_TRANSPORT           MBEDTLS_SSL_TRANSPORT_STREAM
@@ -418,11 +420,26 @@
 #endif
 
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
 #define USAGE_ECJPAKE \
-    "    ecjpake_pw=%%s       default: none (disabled)\n"
-#else
+    "    ecjpake_pw=%%s           default: none (disabled)\n"   \
+    "    ecjpake_pw_opaque=%%d    default: 0 (disabled)\n"
+#else /* MBEDTLS_USE_PSA_CRYPTO */
+#define USAGE_ECJPAKE \
+    "    ecjpake_pw=%%s           default: none (disabled)\n"
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+#else /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
 #define USAGE_ECJPAKE ""
-#endif
+#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
+
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+#define USAGE_EARLY_DATA \
+    "    max_early_data_size=%%d default: -1 (disabled)\n"             \
+    "                            options: -1 (disabled), "           \
+    "                                     >= 0 (enabled, max amount of early data )\n"
+#else
+#define USAGE_EARLY_DATA ""
+#endif /* MBEDTLS_SSL_EARLY_DATA */
 
 #if defined(MBEDTLS_ECP_C)
 #define USAGE_CURVES \
@@ -621,6 +638,9 @@
     const char *psk_identity;   /* the pre-shared key identity              */
     char *psk_list;             /* list of PSK id/key pairs for callback    */
     const char *ecjpake_pw;     /* the EC J-PAKE password                   */
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    int ecjpake_pw_opaque;      /* set to 1 to use the opaque method for setting the password */
+#endif
     int force_ciphersuite[2];   /* protocol/ciphersuite to use, or all      */
 #if defined(MBEDTLS_SSL_PROTO_TLS1_3)
     int tls13_kex_modes;        /* supported TLS 1.3 key exchange modes     */
@@ -677,6 +697,7 @@
     const char *cid_val_renego; /* the CID to use for incoming messages
                                  * after renegotiation                      */
     int reproducible;           /* make communication reproducible          */
+    uint32_t max_early_data_size; /* max amount of early data               */
     int query_config_mode;      /* whether to read config                   */
     int use_srtp;               /* Support SRTP                             */
     int force_srtp_profile;     /* SRTP protection profile to use or all    */
@@ -1506,6 +1527,10 @@
     unsigned char *context_buf = NULL;
     size_t context_buf_len = 0;
 #endif
+#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) && \
+    defined(MBEDTLS_USE_PSA_CRYPTO)
+    mbedtls_svc_key_id_t ecjpake_pw_slot = MBEDTLS_SVC_KEY_ID_INIT; /* ecjpake password key slot */
+#endif /* MBEDTLS_USE_PSA_CRYPTO && MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
 
 #if defined(MBEDTLS_SSL_HANDSHAKE_WITH_CERT_ENABLED)
     uint16_t sig_alg_list[SIG_ALG_LIST_SIZE];
@@ -1535,6 +1560,9 @@
      };
 #endif /* MBEDTLS_SSL_DTLS_SRTP */
 
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+    int tls13_early_data_enabled = MBEDTLS_SSL_EARLY_DATA_DISABLED;
+#endif
 #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
     mbedtls_memory_buffer_alloc_init( alloc_buf, sizeof(alloc_buf) );
 #if defined(MBEDTLS_MEMORY_DEBUG)
@@ -1661,6 +1689,9 @@
     opt.psk_identity        = DFL_PSK_IDENTITY;
     opt.psk_list            = DFL_PSK_LIST;
     opt.ecjpake_pw          = DFL_ECJPAKE_PW;
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    opt.ecjpake_pw_opaque   = DFL_ECJPAKE_PW_OPAQUE;
+#endif
     opt.force_ciphersuite[0]= DFL_FORCE_CIPHER;
 #if defined(MBEDTLS_SSL_PROTO_TLS1_3)
     opt.tls13_kex_modes     = DFL_TLS1_3_KEX_MODES;
@@ -1691,6 +1722,7 @@
     opt.sni                 = DFL_SNI;
     opt.alpn_string         = DFL_ALPN_STRING;
     opt.curves              = DFL_CURVES;
+    opt.max_early_data_size = DFL_MAX_EARLY_DATA_SIZE;
     opt.sig_algs            = DFL_SIG_ALGS;
     opt.dhm_file            = DFL_DHM_FILE;
     opt.transport           = DFL_TRANSPORT;
@@ -1864,6 +1896,10 @@
             opt.psk_list = q;
         else if( strcmp( p, "ecjpake_pw" ) == 0 )
             opt.ecjpake_pw = q;
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+        else if( strcmp( p, "ecjpake_pw_opaque" ) == 0 )
+            opt.ecjpake_pw_opaque = atoi( q );
+#endif
         else if( strcmp( p, "force_ciphersuite" ) == 0 )
         {
             opt.force_ciphersuite[0] = mbedtls_ssl_get_ciphersuite_id( q );
@@ -1881,6 +1917,19 @@
         else if( strcmp( p, "sig_algs" ) == 0 )
             opt.sig_algs = q;
 #endif
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+        else if( strcmp( p, "max_early_data_size" ) == 0 )
+        {
+            long long value = atoll( q );
+            tls13_early_data_enabled =
+                value >= 0 ? MBEDTLS_SSL_EARLY_DATA_ENABLED :
+                             MBEDTLS_SSL_EARLY_DATA_DISABLED;
+            if( tls13_early_data_enabled )
+            {
+                opt.max_early_data_size = atoi( q );
+            }
+        }
+#endif /* MBEDTLS_SSL_EARLY_DATA */
         else if( strcmp( p, "renegotiation" ) == 0 )
         {
             opt.renegotiation = (atoi( q )) ?
@@ -1949,7 +1998,7 @@
              * is not recommended in practice.
              * `psk_or_ephemeral` exists in theory, we need this mode to test if
              * this setting work correctly. With this key exchange setting, server
-             * should always perform `ephemeral` handshake. `psk` or `psk_ephermal`
+             * should always perform `ephemeral` handshake. `psk` or `psk_ephemeral`
              * is not expected.
              */
             else if( strcmp( q, "psk_or_ephemeral" ) == 0 )
@@ -2876,6 +2925,15 @@
     if( opt.cert_req_ca_list != DFL_CERT_REQ_CA_LIST )
         mbedtls_ssl_conf_cert_req_ca_list( &conf, opt.cert_req_ca_list );
 
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+    mbedtls_ssl_tls13_conf_early_data( &conf, tls13_early_data_enabled );
+    if( tls13_early_data_enabled == MBEDTLS_SSL_EARLY_DATA_ENABLED )
+    {
+        mbedtls_ssl_tls13_conf_max_early_data_size(
+            &conf, opt.max_early_data_size );
+    }
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
 #if defined(MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED)
     /* exercise setting DN hints for server certificate request
      * (Intended for use where the client cert expected has been signed by
@@ -3491,15 +3549,46 @@
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
     if( opt.ecjpake_pw != DFL_ECJPAKE_PW )
     {
-        if( ( ret = mbedtls_ssl_set_hs_ecjpake_password( &ssl,
-                        (const unsigned char *) opt.ecjpake_pw,
-                                        strlen( opt.ecjpake_pw ) ) ) != 0 )
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+        if ( opt.ecjpake_pw_opaque != DFL_ECJPAKE_PW_OPAQUE )
         {
-            mbedtls_printf( " failed\n  ! mbedtls_ssl_set_hs_ecjpake_password returned %d\n\n", ret );
-            goto exit;
+            psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+            psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DERIVE );
+            psa_set_key_algorithm( &attributes, PSA_ALG_JPAKE );
+            psa_set_key_type( &attributes, PSA_KEY_TYPE_PASSWORD );
+
+            status = psa_import_key( &attributes,
+                                (const unsigned char *) opt.ecjpake_pw,
+                                strlen( opt.ecjpake_pw ),
+                                &ecjpake_pw_slot );
+            if( status != PSA_SUCCESS )
+            {
+                mbedtls_printf( " failed\n  ! psa_import_key returned %d\n\n",
+                            status );
+                goto exit;
+            }
+            if( ( ret = mbedtls_ssl_set_hs_ecjpake_password_opaque( &ssl,
+                                        ecjpake_pw_slot ) ) != 0 )
+            {
+                mbedtls_printf( " failed\n  ! mbedtls_ssl_set_hs_ecjpake_password_opaque returned %d\n\n", ret );
+                goto exit;
+            }
+            mbedtls_printf( "using opaque password\n");
+        }
+        else
+#endif  /* MBEDTLS_USE_PSA_CRYPTO */
+        {
+            if( ( ret = mbedtls_ssl_set_hs_ecjpake_password( &ssl,
+                                        (const unsigned char *) opt.ecjpake_pw,
+                                        strlen( opt.ecjpake_pw ) ) ) != 0 )
+            {
+                mbedtls_printf( " failed\n  ! mbedtls_ssl_set_hs_ecjpake_password returned %d\n\n", ret );
+                goto exit;
+            }
         }
     }
-#endif
+#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
 
 #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
 #if defined(MBEDTLS_KEY_EXCHANGE_CERT_REQ_ALLOWED_ENABLED)
@@ -4385,6 +4474,31 @@
 #endif /* MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED &&
           MBEDTLS_USE_PSA_CRYPTO */
 
+#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) && \
+    defined(MBEDTLS_USE_PSA_CRYPTO)
+    /*
+     * In case opaque keys it's the user responsibility to keep the key valid
+     * for the duration of the handshake and destroy it at the end
+     */
+    if( ( opt.ecjpake_pw_opaque != DFL_ECJPAKE_PW_OPAQUE ) )
+    {
+        psa_key_attributes_t check_attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+        /* Verify that the key is still valid before destroying it */
+        if( psa_get_key_attributes( ecjpake_pw_slot, &check_attributes ) !=
+                PSA_SUCCESS )
+        {
+            if( ret == 0 )
+                ret = 1;
+            mbedtls_printf( "The EC J-PAKE password key has unexpectedly been already destroyed\n" );
+        }
+        else
+        {
+            psa_destroy_key( ecjpake_pw_slot );
+        }
+    }
+#endif  /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED && MBEDTLS_USE_PSA_CRYPTO */
+
 #if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_SSL_PROTO_TLS1_3)
     const char* message = mbedtls_test_helper_is_psa_leaking();
     if( message )
diff --git a/programs/test/benchmark.c b/programs/test/benchmark.c
index ecb093e..1ad2034 100644
--- a/programs/test/benchmark.c
+++ b/programs/test/benchmark.c
@@ -398,7 +398,7 @@
     }
 
     gettimeofday( &tv_cur, NULL );
-    return( ( tv_cur.tv_sec  - tv_init.tv_sec  ) * 1000000
+    return( ( tv_cur.tv_sec  - tv_init.tv_sec  ) * 1000000U
           + ( tv_cur.tv_usec - tv_init.tv_usec ) );
 }
 #endif /* !HAVE_HARDCLOCK */
@@ -416,7 +416,7 @@
     Sleep( alarmMs );
     mbedtls_timing_alarmed = 1;
     /* _endthread will be called implicitly on return
-     * That ensures execution of thread funcition's epilogue */
+     * That ensures execution of thread function's epilogue */
 }
 
 static void mbedtls_set_alarm( int seconds )
diff --git a/programs/test/cmake_package_install/CMakeLists.txt b/programs/test/cmake_package_install/CMakeLists.txt
index 711a1e5..fb5ad51 100644
--- a/programs/test/cmake_package_install/CMakeLists.txt
+++ b/programs/test/cmake_package_install/CMakeLists.txt
@@ -26,7 +26,7 @@
 # Locate the package.
 #
 
-set(MbedTLS_DIR "${MbedTLS_INSTALL_DIR}/cmake")
+list(INSERT CMAKE_PREFIX_PATH 0 "${MbedTLS_INSTALL_DIR}")
 find_package(MbedTLS REQUIRED)
 
 #
diff --git a/programs/test/udp_proxy.c b/programs/test/udp_proxy.c
index e3386d1..ccd1303 100644
--- a/programs/test/udp_proxy.c
+++ b/programs/test/udp_proxy.c
@@ -377,7 +377,7 @@
 
 #if defined(MBEDTLS_TIMING_C)
 /* Return elapsed time in milliseconds since the first call */
-static unsigned ellapsed_time( void )
+static unsigned elapsed_time( void )
 {
     static int initialized = 0;
     static struct mbedtls_timing_hr_time hires;
@@ -413,9 +413,9 @@
     int ret;
 
     mbedtls_printf( "  %05u flush    %s: %u bytes, %u datagrams, last %u ms\n",
-                    ellapsed_time(), buf->description,
+                    elapsed_time(), buf->description,
                     (unsigned) buf->len, buf->num_datagrams,
-                    ellapsed_time() - buf->packet_lifetime );
+                    elapsed_time() - buf->packet_lifetime );
 
     ret = mbedtls_net_send( buf->ctx, buf->data, buf->len );
 
@@ -427,7 +427,7 @@
 
 static unsigned ctx_buffer_time_remaining( ctx_buffer *buf )
 {
-    unsigned const cur_time = ellapsed_time();
+    unsigned const cur_time = elapsed_time();
 
     if( buf->num_datagrams == 0 )
         return( (unsigned) -1 );
@@ -467,7 +467,7 @@
 
     buf->len += len;
     if( ++buf->num_datagrams == 1 )
-        buf->packet_lifetime = ellapsed_time();
+        buf->packet_lifetime = elapsed_time();
 
     return( (int) len );
 }
@@ -517,10 +517,10 @@
 #if defined(MBEDTLS_TIMING_C)
     if( why == NULL )
         mbedtls_printf( "  %05u dispatch %s %s (%u bytes)\n",
-                ellapsed_time(), p->way, p->type, p->len );
+                elapsed_time(), p->way, p->type, p->len );
     else
         mbedtls_printf( "  %05u dispatch %s %s (%u bytes): %s\n",
-                ellapsed_time(), p->way, p->type, p->len, why );
+                elapsed_time(), p->way, p->type, p->len, why );
 #else
     if( why == NULL )
         mbedtls_printf( "        dispatch %s %s (%u bytes)\n",
diff --git a/programs/x509/cert_req.c b/programs/x509/cert_req.c
index 30b389a..4879583 100644
--- a/programs/x509/cert_req.c
+++ b/programs/x509/cert_req.c
@@ -355,7 +355,7 @@
     if( ( ret = write_certificate_request( &req, opt.output_file,
                                            mbedtls_ctr_drbg_random, &ctr_drbg ) ) != 0 )
     {
-        mbedtls_printf( " failed\n  !  write_certifcate_request %d", ret );
+        mbedtls_printf( " failed\n  !  write_certificate_request %d", ret );
         goto exit;
     }
 
diff --git a/programs/x509/cert_write.c b/programs/x509/cert_write.c
index f9366fe..a8910d7 100644
--- a/programs/x509/cert_write.c
+++ b/programs/x509/cert_write.c
@@ -752,7 +752,7 @@
         if( ret != 0 )
         {
             mbedtls_strerror( ret, buf, sizeof(buf) );
-            mbedtls_printf( " failed\n  !  x509write_crt_set_basic_contraints "
+            mbedtls_printf( " failed\n  !  x509write_crt_set_basic_constraints "
                             "returned -0x%04x - %s\n\n", (unsigned int) -ret, buf );
             goto exit;
         }
diff --git a/scripts/code_style.py b/scripts/code_style.py
new file mode 100755
index 0000000..8e82b93
--- /dev/null
+++ b/scripts/code_style.py
@@ -0,0 +1,185 @@
+#!/usr/bin/env python3
+"""Check or fix the code style by running Uncrustify.
+
+Note: The code style enforced by this script is not yet introduced to
+Mbed TLS. At present this script will only be used to prepare for a future
+change of code style.
+"""
+# 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 argparse
+import io
+import os
+import re
+import subprocess
+import sys
+from typing import FrozenSet, List
+
+UNCRUSTIFY_SUPPORTED_VERSION = "0.75.1"
+CONFIG_FILE = ".uncrustify.cfg"
+UNCRUSTIFY_EXE = "uncrustify"
+UNCRUSTIFY_ARGS = ["-c", CONFIG_FILE]
+STDOUT_UTF8 = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
+STDERR_UTF8 = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
+CHECK_GENERATED_FILES = "tests/scripts/check-generated-files.sh"
+
+def print_err(*args):
+    print("Error: ", *args, file=STDERR_UTF8)
+
+# Match FILENAME(s) in "check SCRIPT (FILENAME...)"
+CHECK_CALL_RE = re.compile(r"\n\s*check\s+[^\s#$&*?;|]+([^\n#$&*?;|]+)",
+                           re.ASCII)
+def list_generated_files() -> FrozenSet[str]:
+    """Return the names of generated files.
+
+    We don't reformat generated files, since the result might be different
+    from the output of the generator. Ideally the result of the generator
+    would conform to the code style, but this would be difficult, especially
+    with respect to the placement of line breaks in long logical lines.
+    """
+    # Parse check-generated-files.sh to get an up-to-date list of
+    # generated files. Read the file rather than calling it so that
+    # this script only depends on Git, Python and uncrustify, and not other
+    # tools such as sh or grep which might not be available on Windows.
+    # This introduces a limitation: check-generated-files.sh must have
+    # the expected format and must list the files explicitly, not through
+    # wildcards or command substitution.
+    content = open(CHECK_GENERATED_FILES, encoding="utf-8").read()
+    checks = re.findall(CHECK_CALL_RE, content)
+    return frozenset(word for s in checks for word in s.split())
+
+def get_src_files() -> List[str]:
+    """
+    Use git ls-files to get a list of the source files
+    """
+    git_ls_files_cmd = ["git", "ls-files",
+                        "*.[hc]",
+                        "tests/suites/*.function",
+                        "scripts/data_files/*.fmt"]
+
+    result = subprocess.run(git_ls_files_cmd, stdout=subprocess.PIPE, \
+            stderr=STDERR_UTF8, check=False)
+
+    if result.returncode != 0:
+        print_err("git ls-files returned: " + str(result.returncode))
+        return []
+    else:
+        generated_files = list_generated_files()
+        src_files = str(result.stdout, "utf-8").split()
+        # Don't correct style for third-party files (and, for simplicity,
+        # companion files in the same subtree), or for automatically
+        # generated files (we're correcting the templates instead).
+        src_files = [filename for filename in src_files
+                     if not (filename.startswith("3rdparty/") or
+                             filename in generated_files)]
+        return src_files
+
+def get_uncrustify_version() -> str:
+    """
+    Get the version string from Uncrustify
+    """
+    result = subprocess.run([UNCRUSTIFY_EXE, "--version"], \
+            stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False)
+    if result.returncode != 0:
+        print_err("Could not get Uncrustify version:", str(result.stderr, "utf-8"))
+        return ""
+    else:
+        return str(result.stdout, "utf-8")
+
+def check_style_is_correct(src_file_list: List[str]) -> bool:
+    """
+    Check the code style and output a diff for each file whose style is
+    incorrect.
+    """
+    style_correct = True
+    for src_file in src_file_list:
+        uncrustify_cmd = [UNCRUSTIFY_EXE] + UNCRUSTIFY_ARGS + [src_file]
+        subprocess.run(uncrustify_cmd, stdout=subprocess.PIPE, \
+                stderr=subprocess.PIPE, check=False)
+
+        # Uncrustify makes changes to the code and places the result in a new
+        # file with the extension ".uncrustify". To get the changes (if any)
+        # simply diff the 2 files.
+        diff_cmd = ["diff", "-u", src_file, src_file + ".uncrustify"]
+        result = subprocess.run(diff_cmd, stdout=subprocess.PIPE, \
+                stderr=STDERR_UTF8, check=False)
+        if len(result.stdout) > 0:
+            print(src_file + " - Incorrect code style.", file=STDOUT_UTF8)
+            print("File changed - diff:", file=STDOUT_UTF8)
+            print(str(result.stdout, "utf-8"), file=STDOUT_UTF8)
+            style_correct = False
+        else:
+            print(src_file + " - OK.", file=STDOUT_UTF8)
+
+        # Tidy up artifact
+        os.remove(src_file + ".uncrustify")
+
+    return style_correct
+
+def fix_style_single_pass(src_file_list: List[str]) -> None:
+    """
+    Run Uncrustify once over the source files.
+    """
+    code_change_args = UNCRUSTIFY_ARGS + ["--no-backup"]
+    for src_file in src_file_list:
+        uncrustify_cmd = [UNCRUSTIFY_EXE] + code_change_args + [src_file]
+        subprocess.run(uncrustify_cmd, check=False, stdout=STDOUT_UTF8, \
+                stderr=STDERR_UTF8)
+
+def fix_style(src_file_list: List[str]) -> int:
+    """
+    Fix the code style. This takes 2 passes of Uncrustify.
+    """
+    fix_style_single_pass(src_file_list)
+    fix_style_single_pass(src_file_list)
+
+    # Guard against future changes that cause the codebase to require
+    # more passes.
+    if not check_style_is_correct(src_file_list):
+        print("Code style still incorrect after second run of Uncrustify.")
+        return 1
+    else:
+        return 0
+
+def main() -> int:
+    """
+    Main with command line arguments.
+    """
+    uncrustify_version = get_uncrustify_version().strip()
+    if UNCRUSTIFY_SUPPORTED_VERSION not in uncrustify_version:
+        print("Warning: Using unsupported Uncrustify version '" \
+                + uncrustify_version + "' (Note: The only supported version" \
+                "is " + UNCRUSTIFY_SUPPORTED_VERSION + ")", file=STDOUT_UTF8)
+
+    src_files = get_src_files()
+
+    parser = argparse.ArgumentParser()
+    parser.add_argument('-f', '--fix', action='store_true', \
+            help='modify source files to fix the code style')
+
+    args = parser.parse_args()
+
+    if args.fix:
+        # Fix mode
+        return fix_style(src_files)
+    else:
+        # Check mode
+        if check_style_is_correct(src_files):
+            return 0
+        else:
+            return 1
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/scripts/config.py b/scripts/config.py
index 470c63d..a53c470 100755
--- a/scripts/config.py
+++ b/scripts/config.py
@@ -194,7 +194,6 @@
     'MBEDTLS_DEPRECATED_WARNING', # conflicts with deprecated options
     'MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED', # influences the use of ECDH in TLS
     'MBEDTLS_ECP_NO_FALLBACK', # removes internal ECP implementation
-    'MBEDTLS_ECP_RESTARTABLE', # incompatible with USE_PSA_CRYPTO
     'MBEDTLS_ENTROPY_FORCE_SHA256', # interacts with CTR_DRBG_128_BIT_KEY
     'MBEDTLS_HAVE_SSE2', # hardware dependency
     'MBEDTLS_MEMORY_BACKTRACE', # depends on MEMORY_BUFFER_ALLOC_C
@@ -311,6 +310,7 @@
     if name in [
             'MBEDTLS_DEBUG_C', # part of libmbedtls
             'MBEDTLS_NET_C', # part of libmbedtls
+            'MBEDTLS_PKCS7_C', # part of libmbedx509
     ]:
         return False
     return True
diff --git a/scripts/data_files/driver_templates/psa_crypto_driver_wrappers.c.jinja b/scripts/data_files/driver_templates/psa_crypto_driver_wrappers.c.jinja
index a491b07..e716e40 100644
--- a/scripts/data_files/driver_templates/psa_crypto_driver_wrappers.c.jinja
+++ b/scripts/data_files/driver_templates/psa_crypto_driver_wrappers.c.jinja
@@ -291,7 +291,7 @@
                     alg, hash, hash_length,
                     signature, signature_size, signature_length ) );
     }
-#endif /* PSA_CRYPTO_SE_C */
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
 
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location =
@@ -375,7 +375,7 @@
                     alg, hash, hash_length,
                     signature, signature_length ) );
     }
-#endif /* PSA_CRYPTO_SE_C */
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
 
     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
     psa_key_location_t location =
@@ -647,7 +647,7 @@
 
         return( PSA_SUCCESS );
     }
-#endif /* PSA_CRYPTO_SE_C */
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
 
     switch( location )
     {
@@ -715,7 +715,7 @@
                      *( (psa_key_slot_number_t *)key_buffer ),
                      data, data_size, data_length ) );
     }
-#endif /* PSA_CRYPTO_SE_C */
+#endif /* MBEDTLS_PSA_CRYPTO_SE_C */
 
     switch( location )
     {
@@ -2476,4 +2476,72 @@
     }
 }
 
+psa_status_t psa_driver_wrapper_key_agreement(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer,
+    size_t key_buffer_size,
+    psa_algorithm_t alg,
+    const uint8_t *peer_key,
+    size_t peer_key_length,
+    uint8_t *shared_secret,
+    size_t shared_secret_size,
+    size_t *shared_secret_length
+ )
+ {
+    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+    psa_key_location_t location =
+        PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
+
+    switch( location )
+    {
+        case PSA_KEY_LOCATION_LOCAL_STORAGE:
+            /* Key is stored in the slot in export representation, so
+             * cycle through all known transparent accelerators */
+#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+            status =
+                mbedtls_test_transparent_key_agreement( attributes,
+                        key_buffer, key_buffer_size, alg, peer_key,
+                        peer_key_length, shared_secret, shared_secret_size,
+                        shared_secret_length );
+            if( status != PSA_ERROR_NOT_SUPPORTED )
+                return( status );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
+
+            /* Software Fallback */
+            status = psa_key_agreement_raw_builtin( attributes,
+                                                    key_buffer,
+                                                    key_buffer_size,
+                                                    alg,
+                                                    peer_key,
+                                                    peer_key_length,
+                                                    shared_secret,
+                                                    shared_secret_size,
+                                                    shared_secret_length );
+            return( status );
+#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+        case PSA_CRYPTO_TEST_DRIVER_LOCATION:
+            return( mbedtls_test_opaque_key_agreement( attributes,
+                        key_buffer, key_buffer_size, alg, peer_key,
+                        peer_key_length, shared_secret, shared_secret_size,
+                        shared_secret_length ) );
+#endif /* PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
+
+        default:
+            (void) attributes;
+            (void) key_buffer;
+            (void) key_buffer_size;
+            (void) peer_key;
+            (void) peer_key_length;
+            (void) shared_secret;
+            (void) shared_secret_size;
+            (void) shared_secret_length;
+            return( PSA_ERROR_NOT_SUPPORTED );
+
+    }
+ }
+
 #endif /* MBEDTLS_PSA_CRYPTO_C */
diff --git a/scripts/generate_errors.pl b/scripts/generate_errors.pl
index 41b0337..5395abf 100755
--- a/scripts/generate_errors.pl
+++ b/scripts/generate_errors.pl
@@ -52,7 +52,7 @@
                             SHA1 SHA256 SHA512 THREADING );
 my @high_level_modules = qw( CIPHER DHM ECP MD
                              PEM PK PKCS12 PKCS5
-                             RSA SSL X509 );
+                             RSA SSL X509 PKCS7 );
 
 undef $/;
 
@@ -136,6 +136,7 @@
     $define_name = "ASN1_PARSE" if ($define_name eq "ASN1");
     $define_name = "SSL_TLS" if ($define_name eq "SSL");
     $define_name = "PEM_PARSE,PEM_WRITE" if ($define_name eq "PEM");
+    $define_name = "PKCS7" if ($define_name eq "PKCS7");
 
     my $include_name = $module_name;
     $include_name =~ tr/A-Z/a-z/;
diff --git a/scripts/lcov.sh b/scripts/lcov.sh
new file mode 100755
index 0000000..8d141ee
--- /dev/null
+++ b/scripts/lcov.sh
@@ -0,0 +1,81 @@
+#!/bin/sh
+
+help () {
+    cat <<EOF
+Usage: $0 [-r]
+Collect coverage statistics of library code into an HTML report.
+
+General instructions:
+1. Build the library with CFLAGS="--coverage -O0 -g3" and link the test
+   programs with LDFLAGS="--coverage".
+   This can be an out-of-tree build.
+   For example (in-tree):
+        make CFLAGS="--coverage -O0 -g3" LDFLAGS="--coverage"
+   Or (out-of-tree):
+        mkdir build-coverage && cd build-coverage &&
+        cmake -D CMAKE_BUILD_TYPE=Coverage .. && make
+2. Run whatever tests you want.
+3. Run this script from the parent of the directory containing the library
+   object files and coverage statistics files.
+4. Browse the coverage report in Coverage/index.html.
+5. After rework, run "$0 -r", then re-test and run "$0" to get a fresh report.
+
+Options
+  -r    Reset traces. Run this before re-testing to get fresh measurements.
+EOF
+}
+
+# Copyright The Mbed TLS Contributors
+# SPDX-License-Identifier: Apache-2.0
+#
+# 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.
+
+set -eu
+
+# Collect stats and build a HTML report.
+lcov_library_report () {
+    rm -rf Coverage
+    mkdir Coverage Coverage/tmp
+    lcov --capture --initial --directory library -o Coverage/tmp/files.info
+    lcov --rc lcov_branch_coverage=1 --capture --directory library -o Coverage/tmp/tests.info
+    lcov --rc lcov_branch_coverage=1 --add-tracefile Coverage/tmp/files.info --add-tracefile Coverage/tmp/tests.info -o Coverage/tmp/all.info
+    lcov --rc lcov_branch_coverage=1 --remove Coverage/tmp/all.info -o Coverage/tmp/final.info '*.h'
+    gendesc tests/Descriptions.txt -o Coverage/tmp/descriptions
+    genhtml --title "mbed TLS" --description-file Coverage/tmp/descriptions --keep-descriptions --legend --branch-coverage -o Coverage Coverage/tmp/final.info
+    rm -f Coverage/tmp/*.info Coverage/tmp/descriptions
+    echo "Coverage report in: Coverage/index.html"
+}
+
+# Reset the traces to 0.
+lcov_reset_traces () {
+    # Location with plain make
+    rm -f library/*.gcda
+    # Location with CMake
+    rm -f library/CMakeFiles/*.dir/*.gcda
+}
+
+if [ $# -gt 0 ] && [ "$1" = "--help" ]; then
+    help
+    exit
+fi
+
+main=lcov_library_report
+while getopts r OPTLET; do
+    case $OPTLET in
+        r) main=lcov_reset_traces;;
+        *) help 2>&1; exit 120;;
+    esac
+done
+shift $((OPTIND - 1))
+
+"$main" "$@"
diff --git a/scripts/mbedtls_dev/bignum_common.py b/scripts/mbedtls_dev/bignum_common.py
index 279668f..2422175 100644
--- a/scripts/mbedtls_dev/bignum_common.py
+++ b/scripts/mbedtls_dev/bignum_common.py
@@ -14,11 +14,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import itertools
-import typing
-
 from abc import abstractmethod
-from typing import Iterator, List, Tuple, TypeVar
+import enum
+from typing import Iterator, List, Tuple, TypeVar, Any
+from itertools import chain
+
+from . import test_case
+from . import test_data_generation
+from .bignum_data import INPUTS_DEFAULT, MODULI_DEFAULT
 
 T = TypeVar('T') #pylint: disable=invalid-name
 
@@ -37,10 +40,21 @@
         return b
     raise ValueError("Not invertible")
 
-def hex_to_int(val: str) -> int:
-    return int(val, 16) if val else 0
+def invmod_positive(a: int, n: int) -> int:
+    """Return a non-negative inverse of a to modulo n."""
+    inv = invmod(a, n)
+    return inv if inv >= 0 else inv + n
 
-def quote_str(val) -> str:
+def hex_to_int(val: str) -> int:
+    """Implement the syntax accepted by mbedtls_test_read_mpi().
+
+    This is a superset of what is accepted by mbedtls_test_read_mpi_core().
+    """
+    if val in ['', '-']:
+        return 0
+    return int(val, 16)
+
+def quote_str(val: str) -> str:
     return "\"{}\"".format(val)
 
 def bound_mpi(val: int, bits_in_limb: int) -> int:
@@ -57,18 +71,10 @@
     return (val.bit_length() + bits_in_limb - 1) // bits_in_limb
 
 def combination_pairs(values: List[T]) -> List[Tuple[T, T]]:
-    """Return all pair combinations from input values.
+    """Return all pair combinations from input values."""
+    return [(x, y) for x in values for y in values]
 
-    The return value is cast, as older versions of mypy are unable to derive
-    the specific type returned by itertools.combinations_with_replacement.
-    """
-    return typing.cast(
-        List[Tuple[T, T]],
-        list(itertools.combinations_with_replacement(values, 2))
-    )
-
-
-class OperationCommon:
+class OperationCommon(test_data_generation.BaseTest):
     """Common features for bignum binary operations.
 
     This adds functionality common in binary operation tests.
@@ -82,22 +88,108 @@
         unique_combinations_only: Boolean to select if test case combinations
             must be unique. If True, only A,B or B,A would be included as a test
             case. If False, both A,B and B,A would be included.
+        input_style: Controls the way how test data is passed to the functions
+            in the generated test cases. "variable" passes them as they are
+            defined in the python source. "arch_split" pads the values with
+            zeroes depending on the architecture/limb size. If this is set,
+            test cases are generated for all architectures.
+        arity: the number of operands for the operation. Currently supported
+            values are 1 and 2.
     """
     symbol = ""
-    input_values = [] # type: List[str]
-    input_cases = [] # type: List[Tuple[str, str]]
-    unique_combinations_only = True
+    input_values = INPUTS_DEFAULT # type: List[str]
+    input_cases = [] # type: List[Any]
+    unique_combinations_only = False
+    input_styles = ["variable", "fixed", "arch_split"] # type: List[str]
+    input_style = "variable" # type: str
+    limb_sizes = [32, 64] # type: List[int]
+    arities = [1, 2]
+    arity = 2
+    suffix = False   # for arity = 1, symbol can be prefix (default) or suffix
 
-    def __init__(self, val_a: str, val_b: str) -> None:
-        self.arg_a = val_a
-        self.arg_b = val_b
+    def __init__(self, val_a: str, val_b: str = "0", bits_in_limb: int = 32) -> None:
+        self.val_a = val_a
+        self.val_b = val_b
+        # Setting the int versions here as opposed to making them @properties
+        # provides earlier/more robust input validation.
         self.int_a = hex_to_int(val_a)
         self.int_b = hex_to_int(val_b)
+        if bits_in_limb not in self.limb_sizes:
+            raise ValueError("Invalid number of bits in limb!")
+        if self.input_style == "arch_split":
+            self.dependencies = ["MBEDTLS_HAVE_INT{:d}".format(bits_in_limb)]
+        self.bits_in_limb = bits_in_limb
+
+    @property
+    def boundary(self) -> int:
+        if self.arity == 1:
+            return self.int_a
+        elif self.arity == 2:
+            return max(self.int_a, self.int_b)
+        raise ValueError("Unsupported number of operands!")
+
+    @property
+    def limb_boundary(self) -> int:
+        return bound_mpi(self.boundary, self.bits_in_limb)
+
+    @property
+    def limbs(self) -> int:
+        return limbs_mpi(self.boundary, self.bits_in_limb)
+
+    @property
+    def hex_digits(self) -> int:
+        return 2 * (self.limbs * self.bits_in_limb // 8)
+
+    def format_arg(self, val: str) -> str:
+        if self.input_style not in self.input_styles:
+            raise ValueError("Unknown input style!")
+        if self.input_style == "variable":
+            return val
+        else:
+            return val.zfill(self.hex_digits)
+
+    def format_result(self, res: int) -> str:
+        res_str = '{:x}'.format(res)
+        return quote_str(self.format_arg(res_str))
+
+    @property
+    def arg_a(self) -> str:
+        return self.format_arg(self.val_a)
+
+    @property
+    def arg_b(self) -> str:
+        if self.arity == 1:
+            raise AttributeError("Operation is unary and doesn't have arg_b!")
+        return self.format_arg(self.val_b)
 
     def arguments(self) -> List[str]:
-        return [
-            quote_str(self.arg_a), quote_str(self.arg_b)
-        ] + self.result()
+        args = [quote_str(self.arg_a)]
+        if self.arity == 2:
+            args.append(quote_str(self.arg_b))
+        return args + self.result()
+
+    def description(self) -> str:
+        """Generate a description for the test case.
+
+        If not set, case_description uses the form A `symbol` B, where symbol
+        is used to represent the operation. Descriptions of each value are
+        generated to provide some context to the test case.
+        """
+        if not self.case_description:
+            if self.arity == 1:
+                format_string = "{1:x} {0}" if self.suffix else "{0} {1:x}"
+                self.case_description = format_string.format(
+                    self.symbol, self.int_a
+                )
+            elif self.arity == 2:
+                self.case_description = "{:x} {} {:x}".format(
+                    self.int_a, self.symbol, self.int_b
+                )
+        return super().description()
+
+    @property
+    def is_valid(self) -> bool:
+        return True
 
     @abstractmethod
     def result(self) -> List[str]:
@@ -115,15 +207,183 @@
         Combinations are first generated from all input values, and then
         specific cases provided.
         """
-        if cls.unique_combinations_only:
-            yield from combination_pairs(cls.input_values)
+        if cls.arity == 1:
+            yield from ((a, "0") for a in cls.input_values)
+        elif cls.arity == 2:
+            if cls.unique_combinations_only:
+                yield from combination_pairs(cls.input_values)
+            else:
+                yield from (
+                    (a, b)
+                    for a in cls.input_values
+                    for b in cls.input_values
+                )
         else:
-            yield from (
-                (a, b)
-                for a in cls.input_values
-                for b in cls.input_values
-            )
-        yield from cls.input_cases
+            raise ValueError("Unsupported number of operands!")
+
+    @classmethod
+    def generate_function_tests(cls) -> Iterator[test_case.TestCase]:
+        if cls.input_style not in cls.input_styles:
+            raise ValueError("Unknown input style!")
+        if cls.arity not in cls.arities:
+            raise ValueError("Unsupported number of operands!")
+        if cls.input_style == "arch_split":
+            test_objects = (cls(a, b, bits_in_limb=bil)
+                            for a, b in cls.get_value_pairs()
+                            for bil in cls.limb_sizes)
+            special_cases = (cls(*args, bits_in_limb=bil) # type: ignore
+                             for args in cls.input_cases
+                             for bil in cls.limb_sizes)
+        else:
+            test_objects = (cls(a, b)
+                            for a, b in cls.get_value_pairs())
+            special_cases = (cls(*args) for args in cls.input_cases)
+        yield from (valid_test_object.create_test_case()
+                    for valid_test_object in filter(
+                        lambda test_object: test_object.is_valid,
+                        chain(test_objects, special_cases)
+                        )
+                    )
+
+
+class ModulusRepresentation(enum.Enum):
+    """Representation selector of a modulus."""
+    # Numerical values aligned with the type mbedtls_mpi_mod_rep_selector
+    INVALID = 0
+    MONTGOMERY = 2
+    OPT_RED = 3
+
+    def symbol(self) -> str:
+        """The C symbol for this representation selector."""
+        return 'MBEDTLS_MPI_MOD_REP_' + self.name
+
+    @classmethod
+    def supported_representations(cls) -> List['ModulusRepresentation']:
+        """Return all representations that are supported in positive test cases."""
+        return [cls.MONTGOMERY, cls.OPT_RED]
+
+
+class ModOperationCommon(OperationCommon):
+    #pylint: disable=abstract-method
+    """Target for bignum mod_raw test case generation."""
+    moduli = MODULI_DEFAULT # type: List[str]
+    montgomery_form_a = False
+    disallow_zero_a = False
+
+    def __init__(self, val_n: str, val_a: str, val_b: str = "0",
+                 bits_in_limb: int = 64) -> None:
+        super().__init__(val_a=val_a, val_b=val_b, bits_in_limb=bits_in_limb)
+        self.val_n = val_n
+        # Setting the int versions here as opposed to making them @properties
+        # provides earlier/more robust input validation.
+        self.int_n = hex_to_int(val_n)
+
+    def to_montgomery(self, val: int) -> int:
+        return (val * self.r) % self.int_n
+
+    def from_montgomery(self, val: int) -> int:
+        return (val * self.r_inv) % self.int_n
+
+    def convert_from_canonical(self, canonical: int,
+                               rep: ModulusRepresentation) -> int:
+        """Convert values from canonical representation to the given representation."""
+        if rep is ModulusRepresentation.MONTGOMERY:
+            return self.to_montgomery(canonical)
+        elif rep is ModulusRepresentation.OPT_RED:
+            return canonical
+        else:
+            raise ValueError('Modulus representation not supported: {}'
+                             .format(rep.name))
+
+    @property
+    def boundary(self) -> int:
+        return self.int_n
+
+    @property
+    def arg_a(self) -> str:
+        if self.montgomery_form_a:
+            value_a = self.to_montgomery(self.int_a)
+        else:
+            value_a = self.int_a
+        return self.format_arg('{:x}'.format(value_a))
+
+    @property
+    def arg_n(self) -> str:
+        return self.format_arg(self.val_n)
+
+    def format_arg(self, val: str) -> str:
+        return super().format_arg(val).zfill(self.hex_digits)
+
+    def arguments(self) -> List[str]:
+        return [quote_str(self.arg_n)] + super().arguments()
+
+    @property
+    def r(self) -> int: # pylint: disable=invalid-name
+        l = limbs_mpi(self.int_n, self.bits_in_limb)
+        return bound_mpi_limbs(l, self.bits_in_limb)
+
+    @property
+    def r_inv(self) -> int:
+        return invmod(self.r, self.int_n)
+
+    @property
+    def r2(self) -> int: # pylint: disable=invalid-name
+        return pow(self.r, 2)
+
+    @property
+    def is_valid(self) -> bool:
+        if self.int_a >= self.int_n:
+            return False
+        if self.disallow_zero_a and self.int_a == 0:
+            return False
+        if self.arity == 2 and self.int_b >= self.int_n:
+            return False
+        return True
+
+    def description(self) -> str:
+        """Generate a description for the test case.
+
+        It uses the form A `symbol` B mod N, where symbol is used to represent
+        the operation.
+        """
+
+        if not self.case_description:
+            return super().description() + " mod {:x}".format(self.int_n)
+        return super().description()
+
+    @classmethod
+    def input_cases_args(cls) -> Iterator[Tuple[Any, Any, Any]]:
+        if cls.arity == 1:
+            yield from ((n, a, "0") for a, n in cls.input_cases)
+        elif cls.arity == 2:
+            yield from ((n, a, b) for a, b, n in cls.input_cases)
+        else:
+            raise ValueError("Unsupported number of operands!")
+
+    @classmethod
+    def generate_function_tests(cls) -> Iterator[test_case.TestCase]:
+        if cls.input_style not in cls.input_styles:
+            raise ValueError("Unknown input style!")
+        if cls.arity not in cls.arities:
+            raise ValueError("Unsupported number of operands!")
+        if cls.input_style == "arch_split":
+            test_objects = (cls(n, a, b, bits_in_limb=bil)
+                            for n in cls.moduli
+                            for a, b in cls.get_value_pairs()
+                            for bil in cls.limb_sizes)
+            special_cases = (cls(*args, bits_in_limb=bil)
+                             for args in cls.input_cases_args()
+                             for bil in cls.limb_sizes)
+        else:
+            test_objects = (cls(n, a, b)
+                            for n in cls.moduli
+                            for a, b in cls.get_value_pairs())
+            special_cases = (cls(*args) for args in cls.input_cases_args())
+        yield from (valid_test_object.create_test_case()
+                    for valid_test_object in filter(
+                        lambda test_object: test_object.is_valid,
+                        chain(test_objects, special_cases)
+                        ))
 
 # BEGIN MERGE SLOT 1
 
diff --git a/scripts/mbedtls_dev/bignum_core.py b/scripts/mbedtls_dev/bignum_core.py
index 0cc86b8..24d37cb 100644
--- a/scripts/mbedtls_dev/bignum_core.py
+++ b/scripts/mbedtls_dev/bignum_core.py
@@ -16,20 +16,19 @@
 
 import random
 
-from abc import ABCMeta
 from typing import Dict, Iterator, List, Tuple
 
 from . import test_case
 from . import test_data_generation
 from . import bignum_common
 
-class BignumCoreTarget(test_data_generation.BaseTarget, metaclass=ABCMeta):
-    #pylint: disable=abstract-method
+class BignumCoreTarget(test_data_generation.BaseTarget):
+    #pylint: disable=abstract-method, too-few-public-methods
     """Target for bignum core test case generation."""
     target_basename = 'test_suite_bignum_core.generated'
 
 
-class BignumCoreShiftR(BignumCoreTarget, metaclass=ABCMeta):
+class BignumCoreShiftR(BignumCoreTarget, test_data_generation.BaseTest):
     """Test cases for mbedtls_bignum_core_shift_r()."""
     count = 0
     test_function = "mpi_core_shift_r"
@@ -69,7 +68,7 @@
             for count in counts:
                 yield cls(input_hex, descr, count).create_test_case()
 
-class BignumCoreCTLookup(BignumCoreTarget, metaclass=ABCMeta):
+class BignumCoreCTLookup(BignumCoreTarget, test_data_generation.BaseTest):
     """Test cases for mbedtls_mpi_core_ct_uint_table_lookup()."""
     test_function = "mpi_core_ct_uint_table_lookup"
     test_name = "Constant time MPI table lookup"
@@ -107,129 +106,53 @@
                 yield (cls(bitsize, bitsize_description, window_size)
                        .create_test_case())
 
-class BignumCoreOperation(bignum_common.OperationCommon, BignumCoreTarget, metaclass=ABCMeta):
-    #pylint: disable=abstract-method
-    """Common features for bignum core operations."""
-    input_values = [
-        "0", "1", "3", "f", "fe", "ff", "100", "ff00", "fffe", "ffff", "10000",
-        "fffffffe", "ffffffff", "100000000", "1f7f7f7f7f7f7f",
-        "8000000000000000", "fefefefefefefefe", "fffffffffffffffe",
-        "ffffffffffffffff", "10000000000000000", "1234567890abcdef0",
-        "fffffffffffffffffefefefefefefefe", "fffffffffffffffffffffffffffffffe",
-        "ffffffffffffffffffffffffffffffff", "100000000000000000000000000000000",
-        "1234567890abcdef01234567890abcdef0",
-        "fffffffffffffffffffffffffffffffffffffffffffffffffefefefefefefefe",
-        "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
-        "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
-        "10000000000000000000000000000000000000000000000000000000000000000",
-        "1234567890abcdef01234567890abcdef01234567890abcdef01234567890abcdef0",
-        (
-            "4df72d07b4b71c8dacb6cffa954f8d88254b6277099308baf003fab73227f34029"
-            "643b5a263f66e0d3c3fa297ef71755efd53b8fb6cb812c6bbf7bcf179298bd9947"
-            "c4c8b14324140a2c0f5fad7958a69050a987a6096e9f055fb38edf0c5889eca4a0"
-            "cfa99b45fbdeee4c696b328ddceae4723945901ec025076b12b"
-        )
-    ]
 
-    def description(self) -> str:
-        """Generate a description for the test case.
-
-        If not set, case_description uses the form A `symbol` B, where symbol
-        is used to represent the operation. Descriptions of each value are
-        generated to provide some context to the test case.
-        """
-        if not self.case_description:
-            self.case_description = "{:x} {} {:x}".format(
-                self.int_a, self.symbol, self.int_b
-            )
-        return super().description()
-
-    @classmethod
-    def generate_function_tests(cls) -> Iterator[test_case.TestCase]:
-        for a_value, b_value in cls.get_value_pairs():
-            yield cls(a_value, b_value).create_test_case()
-
-
-class BignumCoreOperationArchSplit(BignumCoreOperation):
-    #pylint: disable=abstract-method
-    """Common features for bignum core operations where the result depends on
-    the limb size."""
-
-    def __init__(self, val_a: str, val_b: str, bits_in_limb: int) -> None:
-        super().__init__(val_a, val_b)
-        bound_val = max(self.int_a, self.int_b)
-        self.bits_in_limb = bits_in_limb
-        self.bound = bignum_common.bound_mpi(bound_val, self.bits_in_limb)
-        limbs = bignum_common.limbs_mpi(bound_val, self.bits_in_limb)
-        byte_len = limbs * self.bits_in_limb // 8
-        self.hex_digits = 2 * byte_len
-        if self.bits_in_limb == 32:
-            self.dependencies = ["MBEDTLS_HAVE_INT32"]
-        elif self.bits_in_limb == 64:
-            self.dependencies = ["MBEDTLS_HAVE_INT64"]
-        else:
-            raise ValueError("Invalid number of bits in limb!")
-        self.arg_a = self.arg_a.zfill(self.hex_digits)
-        self.arg_b = self.arg_b.zfill(self.hex_digits)
-
-    def pad_to_limbs(self, val) -> str:
-        return "{:x}".format(val).zfill(self.hex_digits)
-
-    @classmethod
-    def generate_function_tests(cls) -> Iterator[test_case.TestCase]:
-        for a_value, b_value in cls.get_value_pairs():
-            yield cls(a_value, b_value, 32).create_test_case()
-            yield cls(a_value, b_value, 64).create_test_case()
-
-class BignumCoreAddAndAddIf(BignumCoreOperationArchSplit):
+class BignumCoreAddAndAddIf(BignumCoreTarget, bignum_common.OperationCommon):
     """Test cases for bignum core add and add-if."""
     count = 0
     symbol = "+"
     test_function = "mpi_core_add_and_add_if"
     test_name = "mpi_core_add_and_add_if"
+    input_style = "arch_split"
+    unique_combinations_only = True
 
     def result(self) -> List[str]:
         result = self.int_a + self.int_b
 
-        carry, result = divmod(result, self.bound)
+        carry, result = divmod(result, self.limb_boundary)
 
         return [
-            bignum_common.quote_str(self.pad_to_limbs(result)),
+            self.format_result(result),
             str(carry)
         ]
 
-class BignumCoreSub(BignumCoreOperation):
+
+class BignumCoreSub(BignumCoreTarget, bignum_common.OperationCommon):
     """Test cases for bignum core sub."""
     count = 0
+    input_style = "arch_split"
     symbol = "-"
     test_function = "mpi_core_sub"
     test_name = "mbedtls_mpi_core_sub"
-    unique_combinations_only = False
 
     def result(self) -> List[str]:
         if self.int_a >= self.int_b:
-            result_4 = result_8 = self.int_a - self.int_b
+            result = self.int_a - self.int_b
             carry = 0
         else:
-            bound_val = max(self.int_a, self.int_b)
-            bound_4 = bignum_common.bound_mpi(bound_val, 32)
-            result_4 = bound_4 + self.int_a - self.int_b
-            bound_8 = bignum_common.bound_mpi(bound_val, 64)
-            result_8 = bound_8 + self.int_a - self.int_b
+            result = self.limb_boundary + self.int_a - self.int_b
             carry = 1
         return [
-            "\"{:x}\"".format(result_4),
-            "\"{:x}\"".format(result_8),
+            self.format_result(result),
             str(carry)
         ]
 
 
-class BignumCoreMLA(BignumCoreOperation):
+class BignumCoreMLA(BignumCoreTarget, bignum_common.OperationCommon):
     """Test cases for fixed-size multiply accumulate."""
     count = 0
     test_function = "mpi_core_mla"
     test_name = "mbedtls_mpi_core_mla"
-    unique_combinations_only = False
 
     input_values = [
         "0", "1", "fffe", "ffffffff", "100000000", "20000000000000",
@@ -289,6 +212,16 @@
         ]
 
     @classmethod
+    def get_value_pairs(cls) -> Iterator[Tuple[str, str]]:
+        """Generator to yield pairs of inputs.
+
+        Combinations are first generated from all input values, and then
+        specific cases provided.
+        """
+        yield from super().get_value_pairs()
+        yield from cls.input_cases
+
+    @classmethod
     def generate_function_tests(cls) -> Iterator[test_case.TestCase]:
         """Override for additional scalar input."""
         for a_value, b_value in cls.get_value_pairs():
@@ -297,7 +230,7 @@
                 yield cur_op.create_test_case()
 
 
-class BignumCoreMontmul(BignumCoreTarget):
+class BignumCoreMontmul(BignumCoreTarget, test_data_generation.BaseTest):
     """Test cases for Montgomery multiplication."""
     count = 0
     test_function = "mpi_core_montmul"
@@ -818,6 +751,26 @@
 
 # BEGIN MERGE SLOT 1
 
+class BignumCoreExpMod(BignumCoreTarget, bignum_common.ModOperationCommon):
+    """Test cases for bignum core exponentiation."""
+    symbol = "^"
+    test_function = "mpi_core_exp_mod"
+    test_name = "Core modular exponentiation (Mongtomery form only)"
+    input_style = "fixed"
+    montgomery_form_a = True
+
+    def result(self) -> List[str]:
+        # Result has to be given in Montgomery form too
+        result = pow(self.int_a, self.int_b, self.int_n)
+        mont_result = self.to_montgomery(result)
+        return [self.format_result(mont_result)]
+
+    @property
+    def is_valid(self) -> bool:
+        # The base needs to be canonical, but the exponent can be larger than
+        # the modulus (see for example exponent blinding)
+        return bool(self.int_a < self.int_n)
+
 # END MERGE SLOT 1
 
 # BEGIN MERGE SLOT 2
@@ -826,6 +779,51 @@
 
 # BEGIN MERGE SLOT 3
 
+class BignumCoreSubInt(BignumCoreTarget, bignum_common.OperationCommon):
+    """Test cases for bignum core sub int."""
+    count = 0
+    symbol = "-"
+    test_function = "mpi_core_sub_int"
+    test_name = "mpi_core_sub_int"
+    input_style = "arch_split"
+
+    @property
+    def is_valid(self) -> bool:
+        # This is "sub int", so b is only one limb
+        if bignum_common.limbs_mpi(self.int_b, self.bits_in_limb) > 1:
+            return False
+        return True
+
+    # Overriding because we don't want leading zeros on b
+    @property
+    def arg_b(self) -> str:
+        return self.val_b
+
+    def result(self) -> List[str]:
+        result = self.int_a - self.int_b
+
+        borrow, result = divmod(result, self.limb_boundary)
+
+        # Borrow will be -1 if non-zero, but we want it to be 1 in the test data
+        return [
+            self.format_result(result),
+            str(-borrow)
+        ]
+
+class BignumCoreZeroCheckCT(BignumCoreTarget, bignum_common.OperationCommon):
+    """Test cases for bignum core zero check (constant flow)."""
+    count = 0
+    symbol = "== 0"
+    test_function = "mpi_core_check_zero_ct"
+    test_name = "mpi_core_check_zero_ct"
+    input_style = "variable"
+    arity = 1
+    suffix = True
+
+    def result(self) -> List[str]:
+        result = 1 if self.int_a == 0 else 0
+        return [str(result)]
+
 # END MERGE SLOT 3
 
 # BEGIN MERGE SLOT 4
diff --git a/scripts/mbedtls_dev/bignum_data.py b/scripts/mbedtls_dev/bignum_data.py
new file mode 100644
index 0000000..0a48e53
--- /dev/null
+++ b/scripts/mbedtls_dev/bignum_data.py
@@ -0,0 +1,147 @@
+"""Base values and datasets for bignum generated tests and helper functions that
+produced them."""
+# 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 random
+
+# Functions calling these were used to produce test data and are here only for
+# reproducibility, they are not used by the test generation framework/classes
+try:
+    from Cryptodome.Util.number import isPrime, getPrime #type: ignore #pylint: disable=import-error
+except ImportError:
+    pass
+
+# Generated by bignum_common.gen_safe_prime(192,1)
+SAFE_PRIME_192_BIT_SEED_1 = "d1c127a667786703830500038ebaef20e5a3e2dc378fb75b"
+
+# First number generated by random.getrandbits(192) - seed(2,2), not a prime
+RANDOM_192_BIT_SEED_2_NO1 = "177219d30e7a269fd95bafc8f2a4d27bdcf4bb99f4bea973"
+
+# Second number generated by random.getrandbits(192) - seed(2,2), not a prime
+RANDOM_192_BIT_SEED_2_NO2 = "cf1822ffbc6887782b491044d5e341245c6e433715ba2bdd"
+
+# Third number generated by random.getrandbits(192) - seed(2,2), not a prime
+RANDOM_192_BIT_SEED_2_NO3 = "3653f8dd9b1f282e4067c3584ee207f8da94e3e8ab73738f"
+
+# Fourth number generated by random.getrandbits(192) - seed(2,2), not a prime
+RANDOM_192_BIT_SEED_2_NO4 = "ffed9235288bc781ae66267594c9c9500925e4749b575bd1"
+
+# Ninth number generated by random.getrandbits(192) - seed(2,2), not a prime
+RANDOM_192_BIT_SEED_2_NO9 = "2a1be9cd8697bbd0e2520e33e44c50556c71c4a66148a86f"
+
+# Generated by bignum_common.gen_safe_prime(1024,3)
+SAFE_PRIME_1024_BIT_SEED_3 = ("c93ba7ec74d96f411ba008bdb78e63ff11bb5df46a51e16b"
+                              "2c9d156f8e4e18abf5e052cb01f47d0d1925a77f60991577"
+                              "e128fb6f52f34a27950a594baadd3d8057abeb222cf3cca9"
+                              "62db16abf79f2ada5bd29ab2f51244bf295eff9f6aaba130"
+                              "2efc449b128be75eeaca04bc3c1a155d11d14e8be32a2c82"
+                              "87b3996cf6ad5223")
+
+# First number generated by random.getrandbits(1024) - seed(4,2), not a prime
+RANDOM_1024_BIT_SEED_4_NO1 = ("6905269ed6f0b09f165c8ce36e2f24b43000de01b2ed40ed"
+                              "3addccb2c33be0ac79d679346d4ac7a5c3902b38963dc6e8"
+                              "534f45738d048ec0f1099c6c3e1b258fd724452ccea71ff4"
+                              "a14876aeaff1a098ca5996666ceab360512bd13110722311"
+                              "710cf5327ac435a7a97c643656412a9b8a1abcd1a6916c74"
+                              "da4f9fc3c6da5d7")
+
+# Second number generated by random.getrandbits(1024) - seed(4,2), not a prime
+RANDOM_1024_BIT_SEED_4_NO2 = ("f1cfd99216df648647adec26793d0e453f5082492d83a823"
+                              "3fb62d2c81862fc9634f806fabf4a07c566002249b191bf4"
+                              "d8441b5616332aca5f552773e14b0190d93936e1daca3c06"
+                              "f5ff0c03bb5d7385de08caa1a08179104a25e4664f5253a0"
+                              "2a3187853184ff27459142deccea264542a00403ce80c4b0"
+                              "a4042bb3d4341aad")
+
+# Third number generated by random.getrandbits(1024) - seed(4,2), not a prime
+RANDOM_1024_BIT_SEED_4_NO3 = ("14c15c910b11ad28cc21ce88d0060cc54278c2614e1bcb38"
+                              "3bb4a570294c4ea3738d243a6e58d5ca49c7b59b995253fd"
+                              "6c79a3de69f85e3131f3b9238224b122c3e4a892d9196ada"
+                              "4fcfa583e1df8af9b474c7e89286a1754abcb06ae8abb93f"
+                              "01d89a024cdce7a6d7288ff68c320f89f1347e0cdd905ecf"
+                              "d160c5d0ef412ed6")
+
+# Fourth number generated by random.getrandbits(1024) - seed(4,2), not a prime
+RANDOM_1024_BIT_SEED_4_NO4 = ("32decd6b8efbc170a26a25c852175b7a96b98b5fbf37a2be"
+                              "6f98bca35b17b9662f0733c846bbe9e870ef55b1a1f65507"
+                              "a2909cb633e238b4e9dd38b869ace91311021c9e32111ac1"
+                              "ac7cc4a4ff4dab102522d53857c49391b36cc9aa78a330a1"
+                              "a5e333cb88dcf94384d4cd1f47ca7883ff5a52f1a05885ac"
+                              "7671863c0bdbc23a")
+
+# Fifth number generated by random.getrandbits(1024) - seed(4,2), not a prime
+RANDOM_1024_BIT_SEED_4_NO5 = ("53be4721f5b9e1f5acdac615bc20f6264922b9ccf469aef8"
+                              "f6e7d078e55b85dd1525f363b281b8885b69dc230af5ac87"
+                              "0692b534758240df4a7a03052d733dcdef40af2e54c0ce68"
+                              "1f44ebd13cc75f3edcb285f89d8cf4d4950b16ffc3e1ac3b"
+                              "4708d9893a973000b54a23020fc5b043d6e4a51519d9c9cc"
+                              "52d32377e78131c1")
+
+# Adding 192 bit and 1024 bit numbers because these are the shortest required
+# for ECC and RSA respectively.
+INPUTS_DEFAULT = [
+        "0", "1", # corner cases
+        "2", "3", # small primes
+        "4",      # non-prime even
+        "38",     # small random
+        SAFE_PRIME_192_BIT_SEED_1,  # prime
+        RANDOM_192_BIT_SEED_2_NO1,  # not a prime
+        RANDOM_192_BIT_SEED_2_NO2,  # not a prime
+        SAFE_PRIME_1024_BIT_SEED_3, # prime
+        RANDOM_1024_BIT_SEED_4_NO1, # not a prime
+        RANDOM_1024_BIT_SEED_4_NO3, # not a prime
+        RANDOM_1024_BIT_SEED_4_NO2, # largest (not a prime)
+        ]
+
+# Only odd moduli are present as in the new bignum code only odd moduli are
+# supported for now.
+MODULI_DEFAULT = [
+        "53", # safe prime
+        "45", # non-prime
+        SAFE_PRIME_192_BIT_SEED_1,  # safe prime
+        RANDOM_192_BIT_SEED_2_NO4,  # not a prime
+        SAFE_PRIME_1024_BIT_SEED_3, # safe prime
+        RANDOM_1024_BIT_SEED_4_NO5, # not a prime
+        ]
+
+# Some functions, e.g. mbedtls_mpi_mod_raw_inv_prime(), only support prime moduli.
+ONLY_PRIME_MODULI = [
+        "53", # safe prime
+        "8ac72304057392b5",     # 9999999997777777333 (longer, not safe, prime)
+        # The next prime has a different R in Montgomery form depending on
+        # whether 32- or 64-bit MPIs are used.
+        "152d02c7e14af67fe0bf", # 99999999999999999991999
+        SAFE_PRIME_192_BIT_SEED_1,  # safe prime
+        SAFE_PRIME_1024_BIT_SEED_3, # safe prime
+        ]
+
+def __gen_safe_prime(bits, seed):
+    '''
+    Generate a safe prime.
+
+    This function is intended for generating constants offline and shouldn't be
+    used in test generation classes.
+
+    Requires pycryptodomex for getPrime and isPrime and python 3.9 or later for
+    randbytes.
+    '''
+    rng = random.Random()
+    # We want reproducibility across python versions
+    rng.seed(seed, version=2)
+    while True:
+        prime = 2*getPrime(bits-1, rng.randbytes)+1 #pylint: disable=no-member
+        if isPrime(prime, 1e-30):
+            return prime
diff --git a/scripts/mbedtls_dev/bignum_mod.py b/scripts/mbedtls_dev/bignum_mod.py
index 2bd7fbb..a83e136 100644
--- a/scripts/mbedtls_dev/bignum_mod.py
+++ b/scripts/mbedtls_dev/bignum_mod.py
@@ -14,12 +14,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from abc import ABCMeta
+from typing import Dict, List
 
 from . import test_data_generation
+from . import bignum_common
+from .bignum_data import ONLY_PRIME_MODULI
 
-class BignumModTarget(test_data_generation.BaseTarget, metaclass=ABCMeta):
-    #pylint: disable=abstract-method
+class BignumModTarget(test_data_generation.BaseTarget):
+    #pylint: disable=abstract-method, too-few-public-methods
     """Target for bignum mod test case generation."""
     target_basename = 'test_suite_bignum_mod.generated'
 
@@ -29,10 +31,80 @@
 
 # BEGIN MERGE SLOT 2
 
+class BignumModMul(bignum_common.ModOperationCommon,
+                   BignumModTarget):
+    # pylint:disable=duplicate-code
+    """Test cases for bignum mpi_mod_mul()."""
+    symbol = "*"
+    test_function = "mpi_mod_mul"
+    test_name = "mbedtls_mpi_mod_mul"
+    input_style = "arch_split"
+    arity = 2
+
+    def arguments(self) -> List[str]:
+        return [self.format_result(self.to_montgomery(self.int_a)),
+                self.format_result(self.to_montgomery(self.int_b)),
+                bignum_common.quote_str(self.arg_n)
+               ] + self.result()
+
+    def result(self) -> List[str]:
+        result = (self.int_a * self.int_b) % self.int_n
+        return [self.format_result(self.to_montgomery(result))]
+
 # END MERGE SLOT 2
 
 # BEGIN MERGE SLOT 3
 
+class BignumModSub(bignum_common.ModOperationCommon, BignumModTarget):
+    """Test cases for bignum mpi_mod_sub()."""
+    symbol = "-"
+    test_function = "mpi_mod_sub"
+    test_name = "mbedtls_mpi_mod_sub"
+    input_style = "fixed"
+    arity = 2
+
+    def result(self) -> List[str]:
+        result = (self.int_a - self.int_b) % self.int_n
+        # To make negative tests easier, append 0 for success to the
+        # generated cases
+        return [self.format_result(result), "0"]
+
+class BignumModInvNonMont(bignum_common.ModOperationCommon, BignumModTarget):
+    """Test cases for bignum mpi_mod_inv() - not in Montgomery form."""
+    moduli = ONLY_PRIME_MODULI  # for now only prime moduli supported
+    symbol = "^ -1"
+    test_function = "mpi_mod_inv_non_mont"
+    test_name = "mbedtls_mpi_mod_inv non-Mont. form"
+    input_style = "fixed"
+    arity = 1
+    suffix = True
+    disallow_zero_a = True
+
+    def result(self) -> List[str]:
+        result = bignum_common.invmod_positive(self.int_a, self.int_n)
+        # To make negative tests easier, append 0 for success to the
+        # generated cases
+        return [self.format_result(result), "0"]
+
+class BignumModInvMont(bignum_common.ModOperationCommon, BignumModTarget):
+    """Test cases for bignum mpi_mod_inv() - Montgomery form."""
+    moduli = ONLY_PRIME_MODULI  # for now only prime moduli supported
+    symbol = "^ -1"
+    test_function = "mpi_mod_inv_mont"
+    test_name = "mbedtls_mpi_mod_inv Mont. form"
+    input_style = "arch_split"  # Mont. form requires arch_split
+    arity = 1
+    suffix = True
+    disallow_zero_a = True
+    montgomery_form_a = True
+
+    def result(self) -> List[str]:
+        result = bignum_common.invmod_positive(self.int_a, self.int_n)
+        mont_result = self.to_montgomery(result)
+        # To make negative tests easier, append 0 for success to the
+        # generated cases
+        return [self.format_result(mont_result), "0"]
+
 # END MERGE SLOT 3
 
 # BEGIN MERGE SLOT 4
@@ -40,6 +112,20 @@
 # END MERGE SLOT 4
 
 # BEGIN MERGE SLOT 5
+class BignumModAdd(bignum_common.ModOperationCommon, BignumModTarget):
+    """Test cases for bignum mpi_mod_add()."""
+    count = 0
+    symbol = "+"
+    test_function = "mpi_mod_add"
+    test_name = "mbedtls_mpi_mod_add"
+    input_style = "fixed"
+
+    def result(self) -> List[str]:
+        result = (self.int_a + self.int_b) % self.int_n
+        # To make negative tests easier, append "0" for success to the
+        # generated cases
+        return [self.format_result(result), "0"]
+
 
 # END MERGE SLOT 5
 
diff --git a/scripts/mbedtls_dev/bignum_mod_raw.py b/scripts/mbedtls_dev/bignum_mod_raw.py
index 1465e3e..f9d9899 100644
--- a/scripts/mbedtls_dev/bignum_mod_raw.py
+++ b/scripts/mbedtls_dev/bignum_mod_raw.py
@@ -14,99 +14,84 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from abc import ABCMeta
-from typing import Dict, Iterator, List
+from typing import Iterator, List
 
 from . import test_case
 from . import test_data_generation
 from . import bignum_common
+from .bignum_data import ONLY_PRIME_MODULI
 
-class BignumModRawTarget(test_data_generation.BaseTarget, metaclass=ABCMeta):
-    #pylint: disable=abstract-method
+class BignumModRawTarget(test_data_generation.BaseTarget):
+    #pylint: disable=abstract-method, too-few-public-methods
     """Target for bignum mod_raw test case generation."""
     target_basename = 'test_suite_bignum_mod_raw.generated'
 
-class BignumModRawOperation(bignum_common.OperationCommon, BignumModRawTarget, metaclass=ABCMeta):
-    #pylint: disable=abstract-method
-    """Target for bignum mod_raw test case generation."""
-
-    def __init__(self, val_n: str, val_a: str, val_b: str = "0", bits_in_limb: int = 64) -> None:
-        super().__init__(val_a=val_a, val_b=val_b)
-        self.val_n = val_n
-        self.bits_in_limb = bits_in_limb
-
-    @property
-    def int_n(self) -> int:
-        return bignum_common.hex_to_int(self.val_n)
-
-    @property
-    def boundary(self) -> int:
-        data_in = [self.int_a, self.int_b, self.int_n]
-        return max([n for n in data_in if n is not None])
-
-    @property
-    def limbs(self) -> int:
-        return bignum_common.limbs_mpi(self.boundary, self.bits_in_limb)
-
-    @property
-    def hex_digits(self) -> int:
-        return 2 * (self.limbs * self.bits_in_limb // 8)
-
-    @property
-    def hex_n(self) -> str:
-        return "{:x}".format(self.int_n).zfill(self.hex_digits)
-
-    @property
-    def hex_a(self) -> str:
-        return "{:x}".format(self.int_a).zfill(self.hex_digits)
-
-    @property
-    def hex_b(self) -> str:
-        return "{:x}".format(self.int_b).zfill(self.hex_digits)
-
-    @property
-    def r(self) -> int: # pylint: disable=invalid-name
-        l = bignum_common.limbs_mpi(self.int_n, self.bits_in_limb)
-        return bignum_common.bound_mpi_limbs(l, self.bits_in_limb)
-
-    @property
-    def r_inv(self) -> int:
-        return bignum_common.invmod(self.r, self.int_n)
-
-    @property
-    def r2(self) -> int: # pylint: disable=invalid-name
-        return pow(self.r, 2)
-
-class BignumModRawOperationArchSplit(BignumModRawOperation):
-    #pylint: disable=abstract-method
-    """Common features for bignum mod raw operations where the result depends on
-    the limb size."""
-
-    limb_sizes = [32, 64] # type: List[int]
-
-    def __init__(self, val_n: str, val_a: str, val_b: str = "0", bits_in_limb: int = 64) -> None:
-        super().__init__(val_n=val_n, val_a=val_a, val_b=val_b, bits_in_limb=bits_in_limb)
-
-        if bits_in_limb not in self.limb_sizes:
-            raise ValueError("Invalid number of bits in limb!")
-
-        self.dependencies = ["MBEDTLS_HAVE_INT{:d}".format(bits_in_limb)]
-
-    @classmethod
-    def generate_function_tests(cls) -> Iterator[test_case.TestCase]:
-        for a_value, b_value in cls.get_value_pairs():
-            for bil in cls.limb_sizes:
-                yield cls(a_value, b_value, bits_in_limb=bil).create_test_case()
 # BEGIN MERGE SLOT 1
 
 # END MERGE SLOT 1
 
 # BEGIN MERGE SLOT 2
 
+class BignumModRawSub(bignum_common.ModOperationCommon,
+                      BignumModRawTarget):
+    """Test cases for bignum mpi_mod_raw_sub()."""
+    symbol = "-"
+    test_function = "mpi_mod_raw_sub"
+    test_name = "mbedtls_mpi_mod_raw_sub"
+    input_style = "fixed"
+    arity = 2
+
+    def arguments(self) -> List[str]:
+        return [bignum_common.quote_str(n) for n in [self.arg_a,
+                                                     self.arg_b,
+                                                     self.arg_n]
+               ] + self.result()
+
+    def result(self) -> List[str]:
+        result = (self.int_a - self.int_b) % self.int_n
+        return [self.format_result(result)]
+
+class BignumModRawMul(bignum_common.ModOperationCommon,
+                      BignumModRawTarget):
+    """Test cases for bignum mpi_mod_raw_mul()."""
+    symbol = "*"
+    test_function = "mpi_mod_raw_mul"
+    test_name = "mbedtls_mpi_mod_raw_mul"
+    input_style = "arch_split"
+    arity = 2
+
+    def arguments(self) -> List[str]:
+        return [self.format_result(self.to_montgomery(self.int_a)),
+                self.format_result(self.to_montgomery(self.int_b)),
+                bignum_common.quote_str(self.arg_n)
+               ] + self.result()
+
+    def result(self) -> List[str]:
+        result = (self.int_a * self.int_b) % self.int_n
+        return [self.format_result(self.to_montgomery(result))]
+
 # END MERGE SLOT 2
 
 # BEGIN MERGE SLOT 3
 
+class BignumModRawInvPrime(bignum_common.ModOperationCommon,
+                           BignumModRawTarget):
+    """Test cases for bignum mpi_mod_raw_inv_prime()."""
+    moduli = ONLY_PRIME_MODULI
+    symbol = "^ -1"
+    test_function = "mpi_mod_raw_inv_prime"
+    test_name = "mbedtls_mpi_mod_raw_inv_prime (Montgomery form only)"
+    input_style = "arch_split"
+    arity = 1
+    suffix = True
+    montgomery_form_a = True
+    disallow_zero_a = True
+
+    def result(self) -> List[str]:
+        result = bignum_common.invmod_positive(self.int_a, self.int_n)
+        mont_result = self.to_montgomery(result)
+        return [self.format_result(mont_result)]
+
 # END MERGE SLOT 3
 
 # BEGIN MERGE SLOT 4
@@ -115,14 +100,147 @@
 
 # BEGIN MERGE SLOT 5
 
+class BignumModRawAdd(bignum_common.ModOperationCommon,
+                      BignumModRawTarget):
+    """Test cases for bignum mpi_mod_raw_add()."""
+    symbol = "+"
+    test_function = "mpi_mod_raw_add"
+    test_name = "mbedtls_mpi_mod_raw_add"
+    input_style = "fixed"
+    arity = 2
+
+    def result(self) -> List[str]:
+        result = (self.int_a + self.int_b) % self.int_n
+        return [self.format_result(result)]
+
 # END MERGE SLOT 5
 
 # BEGIN MERGE SLOT 6
 
+class BignumModRawConvertRep(bignum_common.ModOperationCommon,
+                             BignumModRawTarget):
+    # This is an abstract class, it's ok to have unimplemented methods.
+    #pylint: disable=abstract-method
+    """Test cases for representation conversion."""
+    symbol = ""
+    input_style = "arch_split"
+    arity = 1
+    rep = bignum_common.ModulusRepresentation.INVALID
+
+    def set_representation(self, r: bignum_common.ModulusRepresentation) -> None:
+        self.rep = r
+
+    def arguments(self) -> List[str]:
+        return ([bignum_common.quote_str(self.arg_n), self.rep.symbol(),
+                 bignum_common.quote_str(self.arg_a)] +
+                self.result())
+
+    def description(self) -> str:
+        base = super().description()
+        mod_with_rep = 'mod({})'.format(self.rep.name)
+        return base.replace('mod', mod_with_rep, 1)
+
+    @classmethod
+    def test_cases_for_values(cls, rep: bignum_common.ModulusRepresentation,
+                              n: str, a: str) -> Iterator[test_case.TestCase]:
+        """Emit test cases for the given values (if any).
+
+        This may emit no test cases if a isn't valid for the modulus n,
+        or multiple test cases if rep requires different data depending
+        on the limb size.
+        """
+        for bil in cls.limb_sizes:
+            test_object = cls(n, a, bits_in_limb=bil)
+            test_object.set_representation(rep)
+            # The class is set to having separate test cases for each limb
+            # size, because the Montgomery representation requires it.
+            # But other representations don't require it. So for other
+            # representations, emit a single test case with no dependency
+            # on the limb size.
+            if rep is not bignum_common.ModulusRepresentation.MONTGOMERY:
+                test_object.dependencies = \
+                    [dep for dep in test_object.dependencies
+                     if not dep.startswith('MBEDTLS_HAVE_INT')]
+            if test_object.is_valid:
+                yield test_object.create_test_case()
+            if rep is not bignum_common.ModulusRepresentation.MONTGOMERY:
+                # A single test case (emitted, or skipped due to invalidity)
+                # is enough, since this test case doesn't depend on the
+                # limb size.
+                break
+
+    # The parent class doesn't support non-bignum parameters. So we override
+    # test generation, in order to have the representation as a parameter.
+    @classmethod
+    def generate_function_tests(cls) -> Iterator[test_case.TestCase]:
+
+        for rep in bignum_common.ModulusRepresentation.supported_representations():
+            for n in cls.moduli:
+                for a in cls.input_values:
+                    yield from cls.test_cases_for_values(rep, n, a)
+
+class BignumModRawCanonicalToModulusRep(BignumModRawConvertRep):
+    """Test cases for mpi_mod_raw_canonical_to_modulus_rep."""
+    test_function = "mpi_mod_raw_canonical_to_modulus_rep"
+    test_name = "Rep canon->mod"
+
+    def result(self) -> List[str]:
+        return [self.format_result(self.convert_from_canonical(self.int_a, self.rep))]
+
+class BignumModRawModulusToCanonicalRep(BignumModRawConvertRep):
+    """Test cases for mpi_mod_raw_modulus_to_canonical_rep."""
+    test_function = "mpi_mod_raw_modulus_to_canonical_rep"
+    test_name = "Rep mod->canon"
+
+    @property
+    def arg_a(self) -> str:
+        return self.format_arg("{:x}".format(self.convert_from_canonical(self.int_a, self.rep)))
+
+    def result(self) -> List[str]:
+        return [self.format_result(self.int_a)]
+
 # END MERGE SLOT 6
 
 # BEGIN MERGE SLOT 7
 
+class BignumModRawConvertToMont(bignum_common.ModOperationCommon,
+                                BignumModRawTarget):
+    """ Test cases for mpi_mod_raw_to_mont_rep(). """
+    test_function = "mpi_mod_raw_to_mont_rep"
+    test_name = "Convert into Mont: "
+    symbol = "R *"
+    input_style = "arch_split"
+    arity = 1
+
+    def result(self) -> List[str]:
+        result = self.to_montgomery(self.int_a)
+        return [self.format_result(result)]
+
+class BignumModRawConvertFromMont(bignum_common.ModOperationCommon,
+                                  BignumModRawTarget):
+    """ Test cases for mpi_mod_raw_from_mont_rep(). """
+    test_function = "mpi_mod_raw_from_mont_rep"
+    test_name = "Convert from Mont: "
+    symbol = "1/R *"
+    input_style = "arch_split"
+    arity = 1
+
+    def result(self) -> List[str]:
+        result = self.from_montgomery(self.int_a)
+        return [self.format_result(result)]
+
+class BignumModRawModNegate(bignum_common.ModOperationCommon,
+                            BignumModRawTarget):
+    """ Test cases for mpi_mod_raw_neg(). """
+    test_function = "mpi_mod_raw_neg"
+    test_name = "Modular negation: "
+    symbol = "-"
+    input_style = "arch_split"
+    arity = 1
+
+    def result(self) -> List[str]:
+        result = (self.int_n - self.int_a) % self.int_n
+        return [self.format_result(result)]
 # END MERGE SLOT 7
 
 # BEGIN MERGE SLOT 8
diff --git a/scripts/mbedtls_dev/test_data_generation.py b/scripts/mbedtls_dev/test_data_generation.py
index eec0f9d..02aa510 100644
--- a/scripts/mbedtls_dev/test_data_generation.py
+++ b/scripts/mbedtls_dev/test_data_generation.py
@@ -25,6 +25,7 @@
 import os
 import posixpath
 import re
+import inspect
 
 from abc import ABCMeta, abstractmethod
 from typing import Callable, Dict, Iterable, Iterator, List, Type, TypeVar
@@ -35,12 +36,8 @@
 T = TypeVar('T') #pylint: disable=invalid-name
 
 
-class BaseTarget(metaclass=ABCMeta):
-    """Base target for test case generation.
-
-    Child classes of this class represent an output file, and can be referred
-    to as file targets. These indicate where test cases will be written to for
-    all subclasses of the file target, which is set by `target_basename`.
+class BaseTest(metaclass=ABCMeta):
+    """Base class for test case generation.
 
     Attributes:
         count: Counter for test cases from this class.
@@ -48,8 +45,6 @@
             automatically generated using the class, or manually set.
         dependencies: A list of dependencies required for the test case.
         show_test_count: Toggle for inclusion of `count` in the test description.
-        target_basename: Basename of file to write generated tests to. This
-            should be specified in a child class of BaseTarget.
         test_function: Test function which the class generates cases for.
         test_name: A common name or description of the test function. This can
             be `test_function`, a clearer equivalent, or a short summary of the
@@ -59,7 +54,6 @@
     case_description = ""
     dependencies = [] # type: List[str]
     show_test_count = True
-    target_basename = ""
     test_function = ""
     test_name = ""
 
@@ -121,6 +115,21 @@
         """
         raise NotImplementedError
 
+
+class BaseTarget:
+    #pylint: disable=too-few-public-methods
+    """Base target for test case generation.
+
+    Child classes of this class represent an output file, and can be referred
+    to as file targets. These indicate where test cases will be written to for
+    all subclasses of the file target, which is set by `target_basename`.
+
+    Attributes:
+        target_basename: Basename of file to write generated tests to. This
+            should be specified in a child class of BaseTarget.
+    """
+    target_basename = ""
+
     @classmethod
     def generate_tests(cls) -> Iterator[test_case.TestCase]:
         """Generate test cases for the class and its subclasses.
@@ -132,7 +141,8 @@
         yield from `generate_tests()` in each. Calling this method on a class X
         will yield test cases from all classes derived from X.
         """
-        if cls.test_function:
+        if issubclass(cls, BaseTest) and not inspect.isabstract(cls):
+            #pylint: disable=no-member
             yield from cls.generate_function_tests()
         for subclass in sorted(cls.__subclasses__(), key=lambda c: c.__name__):
             yield from subclass.generate_tests()
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index c23cb6b..4a7de82 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -70,6 +70,8 @@
             ${CMAKE_CURRENT_SOURCE_DIR}/../tests/scripts/generate_bignum_tests.py
             ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/bignum_common.py
             ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/bignum_core.py
+            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/bignum_mod_raw.py
+            ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/bignum_mod.py
             ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/test_case.py
             ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/test_data_generation.py
     )
@@ -106,6 +108,10 @@
 # the risk of a race.
 add_custom_target(test_suite_bignum_generated_data DEPENDS ${bignum_generated_data_files})
 add_custom_target(test_suite_psa_generated_data DEPENDS ${psa_generated_data_files})
+# If SKIP_TEST_SUITES is not defined with -D, get it from the environment.
+if((NOT DEFINED SKIP_TEST_SUITES) AND (DEFINED ENV{SKIP_TEST_SUITES}))
+    set(SKIP_TEST_SUITES $ENV{SKIP_TEST_SUITES})
+endif()
 # Test suites caught by SKIP_TEST_SUITES are built but not executed.
 # "foo" as a skip pattern skips "test_suite_foo" and "test_suite_foo.bar"
 # but not "test_suite_foobar".
@@ -237,6 +243,7 @@
     if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/seedfile")
         link_to_source(seedfile)
     endif()
+    link_to_source(Descriptions.txt)
     link_to_source(compat.sh)
     link_to_source(context-info.sh)
     link_to_source(data_files)
diff --git a/tests/Makefile b/tests/Makefile
index 7c08f54..f037338 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -94,6 +94,8 @@
 generated_bignum_test_data: scripts/generate_bignum_tests.py
 generated_bignum_test_data: ../scripts/mbedtls_dev/bignum_common.py
 generated_bignum_test_data: ../scripts/mbedtls_dev/bignum_core.py
+generated_bignum_test_data: ../scripts/mbedtls_dev/bignum_mod_raw.py
+generated_bignum_test_data: ../scripts/mbedtls_dev/bignum_mod.py
 generated_bignum_test_data: ../scripts/mbedtls_dev/test_case.py
 generated_bignum_test_data: ../scripts/mbedtls_dev/test_data_generation.py
 generated_bignum_test_data:
@@ -163,6 +165,7 @@
 	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) -o $@ -c $<
 
 C_FILES := $(addsuffix .c,$(APPS))
+c: $(C_FILES)
 
 # Wildcard target for test code generation:
 # A .c file is generated for each .data file in the suites/ directory. Each .c
diff --git a/tests/compat-in-docker.sh b/tests/compat-in-docker.sh
index 3a1cd21..ad73582 100755
--- a/tests/compat-in-docker.sh
+++ b/tests/compat-in-docker.sh
@@ -6,6 +6,10 @@
 # -------
 # This runs compat.sh in a Docker container.
 #
+# WARNING: the Dockerfile used by this script is no longer maintained! See
+# https://github.com/Mbed-TLS/mbedtls-test/blob/master/README.md#quick-start
+# for the set of Docker images we use on the CI.
+#
 # Notes for users
 # ---------------
 # If OPENSSL_CMD, GNUTLS_CLI, or GNUTLS_SERV are specified the path must
diff --git a/tests/compat.sh b/tests/compat.sh
index d681217..529c2c5 100755
--- a/tests/compat.sh
+++ b/tests/compat.sh
@@ -595,6 +595,20 @@
     G_CLIENT_ARGS="-p $PORT --debug 3 $G_MODE"
     G_CLIENT_PRIO="NONE:$G_PRIO_MODE:+COMP-NULL:+CURVE-ALL:+SIGN-ALL"
 
+    # Newer versions of OpenSSL have a syntax to enable all "ciphers", even
+    # low-security ones. This covers not just cipher suites but also protocol
+    # versions. It is necessary, for example, to use (D)TLS 1.0/1.1 on
+    # OpenSSL 1.1.1f from Ubuntu 20.04. The syntax was only introduced in
+    # OpenSSL 1.1.0 (21e0c1d23afff48601eb93135defddae51f7e2e3) and I can't find
+    # a way to discover it from -help, so check the openssl version.
+    case $($OPENSSL_CMD version) in
+        "OpenSSL 0"*|"OpenSSL 1.0"*) :;;
+        *)
+            O_CLIENT_ARGS="$O_CLIENT_ARGS -cipher ALL@SECLEVEL=0"
+            O_SERVER_ARGS="$O_SERVER_ARGS -cipher ALL@SECLEVEL=0"
+            ;;
+    esac
+
     if [ "X$VERIFY" = "XYES" ];
     then
         M_SERVER_ARGS="$M_SERVER_ARGS ca_file=data_files/test-ca_cat12.crt auth_mode=required"
diff --git a/tests/configs/tls13-only.h b/tests/configs/tls13-only.h
index 7483f1c..963086f 100644
--- a/tests/configs/tls13-only.h
+++ b/tests/configs/tls13-only.h
@@ -34,6 +34,8 @@
 #undef MBEDTLS_SSL_DTLS_ANTI_REPLAY
 #undef MBEDTLS_SSL_DTLS_HELLO_VERIFY
 #undef MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE
+#undef MBEDTLS_SSL_DTLS_CONNECTION_ID
+#undef MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT
 
 /* Enable some invasive tests */
 #define MBEDTLS_TEST_HOOKS
diff --git a/tests/data_files/Makefile b/tests/data_files/Makefile
index 09a0689..388b0ce 100644
--- a/tests/data_files/Makefile
+++ b/tests/data_files/Makefile
@@ -280,7 +280,7 @@
 	$(OPENSSL) req -x509 -new -subj "/C=UK/O=Mbed TLS/CN=Mbed TLS non-printable othername SAN" -set_serial 77 -config $(test_ca_config_file) -extensions nonprintable_othername_san -days 3650 -sha256 -key $< -out $@
 
 server5-unsupported_othername.crt: server5.key
-	$(OPENSSL) req -x509 -new -subj "/C=UK/O=Mbed TLS/CN=Mbed TLS unsupported othername SAN" -set_serial 77 -config $(test_ca_config_file) -extensions unsupoported_othername_san -days 3650 -sha256 -key $< -out $@
+	$(OPENSSL) req -x509 -new -subj "/C=UK/O=Mbed TLS/CN=Mbed TLS unsupported othername SAN" -set_serial 77 -config $(test_ca_config_file) -extensions unsupported_othername_san -days 3650 -sha256 -key $< -out $@
 
 server5-fan.crt: server5.key
 	$(OPENSSL) req -x509 -new -subj "/C=UK/O=Mbed TLS/CN=Mbed TLS FAN" -set_serial 77 -config $(test_ca_config_file) -extensions fan_cert -days 3650 -sha256 -key server5.key -out $@
@@ -884,6 +884,11 @@
 	$(MBEDTLS_CERT_REQ) output_file=$@ filename=$< subject_name="C=NL,O=PolarSSL,CN=PolarSSL Server 1" md=SHA256
 all_final += server1.req.sha256
 
+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"
+all_final += server1.req.sha256.ext
+
 server1.req.sha384: server1.key
 	$(MBEDTLS_CERT_REQ) output_file=$@ filename=$< subject_name="C=NL,O=PolarSSL,CN=PolarSSL Server 1" md=SHA384
 all_final += server1.req.sha384
@@ -1134,6 +1139,108 @@
 all_final += ecdsa_secp521r1.crt ecdsa_secp521r1.key
 tls13_certs: ecdsa_secp521r1.crt ecdsa_secp521r1.key
 
+# PKCS7 test data
+pkcs7_test_cert_1 = pkcs7-rsa-sha256-1.crt
+pkcs7_test_cert_2 = pkcs7-rsa-sha256-2.crt
+pkcs7_test_file = pkcs7_data.bin
+
+$(pkcs7_test_file):
+	echo -e "Hello\xd" > $@
+all_final += $(pkcs7_test_file)
+
+pkcs7_data_1.bin:
+	echo -e "2\xd" > $@
+all_final += pkcs7_data_1.bin
+
+# Generate signing cert
+pkcs7-rsa-sha256-1.crt:
+	$(OPENSSL) req -x509 -subj="/C=NL/O=PKCS7/CN=PKCS7 Cert 1" -sha256 -nodes -days 365  -newkey rsa:2048 -keyout pkcs7-rsa-sha256-1.key -out pkcs7-rsa-sha256-1.crt
+	cat pkcs7-rsa-sha256-1.crt pkcs7-rsa-sha256-1.key > pkcs7-rsa-sha256-1.pem
+all_final += pkcs7-rsa-sha256-1.crt
+
+pkcs7-rsa-sha256-2.crt:
+	$(OPENSSL) req -x509 -subj="/C=NL/O=PKCS7/CN=PKCS7 Cert 2" -sha256 -nodes -days 365  -newkey rsa:2048 -keyout pkcs7-rsa-sha256-2.key -out pkcs7-rsa-sha256-2.crt
+	cat pkcs7-rsa-sha256-2.crt pkcs7-rsa-sha256-2.key > pkcs7-rsa-sha256-2.pem
+all_final += pkcs7-rsa-sha256-2.crt
+
+# Convert signing certs to DER for testing PEM-free builds
+pkcs7-rsa-sha256-1.der: $(pkcs7_test_cert_1)
+	$(OPENSSL) x509 -in pkcs7-rsa-sha256-1.crt -out $@ -outform DER
+all_final += pkcs7-rsa-sha256-1.der
+
+pkcs7-rsa-sha256-2.der: $(pkcs7_test_cert_2)
+	$(OPENSSL) x509 -in pkcs7-rsa-sha256-2.crt -out $@ -outform DER
+all_final += pkcs7-rsa-sha256-2.der
+
+# pkcs7 signature file with CERT
+pkcs7_data_cert_signed_sha256.der: $(pkcs7_test_file) $(pkcs7_test_cert_1)
+	$(OPENSSL) smime -sign -binary -in pkcs7_data.bin -out $@ -md sha256 -signer pkcs7-rsa-sha256-1.pem -noattr -outform DER -out $@
+all_final += pkcs7_data_cert_signed_sha256.der
+
+# pkcs7 signature file with CERT and sha1
+pkcs7_data_cert_signed_sha1.der: $(pkcs7_test_file) $(pkcs7_test_cert_1)
+	$(OPENSSL) smime -sign -binary -in pkcs7_data.bin -out $@ -md sha1 -signer pkcs7-rsa-sha256-1.pem -noattr -outform DER -out $@
+all_final += pkcs7_data_cert_signed_sha1.der
+
+# pkcs7 signature file with CERT and sha512
+pkcs7_data_cert_signed_sha512.der: $(pkcs7_test_file) $(pkcs7_test_cert_1)
+	$(OPENSSL) smime -sign -binary -in pkcs7_data.bin -out $@ -md sha512 -signer pkcs7-rsa-sha256-1.pem -noattr -outform DER -out $@
+all_final += pkcs7_data_cert_signed_sha512.der
+
+# pkcs7 signature file without CERT
+pkcs7_data_without_cert_signed.der: $(pkcs7_test_file) $(pkcs7_test_cert_1)
+	$(OPENSSL) smime -sign -binary -in pkcs7_data.bin -out $@ -md sha256 -signer pkcs7-rsa-sha256-1.pem -nocerts -noattr -outform DER -out $@
+all_final += pkcs7_data_without_cert_signed.der
+
+# pkcs7 signature file with multiple signers
+pkcs7_data_multiple_signed.der: $(pkcs7_test_file) $(pkcs7_test_cert_1) $(pkcs7_test_cert_2)
+	$(OPENSSL) smime -sign -binary -in pkcs7_data.bin -out $@ -md sha256 -signer pkcs7-rsa-sha256-1.pem -signer pkcs7-rsa-sha256-2.pem -nocerts -noattr -outform DER -out $@
+all_final += pkcs7_data_multiple_signed.der
+
+# pkcs7 signature file with multiple certificates
+pkcs7_data_multiple_certs_signed.der: $(pkcs7_test_file) $(pkcs7_test_cert_1) $(pkcs7_test_cert_2)
+	$(OPENSSL) smime -sign -binary -in pkcs7_data.bin -out $@ -md sha256 -signer pkcs7-rsa-sha256-1.pem -signer pkcs7-rsa-sha256-2.pem -noattr -outform DER -out $@
+all_final += pkcs7_data_multiple_certs_signed.der
+
+# pkcs7 signature file with corrupted CERT
+pkcs7_data_signed_badcert.der: pkcs7_data_cert_signed_sha256.der
+	cp pkcs7_data_cert_signed_sha256.der $@
+	echo -en '\xa1' | dd of=$@ bs=1 seek=547 conv=notrunc
+all_final += pkcs7_data_signed_badcert.der
+
+# pkcs7 signature file with corrupted signer info
+pkcs7_data_signed_badsigner.der: pkcs7_data_cert_signed_sha256.der
+	cp pkcs7_data_cert_signed_sha256.der $@
+	echo -en '\xa1' | dd of=$@ bs=1 seek=918 conv=notrunc
+all_final += pkcs7_data_signed_badsigner.der
+
+# pkcs7 file with version 2
+pkcs7_data_cert_signed_v2.der: pkcs7_data_cert_signed_sha256.der
+	cp pkcs7_data_cert_signed_sha256.der $@
+	echo -en '\x02' | dd of=$@ bs=1 seek=25 conv=notrunc
+all_final += pkcs7_data_cert_signed_v2.der
+
+pkcs7_data_cert_encrypted.der: $(pkcs7_test_file) $(pkcs7_test_cert_1)
+	$(OPENSSL) smime -encrypt -aes256 -in pkcs7_data.bin -binary -outform DER -out $@ pkcs7-rsa-sha256-1.crt
+all_final += pkcs7_data_cert_encrypted.der
+
+## Negative tests
+# For some interesting sizes, what happens if we make them off-by-one?
+pkcs7_signerInfo_issuer_invalid_size.der: pkcs7_data_cert_signed_sha256.der
+	cp $< $@
+	echo -en '\x35' | dd of=$@ seek=919 bs=1 conv=notrunc
+all_final += pkcs7_signerInfo_issuer_invalid_size.der
+
+pkcs7_signerInfo_serial_invalid_size.der: pkcs7_data_cert_signed_sha256.der
+	cp $< $@
+	echo -en '\x15' | dd of=$@ seek=973 bs=1 conv=notrunc
+all_final += pkcs7_signerInfo_serial_invalid_size.der
+
+# pkcs7 signature file just with signed data
+pkcs7_data_cert_signeddata_sha256.der: pkcs7_data_cert_signed_sha256.der
+	dd if=pkcs7_data_cert_signed_sha256.der of=$@ skip=19 bs=1
+all_final += pkcs7_data_cert_signeddata_sha256.der
+
 ################################################################
 #### Diffie-Hellman parameters
 ################################################################
diff --git a/tests/data_files/pkcs7-rsa-sha256-1.crt b/tests/data_files/pkcs7-rsa-sha256-1.crt
new file mode 100644
index 0000000..9e461cd
--- /dev/null
+++ b/tests/data_files/pkcs7-rsa-sha256-1.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDSTCCAjGgAwIBAgIUe97d0kRM0c3+XEGoECyJt98ubL8wDQYJKoZIhvcNAQEL
+BQAwNDELMAkGA1UEBhMCTkwxDjAMBgNVBAoMBVBLQ1M3MRUwEwYDVQQDDAxQS0NT
+NyBDZXJ0IDEwHhcNMjIxMDI4MTYxMDU2WhcNMjMxMDI4MTYxMDU2WjA0MQswCQYD
+VQQGEwJOTDEOMAwGA1UECgwFUEtDUzcxFTATBgNVBAMMDFBLQ1M3IENlcnQgMTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMi2z2mJnNHw67TKZFwF5w4N
+Lv7dzGHQicvVFaOaNXm5I0O2HsdQBg+07TeHYzJADkJfHTdsfnXClzMU7fS7MMj4
+3QO5/P+VWiRdSRN61uYAVsrBlVKoZdUhhxh8wELJxJ4+OpwXpTS0U82rwMsRO09j
+9bMXS57pkCsZENEUlqJ5p0Mmrc/uEL/Z5+uvuzd76bY5WRZdE91XURccra08HTra
+xovIAR1htUz2AXi+NoOaiayRq0GePKN9a6iB0lUYxNtovKb3yDYC9pmoaxf7Hnc7
+y+dLuTpJslGuhkKLV0Dhhoux1vq54ocS6Y7DGa2Pyk1zAQxLCcS4BFiWHnzwg1MC
+AwEAAaNTMFEwHQYDVR0OBBYEFIru5ZR8xnxd1RWnbip+zTHuUv3IMB8GA1UdIwQY
+MBaAFIru5ZR8xnxd1RWnbip+zTHuUv3IMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAIIda5jNRX3r0rCBrKJ+vs1Pk6zIKEQ7Oeq/+p+k6eRUO0b8
+wx4rW0gXeQPeppaaxKLMZXBlA5DxsI1DpML5dcfti/M1bHIYOAISRRqPEd5GVTy8
+1ltCVN249mg06yHdoqjzO1geFIRVesoblO6JMd3xYDe3pxcTIakZNq/Cf/zjld51
+1fcMuLWu4F/1BwiNZa8eQ5Zs1Cy+b3+s+NrgVd2CIrFpZSFyP4EkUXhZXJha6Rf9
+SzmYdz4al7e9EAhURvQlm8wJpFSSkoLBuJtx7Vh6d14KPUU2NB9F2ulp6AbJb+/H
+EGd3bAK6IhIrkZmxTAwowESHUJBwuX890tbZcnM=
+-----END CERTIFICATE-----
diff --git a/tests/data_files/pkcs7-rsa-sha256-1.der b/tests/data_files/pkcs7-rsa-sha256-1.der
new file mode 100644
index 0000000..0d799ea
--- /dev/null
+++ b/tests/data_files/pkcs7-rsa-sha256-1.der
Binary files differ
diff --git a/tests/data_files/pkcs7-rsa-sha256-1.key b/tests/data_files/pkcs7-rsa-sha256-1.key
new file mode 100644
index 0000000..e31159d
--- /dev/null
+++ b/tests/data_files/pkcs7-rsa-sha256-1.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDIts9piZzR8Ou0
+ymRcBecODS7+3cxh0InL1RWjmjV5uSNDth7HUAYPtO03h2MyQA5CXx03bH51wpcz
+FO30uzDI+N0Dufz/lVokXUkTetbmAFbKwZVSqGXVIYcYfMBCycSePjqcF6U0tFPN
+q8DLETtPY/WzF0ue6ZArGRDRFJaieadDJq3P7hC/2efrr7s3e+m2OVkWXRPdV1EX
+HK2tPB062saLyAEdYbVM9gF4vjaDmomskatBnjyjfWuogdJVGMTbaLym98g2AvaZ
+qGsX+x53O8vnS7k6SbJRroZCi1dA4YaLsdb6ueKHEumOwxmtj8pNcwEMSwnEuARY
+lh588INTAgMBAAECggEBAIg+P1B+TurbRMQ11iX5A7wwCsSKPh/vdHneLJAfL0lu
++JcP2piko1iqEZPt3NHRVVyMP8LNbJH3Ardz74p+PkFNXIkZCLlc4hFpGR+V9KWv
+eTqsaPXwxR8FYTSoCcHMQCDCUPp/um6qMXCcs4OkMMRVMATfPT+jf28h1p52AUJL
+aAoBJfn7gP3WiB0FWq0bRZgSZzNYowE/MhGAQ+DuBGTSASSK3YJcxE94044fBVE8
+EqYKrxoY/x56li5cZ0v9kaURCrvhqCeq2+U5kIkgtvp2l6wF0Mm1du3BLxo2LQEI
+Y2j+6BFEV74Mtv48GTwrZcyit787zyo9vVGcviSD5VECgYEA/mgLc5KfF/cQLmM/
+20T4k0edvktkRIJHFUBphowt5Hb0a0wM5C1VM4z3yN3b9ikQK+ZaQXETdPATBXIe
+LntX1D1xtbMxdcAfd1FSq8QxAuaPknJZBgtzlpCsx3ZvMnNuzKZN/TU8kR1biwPE
+9HaeEG3bouUu+CI/l/DqrBbQRacCgYEAyfiqsLWGhXQ7e3pLk47PDYlMOsjDWPjs
+SGcatH1/lIMWyZue4W2IUcFMbpbjA6QWibo3VnOavIRSTn97JNUWYvgc5MmaQ7iX
+Iss4m3vJ1LIqx30iUgw3EfDoWdpufEEYssZ/VxJPs3sdmZGALgd3CaqxHJuhuS+U
+eVhWzD6LonUCgYBRCbt8GRxsedrBrAPPSO0VnR52W3WZDRavglEa9tQ3jlzVQOhq
+VrZpMWJMrb8/bl0kXsApUGeuPDsS5QMQM2IKzXfHNUlwBL8BNvpqlJg4IFFjiOEq
+t8MeFv+ymdtZ6sNElUUKf0bHwt5CLfUzGgXHnfb0sKSBjgdL0wYtwyacyQKBgQDJ
+NcyG4zEy/srLhtiIFnu8Fo40+hFzL/nlX6JBMc3KHJa1Hy43krF+ET6d5gAffndd
+moDKxbzgFksRHPuHhCobSucuHpJq6RjYdvDcJYS7OwxXVRi9+KFcZE52RaBQdWGv
+qQTvr7RrMDoa5dN3B8TVgpGT2JBTN02JXjKKo7zkiQKBgCZwKDiXl7qsGidvlFZc
+4CEtFsCgnNgdRTzsTL/Pr8q9CBK3BhjZjNzQALF1iGFDC1FdFYFOwI1E3j+MRHJB
+rQMF8zbmmlZ6SC5QtqatCSCCKUyrUjD5J+4UfJqWFjiBBdwz+5VJojHw1yijEwl4
+LrS/V2yBrDJVczQQM4psonLF
+-----END PRIVATE KEY-----
diff --git a/tests/data_files/pkcs7-rsa-sha256-1.pem b/tests/data_files/pkcs7-rsa-sha256-1.pem
new file mode 100644
index 0000000..3795b71
--- /dev/null
+++ b/tests/data_files/pkcs7-rsa-sha256-1.pem
@@ -0,0 +1,48 @@
+-----BEGIN CERTIFICATE-----
+MIIDSTCCAjGgAwIBAgIUe97d0kRM0c3+XEGoECyJt98ubL8wDQYJKoZIhvcNAQEL
+BQAwNDELMAkGA1UEBhMCTkwxDjAMBgNVBAoMBVBLQ1M3MRUwEwYDVQQDDAxQS0NT
+NyBDZXJ0IDEwHhcNMjIxMDI4MTYxMDU2WhcNMjMxMDI4MTYxMDU2WjA0MQswCQYD
+VQQGEwJOTDEOMAwGA1UECgwFUEtDUzcxFTATBgNVBAMMDFBLQ1M3IENlcnQgMTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMi2z2mJnNHw67TKZFwF5w4N
+Lv7dzGHQicvVFaOaNXm5I0O2HsdQBg+07TeHYzJADkJfHTdsfnXClzMU7fS7MMj4
+3QO5/P+VWiRdSRN61uYAVsrBlVKoZdUhhxh8wELJxJ4+OpwXpTS0U82rwMsRO09j
+9bMXS57pkCsZENEUlqJ5p0Mmrc/uEL/Z5+uvuzd76bY5WRZdE91XURccra08HTra
+xovIAR1htUz2AXi+NoOaiayRq0GePKN9a6iB0lUYxNtovKb3yDYC9pmoaxf7Hnc7
+y+dLuTpJslGuhkKLV0Dhhoux1vq54ocS6Y7DGa2Pyk1zAQxLCcS4BFiWHnzwg1MC
+AwEAAaNTMFEwHQYDVR0OBBYEFIru5ZR8xnxd1RWnbip+zTHuUv3IMB8GA1UdIwQY
+MBaAFIru5ZR8xnxd1RWnbip+zTHuUv3IMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAIIda5jNRX3r0rCBrKJ+vs1Pk6zIKEQ7Oeq/+p+k6eRUO0b8
+wx4rW0gXeQPeppaaxKLMZXBlA5DxsI1DpML5dcfti/M1bHIYOAISRRqPEd5GVTy8
+1ltCVN249mg06yHdoqjzO1geFIRVesoblO6JMd3xYDe3pxcTIakZNq/Cf/zjld51
+1fcMuLWu4F/1BwiNZa8eQ5Zs1Cy+b3+s+NrgVd2CIrFpZSFyP4EkUXhZXJha6Rf9
+SzmYdz4al7e9EAhURvQlm8wJpFSSkoLBuJtx7Vh6d14KPUU2NB9F2ulp6AbJb+/H
+EGd3bAK6IhIrkZmxTAwowESHUJBwuX890tbZcnM=
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDIts9piZzR8Ou0
+ymRcBecODS7+3cxh0InL1RWjmjV5uSNDth7HUAYPtO03h2MyQA5CXx03bH51wpcz
+FO30uzDI+N0Dufz/lVokXUkTetbmAFbKwZVSqGXVIYcYfMBCycSePjqcF6U0tFPN
+q8DLETtPY/WzF0ue6ZArGRDRFJaieadDJq3P7hC/2efrr7s3e+m2OVkWXRPdV1EX
+HK2tPB062saLyAEdYbVM9gF4vjaDmomskatBnjyjfWuogdJVGMTbaLym98g2AvaZ
+qGsX+x53O8vnS7k6SbJRroZCi1dA4YaLsdb6ueKHEumOwxmtj8pNcwEMSwnEuARY
+lh588INTAgMBAAECggEBAIg+P1B+TurbRMQ11iX5A7wwCsSKPh/vdHneLJAfL0lu
++JcP2piko1iqEZPt3NHRVVyMP8LNbJH3Ardz74p+PkFNXIkZCLlc4hFpGR+V9KWv
+eTqsaPXwxR8FYTSoCcHMQCDCUPp/um6qMXCcs4OkMMRVMATfPT+jf28h1p52AUJL
+aAoBJfn7gP3WiB0FWq0bRZgSZzNYowE/MhGAQ+DuBGTSASSK3YJcxE94044fBVE8
+EqYKrxoY/x56li5cZ0v9kaURCrvhqCeq2+U5kIkgtvp2l6wF0Mm1du3BLxo2LQEI
+Y2j+6BFEV74Mtv48GTwrZcyit787zyo9vVGcviSD5VECgYEA/mgLc5KfF/cQLmM/
+20T4k0edvktkRIJHFUBphowt5Hb0a0wM5C1VM4z3yN3b9ikQK+ZaQXETdPATBXIe
+LntX1D1xtbMxdcAfd1FSq8QxAuaPknJZBgtzlpCsx3ZvMnNuzKZN/TU8kR1biwPE
+9HaeEG3bouUu+CI/l/DqrBbQRacCgYEAyfiqsLWGhXQ7e3pLk47PDYlMOsjDWPjs
+SGcatH1/lIMWyZue4W2IUcFMbpbjA6QWibo3VnOavIRSTn97JNUWYvgc5MmaQ7iX
+Iss4m3vJ1LIqx30iUgw3EfDoWdpufEEYssZ/VxJPs3sdmZGALgd3CaqxHJuhuS+U
+eVhWzD6LonUCgYBRCbt8GRxsedrBrAPPSO0VnR52W3WZDRavglEa9tQ3jlzVQOhq
+VrZpMWJMrb8/bl0kXsApUGeuPDsS5QMQM2IKzXfHNUlwBL8BNvpqlJg4IFFjiOEq
+t8MeFv+ymdtZ6sNElUUKf0bHwt5CLfUzGgXHnfb0sKSBjgdL0wYtwyacyQKBgQDJ
+NcyG4zEy/srLhtiIFnu8Fo40+hFzL/nlX6JBMc3KHJa1Hy43krF+ET6d5gAffndd
+moDKxbzgFksRHPuHhCobSucuHpJq6RjYdvDcJYS7OwxXVRi9+KFcZE52RaBQdWGv
+qQTvr7RrMDoa5dN3B8TVgpGT2JBTN02JXjKKo7zkiQKBgCZwKDiXl7qsGidvlFZc
+4CEtFsCgnNgdRTzsTL/Pr8q9CBK3BhjZjNzQALF1iGFDC1FdFYFOwI1E3j+MRHJB
+rQMF8zbmmlZ6SC5QtqatCSCCKUyrUjD5J+4UfJqWFjiBBdwz+5VJojHw1yijEwl4
+LrS/V2yBrDJVczQQM4psonLF
+-----END PRIVATE KEY-----
diff --git a/tests/data_files/pkcs7-rsa-sha256-2.crt b/tests/data_files/pkcs7-rsa-sha256-2.crt
new file mode 100644
index 0000000..a0df7d9
--- /dev/null
+++ b/tests/data_files/pkcs7-rsa-sha256-2.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDSTCCAjGgAwIBAgIUVk1VQCWvWZ4ycHmycg7wDfN8+3wwDQYJKoZIhvcNAQEL
+BQAwNDELMAkGA1UEBhMCTkwxDjAMBgNVBAoMBVBLQ1M3MRUwEwYDVQQDDAxQS0NT
+NyBDZXJ0IDIwHhcNMjIxMDI4MTYxMDU2WhcNMjMxMDI4MTYxMDU2WjA0MQswCQYD
+VQQGEwJOTDEOMAwGA1UECgwFUEtDUzcxFTATBgNVBAMMDFBLQ1M3IENlcnQgMjCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMmVNZZ0/qcT+h/lVNO+gP65
+lERTTudQ15h8QTLjaKhx5SSTLnuUhD0jLbR+ng8PMqdJ8ePkZEh1+7mi9MHzID4Y
+c47jH8M+Jc/JdBr6cSjbFd23QHESUjKKmV1IjSHc6Llbxe962z4gEXYjJAMkfr6B
+g1iecK3AlnEI4F0BsQfC5dgA4Qce2okvcTuhYgvHtLZ+UN4ca50Kw0o4u5FYdl89
+KDCE4zNp8MaaxGC83xcM4A9XqjHyZ7a2wvACTlmLQ2q/E+RN/8THEel4Y+yv82Uj
+j2LqqEaA06dvSdOPdaGz9jUZauqBw7TcuGGVzrrsZ0g/sHXKng9TppehAV/HrJUC
+AwEAAaNTMFEwHQYDVR0OBBYEFI5FVrtfLwPXRERcyVX6qBVvfoduMB8GA1UdIwQY
+MBaAFI5FVrtfLwPXRERcyVX6qBVvfoduMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAKRl0wgREe6eAduJSV5fs+Ec0s2qs2lHQqt/0JGEIbZBBtka
+q1UH9CIMMAd6Kb0kh5GlJT2shg/EAYWoitMwntkeRYTln2k2/B5jux+U5Ph4HyC+
+ad2GqmsoXWDru79rltT7Pv1hS1ofJyQ4Jv88vQA/SuIIRGdTC24VAVgg00JxvDRB
+xeqsQ9Pld4ebg4VvqsInnSpmKCcxfWxFhJk/Ax8bK/tV/GnrPiwsvry1j9nZyebS
+IyI01/6DwJS2ZhFnsLGyPHFOAFNtomjIdQ6gf2L1wq0qiGOKj/K9IzFNCpCz82a+
+gMgqFzCT5TCZC16kUG2NA2pXAx9O4uppKjRk97U=
+-----END CERTIFICATE-----
diff --git a/tests/data_files/pkcs7-rsa-sha256-2.der b/tests/data_files/pkcs7-rsa-sha256-2.der
new file mode 100644
index 0000000..fc7a3ea
--- /dev/null
+++ b/tests/data_files/pkcs7-rsa-sha256-2.der
Binary files differ
diff --git a/tests/data_files/pkcs7-rsa-sha256-2.key b/tests/data_files/pkcs7-rsa-sha256-2.key
new file mode 100644
index 0000000..659c015
--- /dev/null
+++ b/tests/data_files/pkcs7-rsa-sha256-2.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDJlTWWdP6nE/of
+5VTTvoD+uZREU07nUNeYfEEy42ioceUkky57lIQ9Iy20fp4PDzKnSfHj5GRIdfu5
+ovTB8yA+GHOO4x/DPiXPyXQa+nEo2xXdt0BxElIyipldSI0h3Oi5W8Xvets+IBF2
+IyQDJH6+gYNYnnCtwJZxCOBdAbEHwuXYAOEHHtqJL3E7oWILx7S2flDeHGudCsNK
+OLuRWHZfPSgwhOMzafDGmsRgvN8XDOAPV6ox8me2tsLwAk5Zi0NqvxPkTf/ExxHp
+eGPsr/NlI49i6qhGgNOnb0nTj3Whs/Y1GWrqgcO03Lhhlc667GdIP7B1yp4PU6aX
+oQFfx6yVAgMBAAECggEBAMVHm3w134qQCHfyroPTqtaftDTx+wRyn6yB3iT5XdGM
+NZ8H07Pp80kKBo7gY7uFOiNyQKKxQFuR69sPWc3+LI3YzC8IpGslhUfHdjN46gn7
+73hfAVgnf/4qmlEq0cRUOAY/hIUMjUhNhglB9tqEeu3iPjMaTFgfZJwW/czH/QMD
+w4zj5XoLgwRkqVvUceu/dBgV8KP5DpON+q8wpfWtjunv7rg5Nc3BVBrpb5SadJ7T
+i5TsS+pZQyp+mTvyCI3A1hkr2Vw5tULWO8SPhuEQkdtC/CL+luCUO7L16lU6KhFB
+qP5Fduik5skyLCVvAMUkjKcrC22k0gkhOHvfmMhjaAECgYEA68+hAQIiV9ErZGk9
+ZLu+VJHBSPmEQCkUcbviwzoRo8YSyka12TZERy+NJcvmD9deNgFbp8GyZf01XJWH
+slSYt6LyInrJrTpv+3q2Vl5GQp0f+39i7MHnwGGKbWsDbSAm+L9yKTJzYJz1O5fo
+in06AiyyGPwnXd1cm5bTXVX+dQECgYEA2tdi6DXF8awE23pv4HphPBhXS5hmYP/D
+NC7CtP8wQsxjPdiIxkBFFVEaFCC2njq1VhTyJb5noJM4kOIwcoaQ/zgyyxQa0u7w
++CqvAh1WwG+sT/B7vivrtDmmYeyGQapFo5DRIz+MflKAhzDhtnEyT9vLuCdn8J95
+0YvxZJ9+k5UCgYEAh+e7SER9nJUt6AoLWyIlGMKEXlWIFh5W7RG3KIMwJW6D59aG
++fAfu9M5Cx6PsnOSlZeExpOJCOS9O2Xmti2xcqzT1nFkCJWUcqCPtAlTfxLlmuIZ
+FpDOy36r9FHnwJ32OAjGd93ex0DOyZDMcfyoURaHcoTo/10UAYwUt0dXhwECgYAI
+xad2TWmA1XdgYNkJM36gTQ16v0IjUz084z70yGHj25OC0CIzaDIct6KG+gS39Px9
+1dsa/jXjLuOOkzKD9LbtNBB9KXIl0GQiXnujZw+qKQ/MKISdS99n2wO7WyLKkQu3
+kb+AXTTBf4cdZC04BfORVesll5bIA2x7pNNpSCdnvQKBgG7VXYcPlIV7iAyi2xFa
+uN1jccu/AK7xA0G1jz2SHNlpet74LmWR8XsTujJeo8WG1IRFxSky4h/pAP0XWIFO
+0LPK7eeDtnFq6y1/DXpI+/9BWX5T/8+4Yk93p37YrBVWKfd21dhrAklQs11m3rlQ
+Qn6c/zyvMKSyrCVxo5pTd5Il
+-----END PRIVATE KEY-----
diff --git a/tests/data_files/pkcs7-rsa-sha256-2.pem b/tests/data_files/pkcs7-rsa-sha256-2.pem
new file mode 100644
index 0000000..b11a00a
--- /dev/null
+++ b/tests/data_files/pkcs7-rsa-sha256-2.pem
@@ -0,0 +1,48 @@
+-----BEGIN CERTIFICATE-----
+MIIDSTCCAjGgAwIBAgIUVk1VQCWvWZ4ycHmycg7wDfN8+3wwDQYJKoZIhvcNAQEL
+BQAwNDELMAkGA1UEBhMCTkwxDjAMBgNVBAoMBVBLQ1M3MRUwEwYDVQQDDAxQS0NT
+NyBDZXJ0IDIwHhcNMjIxMDI4MTYxMDU2WhcNMjMxMDI4MTYxMDU2WjA0MQswCQYD
+VQQGEwJOTDEOMAwGA1UECgwFUEtDUzcxFTATBgNVBAMMDFBLQ1M3IENlcnQgMjCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMmVNZZ0/qcT+h/lVNO+gP65
+lERTTudQ15h8QTLjaKhx5SSTLnuUhD0jLbR+ng8PMqdJ8ePkZEh1+7mi9MHzID4Y
+c47jH8M+Jc/JdBr6cSjbFd23QHESUjKKmV1IjSHc6Llbxe962z4gEXYjJAMkfr6B
+g1iecK3AlnEI4F0BsQfC5dgA4Qce2okvcTuhYgvHtLZ+UN4ca50Kw0o4u5FYdl89
+KDCE4zNp8MaaxGC83xcM4A9XqjHyZ7a2wvACTlmLQ2q/E+RN/8THEel4Y+yv82Uj
+j2LqqEaA06dvSdOPdaGz9jUZauqBw7TcuGGVzrrsZ0g/sHXKng9TppehAV/HrJUC
+AwEAAaNTMFEwHQYDVR0OBBYEFI5FVrtfLwPXRERcyVX6qBVvfoduMB8GA1UdIwQY
+MBaAFI5FVrtfLwPXRERcyVX6qBVvfoduMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAKRl0wgREe6eAduJSV5fs+Ec0s2qs2lHQqt/0JGEIbZBBtka
+q1UH9CIMMAd6Kb0kh5GlJT2shg/EAYWoitMwntkeRYTln2k2/B5jux+U5Ph4HyC+
+ad2GqmsoXWDru79rltT7Pv1hS1ofJyQ4Jv88vQA/SuIIRGdTC24VAVgg00JxvDRB
+xeqsQ9Pld4ebg4VvqsInnSpmKCcxfWxFhJk/Ax8bK/tV/GnrPiwsvry1j9nZyebS
+IyI01/6DwJS2ZhFnsLGyPHFOAFNtomjIdQ6gf2L1wq0qiGOKj/K9IzFNCpCz82a+
+gMgqFzCT5TCZC16kUG2NA2pXAx9O4uppKjRk97U=
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDJlTWWdP6nE/of
+5VTTvoD+uZREU07nUNeYfEEy42ioceUkky57lIQ9Iy20fp4PDzKnSfHj5GRIdfu5
+ovTB8yA+GHOO4x/DPiXPyXQa+nEo2xXdt0BxElIyipldSI0h3Oi5W8Xvets+IBF2
+IyQDJH6+gYNYnnCtwJZxCOBdAbEHwuXYAOEHHtqJL3E7oWILx7S2flDeHGudCsNK
+OLuRWHZfPSgwhOMzafDGmsRgvN8XDOAPV6ox8me2tsLwAk5Zi0NqvxPkTf/ExxHp
+eGPsr/NlI49i6qhGgNOnb0nTj3Whs/Y1GWrqgcO03Lhhlc667GdIP7B1yp4PU6aX
+oQFfx6yVAgMBAAECggEBAMVHm3w134qQCHfyroPTqtaftDTx+wRyn6yB3iT5XdGM
+NZ8H07Pp80kKBo7gY7uFOiNyQKKxQFuR69sPWc3+LI3YzC8IpGslhUfHdjN46gn7
+73hfAVgnf/4qmlEq0cRUOAY/hIUMjUhNhglB9tqEeu3iPjMaTFgfZJwW/czH/QMD
+w4zj5XoLgwRkqVvUceu/dBgV8KP5DpON+q8wpfWtjunv7rg5Nc3BVBrpb5SadJ7T
+i5TsS+pZQyp+mTvyCI3A1hkr2Vw5tULWO8SPhuEQkdtC/CL+luCUO7L16lU6KhFB
+qP5Fduik5skyLCVvAMUkjKcrC22k0gkhOHvfmMhjaAECgYEA68+hAQIiV9ErZGk9
+ZLu+VJHBSPmEQCkUcbviwzoRo8YSyka12TZERy+NJcvmD9deNgFbp8GyZf01XJWH
+slSYt6LyInrJrTpv+3q2Vl5GQp0f+39i7MHnwGGKbWsDbSAm+L9yKTJzYJz1O5fo
+in06AiyyGPwnXd1cm5bTXVX+dQECgYEA2tdi6DXF8awE23pv4HphPBhXS5hmYP/D
+NC7CtP8wQsxjPdiIxkBFFVEaFCC2njq1VhTyJb5noJM4kOIwcoaQ/zgyyxQa0u7w
++CqvAh1WwG+sT/B7vivrtDmmYeyGQapFo5DRIz+MflKAhzDhtnEyT9vLuCdn8J95
+0YvxZJ9+k5UCgYEAh+e7SER9nJUt6AoLWyIlGMKEXlWIFh5W7RG3KIMwJW6D59aG
++fAfu9M5Cx6PsnOSlZeExpOJCOS9O2Xmti2xcqzT1nFkCJWUcqCPtAlTfxLlmuIZ
+FpDOy36r9FHnwJ32OAjGd93ex0DOyZDMcfyoURaHcoTo/10UAYwUt0dXhwECgYAI
+xad2TWmA1XdgYNkJM36gTQ16v0IjUz084z70yGHj25OC0CIzaDIct6KG+gS39Px9
+1dsa/jXjLuOOkzKD9LbtNBB9KXIl0GQiXnujZw+qKQ/MKISdS99n2wO7WyLKkQu3
+kb+AXTTBf4cdZC04BfORVesll5bIA2x7pNNpSCdnvQKBgG7VXYcPlIV7iAyi2xFa
+uN1jccu/AK7xA0G1jz2SHNlpet74LmWR8XsTujJeo8WG1IRFxSky4h/pAP0XWIFO
+0LPK7eeDtnFq6y1/DXpI+/9BWX5T/8+4Yk93p37YrBVWKfd21dhrAklQs11m3rlQ
+Qn6c/zyvMKSyrCVxo5pTd5Il
+-----END PRIVATE KEY-----
diff --git a/tests/data_files/pkcs7_data.bin b/tests/data_files/pkcs7_data.bin
new file mode 100644
index 0000000..40ee264
--- /dev/null
+++ b/tests/data_files/pkcs7_data.bin
@@ -0,0 +1 @@
+Hello

diff --git a/tests/data_files/pkcs7_data_1.bin b/tests/data_files/pkcs7_data_1.bin
new file mode 100644
index 0000000..78c6bae
--- /dev/null
+++ b/tests/data_files/pkcs7_data_1.bin
@@ -0,0 +1 @@
+2

diff --git a/tests/data_files/pkcs7_data_cert_encrypted.der b/tests/data_files/pkcs7_data_cert_encrypted.der
new file mode 100644
index 0000000..b7b1c83
--- /dev/null
+++ b/tests/data_files/pkcs7_data_cert_encrypted.der
Binary files differ
diff --git a/tests/data_files/pkcs7_data_cert_signed_sha1.der b/tests/data_files/pkcs7_data_cert_signed_sha1.der
new file mode 100644
index 0000000..fb1deb0
--- /dev/null
+++ b/tests/data_files/pkcs7_data_cert_signed_sha1.der
Binary files differ
diff --git a/tests/data_files/pkcs7_data_cert_signed_sha256.der b/tests/data_files/pkcs7_data_cert_signed_sha256.der
new file mode 100644
index 0000000..8dc2f4c
--- /dev/null
+++ b/tests/data_files/pkcs7_data_cert_signed_sha256.der
Binary files differ
diff --git a/tests/data_files/pkcs7_data_cert_signed_sha512.der b/tests/data_files/pkcs7_data_cert_signed_sha512.der
new file mode 100644
index 0000000..a4aa587
--- /dev/null
+++ b/tests/data_files/pkcs7_data_cert_signed_sha512.der
Binary files differ
diff --git a/tests/data_files/pkcs7_data_cert_signed_v2.der b/tests/data_files/pkcs7_data_cert_signed_v2.der
new file mode 100644
index 0000000..4f4cb04
--- /dev/null
+++ b/tests/data_files/pkcs7_data_cert_signed_v2.der
Binary files differ
diff --git a/tests/data_files/pkcs7_data_cert_signeddata_sha256.der b/tests/data_files/pkcs7_data_cert_signeddata_sha256.der
new file mode 100644
index 0000000..cb7d751
--- /dev/null
+++ b/tests/data_files/pkcs7_data_cert_signeddata_sha256.der
Binary files differ
diff --git a/tests/data_files/pkcs7_data_multiple_certs_signed.der b/tests/data_files/pkcs7_data_multiple_certs_signed.der
new file mode 100644
index 0000000..4a237e9
--- /dev/null
+++ b/tests/data_files/pkcs7_data_multiple_certs_signed.der
Binary files differ
diff --git a/tests/data_files/pkcs7_data_multiple_signed.der b/tests/data_files/pkcs7_data_multiple_signed.der
new file mode 100644
index 0000000..095b80c
--- /dev/null
+++ b/tests/data_files/pkcs7_data_multiple_signed.der
Binary files differ
diff --git a/tests/data_files/pkcs7_data_signed_badcert.der b/tests/data_files/pkcs7_data_signed_badcert.der
new file mode 100644
index 0000000..ed00f65
--- /dev/null
+++ b/tests/data_files/pkcs7_data_signed_badcert.der
Binary files differ
diff --git a/tests/data_files/pkcs7_data_signed_badsigner.der b/tests/data_files/pkcs7_data_signed_badsigner.der
new file mode 100644
index 0000000..aa5447c
--- /dev/null
+++ b/tests/data_files/pkcs7_data_signed_badsigner.der
Binary files differ
diff --git a/tests/data_files/pkcs7_data_without_cert_signed.der b/tests/data_files/pkcs7_data_without_cert_signed.der
new file mode 100644
index 0000000..b47fe92
--- /dev/null
+++ b/tests/data_files/pkcs7_data_without_cert_signed.der
Binary files differ
diff --git a/tests/data_files/pkcs7_get_signers_info_set-leak-fuzz_pkcs7-4541044530479104.der b/tests/data_files/pkcs7_get_signers_info_set-leak-fuzz_pkcs7-4541044530479104.der
new file mode 100644
index 0000000..51aef0d
--- /dev/null
+++ b/tests/data_files/pkcs7_get_signers_info_set-leak-fuzz_pkcs7-4541044530479104.der
Binary files differ
diff --git a/tests/data_files/pkcs7_get_signers_info_set-missing_free-fuzz_pkcs7-6213931373035520.der b/tests/data_files/pkcs7_get_signers_info_set-missing_free-fuzz_pkcs7-6213931373035520.der
new file mode 100644
index 0000000..ce4fb3b
--- /dev/null
+++ b/tests/data_files/pkcs7_get_signers_info_set-missing_free-fuzz_pkcs7-6213931373035520.der
Binary files differ
diff --git a/tests/data_files/pkcs7_signerInfo_issuer_invalid_size.der b/tests/data_files/pkcs7_signerInfo_issuer_invalid_size.der
new file mode 100644
index 0000000..898ca67
--- /dev/null
+++ b/tests/data_files/pkcs7_signerInfo_issuer_invalid_size.der
Binary files differ
diff --git a/tests/data_files/pkcs7_signerInfo_serial_invalid_size.der b/tests/data_files/pkcs7_signerInfo_serial_invalid_size.der
new file mode 100644
index 0000000..f4b4e38
--- /dev/null
+++ b/tests/data_files/pkcs7_signerInfo_serial_invalid_size.der
Binary files differ
diff --git a/tests/data_files/server1.req.sha256.ext b/tests/data_files/server1.req.sha256.ext
new file mode 100644
index 0000000..3f26f09
--- /dev/null
+++ b/tests/data_files/server1.req.sha256.ext
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICpzCCAY8CAQAwPDELMAkGA1UEBhMCTkwxETAPBgNVBAoMCFBvbGFyU1NMMRow
+GAYDVQQDDBFQb2xhclNTTCBTZXJ2ZXIgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAKkCHz1AatVVU4v9Nu6CZS4VYV6Jv7joRZDb7ogWUtPxQ1BHlhJZ
+ZIdr/SvgRvlzvt3PkuGRW+1moG+JKXlFgNCDatVBQ3dfOXwJBEeCsFc5cO2j7BUZ
+HqgzCEfBBUKp/UzDtN/dBh9NEFFAZ3MTD0D4bYElXwqxU8YwfhU5rPla7n+SnqYF
+W+cTl4W1I5LZ1CQG1QkliXUH3aYajz8JGb6tZSxk65Wb3P5BXhem2mxbacwCuhQs
+FiScStzN0PdSZ3PxLaAj/X70McotcMqJCwTbLqZPcG6ezr1YieJTWZ5uWpJl4og/
+DJQZo93l6J2VE+0p26twEtxaymsXq1KCVLECAwEAAaAmMCQGCSqGSIb3DQEJDjEX
+MBUwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBAHi0yEGu
+Fh5tuLiLuT95UrRnly55+lTY9xchFiKtlcoEdSheybYxqk3JHuSSqojOFKZBlRdk
+oG6Azg56/aMHPWyvtCMSRQX4b+FgjeQsm9IfhYNMquQOxyPxm62vjuU3MfZIofXH
+hKdI6Ci2CDF4Fyvw50KBWniV38eE9+kjsvDLdXD3ESZJGhjjuFl8ReUiA2wdBTcP
+XEZaXUIc6B4tUnlPeqn/2zp4GBqqWzNZx6TXBpApASGG3BEJnM52FVPC7E9p+8YZ
+qIGuiF5Cz/rYZkpwffBWIfS2zZakHLm5TB8FgZkWlyReJU9Ihk2Tl/sZ1kllFdYa
+xLPnLCL82KFL1Co=
+-----END CERTIFICATE REQUEST-----
diff --git a/tests/data_files/test-ca.opensslconf b/tests/data_files/test-ca.opensslconf
index 3bb2379..b2c2fa1 100644
--- a/tests/data_files/test-ca.opensslconf
+++ b/tests/data_files/test-ca.opensslconf
@@ -18,7 +18,7 @@
 [nonprintable_othername_san]
 subjectAltName=otherName:1.3.6.1.5.5.7.8.4;SEQ:nonprintable_hw_module_name
 
-[unsupoported_othername_san]
+[unsupported_othername_san]
 subjectAltName=otherName:1.2.3.4;UTF8:some other identifier
 
 [dns_alt_names]
diff --git a/tests/docker/bionic/Dockerfile b/tests/docker/bionic/Dockerfile
index 28d33b7..d44cdff 100644
--- a/tests/docker/bionic/Dockerfile
+++ b/tests/docker/bionic/Dockerfile
@@ -4,6 +4,10 @@
 # -------
 # Defines a Docker container suitable to build and run all tests (all.sh),
 # except for those that use a proprietary toolchain.
+#
+# WARNING: this Dockerfile is no longer maintained! See
+# https://github.com/Mbed-TLS/mbedtls-test/blob/master/README.md#quick-start
+# for the set of Docker images we use on the CI.
 
 # Copyright The Mbed TLS Contributors
 # SPDX-License-Identifier: Apache-2.0
diff --git a/tests/include/test/bignum_helpers.h b/tests/include/test/bignum_helpers.h
new file mode 100644
index 0000000..164017e
--- /dev/null
+++ b/tests/include/test/bignum_helpers.h
@@ -0,0 +1,118 @@
+/**
+ * \file bignum_helpers.h
+ *
+ * \brief   This file contains the prototypes of helper functions for
+ *          bignum-related 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 TEST_BIGNUM_HELPERS_H
+#define TEST_BIGNUM_HELPERS_H
+
+#include <mbedtls/build_info.h>
+
+#if defined(MBEDTLS_BIGNUM_C)
+
+#include <mbedtls/bignum.h>
+#include <bignum_mod.h>
+
+/** Allocate and populate a core MPI from a test case argument.
+ *
+ * This function allocates exactly as many limbs as necessary to fit
+ * the length of the input. In other words, it preserves leading zeros.
+ *
+ * The limb array is allocated with mbedtls_calloc() and must later be
+ * freed with mbedtls_free().
+ *
+ * \param[in,out] pX    The address where a pointer to the allocated limb
+ *                      array will be stored.
+ *                      \c *pX must be null on entry.
+ *                      On exit, \c *pX is null on error or if the number
+ *                      of limbs is 0.
+ * \param[out] plimbs   The address where the number of limbs will be stored.
+ * \param[in] input     The test argument to read.
+ *                      It is interpreted as a hexadecimal representation
+ *                      of a non-negative integer.
+ *
+ * \return \c 0 on success, an \c MBEDTLS_ERR_MPI_xxx error code otherwise.
+ */
+int mbedtls_test_read_mpi_core( mbedtls_mpi_uint **pX, size_t *plimbs,
+                                const char *input );
+
+/** Read a modulus from a hexadecimal string.
+ *
+ * This function allocates exactly as many limbs as necessary to fit
+ * the length of the input. In other words, it preserves leading zeros.
+ *
+ * The limb array is allocated with mbedtls_calloc() and must later be
+ * freed with mbedtls_free(). You can do that by calling
+ * mbedtls_test_mpi_mod_modulus_free_with_limbs().
+ *
+ * \param[in,out] N     A modulus structure. It must be initialized, but
+ *                      not set up.
+ * \param[in] s         The null-terminated hexadecimal string to read from.
+ * \param int_rep       The desired representation of residues.
+ *
+ * \return \c 0 on success, an \c MBEDTLS_ERR_MPI_xxx error code otherwise.
+ */
+int mbedtls_test_read_mpi_modulus( mbedtls_mpi_mod_modulus *N,
+                                   const char *s,
+                                   mbedtls_mpi_mod_rep_selector int_rep );
+
+/** Free a modulus and its limbs.
+ *
+ * \param[in] N         A modulus structure such that there is no other
+ *                      reference to `N->p`.
+ */
+void mbedtls_test_mpi_mod_modulus_free_with_limbs( mbedtls_mpi_mod_modulus *N );
+
+/** Read an MPI from a hexadecimal string.
+ *
+ * Like mbedtls_mpi_read_string(), but with tighter guarantees around
+ * edge cases.
+ *
+ * - This function guarantees that if \p s begins with '-' then the sign
+ *   bit of the result will be negative, even if the value is 0.
+ *   When this function encounters such a "negative 0", it
+ *   increments #mbedtls_test_case_uses_negative_0.
+ * - The size of the result is exactly the minimum number of limbs needed
+ *   to fit the digits in the input. In particular, this function constructs
+ *   a bignum with 0 limbs for an empty string, and a bignum with leading 0
+ *   limbs if the string has sufficiently many leading 0 digits.
+ *   This is important so that the "0 (null)" and "0 (1 limb)" and
+ *   "leading zeros" test cases do what they claim.
+ *
+ * \param[out] X        The MPI object to populate. It must be initialized.
+ * \param[in] s         The null-terminated hexadecimal string to read from.
+ *
+ * \return \c 0 on success, an \c MBEDTLS_ERR_MPI_xxx error code otherwise.
+ */
+int mbedtls_test_read_mpi( mbedtls_mpi *X, const char *s );
+
+/** Nonzero if the current test case had an input parsed with
+ * mbedtls_test_read_mpi() that is a negative 0 (`"-"`, `"-0"`, `"-00"`, etc.,
+ * constructing a result with the sign bit set to -1 and the value being
+ * all-limbs-0, which is not a valid representation in #mbedtls_mpi but is
+ * tested for robustness).
+ */
+extern unsigned mbedtls_test_case_uses_negative_0;
+
+#endif /* MBEDTLS_BIGNUM_C */
+
+#endif /* TEST_BIGNUM_HELPERS_H */
diff --git a/tests/include/test/constant_flow.h b/tests/include/test/constant_flow.h
index 9626af9..f3d676e 100644
--- a/tests/include/test/constant_flow.h
+++ b/tests/include/test/constant_flow.h
@@ -46,6 +46,12 @@
  * This file contains two implementations: one based on MemorySanitizer, the
  * other on valgrind's memcheck. If none of them is enabled, dummy macros that
  * do nothing are defined for convenience.
+ *
+ * \note #TEST_CF_SECRET must be called directly from within a .function file,
+ *       not indirectly via a macro defined under tests/include or a function
+ *       under tests/src. This is because we only run Valgrind for constant
+ *       flow on test suites that have greppable annotations inside them (see
+ *       `skip_suites_without_constant_flow` in `tests/scripts/all.sh`).
  */
 
 #if defined(MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN)
diff --git a/tests/include/test/drivers/crypto_config_test_driver_extension.h b/tests/include/test/drivers/crypto_config_test_driver_extension.h
index 0bbca4a..fbfe8da 100644
--- a/tests/include/test/drivers/crypto_config_test_driver_extension.h
+++ b/tests/include/test/drivers/crypto_config_test_driver_extension.h
@@ -54,6 +54,14 @@
 #endif
 #endif
 
+#if defined(PSA_WANT_ALG_ECDH)
+#if defined(MBEDTLS_PSA_ACCEL_ALG_ECDH)
+#undef MBEDTLS_PSA_ACCEL_ALG_ECDH
+#else
+#define MBEDTLS_PSA_ACCEL_ALG_ECDH 1
+#endif
+#endif
+
 #if defined(PSA_WANT_ALG_MD5)
 #if defined(MBEDTLS_PSA_ACCEL_ALG_MD5)
 #undef MBEDTLS_PSA_ACCEL_ALG_MD5
@@ -202,7 +210,6 @@
 #define MBEDTLS_PSA_ACCEL_ALG_CCM 1
 #define MBEDTLS_PSA_ACCEL_ALG_CMAC 1
 #define MBEDTLS_PSA_ACCEL_ALG_ECB_NO_PADDING 1
-#define MBEDTLS_PSA_ACCEL_ALG_ECDH 1
 #define MBEDTLS_PSA_ACCEL_ALG_GCM 1
 #define MBEDTLS_PSA_ACCEL_ALG_HKDF 1
 #define MBEDTLS_PSA_ACCEL_ALG_HKDF_EXTRACT 1
@@ -215,6 +222,7 @@
 #define MBEDTLS_PSA_ACCEL_ALG_TLS12_PSK_TO_MS 1
 
 #if defined(MBEDTLS_PSA_ACCEL_ALG_ECDSA)
+#if defined(MBEDTLS_PSA_ACCEL_ALG_ECDH)
 #define MBEDTLS_PSA_ACCEL_ECC_BRAINPOOL_P_R1_256 1
 #define MBEDTLS_PSA_ACCEL_ECC_BRAINPOOL_P_R1_384 1
 #define MBEDTLS_PSA_ACCEL_ECC_BRAINPOOL_P_R1_512 1
@@ -229,6 +237,7 @@
 #define MBEDTLS_PSA_ACCEL_ECC_SECP_R1_384 1
 #define MBEDTLS_PSA_ACCEL_ECC_SECP_R1_521 1
 #endif
+#endif
 
 #define MBEDTLS_PSA_ACCEL_KEY_TYPE_DERIVE 1
 #define MBEDTLS_PSA_ACCEL_KEY_TYPE_HMAC 1
diff --git a/tests/include/test/drivers/key_agreement.h b/tests/include/test/drivers/key_agreement.h
new file mode 100644
index 0000000..8f28cef
--- /dev/null
+++ b/tests/include/test/drivers/key_agreement.h
@@ -0,0 +1,74 @@
+/*
+ * Test driver for key agreement functions.
+ */
+/*  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 PSA_CRYPTO_TEST_DRIVERS_KEY_AGREEMENT_H
+#define PSA_CRYPTO_TEST_DRIVERS_KEY_AGREEMENT_H
+
+#include "mbedtls/build_info.h"
+
+#if defined(PSA_CRYPTO_DRIVER_TEST)
+#include <psa/crypto_driver_common.h>
+
+typedef struct {
+    /* If non-null, on success, copy this to the output. */
+    void *forced_output;
+    size_t forced_output_length;
+    /* If not PSA_SUCCESS, return this error code instead of processing the
+     * function call. */
+    psa_status_t forced_status;
+    /* Count the amount of times one of the signature driver functions is called. */
+    unsigned long hits;
+} mbedtls_test_driver_key_agreement_hooks_t;
+
+#define MBEDTLS_TEST_DRIVER_KEY_AGREEMENT_INIT { NULL, 0, PSA_SUCCESS, 0 }
+static inline mbedtls_test_driver_key_agreement_hooks_t
+    mbedtls_test_driver_key_agreement_hooks_init( void )
+{
+    const mbedtls_test_driver_key_agreement_hooks_t
+        v = MBEDTLS_TEST_DRIVER_KEY_AGREEMENT_INIT;
+    return( v );
+}
+
+extern mbedtls_test_driver_key_agreement_hooks_t
+    mbedtls_test_driver_key_agreement_hooks;
+
+psa_status_t mbedtls_test_transparent_key_agreement(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer,
+    size_t key_buffer_size,
+    psa_algorithm_t alg,
+    const uint8_t *peer_key,
+    size_t peer_key_length,
+    uint8_t *shared_secret,
+    size_t shared_secret_size,
+    size_t *shared_secret_length );
+
+psa_status_t mbedtls_test_opaque_key_agreement(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer,
+    size_t key_buffer_size,
+    psa_algorithm_t alg,
+    const uint8_t *peer_key,
+    size_t peer_key_length,
+    uint8_t *shared_secret,
+    size_t shared_secret_size,
+    size_t *shared_secret_length );
+
+#endif /*PSA_CRYPTO_DRIVER_TEST */
+#endif /* PSA_CRYPTO_TEST_DRIVERS_KEY_AGREEMENT_H */
diff --git a/tests/include/test/drivers/test_driver.h b/tests/include/test/drivers/test_driver.h
index b3c29e4..0a65b40 100644
--- a/tests/include/test/drivers/test_driver.h
+++ b/tests/include/test/drivers/test_driver.h
@@ -37,6 +37,7 @@
 #include "test/drivers/key_management.h"
 #include "test/drivers/signature.h"
 #include "test/drivers/asymmetric_encryption.h"
+#include "test/drivers/key_agreement.h"
 
 #endif /* PSA_CRYPTO_DRIVER_TEST */
 #endif /* PSA_CRYPTO_TEST_DRIVER_H */
diff --git a/tests/include/test/helpers.h b/tests/include/test/helpers.h
index e0e6fd2..b64bfcb 100644
--- a/tests/include/test/helpers.h
+++ b/tests/include/test/helpers.h
@@ -216,6 +216,17 @@
                           int len );
 
 /**
+ * \brief Convert hexadecimal digit to an integer.
+ *
+ * \param c        The digit to convert (`'0'` to `'9'`, `'A'` to `'F'` or
+ *                 `'a'` to `'f'`).
+ * \param[out] uc  On success, the value of the digit (0 to 15).
+ *
+ * \return         0 on success, -1 if \p c is not a hexadecimal digit.
+ */
+int mbedtls_test_ascii2uc(const char c, unsigned char *uc);
+
+/**
  * Allocate and zeroize a buffer.
  *
  * If the size if zero, a pointer to a zeroized 1-byte buffer is returned.
@@ -269,46 +280,4 @@
                                  const char *file, int line);
 #endif
 
-#if defined(MBEDTLS_BIGNUM_C)
-/** Allocate and populate a core MPI from a test case argument.
- *
- * This function allocates exactly as many limbs as necessary to fit
- * the length of the input. In other words, it preserves leading zeros.
- *
- * The limb array is allocated with mbedtls_calloc() and must later be
- * freed with mbedtls_free().
- *
- * \param[in,out] pX    The address where a pointer to the allocated limb
- *                      array will be stored.
- *                      \c *pX must be null on entry.
- *                      On exit, \c *pX is null on error or if the number
- *                      of limbs is 0.
- * \param[out] plimbs   The address where the number of limbs will be stored.
- * \param[in] input     The test argument to read.
- *                      It is interpreted as a hexadecimal representation
- *                      of a non-negative integer.
- *
- * \return \c 0 on success, an \c MBEDTLS_ERR_MPI_xxx error code otherwise.
- */
-int mbedtls_test_read_mpi_core( mbedtls_mpi_uint **pX, size_t *plimbs,
-                                const char *input );
-
-/** Read an MPI from a hexadecimal string.
- *
- * Like mbedtls_mpi_read_string(), but size the resulting bignum based
- * on the number of digits in the string. In particular, construct a
- * bignum with 0 limbs for an empty string, and a bignum with leading 0
- * limbs if the string has sufficiently many leading 0 digits.
- *
- * This is important so that the "0 (null)" and "0 (1 limb)" and
- * "leading zeros" test cases do what they claim.
- *
- * \param[out] X        The MPI object to populate. It must be initialized.
- * \param[in] s         The null-terminated hexadecimal string to read from.
- *
- * \return \c 0 on success, an \c MBEDTLS_ERR_MPI_xxx error code otherwise.
- */
-int mbedtls_test_read_mpi( mbedtls_mpi *X, const char *s );
-#endif /* MBEDTLS_BIGNUM_C */
-
 #endif /* TEST_HELPERS_H */
diff --git a/tests/include/test/psa_crypto_helpers.h b/tests/include/test/psa_crypto_helpers.h
index bc2b016..3542950 100644
--- a/tests/include/test/psa_crypto_helpers.h
+++ b/tests/include/test/psa_crypto_helpers.h
@@ -189,7 +189,7 @@
  *
  * Do a key policy permission extension on key usage policies always involves
  * permissions of other usage policies
- * (like PSA_KEY_USAGE_SIGN_HASH involves PSA_KEY_USAGE_SIGN_MESSGAE).
+ * (like PSA_KEY_USAGE_SIGN_HASH involves PSA_KEY_USAGE_SIGN_MESSAGE).
  */
 psa_key_usage_t mbedtls_test_update_key_usage_flags( psa_key_usage_t usage_flags );
 
diff --git a/tests/make-in-docker.sh b/tests/make-in-docker.sh
index 77dc8ab..0ee08dc 100755
--- a/tests/make-in-docker.sh
+++ b/tests/make-in-docker.sh
@@ -8,6 +8,10 @@
 #
 # See also:
 # - scripts/docker_env.sh for general Docker prerequisites and other information.
+#
+# WARNING: the Dockerfile used by this script is no longer maintained! See
+# https://github.com/Mbed-TLS/mbedtls-test/blob/master/README.md#quick-start
+# for the set of Docker images we use on the CI.
 
 # Copyright The Mbed TLS Contributors
 # SPDX-License-Identifier: Apache-2.0
diff --git a/tests/opt-testcases/tls13-misc.sh b/tests/opt-testcases/tls13-misc.sh
index 4ad6faa..710fb34 100755
--- a/tests/opt-testcases/tls13-misc.sh
+++ b/tests/opt-testcases/tls13-misc.sh
@@ -56,11 +56,8 @@
             -s "No matched ciphersuite"
 
 requires_all_configs_enabled MBEDTLS_SSL_PROTO_TLS1_3 MBEDTLS_SSL_SESSION_TICKETS MBEDTLS_SSL_SRV_C \
-                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME
-requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED \
-                             MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
-requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED \
-                             MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
 run_test "TLS 1.3 m->m: Multiple PSKs: valid ticket, reconnect with ticket" \
          "$P_SRV force_version=tls13 tls13_kex_modes=psk_ephemeral debug_level=5 psk_identity=Client_identity psk=6162636465666768696a6b6c6d6e6f70 tickets=8" \
          "$P_CLI force_version=tls13 tls13_kex_modes=psk_ephemeral debug_level=5 psk_identity=Client_identity psk=6162636465666768696a6b6c6d6e6f70 reco_mode=1 reconnect=1" \
@@ -73,11 +70,8 @@
          -S "ticket is not authentic"
 
 requires_all_configs_enabled MBEDTLS_SSL_PROTO_TLS1_3 MBEDTLS_SSL_SESSION_TICKETS MBEDTLS_SSL_SRV_C \
-                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME
-requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED \
-                             MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
-requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED \
-                             MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
 run_test "TLS 1.3 m->m: Multiple PSKs: invalid ticket, reconnect with PSK" \
          "$P_SRV force_version=tls13 tls13_kex_modes=psk_ephemeral debug_level=5 psk_identity=Client_identity psk=6162636465666768696a6b6c6d6e6f70 tickets=8 dummy_ticket=1" \
          "$P_CLI force_version=tls13 tls13_kex_modes=psk_ephemeral debug_level=5 psk_identity=Client_identity psk=6162636465666768696a6b6c6d6e6f70 reco_mode=1 reconnect=1" \
@@ -90,11 +84,9 @@
          -s "ticket is not authentic"
 
 requires_all_configs_enabled MBEDTLS_SSL_PROTO_TLS1_3 MBEDTLS_SSL_SESSION_TICKETS MBEDTLS_SSL_SRV_C \
-                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME
-requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED \
-                             MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
-requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED \
-                             MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
 run_test "TLS 1.3 m->m: Session resumption failure, ticket authentication failed." \
          "$P_SRV debug_level=4 crt_file=data_files/server5.crt key_file=data_files/server5.key force_version=tls13 tickets=8 dummy_ticket=1" \
          "$P_CLI debug_level=4 reco_mode=1 reconnect=1" \
@@ -111,11 +103,9 @@
          -S "Ticket age outside tolerance window"
 
 requires_all_configs_enabled MBEDTLS_SSL_PROTO_TLS1_3 MBEDTLS_SSL_SESSION_TICKETS MBEDTLS_SSL_SRV_C \
-                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME
-requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED \
-                             MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
-requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED \
-                             MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
 run_test "TLS 1.3 m->m: Session resumption failure, ticket expired." \
          "$P_SRV debug_level=4 crt_file=data_files/server5.crt key_file=data_files/server5.key force_version=tls13 tickets=8 dummy_ticket=2" \
          "$P_CLI debug_level=4 reco_mode=1 reconnect=1" \
@@ -132,11 +122,9 @@
          -S "Ticket age outside tolerance window"
 
 requires_all_configs_enabled MBEDTLS_SSL_PROTO_TLS1_3 MBEDTLS_SSL_SESSION_TICKETS MBEDTLS_SSL_SRV_C \
-                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME
-requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED \
-                             MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
-requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED \
-                             MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
 run_test "TLS 1.3 m->m: Session resumption failure, invalid start time." \
          "$P_SRV debug_level=4 crt_file=data_files/server5.crt key_file=data_files/server5.key force_version=tls13 tickets=8 dummy_ticket=3" \
          "$P_CLI debug_level=4 reco_mode=1 reconnect=1" \
@@ -153,11 +141,9 @@
          -S "Ticket age outside tolerance window"
 
 requires_all_configs_enabled MBEDTLS_SSL_PROTO_TLS1_3 MBEDTLS_SSL_SESSION_TICKETS MBEDTLS_SSL_SRV_C \
-                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME
-requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED \
-                             MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
-requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED \
-                             MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
 run_test "TLS 1.3 m->m: Session resumption failure, ticket expired. too old" \
          "$P_SRV debug_level=4 crt_file=data_files/server5.crt key_file=data_files/server5.key force_version=tls13 tickets=8 dummy_ticket=4" \
          "$P_CLI debug_level=4 reco_mode=1 reconnect=1" \
@@ -174,11 +160,9 @@
          -S "Ticket age outside tolerance window"
 
 requires_all_configs_enabled MBEDTLS_SSL_PROTO_TLS1_3 MBEDTLS_SSL_SESSION_TICKETS MBEDTLS_SSL_SRV_C \
-                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME
-requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED \
-                             MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
-requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED \
-                             MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
 run_test "TLS 1.3 m->m: Session resumption failure, age outside tolerance window, too young." \
          "$P_SRV debug_level=4 crt_file=data_files/server5.crt key_file=data_files/server5.key force_version=tls13 tickets=8 dummy_ticket=5" \
          "$P_CLI debug_level=4 reco_mode=1 reconnect=1" \
@@ -195,11 +179,9 @@
          -s "Ticket age outside tolerance window"
 
 requires_all_configs_enabled MBEDTLS_SSL_PROTO_TLS1_3 MBEDTLS_SSL_SESSION_TICKETS MBEDTLS_SSL_SRV_C \
-                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME
-requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED \
-                             MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
-requires_any_configs_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED \
-                             MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+                             MBEDTLS_SSL_CLI_C MBEDTLS_DEBUG_C MBEDTLS_HAVE_TIME \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
 run_test "TLS 1.3 m->m: Session resumption failure, age outside tolerance window, too old." \
          "$P_SRV debug_level=4 crt_file=data_files/server5.crt key_file=data_files/server5.key force_version=tls13 tickets=8 dummy_ticket=6" \
          "$P_CLI debug_level=4 reco_mode=1 reconnect=1" \
@@ -282,3 +264,65 @@
             0 \
             -s "key exchange mode: ephemeral$"
 
+# skip the basic check now cause it will randomly trigger the anti-replay protection in gnutls_server
+# Add it back once we fix the issue
+skip_next_test
+requires_gnutls_tls1_3
+requires_config_enabled MBEDTLS_DEBUG_C
+requires_config_enabled MBEDTLS_SSL_CLI_C
+requires_all_configs_enabled MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED \
+                             MBEDTLS_SSL_EARLY_DATA
+requires_any_configs_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED
+run_test    "TLS 1.3 m->G: EarlyData: basic check, good" \
+            "$G_NEXT_SRV -d 10 --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3:+CIPHER-ALL:+ECDHE-PSK:+PSK --earlydata --disable-client-cert" \
+            "$P_CLI debug_level=4 early_data=1 reco_mode=1 reconnect=1 reco_delay=2" \
+            1 \
+            -c "Reconnecting with saved session" \
+            -c "NewSessionTicket: early_data(42) extension received." \
+            -c "ClientHello: early_data(42) extension exists." \
+            -c "EncryptedExtensions: early_data(42) extension received." \
+            -c "EncryptedExtensions: early_data(42) extension exists." \
+            -s "Parsing extension 'Early Data/42' (0 bytes)" \
+            -s "Sending extension Early Data/42 (0 bytes)" \
+            -s "early data accepted"
+
+requires_gnutls_tls1_3
+requires_config_enabled MBEDTLS_DEBUG_C
+requires_config_enabled MBEDTLS_SSL_CLI_C
+requires_all_configs_enabled MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED \
+                             MBEDTLS_SSL_EARLY_DATA
+requires_any_configs_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED
+run_test    "TLS 1.3 m->G: EarlyData: no early_data in NewSessionTicket, good" \
+            "$G_NEXT_SRV -d 10 --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3:+CIPHER-ALL:+ECDHE-PSK:+PSK --disable-client-cert" \
+            "$P_CLI debug_level=4 early_data=1 reco_mode=1 reconnect=1 reco_delay=2" \
+            0 \
+            -c "Reconnecting with saved session" \
+            -C "NewSessionTicket: early_data(42) extension received." \
+            -c "ClientHello: early_data(42) extension does not exist." \
+            -C "EncryptedExtensions: early_data(42) extension received." \
+            -C "EncryptedExtensions: early_data(42) extension exists."
+
+#TODO: OpenSSL tests don't work now. It might be openssl options issue, cause GnuTLS has worked.
+skip_next_test
+requires_openssl_tls1_3
+requires_config_enabled MBEDTLS_DEBUG_C
+requires_config_enabled MBEDTLS_SSL_CLI_C
+requires_all_configs_enabled MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED \
+                             MBEDTLS_SSL_EARLY_DATA
+requires_any_configs_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED \
+                             MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED
+run_test    "TLS 1.3, ext PSK, early data" \
+            "$O_NEXT_SRV_EARLY_DATA -msg -debug -tls1_3 -psk_identity 0a0b0c -psk 010203 -allow_no_dhe_kex -nocert" \
+            "$P_CLI debug_level=5 force_version=tls13 tls13_kex_modes=psk early_data=1 psk=010203 psk_identity=0a0b0c" \
+             1 \
+            -c "Reconnecting with saved session" \
+            -c "NewSessionTicket: early_data(42) extension received." \
+            -c "ClientHello: early_data(42) extension exists." \
+            -c "EncryptedExtensions: early_data(42) extension received." \
+            -c "EncryptedExtensions: early_data(42) extension ( ignored )."
+
diff --git a/tests/scripts/all-in-docker.sh b/tests/scripts/all-in-docker.sh
index 8c9ff47..7c03d91 100755
--- a/tests/scripts/all-in-docker.sh
+++ b/tests/scripts/all-in-docker.sh
@@ -6,6 +6,10 @@
 # -------
 # This runs all.sh (except for armcc) in a Docker container.
 #
+# WARNING: the Dockerfile used by this script is no longer maintained! See
+# https://github.com/Mbed-TLS/mbedtls-test/blob/master/README.md#quick-start
+# for the set of Docker images we use on the CI.
+#
 # Notes for users
 # ---------------
 # See docker_env.sh for prerequisites and other information.
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 9295c9d..18dc8a6 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -185,7 +185,8 @@
     export CTEST_OUTPUT_ON_FAILURE=1
 
     # CFLAGS and LDFLAGS for Asan builds that don't use CMake
-    ASAN_CFLAGS='-Werror -Wall -Wextra -fsanitize=address,undefined -fno-sanitize-recover=all'
+    # default to -O2, use -Ox _after_ this if you want another level
+    ASAN_CFLAGS='-O2 -Werror -fsanitize=address,undefined -fno-sanitize-recover=all'
 
     # Gather the list of available components. These are the functions
     # defined in this script whose name starts with "component_".
@@ -869,14 +870,8 @@
     else
         opt=''
     fi
-    tests/scripts/check_test_cases.py $opt
+    tests/scripts/check_test_cases.py -q $opt
     unset opt
-
-    # Check that no tests are explicitely disabled when USE_PSA_CRYPTO is set
-    # as a matter of policy to ensure there is no missed testing
-    msg "Check: explicitely disabled test with USE_PSA_CRYPTO"  # < 1s
-    not grep -n 'depends_on:.*!MBEDTLS_USE_PSA_CRYPTO' tests/suites/*.function tests/suites/*.data
-    not grep -n '^ *requires_config_disabled.*MBEDTLS_USE_PSA_CRYPTO' tests/ssl-opt.sh tests/opt-testcases/*.sh
 }
 
 component_check_doxygen_warnings () {
@@ -1217,6 +1212,7 @@
     # Direct dependencies
     scripts/config.py unset MBEDTLS_HKDF_C
     scripts/config.py unset MBEDTLS_HMAC_DRBG_C
+    scripts/config.py unset MBEDTLS_PKCS7_C
     # Indirect dependencies
     scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC
     make
@@ -1245,6 +1241,7 @@
     scripts/config.py unset MBEDTLS_PSA_CRYPTO_STORAGE_C
     scripts/config.py unset MBEDTLS_SSL_DTLS_ANTI_REPLAY
     scripts/config.py unset MBEDTLS_SSL_DTLS_CONNECTION_ID
+    scripts/config.py unset MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT
     scripts/config.py unset MBEDTLS_SSL_PROTO_TLS1_3
     scripts/config.py unset MBEDTLS_SSL_SRV_C
     scripts/config.py unset MBEDTLS_USE_PSA_CRYPTO
@@ -1437,6 +1434,35 @@
     tests/ssl-opt.sh -f "TLS 1.2"
 }
 
+# We're not aware of any other (open source) implementation of EC J-PAKE in TLS
+# that we could use for interop testing. However, we now have sort of two
+# implementations ourselves: one using PSA, the other not. At least test that
+# these two interoperate with each other.
+component_test_tls1_2_ecjpake_compatibility() {
+    msg "build: TLS1.2 server+client w/ EC-JPAKE w/o USE_PSA"
+    scripts/config.py set MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED
+    make -C programs ssl/ssl_server2 ssl/ssl_client2
+    cp programs/ssl/ssl_server2 s2_no_use_psa
+    cp programs/ssl/ssl_client2 c2_no_use_psa
+
+    msg "build: TLS1.2 server+client w/ EC-JPAKE w/ USE_PSA"
+    scripts/config.py set MBEDTLS_USE_PSA_CRYPTO
+    make clean
+    make -C programs ssl/ssl_server2 ssl/ssl_client2
+    make -C programs test/udp_proxy test/query_compile_time_config
+
+    msg "test: server w/o USE_PSA - client w/ USE_PSA, text password"
+    P_SRV=../s2_no_use_psa tests/ssl-opt.sh -f "ECJPAKE: working, TLS"
+    msg "test: server w/o USE_PSA - client w/ USE_PSA, opaque password"
+    P_SRV=../s2_no_use_psa tests/ssl-opt.sh -f "ECJPAKE: opaque password client only, working, TLS"
+    msg "test: client w/o USE_PSA - server w/ USE_PSA, text password"
+    P_CLI=../c2_no_use_psa tests/ssl-opt.sh -f "ECJPAKE: working, TLS"
+    msg "test: client w/o USE_PSA - server w/ USE_PSA, opaque password"
+    P_CLI=../c2_no_use_psa tests/ssl-opt.sh -f "ECJPAKE: opaque password server only, working, TLS"
+
+    rm s2_no_use_psa c2_no_use_psa
+}
+
 component_test_psa_external_rng_use_psa_crypto () {
     msg "build: full + PSA_CRYPTO_EXTERNAL_RNG + USE_PSA_CRYPTO minus CTR_DRBG"
     scripts/config.py full
@@ -1564,6 +1590,17 @@
     env OPENSSL_CMD="$OPENSSL_NEXT" tests/compat.sh -e '^$' -f 'ARIA\|CHACHA'
 }
 
+skip_suites_without_constant_flow () {
+    # Skip the test suites that don't have any constant-flow annotations.
+    # This will need to be adjusted if we ever start declaring things as
+    # secret from macros or functions inside tests/include or tests/src.
+    SKIP_TEST_SUITES=$(
+        git -C tests/suites grep -L TEST_CF_ 'test_suite_*.function' |
+            sed 's/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:
@@ -1615,12 +1652,13 @@
     scripts/config.py full
     scripts/config.py set MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND
     scripts/config.py unset MBEDTLS_USE_PSA_CRYPTO
+    skip_suites_without_constant_flow
     cmake -D CMAKE_BUILD_TYPE:String=Release .
     make
 
     # this only shows a summary of the results (how many of each type)
     # details are left in Testing/<date>/DynamicAnalysis.xml
-    msg "test: main suites (full minus MBEDTLS_USE_PSA_CRYPTO, valgrind + constant flow)"
+    msg "test: some suites (full minus MBEDTLS_USE_PSA_CRYPTO, valgrind + constant flow)"
     make memcheck
 }
 
@@ -1637,12 +1675,13 @@
     msg "build: cmake release GCC, full config with constant flow testing"
     scripts/config.py full
     scripts/config.py set MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND
+    skip_suites_without_constant_flow
     cmake -D CMAKE_BUILD_TYPE:String=Release .
     make
 
     # this only shows a summary of the results (how many of each type)
     # details are left in Testing/<date>/DynamicAnalysis.xml
-    msg "test: main suites (valgrind + constant flow)"
+    msg "test: some suites (valgrind + constant flow)"
     make memcheck
 }
 
@@ -1848,10 +1887,13 @@
 component_build_module_alt () {
     msg "build: MBEDTLS_XXX_ALT" # ~30s
     scripts/config.py full
-    # Disable options that are incompatible with some ALT implementations.
+
+    # Disable options that are incompatible with some ALT implementations:
     # aesni.c and padlock.c reference mbedtls_aes_context fields directly.
     scripts/config.py unset MBEDTLS_AESNI_C
     scripts/config.py unset MBEDTLS_PADLOCK_C
+    # MBEDTLS_ECP_RESTARTABLE is documented as incompatible.
+    scripts/config.py unset MBEDTLS_ECP_RESTARTABLE
     # You can only have one threading implementation: alt or pthread, not both.
     scripts/config.py unset MBEDTLS_THREADING_PTHREAD
     # The SpecifiedECDomain parsing code accesses mbedtls_ecp_group fields
@@ -1863,10 +1905,12 @@
     # MBEDTLS_SHA512_*ALT can't be used with MBEDTLS_SHA512_USE_A64_CRYPTO_*
     scripts/config.py unset MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT
     scripts/config.py unset MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY
+
     # Enable all MBEDTLS_XXX_ALT for whole modules. Do not enable
     # MBEDTLS_XXX_YYY_ALT which are for single functions.
     scripts/config.py set-all 'MBEDTLS_([A-Z0-9]*|NIST_KW)_ALT'
     scripts/config.py unset MBEDTLS_DHM_ALT #incompatible with MBEDTLS_DEBUG_C
+
     # We can only compile, not link, since we don't have any implementations
     # suitable for testing with the dummy alt headers.
     make CC=gcc CFLAGS='-Werror -Wall -Wextra -I../tests/include/alt-dummy' lib
@@ -1887,7 +1931,6 @@
     # full minus MBEDTLS_USE_PSA_CRYPTO: run the same set of tests as basic-build-test.sh
     msg "build: cmake, full config minus MBEDTLS_USE_PSA_CRYPTO, ASan"
     scripts/config.py full
-    scripts/config.py set MBEDTLS_ECP_RESTARTABLE  # not using PSA, so enable restartable ECC
     scripts/config.py unset MBEDTLS_PSA_CRYPTO_C
     scripts/config.py unset MBEDTLS_USE_PSA_CRYPTO
     scripts/config.py unset MBEDTLS_SSL_PROTO_TLS1_3
@@ -1902,6 +1945,9 @@
     msg "test: main suites (full minus MBEDTLS_USE_PSA_CRYPTO)"
     make test
 
+    # Note: ssl-opt.sh has some test cases that depend on
+    # MBEDTLS_ECP_RESTARTABLE && !MBEDTLS_USE_PSA_CRYPTO
+    # This is the only component where those tests are not skipped.
     msg "test: ssl-opt.sh (full minus MBEDTLS_USE_PSA_CRYPTO)"
     tests/ssl-opt.sh
 
@@ -1952,6 +1998,38 @@
     make test
 }
 
+component_test_psa_crypto_config_accel_ecdh () {
+    msg "test: MBEDTLS_PSA_CRYPTO_CONFIG with accelerated ECDH"
+
+    # Disable ALG_STREAM_CIPHER and ALG_ECB_NO_PADDING to avoid having
+    # partial support for cipher operations in the driver test library.
+    scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_STREAM_CIPHER
+    scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_ECB_NO_PADDING
+
+    loc_accel_list="ALG_ECDH KEY_TYPE_ECC_KEY_PAIR KEY_TYPE_ECC_PUBLIC_KEY"
+    loc_accel_flags=$( echo "$loc_accel_list" | sed 's/[^ ]* */-DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_&/g' )
+    make -C tests libtestdriver1.a CFLAGS=" $ASAN_CFLAGS $loc_accel_flags" LDFLAGS="$ASAN_CFLAGS"
+
+    scripts/config.py set MBEDTLS_PSA_CRYPTO_DRIVERS
+    scripts/config.py set MBEDTLS_PSA_CRYPTO_CONFIG
+    scripts/config.py unset MBEDTLS_USE_PSA_CRYPTO
+    scripts/config.py unset MBEDTLS_SSL_PROTO_TLS1_3
+    scripts/config.py unset MBEDTLS_ECDH_C
+    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED
+    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED
+    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
+    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED
+    scripts/config.py unset MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
+
+    loc_accel_flags="$loc_accel_flags $( echo "$loc_accel_list" | sed 's/[^ ]* */-DMBEDTLS_PSA_ACCEL_&/g' )"
+    make CFLAGS="$ASAN_CFLAGS -O -Werror -I../tests/include -I../tests -I../../tests -DPSA_CRYPTO_DRIVER_TEST -DMBEDTLS_TEST_LIBTESTDRIVER1 $loc_accel_flags" LDFLAGS="-ltestdriver1 $ASAN_CFLAGS"
+
+    not grep mbedtls_ecdh_ library/ecdh.o
+
+    msg "test: MBEDTLS_PSA_CRYPTO_CONFIG with accelerated ECDH"
+    make test
+}
+
 component_test_psa_crypto_config_accel_rsa_signature () {
     msg "test: MBEDTLS_PSA_CRYPTO_CONFIG with accelerated RSA signature"
 
@@ -2065,6 +2143,48 @@
     make test
 }
 
+# Auxiliary function to build config for hashes with and without drivers
+config_psa_crypto_hash_use_psa () {
+    DRIVER_ONLY="$1"
+    # start with config full for maximum coverage (also enables USE_PSA)
+    scripts/config.py full
+    # enable support for drivers and configuring PSA-only algorithms
+    scripts/config.py set MBEDTLS_PSA_CRYPTO_CONFIG
+    scripts/config.py set MBEDTLS_PSA_CRYPTO_DRIVERS
+    if [ "$DRIVER_ONLY" -eq 1 ]; then
+        # disable the built-in implementation of hashes
+        scripts/config.py unset MBEDTLS_MD5_C
+        scripts/config.py unset MBEDTLS_RIPEMD160_C
+        scripts/config.py unset MBEDTLS_SHA1_C
+        scripts/config.py unset MBEDTLS_SHA224_C
+        scripts/config.py unset MBEDTLS_SHA256_C # see external RNG below
+        scripts/config.py unset MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT
+        scripts/config.py unset MBEDTLS_SHA384_C
+        scripts/config.py unset MBEDTLS_SHA512_C
+        scripts/config.py unset MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT
+    fi
+    # Use an external RNG as currently internal RNGs depend on entropy.c
+    # which in turn hard-depends on SHA256_C (or SHA512_C).
+    # See component_test_psa_external_rng_no_drbg_use_psa.
+    scripts/config.py set MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+    scripts/config.py unset MBEDTLS_ENTROPY_C
+    scripts/config.py unset MBEDTLS_ENTROPY_NV_SEED # depends on ENTROPY_C
+    scripts/config.py unset MBEDTLS_PLATFORM_NV_SEED_ALT # depends on former
+    # Also unset MD_C and things that depend on it;
+    # see component_test_crypto_full_no_md.
+    if [ "$DRIVER_ONLY" -eq 1 ]; then
+        scripts/config.py unset MBEDTLS_MD_C
+    fi
+    scripts/config.py unset MBEDTLS_HKDF_C # has independent PSA implementation
+    scripts/config.py unset MBEDTLS_HMAC_DRBG_C
+    scripts/config.py unset MBEDTLS_PKCS7_C
+    scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC
+    scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_DETERMINISTIC_ECDSA
+}
+
+# Note that component_test_psa_crypto_config_reference_hash_use_psa
+# is related to this component and both components need to be kept in sync.
+# For details please see comments for component_test_psa_crypto_config_reference_hash_use_psa.
 component_test_psa_crypto_config_accel_hash_use_psa () {
     msg "test: MBEDTLS_PSA_CRYPTO_CONFIG with accelerated hash and USE_PSA"
 
@@ -2077,35 +2197,7 @@
     loc_accel_flags=$( echo "$loc_accel_list" | sed 's/[^ ]* */-DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_&/g' )
     make -C tests libtestdriver1.a CFLAGS="$ASAN_CFLAGS $loc_accel_flags" LDFLAGS="$ASAN_CFLAGS"
 
-    # start with config full for maximum coverage (also enables USE_PSA)
-    scripts/config.py full
-    # enable support for drivers and configuring PSA-only algorithms
-    scripts/config.py set MBEDTLS_PSA_CRYPTO_DRIVERS
-    scripts/config.py set MBEDTLS_PSA_CRYPTO_CONFIG
-    # disable the built-in implementation of hashes
-    scripts/config.py unset MBEDTLS_MD5_C
-    scripts/config.py unset MBEDTLS_RIPEMD160_C
-    scripts/config.py unset MBEDTLS_SHA1_C
-    scripts/config.py unset MBEDTLS_SHA224_C
-    scripts/config.py unset MBEDTLS_SHA256_C # see external RNG below
-    scripts/config.py unset MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT
-    scripts/config.py unset MBEDTLS_SHA384_C
-    scripts/config.py unset MBEDTLS_SHA512_C
-    scripts/config.py unset MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT
-    # Use an external RNG as currently internal RNGs depend on entropy.c
-    # which in turn hard-depends on SHA256_C (or SHA512_C).
-    # See component_test_psa_external_rng_no_drbg_use_psa.
-    scripts/config.py set MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
-    scripts/config.py unset MBEDTLS_ENTROPY_C
-    scripts/config.py unset MBEDTLS_ENTROPY_NV_SEED # depends on ENTROPY_C
-    scripts/config.py unset MBEDTLS_PLATFORM_NV_SEED_ALT # depends on former
-    # Also unset MD_C and things that depend on it;
-    # see component_test_crypto_full_no_md.
-    scripts/config.py unset MBEDTLS_MD_C
-    scripts/config.py unset MBEDTLS_HKDF_C # has independent PSA implementation
-    scripts/config.py unset MBEDTLS_HMAC_DRBG_C
-    scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC
-    scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_DETERMINISTIC_ECDSA
+    config_psa_crypto_hash_use_psa 1
 
     loc_accel_flags="$loc_accel_flags $( echo "$loc_accel_list" | sed 's/[^ ]* */-DMBEDTLS_PSA_ACCEL_&/g' )"
     make CFLAGS="$ASAN_CFLAGS -Werror -I../tests/include -I../tests -I../../tests -DPSA_CRYPTO_DRIVER_TEST -DMBEDTLS_TEST_LIBTESTDRIVER1 $loc_accel_flags" LDFLAGS="-ltestdriver1 $ASAN_CFLAGS" all
@@ -2122,16 +2214,37 @@
     msg "test: MBEDTLS_PSA_CRYPTO_CONFIG with accelerated hash and USE_PSA"
     make test
 
-    # hidden option: when running outcome-analysis.sh, we can skip this
-    if [ "${SKIP_SSL_OPT_COMPAT_SH-unset}" = "unset" ]; then
-        msg "test: ssl-opt.sh, MBEDTLS_PSA_CRYPTO_CONFIG with accelerated hash and USE_PSA"
-        tests/ssl-opt.sh
+    # This is mostly useful so that we can later compare outcome files with
+    # the reference config in analyze_outcomes.py, to check that the
+    # dependency declarations in ssl-opt.sh and in TLS code are correct.
+    msg "test: ssl-opt.sh, MBEDTLS_PSA_CRYPTO_CONFIG with accelerated hash and USE_PSA"
+    tests/ssl-opt.sh
 
-        msg "test: compat.sh, MBEDTLS_PSA_CRYPTO_CONFIG with accelerated hash and USE_PSA"
-        tests/compat.sh
-    else
-        echo "skip ssl-opt.sh and compat.sh"
-    fi
+    # This is to make sure all ciphersuites are exercised, but we don't need
+    # interop testing (besides, we already got some from ssl-opt.sh).
+    msg "test: compat.sh, MBEDTLS_PSA_CRYPTO_CONFIG with accelerated hash and USE_PSA"
+    tests/compat.sh -p mbedTLS -V YES
+}
+
+# This component provides reference configuration for test_psa_crypto_config_accel_hash_use_psa
+# without accelerated hash. The outcome from both components are used by the analyze_outcomes.py
+# script to find regression in test coverage when accelerated hash is used (tests and ssl-opt).
+# Both components need to be kept in sync.
+component_test_psa_crypto_config_reference_hash_use_psa() {
+    msg "test: MBEDTLS_PSA_CRYPTO_CONFIG without accelerated hash and USE_PSA"
+
+    scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_STREAM_CIPHER
+    scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_ECB_NO_PADDING
+
+    config_psa_crypto_hash_use_psa 0
+
+    make
+
+    msg "test: MBEDTLS_PSA_CRYPTO_CONFIG without accelerated hash and USE_PSA"
+    make test
+
+    msg "test: ssl-opt.sh, MBEDTLS_PSA_CRYPTO_CONFIG without accelerated hash and USE_PSA"
+    tests/ssl-opt.sh
 }
 
 component_test_psa_crypto_config_accel_cipher () {
@@ -2709,21 +2822,20 @@
     tests/compat.sh
 }
 
-component_test_variable_ssl_in_out_buffer_len_CID () {
-    msg "build: MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH and MBEDTLS_SSL_DTLS_CONNECTION_ID enabled (ASan build)"
-    scripts/config.py set MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH
-    scripts/config.py set MBEDTLS_SSL_DTLS_CONNECTION_ID
+component_test_dtls_cid_legacy () {
+    msg "build: MBEDTLS_SSL_DTLS_CONNECTION_ID (legacy) enabled (ASan build)"
+    scripts/config.py set MBEDTLS_SSL_DTLS_CONNECTION_ID_COMPAT 1
 
     CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
     make
 
-    msg "test: MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH and MBEDTLS_SSL_DTLS_CONNECTION_ID"
+    msg "test: MBEDTLS_SSL_DTLS_CONNECTION_ID (legacy)"
     make test
 
-    msg "test: ssl-opt.sh, MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH and MBEDTLS_SSL_DTLS_CONNECTION_ID enabled"
+    msg "test: ssl-opt.sh, MBEDTLS_SSL_DTLS_CONNECTION_ID (legacy) enabled"
     tests/ssl-opt.sh
 
-    msg "test: compat.sh, MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH and MBEDTLS_SSL_DTLS_CONNECTION_ID enabled"
+    msg "test: compat.sh, MBEDTLS_SSL_DTLS_CONNECTION_ID (legacy) enabled"
     tests/compat.sh
 }
 
@@ -3221,6 +3333,7 @@
 
 component_test_tls13_only () {
     msg "build: default config with MBEDTLS_SSL_PROTO_TLS1_3, without MBEDTLS_SSL_PROTO_TLS1_2"
+    scripts/config.py set MBEDTLS_SSL_EARLY_DATA
     make CFLAGS="'-DMBEDTLS_USER_CONFIG_FILE=\"../tests/configs/tls13-only.h\"'"
 
     msg "test: TLS 1.3 only, all key exchange modes enabled"
@@ -3240,6 +3353,8 @@
     scripts/config.py unset MBEDTLS_SSL_SERVER_NAME_INDICATION
     scripts/config.py unset MBEDTLS_ECDSA_C
     scripts/config.py unset MBEDTLS_PKCS1_V21
+    scripts/config.py unset MBEDTLS_PKCS7_C
+    scripts/config.py set   MBEDTLS_SSL_EARLY_DATA
     make CFLAGS="'-DMBEDTLS_USER_CONFIG_FILE=\"../tests/configs/tls13-only.h\"'"
 
     msg "test_suite_ssl: TLS 1.3 only, only PSK key exchange mode enabled"
@@ -3253,6 +3368,7 @@
     msg "build: TLS 1.3 only from default, only ephemeral key exchange mode"
     scripts/config.py unset MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED
     scripts/config.py unset MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
+    scripts/config.py unset MBEDTLS_SSL_EARLY_DATA
     make CFLAGS="'-DMBEDTLS_USER_CONFIG_FILE=\"../tests/configs/tls13-only.h\"'"
 
     msg "test_suite_ssl: TLS 1.3 only, only ephemeral key exchange mode"
@@ -3271,6 +3387,8 @@
     scripts/config.py unset MBEDTLS_SSL_SERVER_NAME_INDICATION
     scripts/config.py unset MBEDTLS_ECDSA_C
     scripts/config.py unset MBEDTLS_PKCS1_V21
+    scripts/config.py unset MBEDTLS_PKCS7_C
+    scripts/config.py set   MBEDTLS_SSL_EARLY_DATA
     make CFLAGS="'-DMBEDTLS_USER_CONFIG_FILE=\"../tests/configs/tls13-only.h\"'"
 
     msg "test_suite_ssl: TLS 1.3 only, only PSK ephemeral key exchange mode"
@@ -3288,6 +3406,8 @@
     scripts/config.py unset MBEDTLS_SSL_SERVER_NAME_INDICATION
     scripts/config.py unset MBEDTLS_ECDSA_C
     scripts/config.py unset MBEDTLS_PKCS1_V21
+    scripts/config.py unset MBEDTLS_PKCS7_C
+    scripts/config.py set   MBEDTLS_SSL_EARLY_DATA
     make CFLAGS="'-DMBEDTLS_USER_CONFIG_FILE=\"../tests/configs/tls13-only.h\"'"
 
     msg "test_suite_ssl: TLS 1.3 only, PSK and PSK ephemeral key exchange modes"
@@ -3300,6 +3420,7 @@
 component_test_tls13_only_ephemeral_all () {
     msg "build: TLS 1.3 only from default, without PSK key exchange mode"
     scripts/config.py unset MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED
+    scripts/config.py set   MBEDTLS_SSL_EARLY_DATA
     make CFLAGS="'-DMBEDTLS_USER_CONFIG_FILE=\"../tests/configs/tls13-only.h\"'"
 
     msg "test_suite_ssl: TLS 1.3 only, ephemeral and PSK ephemeral key exchange modes"
@@ -3314,6 +3435,7 @@
     scripts/config.py set MBEDTLS_SSL_PROTO_TLS1_3
     scripts/config.py set MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE
     scripts/config.py set MBEDTLS_SSL_CID_TLS1_3_PADDING_GRANULARITY 1
+    scripts/config.py set MBEDTLS_SSL_EARLY_DATA
     CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
     make
     msg "test: default config with MBEDTLS_SSL_PROTO_TLS1_3 enabled, without padding"
@@ -3327,6 +3449,7 @@
     scripts/config.py set   MBEDTLS_SSL_PROTO_TLS1_3
     scripts/config.py unset MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE
     scripts/config.py set   MBEDTLS_SSL_CID_TLS1_3_PADDING_GRANULARITY 1
+    scripts/config.py set   MBEDTLS_SSL_EARLY_DATA
     CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
     make
     msg "test: default config with MBEDTLS_SSL_PROTO_TLS1_3 enabled, without padding"
@@ -3377,30 +3500,43 @@
 
 component_test_valgrind () {
     msg "build: Release (clang)"
+    # default config, in particular without MBEDTLS_USE_PSA_CRYPTO
     CC=clang cmake -D CMAKE_BUILD_TYPE:String=Release .
     make
 
-    msg "test: main suites valgrind (Release)"
+    msg "test: main suites, Valgrind (default config)"
     make memcheck
 
     # Optional parts (slow; currently broken on OS X because programs don't
     # seem to receive signals under valgrind on OS X).
+    # These optional parts don't run on the CI.
     if [ "$MEMORY" -gt 0 ]; then
-        msg "test: ssl-opt.sh --memcheck (Release)"
+        msg "test: ssl-opt.sh --memcheck (default config)"
         tests/ssl-opt.sh --memcheck
     fi
 
     if [ "$MEMORY" -gt 1 ]; then
-        msg "test: compat.sh --memcheck (Release)"
+        msg "test: compat.sh --memcheck (default config)"
         tests/compat.sh --memcheck
     fi
 
     if [ "$MEMORY" -gt 0 ]; then
-        msg "test: context-info.sh --memcheck (Release)"
+        msg "test: context-info.sh --memcheck (default config)"
         tests/context-info.sh --memcheck
     fi
 }
 
+component_test_valgrind_psa () {
+    msg "build: Release, full (clang)"
+    # full config, in particular with MBEDTLS_USE_PSA_CRYPTO
+    scripts/config.py full
+    CC=clang cmake -D CMAKE_BUILD_TYPE:String=Release .
+    make
+
+    msg "test: main suites, Valgrind (full config)"
+    make memcheck
+}
+
 support_test_cmake_out_of_source () {
     distrib_id=""
     distrib_ver=""
@@ -3537,6 +3673,26 @@
     [ "$ver_major" -eq 3 ] && [ "$ver_minor" -ge 10 ]
 }
 
+component_test_corrected_code_style () {
+    ./scripts/code_style.py --fix
+
+    msg "build: make, default config (out-of-box), corrected code style"
+    make
+
+    msg "test: main suites make, default config (out-of-box), corrected code style"
+    make test
+
+    # Clean up code-style corrections
+    git checkout -- .
+}
+
+support_test_corrected_code_style() {
+    case $(uncrustify --version) in
+        *0.75.1*) true;;
+        *) false;;
+    esac
+}
+
 component_check_python_files () {
     msg "Lint: Python scripts"
     tests/scripts/check-python-files.sh
diff --git a/tests/scripts/analyze_outcomes.py b/tests/scripts/analyze_outcomes.py
index d06a059..bb44396 100755
--- a/tests/scripts/analyze_outcomes.py
+++ b/tests/scripts/analyze_outcomes.py
@@ -9,6 +9,7 @@
 import argparse
 import sys
 import traceback
+import re
 
 import check_test_cases
 
@@ -60,6 +61,37 @@
             # fixed this branch to have full coverage of test cases.
             results.warning('Test case not executed: {}', key)
 
+def analyze_driver_vs_reference(outcomes, component_ref, component_driver, ignored_tests):
+    """Check that all tests executed in the reference component are also
+    executed in the corresponding driver component.
+    Skip test suites provided in ignored_tests list.
+    """
+    available = check_test_cases.collect_available_test_cases()
+    result = True
+
+    for key in available:
+        # Skip ignored test suites
+        test_suite = key.split(';')[0] # retrieve test suit name
+        test_suite = test_suite.split('.')[0] # retrieve main part of test suit name
+        if test_suite in ignored_tests:
+            continue
+        # Continue if test was not executed by any component
+        hits = outcomes[key].hits() if key in outcomes else 0
+        if hits == 0:
+            continue
+        # Search for tests that run in reference component and not in driver component
+        driver_test_passed = False
+        reference_test_passed = False
+        for entry in outcomes[key].successes:
+            if component_driver in entry:
+                driver_test_passed = True
+            if component_ref in entry:
+                reference_test_passed = True
+        if(driver_test_passed is False and reference_test_passed is True):
+            print('{}: driver: skipped/failed; reference: passed'.format(key))
+            result = False
+    return result
+
 def analyze_outcomes(outcomes):
     """Run all analyses on the given outcome collection."""
     results = Results()
@@ -87,20 +119,75 @@
                 outcomes[key].failures.append(setup)
     return outcomes
 
-def analyze_outcome_file(outcome_file):
-    """Analyze the given outcome file."""
+def do_analyze_coverage(outcome_file, args):
+    """Perform coverage analysis."""
+    del args # unused
     outcomes = read_outcome_file(outcome_file)
-    return analyze_outcomes(outcomes)
+    results = analyze_outcomes(outcomes)
+    return results.error_count == 0
+
+def do_analyze_driver_vs_reference(outcome_file, args):
+    """Perform driver vs reference analyze."""
+    ignored_tests = ['test_suite_' + x for x in args['ignored_suites']]
+
+    outcomes = read_outcome_file(outcome_file)
+    return analyze_driver_vs_reference(outcomes, args['component_ref'],
+                                       args['component_driver'], ignored_tests)
+
+# List of tasks with a function that can handle this task and additional arguments if required
+TASKS = {
+    'analyze_coverage':                 {
+        'test_function': do_analyze_coverage,
+        'args': {}},
+    'analyze_driver_vs_reference_hash': {
+        'test_function': do_analyze_driver_vs_reference,
+        'args': {
+            'component_ref': 'test_psa_crypto_config_reference_hash_use_psa',
+            'component_driver': 'test_psa_crypto_config_accel_hash_use_psa',
+            'ignored_suites': ['shax', 'mdx', # the software implementations that are being excluded
+                               'md',  # the legacy abstraction layer that's being excluded
+                              ]}}
+}
 
 def main():
     try:
         parser = argparse.ArgumentParser(description=__doc__)
         parser.add_argument('outcomes', metavar='OUTCOMES.CSV',
                             help='Outcome file to analyze')
+        parser.add_argument('task', default='all', nargs='?',
+                            help='Analysis to be done. By default, run all tasks. '
+                                 'With one or more TASK, run only those. '
+                                 'TASK can be the name of a single task or '
+                                 'comma/space-separated list of tasks. ')
+        parser.add_argument('--list', action='store_true',
+                            help='List all available tasks and exit.')
         options = parser.parse_args()
-        results = analyze_outcome_file(options.outcomes)
-        if results.error_count > 0:
+
+        if options.list:
+            for task in TASKS:
+                print(task)
+            sys.exit(0)
+
+        result = True
+
+        if options.task == 'all':
+            tasks = TASKS.keys()
+        else:
+            tasks = re.split(r'[, ]+', options.task)
+
+            for task in tasks:
+                if task not in TASKS:
+                    print('Error: invalid task: {}'.format(task))
+                    sys.exit(1)
+
+        for task in TASKS:
+            if task in tasks:
+                if not TASKS[task]['test_function'](options.outcomes, TASKS[task]['args']):
+                    result = False
+
+        if result is False:
             sys.exit(1)
+        print("SUCCESS :-)")
     except Exception: # pylint: disable=broad-except
         # Print the backtrace and exit explicitly with our chosen status.
         traceback.print_exc()
diff --git a/tests/scripts/basic-build-test.sh b/tests/scripts/basic-build-test.sh
index 31beb1c..3dc8a73 100755
--- a/tests/scripts/basic-build-test.sh
+++ b/tests/scripts/basic-build-test.sh
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-# basic-build-tests.sh
+# basic-build-test.sh
 #
 # Copyright The Mbed TLS Contributors
 # SPDX-License-Identifier: Apache-2.0
@@ -36,7 +36,7 @@
 #
 # This script has been written to be generic and should work on any shell.
 #
-# Usage: basic-build-tests.sh
+# Usage: basic-build-test.sh
 #
 
 # Abort on errors (and uninitiliased variables)
@@ -243,35 +243,16 @@
     echo
 
 
-    # Step 4e - Coverage
-    echo "Coverage"
-
-    LINES_TESTED=$(tail -n4 cov-$TEST_OUTPUT|sed -n -e 's/  lines......: [0-9]*.[0-9]% (\([0-9]*\) of [0-9]* lines)/\1/p')
-    LINES_TOTAL=$(tail -n4 cov-$TEST_OUTPUT|sed -n -e 's/  lines......: [0-9]*.[0-9]% ([0-9]* of \([0-9]*\) lines)/\1/p')
-    FUNCS_TESTED=$(tail -n4 cov-$TEST_OUTPUT|sed -n -e 's/  functions..: [0-9]*.[0-9]% (\([0-9]*\) of [0-9]* functions)$/\1/p')
-    FUNCS_TOTAL=$(tail -n4 cov-$TEST_OUTPUT|sed -n -e 's/  functions..: [0-9]*.[0-9]% ([0-9]* of \([0-9]*\) functions)$/\1/p')
-    BRANCHES_TESTED=$(tail -n4 cov-$TEST_OUTPUT|sed -n -e 's/  branches...: [0-9]*.[0-9]% (\([0-9]*\) of [0-9]* branches)$/\1/p')
-    BRANCHES_TOTAL=$(tail -n4 cov-$TEST_OUTPUT|sed -n -e 's/  branches...: [0-9]*.[0-9]% ([0-9]* of \([0-9]*\) branches)$/\1/p')
-
-    LINES_PERCENT=$((1000*$LINES_TESTED/$LINES_TOTAL))
-    LINES_PERCENT="$(($LINES_PERCENT/10)).$(($LINES_PERCENT-($LINES_PERCENT/10)*10))"
-
-    FUNCS_PERCENT=$((1000*$FUNCS_TESTED/$FUNCS_TOTAL))
-    FUNCS_PERCENT="$(($FUNCS_PERCENT/10)).$(($FUNCS_PERCENT-($FUNCS_PERCENT/10)*10))"
-
-    BRANCHES_PERCENT=$((1000*$BRANCHES_TESTED/$BRANCHES_TOTAL))
-    BRANCHES_PERCENT="$(($BRANCHES_PERCENT/10)).$(($BRANCHES_PERCENT-($BRANCHES_PERCENT/10)*10))"
+    # Step 4e - Coverage report
+    echo "Coverage statistics:"
+    sed -n '1,/^Overall coverage/d; /%/p' cov-$TEST_OUTPUT
+    echo
 
     rm unit-test-$TEST_OUTPUT
     rm sys-test-$TEST_OUTPUT
     rm compat-test-$TEST_OUTPUT
     rm cov-$TEST_OUTPUT
 
-    echo "Lines Tested       : $LINES_TESTED of $LINES_TOTAL $LINES_PERCENT%"
-    echo "Functions Tested   : $FUNCS_TESTED of $FUNCS_TOTAL $FUNCS_PERCENT%"
-    echo "Branches Tested    : $BRANCHES_TESTED of $BRANCHES_TOTAL $BRANCHES_PERCENT%"
-    echo
-
     # Mark the report generation as having succeeded. This must be the
     # last thing in the report generation.
     touch "basic-build-test-$$.ok"
diff --git a/tests/scripts/basic-in-docker.sh b/tests/scripts/basic-in-docker.sh
index 1f65710..02cafb0 100755
--- a/tests/scripts/basic-in-docker.sh
+++ b/tests/scripts/basic-in-docker.sh
@@ -9,6 +9,10 @@
 # in the default configuration, partial test runs in the reference
 # configurations, and some dependency tests.
 #
+# WARNING: the Dockerfile used by this script is no longer maintained! See
+# https://github.com/Mbed-TLS/mbedtls-test/blob/master/README.md#quick-start
+# for the set of Docker images we use on the CI.
+#
 # Notes for users
 # ---------------
 # See docker_env.sh for prerequisites and other information.
diff --git a/tests/scripts/check-generated-files.sh b/tests/scripts/check-generated-files.sh
index 3006ec7..946794c 100755
--- a/tests/scripts/check-generated-files.sh
+++ b/tests/scripts/check-generated-files.sh
@@ -116,6 +116,16 @@
     fi
 }
 
+# Note: if the format of calls to the "check" function changes, update
+# scripts/code_style.py accordingly. For generated C source files (*.h or *.c),
+# the format must be "check SCRIPT FILENAME...". For other source files,
+# any shell syntax is permitted (including e.g. command substitution).
+
+# Note: Instructions to generate those files are replicated in:
+#   - **/Makefile (to (re)build them with make)
+#   - **/CMakeLists.txt (to (re)build them with cmake)
+#   - scripts/make_generated_files.bat (to generate them under Windows)
+
 check scripts/generate_errors.pl library/error.c
 check scripts/generate_query_config.pl programs/test/query_config.c
 check scripts/generate_driver_wrappers.py library/psa_crypto_driver_wrappers.c
diff --git a/tests/scripts/check_files.py b/tests/scripts/check_files.py
index 5c18702..42f2e82 100755
--- a/tests/scripts/check_files.py
+++ b/tests/scripts/check_files.py
@@ -122,6 +122,7 @@
     r'tests/data_files/.*\.req\.[^/]+\Z',
     r'tests/data_files/.*malformed[^/]+\Z',
     r'tests/data_files/format_pkcs12\.fmt\Z',
+    r'tests/data_files/pkcs7_data.*\.bin\Z',
 ]
 BINARY_FILE_PATH_RE = re.compile('|'.join(BINARY_FILE_PATH_RE_LIST))
 
diff --git a/tests/scripts/check_names.py b/tests/scripts/check_names.py
index 396ab74..7398f3c 100755
--- a/tests/scripts/check_names.py
+++ b/tests/scripts/check_names.py
@@ -36,7 +36,7 @@
   declared in the header files. This uses the nm command.
 - All macros, constants, and identifiers (function names, struct names, etc)
   follow the required regex pattern.
-- Typo checking: All words that begin with MBED exist as macros or constants.
+- Typo checking: All words that begin with MBED|PSA exist as macros or constants.
 
 The script returns 0 on success, 1 on test failure, and 2 if there is a script
 error. It must be run from Mbed TLS root.
@@ -191,11 +191,12 @@
 
 class Typo(Problem): # pylint: disable=too-few-public-methods
     """
-    A problem that occurs when a word using MBED doesn't appear to be defined as
-    constants nor enum values. Created with NameCheck.check_for_typos()
+    A problem that occurs when a word using MBED or PSA doesn't
+    appear to be defined as constants nor enum values. Created with
+    NameCheck.check_for_typos()
 
     Fields:
-    * match: the Match object of the MBED name in question.
+    * match: the Match object of the MBED|PSA name in question.
     """
     def __init__(self, match):
         self.match = match
@@ -245,7 +246,7 @@
             .format(str(self.excluded_files))
         )
 
-        all_macros = {"public": [], "internal": []}
+        all_macros = {"public": [], "internal": [], "private":[]}
         all_macros["public"] = self.parse_macros([
             "include/mbedtls/*.h",
             "include/psa/*.h",
@@ -256,9 +257,14 @@
             "library/*.h",
             "tests/include/test/drivers/*.h",
         ])
+        all_macros["private"] = self.parse_macros([
+            "library/*.c",
+        ])
         enum_consts = self.parse_enum_consts([
             "include/mbedtls/*.h",
+            "include/psa/*.h",
             "library/*.h",
+            "library/*.c",
             "3rdparty/everest/include/everest/everest.h",
             "3rdparty/everest/include/everest/x25519.h"
         ])
@@ -269,7 +275,7 @@
             "3rdparty/everest/include/everest/everest.h",
             "3rdparty/everest/include/everest/x25519.h"
         ])
-        mbed_words = self.parse_mbed_words([
+        mbed_psa_words = self.parse_mbed_psa_words([
             "include/mbedtls/*.h",
             "include/psa/*.h",
             "library/*.h",
@@ -302,10 +308,11 @@
         return {
             "public_macros": actual_macros["public"],
             "internal_macros": actual_macros["internal"],
+            "private_macros": all_macros["private"],
             "enum_consts": enum_consts,
             "identifiers": identifiers,
             "symbols": symbols,
-            "mbed_words": mbed_words
+            "mbed_psa_words": mbed_psa_words
         }
 
     def is_file_excluded(self, path, exclude_wildcards):
@@ -373,25 +380,28 @@
 
         return macros
 
-    def parse_mbed_words(self, include, exclude=None):
+    def parse_mbed_psa_words(self, include, exclude=None):
         """
-        Parse all words in the file that begin with MBED, in and out of macros,
-        comments, anything.
+        Parse all words in the file that begin with MBED|PSA, in and out of
+        macros, comments, anything.
 
         Args:
         * include: A List of glob expressions to look for files through.
         * exclude: A List of glob expressions for excluding files.
 
-        Returns a List of Match objects for words beginning with MBED.
+        Returns a List of Match objects for words beginning with MBED|PSA.
         """
         # Typos of TLS are common, hence the broader check below than MBEDTLS.
-        mbed_regex = re.compile(r"\bMBED.+?_[A-Z0-9_]*")
+        mbed_regex = re.compile(r"\b(MBED.+?|PSA)_[A-Z0-9_]*")
         exclusions = re.compile(r"// *no-check-names|#error")
 
         files = self.get_files(include, exclude)
-        self.log.debug("Looking for MBED words in {} files".format(len(files)))
+        self.log.debug(
+            "Looking for MBED|PSA words in {} files"
+            .format(len(files))
+        )
 
-        mbed_words = []
+        mbed_psa_words = []
         for filename in files:
             with open(filename, "r", encoding="utf-8") as fp:
                 for line_no, line in enumerate(fp):
@@ -399,14 +409,14 @@
                         continue
 
                     for name in mbed_regex.finditer(line):
-                        mbed_words.append(Match(
+                        mbed_psa_words.append(Match(
                             filename,
                             line,
                             line_no,
                             name.span(0),
                             name.group(0)))
 
-        return mbed_words
+        return mbed_psa_words
 
     def parse_enum_consts(self, include, exclude=None):
         """
@@ -434,8 +444,11 @@
                     # Match typedefs and brackets only when they are at the
                     # beginning of the line -- if they are indented, they might
                     # be sub-structures within structs, etc.
+                    optional_c_identifier = r"([_a-zA-Z][_a-zA-Z0-9]*)?"
                     if (state == states.OUTSIDE_KEYWORD and
-                            re.search(r"^(typedef +)?enum +{", line)):
+                            re.search(r"^(typedef +)?enum " + \
+                                    optional_c_identifier + \
+                                    r" *{", line)):
                         state = states.IN_BRACES
                     elif (state == states.OUTSIDE_KEYWORD and
                           re.search(r"^(typedef +)?enum", line)):
@@ -629,7 +642,7 @@
         self.log.info("Compiling...")
         symbols = []
 
-        # Back up the config and atomically compile with the full configratuion.
+        # Back up the config and atomically compile with the full configuration.
         shutil.copy(
             "include/mbedtls/mbedtls_config.h",
             "include/mbedtls/mbedtls_config.h.bak"
@@ -832,12 +845,14 @@
             for match
             in self.parse_result["public_macros"] +
             self.parse_result["internal_macros"] +
+            self.parse_result["private_macros"] +
             self.parse_result["enum_consts"]
             }
         typo_exclusion = re.compile(r"XXX|__|_$|^MBEDTLS_.*CONFIG_FILE$|"
-                                    r"MBEDTLS_TEST_LIBTESTDRIVER*")
+                                    r"MBEDTLS_TEST_LIBTESTDRIVER*|"
+                                    r"PSA_CRYPTO_DRIVER_TEST")
 
-        for name_match in self.parse_result["mbed_words"]:
+        for name_match in self.parse_result["mbed_psa_words"]:
             found = name_match.name in all_caps_names
 
             # Since MBEDTLS_PSA_ACCEL_XXX defines are defined by the
@@ -892,7 +907,7 @@
     parser.add_argument(
         "-q", "--quiet",
         action="store_true",
-        help="hide unnecessary text, explanations, and highlighs"
+        help="hide unnecessary text, explanations, and highlights"
     )
 
     args = parser.parse_args()
diff --git a/tests/scripts/depends.py b/tests/scripts/depends.py
index 0d6ec94..d09b732 100755
--- a/tests/scripts/depends.py
+++ b/tests/scripts/depends.py
@@ -234,6 +234,7 @@
     'MBEDTLS_ECP_C': ['MBEDTLS_ECDSA_C',
                       'MBEDTLS_ECDH_C',
                       'MBEDTLS_ECJPAKE_C',
+                      'MBEDTLS_ECP_RESTARTABLE',
                       'MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED',
                       'MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED',
                       'MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED',
diff --git a/tests/scripts/docker_env.sh b/tests/scripts/docker_env.sh
index be96c72..3dbc41d 100755
--- a/tests/scripts/docker_env.sh
+++ b/tests/scripts/docker_env.sh
@@ -9,6 +9,10 @@
 # thus making it easier to get set up as well as isolating test dependencies
 # (which include legacy/insecure configurations of openssl and gnutls).
 #
+# WARNING: the Dockerfile used by this script is no longer maintained! See
+# https://github.com/Mbed-TLS/mbedtls-test/blob/master/README.md#quick-start
+# for the set of Docker images we use on the CI.
+#
 # Notes for users
 # ---------------
 # This script expects a Linux x86_64 system with a recent version of Docker
diff --git a/tests/scripts/generate_bignum_tests.py b/tests/scripts/generate_bignum_tests.py
index a105203..6ee6ab3 100755
--- a/tests/scripts/generate_bignum_tests.py
+++ b/tests/scripts/generate_bignum_tests.py
@@ -57,32 +57,39 @@
 import sys
 
 from abc import ABCMeta
-from typing import Iterator, List
+from typing import List
 
 import scripts_path # pylint: disable=unused-import
-from mbedtls_dev import test_case
 from mbedtls_dev import test_data_generation
 from mbedtls_dev import bignum_common
 # Import modules containing additional test classes
 # Test function classes in these modules will be registered by
 # the framework
-from mbedtls_dev import bignum_core, bignum_mod_raw # pylint: disable=unused-import
+from mbedtls_dev import bignum_core, bignum_mod_raw, bignum_mod # pylint: disable=unused-import
 
-class BignumTarget(test_data_generation.BaseTarget, metaclass=ABCMeta):
-    #pylint: disable=abstract-method
+class BignumTarget(test_data_generation.BaseTarget):
+    #pylint: disable=too-few-public-methods
     """Target for bignum (legacy) test case generation."""
     target_basename = 'test_suite_bignum.generated'
 
 
-class BignumOperation(bignum_common.OperationCommon, BignumTarget, metaclass=ABCMeta):
+class BignumOperation(bignum_common.OperationCommon, BignumTarget,
+                      metaclass=ABCMeta):
     #pylint: disable=abstract-method
     """Common features for bignum operations in legacy tests."""
+    unique_combinations_only = True
     input_values = [
-        "", "0", "7b", "-7b",
+        "", "0", "-", "-0",
+        "7b", "-7b",
         "0000000000000000123", "-0000000000000000123",
         "1230000000000000000", "-1230000000000000000"
     ]
 
+    def description_suffix(self) -> str:
+        #pylint: disable=no-self-use # derived classes need self
+        """Text to add at the end of the test case description."""
+        return ""
+
     def description(self) -> str:
         """Generate a description for the test case.
 
@@ -96,6 +103,9 @@
                 self.symbol,
                 self.value_description(self.arg_b)
             )
+            description_suffix = self.description_suffix()
+            if description_suffix:
+                self.case_description += " " + description_suffix
         return super().description()
 
     @staticmethod
@@ -107,6 +117,8 @@
         """
         if val == "":
             return "0 (null)"
+        if val == "-":
+            return "negative 0 (null)"
         if val == "0":
             return "0 (1 limb)"
 
@@ -121,11 +133,6 @@
             tmp = "large " + tmp
         return tmp
 
-    @classmethod
-    def generate_function_tests(cls) -> Iterator[test_case.TestCase]:
-        for a_value, b_value in cls.get_value_pairs():
-            yield cls(a_value, b_value).create_test_case()
-
 
 class BignumCmp(BignumOperation):
     """Test cases for bignum value comparison."""
@@ -171,9 +178,21 @@
         ]
     )
 
-    def result(self) -> List[str]:
-        return [bignum_common.quote_str("{:x}").format(self.int_a + self.int_b)]
+    def __init__(self, val_a: str, val_b: str) -> None:
+        super().__init__(val_a, val_b)
+        self._result = self.int_a + self.int_b
 
+    def description_suffix(self) -> str:
+        if (self.int_a >= 0 and self.int_b >= 0):
+            return "" # obviously positive result or 0
+        if (self.int_a <= 0 and self.int_b <= 0):
+            return "" # obviously negative result or 0
+        # The sign of the result is not obvious, so indicate it
+        return ", result{}0".format('>' if self._result > 0 else
+                                    '<' if self._result < 0 else '=')
+
+    def result(self) -> List[str]:
+        return [bignum_common.quote_str("{:x}".format(self._result))]
 
 if __name__ == '__main__':
     # Use the section of the docstring relevant to the CLI as description
diff --git a/tests/scripts/generate_psa_tests.py b/tests/scripts/generate_psa_tests.py
index 2f09007..b271048 100755
--- a/tests/scripts/generate_psa_tests.py
+++ b/tests/scripts/generate_psa_tests.py
@@ -80,7 +80,7 @@
 # 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 proprely leads to a test
+# 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
@@ -459,7 +459,7 @@
         """Prepare to generate a key.
 
         * `usage`                 : The usage flags used for the key.
-        * `without_implicit_usage`: Flag to defide to apply the usage extension
+        * `without_implicit_usage`: Flag to define to apply the usage extension
         """
         usage_flags = set(usage)
         if not without_implicit_usage:
@@ -483,7 +483,7 @@
     ) -> None:
         """Prepare to generate test data
 
-        * `description`   : used for the the test case names
+        * `description`   : used for the test case names
         * `expected_usage`: the usage flags generated as the expected usage flags
                             in the test cases. CAn differ from the usage flags
                             stored in the keys because of the usage flags extension.
diff --git a/tests/scripts/generate_test_code.py b/tests/scripts/generate_test_code.py
index 938f24c..f19d30b 100755
--- a/tests/scripts/generate_test_code.py
+++ b/tests/scripts/generate_test_code.py
@@ -220,25 +220,17 @@
 
         :param file_name: File path to open.
         """
-        super(FileWrapper, self).__init__(file_name, 'r')
+        super().__init__(file_name, 'r')
         self._line_no = 0
 
-    def next(self):
+    def __next__(self):
         """
-        Python 2 iterator method. This method overrides base class's
-        next method and extends the next method to count the line
-        numbers as each line is read.
-
-        It works for both Python 2 and Python 3 by checking iterator
-        method name in the base iterator object.
+        This method overrides base class's __next__ method and extends it
+        method to count the line numbers as each line is read.
 
         :return: Line read from file.
         """
-        parent = super(FileWrapper, self)
-        if hasattr(parent, '__next__'):
-            line = parent.__next__()  # Python 3
-        else:
-            line = parent.next()  # Python 2 # pylint: disable=no-member
+        line = super().__next__()
         if line is not None:
             self._line_no += 1
             # Convert byte array to string with correct encoding and
@@ -246,9 +238,6 @@
             return line.decode(sys.getdefaultencoding()).rstrip() + '\n'
         return None
 
-    # Python 3 iterator method
-    __next__ = next
-
     def get_line_no(self):
         """
         Gives current line number.
@@ -530,6 +519,50 @@
         gen_dependencies(dependencies)
     return preprocessor_check_start + code + preprocessor_check_end
 
+COMMENT_START_REGEX = re.compile(r'/[*/]')
+
+def skip_comments(line, stream):
+    """Remove comments in line.
+
+    If the line contains an unfinished comment, read more lines from stream
+    until the line that contains the comment.
+
+    :return: The original line with inner comments replaced by spaces.
+             Trailing comments and whitespace may be removed completely.
+    """
+    pos = 0
+    while True:
+        opening = COMMENT_START_REGEX.search(line, pos)
+        if not opening:
+            break
+        if line[opening.start(0) + 1] == '/': # //...
+            continuation = line
+            # Count the number of line breaks, to keep line numbers aligned
+            # in the output.
+            line_count = 1
+            while continuation.endswith('\\\n'):
+                # This errors out if the file ends with an unfinished line
+                # comment. That's acceptable to not complicate the code further.
+                continuation = next(stream)
+                line_count += 1
+            return line[:opening.start(0)].rstrip() + '\n' * line_count
+        # Parsing /*...*/, looking for the end
+        closing = line.find('*/', opening.end(0))
+        while closing == -1:
+            # This errors out if the file ends with an unfinished block
+            # comment. That's acceptable to not complicate the code further.
+            line += next(stream)
+            closing = line.find('*/', opening.end(0))
+        pos = closing + 2
+        # Replace inner comment by spaces. There needs to be at least one space
+        # for things like 'int/*ihatespaces*/foo'. Go further and preserve the
+        # width of the comment and line breaks, this way positions in error
+        # messages remain correct.
+        line = (line[:opening.start(0)] +
+                re.sub(r'.', r' ', line[opening.start(0):pos]) +
+                line[pos:])
+    # Strip whitespace at the end of lines (it's irrelevant to error messages).
+    return re.sub(r' +(\n|\Z)', r'\1', line)
 
 def parse_function_code(funcs_f, dependencies, suite_dependencies):
     """
@@ -549,6 +582,7 @@
         # across multiple lines. Here we try to find the start of
         # arguments list, then remove '\n's and apply the regex to
         # detect function start.
+        line = skip_comments(line, funcs_f)
         up_to_arg_list_start = code + line[:line.find('(') + 1]
         match = re.match(TEST_FUNCTION_VALIDATION_REGEX,
                          up_to_arg_list_start.replace('\n', ' '), re.I)
@@ -557,7 +591,7 @@
             name = match.group('func_name')
             if not re.match(FUNCTION_ARG_LIST_END_REGEX, line):
                 for lin in funcs_f:
-                    line += lin
+                    line += skip_comments(lin, funcs_f)
                     if re.search(FUNCTION_ARG_LIST_END_REGEX, line):
                         break
             args, local_vars, args_dispatch = parse_function_arguments(
diff --git a/tests/scripts/run-test-suites.pl b/tests/scripts/run-test-suites.pl
index 8a5bb93..cedc0bf 100755
--- a/tests/scripts/run-test-suites.pl
+++ b/tests/scripts/run-test-suites.pl
@@ -50,10 +50,10 @@
            'verbose|v:1' => \$verbose,
           ) or die;
 
-# All test suites = executable files derived from a .data file.
+# All test suites = executable files with a .datax file.
 my @suites = ();
-for my $data_file (glob 'suites/test_suite_*.data') {
-    (my $base = $data_file) =~ s#^suites/(.*)\.data$#$1#;
+for my $data_file (glob 'test_suite_*.datax') {
+    (my $base = $data_file) =~ s/\.datax$//;
     push @suites, $base if -x $base;
     push @suites, "$base.exe" if -e "$base.exe";
 }
diff --git a/tests/scripts/test_generate_test_code.py b/tests/scripts/test_generate_test_code.py
index 9bf66f1..d23d742 100755
--- a/tests/scripts/test_generate_test_code.py
+++ b/tests/scripts/test_generate_test_code.py
@@ -682,12 +682,12 @@
     @patch("generate_test_code.gen_dependencies")
     @patch("generate_test_code.gen_function_wrapper")
     @patch("generate_test_code.parse_function_arguments")
-    def test_functio_name_on_newline(self, parse_function_arguments_mock,
-                                     gen_function_wrapper_mock,
-                                     gen_dependencies_mock,
-                                     gen_dispatch_mock):
+    def test_function_name_on_newline(self, parse_function_arguments_mock,
+                                      gen_function_wrapper_mock,
+                                      gen_dependencies_mock,
+                                      gen_dispatch_mock):
         """
-        Test when exit label is present.
+        Test with line break before the function name.
         :return:
         """
         parse_function_arguments_mock.return_value = ([], '', [])
@@ -727,6 +727,194 @@
 '''
         self.assertEqual(code, expected)
 
+    @patch("generate_test_code.gen_dispatch")
+    @patch("generate_test_code.gen_dependencies")
+    @patch("generate_test_code.gen_function_wrapper")
+    @patch("generate_test_code.parse_function_arguments")
+    def test_case_starting_with_comment(self, parse_function_arguments_mock,
+                                        gen_function_wrapper_mock,
+                                        gen_dependencies_mock,
+                                        gen_dispatch_mock):
+        """
+        Test with comments before the function signature
+        :return:
+        """
+        parse_function_arguments_mock.return_value = ([], '', [])
+        gen_function_wrapper_mock.return_value = ''
+        gen_dependencies_mock.side_effect = gen_dependencies
+        gen_dispatch_mock.side_effect = gen_dispatch
+        data = '''/* comment */
+/* more
+ * comment */
+// this is\\
+still \\
+a comment
+void func()
+{
+    ba ba black sheep
+    have you any wool
+exit:
+    yes sir yes sir
+    3 bags full
+}
+/* END_CASE */
+'''
+        stream = StringIOWrapper('test_suite_ut.function', data)
+        _, _, code, _ = parse_function_code(stream, [], [])
+
+        expected = '''#line 1 "test_suite_ut.function"
+
+
+
+
+
+
+void test_func()
+{
+    ba ba black sheep
+    have you any wool
+exit:
+    yes sir yes sir
+    3 bags full
+}
+'''
+        self.assertEqual(code, expected)
+
+    @patch("generate_test_code.gen_dispatch")
+    @patch("generate_test_code.gen_dependencies")
+    @patch("generate_test_code.gen_function_wrapper")
+    @patch("generate_test_code.parse_function_arguments")
+    def test_comment_in_prototype(self, parse_function_arguments_mock,
+                                  gen_function_wrapper_mock,
+                                  gen_dependencies_mock,
+                                  gen_dispatch_mock):
+        """
+        Test with comments in the function prototype
+        :return:
+        """
+        parse_function_arguments_mock.return_value = ([], '', [])
+        gen_function_wrapper_mock.return_value = ''
+        gen_dependencies_mock.side_effect = gen_dependencies
+        gen_dispatch_mock.side_effect = gen_dispatch
+        data = '''
+void func( int x, // (line \\
+                     comment)
+           int y /* lone closing parenthesis) */ )
+{
+    ba ba black sheep
+    have you any wool
+exit:
+    yes sir yes sir
+    3 bags full
+}
+/* END_CASE */
+'''
+        stream = StringIOWrapper('test_suite_ut.function', data)
+        _, _, code, _ = parse_function_code(stream, [], [])
+
+        expected = '''#line 1 "test_suite_ut.function"
+
+void test_func( int x,
+
+           int y                                 )
+{
+    ba ba black sheep
+    have you any wool
+exit:
+    yes sir yes sir
+    3 bags full
+}
+'''
+        self.assertEqual(code, expected)
+
+    @patch("generate_test_code.gen_dispatch")
+    @patch("generate_test_code.gen_dependencies")
+    @patch("generate_test_code.gen_function_wrapper")
+    @patch("generate_test_code.parse_function_arguments")
+    def test_line_comment_in_block_comment(self, parse_function_arguments_mock,
+                                           gen_function_wrapper_mock,
+                                           gen_dependencies_mock,
+                                           gen_dispatch_mock):
+        """
+        Test with line comment in block comment.
+        :return:
+        """
+        parse_function_arguments_mock.return_value = ([], '', [])
+        gen_function_wrapper_mock.return_value = ''
+        gen_dependencies_mock.side_effect = gen_dependencies
+        gen_dispatch_mock.side_effect = gen_dispatch
+        data = '''
+void func( int x /* // */ )
+{
+    ba ba black sheep
+    have you any wool
+exit:
+    yes sir yes sir
+    3 bags full
+}
+/* END_CASE */
+'''
+        stream = StringIOWrapper('test_suite_ut.function', data)
+        _, _, code, _ = parse_function_code(stream, [], [])
+
+        expected = '''#line 1 "test_suite_ut.function"
+
+void test_func( int x          )
+{
+    ba ba black sheep
+    have you any wool
+exit:
+    yes sir yes sir
+    3 bags full
+}
+'''
+        self.assertEqual(code, expected)
+
+    @patch("generate_test_code.gen_dispatch")
+    @patch("generate_test_code.gen_dependencies")
+    @patch("generate_test_code.gen_function_wrapper")
+    @patch("generate_test_code.parse_function_arguments")
+    def test_block_comment_in_line_comment(self, parse_function_arguments_mock,
+                                           gen_function_wrapper_mock,
+                                           gen_dependencies_mock,
+                                           gen_dispatch_mock):
+        """
+        Test with block comment in line comment.
+        :return:
+        """
+        parse_function_arguments_mock.return_value = ([], '', [])
+        gen_function_wrapper_mock.return_value = ''
+        gen_dependencies_mock.side_effect = gen_dependencies
+        gen_dispatch_mock.side_effect = gen_dispatch
+        data = '''
+// /*
+void func( int x )
+{
+    ba ba black sheep
+    have you any wool
+exit:
+    yes sir yes sir
+    3 bags full
+}
+/* END_CASE */
+'''
+        stream = StringIOWrapper('test_suite_ut.function', data)
+        _, _, code, _ = parse_function_code(stream, [], [])
+
+        expected = '''#line 1 "test_suite_ut.function"
+
+
+void test_func( int x )
+{
+    ba ba black sheep
+    have you any wool
+exit:
+    yes sir yes sir
+    3 bags full
+}
+'''
+        self.assertEqual(code, expected)
+
 
 class ParseFunction(TestCase):
     """
diff --git a/tests/scripts/test_psa_compliance.py b/tests/scripts/test_psa_compliance.py
index 7d06db1..92db417 100755
--- a/tests/scripts/test_psa_compliance.py
+++ b/tests/scripts/test_psa_compliance.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 """Run the PSA Crypto API compliance test suite.
 Clone the repo and check out the commit specified by PSA_ARCH_TEST_REPO and PSA_ARCH_TEST_REF,
-then complie and run the test suite. The clone is stored at <Mbed TLS root>/psa-arch-tests.
+then compile and run the test suite. The clone is stored at <Mbed TLS root>/psa-arch-tests.
 Known defects in either the test suite or mbedtls - identified by their test number - are ignored,
 while unexpected failures AND successes are reported as errors,
 to help keep the list of known defects as up to date as possible.
diff --git a/tests/src/bignum_helpers.c b/tests/src/bignum_helpers.c
new file mode 100644
index 0000000..d6ec9bd
--- /dev/null
+++ b/tests/src/bignum_helpers.c
@@ -0,0 +1,142 @@
+/**
+ * \file bignum_helpers.c
+ *
+ * \brief   This file contains the prototypes of helper functions for
+ *          bignum-related 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.
+ */
+
+#define MBEDTLS_ALLOW_PRIVATE_ACCESS
+#include <test/bignum_helpers.h>
+
+#if defined(MBEDTLS_BIGNUM_C)
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <mbedtls/bignum.h>
+#include <bignum_core.h>
+#include <bignum_mod.h>
+#include <bignum_mod_raw.h>
+
+#include <test/helpers.h>
+#include <test/macros.h>
+
+int mbedtls_test_read_mpi_core( mbedtls_mpi_uint **pX, size_t *plimbs,
+                                const char *input )
+{
+    /* Sanity check */
+    if( *pX != NULL )
+        return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+
+    size_t hex_len = strlen( input );
+    size_t byte_len = ( hex_len + 1 ) / 2;
+    *plimbs = CHARS_TO_LIMBS( byte_len );
+
+    /* A core bignum is not allowed to be empty. Forbid it as test data,
+     * this way static analyzers have a chance of knowing we don't expect
+     * the bignum functions to support empty inputs. */
+    if( *plimbs == 0 )
+        return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+
+    *pX = mbedtls_calloc( *plimbs, sizeof( **pX ) );
+    if( *pX == NULL )
+        return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
+
+    unsigned char *byte_start = ( unsigned char * ) *pX;
+    if( byte_len % sizeof( mbedtls_mpi_uint ) != 0 )
+    {
+        byte_start += sizeof( mbedtls_mpi_uint ) - byte_len % sizeof( mbedtls_mpi_uint );
+    }
+    if( ( hex_len & 1 ) != 0 )
+    {
+        /* mbedtls_test_unhexify wants an even number of hex digits */
+        TEST_ASSERT( mbedtls_test_ascii2uc( *input, byte_start ) == 0 );
+        ++byte_start;
+        ++input;
+        --byte_len;
+    }
+    TEST_ASSERT( mbedtls_test_unhexify( byte_start,
+                                        byte_len,
+                                        input,
+                                        &byte_len ) == 0 );
+
+    mbedtls_mpi_core_bigendian_to_host( *pX, *plimbs );
+    return( 0 );
+
+exit:
+    mbedtls_free( *pX );
+    return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+}
+
+int mbedtls_test_read_mpi_modulus( mbedtls_mpi_mod_modulus *N,
+                                   const char *s,
+                                   mbedtls_mpi_mod_rep_selector int_rep )
+{
+    mbedtls_mpi_uint *p = NULL;
+    size_t limbs = 0;
+    if( N->limbs != 0 )
+        return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+    int ret = mbedtls_test_read_mpi_core( &p, &limbs, s );
+    if( ret != 0 )
+        return( ret );
+    ret = mbedtls_mpi_mod_modulus_setup( N, p, limbs, int_rep );
+    if( ret != 0 )
+        mbedtls_free( p );
+    return( ret );
+}
+
+void mbedtls_test_mpi_mod_modulus_free_with_limbs( mbedtls_mpi_mod_modulus *N )
+{
+    mbedtls_free( (mbedtls_mpi_uint*) N->p );
+    mbedtls_mpi_mod_modulus_free( N );
+}
+
+int mbedtls_test_read_mpi( mbedtls_mpi *X, const char *s )
+{
+    int negative = 0;
+    /* Always set the sign bit to -1 if the input has a minus sign, even for 0.
+     * This creates an invalid representation, which mbedtls_mpi_read_string()
+     * avoids but we want to be able to create that in test data. */
+    if( s[0] == '-' )
+    {
+        ++s;
+        negative = 1;
+    }
+    /* mbedtls_mpi_read_string() currently retains leading zeros.
+     * It always allocates at least one limb for the value 0. */
+    if( s[0] == 0 )
+    {
+        mbedtls_mpi_free( X );
+        return( 0 );
+    }
+    int ret = mbedtls_mpi_read_string( X, 16, s );
+    if( ret != 0 )
+        return( ret );
+    if( negative )
+    {
+        if( mbedtls_mpi_cmp_int( X, 0 ) == 0 )
+            ++mbedtls_test_case_uses_negative_0;
+        X->s = -1;
+    }
+    return( 0 );
+}
+
+#endif /* MBEDTLS_BIGNUM_C */
+
diff --git a/tests/src/drivers/test_driver_key_agreement.c b/tests/src/drivers/test_driver_key_agreement.c
new file mode 100644
index 0000000..7c37b03
--- /dev/null
+++ b/tests/src/drivers/test_driver_key_agreement.c
@@ -0,0 +1,128 @@
+/*
+ * Test driver for key agreement functions.
+ */
+/*  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 <test/helpers.h>
+
+#if defined(MBEDTLS_PSA_CRYPTO_DRIVERS) && defined(PSA_CRYPTO_DRIVER_TEST)
+
+#include "psa/crypto.h"
+#include "psa_crypto_core.h"
+#include "psa_crypto_ecp.h"
+
+#include "test/drivers/key_agreement.h"
+#include "test/drivers/test_driver.h"
+
+#include <string.h>
+
+#if defined(MBEDTLS_TEST_LIBTESTDRIVER1)
+#include "libtestdriver1/include/psa/crypto.h"
+#include "libtestdriver1/library/psa_crypto_ecp.h"
+#endif
+
+mbedtls_test_driver_key_agreement_hooks_t
+    mbedtls_test_driver_key_agreement_hooks = MBEDTLS_TEST_DRIVER_KEY_AGREEMENT_INIT;
+
+psa_status_t mbedtls_test_transparent_key_agreement(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer,
+    size_t key_buffer_size,
+    psa_algorithm_t alg,
+    const uint8_t *peer_key,
+    size_t peer_key_length,
+    uint8_t *shared_secret,
+    size_t shared_secret_size,
+    size_t *shared_secret_length )
+{
+    mbedtls_test_driver_key_agreement_hooks.hits++;
+
+    if( mbedtls_test_driver_key_agreement_hooks.forced_status != PSA_SUCCESS )
+        return( mbedtls_test_driver_key_agreement_hooks.forced_status );
+
+    if( mbedtls_test_driver_key_agreement_hooks.forced_output != NULL )
+    {
+        if( mbedtls_test_driver_key_agreement_hooks.forced_output_length > shared_secret_size )
+            return( PSA_ERROR_BUFFER_TOO_SMALL );
+
+        memcpy( shared_secret, mbedtls_test_driver_key_agreement_hooks.forced_output,
+                mbedtls_test_driver_key_agreement_hooks.forced_output_length );
+        *shared_secret_length = mbedtls_test_driver_key_agreement_hooks.forced_output_length;
+
+        return( PSA_SUCCESS );
+    }
+
+    if( PSA_ALG_IS_ECDH(alg) )
+    {
+#if (defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \
+    defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_ALG_ECDH))
+        return( libtestdriver1_mbedtls_psa_key_agreement_ecdh(
+                    (const libtestdriver1_psa_key_attributes_t *) attributes,
+                    key_buffer, key_buffer_size,
+                    alg, peer_key, peer_key_length,
+                    shared_secret, shared_secret_size,
+                    shared_secret_length ) );
+#elif defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH)
+        return( mbedtls_psa_key_agreement_ecdh(
+                attributes,
+                key_buffer, key_buffer_size,
+                alg, peer_key, peer_key_length,
+                shared_secret, shared_secret_size,
+                shared_secret_length ) );
+#else
+        (void) attributes;
+        (void) key_buffer;
+        (void) key_buffer_size;
+        (void) peer_key;
+        (void) peer_key_length;
+        (void) shared_secret;
+        (void) shared_secret_size;
+        (void) shared_secret_length;
+        return( PSA_ERROR_NOT_SUPPORTED );
+#endif
+    }
+    else
+    {
+        return( PSA_ERROR_INVALID_ARGUMENT );
+    }
+
+}
+
+psa_status_t mbedtls_test_opaque_key_agreement(
+    const psa_key_attributes_t *attributes,
+    const uint8_t *key_buffer,
+    size_t key_buffer_size,
+    psa_algorithm_t alg,
+    const uint8_t *peer_key,
+    size_t peer_key_length,
+    uint8_t *shared_secret,
+    size_t shared_secret_size,
+    size_t *shared_secret_length )
+{
+    (void) attributes;
+    (void) key_buffer;
+    (void) key_buffer_size;
+    (void) alg;
+    (void) peer_key;
+    (void) peer_key_length;
+    (void) shared_secret;
+    (void) shared_secret_size;
+    (void) shared_secret_length;
+    return( PSA_ERROR_NOT_SUPPORTED );
+}
+
+#endif /* MBEDTLS_PSA_CRYPTO_DRIVERS && PSA_CRYPTO_DRIVER_TEST */
diff --git a/tests/src/helpers.c b/tests/src/helpers.c
index cc23fd7..be5c465 100644
--- a/tests/src/helpers.c
+++ b/tests/src/helpers.c
@@ -48,7 +48,7 @@
 #endif /* MBEDTLS_PLATFORM_C */
 }
 
-static int ascii2uc(const char c, unsigned char *uc)
+int mbedtls_test_ascii2uc(const char c, unsigned char *uc)
 {
     if( ( c >= '0' ) && ( c <= '9' ) )
         *uc = c - '0';
@@ -89,6 +89,10 @@
     mbedtls_test_info.step = step;
 }
 
+#if defined(MBEDTLS_BIGNUM_C)
+unsigned mbedtls_test_case_uses_negative_0 = 0;
+#endif
+
 void mbedtls_test_info_reset( void )
 {
     mbedtls_test_info.result = MBEDTLS_TEST_RESULT_SUCCESS;
@@ -98,6 +102,9 @@
     mbedtls_test_info.filename = 0;
     memset( mbedtls_test_info.line1, 0, sizeof( mbedtls_test_info.line1 ) );
     memset( mbedtls_test_info.line2, 0, sizeof( mbedtls_test_info.line2 ) );
+#if defined(MBEDTLS_BIGNUM_C)
+    mbedtls_test_case_uses_negative_0 = 0;
+#endif
 }
 
 int mbedtls_test_equal( const char *test, int line_no, const char* filename,
@@ -200,10 +207,10 @@
 
     while( *ibuf != 0 )
     {
-        if ( ascii2uc( *(ibuf++), &uc ) != 0 )
+        if ( mbedtls_test_ascii2uc( *(ibuf++), &uc ) != 0 )
             return( -1 );
 
-        if ( ascii2uc( *(ibuf++), &uc2 ) != 0 )
+        if ( mbedtls_test_ascii2uc( *(ibuf++), &uc2 ) != 0 )
             return( -1 );
 
         *(obuf++) = ( uc << 4 ) | uc2;
@@ -343,67 +350,3 @@
     }
 }
 #endif /* MBEDTLS_TEST_HOOKS */
-
-#if defined(MBEDTLS_BIGNUM_C)
-#include "bignum_core.h"
-
-int mbedtls_test_read_mpi_core( mbedtls_mpi_uint **pX, size_t *plimbs,
-                                const char *input )
-{
-    /* Sanity check */
-    if( *pX != NULL )
-        return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
-
-    size_t hex_len = strlen( input );
-    size_t byte_len = ( hex_len + 1 ) / 2;
-    *plimbs = CHARS_TO_LIMBS( byte_len );
-
-    /* A core bignum is not allowed to be empty. Forbid it as test data,
-     * this way static analyzers have a chance of knowing we don't expect
-     * the bignum functions to support empty inputs. */
-    if( *plimbs == 0 )
-        return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
-
-    *pX = mbedtls_calloc( *plimbs, sizeof( **pX ) );
-    if( *pX == NULL )
-        return( MBEDTLS_ERR_MPI_ALLOC_FAILED );
-
-    unsigned char *byte_start = ( unsigned char * ) *pX;
-    if( byte_len % sizeof( mbedtls_mpi_uint ) != 0 )
-    {
-        byte_start += sizeof( mbedtls_mpi_uint ) - byte_len % sizeof( mbedtls_mpi_uint );
-    }
-    if( ( hex_len & 1 ) != 0 )
-    {
-        /* mbedtls_test_unhexify wants an even number of hex digits */
-        TEST_ASSERT( ascii2uc( *input, byte_start ) == 0 );
-        ++byte_start;
-        ++input;
-        --byte_len;
-    }
-    TEST_ASSERT( mbedtls_test_unhexify( byte_start,
-                                        byte_len,
-                                        input,
-                                        &byte_len ) == 0 );
-
-    mbedtls_mpi_core_bigendian_to_host( *pX, *plimbs );
-    return( 0 );
-
-exit:
-    mbedtls_free( *pX );
-    return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
-}
-
-int mbedtls_test_read_mpi( mbedtls_mpi *X, const char *s )
-{
-    /* mbedtls_mpi_read_string() currently retains leading zeros.
-     * It always allocates at least one limb for the value 0. */
-    if( s[0] == 0 )
-    {
-        mbedtls_mpi_free( X );
-        return( 0 );
-    }
-    else
-        return( mbedtls_mpi_read_string( X, 16, s ) );
-}
-#endif
diff --git a/tests/ssl-opt-in-docker.sh b/tests/ssl-opt-in-docker.sh
index e7bb01d..c8c6697 100755
--- a/tests/ssl-opt-in-docker.sh
+++ b/tests/ssl-opt-in-docker.sh
@@ -6,6 +6,10 @@
 # -------
 # This runs ssl-opt.sh in a Docker container.
 #
+# WARNING: the Dockerfile used by this script is no longer maintained! See
+# https://github.com/Mbed-TLS/mbedtls-test/blob/master/README.md#quick-start
+# for the set of Docker images we use on the CI.
+#
 # Notes for users
 # ---------------
 # If OPENSSL_CMD, GNUTLS_CLI, or GNUTLS_SERV are specified, the path must
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 9eb925a..0d4ce6e 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -80,12 +80,14 @@
 
 if [ -n "${OPENSSL_NEXT:-}" ]; then
     O_NEXT_SRV="$OPENSSL_NEXT s_server -www -cert data_files/server5.crt -key data_files/server5.key"
+    O_NEXT_SRV_EARLY_DATA="$OPENSSL_NEXT s_server -early_data -cert data_files/server5.crt -key data_files/server5.key"
     O_NEXT_SRV_NO_CERT="$OPENSSL_NEXT s_server -www "
     O_NEXT_CLI="echo 'GET / HTTP/1.0' | $OPENSSL_NEXT s_client -CAfile data_files/test-ca_cat12.crt"
     O_NEXT_CLI_NO_CERT="echo 'GET / HTTP/1.0' | $OPENSSL_NEXT s_client"
 else
     O_NEXT_SRV=false
     O_NEXT_SRV_NO_CERT=false
+    O_NEXT_SRV_EARLY_DATA=false
     O_NEXT_CLI_NO_CERT=false
     O_NEXT_CLI=false
 fi
@@ -1360,7 +1362,7 @@
 
     if [ -n "$PXY_CMD" ]; then
         kill $PXY_PID >/dev/null 2>&1
-        wait $PXY_PID
+        wait $PXY_PID >> $PXY_OUT 2>&1
     fi
 }
 
@@ -1687,9 +1689,24 @@
     O_LEGACY_CLI="$O_LEGACY_CLI -connect 127.0.0.1:+SRV_PORT"
 fi
 
+# Newer versions of OpenSSL have a syntax to enable all "ciphers", even
+# low-security ones. This covers not just cipher suites but also protocol
+# versions. It is necessary, for example, to use (D)TLS 1.0/1.1 on
+# OpenSSL 1.1.1f from Ubuntu 20.04. The syntax was only introduced in
+# OpenSSL 1.1.0 (21e0c1d23afff48601eb93135defddae51f7e2e3) and I can't find
+# a way to discover it from -help, so check the openssl version.
+case $($OPENSSL_CMD version) in
+    "OpenSSL 0"*|"OpenSSL 1.0"*) :;;
+    *)
+        O_CLI="$O_CLI -cipher ALL@SECLEVEL=0"
+        O_SRV="$O_SRV -cipher ALL@SECLEVEL=0"
+        ;;
+esac
+
 if [ -n "${OPENSSL_NEXT:-}" ]; then
     O_NEXT_SRV="$O_NEXT_SRV -accept $SRV_PORT"
     O_NEXT_SRV_NO_CERT="$O_NEXT_SRV_NO_CERT -accept $SRV_PORT"
+    O_NEXT_SRV_EARLY_DATA="$O_NEXT_SRV_EARLY_DATA -accept $SRV_PORT"
     O_NEXT_CLI="$O_NEXT_CLI -connect 127.0.0.1:+SRV_PORT"
     O_NEXT_CLI_NO_CERT="$O_NEXT_CLI_NO_CERT -connect 127.0.0.1:+SRV_PORT"
 fi
@@ -2381,6 +2398,31 @@
             -u "IV used" \
             -U "IV used"
 
+# Test for correctness of sent single supported algorithm
+requires_config_enabled MBEDTLS_ECP_DP_SECP256R1_ENABLED
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+requires_config_enabled MBEDTLS_DEBUG_C
+requires_config_enabled MBEDTLS_SSL_CLI_C
+requires_config_enabled MBEDTLS_SSL_SRV_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_hash_alg SHA_256
+run_test    "Single supported algorithm sending: mbedtls client" \
+            "$P_SRV sig_algs=ecdsa_secp256r1_sha256 auth_mode=required" \
+            "$P_CLI sig_algs=ecdsa_secp256r1_sha256 debug_level=3" \
+            0 \
+            -c "Supported Signature Algorithm found: 04 03"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+requires_config_enabled MBEDTLS_SSL_SRV_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_ECP_DP_SECP256R1_ENABLED
+requires_hash_alg SHA_256
+run_test    "Single supported algorithm sending: openssl client" \
+            "$P_SRV sig_algs=ecdsa_secp256r1_sha256 auth_mode=required" \
+            "$O_CLI -cert data_files/server6.crt \
+                    -key data_files/server6.key" \
+            0
+
 # Tests for certificate verification callback
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 run_test    "Configuration-specific CRT verification callback" \
@@ -2572,7 +2614,6 @@
             -c "Deserializing connection..." \
             -S "Deserializing connection..."
 
-requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION
 run_test    "Context serialization, server serializes, CCM" \
             "$P_SRV dtls=1 serialize=1 exchanges=2" \
@@ -2646,7 +2687,6 @@
             -c "Deserializing connection..." \
             -s "Deserializing connection..."
 
-requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION
 run_test    "Context serialization, re-init, client serializes, CCM" \
             "$P_SRV dtls=1 serialize=0 exchanges=2" \
@@ -2683,7 +2723,6 @@
             -c "Deserializing connection..." \
             -S "Deserializing connection..."
 
-requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION
 run_test    "Context serialization, re-init, server serializes, CCM" \
             "$P_SRV dtls=1 serialize=2 exchanges=2" \
@@ -5284,8 +5323,8 @@
              key_file=data_files/server6.key \
              force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384" \
             0 \
-            -c "Supported Signature Algorithm found: 4," \
-            -c "Supported Signature Algorithm found: 5,"
+            -c "Supported Signature Algorithm found: 04 " \
+            -c "Supported Signature Algorithm found: 05 "
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 requires_any_configs_enabled $TLS1_2_KEY_EXCHANGES_WITH_CERT
@@ -5295,8 +5334,8 @@
              key_file=data_files/server6.key \
              force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256" \
             0 \
-            -c "Supported Signature Algorithm found: 4," \
-            -c "Supported Signature Algorithm found: 5,"
+            -c "Supported Signature Algorithm found: 04 " \
+            -c "Supported Signature Algorithm found: 05 "
 
 requires_key_exchange_with_cert_in_tls12_or_tls13_enabled
 run_test    "Authentication: client has no cert, server required (TLS)" \
@@ -5697,8 +5736,8 @@
              force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384" \
             0 \
             -s "use CA callback for X.509 CRT verification" \
-            -c "Supported Signature Algorithm found: 4," \
-            -c "Supported Signature Algorithm found: 5,"
+            -c "Supported Signature Algorithm found: 04 " \
+            -c "Supported Signature Algorithm found: 05 "
 
 requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
@@ -5710,8 +5749,8 @@
              force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256" \
             0 \
             -s "use CA callback for X.509 CRT verification" \
-            -c "Supported Signature Algorithm found: 4," \
-            -c "Supported Signature Algorithm found: 5,"
+            -c "Supported Signature Algorithm found: 04 " \
+            -c "Supported Signature Algorithm found: 05 "
 
 requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
@@ -7947,6 +7986,8 @@
             -C "found ecjpake_kkpp extension" \
             -s "SSL - The handshake negotiation failed"
 
+# Note: if the name of this test is changed, then please adjust the corresponding
+#       filtering label in "test_tls1_2_ecjpake_compatibility" (in "all.sh")
 requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 run_test    "ECJPAKE: working, TLS" \
@@ -7965,6 +8006,73 @@
             -S "SSL - The handshake negotiation failed" \
             -S "SSL - Verification of the message MAC failed"
 
+requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED
+requires_config_enabled MBEDTLS_USE_PSA_CRYPTO
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test    "ECJPAKE: opaque password client+server, working, TLS" \
+            "$P_SRV debug_level=3 ecjpake_pw=bla ecjpake_pw_opaque=1" \
+            "$P_CLI debug_level=3 ecjpake_pw=bla ecjpake_pw_opaque=1\
+             force_ciphersuite=TLS-ECJPAKE-WITH-AES-128-CCM-8" \
+            0 \
+            -c "add ciphersuite: c0ff" \
+            -c "adding ecjpake_kkpp extension" \
+            -c "using opaque password" \
+            -s "using opaque password" \
+            -C "re-using cached ecjpake parameters" \
+            -s "found ecjpake kkpp extension" \
+            -S "skip ecjpake kkpp extension" \
+            -S "ciphersuite mismatch: ecjpake not configured" \
+            -s "server hello, ecjpake kkpp extension" \
+            -c "found ecjpake_kkpp extension" \
+            -S "SSL - The handshake negotiation failed" \
+            -S "SSL - Verification of the message MAC failed"
+
+# Note: if the name of this test is changed, then please adjust the corresponding
+#       filtering label in "test_tls1_2_ecjpake_compatibility" (in "all.sh")
+requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED
+requires_config_enabled MBEDTLS_USE_PSA_CRYPTO
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test    "ECJPAKE: opaque password client only, working, TLS" \
+            "$P_SRV debug_level=3 ecjpake_pw=bla" \
+            "$P_CLI debug_level=3 ecjpake_pw=bla ecjpake_pw_opaque=1\
+             force_ciphersuite=TLS-ECJPAKE-WITH-AES-128-CCM-8" \
+            0 \
+            -c "add ciphersuite: c0ff" \
+            -c "adding ecjpake_kkpp extension" \
+            -c "using opaque password" \
+            -S "using opaque password" \
+            -C "re-using cached ecjpake parameters" \
+            -s "found ecjpake kkpp extension" \
+            -S "skip ecjpake kkpp extension" \
+            -S "ciphersuite mismatch: ecjpake not configured" \
+            -s "server hello, ecjpake kkpp extension" \
+            -c "found ecjpake_kkpp extension" \
+            -S "SSL - The handshake negotiation failed" \
+            -S "SSL - Verification of the message MAC failed"
+
+# Note: if the name of this test is changed, then please adjust the corresponding
+#       filtering label in "test_tls1_2_ecjpake_compatibility" (in "all.sh")
+requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED
+requires_config_enabled MBEDTLS_USE_PSA_CRYPTO
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test    "ECJPAKE: opaque password server only, working, TLS" \
+            "$P_SRV debug_level=3 ecjpake_pw=bla ecjpake_pw_opaque=1" \
+            "$P_CLI debug_level=3 ecjpake_pw=bla\
+             force_ciphersuite=TLS-ECJPAKE-WITH-AES-128-CCM-8" \
+            0 \
+            -c "add ciphersuite: c0ff" \
+            -c "adding ecjpake_kkpp extension" \
+            -C "using opaque password" \
+            -s "using opaque password" \
+            -C "re-using cached ecjpake parameters" \
+            -s "found ecjpake kkpp extension" \
+            -S "skip ecjpake kkpp extension" \
+            -S "ciphersuite mismatch: ecjpake not configured" \
+            -s "server hello, ecjpake kkpp extension" \
+            -c "found ecjpake_kkpp extension" \
+            -S "SSL - The handshake negotiation failed" \
+            -S "SSL - Verification of the message MAC failed"
+
 server_needs_more_time 1
 requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
@@ -7976,6 +8084,20 @@
             -C "re-using cached ecjpake parameters" \
             -s "SSL - Verification of the message MAC failed"
 
+server_needs_more_time 1
+requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED
+requires_config_enabled MBEDTLS_USE_PSA_CRYPTO
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test    "ECJPAKE_OPAQUE_PW: opaque password mismatch, TLS" \
+            "$P_SRV debug_level=3 ecjpake_pw=bla ecjpake_pw_opaque=1" \
+            "$P_CLI debug_level=3 ecjpake_pw=bad ecjpake_pw_opaque=1 \
+             force_ciphersuite=TLS-ECJPAKE-WITH-AES-128-CCM-8" \
+            1 \
+            -c "using opaque password" \
+            -s "using opaque password" \
+            -C "re-using cached ecjpake parameters" \
+            -s "SSL - Verification of the message MAC failed"
+
 requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 run_test    "ECJPAKE: working, DTLS" \
@@ -8356,10 +8478,12 @@
             -C "mbedtls_ecdh_make_public.*4b00" \
             -C "mbedtls_pk_sign.*4b00"
 
+# With USE_PSA disabled we expect full restartable behaviour.
 requires_config_enabled MBEDTLS_ECP_RESTARTABLE
 requires_config_enabled MBEDTLS_ECP_DP_SECP256R1_ENABLED
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-run_test    "EC restart: TLS, max_ops=1000" \
+requires_config_disabled MBEDTLS_USE_PSA_CRYPTO
+run_test    "EC restart: TLS, max_ops=1000 (no USE_PSA)" \
             "$P_SRV curves=secp256r1 auth_mode=required" \
             "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \
              key_file=data_files/server5.key crt_file=data_files/server5.crt  \
@@ -8370,6 +8494,25 @@
             -c "mbedtls_ecdh_make_public.*4b00" \
             -c "mbedtls_pk_sign.*4b00"
 
+# With USE_PSA enabled we expect only partial restartable behaviour:
+# everything except ECDH (where TLS calls PSA directly).
+requires_config_enabled MBEDTLS_ECP_RESTARTABLE
+requires_config_enabled MBEDTLS_ECP_DP_SECP256R1_ENABLED
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+requires_config_enabled MBEDTLS_USE_PSA_CRYPTO
+run_test    "EC restart: TLS, max_ops=1000 (USE_PSA)" \
+            "$P_SRV curves=secp256r1 auth_mode=required" \
+            "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \
+             key_file=data_files/server5.key crt_file=data_files/server5.crt  \
+             debug_level=1 ec_max_ops=1000" \
+            0 \
+            -c "x509_verify_cert.*4b00" \
+            -c "mbedtls_pk_verify.*4b00" \
+            -C "mbedtls_ecdh_make_public.*4b00" \
+            -c "mbedtls_pk_sign.*4b00"
+
+# This works the same with & without USE_PSA as we never get to ECDH:
+# we abort as soon as we determined the cert is bad.
 requires_config_enabled MBEDTLS_ECP_RESTARTABLE
 requires_config_enabled MBEDTLS_ECP_DP_SECP256R1_ENABLED
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
@@ -8389,10 +8532,12 @@
             -c "! mbedtls_ssl_handshake returned" \
             -c "X509 - Certificate verification failed"
 
+# With USE_PSA disabled we expect full restartable behaviour.
 requires_config_enabled MBEDTLS_ECP_RESTARTABLE
 requires_config_enabled MBEDTLS_ECP_DP_SECP256R1_ENABLED
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-run_test    "EC restart: TLS, max_ops=1000, auth_mode=optional badsign" \
+requires_config_disabled MBEDTLS_USE_PSA_CRYPTO
+run_test    "EC restart: TLS, max_ops=1000, auth_mode=optional badsign (no USE_PSA)" \
             "$P_SRV curves=secp256r1 auth_mode=required \
              crt_file=data_files/server5-badsign.crt \
              key_file=data_files/server5.key" \
@@ -8408,10 +8553,34 @@
             -C "! mbedtls_ssl_handshake returned" \
             -C "X509 - Certificate verification failed"
 
+# With USE_PSA enabled we expect only partial restartable behaviour:
+# everything except ECDH (where TLS calls PSA directly).
 requires_config_enabled MBEDTLS_ECP_RESTARTABLE
 requires_config_enabled MBEDTLS_ECP_DP_SECP256R1_ENABLED
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-run_test    "EC restart: TLS, max_ops=1000, auth_mode=none badsign" \
+requires_config_enabled MBEDTLS_USE_PSA_CRYPTO
+run_test    "EC restart: TLS, max_ops=1000, auth_mode=optional badsign (USE_PSA)" \
+            "$P_SRV curves=secp256r1 auth_mode=required \
+             crt_file=data_files/server5-badsign.crt \
+             key_file=data_files/server5.key" \
+            "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \
+             key_file=data_files/server5.key crt_file=data_files/server5.crt  \
+             debug_level=1 ec_max_ops=1000 auth_mode=optional" \
+            0 \
+            -c "x509_verify_cert.*4b00" \
+            -c "mbedtls_pk_verify.*4b00" \
+            -C "mbedtls_ecdh_make_public.*4b00" \
+            -c "mbedtls_pk_sign.*4b00" \
+            -c "! The certificate is not correctly signed by the trusted CA" \
+            -C "! mbedtls_ssl_handshake returned" \
+            -C "X509 - Certificate verification failed"
+
+# With USE_PSA disabled we expect full restartable behaviour.
+requires_config_enabled MBEDTLS_ECP_RESTARTABLE
+requires_config_enabled MBEDTLS_ECP_DP_SECP256R1_ENABLED
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+requires_config_disabled MBEDTLS_USE_PSA_CRYPTO
+run_test    "EC restart: TLS, max_ops=1000, auth_mode=none badsign (no USE_PSA)" \
             "$P_SRV curves=secp256r1 auth_mode=required \
              crt_file=data_files/server5-badsign.crt \
              key_file=data_files/server5.key" \
@@ -8427,10 +8596,34 @@
             -C "! mbedtls_ssl_handshake returned" \
             -C "X509 - Certificate verification failed"
 
+# With USE_PSA enabled we expect only partial restartable behaviour:
+# everything except ECDH (where TLS calls PSA directly).
 requires_config_enabled MBEDTLS_ECP_RESTARTABLE
 requires_config_enabled MBEDTLS_ECP_DP_SECP256R1_ENABLED
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-run_test    "EC restart: DTLS, max_ops=1000" \
+requires_config_enabled MBEDTLS_USE_PSA_CRYPTO
+run_test    "EC restart: TLS, max_ops=1000, auth_mode=none badsign (USE_PSA)" \
+            "$P_SRV curves=secp256r1 auth_mode=required \
+             crt_file=data_files/server5-badsign.crt \
+             key_file=data_files/server5.key" \
+            "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \
+             key_file=data_files/server5.key crt_file=data_files/server5.crt  \
+             debug_level=1 ec_max_ops=1000 auth_mode=none" \
+            0 \
+            -C "x509_verify_cert.*4b00" \
+            -c "mbedtls_pk_verify.*4b00" \
+            -C "mbedtls_ecdh_make_public.*4b00" \
+            -c "mbedtls_pk_sign.*4b00" \
+            -C "! The certificate is not correctly signed by the trusted CA" \
+            -C "! mbedtls_ssl_handshake returned" \
+            -C "X509 - Certificate verification failed"
+
+# With USE_PSA disabled we expect full restartable behaviour.
+requires_config_enabled MBEDTLS_ECP_RESTARTABLE
+requires_config_enabled MBEDTLS_ECP_DP_SECP256R1_ENABLED
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+requires_config_disabled MBEDTLS_USE_PSA_CRYPTO
+run_test    "EC restart: DTLS, max_ops=1000 (no USE_PSA)" \
             "$P_SRV curves=secp256r1 auth_mode=required dtls=1" \
             "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \
              key_file=data_files/server5.key crt_file=data_files/server5.crt  \
@@ -8441,10 +8634,29 @@
             -c "mbedtls_ecdh_make_public.*4b00" \
             -c "mbedtls_pk_sign.*4b00"
 
+# With USE_PSA enabled we expect only partial restartable behaviour:
+# everything except ECDH (where TLS calls PSA directly).
 requires_config_enabled MBEDTLS_ECP_RESTARTABLE
 requires_config_enabled MBEDTLS_ECP_DP_SECP256R1_ENABLED
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-run_test    "EC restart: TLS, max_ops=1000 no client auth" \
+requires_config_enabled MBEDTLS_USE_PSA_CRYPTO
+run_test    "EC restart: DTLS, max_ops=1000 (USE_PSA)" \
+            "$P_SRV curves=secp256r1 auth_mode=required dtls=1" \
+            "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \
+             key_file=data_files/server5.key crt_file=data_files/server5.crt  \
+             dtls=1 debug_level=1 ec_max_ops=1000" \
+            0 \
+            -c "x509_verify_cert.*4b00" \
+            -c "mbedtls_pk_verify.*4b00" \
+            -C "mbedtls_ecdh_make_public.*4b00" \
+            -c "mbedtls_pk_sign.*4b00"
+
+# With USE_PSA disabled we expect full restartable behaviour.
+requires_config_enabled MBEDTLS_ECP_RESTARTABLE
+requires_config_enabled MBEDTLS_ECP_DP_SECP256R1_ENABLED
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+requires_config_disabled MBEDTLS_USE_PSA_CRYPTO
+run_test    "EC restart: TLS, max_ops=1000 no client auth (no USE_PSA)" \
             "$P_SRV curves=secp256r1" \
             "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \
              debug_level=1 ec_max_ops=1000" \
@@ -8454,13 +8666,35 @@
             -c "mbedtls_ecdh_make_public.*4b00" \
             -C "mbedtls_pk_sign.*4b00"
 
+
+# With USE_PSA enabled we expect only partial restartable behaviour:
+# everything except ECDH (where TLS calls PSA directly).
 requires_config_enabled MBEDTLS_ECP_RESTARTABLE
 requires_config_enabled MBEDTLS_ECP_DP_SECP256R1_ENABLED
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-run_test    "EC restart: TLS, max_ops=1000, ECDHE-PSK" \
-            "$P_SRV curves=secp256r1 psk=abc123" \
-            "$P_CLI force_ciphersuite=TLS-ECDHE-PSK-WITH-AES-128-CBC-SHA256 \
-             psk=abc123 debug_level=1 ec_max_ops=1000" \
+requires_config_enabled MBEDTLS_USE_PSA_CRYPTO
+run_test    "EC restart: TLS, max_ops=1000 no client auth (USE_PSA)" \
+            "$P_SRV curves=secp256r1" \
+            "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \
+             debug_level=1 ec_max_ops=1000" \
+            0 \
+            -c "x509_verify_cert.*4b00" \
+            -c "mbedtls_pk_verify.*4b00" \
+            -C "mbedtls_ecdh_make_public.*4b00" \
+            -C "mbedtls_pk_sign.*4b00"
+
+# Restartable is only for ECDHE-ECDSA, with another ciphersuite we expect no
+# restartable behaviour at all (not even client auth).
+# This is the same as "EC restart: TLS, max_ops=1000" except with ECDHE-RSA,
+# and all 4 assertions negated.
+requires_config_enabled MBEDTLS_ECP_RESTARTABLE
+requires_config_enabled MBEDTLS_ECP_DP_SECP256R1_ENABLED
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test    "EC restart: TLS, max_ops=1000, ECDHE-RSA" \
+            "$P_SRV curves=secp256r1 auth_mode=required" \
+            "$P_CLI force_ciphersuite=TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256 \
+             key_file=data_files/server5.key crt_file=data_files/server5.crt  \
+             debug_level=1 ec_max_ops=1000" \
             0 \
             -C "x509_verify_cert.*4b00" \
             -C "mbedtls_pk_verify.*4b00" \
@@ -12917,8 +13151,8 @@
             "$O_NEXT_CLI -msg -debug -tls1_3 -reconnect" \
             0 \
             -s "=> write NewSessionTicket msg" \
-            -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET" \
-            -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET_FLUSH"
+            -s "server state: MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET" \
+            -s "server state: MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET_FLUSH"
 
 requires_gnutls_tls1_3
 requires_config_enabled MBEDTLS_SSL_SESSION_TICKETS
@@ -12934,8 +13168,8 @@
             -c "Connecting again- trying to resume previous session" \
             -c "NEW SESSION TICKET (4) was received" \
             -s "=> write NewSessionTicket msg" \
-            -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET" \
-            -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET_FLUSH" \
+            -s "server state: MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET" \
+            -s "server state: MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET_FLUSH" \
             -s "key exchange mode: ephemeral" \
             -s "key exchange mode: psk_ephemeral" \
             -s "found pre_shared_key extension"
@@ -12957,8 +13191,8 @@
             -c "Reconnecting with saved session" \
             -c "HTTP/1.0 200 OK"    \
             -s "=> write NewSessionTicket msg" \
-            -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET" \
-            -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET_FLUSH" \
+            -s "server state: MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET" \
+            -s "server state: MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET_FLUSH" \
             -s "key exchange mode: ephemeral" \
             -s "key exchange mode: psk_ephemeral" \
             -s "found pre_shared_key extension"
@@ -13012,8 +13246,8 @@
             -c "Reconnecting with saved session" \
             -c "HTTP/1.0 200 OK"    \
             -s "=> write NewSessionTicket msg" \
-            -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET" \
-            -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET_FLUSH" \
+            -s "server state: MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET" \
+            -s "server state: MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET_FLUSH" \
             -s "key exchange mode: ephemeral" \
             -s "key exchange mode: psk_ephemeral" \
             -s "found pre_shared_key extension"
@@ -13036,8 +13270,8 @@
             -c "Reconnecting with saved session" \
             -c "Hostname mismatch the session ticket, disable session resumption."    \
             -s "=> write NewSessionTicket msg" \
-            -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET" \
-            -s "server state: MBEDTLS_SSL_NEW_SESSION_TICKET_FLUSH"
+            -s "server state: MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET" \
+            -s "server state: MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET_FLUSH"
 
 # Test heap memory usage after handshake
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
diff --git a/tests/suites/helpers.function b/tests/suites/helpers.function
index fe33f9b..8249564 100644
--- a/tests/suites/helpers.function
+++ b/tests/suites/helpers.function
@@ -5,6 +5,7 @@
 #include <test/helpers.h>
 #include <test/macros.h>
 #include <test/random.h>
+#include <test/bignum_helpers.h>
 #include <test/psa_crypto_helpers.h>
 
 #include <stdlib.h>
diff --git a/tests/suites/test_suite_alignment.data b/tests/suites/test_suite_alignment.data
new file mode 100644
index 0000000..8c0c21d
--- /dev/null
+++ b/tests/suites/test_suite_alignment.data
@@ -0,0 +1,119 @@
+Aligned 16-bit access
+mbedtls_unaligned_access:16:0
+
+Aligned 32-bit access
+mbedtls_unaligned_access:32:0
+
+Aligned 64-bit access
+mbedtls_unaligned_access:64:0
+
+Unaligned 16-bit access offset=1
+mbedtls_unaligned_access:16:1
+
+Unaligned 32-bit access offset=1
+mbedtls_unaligned_access:32:1
+
+Unaligned 64-bit access offset=1
+mbedtls_unaligned_access:64:1
+
+Unaligned 16-bit access offset=4
+mbedtls_unaligned_access:16:4
+
+Unaligned 32-bit access offset=4
+mbedtls_unaligned_access:32:4
+
+Unaligned 64-bit access offset=4
+mbedtls_unaligned_access:64:4
+
+Unaligned 16-bit access offset=7
+mbedtls_unaligned_access:16:7
+
+Unaligned 32-bit access offset=7
+mbedtls_unaligned_access:32:7
+
+Unaligned 64-bit access offset=7
+mbedtls_unaligned_access:64:7
+
+Unaligned 16-bit access offset=8
+mbedtls_unaligned_access:16:8
+
+Unaligned 32-bit access offset=8
+mbedtls_unaligned_access:32:8
+
+Unaligned 64-bit access offset=8
+mbedtls_unaligned_access:64:8
+
+Byteswap 16
+mbedtls_byteswap:"0100":16:"0001"
+
+Byteswap 16 with truncation
+mbedtls_byteswap:"0706050403020100":16:"0001"
+
+Byteswap 16 all-zero
+mbedtls_byteswap:"0000":16:"0000"
+
+Byteswap 16 all-ones
+mbedtls_byteswap:"ffffffffffffffff":16:"ffff"
+
+Byteswap 32
+mbedtls_byteswap:"03020100":32:"00010203"
+
+Byteswap 32 with truncation
+mbedtls_byteswap:"0706050403020100":32:"00010203"
+
+Byteswap 32 all-zero
+mbedtls_byteswap:"00000000":32:"00000000"
+
+Byteswap 32 all-ones
+mbedtls_byteswap:"ffffffffffffffff":32:"ffffffff"
+
+Byteswap 64
+mbedtls_byteswap:"0706050403020100":64:"01020304050607"
+
+Byteswap 64 all-zero
+mbedtls_byteswap:"0000000000000000":64:"0000000000000000"
+
+Byteswap 64 all-ones
+mbedtls_byteswap:"ffffffffffffffff":64:"ffffffffffffffff"
+
+Get individual bytes
+get_byte
+
+Endian-aware unaligned 16-bit BE offset=0
+unaligned_access_endian_aware:16:0:1
+
+Endian-aware unaligned 16-bit BE offset=3
+unaligned_access_endian_aware:16:3:1
+
+Endian-aware unaligned 16-bit LE offset=0
+unaligned_access_endian_aware:16:0:0
+
+Endian-aware unaligned 16-bit LE offset=3
+unaligned_access_endian_aware:16:3:0
+
+Endian-aware unaligned 32-bit BE offset=0
+unaligned_access_endian_aware:32:0:1
+
+Endian-aware unaligned 32-bit BE offset=3
+unaligned_access_endian_aware:32:3:1
+
+Endian-aware unaligned 32-bit LE offset=0
+unaligned_access_endian_aware:32:0:0
+
+Endian-aware unaligned 32-bit LE offset=3
+unaligned_access_endian_aware:32:3:0
+
+Endian-aware unaligned 64-bit BE offset=0
+unaligned_access_endian_aware:64:0:1
+
+Endian-aware unaligned 64-bit BE offset=3
+unaligned_access_endian_aware:64:3:1
+
+Endian-aware unaligned 64-bit LE offset=0
+unaligned_access_endian_aware:64:0:0
+
+Endian-aware unaligned 64-bit LE offset=3
+unaligned_access_endian_aware:64:3:0
+
+Big-endian check
+mbedtls_is_big_endian
diff --git a/tests/suites/test_suite_alignment.function b/tests/suites/test_suite_alignment.function
new file mode 100644
index 0000000..06c5668
--- /dev/null
+++ b/tests/suites/test_suite_alignment.function
@@ -0,0 +1,407 @@
+/* BEGIN_HEADER */
+#include "../library/alignment.h"
+
+#include <stdint.h>
+
+#if defined(__clang__)
+#pragma clang diagnostic ignored "-Wunreachable-code"
+#endif
+#include <stdio.h>
+
+/*
+ * Convert a string of the form "abcd" (case-insensitive) to a uint64_t.
+ */
+int parse_hex_string( char* hex_string, uint64_t *result )
+{
+    uint8_t raw[8];
+    size_t olen;
+    if ( mbedtls_test_unhexify(raw, sizeof(raw), hex_string, &olen) != 0 ) return 0;
+    *result = 0;
+    for ( size_t i = 0; i < olen; i++ )
+    {
+        if ( MBEDTLS_IS_BIG_ENDIAN ) {
+            *result |= ((uint64_t)raw[i]) << ( i * 8 );
+        }
+        else
+        {
+            *result |= ((uint64_t)raw[i]) << ( (olen - i - 1) * 8 );
+        }
+    }
+    return 1;
+}
+
+/* END_HEADER */
+
+/* BEGIN_CASE */
+void mbedtls_unaligned_access( int size, int offset )
+{
+    /* Define 64-bit aligned raw byte array */
+    uint64_t raw[2];
+
+    /* Populate with known data */
+    uint8_t *x = (uint8_t *) raw;
+    for ( size_t i = 0; i < sizeof(raw); i++ )
+        x[i] = (uint8_t)i;
+
+    TEST_ASSERT( size == 16 || size == 32 || size == 64 );
+
+    uint64_t r = 0;
+    switch ( size )
+    {
+        case 16:
+            r = mbedtls_get_unaligned_uint16( x + offset );
+            break;
+        case 32:
+            r = mbedtls_get_unaligned_uint32( x + offset );
+            break;
+        case 64:
+            r = mbedtls_get_unaligned_uint64( x + offset );
+            break;
+    }
+
+    /* Generate expected result */
+    uint64_t expected = 0;
+    for ( uint8_t i = 0; i < 8; i++ )
+    {
+        uint8_t shift;
+        if ( MBEDTLS_IS_BIG_ENDIAN )
+        {
+            /*
+            * Similar to little-endian case described below, but the shift needs
+            * to be inverted
+            */
+            shift = 7 - ( i * 8 );
+        } else {
+            /* example for offset == 1:
+            * expected = (( 1 + 0 ) << (0 * 8)) | (( 1 + 1 ) << (1 * 8)) | (( 1 + 2 ) << (2 * 8)))
+            *          = (1 << 0) | (2 << 8) | (3 << 16) ...
+            *          = 0x0807060504030201
+            * x = { 0, 1, 2, 3, ... }
+            * ie expected is the value that would be read from x on a LE system, when
+            * byte swapping is not performed
+            */
+            shift = i * 8;
+        }
+        uint64_t b = offset + i;
+        expected |= b << shift;
+    }
+
+    /* Mask out excess bits from expected result */
+    switch ( size )
+    {
+        case 16:
+            expected &= 0xffff;
+            break;
+        case 32:
+            expected &= 0xffffffff;
+            break;
+    }
+
+    TEST_EQUAL( r, expected );
+
+    /* Write sentinel to the part of the array we will testing writing to */
+    for ( size_t i = 0; i < (size_t) ( size / 8 ); i++ )
+    {
+        x[i + offset] = 0xff;
+    }
+    /*
+        * Write back to the array with mbedtls_put_unaligned_uint16 and validate
+        * that the array is unchanged as a result.
+        */
+    switch ( size )
+    {
+        case 16:
+            mbedtls_put_unaligned_uint16( x + offset, r );
+            break;
+        case 32:
+            mbedtls_put_unaligned_uint32( x + offset, r );
+            break;
+        case 64:
+            mbedtls_put_unaligned_uint64( x + offset, r );
+            break;
+    }
+    for ( size_t i = 0; i < sizeof(x); i++ )
+    {
+        TEST_EQUAL( x[i], (uint8_t)i );
+    }
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mbedtls_byteswap( char* input_str, int size, char *expected_str )
+{
+    uint64_t input, expected;
+    TEST_ASSERT( parse_hex_string( input_str, &input ) );
+    TEST_ASSERT( parse_hex_string( expected_str, &expected ) );
+
+    /* Check against expected result */
+    uint64_t r = 0;
+    switch ( size )
+    {
+        case 16:
+            r = MBEDTLS_BSWAP16( input );
+            break;
+        case 32:
+            r = MBEDTLS_BSWAP32( input );
+            break;
+        case 64:
+            r = MBEDTLS_BSWAP64( input );
+            break;
+        default:
+            TEST_ASSERT( ! "size must be 16, 32 or 64" );
+    }
+    TEST_EQUAL( r, expected );
+
+    /*
+     * Check byte by byte by extracting bytes from opposite ends of
+     * input and r.
+     */
+    for ( size_t i = 0; i < (size_t)( size / 8 ); i++ )
+    {
+        size_t s1 = i * 8;
+        size_t s2 = ( ( size / 8 - 1 ) - i ) * 8;
+        uint64_t a = ( input & ( (uint64_t)0xff << s1 ) ) >> s1;
+        uint64_t b = ( r & ( (uint64_t)0xff << s2 ) ) >> s2;
+        TEST_EQUAL( a, b );
+    }
+
+    /* Check BSWAP(BSWAP(x)) == x */
+    switch ( size )
+    {
+        case 16:
+            r = MBEDTLS_BSWAP16( r );
+            TEST_EQUAL( r, input & 0xffff );
+            break;
+        case 32:
+            r = MBEDTLS_BSWAP32( r );
+            TEST_EQUAL( r, input & 0xffffffff );
+            break;
+        case 64:
+            r = MBEDTLS_BSWAP64( r );
+            TEST_EQUAL( r, input );
+            break;
+    }
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void get_byte()
+{
+    uint8_t data[16];
+
+    for ( size_t i = 0; i < sizeof(data); i++ )
+        data[i] = (uint8_t) i;
+
+    uint64_t u64 = 0x0706050403020100;
+    for ( size_t b = 0; b < 8 ; b++ )
+    {
+        uint8_t expected = b;
+        uint8_t actual = b + 1;
+        switch ( b )
+        {
+            case 0:
+                actual = MBEDTLS_BYTE_0( u64 );
+                break;
+            case 1:
+                actual = MBEDTLS_BYTE_1( u64 );
+                break;
+            case 2:
+                actual = MBEDTLS_BYTE_2( u64 );
+                break;
+            case 3:
+                actual = MBEDTLS_BYTE_3( u64 );
+                break;
+            case 4:
+                actual = MBEDTLS_BYTE_4( u64 );
+                break;
+            case 5:
+                actual = MBEDTLS_BYTE_5( u64 );
+                break;
+            case 6:
+                actual = MBEDTLS_BYTE_6( u64 );
+                break;
+            case 7:
+                actual = MBEDTLS_BYTE_7( u64 );
+                break;
+        }
+        TEST_EQUAL( actual, expected );
+    }
+
+    uint32_t u32 = 0x03020100;
+    for ( size_t b = 0; b < 4 ; b++ )
+    {
+        uint8_t expected = b;
+        uint8_t actual = b + 1;
+        switch ( b )
+        {
+            case 0:
+                actual = MBEDTLS_BYTE_0( u32 );
+                break;
+            case 1:
+                actual = MBEDTLS_BYTE_1( u32 );
+                break;
+            case 2:
+                actual = MBEDTLS_BYTE_2( u32 );
+                break;
+            case 3:
+                actual = MBEDTLS_BYTE_3( u32 );
+                break;
+        }
+        TEST_EQUAL( actual, expected );
+    }
+
+    uint16_t u16 = 0x0100;
+    for ( size_t b = 0; b < 2 ; b++ )
+    {
+        uint8_t expected = b;
+        uint8_t actual = b + 1;
+        switch ( b )
+        {
+            case 0:
+                actual = MBEDTLS_BYTE_0( u16 );
+                break;
+            case 1:
+                actual = MBEDTLS_BYTE_1( u16 );
+                break;
+        }
+        TEST_EQUAL( actual, expected );
+    }
+
+    uint8_t u8 = 0x01;
+    uint8_t actual = MBEDTLS_BYTE_0( u8 );
+    TEST_EQUAL( actual, u8 );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void unaligned_access_endian_aware(int size, int offset, int big_endian )
+{
+    TEST_ASSERT( size == 16 || size == 24 || size == 32 || size == 64 );
+    TEST_ASSERT( offset >= 0 && offset < 8 );
+
+    /* Define 64-bit aligned raw byte array */
+    uint64_t raw[2];
+    /* Populate with known data: x == { 0, 1, 2, ... } */
+    uint8_t *x = (uint8_t *) raw;
+    for ( size_t i = 0; i < sizeof(raw); i++ )
+        x[i] = (uint8_t) i;
+
+    uint64_t read = 0;
+    if ( big_endian )
+    {
+        switch ( size )
+        {
+            case 16:
+                read = MBEDTLS_GET_UINT16_BE( x, offset );
+                break;
+            case 24:
+                read = MBEDTLS_GET_UINT24_BE( x, offset );
+                break;
+            case 32:
+                read = MBEDTLS_GET_UINT32_BE( x, offset );
+                break;
+            case 64:
+                read = MBEDTLS_GET_UINT64_BE( x, offset );
+                break;
+        }
+    }
+    else
+    {
+        switch ( size )
+        {
+            case 16:
+                read = MBEDTLS_GET_UINT16_LE( x, offset );
+                break;
+            case 24:
+                read = MBEDTLS_GET_UINT24_LE( x, offset );
+                break;
+            case 32:
+                read = MBEDTLS_GET_UINT32_LE( x, offset );
+                break;
+            case 64:
+                read = MBEDTLS_GET_UINT64_LE( x, offset );
+                break;
+        }
+    }
+
+    /* Build up expected value byte by byte, in either big or little endian format */
+    uint64_t expected = 0;
+    for ( size_t i = 0; i < (size_t)(size / 8); i++ )
+    {
+        uint64_t b = x[i + offset];
+        uint8_t shift = (big_endian) ? (8 * ((size / 8 - 1) - i)) : (8 * i);
+        expected |= b << shift;
+    }
+
+    /* Verify read */
+    TEST_EQUAL( read, expected );
+
+    /* Test writing back to memory. First write sentiel */
+    for ( size_t i = 0; i < (size_t)(size / 8); i++ )
+    {
+        x[i + offset] = 0xff;
+    }
+    /* Overwrite sentinel with endian-aware write macro */
+    if ( big_endian )
+    {
+        switch ( size )
+        {
+            case 16:
+                MBEDTLS_PUT_UINT16_BE( read, x, offset );
+                break;
+            case 24:
+                MBEDTLS_PUT_UINT24_BE( read, x, offset );
+                break;
+            case 32:
+                MBEDTLS_PUT_UINT32_BE( read, x, offset );
+                break;
+            case 64:
+                MBEDTLS_PUT_UINT64_BE( read, x, offset );
+                break;
+        }
+    }
+    else
+    {
+        switch ( size )
+        {
+            case 16:
+                MBEDTLS_PUT_UINT16_LE( read, x, offset );
+                break;
+                case 24:
+                MBEDTLS_PUT_UINT24_LE( read, x, offset );
+                break;
+            case 32:
+                MBEDTLS_PUT_UINT32_LE( read, x, offset );
+                break;
+            case 64:
+                MBEDTLS_PUT_UINT64_LE( read, x, offset );
+                break;
+        }
+    }
+
+    /* Verify write - check memory is correct */
+    for ( size_t i = 0; i < sizeof(raw); i++ )
+        TEST_EQUAL( x[i], (uint8_t) i );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mbedtls_is_big_endian()
+{
+    uint16_t check = 0x1234;
+    uint8_t* p = (uint8_t*) &check;
+
+    if ( MBEDTLS_IS_BIG_ENDIAN )
+    {
+        /* Big-endian: data stored MSB first, i.e. p == { 0x12, 0x34 } */
+        TEST_EQUAL( p[0], 0x12 );
+        TEST_EQUAL( p[1], 0x34 );
+    }
+    else
+    {
+        /* Little-endian: data stored LSB first, i.e. p == { 0x34, 0x12 } */
+        TEST_EQUAL( p[0], 0x34 );
+        TEST_EQUAL( p[1], 0x12 );
+    }
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_bignum.function b/tests/suites/test_suite_bignum.function
index 4cec0a7..01af2ff 100644
--- a/tests/suites/test_suite_bignum.function
+++ b/tests/suites/test_suite_bignum.function
@@ -2,6 +2,7 @@
 #include "mbedtls/bignum.h"
 #include "mbedtls/entropy.h"
 #include "constant_time_internal.h"
+#include "bignum_core.h"
 #include "test/constant_flow.h"
 
 #if MBEDTLS_MPI_MAX_BITS > 792
@@ -13,10 +14,21 @@
  * constructing the value. */
 static int sign_is_valid( const mbedtls_mpi *X )
 {
+    /* Only +1 and -1 are valid sign bits, not e.g. 0 */
     if( X->s != 1 && X->s != -1 )
-        return( 0 ); // invalid sign bit, e.g. 0
-    if( mbedtls_mpi_bitlen( X ) == 0 && X->s != 1 )
-        return( 0 ); // negative zero
+        return( 0 );
+
+    /* The value 0 must be represented with the sign +1. A "negative zero"
+     * with s=-1 is an invalid representation. Forbid that. As an exception,
+     * we sometimes test the robustness of library functions when given
+     * a negative zero input. If a test case has a negative zero as input,
+     * we don't mind if the function has a negative zero output. */
+    if( ! mbedtls_test_case_uses_negative_0 &&
+        mbedtls_mpi_bitlen( X ) == 0 && X->s != 1 )
+    {
+        return( 0 );
+    }
+
     return( 1 );
 }
 
@@ -78,50 +90,6 @@
     return( 0 );
 }
 
-/* Test whether bytes represents (in big-endian base 256) a number b that
- * is significantly above a power of 2. That is, b must not have a long run
- * of unset bits after the most significant bit.
- *
- * Let n be the bit-size of b, i.e. the integer such that 2^n <= b < 2^{n+1}.
- * This function returns 1 if, when drawing a number between 0 and b,
- * the probability that this number is at least 2^n is not negligible.
- * This probability is (b - 2^n) / b and this function checks that this
- * number is above some threshold A. The threshold value is heuristic and
- * based on the needs of mpi_random_many().
- */
-static int is_significantly_above_a_power_of_2( data_t *bytes )
-{
-    const uint8_t *p = bytes->x;
-    size_t len = bytes->len;
-    unsigned x;
-
-    /* Skip leading null bytes */
-    while( len > 0 && p[0] == 0 )
-    {
-        ++p;
-        --len;
-    }
-    /* 0 is not significantly above a power of 2 */
-    if( len == 0 )
-        return( 0 );
-    /* Extract the (up to) 2 most significant bytes */
-    if( len == 1 )
-        x = p[0];
-    else
-        x = ( p[0] << 8 ) | p[1];
-
-    /* Shift the most significant bit of x to position 8 and mask it out */
-    while( ( x & 0xfe00 ) != 0 )
-        x >>= 1;
-    x &= 0x00ff;
-
-    /* At this point, x = floor((b - 2^n) / 2^(n-8)). b is significantly above
-     * a power of 2 iff x is significantly above 0 compared to 2^8.
-     * Testing x >= 2^4 amounts to picking A = 1/16 in the function
-     * description above. */
-    return( x >= 0x10 );
-}
-
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
@@ -959,24 +927,57 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
-void mpi_mod_int( char * input_X, int input_Y,
-                  int input_A, int div_result )
+void mpi_mod_int( char * input_X, char * input_Y,
+                  char * input_A, int mod_result )
 {
     mbedtls_mpi X;
+    mbedtls_mpi Y;
+    mbedtls_mpi A;
     int res;
     mbedtls_mpi_uint r;
-    mbedtls_mpi_init( &X );
 
-    TEST_ASSERT( mbedtls_test_read_mpi( &X, input_X ) == 0 );
-    res = mbedtls_mpi_mod_int( &r, &X, input_Y );
-    TEST_ASSERT( res == div_result );
+    mbedtls_mpi_init( &X );
+    mbedtls_mpi_init( &Y );
+    mbedtls_mpi_init( &A );
+
+    /* We use MPIs to read Y and A since the test framework limits us to
+     * ints, so we can't have 64-bit values */
+    TEST_EQUAL( mbedtls_test_read_mpi( &X, input_X ), 0 );
+    TEST_EQUAL( mbedtls_test_read_mpi( &Y, input_Y ), 0 );
+    TEST_EQUAL( mbedtls_test_read_mpi( &A, input_A ), 0 );
+
+    TEST_EQUAL( Y.n, 1 );
+    TEST_EQUAL( A.n, 1 );
+
+    /* Convert the MPIs for Y and A to (signed) mbedtls_mpi_sints */
+
+    /* Since we're converting sign+magnitude to two's complement, we lose one
+     * bit of value in the output. This means there are some values we can't
+     * represent, e.g. (hex) -A0000000 on 32-bit systems. These are technically
+     * invalid test cases, so could be considered "won't happen", but they are
+     * easy to test for, and this helps guard against human error. */
+
+    mbedtls_mpi_sint y = (mbedtls_mpi_sint) Y.p[0];
+    TEST_ASSERT( y >= 0 );      /* If y < 0 here, we can't make negative y */
+    if( Y.s == -1 )
+        y = -y;
+
+    mbedtls_mpi_sint a = (mbedtls_mpi_sint) A.p[0];
+    TEST_ASSERT( a >= 0 );      /* Same goes for a */
+    if( A.s == -1 )
+        a = -a;
+
+    res = mbedtls_mpi_mod_int( &r, &X, y );
+    TEST_EQUAL( res, mod_result );
     if( res == 0 )
     {
-        TEST_ASSERT( r == (mbedtls_mpi_uint) input_A );
+        TEST_EQUAL( r, a );
     }
 
 exit:
     mbedtls_mpi_free( &X );
+    mbedtls_mpi_free( &Y );
+    mbedtls_mpi_free( &A );
 }
 /* END_CASE */
 
@@ -1251,166 +1252,145 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
-void mpi_random_many( int min, data_t *bound_bytes, int iterations )
+void most_negative_mpi_sint( )
 {
-    /* Generate numbers in the range 1..bound-1. Do it iterations times.
-     * This function assumes that the value of bound is at least 2 and
-     * that iterations is large enough that a one-in-2^iterations chance
-     * effectively never occurs.
+    /* Ad hoc tests for n = -p = -2^(biL-1) as a mbedtls_mpi_sint. We
+     * guarantee that mbedtls_mpi_sint is a two's complement type, so this
+     * is a valid value. However, negating it (`-n`) has undefined behavior
+     * (although in practice `-n` evaluates to the value n).
+     *
+     * This function has ad hoc tests for this value. It's separated from other
+     * functions because the test framework makes it hard to pass this value
+     * into test cases.
+     *
+     * In the comments here:
+     * - biL = number of bits in limbs
+     * - p = 2^(biL-1) (smallest positive value not in mbedtls_mpi_sint range)
+     * - n = -2^(biL-1) (largest negative value in mbedtls_mpi_sint range)
      */
 
-    mbedtls_mpi upper_bound;
-    size_t n_bits;
-    mbedtls_mpi result;
-    size_t b;
-    /* If upper_bound is small, stats[b] is the number of times the value b
-     * has been generated. Otherwise stats[b] is the number of times a
-     * value with bit b set has been generated. */
-    size_t *stats = NULL;
-    size_t stats_len;
-    int full_stats;
-    size_t i;
+    mbedtls_mpi A, R, X;
+    mbedtls_mpi_init( &A );
+    mbedtls_mpi_init( &R );
+    mbedtls_mpi_init( &X );
 
-    mbedtls_mpi_init( &upper_bound );
-    mbedtls_mpi_init( &result );
+    mbedtls_mpi_uint most_positive_plus_1 = (mbedtls_mpi_uint) 1 << ( biL - 1 );
+    const mbedtls_mpi_sint most_positive = most_positive_plus_1 - 1;
+    const mbedtls_mpi_sint most_negative = - most_positive - 1;
+    TEST_EQUAL( (mbedtls_mpi_uint) most_negative,
+                (mbedtls_mpi_uint) 1 << ( biL - 1 ) );
+    TEST_EQUAL( (mbedtls_mpi_uint) most_negative << 1, 0 );
 
-    TEST_EQUAL( 0, mbedtls_mpi_read_binary( &upper_bound,
-                                            bound_bytes->x, bound_bytes->len ) );
-    n_bits = mbedtls_mpi_bitlen( &upper_bound );
-    /* Consider a bound "small" if it's less than 2^5. This value is chosen
-     * to be small enough that the probability of missing one value is
-     * negligible given the number of iterations. It must be less than
-     * 256 because some of the code below assumes that "small" values
-     * fit in a byte. */
-    if( n_bits <= 5 )
-    {
-        full_stats = 1;
-        stats_len = bound_bytes->x[bound_bytes->len - 1];
-    }
-    else
-    {
-        full_stats = 0;
-        stats_len = n_bits;
-    }
-    ASSERT_ALLOC( stats, stats_len );
+    /* Test mbedtls_mpi_lset() */
+    TEST_EQUAL( mbedtls_mpi_lset( &A, most_negative ), 0 );
+    TEST_EQUAL( A.s, -1 );
+    TEST_EQUAL( A.n, 1 );
+    TEST_EQUAL( A.p[0], most_positive_plus_1 );
 
-    for( i = 0; i < (size_t) iterations; i++ )
-    {
-        mbedtls_test_set_step( i );
-        TEST_EQUAL( 0, mbedtls_mpi_random( &result, min, &upper_bound,
-                                           mbedtls_test_rnd_std_rand, NULL ) );
+    /* Test mbedtls_mpi_cmp_int(): -p == -p */
+    TEST_EQUAL( mbedtls_mpi_cmp_int( &A, most_negative ), 0 );
 
-        TEST_ASSERT( sign_is_valid( &result ) );
-        TEST_ASSERT( mbedtls_mpi_cmp_mpi( &result, &upper_bound ) < 0 );
-        TEST_ASSERT( mbedtls_mpi_cmp_int( &result, min ) >= 0 );
-        if( full_stats )
-        {
-            uint8_t value;
-            TEST_EQUAL( 0, mbedtls_mpi_write_binary( &result, &value, 1 ) );
-            TEST_ASSERT( value < stats_len );
-            ++stats[value];
-        }
-        else
-        {
-            for( b = 0; b < n_bits; b++ )
-                stats[b] += mbedtls_mpi_get_bit( &result, b );
-        }
-    }
+    /* Test mbedtls_mpi_cmp_int(): -(p+1) < -p */
+    A.p[0] = most_positive_plus_1 + 1;
+    TEST_EQUAL( mbedtls_mpi_cmp_int( &A, most_negative ), -1 );
 
-    if( full_stats )
-    {
-        for( b = min; b < stats_len; b++ )
-        {
-            mbedtls_test_set_step( 1000000 + b );
-            /* Assert that each value has been reached at least once.
-             * This is almost guaranteed if the iteration count is large
-             * enough. This is a very crude way of checking the distribution.
-             */
-            TEST_ASSERT( stats[b] > 0 );
-        }
-    }
-    else
-    {
-        int statistically_safe_all_the_way =
-            is_significantly_above_a_power_of_2( bound_bytes );
-        for( b = 0; b < n_bits; b++ )
-        {
-            mbedtls_test_set_step( 1000000 + b );
-            /* Assert that each bit has been set in at least one result and
-             * clear in at least one result. Provided that iterations is not
-             * too small, it would be extremely unlikely for this not to be
-             * the case if the results are uniformly distributed.
-             *
-             * As an exception, the top bit may legitimately never be set
-             * if bound is a power of 2 or only slightly above.
-             */
-            if( statistically_safe_all_the_way || b != n_bits - 1 )
-            {
-                TEST_ASSERT( stats[b] > 0 );
-            }
-            TEST_ASSERT( stats[b] < (size_t) iterations );
-        }
-    }
+    /* Test mbedtls_mpi_cmp_int(): -(p-1) > -p */
+    A.p[0] = most_positive_plus_1 - 1;
+    TEST_EQUAL( mbedtls_mpi_cmp_int( &A, most_negative ), 1 );
+
+    /* Test mbedtls_mpi_add_int(): (p-1) + (-p) */
+    TEST_EQUAL( mbedtls_mpi_lset( &A, most_positive ), 0 );
+    TEST_EQUAL( mbedtls_mpi_add_int( &X, &A, most_negative ), 0 );
+    TEST_EQUAL( mbedtls_mpi_cmp_int( &X, -1 ), 0 );
+
+    /* Test mbedtls_mpi_add_int(): (0) + (-p) */
+    TEST_EQUAL( mbedtls_mpi_lset( &A, 0 ), 0 );
+    TEST_EQUAL( mbedtls_mpi_add_int( &X, &A, most_negative ), 0 );
+    TEST_EQUAL( mbedtls_mpi_cmp_int( &X, most_negative ), 0 );
+
+    /* Test mbedtls_mpi_add_int(): (-p) + (-p) */
+    TEST_EQUAL( mbedtls_mpi_lset( &A, most_negative ), 0 );
+    TEST_EQUAL( mbedtls_mpi_add_int( &X, &A, most_negative ), 0 );
+    TEST_EQUAL( X.s, -1 );
+    TEST_EQUAL( X.n, 2 );
+    TEST_EQUAL( X.p[0], 0 );
+    TEST_EQUAL( X.p[1], 1 );
+
+    /* Test mbedtls_mpi_sub_int(): (p) - (-p) */
+    mbedtls_mpi_free( &X );
+    TEST_EQUAL( mbedtls_mpi_lset( &A, most_positive ), 0 );
+    TEST_EQUAL( mbedtls_mpi_sub_int( &X, &A, most_negative ), 0 );
+    TEST_EQUAL( X.s, 1 );
+    TEST_EQUAL( X.n, 1 );
+    TEST_EQUAL( X.p[0], ~(mbedtls_mpi_uint)0 );
+
+    /* Test mbedtls_mpi_sub_int(): (0) - (-p) */
+    TEST_EQUAL( mbedtls_mpi_lset( &A, 0 ), 0 );
+    TEST_EQUAL( mbedtls_mpi_sub_int( &X, &A, most_negative ), 0 );
+    TEST_EQUAL( X.s, 1 );
+    TEST_EQUAL( X.n, 1 );
+    TEST_EQUAL( X.p[0], most_positive_plus_1 );
+
+    /* Test mbedtls_mpi_sub_int(): (-p) - (-p) */
+    TEST_EQUAL( mbedtls_mpi_lset( &A, most_negative ), 0 );
+    TEST_EQUAL( mbedtls_mpi_sub_int( &X, &A, most_negative ), 0 );
+    TEST_EQUAL( mbedtls_mpi_cmp_int( &X, 0 ), 0 );
+
+    /* Test mbedtls_mpi_div_int(): (-p+1) / (-p) */
+    TEST_EQUAL( mbedtls_mpi_lset( &A, -most_positive ), 0 );
+    TEST_EQUAL( mbedtls_mpi_div_int( &X, &R, &A, most_negative ), 0 );
+    TEST_EQUAL( mbedtls_mpi_cmp_int( &X, 0 ), 0 );
+    TEST_EQUAL( mbedtls_mpi_cmp_int( &R, -most_positive ), 0 );
+
+    /* Test mbedtls_mpi_div_int(): (-p) / (-p) */
+    TEST_EQUAL( mbedtls_mpi_lset( &A, most_negative ), 0 );
+    TEST_EQUAL( mbedtls_mpi_div_int( &X, &R, &A, most_negative ), 0 );
+    TEST_EQUAL( mbedtls_mpi_cmp_int( &X, 1 ), 0 );
+    TEST_EQUAL( mbedtls_mpi_cmp_int( &R, 0 ), 0 );
+
+    /* Test mbedtls_mpi_div_int(): (-2*p) / (-p) */
+    TEST_EQUAL( mbedtls_mpi_shift_l( &A, 1 ), 0 );
+    TEST_EQUAL( mbedtls_mpi_div_int( &X, &R, &A, most_negative ), 0 );
+    TEST_EQUAL( mbedtls_mpi_cmp_int( &X, 2 ), 0 );
+    TEST_EQUAL( mbedtls_mpi_cmp_int( &R, 0 ), 0 );
+
+    /* Test mbedtls_mpi_div_int(): (-2*p+1) / (-p) */
+    TEST_EQUAL( mbedtls_mpi_add_int( &A, &A, 1 ), 0 );
+    TEST_EQUAL( mbedtls_mpi_div_int( &X, &R, &A, most_negative ), 0 );
+    TEST_EQUAL( mbedtls_mpi_cmp_int( &X, 1 ), 0 );
+    TEST_EQUAL( mbedtls_mpi_cmp_int( &R, -most_positive ), 0 );
+
+    /* Test mbedtls_mpi_div_int(): (p-1) / (-p) */
+    TEST_EQUAL( mbedtls_mpi_lset( &A, most_positive ), 0 );
+    TEST_EQUAL( mbedtls_mpi_div_int( &X, &R, &A, most_negative ), 0 );
+    TEST_EQUAL( mbedtls_mpi_cmp_int( &X, 0 ), 0 );
+    TEST_EQUAL( mbedtls_mpi_cmp_int( &R, most_positive ), 0 );
+
+    /* Test mbedtls_mpi_div_int(): (p) / (-p) */
+    TEST_EQUAL( mbedtls_mpi_add_int( &A, &A, 1 ), 0 );
+    TEST_EQUAL( mbedtls_mpi_div_int( &X, &R, &A, most_negative ), 0 );
+    TEST_EQUAL( mbedtls_mpi_cmp_int( &X, -1 ), 0 );
+    TEST_EQUAL( mbedtls_mpi_cmp_int( &R, 0 ), 0 );
+
+    /* Test mbedtls_mpi_div_int(): (2*p) / (-p) */
+    TEST_EQUAL( mbedtls_mpi_shift_l( &A, 1 ), 0 );
+    TEST_EQUAL( mbedtls_mpi_div_int( &X, &R, &A, most_negative ), 0 );
+    TEST_EQUAL( mbedtls_mpi_cmp_int( &X, -2 ), 0 );
+    TEST_EQUAL( mbedtls_mpi_cmp_int( &R, 0 ), 0 );
+
+    /* Test mbedtls_mpi_mod_int(): never valid */
+    TEST_EQUAL( mbedtls_mpi_mod_int( X.p, &A, most_negative ),
+                MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
+
+    /* Test mbedtls_mpi_random(): never valid */
+    TEST_EQUAL( mbedtls_mpi_random( &X, most_negative, &A,
+                                    mbedtls_test_rnd_std_rand, NULL ),
+                MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
 
 exit:
-    mbedtls_mpi_free( &upper_bound );
-    mbedtls_mpi_free( &result );
-    mbedtls_free( stats );
-}
-/* END_CASE */
-
-/* BEGIN_CASE */
-void mpi_random_sizes( int min, data_t *bound_bytes, int nlimbs, int before )
-{
-    mbedtls_mpi upper_bound;
-    mbedtls_mpi result;
-
-    mbedtls_mpi_init( &upper_bound );
-    mbedtls_mpi_init( &result );
-
-    if( before != 0 )
-    {
-        /* Set result to sign(before) * 2^(|before|-1) */
-        TEST_ASSERT( mbedtls_mpi_lset( &result, before > 0 ? 1 : -1 ) == 0 );
-        if( before < 0 )
-            before = - before;
-        TEST_ASSERT( mbedtls_mpi_shift_l( &result, before - 1 ) == 0 );
-    }
-
-    TEST_EQUAL( 0, mbedtls_mpi_grow( &result, nlimbs ) );
-    TEST_EQUAL( 0, mbedtls_mpi_read_binary( &upper_bound,
-                                            bound_bytes->x, bound_bytes->len ) );
-    TEST_EQUAL( 0, mbedtls_mpi_random( &result, min, &upper_bound,
-                                       mbedtls_test_rnd_std_rand, NULL ) );
-    TEST_ASSERT( sign_is_valid( &result ) );
-    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &result, &upper_bound ) < 0 );
-    TEST_ASSERT( mbedtls_mpi_cmp_int( &result, min ) >= 0 );
-
-exit:
-    mbedtls_mpi_free( &upper_bound );
-    mbedtls_mpi_free( &result );
-}
-/* END_CASE */
-
-/* BEGIN_CASE */
-void mpi_random_fail( int min, data_t *bound_bytes, int expected_ret )
-{
-    mbedtls_mpi upper_bound;
-    mbedtls_mpi result;
-    int actual_ret;
-
-    mbedtls_mpi_init( &upper_bound );
-    mbedtls_mpi_init( &result );
-
-    TEST_EQUAL( 0, mbedtls_mpi_read_binary( &upper_bound,
-                                            bound_bytes->x, bound_bytes->len ) );
-    actual_ret = mbedtls_mpi_random( &result, min, &upper_bound,
-                                     mbedtls_test_rnd_std_rand, NULL );
-    TEST_EQUAL( expected_ret, actual_ret );
-
-exit:
-    mbedtls_mpi_free( &upper_bound );
-    mbedtls_mpi_free( &result );
+    mbedtls_mpi_free( &A );
+    mbedtls_mpi_free( &R );
+    mbedtls_mpi_free( &X );
 }
 /* END_CASE */
 
diff --git a/tests/suites/test_suite_bignum.misc.data b/tests/suites/test_suite_bignum.misc.data
index 29ba4ab..5eda4c1 100644
--- a/tests/suites/test_suite_bignum.misc.data
+++ b/tests/suites/test_suite_bignum.misc.data
@@ -1144,6 +1144,18 @@
 Test mbedtls_mpi_div_mpi: 0 (null) / -1
 mpi_div_mpi:"":"-1":"":"":0
 
+Test mbedtls_mpi_div_mpi: -0 (null) / 1
+mpi_div_mpi:"-":"1":"":"":0
+
+Test mbedtls_mpi_div_mpi: -0 (null) / -1
+mpi_div_mpi:"-":"-1":"":"":0
+
+Test mbedtls_mpi_div_mpi: -0 (null) / 42
+mpi_div_mpi:"-":"2a":"":"":0
+
+Test mbedtls_mpi_div_mpi: -0 (null) / -42
+mpi_div_mpi:"-":"-2a":"":"":0
+
 Test mbedtls_mpi_div_mpi #1
 mpi_div_mpi:"9e22d6da18a33d1ef28d2a82242b3f6e9c9742f63e5d440f58a190bfaf23a7866e67589adb80":"22":"4a6abf75b13dc268ea9cc8b5b6aaf0ac85ecd437a4e0987fb13cf8d2acc57c0306c738c1583":"1a":0
 
@@ -1204,41 +1216,85 @@
 Test mbedtls_mpi_mod_mpi: 0 (null) % -1
 mpi_mod_mpi:"":"-1":"":MBEDTLS_ERR_MPI_NEGATIVE_VALUE
 
+Test mbedtls_mpi_mod_mpi: -0 (null) % 1
+mpi_mod_mpi:"-":"1":"":0
+
+Test mbedtls_mpi_mod_mpi: -0 (null) % -1
+mpi_mod_mpi:"-":"-1":"":MBEDTLS_ERR_MPI_NEGATIVE_VALUE
+
+Test mbedtls_mpi_mod_mpi: -0 (null) % 42
+mpi_mod_mpi:"-":"2a":"":0
+
+Test mbedtls_mpi_mod_mpi: -0 (null) % -42
+mpi_mod_mpi:"-":"-2a":"":MBEDTLS_ERR_MPI_NEGATIVE_VALUE
+
 Base test mbedtls_mpi_mod_int #1
-mpi_mod_int:"3e8":13:12:0
+mpi_mod_int:"3e8":"d":"c":0
 
 Base test mbedtls_mpi_mod_int #2 (Divide by zero)
-mpi_mod_int:"3e8":0:0:MBEDTLS_ERR_MPI_DIVISION_BY_ZERO
+mpi_mod_int:"3e8":"0":"0":MBEDTLS_ERR_MPI_DIVISION_BY_ZERO
 
 Base test mbedtls_mpi_mod_int #3
-mpi_mod_int:"-3e8":13:1:0
+mpi_mod_int:"-3e8":"d":"1":0
 
 Base test mbedtls_mpi_mod_int #4 (Negative modulo)
-mpi_mod_int:"3e8":-13:0:MBEDTLS_ERR_MPI_NEGATIVE_VALUE
+mpi_mod_int:"3e8":"-d":"0":MBEDTLS_ERR_MPI_NEGATIVE_VALUE
 
 Base test mbedtls_mpi_mod_int #5 (Negative modulo)
-mpi_mod_int:"-3e8":-13:0:MBEDTLS_ERR_MPI_NEGATIVE_VALUE
+mpi_mod_int:"-3e8":"-d":"0":MBEDTLS_ERR_MPI_NEGATIVE_VALUE
 
 Base test mbedtls_mpi_mod_int #6 (By 1)
-mpi_mod_int:"3e8":1:0:0
+mpi_mod_int:"3e8":"1":"0":0
 
 Base test mbedtls_mpi_mod_int #7 (By 2)
-mpi_mod_int:"3e9":2:1:0
+mpi_mod_int:"3e9":"2":"1":0
 
 Base test mbedtls_mpi_mod_int #8 (By 2)
-mpi_mod_int:"3e8":2:0:0
+mpi_mod_int:"3e8":"2":"0":0
 
 Test mbedtls_mpi_mod_int: 0 (null) % 1
-mpi_mod_int:"":1:0:0
+mpi_mod_int:"":"1":"0":0
 
 Test mbedtls_mpi_mod_int: 0 (null) % 2
-mpi_mod_int:"":2:0:0
+mpi_mod_int:"":"2":"0":0
 
 Test mbedtls_mpi_mod_int: 0 (null) % -1
-mpi_mod_int:"":-1:0:MBEDTLS_ERR_MPI_NEGATIVE_VALUE
+mpi_mod_int:"":"-1":"0":MBEDTLS_ERR_MPI_NEGATIVE_VALUE
 
 Test mbedtls_mpi_mod_int: 0 (null) % -2
-mpi_mod_int:"":-2:0:MBEDTLS_ERR_MPI_NEGATIVE_VALUE
+mpi_mod_int:"":"-2":"0":MBEDTLS_ERR_MPI_NEGATIVE_VALUE
+
+# CURRENTLY FAILS - SEE GITHUB ISSUE #6540
+#Test mbedtls_mpi_mod_int: 230772460340063000000100500000300000010 % 5178236083361335880 -> 3386266129388798810
+#depends_on:MBEDTLS_HAVE_INT64
+#mpi_mod_int:"AD9D28BF6C4E98FDF156BF0980CEE30A":"47DCCA4847DCCA48":"2EFE6F1A7D28035A":0
+
+Test mbedtls_mpi_mod_mpi: 230772460340063000000100500000300000010 % 5178236083361335880 -> 3386266129388798810
+mpi_mod_mpi:"AD9D28BF6C4E98FDF156BF0980CEE30A":"47DCCA4847DCCA48":"2EFE6F1A7D28035A":0
+
+# CURRENTLY FAILS - SEE GITHUB ISSUE #6540
+#Test mbedtls_mpi_mod_int: 230772460340062999996714233870911201200 % 5178236083361335880 -> 0
+#depends_on:MBEDTLS_HAVE_INT64
+#mpi_mod_int:"AD9D28BF6C4E98FDC2584FEF03A6DFB0":"47DCCA4847DCCA48":"0":0
+
+Test mbedtls_mpi_mod_mpi: 230772460340062999996714233870911201200 % 5178236083361335880 -> 0
+mpi_mod_mpi:"AD9D28BF6C4E98FDC2584FEF03A6DFB0":"47DCCA4847DCCA48":"0":0
+
+# CURRENTLY FAILS WHEN MPIS ARE 32-BIT (ISSUE #6450): WHEN FIXED, REMOVE "depends_on" LINE
+Test mbedtls_mpi_mod_int: 230772460340063000000100500000300000010 % 1205652040 -> 3644370
+depends_on:MBEDTLS_HAVE_INT64
+mpi_mod_int:"AD9D28BF6C4E98FDF156BF0980CEE30A":"47DCCA48":"379BD2":0
+
+Test mbedtls_mpi_mod_mpi: 230772460340063000000100500000300000010 % 1205652040 -> 3644370
+mpi_mod_mpi:"AD9D28BF6C4E98FDF156BF0980CEE30A":"47DCCA48":"379BD2":0
+
+# CURRENTLY FAILS WHEN MPIS ARE 32-BIT (ISSUE #6450): WHEN FIXED, REMOVE "depends_on" LINE
+Test mbedtls_mpi_mod_int: 230772460340063000000100500000296355640 % 1205652040 -> 0
+depends_on:MBEDTLS_HAVE_INT64
+mpi_mod_int:"AD9D28BF6C4E98FDF156BF0980974738":"47DCCA48":"0":0
+
+Test mbedtls_mpi_mod_mpi: 230772460340063000000100500000296355640 % 1205652040 -> 0
+mpi_mod_mpi:"AD9D28BF6C4E98FDF156BF0980974738":"47DCCA48":"0":0
 
 Base test mbedtls_mpi_exp_mod #1
 mpi_exp_mod:"17":"d":"1d":"18":0
@@ -1732,175 +1788,8 @@
 Fill random: MAX_SIZE bytes, RNG failure after MAX_SIZE-1 bytes
 mpi_fill_random:MBEDTLS_MPI_MAX_SIZE:MBEDTLS_MPI_MAX_SIZE-1:0:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
 
-MPI random in range: 1..2
-mpi_random_many:1:"02":1000
-
-MPI random in range: 1..3
-mpi_random_many:1:"03":1000
-
-MPI random in range: 1..4
-mpi_random_many:1:"04":1000
-
-MPI random in range: 1..5
-mpi_random_many:1:"05":1000
-
-MPI random in range: 1..6
-mpi_random_many:1:"06":1000
-
-MPI random in range: 1..7
-mpi_random_many:1:"07":1000
-
-MPI random in range: 1..8
-mpi_random_many:1:"08":1000
-
-MPI random in range: 1..9
-mpi_random_many:1:"09":1000
-
-MPI random in range: 1..10
-mpi_random_many:1:"0a":1000
-
-MPI random in range: 1..11
-mpi_random_many:1:"0b":1000
-
-MPI random in range: 1..12
-mpi_random_many:1:"0c":1000
-
-MPI random in range: 1..255
-mpi_random_many:1:"ff":200
-
-MPI random in range: 1..256
-mpi_random_many:1:"0100":200
-
-MPI random in range: 1..257
-mpi_random_many:1:"0101":200
-
-MPI random in range: 1..272
-mpi_random_many:1:"0110":200
-
-MPI random in range: 1..2^64-1
-mpi_random_many:1:"ffffffffffffffff":100
-
-MPI random in range: 1..2^64
-mpi_random_many:1:"010000000000000000":100
-
-MPI random in range: 1..2^64+1
-mpi_random_many:1:"010000000000000001":100
-
-MPI random in range: 1..2^64+2^63
-mpi_random_many:1:"018000000000000000":100
-
-MPI random in range: 1..2^65-1
-mpi_random_many:1:"01ffffffffffffffff":100
-
-MPI random in range: 1..2^65
-mpi_random_many:1:"020000000000000000":100
-
-MPI random in range: 1..2^65+1
-mpi_random_many:1:"020000000000000001":100
-
-MPI random in range: 1..2^65+2^64
-mpi_random_many:1:"030000000000000000":100
-
-MPI random in range: 1..2^66+2^65
-mpi_random_many:1:"060000000000000000":100
-
-MPI random in range: 1..2^71-1
-mpi_random_many:1:"7fffffffffffffffff":100
-
-MPI random in range: 1..2^71
-mpi_random_many:1:"800000000000000000":100
-
-MPI random in range: 1..2^71+1
-mpi_random_many:1:"800000000000000001":100
-
-MPI random in range: 1..2^71+2^70
-mpi_random_many:1:"c00000000000000000":100
-
-MPI random in range: 1..2^72-1
-mpi_random_many:1:"ffffffffffffffffff":100
-
-MPI random in range: 1..2^72
-mpi_random_many:1:"01000000000000000000":100
-
-MPI random in range: 1..2^72+1
-mpi_random_many:1:"01000000000000000001":100
-
-MPI random in range: 1..2^72+2^71
-mpi_random_many:1:"01800000000000000000":100
-
-MPI random in range: 0..1
-mpi_random_many:0:"04":10000
-
-MPI random in range: 0..4
-mpi_random_many:0:"04":10000
-
-MPI random in range: 2..4
-mpi_random_many:2:"04":10000
-
-MPI random in range: 3..4
-mpi_random_many:3:"04":10000
-
-MPI random in range: smaller result
-mpi_random_sizes:1:"aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb":1:0
-
-MPI random in range: same size result (32-bit limbs)
-mpi_random_sizes:1:"aaaaaaaaaaaaaaaa":2:0
-
-MPI random in range: same size result (64-bit limbs)
-mpi_random_sizes:1:"aaaaaaaaaaaaaaaa":1:0
-
-MPI random in range: larger result
-mpi_random_sizes:1:"aaaaaaaaaaaaaaaa":3:0
-
-## The "0 limb in upper bound" tests rely on the fact that
-## mbedtls_mpi_read_binary() bases the size of the MPI on the size of
-## the input, without first checking for leading zeros. If this was
-## not the case, the tests would still pass, but would not exercise
-## the advertised behavior.
-MPI random in range: leading 0 limb in upper bound #0
-mpi_random_sizes:1:"00aaaaaaaaaaaaaaaa":0:0
-
-MPI random in range: leading 0 limb in upper bound #1
-mpi_random_sizes:1:"00aaaaaaaaaaaaaaaa":1:0
-
-MPI random in range: leading 0 limb in upper bound #2
-mpi_random_sizes:1:"00aaaaaaaaaaaaaaaa":2:0
-
-MPI random in range: leading 0 limb in upper bound #3
-mpi_random_sizes:1:"00aaaaaaaaaaaaaaaa":3:0
-
-MPI random in range: leading 0 limb in upper bound #4
-mpi_random_sizes:1:"00aaaaaaaaaaaaaaaa":4:0
-
-MPI random in range: previously small >0
-mpi_random_sizes:1:"1234567890":4:1
-
-MPI random in range: previously small <0
-mpi_random_sizes:1:"1234567890":4:-1
-
-MPI random in range: previously large >0
-mpi_random_sizes:1:"1234":4:65
-
-MPI random in range: previously large <0
-mpi_random_sizes:1:"1234":4:-65
-
-MPI random bad arguments: min < 0
-mpi_random_fail:-1:"04":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
-
-MPI random bad arguments: min = N = 0
-mpi_random_fail:0:"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
-
-MPI random bad arguments: min = N = 1
-mpi_random_fail:1:"01":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
-
-MPI random bad arguments: min > N = 0
-mpi_random_fail:1:"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
-
-MPI random bad arguments: min > N = 1
-mpi_random_fail:2:"01":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
-
-MPI random bad arguments: min > N = 1, 0 limb in upper bound
-mpi_random_fail:2:"000000000000000001":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+Most negative mbedtls_mpi_sint
+most_negative_mpi_sint:
 
 MPI Selftest
 depends_on:MBEDTLS_SELF_TEST
diff --git a/tests/suites/test_suite_bignum_core.function b/tests/suites/test_suite_bignum_core.function
index 612a7c6..47f9013 100644
--- a/tests/suites/test_suite_bignum_core.function
+++ b/tests/suites/test_suite_bignum_core.function
@@ -345,6 +345,56 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
+void mpi_core_uint_le_mpi( char *input_A )
+{
+    mbedtls_mpi_uint *A = NULL;
+    size_t A_limbs = 0;
+
+    TEST_EQUAL( mbedtls_test_read_mpi_core( &A, &A_limbs, input_A ), 0 );
+
+    int is_large = 0; /* nonzero limbs beyond the lowest-order one? */
+    for( size_t i = 1; i < A_limbs; i++ )
+    {
+        if( A[i] != 0 )
+        {
+            is_large = 1;
+            break;
+        }
+    }
+
+    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 );
+
+    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 );
+    }
+    else
+    {
+        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 ),
+                    (mbedtls_mpi_uint)( -1 ) >> 1 <= A[0] );
+        TEST_EQUAL( mbedtls_mpi_core_uint_le_mpi( (mbedtls_mpi_uint)( -1 ),
+                                                  A, A_limbs ),
+                    (mbedtls_mpi_uint)( -1 ) <= A[0] );
+    }
+
+exit:
+    mbedtls_free( A );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
 void mpi_core_cond_assign( char * input_X,
                            char * input_Y,
                            int input_bytes )
@@ -533,10 +583,9 @@
 
 /* BEGIN_CASE */
 void mpi_core_sub( char * input_A, char * input_B,
-                   char * input_X4, char * input_X8,
-                   int carry )
+                   char * input_X, int carry )
 {
-    mbedtls_mpi A, B, X4, X8;
+    mbedtls_mpi A, B, X;
     mbedtls_mpi_uint *a = NULL;
     mbedtls_mpi_uint *b = NULL;
     mbedtls_mpi_uint *x = NULL; /* expected */
@@ -544,29 +593,23 @@
 
     mbedtls_mpi_init( &A );
     mbedtls_mpi_init( &B );
-    mbedtls_mpi_init( &X4 );
-    mbedtls_mpi_init( &X8 );
+    mbedtls_mpi_init( &X );
 
     TEST_EQUAL( 0, mbedtls_test_read_mpi( &A, input_A ) );
     TEST_EQUAL( 0, mbedtls_test_read_mpi( &B, input_B ) );
-    TEST_EQUAL( 0, mbedtls_test_read_mpi( &X4, input_X4 ) );
-    TEST_EQUAL( 0, mbedtls_test_read_mpi( &X8, input_X8 ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi( &X, input_X ) );
 
     /* All of the inputs are +ve (or zero) */
     TEST_EQUAL( 1, A.s );
     TEST_EQUAL( 1, B.s );
-    TEST_EQUAL( 1, X4.s );
-    TEST_EQUAL( 1, X8.s );
+    TEST_EQUAL( 1, X.s );
 
     /* Get the number of limbs we will need */
     size_t limbs = MAX( A.n, B.n );
     size_t bytes = limbs * sizeof(mbedtls_mpi_uint);
 
-    /* We only need to work with X4 or X8, depending on sizeof(mbedtls_mpi_uint) */
-    mbedtls_mpi *X = ( sizeof(mbedtls_mpi_uint) == 4 ) ? &X4 : &X8;
-
     /* The result shouldn't have more limbs than the longest input */
-    TEST_LE_U( X->n, limbs );
+    TEST_LE_U( X.n, limbs );
 
     /* Now let's get arrays of mbedtls_mpi_uints, rather than MPI structures */
 
@@ -582,7 +625,7 @@
      */
     memcpy( a, A.p, A.n * sizeof(mbedtls_mpi_uint) );
     memcpy( b, B.p, B.n * sizeof(mbedtls_mpi_uint) );
-    memcpy( x, X->p, X->n * sizeof(mbedtls_mpi_uint) );
+    memcpy( x, X.p, X.n * sizeof(mbedtls_mpi_uint) );
 
     /* 1a) r = a - b => we should get the correct carry */
     TEST_EQUAL( carry, mbedtls_mpi_core_sub( r, a, b, limbs ) );
@@ -621,8 +664,7 @@
 
     mbedtls_mpi_free( &A );
     mbedtls_mpi_free( &B );
-    mbedtls_mpi_free( &X4 );
-    mbedtls_mpi_free( &X8 );
+    mbedtls_mpi_free( &X );
 }
 /* END_CASE */
 
@@ -806,7 +848,9 @@
     TEST_EQUAL( 0, mbedtls_mpi_grow( X, limbs_AN ) );
     TEST_EQUAL( 0, mbedtls_mpi_grow( &B, limbs_B ) );
 
-    TEST_EQUAL( 0, mbedtls_mpi_grow( &T, limbs_AN * 2 + 1 ) );
+    size_t working_limbs = mbedtls_mpi_core_montmul_working_limbs( limbs_AN );
+    TEST_EQUAL( working_limbs, limbs_AN * 2 + 1 );
+    TEST_EQUAL( 0, mbedtls_mpi_grow( &T, working_limbs ) );
 
     /* Calculate the Montgomery constant (this is unit tested separately) */
     mbedtls_mpi_uint mm = mbedtls_mpi_core_montmul_init( N.p );
@@ -935,7 +979,7 @@
 }
 /* END_CASE */
 
-/* BEGIN_CASE */
+/* BEGIN_CASE depends_on:MBEDTLS_TEST_HOOKS */
 void mpi_core_ct_uint_table_lookup( int bitlen, int window_size )
 {
     size_t limbs = BITS_TO_LIMBS( bitlen );
@@ -1041,6 +1085,85 @@
 
 /* BEGIN MERGE SLOT 1 */
 
+/* BEGIN_CASE */
+void mpi_core_exp_mod( char * input_N, char * input_A,
+                       char * input_E, char * input_X )
+{
+    mbedtls_mpi_uint *A = NULL;
+    mbedtls_mpi_uint *E = NULL;
+    mbedtls_mpi_uint *N = NULL;
+    mbedtls_mpi_uint *X = NULL;
+    size_t A_limbs, E_limbs, N_limbs, X_limbs;
+    const mbedtls_mpi_uint *R2 = NULL;
+    mbedtls_mpi_uint *Y = NULL;
+    mbedtls_mpi_uint *T = NULL;
+    /* Legacy MPIs for computing R2 */
+    mbedtls_mpi N_mpi;
+    mbedtls_mpi_init( &N_mpi );
+    mbedtls_mpi R2_mpi;
+    mbedtls_mpi_init( &R2_mpi );
+
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &A, &A_limbs, input_A ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &E, &E_limbs, input_E ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &N, &N_limbs, input_N ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &X, &X_limbs, input_X ) );
+    ASSERT_ALLOC( Y, N_limbs );
+
+    TEST_EQUAL( A_limbs, N_limbs );
+    TEST_EQUAL( X_limbs, N_limbs );
+
+    TEST_EQUAL( 0, mbedtls_mpi_grow( &N_mpi, N_limbs ) );
+    memcpy( N_mpi.p, N, N_limbs * sizeof( *N ) );
+    N_mpi.n = N_limbs;
+    TEST_EQUAL( 0,
+                mbedtls_mpi_core_get_mont_r2_unsafe( &R2_mpi, &N_mpi ) );
+    TEST_EQUAL( 0, mbedtls_mpi_grow( &R2_mpi, N_limbs ) );
+    R2 = R2_mpi.p;
+
+    size_t working_limbs = mbedtls_mpi_core_exp_mod_working_limbs( N_limbs,
+                                                                   E_limbs );
+
+    /* No point exactly duplicating the code in mbedtls_mpi_core_exp_mod_working_limbs()
+     * to see if the output is correct, but we can check that it's in a
+     * reasonable range.  The current calculation works out as
+     * `1 + N_limbs * (welem + 3)`, where welem is the number of elements in
+     * the window (1 << 1 up to 1 << 6).
+     */
+    size_t min_expected_working_limbs = 1 + N_limbs * 4;
+    size_t max_expected_working_limbs = 1 + N_limbs * 67;
+
+    TEST_LE_U( min_expected_working_limbs, working_limbs );
+    TEST_LE_U( working_limbs, max_expected_working_limbs );
+
+    /* Should also be at least mbedtls_mpi_core_montmul_working_limbs() */
+    TEST_LE_U( mbedtls_mpi_core_montmul_working_limbs( N_limbs ),
+               working_limbs );
+
+    ASSERT_ALLOC( T, working_limbs );
+
+    mbedtls_mpi_core_exp_mod( Y, A, N, N_limbs, E, E_limbs, R2, T );
+
+    TEST_EQUAL( 0, memcmp( X, Y, N_limbs * sizeof( mbedtls_mpi_uint ) ) );
+
+    /* Check when output aliased to input */
+
+    mbedtls_mpi_core_exp_mod( A, A, N, N_limbs, E, E_limbs, R2, T );
+
+    TEST_EQUAL( 0, memcmp( X, A, N_limbs * sizeof( mbedtls_mpi_uint ) ) );
+
+exit:
+    mbedtls_free( T );
+    mbedtls_free( A );
+    mbedtls_free( E );
+    mbedtls_free( N );
+    mbedtls_free( X );
+    mbedtls_free( Y );
+    mbedtls_mpi_free( &N_mpi );
+    mbedtls_mpi_free( &R2_mpi );
+    // R2 doesn't need to be freed as it is only aliasing R2_mpi
+}
+/* END_CASE */
+
 /* END MERGE SLOT 1 */
 
 /* BEGIN MERGE SLOT 2 */
@@ -1049,6 +1172,71 @@
 
 /* BEGIN MERGE SLOT 3 */
 
+/* BEGIN_CASE */
+void mpi_core_sub_int( char * input_A, char * input_B,
+                       char * input_X, int borrow )
+{
+    /* We are testing A - b, where A is an MPI and b is a scalar, expecting
+     * result X with borrow borrow.  However, for ease of handling we encode b
+     * as a 1-limb MPI (B) in the .data file. */
+
+    mbedtls_mpi_uint *A = NULL;
+    mbedtls_mpi_uint *B = NULL;
+    mbedtls_mpi_uint *X = NULL;
+    mbedtls_mpi_uint *R = NULL;
+    size_t A_limbs, B_limbs, X_limbs;
+
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &A, &A_limbs, input_A ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &B, &B_limbs, input_B ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &X, &X_limbs, input_X ) );
+
+    /* The MPI encoding of scalar b must be only 1 limb */
+    TEST_EQUAL( B_limbs, 1 );
+
+    /* The subtraction is fixed-width, so A and X must have the same number of limbs */
+    TEST_EQUAL( A_limbs, X_limbs );
+    size_t limbs = A_limbs;
+
+    ASSERT_ALLOC( R, limbs );
+
+#define TEST_COMPARE_CORE_MPIS( A, B, limbs ) \
+                ASSERT_COMPARE( A, (limbs) * sizeof(mbedtls_mpi_uint), B, (limbs) * sizeof(mbedtls_mpi_uint) )
+
+    /* 1. R = A - b. Result and borrow should be correct */
+    TEST_EQUAL( mbedtls_mpi_core_sub_int( R, A, B[0], limbs ), borrow );
+    TEST_COMPARE_CORE_MPIS( R, X, limbs );
+
+    /* 2. A = A - b. Result and borrow should be correct */
+    TEST_EQUAL( mbedtls_mpi_core_sub_int( A, A, B[0], limbs ), borrow );
+    TEST_COMPARE_CORE_MPIS( A, X, limbs );
+
+exit:
+    mbedtls_free( A );
+    mbedtls_free( B );
+    mbedtls_free( X );
+    mbedtls_free( R );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mpi_core_check_zero_ct( char *input_X, int expected_is_zero )
+{
+    mbedtls_mpi_uint *X = NULL;
+    size_t X_limbs;
+
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &X, &X_limbs, input_X ) );
+
+    TEST_CF_SECRET( X, X_limbs * sizeof( mbedtls_mpi_uint ) );
+
+    mbedtls_mpi_uint check = mbedtls_mpi_core_check_zero_ct( X, X_limbs );
+    int is_zero = (check == 0);
+    TEST_EQUAL( is_zero, expected_is_zero );
+
+exit:
+    mbedtls_free( X );
+}
+/* END_CASE */
+
 /* END MERGE SLOT 3 */
 
 /* BEGIN MERGE SLOT 4 */
diff --git a/tests/suites/test_suite_bignum_core.misc.data b/tests/suites/test_suite_bignum_core.misc.data
index 62480e4..81a767a 100644
--- a/tests/suites/test_suite_bignum_core.misc.data
+++ b/tests/suites/test_suite_bignum_core.misc.data
@@ -242,6 +242,69 @@
 mbedtls_mpi_core_lt_ct: x>y (alternating limbs)
 mpi_core_lt_ct:"FF1111111111111111":"11FFFFFFFFFFFFFFFF":0
 
+Test mbedtls_mpi_core_uint_le_mpi: 0 (1 limb)
+mpi_core_uint_le_mpi:"00"
+
+Test mbedtls_mpi_core_uint_le_mpi: 0 (>=2 limbs)
+mpi_core_uint_le_mpi:"000000000000000000"
+
+Test mbedtls_mpi_core_uint_le_mpi: 1 (1 limb)
+mpi_core_uint_le_mpi:"01"
+
+Test mbedtls_mpi_core_uint_le_mpi: 1 (>=2 limbs)
+mpi_core_uint_le_mpi:"000000000000000001"
+
+Test mbedtls_mpi_core_uint_le_mpi: 42 (1 limb)
+mpi_core_uint_le_mpi:"2a"
+
+Test mbedtls_mpi_core_uint_le_mpi: 42 (>=2 limbs)
+mpi_core_uint_le_mpi:"000000000000000042"
+
+Test mbedtls_mpi_core_uint_le_mpi: 2^31-1
+mpi_core_uint_le_mpi:"7fffffff"
+
+Test mbedtls_mpi_core_uint_le_mpi: 2^31-1 with leading zero limb
+mpi_core_uint_le_mpi:"00000000007fffffff"
+
+Test mbedtls_mpi_core_uint_le_mpi: 2^32-1
+mpi_core_uint_le_mpi:"ffffffff"
+
+Test mbedtls_mpi_core_uint_le_mpi: 2^32-1 with leading zero limb
+mpi_core_uint_le_mpi:"0000000000ffffffff"
+
+Test mbedtls_mpi_core_uint_le_mpi: 2^32
+mpi_core_uint_le_mpi:"10000000"
+
+Test mbedtls_mpi_core_uint_le_mpi: 2^32 with leading zero limb
+mpi_core_uint_le_mpi:"000000000010000000"
+
+Test mbedtls_mpi_core_uint_le_mpi: 2^32+1
+mpi_core_uint_le_mpi:"10000001"
+
+Test mbedtls_mpi_core_uint_le_mpi: 2^32+1 with leading zero limb
+mpi_core_uint_le_mpi:"000000000010000001"
+
+Test mbedtls_mpi_core_uint_le_mpi: 2^63-1
+mpi_core_uint_le_mpi:"7fffffffffffffff"
+
+Test mbedtls_mpi_core_uint_le_mpi: 2^63-1 with leading zero limb
+mpi_core_uint_le_mpi:"007fffffffffffffff"
+
+Test mbedtls_mpi_core_uint_le_mpi: 2^64-1
+mpi_core_uint_le_mpi:"ffffffffffffffff"
+
+Test mbedtls_mpi_core_uint_le_mpi: 2^64-1 with leading zero limb
+mpi_core_uint_le_mpi:"00ffffffffffffffff"
+
+Test mbedtls_mpi_core_uint_le_mpi: 2^64
+mpi_core_uint_le_mpi:"010000000000000000"
+
+Test mbedtls_mpi_core_uint_le_mpi: 2^64+1
+mpi_core_uint_le_mpi:"010000000000000001"
+
+Test mbedtls_mpi_core_uint_le_mpi: 2^64+2
+mpi_core_uint_le_mpi:"010000000000000002"
+
 mbedtls_mpi_core_cond_assign: 1 limb
 mpi_core_cond_assign:"FFFFFFFF":"11111111":4
 
diff --git a/tests/suites/test_suite_bignum_mod.data b/tests/suites/test_suite_bignum_mod.data
deleted file mode 100644
index 95faa53..0000000
--- a/tests/suites/test_suite_bignum_mod.data
+++ /dev/null
@@ -1,66 +0,0 @@
-Test mbedtls_mpi_mod_setup #1 (Both representations invalid)
-mpi_mod_setup:MBEDTLS_MPI_MOD_EXT_REP_INVALID:MBEDTLS_MPI_MOD_REP_INVALID:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
-
-Test mbedtls_mpi_mod_setup #2 (Internal representation invalid)
-mpi_mod_setup:MBEDTLS_MPI_MOD_EXT_REP_LE:MBEDTLS_MPI_MOD_REP_INVALID:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
-
-Test mbedtls_mpi_mod_setup #3 (Internal representation invalid)
-mpi_mod_setup:MBEDTLS_MPI_MOD_EXT_REP_BE:MBEDTLS_MPI_MOD_REP_INVALID:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
-
-Test mbedtls_mpi_mod_setup #4 (External representation invalid)
-mpi_mod_setup:MBEDTLS_MPI_MOD_EXT_REP_INVALID:MBEDTLS_MPI_MOD_REP_MONTGOMERY:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
-
-Test mbedtls_mpi_mod_setup #5 (External representation invalid)
-mpi_mod_setup:MBEDTLS_MPI_MOD_EXT_REP_INVALID:MBEDTLS_MPI_MOD_REP_OPT_RED:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
-
-Test mbedtls_mpi_mod_setup #6 (Both representations valid)
-mpi_mod_setup:MBEDTLS_MPI_MOD_EXT_REP_BE:MBEDTLS_MPI_MOD_REP_OPT_RED:0
-
-Test mbedtls_mpi_mod_setup #7 (Both representations valid)
-mpi_mod_setup:MBEDTLS_MPI_MOD_EXT_REP_BE:MBEDTLS_MPI_MOD_REP_MONTGOMERY:0
-
-Test mbedtls_mpi_mod_setup #8 (Both representations valid)
-mpi_mod_setup:MBEDTLS_MPI_MOD_EXT_REP_LE:MBEDTLS_MPI_MOD_REP_OPT_RED:0
-
-Test mbedtls_mpi_mod_setup #9 (Both representations valid)
-mpi_mod_setup:MBEDTLS_MPI_MOD_EXT_REP_LE:MBEDTLS_MPI_MOD_REP_MONTGOMERY:0
-
-# BEGIN MERGE SLOT 1
-
-# END MERGE SLOT 1
-
-# BEGIN MERGE SLOT 2
-
-# END MERGE SLOT 2
-
-# BEGIN MERGE SLOT 3
-
-# END MERGE SLOT 3
-
-# BEGIN MERGE SLOT 4
-
-# END MERGE SLOT 4
-
-# BEGIN MERGE SLOT 5
-
-# END MERGE SLOT 5
-
-# BEGIN MERGE SLOT 6
-
-# END MERGE SLOT 6
-
-# BEGIN MERGE SLOT 7
-
-# END MERGE SLOT 7
-
-# BEGIN MERGE SLOT 8
-
-# END MERGE SLOT 8
-
-# BEGIN MERGE SLOT 9
-
-# END MERGE SLOT 9
-
-# BEGIN MERGE SLOT 10
-
-# END MERGE SLOT 10
diff --git a/tests/suites/test_suite_bignum_mod.function b/tests/suites/test_suite_bignum_mod.function
index 1a2d0c1..8ab8ccf 100644
--- a/tests/suites/test_suite_bignum_mod.function
+++ b/tests/suites/test_suite_bignum_mod.function
@@ -2,8 +2,50 @@
 #include "mbedtls/bignum.h"
 #include "mbedtls/entropy.h"
 #include "bignum_mod.h"
+#include "bignum_mod_raw.h"
 #include "constant_time_internal.h"
 #include "test/constant_flow.h"
+
+#define TEST_COMPARE_MPI_RESIDUES( a, b ) \
+            ASSERT_COMPARE( (a).p, (a).limbs * sizeof(mbedtls_mpi_uint), \
+                            (b).p, (b).limbs * sizeof(mbedtls_mpi_uint) )
+
+static int test_read_modulus( mbedtls_mpi_mod_modulus *m,
+                              mbedtls_mpi_mod_rep_selector int_rep,
+                              char *input )
+{
+    mbedtls_mpi_uint *p = NULL;
+    size_t limbs;
+
+    int ret = mbedtls_test_read_mpi_core( &p, &limbs, input );
+    if( ret != 0 )
+        return( ret );
+
+    return( mbedtls_mpi_mod_modulus_setup( m, p, limbs, int_rep ) );
+}
+
+static int test_read_residue( mbedtls_mpi_mod_residue *r,
+                              const mbedtls_mpi_mod_modulus *m,
+                              char *input,
+                              int skip_limbs_and_value_checks )
+{
+    mbedtls_mpi_uint *p = NULL;
+    size_t limbs;
+
+    int ret = mbedtls_test_read_mpi_core( &p, &limbs, input );
+    if( ret != 0 )
+        return( ret );
+
+    if( skip_limbs_and_value_checks )
+    {
+        r->p = p;
+        r->limbs = limbs;
+        return( 0 );
+    }
+
+    /* mbedtls_mpi_mod_residue_setup() checks limbs, and that value < m */
+    return( mbedtls_mpi_mod_residue_setup( r, m, p, limbs ) );
+}
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
@@ -12,7 +54,7 @@
  */
 
 /* BEGIN_CASE */
-void mpi_mod_setup( int ext_rep, int int_rep, int iret )
+void mpi_mod_setup( int int_rep, int iret )
 {
     #define MLIMBS 8
     mbedtls_mpi_uint mp[MLIMBS];
@@ -22,7 +64,7 @@
     memset( mp, 0xFF, sizeof(mp) );
 
     mbedtls_mpi_mod_modulus_init( &m );
-    ret = mbedtls_mpi_mod_modulus_setup( &m, mp, MLIMBS, ext_rep, int_rep );
+    ret = mbedtls_mpi_mod_modulus_setup( &m, mp, MLIMBS, int_rep );
     TEST_EQUAL( ret, iret );
 
     /* Only test if the constants have been set-up  */
@@ -61,10 +103,351 @@
 
 /* BEGIN MERGE SLOT 2 */
 
+/* BEGIN_CASE */
+void mpi_mod_mul( char * input_A,
+                  char * input_B,
+                  char * input_N,
+                  char * result )
+{
+    mbedtls_mpi_uint *X = NULL;
+
+    mbedtls_mpi_mod_residue rA = { NULL, 0 };
+    mbedtls_mpi_mod_residue rB = { NULL, 0 };
+    mbedtls_mpi_mod_residue rR = { NULL, 0 };
+    mbedtls_mpi_mod_residue rX = { NULL, 0 };
+
+    mbedtls_mpi_mod_modulus m;
+    mbedtls_mpi_mod_modulus_init( &m );
+
+    TEST_EQUAL( test_read_modulus( &m, MBEDTLS_MPI_MOD_REP_MONTGOMERY, input_N ),
+                0 );
+
+    TEST_EQUAL( test_read_residue( &rA, &m, input_A, 0 ), 0 );
+    TEST_EQUAL( test_read_residue( &rB, &m, input_B, 0 ), 0 );
+    TEST_EQUAL( test_read_residue( &rR, &m, result,  0 ), 0 );
+
+    const size_t limbs = m.limbs;
+    const size_t bytes = limbs * sizeof( mbedtls_mpi_uint );
+
+    TEST_EQUAL( rA.limbs, limbs );
+    TEST_EQUAL( rB.limbs, limbs );
+    TEST_EQUAL( rR.limbs, limbs );
+
+    ASSERT_ALLOC( X, limbs );
+
+    TEST_EQUAL( mbedtls_mpi_mod_residue_setup( &rX, &m, X, limbs ), 0 );
+
+    TEST_EQUAL( mbedtls_mpi_mod_mul( &rX, &rA, &rB, &m ), 0 );
+    ASSERT_COMPARE( rX.p, bytes, rR.p, bytes );
+
+    /* alias X to A */
+    memcpy( rX.p, rA.p, bytes );
+    TEST_EQUAL( mbedtls_mpi_mod_mul( &rX, &rX, &rB, &m ), 0 );
+    ASSERT_COMPARE( rX.p, bytes, rR.p, bytes );
+
+    /* alias X to B */
+    memcpy( rX.p, rB.p, bytes );
+    TEST_EQUAL( mbedtls_mpi_mod_mul( &rX, &rA, &rX, &m ), 0);
+    ASSERT_COMPARE( rX.p, bytes, rR.p, bytes );
+
+    /* A == B: alias A and B */
+    if( memcmp( rA.p, rB.p, bytes ) == 0 )
+    {
+        TEST_EQUAL( mbedtls_mpi_mod_mul( &rX, &rA, &rA, &m ), 0 );
+        ASSERT_COMPARE( rX.p, bytes, rR.p, bytes );
+
+        /* X, A, B all aliased together */
+        memcpy( rX.p, rA.p, bytes );
+        TEST_EQUAL( mbedtls_mpi_mod_mul( &rX, &rX, &rX, &m ), 0 );
+        ASSERT_COMPARE( rX.p, bytes, rR.p, bytes );
+    }
+
+    /* A != B: test B * A */
+    else
+    {
+        TEST_EQUAL( mbedtls_mpi_mod_mul( &rX, &rB, &rA, &m ), 0 );
+        ASSERT_COMPARE( rX.p, bytes, rR.p, bytes );
+
+        /* B * A: alias X to A */
+        memcpy( rX.p, rA.p, bytes );
+        TEST_EQUAL( mbedtls_mpi_mod_mul( &rX, &rB, &rX, &m ), 0 );
+        ASSERT_COMPARE( rX.p, bytes, rR.p, bytes );
+
+        /* B + A: alias X to B */
+        memcpy( rX.p, rB.p, bytes );
+        TEST_EQUAL( mbedtls_mpi_mod_mul( &rX, &rX, &rA, &m ), 0 );
+        ASSERT_COMPARE( rX.p, bytes, rR.p, bytes );
+    }
+
+exit:
+    mbedtls_free( rA.p );
+    mbedtls_free( rB.p );
+    mbedtls_free( rR.p );
+    mbedtls_free( X );
+    mbedtls_free( (mbedtls_mpi_uint *) m.p );
+
+    mbedtls_mpi_mod_modulus_free( &m );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mpi_mod_mul_neg( char * input_A,
+                      char * input_B,
+                      char * input_N,
+                      char * result,
+                      int exp_ret )
+{
+    mbedtls_mpi_uint *X = NULL;
+
+    mbedtls_mpi_mod_residue rA = { NULL, 0 };
+    mbedtls_mpi_mod_residue rB = { NULL, 0 };
+    mbedtls_mpi_mod_residue rR = { NULL, 0 };
+    mbedtls_mpi_mod_residue rX = { NULL, 0 };
+
+    mbedtls_mpi_mod_modulus m;
+    mbedtls_mpi_mod_modulus_init( &m );
+
+    mbedtls_mpi_mod_modulus fake_m;
+    mbedtls_mpi_mod_modulus_init( &fake_m );
+
+    TEST_EQUAL( test_read_modulus( &m, MBEDTLS_MPI_MOD_REP_MONTGOMERY, input_N ),
+                0 );
+
+    TEST_EQUAL( test_read_residue( &rA, &m, input_A, 1 ), 0 );
+    TEST_EQUAL( test_read_residue( &rB, &m, input_B, 1 ), 0 );
+    TEST_EQUAL( test_read_residue( &rR, &m, result,  1 ), 0 );
+
+    const size_t limbs = m.limbs;
+
+    ASSERT_ALLOC( X, limbs );
+
+    TEST_EQUAL( mbedtls_mpi_mod_residue_setup( &rX, &m, X, limbs ), 0 );
+    rX.limbs = rR.limbs;
+
+    TEST_EQUAL( mbedtls_mpi_mod_mul( &rX, &rA, &rB, &m ), exp_ret );
+
+    /* Check when m is not initialized */
+    TEST_EQUAL( mbedtls_mpi_mod_mul( &rX, &rA, &rB, &fake_m ),
+                MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+
+exit:
+    mbedtls_free( rA.p );
+    mbedtls_free( rB.p );
+    mbedtls_free( rR.p );
+    mbedtls_free( X );
+    mbedtls_free( (mbedtls_mpi_uint *) m.p );
+
+    mbedtls_mpi_mod_modulus_free( &m );
+    mbedtls_mpi_mod_modulus_free( &fake_m );
+}
+/* END_CASE */
+
 /* END MERGE SLOT 2 */
 
 /* BEGIN MERGE SLOT 3 */
+/* BEGIN_CASE */
+void mpi_mod_sub( char * input_N,
+                  char * input_A, char * input_B,
+                  char * input_D, int expected_ret )
+{
+    mbedtls_mpi_mod_residue a = { NULL, 0 };
+    mbedtls_mpi_mod_residue b = { NULL, 0 };
+    mbedtls_mpi_mod_residue d = { NULL, 0 };
+    mbedtls_mpi_mod_residue x = { NULL, 0 };
+    mbedtls_mpi_uint *X_raw = NULL;
 
+    mbedtls_mpi_mod_modulus m;
+    mbedtls_mpi_mod_modulus_init( &m );
+
+    TEST_EQUAL( 0,
+        test_read_modulus( &m, MBEDTLS_MPI_MOD_REP_MONTGOMERY, input_N ) );
+
+    /* test_read_residue() normally checks that inputs have the same number of
+     * limbs as the modulus. For negative testing we can ask it to skip this
+     * with a non-zero final parameter. */
+    TEST_EQUAL( 0, test_read_residue( &a, &m, input_A, expected_ret != 0 ) );
+    TEST_EQUAL( 0, test_read_residue( &b, &m, input_B, expected_ret != 0 ) );
+    TEST_EQUAL( 0, test_read_residue( &d, &m, input_D, expected_ret != 0 ) );
+
+    size_t limbs = m.limbs;
+    size_t bytes = limbs * sizeof( *X_raw );
+
+    if( expected_ret == 0 )
+    {
+        /* Negative test with too many limbs in output */
+        ASSERT_ALLOC( X_raw, limbs + 1 );
+
+        x.p = X_raw;
+        x.limbs = limbs + 1;
+        TEST_EQUAL( MBEDTLS_ERR_MPI_BAD_INPUT_DATA,
+                    mbedtls_mpi_mod_sub( &x, &a, &b, &m ) );
+
+        mbedtls_free( X_raw );
+        X_raw = NULL;
+
+        /* Negative test with too few limbs in output */
+        if( limbs > 1 )
+        {
+            ASSERT_ALLOC( X_raw, limbs - 1 );
+
+            x.p = X_raw;
+            x.limbs = limbs - 1;
+            TEST_EQUAL( MBEDTLS_ERR_MPI_BAD_INPUT_DATA,
+                        mbedtls_mpi_mod_sub( &x, &a, &b, &m ) );
+
+            mbedtls_free( X_raw );
+            X_raw = NULL;
+        }
+
+        /* Negative testing with too many/too few limbs in a and b is covered by
+         * manually-written test cases with expected_ret != 0. */
+    }
+
+    ASSERT_ALLOC( X_raw, limbs );
+
+    TEST_EQUAL( 0, mbedtls_mpi_mod_residue_setup( &x, &m, X_raw, limbs ) );
+
+    /* a - b => Correct result, or expected error */
+    TEST_EQUAL( expected_ret, mbedtls_mpi_mod_sub( &x, &a, &b, &m ) );
+    if( expected_ret != 0 )
+        goto exit;
+
+    TEST_COMPARE_MPI_RESIDUES( x, d );
+
+    /* a - b: alias x to a => Correct result */
+    memcpy( x.p, a.p, bytes );
+    TEST_EQUAL( 0, mbedtls_mpi_mod_sub( &x, &x, &b, &m ) );
+    TEST_COMPARE_MPI_RESIDUES( x, d );
+
+    /* a - b: alias x to b => Correct result */
+    memcpy( x.p, b.p, bytes );
+    TEST_EQUAL( 0, mbedtls_mpi_mod_sub( &x, &a, &x, &m ) );
+    TEST_COMPARE_MPI_RESIDUES( x, d );
+
+    if ( memcmp( a.p, b.p, bytes ) == 0 )
+    {
+        /* a == b: alias a and b */
+
+        /* a - a => Correct result */
+        TEST_EQUAL( 0, mbedtls_mpi_mod_sub( &x, &a, &a, &m ) );
+        TEST_COMPARE_MPI_RESIDUES( x, d );
+
+        /* a - a: x, a, b all aliased together => Correct result */
+        memcpy( x.p, a.p, bytes );
+        TEST_EQUAL( 0, mbedtls_mpi_mod_sub( &x, &x, &x, &m ) );
+        TEST_COMPARE_MPI_RESIDUES( x, d );
+    }
+
+exit:
+    mbedtls_free( (void *)m.p ); /* mbedtls_mpi_mod_modulus_free() sets m.p = NULL */
+    mbedtls_mpi_mod_modulus_free( &m );
+
+    mbedtls_free( a.p );
+    mbedtls_free( b.p );
+    mbedtls_free( d.p );
+    mbedtls_free( X_raw );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mpi_mod_inv_mont( char * input_N,
+                       char * input_A, char * input_I,
+                       int expected_ret )
+{
+    mbedtls_mpi_mod_residue a = { NULL, 0 };    /* argument */
+    mbedtls_mpi_mod_residue i = { NULL, 0 };    /* expected inverse wrt N */
+    mbedtls_mpi_mod_residue x = { NULL, 0 };    /* output */
+    mbedtls_mpi_uint *X_raw = NULL;
+
+    mbedtls_mpi_mod_modulus N;
+    mbedtls_mpi_mod_modulus_init( &N );
+
+    TEST_EQUAL( 0,
+        test_read_modulus( &N, MBEDTLS_MPI_MOD_REP_MONTGOMERY, input_N ) );
+
+    /* test_read_residue() normally checks that inputs have the same number of
+     * limbs as the modulus. For negative testing we can ask it to skip this
+     * with a non-zero final parameter. */
+    TEST_EQUAL( 0, test_read_residue( &a, &N, input_A, expected_ret != 0 ) );
+    TEST_EQUAL( 0, test_read_residue( &i, &N, input_I, expected_ret != 0 ) );
+
+    size_t limbs = N.limbs;
+    size_t bytes = limbs * sizeof( *X_raw );
+
+    ASSERT_ALLOC( X_raw, limbs );
+
+    TEST_EQUAL( 0, mbedtls_mpi_mod_residue_setup( &x, &N, X_raw, limbs ) );
+
+    TEST_EQUAL( expected_ret, mbedtls_mpi_mod_inv( &x, &a, &N ) );
+    if( expected_ret == 0 )
+    {
+        TEST_COMPARE_MPI_RESIDUES( x, i );
+
+        /* a^-1: alias x to a => Correct result */
+        memcpy( x.p, a.p, bytes );
+        TEST_EQUAL( 0, mbedtls_mpi_mod_inv( &x, &x, &N ) );
+        TEST_COMPARE_MPI_RESIDUES( x, i );
+    }
+
+exit:
+    mbedtls_free( (void *)N.p ); /* mbedtls_mpi_mod_modulus_free() sets N.p = NULL */
+    mbedtls_mpi_mod_modulus_free( &N );
+
+    mbedtls_free( a.p );
+    mbedtls_free( i.p );
+    mbedtls_free( X_raw );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mpi_mod_inv_non_mont( char * input_N,
+                           char * input_A, char * input_I,
+                           int expected_ret )
+{
+    mbedtls_mpi_mod_residue a = { NULL, 0 };    /* argument */
+    mbedtls_mpi_mod_residue i = { NULL, 0 };    /* expected inverse wrt N */
+    mbedtls_mpi_mod_residue x = { NULL, 0 };    /* output */
+    mbedtls_mpi_uint *X_raw = NULL;
+
+    mbedtls_mpi_mod_modulus N;
+    mbedtls_mpi_mod_modulus_init( &N );
+
+    TEST_EQUAL( 0,
+        test_read_modulus( &N, MBEDTLS_MPI_MOD_REP_OPT_RED, input_N ) );
+
+    /* test_read_residue() normally checks that inputs have the same number of
+     * limbs as the modulus. For negative testing we can ask it to skip this
+     * with a non-zero final parameter. */
+    TEST_EQUAL( 0, test_read_residue( &a, &N, input_A, expected_ret != 0 ) );
+    TEST_EQUAL( 0, test_read_residue( &i, &N, input_I, expected_ret != 0 ) );
+
+    size_t limbs = N.limbs;
+    size_t bytes = limbs * sizeof( *X_raw );
+
+    ASSERT_ALLOC( X_raw, limbs );
+
+    TEST_EQUAL( 0, mbedtls_mpi_mod_residue_setup( &x, &N, X_raw, limbs ) );
+
+    TEST_EQUAL( expected_ret, mbedtls_mpi_mod_inv( &x, &a, &N ) );
+    if( expected_ret == 0 )
+    {
+        TEST_COMPARE_MPI_RESIDUES( x, i );
+
+        /* a^-1: alias x to a => Correct result */
+        memcpy( x.p, a.p, bytes );
+        TEST_EQUAL( 0, mbedtls_mpi_mod_inv( &x, &x, &N ) );
+        TEST_COMPARE_MPI_RESIDUES( x, i );
+    }
+
+exit:
+    mbedtls_free( (void *)N.p ); /* mbedtls_mpi_mod_modulus_free() sets N.p = NULL */
+    mbedtls_mpi_mod_modulus_free( &N );
+
+    mbedtls_free( a.p );
+    mbedtls_free( i.p );
+    mbedtls_free( X_raw );
+}
+/* END_CASE */
 /* END MERGE SLOT 3 */
 
 /* BEGIN MERGE SLOT 4 */
@@ -72,7 +455,110 @@
 /* END MERGE SLOT 4 */
 
 /* BEGIN MERGE SLOT 5 */
+/* BEGIN_CASE */
+void mpi_mod_add( char * input_N,
+                  char * input_A, char * input_B,
+                  char * input_S, int expected_ret )
+{
+    mbedtls_mpi_mod_residue a = { NULL, 0 };
+    mbedtls_mpi_mod_residue b = { NULL, 0 };
+    mbedtls_mpi_mod_residue s = { NULL, 0 };
+    mbedtls_mpi_mod_residue x = { NULL, 0 };
+    mbedtls_mpi_uint *X_raw = NULL;
 
+    mbedtls_mpi_mod_modulus m;
+    mbedtls_mpi_mod_modulus_init( &m );
+
+    TEST_EQUAL( 0,
+        test_read_modulus( &m, MBEDTLS_MPI_MOD_REP_MONTGOMERY, input_N ) );
+
+    /* test_read_residue() normally checks that inputs have the same number of
+     * limbs as the modulus. For negative testing we can ask it to skip this
+     * with a non-zero final parameter. */
+    TEST_EQUAL( 0, test_read_residue( &a, &m, input_A, expected_ret != 0 ) );
+    TEST_EQUAL( 0, test_read_residue( &b, &m, input_B, expected_ret != 0 ) );
+    TEST_EQUAL( 0, test_read_residue( &s, &m, input_S, expected_ret != 0 ) );
+
+    size_t limbs = m.limbs;
+    size_t bytes = limbs * sizeof( *X_raw );
+
+    if( expected_ret == 0 )
+    {
+        /* Negative test with too many limbs in output */
+        ASSERT_ALLOC( X_raw, limbs + 1 );
+
+        x.p = X_raw;
+        x.limbs = limbs + 1;
+        TEST_EQUAL( MBEDTLS_ERR_MPI_BAD_INPUT_DATA,
+                    mbedtls_mpi_mod_add( &x, &a, &b, &m ) );
+
+        mbedtls_free( X_raw );
+        X_raw = NULL;
+
+        /* Negative test with too few limbs in output */
+        if( limbs > 1 )
+        {
+            ASSERT_ALLOC( X_raw, limbs - 1 );
+
+            x.p = X_raw;
+            x.limbs = limbs - 1;
+            TEST_EQUAL( MBEDTLS_ERR_MPI_BAD_INPUT_DATA,
+                        mbedtls_mpi_mod_add( &x, &a, &b, &m ) );
+
+            mbedtls_free( X_raw );
+            X_raw = NULL;
+        }
+
+        /* Negative testing with too many/too few limbs in a and b is covered by
+         * manually-written test cases with oret != 0. */
+    }
+
+    /* Allocate correct number of limbs for X_raw */
+    ASSERT_ALLOC( X_raw, limbs );
+
+    TEST_EQUAL( 0, mbedtls_mpi_mod_residue_setup( &x, &m, X_raw, limbs ) );
+
+    /* A + B => Correct result or expected error */
+    TEST_EQUAL( expected_ret, mbedtls_mpi_mod_add( &x, &a, &b, &m ) );
+    if( expected_ret != 0 )
+        goto exit;
+
+    TEST_COMPARE_MPI_RESIDUES( x, s );
+
+    /* a + b: alias x to a => Correct result */
+    memcpy( x.p, a.p, bytes );
+    TEST_EQUAL( 0, mbedtls_mpi_mod_add( &x, &x, &b, &m ) );
+    TEST_COMPARE_MPI_RESIDUES( x, s );
+
+    /* a + b: alias x to b => Correct result */
+    memcpy( x.p, b.p, bytes );
+    TEST_EQUAL( 0, mbedtls_mpi_mod_add( &x, &a, &x, &m ) );
+    TEST_COMPARE_MPI_RESIDUES( x, s );
+
+    if ( memcmp( a.p, b.p, bytes ) == 0 )
+    {
+        /* a == b: alias a and b */
+
+        /* a + a => Correct result */
+        TEST_EQUAL( 0, mbedtls_mpi_mod_add( &x, &a, &a, &m ) );
+        TEST_COMPARE_MPI_RESIDUES( x, s );
+
+        /* a + a: x, a, b all aliased together => Correct result */
+        memcpy( x.p, a.p, bytes );
+        TEST_EQUAL( 0, mbedtls_mpi_mod_add( &x, &x, &x, &m ) );
+        TEST_COMPARE_MPI_RESIDUES( x, s );
+    }
+
+exit:
+    mbedtls_free( (void *)m.p ); /* mbedtls_mpi_mod_modulus_free() sets m.p = NULL */
+    mbedtls_mpi_mod_modulus_free( &m );
+
+    mbedtls_free( a.p );
+    mbedtls_free( b.p );
+    mbedtls_free( s.p );
+    mbedtls_free( X_raw );
+}
+/* END_CASE */
 /* END MERGE SLOT 5 */
 
 /* BEGIN MERGE SLOT 6 */
@@ -80,7 +566,214 @@
 /* END MERGE SLOT 6 */
 
 /* BEGIN MERGE SLOT 7 */
+/* BEGIN_CASE */
+void mpi_residue_setup( char * input_N, char * input_R, int ret )
+{
+    mbedtls_mpi_uint *N = NULL;
+    mbedtls_mpi_uint *R = NULL;
+    size_t n_limbs, r_limbs;
+    mbedtls_mpi_mod_modulus m;
+    mbedtls_mpi_mod_residue r;
 
+    mbedtls_mpi_mod_modulus_init( &m );
+
+    /* Allocate the memory for intermediate data structures */
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &N, &n_limbs, input_N ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &R, &r_limbs, input_R ) );
+
+    TEST_EQUAL( 0, mbedtls_mpi_mod_modulus_setup( &m, N, n_limbs,
+                MBEDTLS_MPI_MOD_REP_MONTGOMERY ) );
+
+    TEST_EQUAL( ret, mbedtls_mpi_mod_residue_setup( &r, &m, R , r_limbs ) );
+
+    if ( ret == 0 )
+    {
+        TEST_EQUAL( r.limbs, r_limbs );
+        TEST_ASSERT( r.p == R );
+    }
+
+exit:
+    mbedtls_mpi_mod_modulus_free( &m );
+    mbedtls_free( N );
+    mbedtls_free( R );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mpi_mod_io_neg( char * input_N, data_t * buf, int ret )
+{
+    mbedtls_mpi_uint *N = NULL;
+    mbedtls_mpi_uint *R = NULL;
+
+    mbedtls_mpi_mod_modulus m;
+    mbedtls_mpi_mod_residue r = { NULL, 0 };
+    mbedtls_mpi_mod_ext_rep endian = MBEDTLS_MPI_MOD_EXT_REP_LE;
+
+    mbedtls_mpi_mod_modulus_init( &m );
+
+    size_t n_limbs;
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &N, &n_limbs, input_N ) );
+    size_t r_limbs = n_limbs;
+    ASSERT_ALLOC( R, r_limbs );
+
+    /* modulus->p == NULL || residue->p == NULL ( m has not been set-up ) */
+    TEST_EQUAL( MBEDTLS_ERR_MPI_BAD_INPUT_DATA,
+                mbedtls_mpi_mod_read( &r, &m, buf->x, buf->len, endian ) );
+
+    TEST_EQUAL( MBEDTLS_ERR_MPI_BAD_INPUT_DATA,
+                mbedtls_mpi_mod_write( &r, &m, buf->x, buf->len, endian ) );
+
+    /* Set up modulus and test with residue->p == NULL */
+    TEST_EQUAL( 0, mbedtls_mpi_mod_modulus_setup( &m, N, n_limbs,
+                MBEDTLS_MPI_MOD_REP_MONTGOMERY ) );
+
+    TEST_EQUAL( MBEDTLS_ERR_MPI_BAD_INPUT_DATA,
+                mbedtls_mpi_mod_read( &r, &m, buf->x, buf->len, endian ) );
+    TEST_EQUAL( MBEDTLS_ERR_MPI_BAD_INPUT_DATA,
+                mbedtls_mpi_mod_write( &r, &m, buf->x, buf->len, endian ) );
+
+    /* Do the rest of the tests with a residue set up with the input data */
+    TEST_EQUAL( 0, mbedtls_mpi_mod_residue_setup( &r, &m, R , r_limbs ) );
+
+    /* Fail for r_limbs < m->limbs */
+    r.limbs--;
+    TEST_ASSERT( r.limbs < m.limbs );
+    TEST_EQUAL( MBEDTLS_ERR_MPI_BAD_INPUT_DATA,
+                mbedtls_mpi_mod_read( &r, &m, buf->x, buf->len, endian ) );
+    TEST_EQUAL( MBEDTLS_ERR_MPI_BAD_INPUT_DATA,
+                mbedtls_mpi_mod_write( &r, &m, buf->x, buf->len, endian ) );
+    r.limbs++;
+
+    /* Fail for r_limbs > m->limbs */
+    m.limbs--;
+    TEST_ASSERT( r.limbs > m.limbs );
+    TEST_EQUAL( MBEDTLS_ERR_MPI_BAD_INPUT_DATA,
+                mbedtls_mpi_mod_read( &r, &m, buf->x, buf->len, endian ) );
+    TEST_EQUAL( MBEDTLS_ERR_MPI_BAD_INPUT_DATA,
+                mbedtls_mpi_mod_write( &r, &m, buf->x, buf->len, endian ) );
+    m.limbs++;
+
+    /* Test the read */
+    TEST_EQUAL( ret, mbedtls_mpi_mod_read( &r, &m, buf->x, buf->len, endian ) );
+
+    /* Test write overflow only when the representation is large and read is successful  */
+    if ( r.limbs > 1 && ret == 0 )
+        TEST_EQUAL( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL,
+                        mbedtls_mpi_mod_write( &r, &m, buf->x, 1, endian ) );
+
+exit:
+    mbedtls_mpi_mod_residue_release( &r );
+    mbedtls_mpi_mod_modulus_free( &m );
+    mbedtls_free( N );
+    mbedtls_free( R );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mpi_mod_io( char * input_N, data_t * input_A, int endian )
+{
+    mbedtls_mpi_uint *N = NULL;
+    mbedtls_mpi_uint *R = NULL;
+    mbedtls_mpi_uint *R_COPY = NULL;
+    unsigned char *obuf = NULL;
+    unsigned char *ref_buf = NULL;
+    mbedtls_mpi_mod_modulus m;
+    mbedtls_mpi_mod_residue r;
+    mbedtls_mpi_mod_residue r_copy;
+    size_t n_limbs, n_bytes, a_bytes;
+
+    mbedtls_mpi_mod_modulus_init( &m );
+
+    /* Read inputs */
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &N, &n_limbs, input_N ) );
+    n_bytes = n_limbs * sizeof( mbedtls_mpi_uint );
+    a_bytes = input_A->len;
+
+    /* Allocate the memory for intermediate data structures */
+    ASSERT_ALLOC( R, n_bytes );
+    ASSERT_ALLOC( R_COPY, n_bytes );
+
+    /* Test that input's size is not greater to modulo's */
+    TEST_LE_U( a_bytes, n_bytes );
+
+    /* Init Structures */
+    TEST_EQUAL( 0, mbedtls_mpi_mod_modulus_setup( &m, N, n_limbs,
+                MBEDTLS_MPI_MOD_REP_MONTGOMERY ) );
+
+    /* Enforcing p_limbs >= m->limbs */
+    TEST_EQUAL( 0, mbedtls_mpi_mod_residue_setup( &r, &m, R, n_limbs ) );
+
+    TEST_EQUAL( 0, mbedtls_mpi_mod_read( &r, &m, input_A->x, input_A->len,
+                                         endian ) );
+
+    /* Read a copy for checking that writing didn't change the value of r */
+    TEST_EQUAL( 0, mbedtls_mpi_mod_residue_setup( &r_copy, &m,
+                                                  R_COPY, n_limbs ) );
+    TEST_EQUAL( 0, mbedtls_mpi_mod_read( &r_copy, &m, input_A->x, input_A->len,
+                                         endian ) );
+
+    /* Get number of bytes without leading zeroes */
+    size_t a_bytes_trimmed = a_bytes;
+    while( a_bytes_trimmed > 0 )
+    {
+        unsigned char* r_byte_array = (unsigned char*) r.p;
+        if( r_byte_array[--a_bytes_trimmed] != 0 )
+            break;
+    }
+    a_bytes_trimmed++;
+
+    /* Test write with three output buffer sizes: tight, same as input and
+     * longer than the input */
+    size_t obuf_sizes[3];
+    const size_t obuf_sizes_len = sizeof( obuf_sizes ) / sizeof( obuf_sizes[0] );
+    obuf_sizes[0] = a_bytes_trimmed;
+    obuf_sizes[1] = a_bytes;
+    obuf_sizes[2] = a_bytes + 8;
+
+    for( size_t i = 0; i < obuf_sizes_len; i++ )
+    {
+        ASSERT_ALLOC( obuf, obuf_sizes[i] );
+        TEST_EQUAL( 0, mbedtls_mpi_mod_write( &r, &m, obuf, obuf_sizes[i], endian ) );
+
+        /* Make sure that writing didn't corrupt the value of r */
+        ASSERT_COMPARE( r.p, r.limbs, r_copy.p, r_copy.limbs );
+
+        /* Set up reference output for checking the result */
+        ASSERT_ALLOC( ref_buf, obuf_sizes[i] );
+        switch( endian )
+        {
+            case MBEDTLS_MPI_MOD_EXT_REP_LE:
+                memcpy( ref_buf, input_A->x, a_bytes_trimmed );
+                break;
+            case MBEDTLS_MPI_MOD_EXT_REP_BE:
+                {
+                    size_t a_offset = input_A->len - a_bytes_trimmed;
+                    size_t ref_offset = obuf_sizes[i] - a_bytes_trimmed;
+                    memcpy( ref_buf + ref_offset, input_A->x + a_offset,
+                            a_bytes_trimmed );
+                }
+                break;
+            default:
+                TEST_ASSERT( 0 );
+        }
+
+        /* Check the result */
+        ASSERT_COMPARE( obuf, obuf_sizes[i], ref_buf, obuf_sizes[i] );
+
+        mbedtls_free( ref_buf );
+        ref_buf = NULL;
+        mbedtls_free( obuf );
+        obuf = NULL;
+    }
+
+exit:
+    mbedtls_mpi_mod_modulus_free( &m );
+    mbedtls_free( N );
+    mbedtls_free( R );
+    mbedtls_free( R_COPY );
+    mbedtls_free( obuf );
+}
+/* END_CASE */
 /* END MERGE SLOT 7 */
 
 /* BEGIN MERGE SLOT 8 */
diff --git a/tests/suites/test_suite_bignum_mod.misc.data b/tests/suites/test_suite_bignum_mod.misc.data
new file mode 100644
index 0000000..e369211
--- /dev/null
+++ b/tests/suites/test_suite_bignum_mod.misc.data
@@ -0,0 +1,391 @@
+Test mbedtls_mpi_mod_setup #1 (Internal representation invalid)
+mpi_mod_setup:MBEDTLS_MPI_MOD_REP_INVALID:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+Test mbedtls_mpi_mod_setup #6 (Optimised reduction)
+mpi_mod_setup:MBEDTLS_MPI_MOD_REP_OPT_RED:0
+
+Test mbedtls_mpi_mod_setup #7 (Montgomery representation)
+mpi_mod_setup:MBEDTLS_MPI_MOD_REP_MONTGOMERY:0
+
+# BEGIN MERGE SLOT 1
+
+# END MERGE SLOT 1
+
+# BEGIN MERGE SLOT 2
+Test mpi_mod_mul #1 N->limbs != A->limbs
+mpi_mod_mul_neg:"1":"00000000000000000000000000000000":"f0000000000000000000000000000000":"0":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+Test mpi_mod_mul #2 N->limbs != B->limbs
+mpi_mod_mul_neg:"1234567890abcdef1234567890abcdef":"0":"f0000000000000000000000000000000":"0":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+Test mpi_mod_mul #3 N->limbs != X->limbs
+mpi_mod_mul_neg:"1234567890abcdef1234567890abcdef":"00000000000000000000000000000000":"f0000000000000000000000000000000":"0":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+# END MERGE SLOT 2
+
+# BEGIN MERGE SLOT 3
+
+mpi_mod_sub base case for negative testing (N, a, b all >= 1 limb)
+mpi_mod_sub:"014320a022ccb75bdf470ddf25":"000000025a55a46e5da99c71c7":"00033b2e3c9fd0803ce8000f93":"013fe57440828b4a0008aa4159":0
+
+mpi_mod_sub with modulus too long/both inputs too short
+mpi_mod_sub:"0000000014320a022ccb75bdf470ddf25":"000000025a55a46e5da99c71c7":"00033b2e3c9fd0803ce8000f93":"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+mpi_mod_sub with first input too long
+mpi_mod_sub:"014320a022ccb75bdf470ddf25":"0000000000000025a55a46e5da99c71c7":"00033b2e3c9fd0803ce8000f93":"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+mpi_mod_sub with second input too long
+mpi_mod_sub:"014320a022ccb75bdf470ddf25":"000000025a55a46e5da99c71c7":"000000000033b2e3c9fd0803ce8000f93":"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+mpi_mod_sub with both inputs too long
+mpi_mod_sub:"014320a022ccb75bdf470ddf25":"0000000000000025a55a46e5da99c71c7":"000000000033b2e3c9fd0803ce8000f93":"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+mpi_mod_sub with first input too short
+mpi_mod_sub:"014320a022ccb75bdf470ddf25":"a99c71c7":"00033b2e3c9fd0803ce8000f93":"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+mpi_mod_sub with second input too short
+mpi_mod_sub:"014320a022ccb75bdf470ddf25":"000000025a55a46e5da99c71c7":"e8000f93":"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+mbedtls_mpi_mod_inv non-Mont. form - base case for negative testing (N, A, A^-1)
+mpi_mod_inv_non_mont:"000000000000152d02c7e14af67fe0bf":"00000000000000000000000000000038":"000000000000097418193b6f2e0b5fc3":0
+
+mbedtls_mpi_mod_inv non-Mont. form - A == 0
+mpi_mod_inv_non_mont:"000000000000152d02c7e14af67fe0bf":"00000000000000000000000000000000":"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+mbedtls_mpi_mod_inv non-Mont. form - A too long
+mpi_mod_inv_non_mont:"000000000000152d02c7e14af67fe0bf":"0000000000000000000000000000000000000038":"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+mbedtls_mpi_mod_inv non-Mont. form - A too short
+mpi_mod_inv_non_mont:"000000000000152d02c7e14af67fe0bf":"0000000000000038":"000000000000097418193b6f2e0b5fc3":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+mbedtls_mpi_mod_inv 32-bit Mont. form - base case for negative testing, A = 1 (N, mont(A), mont(A^-1))
+depends_on:MBEDTLS_HAVE_INT32
+mpi_mod_inv_mont:"000000000000152d02c7e14af67fe0bf":"0000000000000d71d51539b9c02b7b28":"0000000000000d71d51539b9c02b7b28":0
+
+mbedtls_mpi_mod_inv 32-bit Mont. form - A == 0
+depends_on:MBEDTLS_HAVE_INT32
+mpi_mod_inv_mont:"000000000000152d02c7e14af67fe0bf":"00000000000000000000000000000000":"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+mbedtls_mpi_mod_inv 32-bit Mont. form - A too long
+depends_on:MBEDTLS_HAVE_INT32
+mpi_mod_inv_mont:"000000000000152d02c7e14af67fe0bf":"000000000000000000000d71d51539b9c02b7b28":"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+mbedtls_mpi_mod_inv 32-bit Mont. form - A too short
+depends_on:MBEDTLS_HAVE_INT32
+mpi_mod_inv_mont:"000000000000152d02c7e14af67fe0bf":"00000d71d51539b9c02b7b28":"0000000000000d71d51539b9c02b7b28":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+mbedtls_mpi_mod_inv 64-bit Mont. form - base case for negative testing, A = 1 (N, mont(A), mont(A^-1))
+depends_on:MBEDTLS_HAVE_INT64
+mpi_mod_inv_mont:"0000000000000000000000000000152d02c7e14af67fe0bf":"000000000000000000000000000009545642424381c611fb":"000000000000000000000000000009545642424381c611fb":0
+
+mbedtls_mpi_mod_inv 64-bit Mont. form - A == 0
+depends_on:MBEDTLS_HAVE_INT64
+mpi_mod_inv_mont:"0000000000000000000000000000152d02c7e14af67fe0bf":"000000000000000000000000000000000000000000000000":"000000000000000000000000000009545642424381c611fb":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+mbedtls_mpi_mod_inv 64-bit Mont. form - A too long
+depends_on:MBEDTLS_HAVE_INT64
+mpi_mod_inv_mont:"0000000000000000000000000000152d02c7e14af67fe0bf":"0000000000000000000000000000000000000000000009545642424381c611fb":"000000000000000000000000000009545642424381c611fb":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+mbedtls_mpi_mod_inv 64-bit Mont. form - A too short
+depends_on:MBEDTLS_HAVE_INT64
+mpi_mod_inv_mont:"0000000000000000000000000000152d02c7e14af67fe0bf":"00000000000009545642424381c611fb":"000000000000000000000000000009545642424381c611fb":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+# END MERGE SLOT 3
+
+# BEGIN MERGE SLOT 4
+
+# END MERGE SLOT 4
+
+# BEGIN MERGE SLOT 5
+mpi_mod_add base case for negative testing (N, a, b all >= 1 limb)
+mpi_mod_add:"014320a022ccb75bdf470ddf25":"000000025a55a46e5da99c71c7":"00033b2e3c9fd0803ce8000f93":"00033b3096f574ee9a919c815a":0
+
+mpi_mod_add with modulus too long/both inputs too short
+mpi_mod_add:"0000000014320a022ccb75bdf470ddf25":"000000025a55a46e5da99c71c7":"00033b2e3c9fd0803ce8000f93":"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+mpi_mod_add with first input too long
+mpi_mod_add:"014320a022ccb75bdf470ddf25":"0000000000000025a55a46e5da99c71c7":"00033b2e3c9fd0803ce8000f93":"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+mpi_mod_add with second input too long
+mpi_mod_add:"014320a022ccb75bdf470ddf25":"000000025a55a46e5da99c71c7":"000000000033b2e3c9fd0803ce8000f93":"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+mpi_mod_add with both inputs too long
+mpi_mod_add:"014320a022ccb75bdf470ddf25":"0000000000000025a55a46e5da99c71c7":"000000000033b2e3c9fd0803ce8000f93":"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+mpi_mod_add with first input too short
+mpi_mod_add:"014320a022ccb75bdf470ddf25":"a99c71c7":"00033b2e3c9fd0803ce8000f93":"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+mpi_mod_add with second input too short
+mpi_mod_add:"014320a022ccb75bdf470ddf25":"000000025a55a46e5da99c71c7":"e8000f93":"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+# END MERGE SLOT 5
+
+# BEGIN MERGE SLOT 6
+
+# END MERGE SLOT 6
+
+# BEGIN MERGE SLOT 7
+Test mbedtls_mpi_residue_setup #1 m > r
+mpi_residue_setup:"fe":"01":0
+
+Test mbedtls_mpi_residue_setup #2 r == m - 1
+mpi_residue_setup:"ff":"fe":0
+
+Test mbedtls_mpi_residue_setup #3 m->limbs = r-> limbs && m > r
+mpi_residue_setup:"7dfe5c6":"fe":0
+
+Test mbedtls_mpi_residue_setup #4 m->limbs = r-> limbs && m > r
+mpi_residue_setup:"7ffffffffffffffffffffffffffffffffffffffffffffff1":"0000000000000000000000000000000000000000000000fe":0
+
+Test mbedtls_mpi_residue_setup #5 m->limbs > r-> limbs && m > r
+mpi_residue_setup:"7ffffffff00000000":"fe":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+Test mbedtls_mpi_residue_setup #6 m->limbs < r-> limbs && m > r
+mpi_residue_setup:"ff":"000000000000000000000000000000000000000000000001":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+Test mbedtls_mpi_residue_setup #7 r == m
+mpi_residue_setup:"fe":"fe":-4
+
+Test mbedtls_mpi_residue_setup #8 r > m
+mpi_residue_setup:"fe":"ff":-4
+
+Test mbedtls_mpi_mod_io_neg #1 input_r < modulo m
+mpi_mod_io_neg:"fe":"fd":0
+
+Test mbedtls_mpi_mod_io_neg #2  input_r == modulo m
+mpi_mod_io_neg:"fe":"fe":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+Test mbedtls_mpi_mod_io_neg #3  input_r > modulo m
+mpi_mod_io_neg:"fe":"ff":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+Test mbedtls_mpi_mod_io_neg #4  input_r too large to fit
+mpi_mod_io_neg:"fe":"ffffffffffffffffff":MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL
+
+Test mbedtls_mpi_mod_io_neg #5  Sucesfull read / output buffer too small
+mpi_mod_io_neg:"7ffffffffffffffffffffffffffffff1":"ffff":0
+
+Test mbedtls_mpi_mod_io #1 N: "11" A: "119".
+mpi_mod_io:"000000000000000b":"0000000000000000":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #2 N: "11" A: "136".
+mpi_mod_io:"000000000000000b":"0000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #3 N: "11" A: "119".
+mpi_mod_io:"000000000000000b":"0000000000000001":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #4 N: "11" A: "136".
+mpi_mod_io:"000000000000000b":"0100000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #5 N: "140737488355333" A: "119".
+mpi_mod_io:"0000800000000005":"0000000000000000":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #6 N: "140737488355333" A: "136".
+mpi_mod_io:"0000800000000005":"0000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #7 N: "140737488355333" A: "119".
+mpi_mod_io:"0000800000000005":"0000000000000001":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #8 N: "140737488355333" A: "136".
+mpi_mod_io:"0000800000000005":"0100000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #9 N: "140737488355333" A: "119".
+mpi_mod_io:"0000800000000005":"00000000000003ca":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #10 N: "140737488355333" A: "136".
+mpi_mod_io:"0000800000000005":"ca03000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #11 N: "140737488355333" A: "119".
+mpi_mod_io:"0000800000000005":"00000000539ed428":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #12 N: "140737488355333" A: "136".
+mpi_mod_io:"0000800000000005":"28d49e5300000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #13 N: "9223372036854775807" A: "119".
+mpi_mod_io:"7fffffffffffffff":"0000000000000000":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #14 N: "9223372036854775807" A: "136".
+mpi_mod_io:"7fffffffffffffff":"0000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #15 N: "9223372036854775807" A: "119".
+mpi_mod_io:"7fffffffffffffff":"0000000000000001":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #16 N: "9223372036854775807" A: "136".
+mpi_mod_io:"7fffffffffffffff":"0100000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #17 N: "9223372036854775807" A: "119".
+mpi_mod_io:"7fffffffffffffff":"00000000000003ca":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #18 N: "9223372036854775807" A: "136".
+mpi_mod_io:"7fffffffffffffff":"ca03000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #19 N: "9223372036854775807" A: "119".
+mpi_mod_io:"7fffffffffffffff":"00000000539ed428":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #20 N: "9223372036854775807" A: "136".
+mpi_mod_io:"7fffffffffffffff":"28d49e5300000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #21 N: "9223372036854775807" A: "119".
+mpi_mod_io:"7fffffffffffffff":"7dfe5c6beb35a2d6":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #22 N: "9223372036854775807" A: "136".
+mpi_mod_io:"7fffffffffffffff":"d6a235eb6b5cfe7d":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #23 N: "6610145858169835373800827072568987987787972943497619105736762797475099959212160692262984293277166612477845864397201463825139894315919781838969391314120587" A: "119".
+mpi_mod_io:"7e35b84cb19ea5bc57ec37f5e431462fa962d98c1e63738d4657f18ad6532e6adc3eafe67f1e5fa262af94cee8d3e7268593942a2a98df75154f8c914a282f8b":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #24 N: "6610145858169835373800827072568987987787972943497619105736762797475099959212160692262984293277166612477845864397201463825139894315919781838969391314120587" A: "136".
+mpi_mod_io:"7e35b84cb19ea5bc57ec37f5e431462fa962d98c1e63738d4657f18ad6532e6adc3eafe67f1e5fa262af94cee8d3e7268593942a2a98df75154f8c914a282f8b":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #25 N: "6610145858169835373800827072568987987787972943497619105736762797475099959212160692262984293277166612477845864397201463825139894315919781838969391314120587" A: "119".
+mpi_mod_io:"7e35b84cb19ea5bc57ec37f5e431462fa962d98c1e63738d4657f18ad6532e6adc3eafe67f1e5fa262af94cee8d3e7268593942a2a98df75154f8c914a282f8b":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #26 N: "6610145858169835373800827072568987987787972943497619105736762797475099959212160692262984293277166612477845864397201463825139894315919781838969391314120587" A: "136".
+mpi_mod_io:"7e35b84cb19ea5bc57ec37f5e431462fa962d98c1e63738d4657f18ad6532e6adc3eafe67f1e5fa262af94cee8d3e7268593942a2a98df75154f8c914a282f8b":"01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #27 N: "6610145858169835373800827072568987987787972943497619105736762797475099959212160692262984293277166612477845864397201463825139894315919781838969391314120587" A: "119".
+mpi_mod_io:"7e35b84cb19ea5bc57ec37f5e431462fa962d98c1e63738d4657f18ad6532e6adc3eafe67f1e5fa262af94cee8d3e7268593942a2a98df75154f8c914a282f8b":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ca":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #28 N: "6610145858169835373800827072568987987787972943497619105736762797475099959212160692262984293277166612477845864397201463825139894315919781838969391314120587" A: "136".
+mpi_mod_io:"7e35b84cb19ea5bc57ec37f5e431462fa962d98c1e63738d4657f18ad6532e6adc3eafe67f1e5fa262af94cee8d3e7268593942a2a98df75154f8c914a282f8b":"ca030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #29 N: "6610145858169835373800827072568987987787972943497619105736762797475099959212160692262984293277166612477845864397201463825139894315919781838969391314120587" A: "119".
+mpi_mod_io:"7e35b84cb19ea5bc57ec37f5e431462fa962d98c1e63738d4657f18ad6532e6adc3eafe67f1e5fa262af94cee8d3e7268593942a2a98df75154f8c914a282f8b":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000539ed428":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #30 N: "6610145858169835373800827072568987987787972943497619105736762797475099959212160692262984293277166612477845864397201463825139894315919781838969391314120587" A: "136".
+mpi_mod_io:"7e35b84cb19ea5bc57ec37f5e431462fa962d98c1e63738d4657f18ad6532e6adc3eafe67f1e5fa262af94cee8d3e7268593942a2a98df75154f8c914a282f8b":"28d49e53000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #31 N: "6610145858169835373800827072568987987787972943497619105736762797475099959212160692262984293277166612477845864397201463825139894315919781838969391314120587" A: "119".
+mpi_mod_io:"7e35b84cb19ea5bc57ec37f5e431462fa962d98c1e63738d4657f18ad6532e6adc3eafe67f1e5fa262af94cee8d3e7268593942a2a98df75154f8c914a282f8b":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007dfe5c6beb35a2d6":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #32 N: "6610145858169835373800827072568987987787972943497619105736762797475099959212160692262984293277166612477845864397201463825139894315919781838969391314120587" A: "136".
+mpi_mod_io:"7e35b84cb19ea5bc57ec37f5e431462fa962d98c1e63738d4657f18ad6532e6adc3eafe67f1e5fa262af94cee8d3e7268593942a2a98df75154f8c914a282f8b":"d6a235eb6b5cfe7d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #33 N: "6610145858169835373800827072568987987787972943497619105736762797475099959212160692262984293277166612477845864397201463825139894315919781838969391314120587" A: "119".
+mpi_mod_io:"7e35b84cb19ea5bc57ec37f5e431462fa962d98c1e63738d4657f18ad6532e6adc3eafe67f1e5fa262af94cee8d3e7268593942a2a98df75154f8c914a282f8b":"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dca8de1c2adfc6d7aafb9b48e":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #34 N: "6610145858169835373800827072568987987787972943497619105736762797475099959212160692262984293277166612477845864397201463825139894315919781838969391314120587" A: "136".
+mpi_mod_io:"7e35b84cb19ea5bc57ec37f5e431462fa962d98c1e63738d4657f18ad6532e6adc3eafe67f1e5fa262af94cee8d3e7268593942a2a98df75154f8c914a282f8b":"8eb4b9af7a6dfcadc2e18dca0d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #35 N: "6610145858169835373800827072568987987787972943497619105736762797475099959212160692262984293277166612477845864397201463825139894315919781838969391314120587" A: "119".
+mpi_mod_io:"7e35b84cb19ea5bc57ec37f5e431462fa962d98c1e63738d4657f18ad6532e6adc3eafe67f1e5fa262af94cee8d3e7268593942a2a98df75154f8c914a282f8b":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7d17b6c4be72f3d5c16bf9c1af6fc933":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #36 N: "6610145858169835373800827072568987987787972943497619105736762797475099959212160692262984293277166612477845864397201463825139894315919781838969391314120587" A: "136".
+mpi_mod_io:"7e35b84cb19ea5bc57ec37f5e431462fa962d98c1e63738d4657f18ad6532e6adc3eafe67f1e5fa262af94cee8d3e7268593942a2a98df75154f8c914a282f8b":"33c96fafc1f96bc1d5f372bec4b6177d0a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #37 N: "6610145858169835373800827072568987987787972943497619105736762797475099959212160692262984293277166612477845864397201463825139894315919781838969391314120587" A: "119".
+mpi_mod_io:"7e35b84cb19ea5bc57ec37f5e431462fa962d98c1e63738d4657f18ad6532e6adc3eafe67f1e5fa262af94cee8d3e7268593942a2a98df75154f8c914a282f8b":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002fec97beec546f9553142ed52f147845463f579":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #38 N: "6610145858169835373800827072568987987787972943497619105736762797475099959212160692262984293277166612477845864397201463825139894315919781838969391314120587" A: "136".
+mpi_mod_io:"7e35b84cb19ea5bc57ec37f5e431462fa962d98c1e63738d4657f18ad6532e6adc3eafe67f1e5fa262af94cee8d3e7268593942a2a98df75154f8c914a282f8b":"79f563548447f152ed423155f946c5ee7bc9fe020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #39 N: "6610145858169835373800827072568987987787972943497619105736762797475099959212160692262984293277166612477845864397201463825139894315919781838969391314120587" A: "119".
+mpi_mod_io:"7e35b84cb19ea5bc57ec37f5e431462fa962d98c1e63738d4657f18ad6532e6adc3eafe67f1e5fa262af94cee8d3e7268593942a2a98df75154f8c914a282f8b":"00000000000000000000000000000000000000000000000000000000000000000000000000000000378dc83b8bc5a7b62cba495af4919578dce6d4f175cadc4f":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #40 N: "6610145858169835373800827072568987987787972943497619105736762797475099959212160692262984293277166612477845864397201463825139894315919781838969391314120587" A: "136".
+mpi_mod_io:"7e35b84cb19ea5bc57ec37f5e431462fa962d98c1e63738d4657f18ad6532e6adc3eafe67f1e5fa262af94cee8d3e7268593942a2a98df75154f8c914a282f8b":"4fdcca75f1d4e6dc789591f45a49ba2cb6a7c58b3bc88d3700000000000000000000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #41 N: "201076468338594879614802819276237850336264827391977454179" A: "119".
+mpi_mod_io:"08335616aed761f1f7f44e6bd49e807b82e3bf2bf11bfa63":"000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #42 N: "201076468338594879614802819276237850336264827391977454179" A: "136".
+mpi_mod_io:"08335616aed761f1f7f44e6bd49e807b82e3bf2bf11bfa63":"000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #43 N: "201076468338594879614802819276237850336264827391977454179" A: "119".
+mpi_mod_io:"08335616aed761f1f7f44e6bd49e807b82e3bf2bf11bfa63":"000000000000000000000000000000000000000000000001":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #44 N: "201076468338594879614802819276237850336264827391977454179" A: "136".
+mpi_mod_io:"08335616aed761f1f7f44e6bd49e807b82e3bf2bf11bfa63":"010000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #45 N: "201076468338594879614802819276237850336264827391977454179" A: "119".
+mpi_mod_io:"08335616aed761f1f7f44e6bd49e807b82e3bf2bf11bfa63":"0000000000000000000000000000000000000000000003ca":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #46 N: "201076468338594879614802819276237850336264827391977454179" A: "136".
+mpi_mod_io:"08335616aed761f1f7f44e6bd49e807b82e3bf2bf11bfa63":"ca0300000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #47 N: "201076468338594879614802819276237850336264827391977454179" A: "119".
+mpi_mod_io:"08335616aed761f1f7f44e6bd49e807b82e3bf2bf11bfa63":"0000000000000000000000000000000000000000539ed428":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #48 N: "201076468338594879614802819276237850336264827391977454179" A: "136".
+mpi_mod_io:"08335616aed761f1f7f44e6bd49e807b82e3bf2bf11bfa63":"28d49e530000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #49 N: "201076468338594879614802819276237850336264827391977454179" A: "119".
+mpi_mod_io:"08335616aed761f1f7f44e6bd49e807b82e3bf2bf11bfa63":"000000000000000000000000000000007dfe5c6beb35a2d6":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #50 N: "201076468338594879614802819276237850336264827391977454179" A: "136".
+mpi_mod_io:"08335616aed761f1f7f44e6bd49e807b82e3bf2bf11bfa63":"d6a235eb6b5cfe7d00000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #51 N: "201076468338594879614802819276237850336264827391977454179" A: "119".
+mpi_mod_io:"08335616aed761f1f7f44e6bd49e807b82e3bf2bf11bfa63":"00000000000000000000000dca8de1c2adfc6d7aafb9b48e":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #52 N: "201076468338594879614802819276237850336264827391977454179" A: "136".
+mpi_mod_io:"08335616aed761f1f7f44e6bd49e807b82e3bf2bf11bfa63":"8eb4b9af7a6dfcadc2e18dca0d0000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #53 N: "201076468338594879614802819276237850336264827391977454179" A: "119".
+mpi_mod_io:"08335616aed761f1f7f44e6bd49e807b82e3bf2bf11bfa63":"000000000000000a7d17b6c4be72f3d5c16bf9c1af6fc933":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #54 N: "201076468338594879614802819276237850336264827391977454179" A: "136".
+mpi_mod_io:"08335616aed761f1f7f44e6bd49e807b82e3bf2bf11bfa63":"33c96fafc1f96bc1d5f372bec4b6177d0a00000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #55 N: "201076468338594879614802819276237850336264827391977454179" A: "119".
+mpi_mod_io:"08335616aed761f1f7f44e6bd49e807b82e3bf2bf11bfa63":"0000000002fec97beec546f9553142ed52f147845463f579":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #56 N: "201076468338594879614802819276237850336264827391977454179" A: "136".
+mpi_mod_io:"08335616aed761f1f7f44e6bd49e807b82e3bf2bf11bfa63":"79f563548447f152ed423155f946c5ee7bc9fe0200000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #57 N: "32292747613635961694771916499883650667878589411552643628627186850993060141490368296439843252993342320145797691611646027435006878234727648863911408777308953382400333083852585109256846643097239747078406546553406955958288616728627292699264194880486908744773379992784153004816057528456043920098334713005039494478693892693017304730883448003944721685094014669042959451482141781404822386404101555113742346277194830729517252154824958327000717338180410404929239489607893939166712107274943411892079802406181464789204374234653633818543559183821503846194953493439237710780169796543565449952151334229364816621060143650318299210551" A: "119".
+mpi_mod_io:"ffcece570f2f991013f26dd5b03c4c5b65f97be5905f36cb4664f2c78ff80aa8135a4aaf57ccb8a0aca2f394909a74cef1ef6758a64d11e2c149c393659d124bfc94196f0ce88f7d7d567efa5a649e2deefaa6e10fdc3deac60d606bf63fc540ac95294347031aefd73d6a9ee10188aaeb7a90d920894553cb196881691cadc51808715a07e8b24fcb1a63df047c7cdf084dd177ba368c806f3d51ddb5d3898c863e687ecaf7d649a57a46264a582f94d3c8f2edaf59f77a7f6bdaf83c991e8f06abe220ec8507386fce8c3da84c6c3903ab8f3ad4630a204196a7dbcbd9bcca4e40ec5cc5c09938d49f5e1e6181db8896f33bb12e6ef73f12ec5c5ea7a8a337":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #58 N: "32292747613635961694771916499883650667878589411552643628627186850993060141490368296439843252993342320145797691611646027435006878234727648863911408777308953382400333083852585109256846643097239747078406546553406955958288616728627292699264194880486908744773379992784153004816057528456043920098334713005039494478693892693017304730883448003944721685094014669042959451482141781404822386404101555113742346277194830729517252154824958327000717338180410404929239489607893939166712107274943411892079802406181464789204374234653633818543559183821503846194953493439237710780169796543565449952151334229364816621060143650318299210551" A: "136".
+mpi_mod_io:"ffcece570f2f991013f26dd5b03c4c5b65f97be5905f36cb4664f2c78ff80aa8135a4aaf57ccb8a0aca2f394909a74cef1ef6758a64d11e2c149c393659d124bfc94196f0ce88f7d7d567efa5a649e2deefaa6e10fdc3deac60d606bf63fc540ac95294347031aefd73d6a9ee10188aaeb7a90d920894553cb196881691cadc51808715a07e8b24fcb1a63df047c7cdf084dd177ba368c806f3d51ddb5d3898c863e687ecaf7d649a57a46264a582f94d3c8f2edaf59f77a7f6bdaf83c991e8f06abe220ec8507386fce8c3da84c6c3903ab8f3ad4630a204196a7dbcbd9bcca4e40ec5cc5c09938d49f5e1e6181db8896f33bb12e6ef73f12ec5c5ea7a8a337":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #59 N: "32292747613635961694771916499883650667878589411552643628627186850993060141490368296439843252993342320145797691611646027435006878234727648863911408777308953382400333083852585109256846643097239747078406546553406955958288616728627292699264194880486908744773379992784153004816057528456043920098334713005039494478693892693017304730883448003944721685094014669042959451482141781404822386404101555113742346277194830729517252154824958327000717338180410404929239489607893939166712107274943411892079802406181464789204374234653633818543559183821503846194953493439237710780169796543565449952151334229364816621060143650318299210551" A: "119".
+mpi_mod_io:"ffcece570f2f991013f26dd5b03c4c5b65f97be5905f36cb4664f2c78ff80aa8135a4aaf57ccb8a0aca2f394909a74cef1ef6758a64d11e2c149c393659d124bfc94196f0ce88f7d7d567efa5a649e2deefaa6e10fdc3deac60d606bf63fc540ac95294347031aefd73d6a9ee10188aaeb7a90d920894553cb196881691cadc51808715a07e8b24fcb1a63df047c7cdf084dd177ba368c806f3d51ddb5d3898c863e687ecaf7d649a57a46264a582f94d3c8f2edaf59f77a7f6bdaf83c991e8f06abe220ec8507386fce8c3da84c6c3903ab8f3ad4630a204196a7dbcbd9bcca4e40ec5cc5c09938d49f5e1e6181db8896f33bb12e6ef73f12ec5c5ea7a8a337":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #60 N: "32292747613635961694771916499883650667878589411552643628627186850993060141490368296439843252993342320145797691611646027435006878234727648863911408777308953382400333083852585109256846643097239747078406546553406955958288616728627292699264194880486908744773379992784153004816057528456043920098334713005039494478693892693017304730883448003944721685094014669042959451482141781404822386404101555113742346277194830729517252154824958327000717338180410404929239489607893939166712107274943411892079802406181464789204374234653633818543559183821503846194953493439237710780169796543565449952151334229364816621060143650318299210551" A: "136".
+mpi_mod_io:"ffcece570f2f991013f26dd5b03c4c5b65f97be5905f36cb4664f2c78ff80aa8135a4aaf57ccb8a0aca2f394909a74cef1ef6758a64d11e2c149c393659d124bfc94196f0ce88f7d7d567efa5a649e2deefaa6e10fdc3deac60d606bf63fc540ac95294347031aefd73d6a9ee10188aaeb7a90d920894553cb196881691cadc51808715a07e8b24fcb1a63df047c7cdf084dd177ba368c806f3d51ddb5d3898c863e687ecaf7d649a57a46264a582f94d3c8f2edaf59f77a7f6bdaf83c991e8f06abe220ec8507386fce8c3da84c6c3903ab8f3ad4630a204196a7dbcbd9bcca4e40ec5cc5c09938d49f5e1e6181db8896f33bb12e6ef73f12ec5c5ea7a8a337":"01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #61 N: "32292747613635961694771916499883650667878589411552643628627186850993060141490368296439843252993342320145797691611646027435006878234727648863911408777308953382400333083852585109256846643097239747078406546553406955958288616728627292699264194880486908744773379992784153004816057528456043920098334713005039494478693892693017304730883448003944721685094014669042959451482141781404822386404101555113742346277194830729517252154824958327000717338180410404929239489607893939166712107274943411892079802406181464789204374234653633818543559183821503846194953493439237710780169796543565449952151334229364816621060143650318299210551" A: "119".
+mpi_mod_io:"ffcece570f2f991013f26dd5b03c4c5b65f97be5905f36cb4664f2c78ff80aa8135a4aaf57ccb8a0aca2f394909a74cef1ef6758a64d11e2c149c393659d124bfc94196f0ce88f7d7d567efa5a649e2deefaa6e10fdc3deac60d606bf63fc540ac95294347031aefd73d6a9ee10188aaeb7a90d920894553cb196881691cadc51808715a07e8b24fcb1a63df047c7cdf084dd177ba368c806f3d51ddb5d3898c863e687ecaf7d649a57a46264a582f94d3c8f2edaf59f77a7f6bdaf83c991e8f06abe220ec8507386fce8c3da84c6c3903ab8f3ad4630a204196a7dbcbd9bcca4e40ec5cc5c09938d49f5e1e6181db8896f33bb12e6ef73f12ec5c5ea7a8a337":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ca":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #62 N: "32292747613635961694771916499883650667878589411552643628627186850993060141490368296439843252993342320145797691611646027435006878234727648863911408777308953382400333083852585109256846643097239747078406546553406955958288616728627292699264194880486908744773379992784153004816057528456043920098334713005039494478693892693017304730883448003944721685094014669042959451482141781404822386404101555113742346277194830729517252154824958327000717338180410404929239489607893939166712107274943411892079802406181464789204374234653633818543559183821503846194953493439237710780169796543565449952151334229364816621060143650318299210551" A: "136".
+mpi_mod_io:"ffcece570f2f991013f26dd5b03c4c5b65f97be5905f36cb4664f2c78ff80aa8135a4aaf57ccb8a0aca2f394909a74cef1ef6758a64d11e2c149c393659d124bfc94196f0ce88f7d7d567efa5a649e2deefaa6e10fdc3deac60d606bf63fc540ac95294347031aefd73d6a9ee10188aaeb7a90d920894553cb196881691cadc51808715a07e8b24fcb1a63df047c7cdf084dd177ba368c806f3d51ddb5d3898c863e687ecaf7d649a57a46264a582f94d3c8f2edaf59f77a7f6bdaf83c991e8f06abe220ec8507386fce8c3da84c6c3903ab8f3ad4630a204196a7dbcbd9bcca4e40ec5cc5c09938d49f5e1e6181db8896f33bb12e6ef73f12ec5c5ea7a8a337":"ca030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #63 N: "32292747613635961694771916499883650667878589411552643628627186850993060141490368296439843252993342320145797691611646027435006878234727648863911408777308953382400333083852585109256846643097239747078406546553406955958288616728627292699264194880486908744773379992784153004816057528456043920098334713005039494478693892693017304730883448003944721685094014669042959451482141781404822386404101555113742346277194830729517252154824958327000717338180410404929239489607893939166712107274943411892079802406181464789204374234653633818543559183821503846194953493439237710780169796543565449952151334229364816621060143650318299210551" A: "119".
+mpi_mod_io:"ffcece570f2f991013f26dd5b03c4c5b65f97be5905f36cb4664f2c78ff80aa8135a4aaf57ccb8a0aca2f394909a74cef1ef6758a64d11e2c149c393659d124bfc94196f0ce88f7d7d567efa5a649e2deefaa6e10fdc3deac60d606bf63fc540ac95294347031aefd73d6a9ee10188aaeb7a90d920894553cb196881691cadc51808715a07e8b24fcb1a63df047c7cdf084dd177ba368c806f3d51ddb5d3898c863e687ecaf7d649a57a46264a582f94d3c8f2edaf59f77a7f6bdaf83c991e8f06abe220ec8507386fce8c3da84c6c3903ab8f3ad4630a204196a7dbcbd9bcca4e40ec5cc5c09938d49f5e1e6181db8896f33bb12e6ef73f12ec5c5ea7a8a337":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000539ed428":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #64 N: "32292747613635961694771916499883650667878589411552643628627186850993060141490368296439843252993342320145797691611646027435006878234727648863911408777308953382400333083852585109256846643097239747078406546553406955958288616728627292699264194880486908744773379992784153004816057528456043920098334713005039494478693892693017304730883448003944721685094014669042959451482141781404822386404101555113742346277194830729517252154824958327000717338180410404929239489607893939166712107274943411892079802406181464789204374234653633818543559183821503846194953493439237710780169796543565449952151334229364816621060143650318299210551" A: "136".
+mpi_mod_io:"ffcece570f2f991013f26dd5b03c4c5b65f97be5905f36cb4664f2c78ff80aa8135a4aaf57ccb8a0aca2f394909a74cef1ef6758a64d11e2c149c393659d124bfc94196f0ce88f7d7d567efa5a649e2deefaa6e10fdc3deac60d606bf63fc540ac95294347031aefd73d6a9ee10188aaeb7a90d920894553cb196881691cadc51808715a07e8b24fcb1a63df047c7cdf084dd177ba368c806f3d51ddb5d3898c863e687ecaf7d649a57a46264a582f94d3c8f2edaf59f77a7f6bdaf83c991e8f06abe220ec8507386fce8c3da84c6c3903ab8f3ad4630a204196a7dbcbd9bcca4e40ec5cc5c09938d49f5e1e6181db8896f33bb12e6ef73f12ec5c5ea7a8a337":"28d49e53000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #65 N: "32292747613635961694771916499883650667878589411552643628627186850993060141490368296439843252993342320145797691611646027435006878234727648863911408777308953382400333083852585109256846643097239747078406546553406955958288616728627292699264194880486908744773379992784153004816057528456043920098334713005039494478693892693017304730883448003944721685094014669042959451482141781404822386404101555113742346277194830729517252154824958327000717338180410404929239489607893939166712107274943411892079802406181464789204374234653633818543559183821503846194953493439237710780169796543565449952151334229364816621060143650318299210551" A: "119".
+mpi_mod_io:"ffcece570f2f991013f26dd5b03c4c5b65f97be5905f36cb4664f2c78ff80aa8135a4aaf57ccb8a0aca2f394909a74cef1ef6758a64d11e2c149c393659d124bfc94196f0ce88f7d7d567efa5a649e2deefaa6e10fdc3deac60d606bf63fc540ac95294347031aefd73d6a9ee10188aaeb7a90d920894553cb196881691cadc51808715a07e8b24fcb1a63df047c7cdf084dd177ba368c806f3d51ddb5d3898c863e687ecaf7d649a57a46264a582f94d3c8f2edaf59f77a7f6bdaf83c991e8f06abe220ec8507386fce8c3da84c6c3903ab8f3ad4630a204196a7dbcbd9bcca4e40ec5cc5c09938d49f5e1e6181db8896f33bb12e6ef73f12ec5c5ea7a8a337":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007dfe5c6beb35a2d6":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #66 N: "32292747613635961694771916499883650667878589411552643628627186850993060141490368296439843252993342320145797691611646027435006878234727648863911408777308953382400333083852585109256846643097239747078406546553406955958288616728627292699264194880486908744773379992784153004816057528456043920098334713005039494478693892693017304730883448003944721685094014669042959451482141781404822386404101555113742346277194830729517252154824958327000717338180410404929239489607893939166712107274943411892079802406181464789204374234653633818543559183821503846194953493439237710780169796543565449952151334229364816621060143650318299210551" A: "136".
+mpi_mod_io:"ffcece570f2f991013f26dd5b03c4c5b65f97be5905f36cb4664f2c78ff80aa8135a4aaf57ccb8a0aca2f394909a74cef1ef6758a64d11e2c149c393659d124bfc94196f0ce88f7d7d567efa5a649e2deefaa6e10fdc3deac60d606bf63fc540ac95294347031aefd73d6a9ee10188aaeb7a90d920894553cb196881691cadc51808715a07e8b24fcb1a63df047c7cdf084dd177ba368c806f3d51ddb5d3898c863e687ecaf7d649a57a46264a582f94d3c8f2edaf59f77a7f6bdaf83c991e8f06abe220ec8507386fce8c3da84c6c3903ab8f3ad4630a204196a7dbcbd9bcca4e40ec5cc5c09938d49f5e1e6181db8896f33bb12e6ef73f12ec5c5ea7a8a337":"d6a235eb6b5cfe7d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #67 N: "32292747613635961694771916499883650667878589411552643628627186850993060141490368296439843252993342320145797691611646027435006878234727648863911408777308953382400333083852585109256846643097239747078406546553406955958288616728627292699264194880486908744773379992784153004816057528456043920098334713005039494478693892693017304730883448003944721685094014669042959451482141781404822386404101555113742346277194830729517252154824958327000717338180410404929239489607893939166712107274943411892079802406181464789204374234653633818543559183821503846194953493439237710780169796543565449952151334229364816621060143650318299210551" A: "119".
+mpi_mod_io:"ffcece570f2f991013f26dd5b03c4c5b65f97be5905f36cb4664f2c78ff80aa8135a4aaf57ccb8a0aca2f394909a74cef1ef6758a64d11e2c149c393659d124bfc94196f0ce88f7d7d567efa5a649e2deefaa6e10fdc3deac60d606bf63fc540ac95294347031aefd73d6a9ee10188aaeb7a90d920894553cb196881691cadc51808715a07e8b24fcb1a63df047c7cdf084dd177ba368c806f3d51ddb5d3898c863e687ecaf7d649a57a46264a582f94d3c8f2edaf59f77a7f6bdaf83c991e8f06abe220ec8507386fce8c3da84c6c3903ab8f3ad4630a204196a7dbcbd9bcca4e40ec5cc5c09938d49f5e1e6181db8896f33bb12e6ef73f12ec5c5ea7a8a337":"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dca8de1c2adfc6d7aafb9b48e":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #68 N: "32292747613635961694771916499883650667878589411552643628627186850993060141490368296439843252993342320145797691611646027435006878234727648863911408777308953382400333083852585109256846643097239747078406546553406955958288616728627292699264194880486908744773379992784153004816057528456043920098334713005039494478693892693017304730883448003944721685094014669042959451482141781404822386404101555113742346277194830729517252154824958327000717338180410404929239489607893939166712107274943411892079802406181464789204374234653633818543559183821503846194953493439237710780169796543565449952151334229364816621060143650318299210551" A: "136".
+mpi_mod_io:"ffcece570f2f991013f26dd5b03c4c5b65f97be5905f36cb4664f2c78ff80aa8135a4aaf57ccb8a0aca2f394909a74cef1ef6758a64d11e2c149c393659d124bfc94196f0ce88f7d7d567efa5a649e2deefaa6e10fdc3deac60d606bf63fc540ac95294347031aefd73d6a9ee10188aaeb7a90d920894553cb196881691cadc51808715a07e8b24fcb1a63df047c7cdf084dd177ba368c806f3d51ddb5d3898c863e687ecaf7d649a57a46264a582f94d3c8f2edaf59f77a7f6bdaf83c991e8f06abe220ec8507386fce8c3da84c6c3903ab8f3ad4630a204196a7dbcbd9bcca4e40ec5cc5c09938d49f5e1e6181db8896f33bb12e6ef73f12ec5c5ea7a8a337":"8eb4b9af7a6dfcadc2e18dca0d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #69 N: "32292747613635961694771916499883650667878589411552643628627186850993060141490368296439843252993342320145797691611646027435006878234727648863911408777308953382400333083852585109256846643097239747078406546553406955958288616728627292699264194880486908744773379992784153004816057528456043920098334713005039494478693892693017304730883448003944721685094014669042959451482141781404822386404101555113742346277194830729517252154824958327000717338180410404929239489607893939166712107274943411892079802406181464789204374234653633818543559183821503846194953493439237710780169796543565449952151334229364816621060143650318299210551" A: "119".
+mpi_mod_io:"ffcece570f2f991013f26dd5b03c4c5b65f97be5905f36cb4664f2c78ff80aa8135a4aaf57ccb8a0aca2f394909a74cef1ef6758a64d11e2c149c393659d124bfc94196f0ce88f7d7d567efa5a649e2deefaa6e10fdc3deac60d606bf63fc540ac95294347031aefd73d6a9ee10188aaeb7a90d920894553cb196881691cadc51808715a07e8b24fcb1a63df047c7cdf084dd177ba368c806f3d51ddb5d3898c863e687ecaf7d649a57a46264a582f94d3c8f2edaf59f77a7f6bdaf83c991e8f06abe220ec8507386fce8c3da84c6c3903ab8f3ad4630a204196a7dbcbd9bcca4e40ec5cc5c09938d49f5e1e6181db8896f33bb12e6ef73f12ec5c5ea7a8a337":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7d17b6c4be72f3d5c16bf9c1af6fc933":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #70 N: "32292747613635961694771916499883650667878589411552643628627186850993060141490368296439843252993342320145797691611646027435006878234727648863911408777308953382400333083852585109256846643097239747078406546553406955958288616728627292699264194880486908744773379992784153004816057528456043920098334713005039494478693892693017304730883448003944721685094014669042959451482141781404822386404101555113742346277194830729517252154824958327000717338180410404929239489607893939166712107274943411892079802406181464789204374234653633818543559183821503846194953493439237710780169796543565449952151334229364816621060143650318299210551" A: "136".
+mpi_mod_io:"ffcece570f2f991013f26dd5b03c4c5b65f97be5905f36cb4664f2c78ff80aa8135a4aaf57ccb8a0aca2f394909a74cef1ef6758a64d11e2c149c393659d124bfc94196f0ce88f7d7d567efa5a649e2deefaa6e10fdc3deac60d606bf63fc540ac95294347031aefd73d6a9ee10188aaeb7a90d920894553cb196881691cadc51808715a07e8b24fcb1a63df047c7cdf084dd177ba368c806f3d51ddb5d3898c863e687ecaf7d649a57a46264a582f94d3c8f2edaf59f77a7f6bdaf83c991e8f06abe220ec8507386fce8c3da84c6c3903ab8f3ad4630a204196a7dbcbd9bcca4e40ec5cc5c09938d49f5e1e6181db8896f33bb12e6ef73f12ec5c5ea7a8a337":"33c96fafc1f96bc1d5f372bec4b6177d0a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #71 N: "32292747613635961694771916499883650667878589411552643628627186850993060141490368296439843252993342320145797691611646027435006878234727648863911408777308953382400333083852585109256846643097239747078406546553406955958288616728627292699264194880486908744773379992784153004816057528456043920098334713005039494478693892693017304730883448003944721685094014669042959451482141781404822386404101555113742346277194830729517252154824958327000717338180410404929239489607893939166712107274943411892079802406181464789204374234653633818543559183821503846194953493439237710780169796543565449952151334229364816621060143650318299210551" A: "119".
+mpi_mod_io:"ffcece570f2f991013f26dd5b03c4c5b65f97be5905f36cb4664f2c78ff80aa8135a4aaf57ccb8a0aca2f394909a74cef1ef6758a64d11e2c149c393659d124bfc94196f0ce88f7d7d567efa5a649e2deefaa6e10fdc3deac60d606bf63fc540ac95294347031aefd73d6a9ee10188aaeb7a90d920894553cb196881691cadc51808715a07e8b24fcb1a63df047c7cdf084dd177ba368c806f3d51ddb5d3898c863e687ecaf7d649a57a46264a582f94d3c8f2edaf59f77a7f6bdaf83c991e8f06abe220ec8507386fce8c3da84c6c3903ab8f3ad4630a204196a7dbcbd9bcca4e40ec5cc5c09938d49f5e1e6181db8896f33bb12e6ef73f12ec5c5ea7a8a337":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002fec97beec546f9553142ed52f147845463f579":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #72 N: "32292747613635961694771916499883650667878589411552643628627186850993060141490368296439843252993342320145797691611646027435006878234727648863911408777308953382400333083852585109256846643097239747078406546553406955958288616728627292699264194880486908744773379992784153004816057528456043920098334713005039494478693892693017304730883448003944721685094014669042959451482141781404822386404101555113742346277194830729517252154824958327000717338180410404929239489607893939166712107274943411892079802406181464789204374234653633818543559183821503846194953493439237710780169796543565449952151334229364816621060143650318299210551" A: "136".
+mpi_mod_io:"ffcece570f2f991013f26dd5b03c4c5b65f97be5905f36cb4664f2c78ff80aa8135a4aaf57ccb8a0aca2f394909a74cef1ef6758a64d11e2c149c393659d124bfc94196f0ce88f7d7d567efa5a649e2deefaa6e10fdc3deac60d606bf63fc540ac95294347031aefd73d6a9ee10188aaeb7a90d920894553cb196881691cadc51808715a07e8b24fcb1a63df047c7cdf084dd177ba368c806f3d51ddb5d3898c863e687ecaf7d649a57a46264a582f94d3c8f2edaf59f77a7f6bdaf83c991e8f06abe220ec8507386fce8c3da84c6c3903ab8f3ad4630a204196a7dbcbd9bcca4e40ec5cc5c09938d49f5e1e6181db8896f33bb12e6ef73f12ec5c5ea7a8a337":"79f563548447f152ed423155f946c5ee7bc9fe020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #73 N: "32292747613635961694771916499883650667878589411552643628627186850993060141490368296439843252993342320145797691611646027435006878234727648863911408777308953382400333083852585109256846643097239747078406546553406955958288616728627292699264194880486908744773379992784153004816057528456043920098334713005039494478693892693017304730883448003944721685094014669042959451482141781404822386404101555113742346277194830729517252154824958327000717338180410404929239489607893939166712107274943411892079802406181464789204374234653633818543559183821503846194953493439237710780169796543565449952151334229364816621060143650318299210551" A: "119".
+mpi_mod_io:"ffcece570f2f991013f26dd5b03c4c5b65f97be5905f36cb4664f2c78ff80aa8135a4aaf57ccb8a0aca2f394909a74cef1ef6758a64d11e2c149c393659d124bfc94196f0ce88f7d7d567efa5a649e2deefaa6e10fdc3deac60d606bf63fc540ac95294347031aefd73d6a9ee10188aaeb7a90d920894553cb196881691cadc51808715a07e8b24fcb1a63df047c7cdf084dd177ba368c806f3d51ddb5d3898c863e687ecaf7d649a57a46264a582f94d3c8f2edaf59f77a7f6bdaf83c991e8f06abe220ec8507386fce8c3da84c6c3903ab8f3ad4630a204196a7dbcbd9bcca4e40ec5cc5c09938d49f5e1e6181db8896f33bb12e6ef73f12ec5c5ea7a8a337":"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000378dc83b8bc5a7b62cba495af4919578dce6d4f175cadc4f":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #74 N: "32292747613635961694771916499883650667878589411552643628627186850993060141490368296439843252993342320145797691611646027435006878234727648863911408777308953382400333083852585109256846643097239747078406546553406955958288616728627292699264194880486908744773379992784153004816057528456043920098334713005039494478693892693017304730883448003944721685094014669042959451482141781404822386404101555113742346277194830729517252154824958327000717338180410404929239489607893939166712107274943411892079802406181464789204374234653633818543559183821503846194953493439237710780169796543565449952151334229364816621060143650318299210551" A: "136".
+mpi_mod_io:"ffcece570f2f991013f26dd5b03c4c5b65f97be5905f36cb4664f2c78ff80aa8135a4aaf57ccb8a0aca2f394909a74cef1ef6758a64d11e2c149c393659d124bfc94196f0ce88f7d7d567efa5a649e2deefaa6e10fdc3deac60d606bf63fc540ac95294347031aefd73d6a9ee10188aaeb7a90d920894553cb196881691cadc51808715a07e8b24fcb1a63df047c7cdf084dd177ba368c806f3d51ddb5d3898c863e687ecaf7d649a57a46264a582f94d3c8f2edaf59f77a7f6bdaf83c991e8f06abe220ec8507386fce8c3da84c6c3903ab8f3ad4630a204196a7dbcbd9bcca4e40ec5cc5c09938d49f5e1e6181db8896f33bb12e6ef73f12ec5c5ea7a8a337":"4fdcca75f1d4e6dc789591f45a49ba2cb6a7c58b3bc88d3700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000":MBEDTLS_MPI_MOD_EXT_REP_LE
+
+Test mbedtls_mpi_mod_io #75 N: "32292747613635961694771916499883650667878589411552643628627186850993060141490368296439843252993342320145797691611646027435006878234727648863911408777308953382400333083852585109256846643097239747078406546553406955958288616728627292699264194880486908744773379992784153004816057528456043920098334713005039494478693892693017304730883448003944721685094014669042959451482141781404822386404101555113742346277194830729517252154824958327000717338180410404929239489607893939166712107274943411892079802406181464789204374234653633818543559183821503846194953493439237710780169796543565449952151334229364816621060143650318299210551" A: "119".
+mpi_mod_io:"ffcece570f2f991013f26dd5b03c4c5b65f97be5905f36cb4664f2c78ff80aa8135a4aaf57ccb8a0aca2f394909a74cef1ef6758a64d11e2c149c393659d124bfc94196f0ce88f7d7d567efa5a649e2deefaa6e10fdc3deac60d606bf63fc540ac95294347031aefd73d6a9ee10188aaeb7a90d920894553cb196881691cadc51808715a07e8b24fcb1a63df047c7cdf084dd177ba368c806f3d51ddb5d3898c863e687ecaf7d649a57a46264a582f94d3c8f2edaf59f77a7f6bdaf83c991e8f06abe220ec8507386fce8c3da84c6c3903ab8f3ad4630a204196a7dbcbd9bcca4e40ec5cc5c09938d49f5e1e6181db8896f33bb12e6ef73f12ec5c5ea7a8a337":"b6415f2a1a8e48a518345db11f56db3829c8f2c6415ab4a395ab3ac2ea4cbef4af86eb18a84eb6ded4c6ecbfc4b59c2879a675487f687adea9d197a84a5242a5cf6125ce19a6ad2e7341f1c57d43ea4f4c852a51cb63dabcd1c9de2b827a3146a3d175b35bea41ae75d2a286a3e9d43623152ac513dcdea1d72a7da846a8ab358d9be4926c79cfb287cf1cf25b689de3b912176be5dcaf4d4c6e7cb839a4a3243a6c47c1e2c99d65c59d6fa3672575c2f1ca8de6a32e854ec9d8ec635c96af7679fce26d7d159e4a9da3bd74e1272c376cd926d74fe3fb164a5935cff3d5cdb92b35fe2cea32138a7e6bfbc319ebd1725dacb9a359cbf693f2ecb785efb9d627":MBEDTLS_MPI_MOD_EXT_REP_BE
+
+Test mbedtls_mpi_mod_io #76 N: "32292747613635961694771916499883650667878589411552643628627186850993060141490368296439843252993342320145797691611646027435006878234727648863911408777308953382400333083852585109256846643097239747078406546553406955958288616728627292699264194880486908744773379992784153004816057528456043920098334713005039494478693892693017304730883448003944721685094014669042959451482141781404822386404101555113742346277194830729517252154824958327000717338180410404929239489607893939166712107274943411892079802406181464789204374234653633818543559183821503846194953493439237710780169796543565449952151334229364816621060143650318299210551" A: "136".
+mpi_mod_io:"ffcece570f2f991013f26dd5b03c4c5b65f97be5905f36cb4664f2c78ff80aa8135a4aaf57ccb8a0aca2f394909a74cef1ef6758a64d11e2c149c393659d124bfc94196f0ce88f7d7d567efa5a649e2deefaa6e10fdc3deac60d606bf63fc540ac95294347031aefd73d6a9ee10188aaeb7a90d920894553cb196881691cadc51808715a07e8b24fcb1a63df047c7cdf084dd177ba368c806f3d51ddb5d3898c863e687ecaf7d649a57a46264a582f94d3c8f2edaf59f77a7f6bdaf83c991e8f06abe220ec8507386fce8c3da84c6c3903ab8f3ad4630a204196a7dbcbd9bcca4e40ec5cc5c09938d49f5e1e6181db8896f33bb12e6ef73f12ec5c5ea7a8a337":"27d6b9ef85b7ecf293f6cb59a3b9ac5d72d1eb19c3fb6b7e8a1332ea2cfe352bb9cdd5f3cf35594a16fbe34fd726d96c372c27e174bda39d4a9e157d6de2fc7976af965c63ecd8c94e852ea3e68dcaf1c2752567a36f9dc5659dc9e2c1476c3a24a3a439b87c6e4c4dafdce56b1712b9e39d685bf21ccf87b2cf796c92e49b8d35aba846a87d2ad7a1dedc13c52a152336d4e9a386a2d275ae41ea5bb375d1a346317a822bdec9d1bcda63cb512a854c4fea437dc5f141732eada619ce2561cfa542524aa897d1a9de7a687f4875a679289cb5c4bfecc6d4deb64ea818eb86aff4be4ceac23aab95a3b45a41c6f2c82938db561fb15d3418a5488e1a2a5f41b6":MBEDTLS_MPI_MOD_EXT_REP_LE
diff --git a/tests/suites/test_suite_bignum_mod_raw.function b/tests/suites/test_suite_bignum_mod_raw.function
index 4b90675..4a658e1 100644
--- a/tests/suites/test_suite_bignum_mod_raw.function
+++ b/tests/suites/test_suite_bignum_mod_raw.function
@@ -49,22 +49,22 @@
 
     mbedtls_mpi_uint init[sizeof( X ) / sizeof( X[0] )];
     memset( init, 0xFF, sizeof( init ) );
-    int ret = mbedtls_mpi_mod_modulus_setup( &m, init, nx, endian,
+    int ret = mbedtls_mpi_mod_modulus_setup( &m, init, nx,
                                              MBEDTLS_MPI_MOD_REP_MONTGOMERY );
     TEST_EQUAL( ret, 0 );
 
     if( iendian == MBEDTLS_MPI_MOD_EXT_REP_INVALID && iret != 0 )
-        m.ext_rep = MBEDTLS_MPI_MOD_EXT_REP_INVALID;
+       endian = MBEDTLS_MPI_MOD_EXT_REP_INVALID;
 
-    ret = mbedtls_mpi_mod_raw_read( X, &m, input->x, input->len );
+    ret = mbedtls_mpi_mod_raw_read( X, &m, input->x, input->len, endian );
     TEST_EQUAL( ret, iret );
 
     if( iret == 0 )
     {
         if( iendian == MBEDTLS_MPI_MOD_EXT_REP_INVALID && oret != 0 )
-            m.ext_rep = MBEDTLS_MPI_MOD_EXT_REP_INVALID;
+            endian = MBEDTLS_MPI_MOD_EXT_REP_INVALID;
 
-        ret = mbedtls_mpi_mod_raw_write( X, &m, buf, nb );
+        ret = mbedtls_mpi_mod_raw_write( X, &m, buf, nb, endian );
         TEST_EQUAL( ret, oret );
     }
 
@@ -117,10 +117,12 @@
     mbedtls_mpi_uint *X = NULL;
     mbedtls_mpi_uint *Y = NULL;
     mbedtls_mpi_uint *buff_m = NULL;
-    mbedtls_mpi_mod_modulus m;
     size_t limbs_X;
     size_t limbs_Y;
 
+    mbedtls_mpi_mod_modulus m;
+    mbedtls_mpi_mod_modulus_init( &m );
+
     TEST_EQUAL( mbedtls_test_read_mpi_core( &X, &limbs_X, input_X ), 0 );
     TEST_EQUAL( mbedtls_test_read_mpi_core( &Y, &limbs_Y, input_Y ), 0 );
 
@@ -129,8 +131,6 @@
     size_t bytes = limbs * sizeof( mbedtls_mpi_uint );
     size_t copy_bytes = copy_limbs * sizeof( mbedtls_mpi_uint );
 
-    mbedtls_mpi_mod_modulus_init( &m );
-
     TEST_EQUAL( limbs_X, limbs_Y );
     TEST_ASSERT( copy_limbs <= limbs );
 
@@ -138,7 +138,6 @@
     memset( buff_m, 0xFF, copy_limbs );
     TEST_EQUAL( mbedtls_mpi_mod_modulus_setup(
                         &m, buff_m, copy_limbs,
-                        MBEDTLS_MPI_MOD_EXT_REP_BE,
                         MBEDTLS_MPI_MOD_REP_MONTGOMERY ), 0 );
 
     /* condition is false */
@@ -190,10 +189,12 @@
     mbedtls_mpi_uint *X = NULL;
     mbedtls_mpi_uint *Y = NULL;
     mbedtls_mpi_uint *buff_m = NULL;
-    mbedtls_mpi_mod_modulus m;
     size_t limbs_X;
     size_t limbs_Y;
 
+    mbedtls_mpi_mod_modulus m;
+    mbedtls_mpi_mod_modulus_init( &m );
+
     TEST_EQUAL( mbedtls_test_read_mpi_core( &tmp_X, &limbs_X, input_X ), 0 );
     TEST_EQUAL( mbedtls_test_read_mpi_core( &tmp_Y, &limbs_Y, input_Y ), 0 );
 
@@ -202,8 +203,6 @@
     size_t bytes = limbs * sizeof( mbedtls_mpi_uint );
     size_t copy_bytes = copy_limbs * sizeof( mbedtls_mpi_uint );
 
-    mbedtls_mpi_mod_modulus_init( &m );
-
     TEST_EQUAL( limbs_X, limbs_Y );
     TEST_ASSERT( copy_limbs <= limbs );
 
@@ -211,7 +210,6 @@
     memset( buff_m, 0xFF, copy_limbs );
     TEST_EQUAL( mbedtls_mpi_mod_modulus_setup(
                         &m, buff_m, copy_limbs,
-                        MBEDTLS_MPI_MOD_EXT_REP_BE,
                         MBEDTLS_MPI_MOD_REP_MONTGOMERY ), 0 );
 
     ASSERT_ALLOC( X, limbs );
@@ -275,10 +273,250 @@
 
 /* BEGIN MERGE SLOT 2 */
 
+/* BEGIN_CASE */
+void mpi_mod_raw_sub( char * input_A,
+                      char * input_B,
+                      char * input_N,
+                      char * result )
+{
+    mbedtls_mpi_uint *A = NULL;
+    mbedtls_mpi_uint *B = NULL;
+    mbedtls_mpi_uint *N = NULL;
+    mbedtls_mpi_uint *X = NULL;
+    mbedtls_mpi_uint *res = NULL;
+    size_t limbs_A;
+    size_t limbs_B;
+    size_t limbs_N;
+    size_t limbs_res;
+
+    mbedtls_mpi_mod_modulus m;
+    mbedtls_mpi_mod_modulus_init( &m );
+
+    TEST_EQUAL( mbedtls_test_read_mpi_core( &A,   &limbs_A,   input_A ), 0 );
+    TEST_EQUAL( mbedtls_test_read_mpi_core( &B,   &limbs_B,   input_B ), 0 );
+    TEST_EQUAL( mbedtls_test_read_mpi_core( &N,   &limbs_N,   input_N ), 0 );
+    TEST_EQUAL( mbedtls_test_read_mpi_core( &res, &limbs_res, result  ), 0 );
+
+    size_t limbs = limbs_N;
+    size_t bytes = limbs * sizeof( mbedtls_mpi_uint );
+
+    TEST_EQUAL( limbs_A,   limbs );
+    TEST_EQUAL( limbs_B,   limbs );
+    TEST_EQUAL( limbs_res, limbs );
+
+    ASSERT_ALLOC( X, limbs );
+
+    TEST_EQUAL( mbedtls_mpi_mod_modulus_setup(
+                        &m, N, limbs,
+                        MBEDTLS_MPI_MOD_REP_MONTGOMERY ), 0 );
+
+    mbedtls_mpi_mod_raw_sub( X, A, B, &m );
+    ASSERT_COMPARE( X, bytes, res, bytes );
+
+    /* alias X to A */
+    memcpy( X, A, bytes );
+    mbedtls_mpi_mod_raw_sub( X, X, B, &m );
+    ASSERT_COMPARE( X, bytes, res, bytes );
+
+    /* alias X to B */
+    memcpy( X, B, bytes );
+    mbedtls_mpi_mod_raw_sub( X, A, X, &m );
+    ASSERT_COMPARE( X, bytes, res, bytes );
+
+    /* A == B: alias A and B */
+    if( memcmp( A, B, bytes ) == 0 )
+    {
+        mbedtls_mpi_mod_raw_sub( X, A, A, &m );
+        ASSERT_COMPARE( X, bytes, res, bytes );
+
+        /* X, A, B all aliased together */
+        memcpy( X, A, bytes );
+        mbedtls_mpi_mod_raw_sub( X, X, X, &m );
+        ASSERT_COMPARE( X, bytes, res, bytes );
+    }
+exit:
+    mbedtls_free( A );
+    mbedtls_free( B );
+    mbedtls_free( X );
+    mbedtls_free( res );
+
+    mbedtls_mpi_mod_modulus_free( &m );
+    mbedtls_free( N );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mpi_mod_raw_mul( char * input_A,
+                      char * input_B,
+                      char * input_N,
+                      char * result )
+{
+    mbedtls_mpi_uint *A = NULL;
+    mbedtls_mpi_uint *B = NULL;
+    mbedtls_mpi_uint *N = NULL;
+    mbedtls_mpi_uint *X = NULL;
+    mbedtls_mpi_uint *R = NULL;
+    mbedtls_mpi_uint *T = NULL;
+    size_t limbs_A;
+    size_t limbs_B;
+    size_t limbs_N;
+    size_t limbs_R;
+
+    mbedtls_mpi_mod_modulus m;
+    mbedtls_mpi_mod_modulus_init( &m );
+
+    TEST_EQUAL( mbedtls_test_read_mpi_core( &A, &limbs_A, input_A ), 0 );
+    TEST_EQUAL( mbedtls_test_read_mpi_core( &B, &limbs_B, input_B ), 0 );
+    TEST_EQUAL( mbedtls_test_read_mpi_core( &N, &limbs_N, input_N ), 0 );
+    TEST_EQUAL( mbedtls_test_read_mpi_core( &R, &limbs_R, result  ), 0 );
+
+    const size_t limbs = limbs_N;
+    const size_t bytes = limbs * sizeof( mbedtls_mpi_uint );
+
+    TEST_EQUAL( limbs_A, limbs );
+    TEST_EQUAL( limbs_B, limbs );
+    TEST_EQUAL( limbs_R, limbs );
+
+    ASSERT_ALLOC( X, limbs );
+
+    TEST_EQUAL( mbedtls_mpi_mod_modulus_setup(
+                        &m, N, limbs,
+                        MBEDTLS_MPI_MOD_REP_MONTGOMERY ), 0 );
+
+    const size_t limbs_T = limbs * 2 + 1;
+    ASSERT_ALLOC( T, limbs_T );
+
+    mbedtls_mpi_mod_raw_mul( X, A, B, &m, T );
+    ASSERT_COMPARE( X, bytes, R, bytes );
+
+    /* alias X to A */
+    memcpy( X, A, bytes );
+    mbedtls_mpi_mod_raw_mul( X, X, B, &m, T );
+    ASSERT_COMPARE( X, bytes, R, bytes );
+
+    /* alias X to B */
+    memcpy( X, B, bytes );
+    mbedtls_mpi_mod_raw_mul( X, A, X, &m, T );
+    ASSERT_COMPARE( X, bytes, R, bytes );
+
+    /* A == B: alias A and B */
+    if( memcmp( A, B, bytes ) == 0 )
+    {
+        mbedtls_mpi_mod_raw_mul( X, A, A, &m, T );
+        ASSERT_COMPARE( X, bytes, R, bytes );
+
+        /* X, A, B all aliased together */
+        memcpy( X, A, bytes );
+        mbedtls_mpi_mod_raw_mul( X, X, X, &m, T );
+        ASSERT_COMPARE( X, bytes, R, bytes );
+    }
+
+    /* A != B: test B * A */
+    else
+    {
+        mbedtls_mpi_mod_raw_mul( X, B, A, &m, T );
+        ASSERT_COMPARE( X, bytes, R, bytes );
+
+        /* B * A: alias X to A */
+        memcpy( X, A, bytes );
+        mbedtls_mpi_mod_raw_mul( X, B, X, &m, T );
+        ASSERT_COMPARE( X, bytes, R, bytes );
+
+        /* B + A: alias X to B */
+        memcpy( X, B, bytes );
+        mbedtls_mpi_mod_raw_mul( X, X, A, &m, T );
+        ASSERT_COMPARE( X, bytes, R, bytes );
+    }
+
+exit:
+    mbedtls_free( A );
+    mbedtls_free( B );
+    mbedtls_free( X );
+    mbedtls_free( R );
+    mbedtls_free( T );
+
+    mbedtls_mpi_mod_modulus_free( &m );
+    mbedtls_free( N );
+}
+/* END_CASE */
+
 /* END MERGE SLOT 2 */
 
 /* BEGIN MERGE SLOT 3 */
 
+/* BEGIN_CASE */
+void mpi_mod_raw_inv_prime( char * input_N, char * input_A, char * input_X )
+{
+    mbedtls_mpi_uint *A = NULL;
+    mbedtls_mpi_uint *N = NULL;
+    mbedtls_mpi_uint *X = NULL;
+    size_t A_limbs, N_limbs, X_limbs;
+    mbedtls_mpi_uint *Y = NULL;
+    mbedtls_mpi_uint *T = NULL;
+    const mbedtls_mpi_uint *R2 = NULL;
+
+    /* Legacy MPIs for computing R2 */
+    mbedtls_mpi N_mpi;  /* gets set up manually, aliasing N, so no need to free */
+    mbedtls_mpi R2_mpi;
+    mbedtls_mpi_init( &R2_mpi );
+
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &A, &A_limbs, input_A ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &N, &N_limbs, input_N ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &X, &X_limbs, input_X ) );
+    ASSERT_ALLOC( Y, N_limbs );
+
+    TEST_EQUAL( A_limbs, N_limbs );
+    TEST_EQUAL( X_limbs, N_limbs );
+
+    N_mpi.s = 1;
+    N_mpi.p = N;
+    N_mpi.n = N_limbs;
+    TEST_EQUAL( 0, mbedtls_mpi_core_get_mont_r2_unsafe( &R2_mpi, &N_mpi ) );
+    TEST_EQUAL( 0, mbedtls_mpi_grow( &R2_mpi, N_limbs ) );
+    R2 = R2_mpi.p;
+
+    size_t working_limbs = mbedtls_mpi_mod_raw_inv_prime_working_limbs( N_limbs );
+
+    /* No point exactly duplicating the code in mbedtls_mpi_mod_raw_inv_prime_working_limbs()
+     * to see if the output is correct, but we can check that it's in a
+     * reasonable range.  The current calculation works out as
+     * `1 + N_limbs * (welem + 4)`, where welem is the number of elements in
+     * the window (1 << 1 up to 1 << 6).
+     */
+    size_t min_expected_working_limbs = 1 + N_limbs * 5;
+    size_t max_expected_working_limbs = 1 + N_limbs * 68;
+
+    TEST_LE_U( min_expected_working_limbs, working_limbs );
+    TEST_LE_U( working_limbs, max_expected_working_limbs );
+
+    /* Should also be at least mbedtls_mpi_core_montmul_working_limbs() */
+    TEST_LE_U( mbedtls_mpi_core_montmul_working_limbs( N_limbs ),
+               working_limbs );
+
+    ASSERT_ALLOC( T, working_limbs );
+
+    mbedtls_mpi_mod_raw_inv_prime( Y, A, N, N_limbs, R2, T );
+
+    TEST_EQUAL( 0, memcmp( X, Y, N_limbs * sizeof( mbedtls_mpi_uint ) ) );
+
+    /* Check when output aliased to input */
+
+    mbedtls_mpi_mod_raw_inv_prime( A, A, N, N_limbs, R2, T );
+
+    TEST_EQUAL( 0, memcmp( X, A, N_limbs * sizeof( mbedtls_mpi_uint ) ) );
+
+exit:
+    mbedtls_free( T );
+    mbedtls_free( A );
+    mbedtls_free( N );
+    mbedtls_free( X );
+    mbedtls_free( Y );
+    mbedtls_mpi_free( &R2_mpi );
+    // R2 doesn't need to be freed as it is only aliasing R2_mpi
+    // N_mpi doesn't need to be freed as it is only aliasing N
+}
+/* END_CASE */
+
 /* END MERGE SLOT 3 */
 
 /* BEGIN MERGE SLOT 4 */
@@ -287,13 +525,338 @@
 
 /* BEGIN MERGE SLOT 5 */
 
+/* BEGIN_CASE */
+void mpi_mod_raw_add( char * input_N,
+                      char * input_A, char * input_B,
+                      char * input_S )
+{
+    mbedtls_mpi_uint *A = NULL;
+    mbedtls_mpi_uint *B = NULL;
+    mbedtls_mpi_uint *S = NULL;
+    mbedtls_mpi_uint *N = NULL;
+    mbedtls_mpi_uint *X = NULL;
+    size_t A_limbs, B_limbs, N_limbs, S_limbs;
+
+    mbedtls_mpi_mod_modulus m;
+    mbedtls_mpi_mod_modulus_init( &m );
+
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &A, &A_limbs, input_A ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &B, &B_limbs, input_B ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &N, &N_limbs, input_N ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &S, &S_limbs, input_S ) );
+
+    /* Modulus gives the number of limbs; all inputs must have the same. */
+    size_t limbs = N_limbs;
+    size_t bytes = limbs * sizeof( *A );
+
+    TEST_EQUAL( A_limbs, limbs );
+    TEST_EQUAL( B_limbs, limbs );
+    TEST_EQUAL( S_limbs, limbs );
+
+    ASSERT_ALLOC( X, limbs );
+
+    TEST_EQUAL( mbedtls_mpi_mod_modulus_setup(
+                        &m, N, limbs,
+                        MBEDTLS_MPI_MOD_REP_MONTGOMERY
+                ), 0 );
+
+    /* A + B => Correct result */
+    mbedtls_mpi_mod_raw_add( X, A, B, &m );
+    ASSERT_COMPARE( X, bytes, S, bytes );
+
+    /* A + B: alias X to A => Correct result */
+    memcpy( X, A, bytes );
+    mbedtls_mpi_mod_raw_add( X, X, B, &m );
+    ASSERT_COMPARE( X, bytes, S, bytes );
+
+    /* A + B: alias X to B => Correct result */
+    memcpy( X, B, bytes );
+    mbedtls_mpi_mod_raw_add( X, A, X, &m );
+    ASSERT_COMPARE( X, bytes, S, bytes );
+
+    if ( memcmp(A, B, bytes ) == 0 )
+    {
+        /* A == B: alias A and B */
+
+        /* A + A => Correct result */
+        mbedtls_mpi_mod_raw_add( X, A, A, &m );
+        ASSERT_COMPARE( X, bytes, S, bytes );
+
+        /* A + A: X, A, B all aliased together => Correct result */
+        memcpy( X, A, bytes );
+        mbedtls_mpi_mod_raw_add( X, X, X, &m );
+        ASSERT_COMPARE( X, bytes, S, bytes );
+    }
+    else
+    {
+        /* A != B: test B + A */
+
+        /* B + A => Correct result */
+        mbedtls_mpi_mod_raw_add( X, B, A, &m );
+        ASSERT_COMPARE( X, bytes, S, bytes );
+
+        /* B + A: alias X to A => Correct result */
+        memcpy( X, A, bytes );
+        mbedtls_mpi_mod_raw_add( X, B, X, &m );
+        ASSERT_COMPARE( X, bytes, S, bytes );
+
+        /* B + A: alias X to B => Correct result */
+        memcpy( X, B, bytes );
+        mbedtls_mpi_mod_raw_add( X, X, A, &m );
+        ASSERT_COMPARE( X, bytes, S, bytes );
+    }
+
+exit:
+    mbedtls_mpi_mod_modulus_free( &m );
+
+    mbedtls_free( A );
+    mbedtls_free( B );
+    mbedtls_free( S );
+    mbedtls_free( N );
+    mbedtls_free( X );
+}
+/* END_CASE */
 /* END MERGE SLOT 5 */
 
 /* BEGIN MERGE SLOT 6 */
+/* BEGIN_CASE */
+void mpi_mod_raw_canonical_to_modulus_rep( const char *input_N, int rep,
+                                           const char *input_A,
+                                           const char *input_X )
+{
+    mbedtls_mpi_mod_modulus N;
+    mbedtls_mpi_mod_modulus_init( &N );
+    mbedtls_mpi_uint *A = NULL;
+    size_t A_limbs = 0;;
+    mbedtls_mpi_uint *X = NULL;
+    size_t X_limbs = 0;
 
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_modulus( &N, input_N, rep ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &A, &A_limbs, input_A ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &X, &X_limbs, input_X ) );
+
+    TEST_EQUAL( 0, mbedtls_mpi_mod_raw_canonical_to_modulus_rep( A, &N ) );
+    ASSERT_COMPARE( A, A_limbs * sizeof( mbedtls_mpi_uint ),
+                    X, X_limbs * sizeof( mbedtls_mpi_uint ) );
+
+exit:
+    mbedtls_test_mpi_mod_modulus_free_with_limbs( &N );
+    mbedtls_free( A );
+    mbedtls_free( X );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mpi_mod_raw_modulus_to_canonical_rep( const char *input_N, int rep,
+                                           const char *input_A,
+                                           const char *input_X )
+{
+    mbedtls_mpi_mod_modulus N;
+    mbedtls_mpi_mod_modulus_init( &N );
+    mbedtls_mpi_uint *A = NULL;
+    size_t A_limbs = 0;
+    mbedtls_mpi_uint *X = NULL;
+    size_t X_limbs = 0;
+
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_modulus( &N, input_N, rep ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &A, &A_limbs, input_A ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &X, &X_limbs, input_X ) );
+
+    TEST_EQUAL( 0, mbedtls_mpi_mod_raw_modulus_to_canonical_rep( A, &N ) );
+    ASSERT_COMPARE( A, A_limbs * sizeof( mbedtls_mpi_uint ),
+                    X, X_limbs * sizeof( mbedtls_mpi_uint ) );
+
+exit:
+    mbedtls_test_mpi_mod_modulus_free_with_limbs( &N );
+    mbedtls_free( A );
+    mbedtls_free( X );
+}
+/* END_CASE */
 /* END MERGE SLOT 6 */
 
 /* BEGIN MERGE SLOT 7 */
+/* BEGIN_CASE */
+void mpi_mod_raw_to_mont_rep( char * input_N, char * input_A, char * input_X )
+{
+    mbedtls_mpi_uint *N = NULL;
+    mbedtls_mpi_uint *A = NULL;
+    mbedtls_mpi_uint *R = NULL; /* for result of low-level conversion */
+    mbedtls_mpi_uint *X = NULL;
+    mbedtls_mpi_uint *T = NULL;
+    size_t n_limbs, a_limbs, x_limbs;
+
+    mbedtls_mpi_mod_modulus m;
+    mbedtls_mpi_mod_modulus_init( &m );
+
+    /* Read inputs */
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &N, &n_limbs, input_N ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &A, &a_limbs, input_A ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &X, &x_limbs, input_X ) );
+
+    /* Number to convert must have same number of limbs as modulus */
+    TEST_EQUAL(a_limbs, n_limbs);
+
+    /* Higher-level conversion is in-place, so expected result must have the
+     * same number of limbs too */
+    TEST_EQUAL(x_limbs, n_limbs);
+
+    size_t limbs = n_limbs;
+    size_t bytes = limbs * sizeof(mbedtls_mpi_uint);
+
+    TEST_EQUAL( 0, mbedtls_mpi_mod_modulus_setup( &m, N, n_limbs,
+                                          MBEDTLS_MPI_MOD_REP_MONTGOMERY ) );
+
+    /* 1. Test low-level function first */
+
+    /* It has separate output, and requires temporary working storage */
+    size_t temp_limbs = mbedtls_mpi_core_montmul_working_limbs( limbs );
+    ASSERT_ALLOC( T, temp_limbs );
+    ASSERT_ALLOC( R, limbs );
+    mbedtls_mpi_core_to_mont_rep( R, A, N, n_limbs,
+                                  m.rep.mont.mm, m.rep.mont.rr, T );
+    /* Test that the low-level function gives the required value */
+    ASSERT_COMPARE( R, bytes, X, bytes );
+
+    /* Test when output is aliased to input */
+    memcpy( R, A, bytes );
+    mbedtls_mpi_core_to_mont_rep( R, R, N, n_limbs,
+                                  m.rep.mont.mm, m.rep.mont.rr, T );
+    ASSERT_COMPARE( R, bytes, X, bytes );
+
+    /* 2. Test higher-level cannonical to Montgomery conversion */
+
+    TEST_EQUAL(0, mbedtls_mpi_mod_raw_to_mont_rep( A, &m ) );
+
+    /* The result matches expected value */
+    ASSERT_COMPARE( A, bytes, X, bytes );
+
+exit:
+    mbedtls_mpi_mod_modulus_free( &m );
+    mbedtls_free( T );
+    mbedtls_free( N );
+    mbedtls_free( A );
+    mbedtls_free( R );
+    mbedtls_free( X );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mpi_mod_raw_from_mont_rep( char * input_N, char * input_A, char * input_X )
+{
+    mbedtls_mpi_uint *N = NULL;
+    mbedtls_mpi_uint *A = NULL;
+    mbedtls_mpi_uint *R = NULL; /* for result of low-level conversion */
+    mbedtls_mpi_uint *X = NULL;
+    mbedtls_mpi_uint *T = NULL;
+    size_t n_limbs, a_limbs, x_limbs;
+
+    mbedtls_mpi_mod_modulus m;
+    mbedtls_mpi_mod_modulus_init( &m );
+
+    /* Read inputs */
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &N, &n_limbs, input_N ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &A, &a_limbs, input_A ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &X, &x_limbs, input_X ) );
+
+    /* Number to convert must have same number of limbs as modulus */
+    TEST_EQUAL(a_limbs, n_limbs);
+
+    /* Higher-level conversion is in-place, so expected result must have the
+     * same number of limbs too */
+    TEST_EQUAL(x_limbs, n_limbs);
+
+    size_t limbs = n_limbs;
+    size_t bytes = limbs * sizeof(mbedtls_mpi_uint);
+
+    TEST_EQUAL( 0, mbedtls_mpi_mod_modulus_setup( &m, N, n_limbs,
+                                          MBEDTLS_MPI_MOD_REP_MONTGOMERY ) );
+
+    /* 1. Test low-level function first */
+
+    /* It has separate output, and requires temporary working storage */
+    size_t temp_limbs = mbedtls_mpi_core_montmul_working_limbs( limbs );
+    ASSERT_ALLOC( T, temp_limbs );
+    ASSERT_ALLOC( R, limbs );
+    mbedtls_mpi_core_from_mont_rep( R, A, N, n_limbs,
+                                    m.rep.mont.mm, T );
+    /* Test that the low-level function gives the required value */
+    ASSERT_COMPARE( R, bytes, X, bytes );
+
+    /* Test when output is aliased to input */
+    memcpy( R, A, bytes );
+    mbedtls_mpi_core_from_mont_rep( R, R, N, n_limbs,
+                                    m.rep.mont.mm, T );
+    ASSERT_COMPARE( R, bytes, X, bytes );
+
+    /* 2. Test higher-level Montgomery to cannonical conversion */
+
+    TEST_EQUAL(0, mbedtls_mpi_mod_raw_from_mont_rep( A, &m ) );
+
+    /* The result matches expected value */
+    ASSERT_COMPARE( A, bytes, X, bytes );
+
+exit:
+    mbedtls_mpi_mod_modulus_free( &m );
+    mbedtls_free( T );
+    mbedtls_free( N );
+    mbedtls_free( A );
+    mbedtls_free( R );
+    mbedtls_free( X );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mpi_mod_raw_neg( char * input_N, char * input_A, char * input_X )
+{
+    mbedtls_mpi_uint *N = NULL;
+    mbedtls_mpi_uint *A = NULL;
+    mbedtls_mpi_uint *X = NULL;
+    mbedtls_mpi_uint *R = NULL;
+    mbedtls_mpi_uint *Z = NULL;
+    size_t n_limbs, a_limbs, x_limbs, bytes;
+
+    mbedtls_mpi_mod_modulus m;
+    mbedtls_mpi_mod_modulus_init( &m );
+
+    /* Read inputs */
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &N, &n_limbs, input_N ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &A, &a_limbs, input_A ) );
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &X, &x_limbs, input_X ) );
+
+    TEST_EQUAL( a_limbs, n_limbs );
+    TEST_EQUAL( x_limbs, n_limbs );
+    bytes = n_limbs * sizeof( mbedtls_mpi_uint );
+
+    ASSERT_ALLOC( R, n_limbs );
+    ASSERT_ALLOC( Z, n_limbs );
+
+    TEST_EQUAL( 0, mbedtls_mpi_mod_modulus_setup( &m, N, n_limbs,
+            MBEDTLS_MPI_MOD_REP_MONTGOMERY ) );
+
+    /* Neg( A == 0 ) => Zero result */
+    mbedtls_mpi_mod_raw_neg( R, Z, &m );
+    ASSERT_COMPARE( R, bytes, Z, bytes );
+
+    /* Neg( A == N ) => Zero result */
+    mbedtls_mpi_mod_raw_neg( R, N, &m );
+    ASSERT_COMPARE( R, bytes, Z, bytes );
+
+    /* Neg( A ) => Correct result */
+    mbedtls_mpi_mod_raw_neg( R, A, &m );
+    ASSERT_COMPARE( R, bytes, X, bytes );
+
+    /* Neg( A ): alias A to R => Correct result */
+    mbedtls_mpi_mod_raw_neg( A, A, &m );
+    ASSERT_COMPARE( A, bytes, X, bytes );
+exit:
+    mbedtls_mpi_mod_modulus_free( &m );
+    mbedtls_free( N );
+    mbedtls_free( A );
+    mbedtls_free( X );
+    mbedtls_free( R );
+    mbedtls_free( Z );
+}
+/* END_CASE */
 
 /* END MERGE SLOT 7 */
 
diff --git a/tests/suites/test_suite_bignum_random.data b/tests/suites/test_suite_bignum_random.data
new file mode 100644
index 0000000..ee5e397
--- /dev/null
+++ b/tests/suites/test_suite_bignum_random.data
@@ -0,0 +1,340 @@
+MPI core random basic: 0..1
+mpi_core_random_basic:0:"01":0
+
+MPI core random basic: 0..2
+mpi_core_random_basic:0:"02":0
+
+MPI core random basic: 1..2
+mpi_core_random_basic:1:"02":0
+
+MPI core random basic: 2^30..2^31
+mpi_core_random_basic:0x40000000:"80000000":0
+
+MPI core random basic: 0..2^128
+mpi_core_random_basic:0x40000000:"0100000000000000000000000000000000":0
+
+MPI core random basic: 2^30..2^129
+mpi_core_random_basic:0x40000000:"0200000000000000000000000000000000":0
+
+# Use the same data values for mpi_core_random_basic->NOT_ACCEPTABLE
+# and for mpi_XXX_random_values where we want to return NOT_ACCEPTABLE
+# but this isn't checked at runtime.
+MPI core random basic: 2^28-1..2^28+1 (NOT_ACCEPTABLE)
+mpi_core_random_basic:0x0fffffff:"10000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE
+
+MPI random legacy=core: 2^28-1..2^28+1 (NOT_ACCEPTABLE)
+mpi_legacy_random_values:0x0fffffff:"10000001"
+
+MPI random mod=core: 2^28-1..2^28+1 (NOT_ACCEPTABLE) (Mont)
+mpi_mod_random_values:0x0fffffff:"10000001":MBEDTLS_MPI_MOD_REP_MONTGOMERY
+
+MPI random mod=core: 2^28-1..2^28+1 (NOT_ACCEPTABLE) (canon)
+mpi_mod_random_values:0x0fffffff:"10000001":MBEDTLS_MPI_MOD_REP_OPT_RED
+
+MPI core random basic: 2^29-1..2^29+1 (NOT_ACCEPTABLE)
+mpi_core_random_basic:0x1fffffff:"20000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE
+
+MPI random legacy=core: 2^29-1..2^29+1 (NOT_ACCEPTABLE)
+mpi_legacy_random_values:0x1fffffff:"20000001"
+
+MPI random mod=core: 2^29-1..2^29+1 (NOT_ACCEPTABLE) (Mont)
+mpi_mod_random_values:0x1fffffff:"20000001":MBEDTLS_MPI_MOD_REP_MONTGOMERY
+
+MPI random mod=core: 2^29-1..2^29+1 (NOT_ACCEPTABLE) (canon)
+mpi_mod_random_values:0x1fffffff:"20000001":MBEDTLS_MPI_MOD_REP_OPT_RED
+
+MPI core random basic: 2^30-1..2^30+1 (NOT_ACCEPTABLE)
+mpi_core_random_basic:0x3fffffff:"40000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE
+
+MPI random legacy=core: 2^30-1..2^30+1 (NOT_ACCEPTABLE)
+mpi_legacy_random_values:0x3fffffff:"40000001"
+
+MPI random mod=core: 2^30-1..2^30+1 (NOT_ACCEPTABLE) (Mont)
+mpi_mod_random_values:0x3fffffff:"40000001":MBEDTLS_MPI_MOD_REP_MONTGOMERY
+
+MPI random mod=core: 2^30-1..2^30+1 (NOT_ACCEPTABLE) (canon)
+mpi_mod_random_values:0x3fffffff:"40000001":MBEDTLS_MPI_MOD_REP_OPT_RED
+
+MPI core random basic: 2^31-1..2^31+1 (NOT_ACCEPTABLE)
+mpi_core_random_basic:0x7fffffff:"80000001":MBEDTLS_ERR_MPI_NOT_ACCEPTABLE
+
+MPI random legacy=core: 2^31-1..2^31+1 (NOT_ACCEPTABLE)
+mpi_legacy_random_values:0x7fffffff:"80000001"
+
+MPI random mod=core: 2^31-1..2^31+1 (NOT_ACCEPTABLE) (Mont)
+mpi_mod_random_values:0x7fffffff:"80000001":MBEDTLS_MPI_MOD_REP_MONTGOMERY
+
+MPI random mod=core: 2^31-1..2^31+1 (NOT_ACCEPTABLE) (canon)
+mpi_mod_random_values:0x7fffffff:"80000001":MBEDTLS_MPI_MOD_REP_OPT_RED
+
+MPI random in range: 1..2
+mpi_random_many:1:"02":1000
+
+MPI random in range: 1..3
+mpi_random_many:1:"03":1000
+
+MPI random in range: 1..4
+mpi_random_many:1:"04":1000
+
+MPI random in range: 1..5
+mpi_random_many:1:"05":1000
+
+MPI random in range: 1..6
+mpi_random_many:1:"06":1000
+
+MPI random in range: 1..7
+mpi_random_many:1:"07":1000
+
+MPI random in range: 1..8
+mpi_random_many:1:"08":1000
+
+MPI random in range: 1..9
+mpi_random_many:1:"09":1000
+
+MPI random in range: 1..10
+mpi_random_many:1:"0a":1000
+
+MPI random in range: 1..11
+mpi_random_many:1:"0b":1000
+
+MPI random in range: 1..12
+mpi_random_many:1:"0c":1000
+
+MPI random in range: 1..255
+mpi_random_many:1:"ff":200
+
+MPI random in range: 1..256
+mpi_random_many:1:"0100":200
+
+MPI random in range: 1..257
+mpi_random_many:1:"0101":200
+
+MPI random in range: 1..272
+mpi_random_many:1:"0110":200
+
+MPI random in range: 1..2^64-1
+mpi_random_many:1:"ffffffffffffffff":100
+
+MPI random in range: 1..2^64
+mpi_random_many:1:"010000000000000000":100
+
+MPI random in range: 1..2^64+1
+mpi_random_many:1:"010000000000000001":100
+
+MPI random in range: 1..2^64+2^63
+mpi_random_many:1:"018000000000000000":100
+
+MPI random in range: 1..2^65-1
+mpi_random_many:1:"01ffffffffffffffff":100
+
+MPI random in range: 1..2^65
+mpi_random_many:1:"020000000000000000":100
+
+MPI random in range: 1..2^65+1
+mpi_random_many:1:"020000000000000001":100
+
+MPI random in range: 1..2^65+2^64
+mpi_random_many:1:"030000000000000000":100
+
+MPI random in range: 1..2^66+2^65
+mpi_random_many:1:"060000000000000000":100
+
+MPI random in range: 1..2^71-1
+mpi_random_many:1:"7fffffffffffffffff":100
+
+MPI random in range: 1..2^71
+mpi_random_many:1:"800000000000000000":100
+
+MPI random in range: 1..2^71+1
+mpi_random_many:1:"800000000000000001":100
+
+MPI random in range: 1..2^71+2^70
+mpi_random_many:1:"c00000000000000000":100
+
+MPI random in range: 1..2^72-1
+mpi_random_many:1:"ffffffffffffffffff":100
+
+MPI random in range: 1..2^72
+mpi_random_many:1:"01000000000000000000":100
+
+MPI random in range: 1..2^72+1
+mpi_random_many:1:"01000000000000000001":100
+
+MPI random in range: 1..2^72+2^71
+mpi_random_many:1:"01800000000000000000":100
+
+MPI random in range: 0..1
+mpi_random_many:0:"04":10000
+
+MPI random in range: 0..4
+mpi_random_many:0:"04":10000
+
+MPI random in range: 2..4
+mpi_random_many:2:"04":10000
+
+MPI random in range: 3..4
+mpi_random_many:3:"04":10000
+
+MPI random in range: smaller result
+mpi_random_sizes:1:"aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb":1:0
+
+MPI random in range: same size result (32-bit limbs)
+mpi_random_sizes:1:"aaaaaaaaaaaaaaaa":2:0
+
+MPI random in range: same size result (64-bit limbs)
+mpi_random_sizes:1:"aaaaaaaaaaaaaaaa":1:0
+
+MPI random in range: larger result
+mpi_random_sizes:1:"aaaaaaaaaaaaaaaa":3:0
+
+## The "0 limb in upper bound" tests rely on the fact that
+## mbedtls_mpi_read_binary() bases the size of the MPI on the size of
+## the input, without first checking for leading zeros. If this was
+## not the case, the tests would still pass, but would not exercise
+## the advertised behavior.
+MPI random in range: leading 0 limb in upper bound #0
+mpi_random_sizes:1:"00aaaaaaaaaaaaaaaa":0:0
+
+MPI random in range: leading 0 limb in upper bound #1
+mpi_random_sizes:1:"00aaaaaaaaaaaaaaaa":1:0
+
+MPI random in range: leading 0 limb in upper bound #2
+mpi_random_sizes:1:"00aaaaaaaaaaaaaaaa":2:0
+
+MPI random in range: leading 0 limb in upper bound #3
+mpi_random_sizes:1:"00aaaaaaaaaaaaaaaa":3:0
+
+MPI random in range: leading 0 limb in upper bound #4
+mpi_random_sizes:1:"00aaaaaaaaaaaaaaaa":4:0
+
+MPI random in range: previously small >0
+mpi_random_sizes:1:"1234567890":4:1
+
+MPI random in range: previously small <0
+mpi_random_sizes:1:"1234567890":4:-1
+
+MPI random in range: previously large >0
+mpi_random_sizes:1:"1234":4:65
+
+MPI random in range: previously large <0
+mpi_random_sizes:1:"1234":4:-65
+
+MPI random bad arguments: min < 0
+mpi_random_fail:-1:"04":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+MPI random bad arguments: min = N = 0
+mpi_random_fail:0:"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+MPI random bad arguments: min = N = 1
+mpi_random_fail:1:"01":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+MPI random bad arguments: min > N = 0
+mpi_random_fail:1:"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+MPI random bad arguments: min > N = 1
+mpi_random_fail:2:"01":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+MPI random bad arguments: min > N = 1, 0 limb in upper bound
+mpi_random_fail:2:"000000000000000001":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+MPI random legacy=core: 0..1
+mpi_legacy_random_values:0:"01"
+
+MPI random legacy=core: 0..2
+mpi_legacy_random_values:0:"02"
+
+MPI random legacy=core: 1..2
+mpi_legacy_random_values:1:"02"
+
+MPI random legacy=core: 2^30..2^31
+mpi_legacy_random_values:0x40000000:"80000000"
+
+MPI random legacy=core: 2^31-1..2^32-1
+mpi_legacy_random_values:0x7fffffff:"ffffffff"
+
+MPI random legacy=core: 0..2^256
+mpi_legacy_random_values:0:"010000000000000000000000000000000000000000000000000000000000000000"
+
+MPI random legacy=core: 0..2^256+1
+mpi_legacy_random_values:0:"010000000000000000000000000000000000000000000000000000000000000001"
+
+MPI random mod=core: 0..1 (Mont)
+mpi_mod_random_values:0:"01":MBEDTLS_MPI_MOD_REP_MONTGOMERY
+
+MPI random mod=core: 0..1 (canon)
+mpi_mod_random_values:0:"01":MBEDTLS_MPI_MOD_REP_OPT_RED
+
+MPI random mod=core: 0..3 (Mont)
+mpi_mod_random_values:0:"03":MBEDTLS_MPI_MOD_REP_MONTGOMERY
+
+MPI random mod=core: 0..3 (canon)
+mpi_mod_random_values:0:"03":MBEDTLS_MPI_MOD_REP_OPT_RED
+
+MPI random mod=core: 1..3 (Mont)
+mpi_mod_random_values:1:"03":MBEDTLS_MPI_MOD_REP_MONTGOMERY
+
+MPI random mod=core: 1..3 (canon)
+mpi_mod_random_values:1:"03":MBEDTLS_MPI_MOD_REP_OPT_RED
+
+MPI random mod=core: 2^30..2^31-1 (Mont)
+mpi_mod_random_values:0x40000000:"7fffffff":MBEDTLS_MPI_MOD_REP_MONTGOMERY
+
+MPI random mod=core: 2^30..2^31-1 (canon)
+mpi_mod_random_values:0x40000000:"7fffffff":MBEDTLS_MPI_MOD_REP_OPT_RED
+
+MPI random mod=core: 2^31-1..2^32-1 (Mont)
+mpi_mod_random_values:0x7fffffff:"ffffffff":MBEDTLS_MPI_MOD_REP_MONTGOMERY
+
+MPI random mod=core: 2^31-1..2^32-1 (canon)
+mpi_mod_random_values:0x7fffffff:"ffffffff":MBEDTLS_MPI_MOD_REP_OPT_RED
+
+MPI random mod=core: 0..2^256+1 (Mont)
+mpi_mod_random_values:0:"010000000000000000000000000000000000000000000000000000000000000001":MBEDTLS_MPI_MOD_REP_MONTGOMERY
+
+MPI random mod=core: 0..2^256+1 (canon)
+mpi_mod_random_values:0:"010000000000000000000000000000000000000000000000000000000000000001":MBEDTLS_MPI_MOD_REP_OPT_RED
+
+MPI random mod validation: 1 limb, good, 0..1
+mpi_mod_random_validation:0:"1":0:0
+
+MPI random mod validation: 1 limb, good, 1..3
+mpi_mod_random_validation:1:"3":0:0
+
+MPI random mod validation: 1 limb, good, 2..3
+mpi_mod_random_validation:2:"3":0:0
+
+MPI random mod validation: 1 limb, good, 3..5
+mpi_mod_random_validation:3:"5":0:0
+
+MPI random mod validation: 1 limb, good, 4..5
+mpi_mod_random_validation:4:"5":0:0
+
+MPI random mod validation: 1 limb, good, 5..7
+mpi_mod_random_validation:5:"7":0:0
+
+MPI random mod validation: 1 limb, good, 6..7
+mpi_mod_random_validation:6:"7":0:0
+
+MPI random mod validation: 1 limb, good, 0..0x123
+mpi_mod_random_validation:0:"123":0:0
+
+MPI random mod validation: 2+ limbs, good
+mpi_mod_random_validation:0:"01234567890123456789":0:0
+
+MPI random mod validation: 1 limb, output null
+mpi_mod_random_validation:0:"123":-1:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+MPI random mod validation: 1 limb, output too large
+mpi_mod_random_validation:0:"123":1:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+MPI random mod validation: 2+ limbs, output too small
+mpi_mod_random_validation:0:"01234567890123456789":-1:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+MPI random mod validation: 2+ limbs, output too large
+mpi_mod_random_validation:0:"01234567890123456789":1:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+MPI random mod validation: min == upper bound
+mpi_mod_random_validation:0x123:"123":-1:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+MPI random mod validation: min > upper bound
+mpi_mod_random_validation:0x124:"123":-1:MBEDTLS_ERR_MPI_BAD_INPUT_DATA
diff --git a/tests/suites/test_suite_bignum_random.function b/tests/suites/test_suite_bignum_random.function
new file mode 100644
index 0000000..4709148
--- /dev/null
+++ b/tests/suites/test_suite_bignum_random.function
@@ -0,0 +1,496 @@
+/* BEGIN_HEADER */
+/* Dedicated test suite for mbedtls_mpi_core_random() and the upper-layer
+ * functions. Due to the complexity of how these functions are tested,
+ * we test all the layers in a single test suite, unlike the way other
+ * functions are tested with each layer in its own test suite.
+ *
+ * Test strategy
+ * =============
+ *
+ * There are three main goals for testing random() functions:
+ * - Parameter validation.
+ * - Correctness of outputs (well-formed, in range).
+ * - Distribution of outputs.
+ *
+ * We test parameter validation in a standard way, with unit tests with
+ * positive and negative cases:
+ * - mbedtls_mpi_core_random(): negative cases for mpi_core_random_basic.
+ * - mbedtls_mpi_mod_raw_random(),  mbedtls_mpi_mod_random(): negative
+ *   cases for mpi_mod_random_validation.
+ * - mbedtls_mpi_random(): mpi_random_fail.
+ *
+ * We test the correctness of outputs in positive tests:
+ * - mbedtls_mpi_core_random(): positive cases for mpi_core_random_basic,
+ *   and mpi_random_many.
+ * - mbedtls_mpi_mod_raw_random(), mbedtls_mpi_mod_random(): tested indirectly
+ *   via mpi_mod_random_values.
+ * - mbedtls_mpi_random(): mpi_random_sizes, plus indirectly via
+ *   mpi_random_values.
+ *
+ * We test the distribution of outputs only for mbedtls_mpi_core_random(),
+ * in mpi_random_many, which runs the function multiple times. This also
+ * helps in validating the output range, through test cases with a small
+ * range where any output out of range would be very likely to lead to a
+ * test failure. For the other functions, we validate the distribution
+ * indirectly by testing that these functions consume the random generator
+ * in the same way as mbedtls_mpi_core_random(). This is done in
+ * mpi_mod_random_values and mpi_legacy_random_values.
+ */
+
+#include "mbedtls/bignum.h"
+#include "mbedtls/entropy.h"
+#include "bignum_core.h"
+#include "bignum_mod_raw.h"
+#include "constant_time_internal.h"
+
+/* This test suite only manipulates non-negative bignums. */
+static int sign_is_valid( const mbedtls_mpi *X )
+{
+    return( X->s == 1 );
+}
+
+/* A common initializer for test functions that should generate the same
+ * sequences for reproducibility and good coverage. */
+const mbedtls_test_rnd_pseudo_info rnd_pseudo_seed = {
+    /* 16-word key */
+    {'T', 'h', 'i', 's', ' ', 'i', 's', ' ',
+     'a', ' ', 's', 'e', 'e', 'd', '!', 0},
+    /* 2-word initial state, should be zero */
+    0, 0};
+
+/* Test whether bytes represents (in big-endian base 256) a number b that
+ * is significantly above a power of 2. That is, b must not have a long run
+ * of unset bits after the most significant bit.
+ *
+ * Let n be the bit-size of b, i.e. the integer such that 2^n <= b < 2^{n+1}.
+ * This function returns 1 if, when drawing a number between 0 and b,
+ * the probability that this number is at least 2^n is not negligible.
+ * This probability is (b - 2^n) / b and this function checks that this
+ * number is above some threshold A. The threshold value is heuristic and
+ * based on the needs of mpi_random_many().
+ */
+static int is_significantly_above_a_power_of_2( data_t *bytes )
+{
+    const uint8_t *p = bytes->x;
+    size_t len = bytes->len;
+    unsigned x;
+
+    /* Skip leading null bytes */
+    while( len > 0 && p[0] == 0 )
+    {
+        ++p;
+        --len;
+    }
+    /* 0 is not significantly above a power of 2 */
+    if( len == 0 )
+        return( 0 );
+    /* Extract the (up to) 2 most significant bytes */
+    if( len == 1 )
+        x = p[0];
+    else
+        x = ( p[0] << 8 ) | p[1];
+
+    /* Shift the most significant bit of x to position 8 and mask it out */
+    while( ( x & 0xfe00 ) != 0 )
+        x >>= 1;
+    x &= 0x00ff;
+
+    /* At this point, x = floor((b - 2^n) / 2^(n-8)). b is significantly above
+     * a power of 2 iff x is significantly above 0 compared to 2^8.
+     * Testing x >= 2^4 amounts to picking A = 1/16 in the function
+     * description above. */
+    return( x >= 0x10 );
+}
+
+/* END_HEADER */
+
+/* BEGIN_DEPENDENCIES
+ * depends_on:MBEDTLS_BIGNUM_C
+ * END_DEPENDENCIES
+ */
+
+/* BEGIN_CASE */
+void mpi_core_random_basic( int min, char *bound_bytes, int expected_ret )
+{
+    /* Same RNG as in mpi_random_values */
+    mbedtls_test_rnd_pseudo_info rnd = rnd_pseudo_seed;
+    size_t limbs;
+    mbedtls_mpi_uint *lower_bound = NULL;
+    mbedtls_mpi_uint *upper_bound = NULL;
+    mbedtls_mpi_uint *result = NULL;
+
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &upper_bound, &limbs,
+                                               bound_bytes ) );
+    ASSERT_ALLOC( lower_bound, limbs );
+    lower_bound[0] = min;
+    ASSERT_ALLOC( result, limbs );
+
+    TEST_EQUAL( expected_ret,
+                mbedtls_mpi_core_random( result, min, upper_bound, limbs,
+                                         mbedtls_test_rnd_pseudo_rand, &rnd ) );
+
+    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 ) );
+    }
+
+exit:
+    mbedtls_free( lower_bound );
+    mbedtls_free( upper_bound );
+    mbedtls_free( result );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mpi_legacy_random_values( int min, char *max_hex )
+{
+    /* Same RNG as in mpi_core_random_basic */
+    mbedtls_test_rnd_pseudo_info rnd_core = rnd_pseudo_seed;
+    mbedtls_test_rnd_pseudo_info rnd_legacy;
+    memcpy( &rnd_legacy, &rnd_core, sizeof( rnd_core ) );
+    mbedtls_mpi max_legacy;
+    mbedtls_mpi_init( &max_legacy );
+    mbedtls_mpi_uint *R_core = NULL;
+    mbedtls_mpi R_legacy;
+    mbedtls_mpi_init( &R_legacy );
+
+    TEST_EQUAL( 0, mbedtls_test_read_mpi( &max_legacy, max_hex ) );
+    size_t limbs = max_legacy.n;
+    ASSERT_ALLOC( R_core, limbs );
+
+    /* Call the legacy function and the core function with the same random
+     * stream. */
+    int core_ret = mbedtls_mpi_core_random( R_core, min, max_legacy.p, limbs,
+                                            mbedtls_test_rnd_pseudo_rand,
+                                            &rnd_core );
+    int legacy_ret = mbedtls_mpi_random( &R_legacy, min, &max_legacy,
+                                         mbedtls_test_rnd_pseudo_rand,
+                                         &rnd_legacy );
+
+    /* They must return the same status, and, on success, output the
+     * same number, with the same limb count. */
+    TEST_EQUAL( core_ret, legacy_ret );
+    if( core_ret == 0 )
+    {
+        ASSERT_COMPARE( R_core, limbs * ciL,
+                        R_legacy.p, R_legacy.n * ciL );
+    }
+
+    /* Also check that they have consumed the RNG in the same way. */
+    /* This may theoretically fail on rare platforms with padding in
+     * the structure! If this is a problem in practice, change to a
+     * field-by-field comparison. */
+    ASSERT_COMPARE( &rnd_core, sizeof( rnd_core ),
+                    &rnd_legacy, sizeof( rnd_legacy ) );
+
+exit:
+    mbedtls_mpi_free( &max_legacy );
+    mbedtls_free( R_core );
+    mbedtls_mpi_free( &R_legacy );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mpi_mod_random_values( int min, char *max_hex, int rep )
+{
+    /* Same RNG as in mpi_core_random_basic */
+    mbedtls_test_rnd_pseudo_info rnd_core = rnd_pseudo_seed;
+    mbedtls_test_rnd_pseudo_info rnd_mod_raw;
+    memcpy( &rnd_mod_raw, &rnd_core, sizeof( rnd_core ) );
+    mbedtls_test_rnd_pseudo_info rnd_mod;
+    memcpy( &rnd_mod, &rnd_core, sizeof( rnd_core ) );
+    mbedtls_mpi_uint *R_core = NULL;
+    mbedtls_mpi_uint *R_mod_raw = NULL;
+    mbedtls_mpi_uint *R_mod_digits = NULL;
+    mbedtls_mpi_mod_residue R_mod;
+    mbedtls_mpi_mod_modulus N;
+    mbedtls_mpi_mod_modulus_init( &N );
+
+    TEST_EQUAL( mbedtls_test_read_mpi_modulus( &N, max_hex, rep ), 0 );
+    ASSERT_ALLOC( R_core, N.limbs );
+    ASSERT_ALLOC( R_mod_raw, N.limbs );
+    ASSERT_ALLOC( R_mod_digits, N.limbs );
+    TEST_EQUAL( mbedtls_mpi_mod_residue_setup( &R_mod, &N,
+                                               R_mod_digits, N.limbs ),
+                0 );
+
+    /* Call the core and mod random() functions with the same random stream. */
+    int core_ret = mbedtls_mpi_core_random( R_core,
+                                            min, N.p, N.limbs,
+                                            mbedtls_test_rnd_pseudo_rand,
+                                            &rnd_core );
+    int mod_raw_ret = mbedtls_mpi_mod_raw_random( R_mod_raw,
+                                                  min, &N,
+                                                  mbedtls_test_rnd_pseudo_rand,
+                                                  &rnd_mod_raw );
+    int mod_ret = mbedtls_mpi_mod_random( &R_mod,
+                                          min, &N,
+                                          mbedtls_test_rnd_pseudo_rand,
+                                          &rnd_mod );
+
+    /* They must return the same status, and, on success, output the
+     * same number, with the same limb count. */
+    TEST_EQUAL( core_ret, mod_raw_ret );
+    TEST_EQUAL( core_ret, mod_ret );
+    if( core_ret == 0 )
+    {
+        TEST_EQUAL( mbedtls_mpi_mod_raw_modulus_to_canonical_rep( R_mod_raw, &N ),
+                    0 );
+        ASSERT_COMPARE( R_core, N.limbs * ciL,
+                        R_mod_raw, N.limbs * ciL );
+        TEST_EQUAL( mbedtls_mpi_mod_raw_modulus_to_canonical_rep( R_mod_digits, &N ),
+                    0 );
+        ASSERT_COMPARE( R_core, N.limbs * ciL,
+                        R_mod_digits, N.limbs * ciL );
+    }
+
+    /* Also check that they have consumed the RNG in the same way. */
+    /* This may theoretically fail on rare platforms with padding in
+     * the structure! If this is a problem in practice, change to a
+     * field-by-field comparison. */
+    ASSERT_COMPARE( &rnd_core, sizeof( rnd_core ),
+                    &rnd_mod_raw, sizeof( rnd_mod_raw ) );
+    ASSERT_COMPARE( &rnd_core, sizeof( rnd_core ),
+                    &rnd_mod, sizeof( rnd_mod ) );
+
+exit:
+    mbedtls_test_mpi_mod_modulus_free_with_limbs( &N );
+    mbedtls_free( R_core );
+    mbedtls_free( R_mod_raw );
+    mbedtls_free( R_mod_digits );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mpi_random_many( int min, char *bound_hex, int iterations )
+{
+    /* Generate numbers in the range 1..bound-1. Do it iterations times.
+     * This function assumes that the value of bound is at least 2 and
+     * that iterations is large enough that a one-in-2^iterations chance
+     * effectively never occurs.
+     */
+
+    data_t bound_bytes = {NULL, 0};
+    mbedtls_mpi_uint *upper_bound = NULL;
+    size_t limbs;
+    size_t n_bits;
+    mbedtls_mpi_uint *result = NULL;
+    size_t b;
+    /* If upper_bound is small, stats[b] is the number of times the value b
+     * has been generated. Otherwise stats[b] is the number of times a
+     * value with bit b set has been generated. */
+    size_t *stats = NULL;
+    size_t stats_len;
+    int full_stats;
+    size_t i;
+
+    TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &upper_bound, &limbs,
+                                               bound_hex ) );
+    ASSERT_ALLOC( result, limbs );
+
+    n_bits = mbedtls_mpi_core_bitlen( upper_bound, limbs );
+    /* Consider a bound "small" if it's less than 2^5. This value is chosen
+     * to be small enough that the probability of missing one value is
+     * negligible given the number of iterations. It must be less than
+     * 256 because some of the code below assumes that "small" values
+     * fit in a byte. */
+    if( n_bits <= 5 )
+    {
+        full_stats = 1;
+        stats_len = (uint8_t) upper_bound[0];
+    }
+    else
+    {
+        full_stats = 0;
+        stats_len = n_bits;
+    }
+    ASSERT_ALLOC( stats, stats_len );
+
+    for( i = 0; i < (size_t) iterations; i++ )
+    {
+        mbedtls_test_set_step( i );
+        TEST_EQUAL( 0, mbedtls_mpi_core_random( result,
+                                                min, upper_bound, limbs,
+                                                mbedtls_test_rnd_std_rand, NULL ) );
+
+        /* Temporarily use a legacy MPI for analysis, because the
+         * necessary auxiliary functions don't exist yet in core. */
+        mbedtls_mpi B = {1, limbs, upper_bound};
+        mbedtls_mpi R = {1, limbs, result};
+
+        TEST_ASSERT( mbedtls_mpi_cmp_mpi( &R, &B ) < 0 );
+        TEST_ASSERT( mbedtls_mpi_cmp_int( &R, min ) >= 0 );
+        if( full_stats )
+        {
+            uint8_t value;
+            TEST_EQUAL( 0, mbedtls_mpi_write_binary( &R, &value, 1 ) );
+            TEST_ASSERT( value < stats_len );
+            ++stats[value];
+        }
+        else
+        {
+            for( b = 0; b < n_bits; b++ )
+                stats[b] += mbedtls_mpi_get_bit( &R, b );
+        }
+    }
+
+    if( full_stats )
+    {
+        for( b = min; b < stats_len; b++ )
+        {
+            mbedtls_test_set_step( 1000000 + b );
+            /* Assert that each value has been reached at least once.
+             * This is almost guaranteed if the iteration count is large
+             * enough. This is a very crude way of checking the distribution.
+             */
+            TEST_ASSERT( stats[b] > 0 );
+        }
+    }
+    else
+    {
+        bound_bytes.len = limbs * sizeof( mbedtls_mpi_uint );
+        ASSERT_ALLOC( bound_bytes.x, bound_bytes.len );
+        mbedtls_mpi_core_write_be( upper_bound, limbs,
+                                   bound_bytes.x, bound_bytes.len );
+        int statistically_safe_all_the_way =
+            is_significantly_above_a_power_of_2( &bound_bytes );
+        for( b = 0; b < n_bits; b++ )
+        {
+            mbedtls_test_set_step( 1000000 + b );
+            /* Assert that each bit has been set in at least one result and
+             * clear in at least one result. Provided that iterations is not
+             * too small, it would be extremely unlikely for this not to be
+             * the case if the results are uniformly distributed.
+             *
+             * As an exception, the top bit may legitimately never be set
+             * if bound is a power of 2 or only slightly above.
+             */
+            if( statistically_safe_all_the_way || b != n_bits - 1 )
+            {
+                TEST_ASSERT( stats[b] > 0 );
+            }
+            TEST_ASSERT( stats[b] < (size_t) iterations );
+        }
+    }
+
+exit:
+    mbedtls_free( bound_bytes.x );
+    mbedtls_free( upper_bound );
+    mbedtls_free( result );
+    mbedtls_free( stats );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mpi_random_sizes( int min, data_t *bound_bytes, int nlimbs, int before )
+{
+    mbedtls_mpi upper_bound;
+    mbedtls_mpi result;
+
+    mbedtls_mpi_init( &upper_bound );
+    mbedtls_mpi_init( &result );
+
+    if( before != 0 )
+    {
+        /* Set result to sign(before) * 2^(|before|-1) */
+        TEST_ASSERT( mbedtls_mpi_lset( &result, before > 0 ? 1 : -1 ) == 0 );
+        if( before < 0 )
+            before = - before;
+        TEST_ASSERT( mbedtls_mpi_shift_l( &result, before - 1 ) == 0 );
+    }
+
+    TEST_EQUAL( 0, mbedtls_mpi_grow( &result, nlimbs ) );
+    TEST_EQUAL( 0, mbedtls_mpi_read_binary( &upper_bound,
+                                            bound_bytes->x, bound_bytes->len ) );
+    TEST_EQUAL( 0, mbedtls_mpi_random( &result, min, &upper_bound,
+                                       mbedtls_test_rnd_std_rand, NULL ) );
+    TEST_ASSERT( sign_is_valid( &result ) );
+    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &result, &upper_bound ) < 0 );
+    TEST_ASSERT( mbedtls_mpi_cmp_int( &result, min ) >= 0 );
+
+exit:
+    mbedtls_mpi_free( &upper_bound );
+    mbedtls_mpi_free( &result );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mpi_mod_random_validation( int min, char *bound_hex,
+                                int result_limbs_delta,
+                                int expected_ret )
+{
+    mbedtls_mpi_uint *result_digits = NULL;
+    mbedtls_mpi_mod_modulus N;
+    mbedtls_mpi_mod_modulus_init( &N );
+
+    TEST_EQUAL( mbedtls_test_read_mpi_modulus( &N, bound_hex,
+                                               MBEDTLS_MPI_MOD_REP_OPT_RED ),
+                0 );
+    size_t result_limbs = N.limbs + result_limbs_delta;
+    ASSERT_ALLOC( result_digits, result_limbs );
+    /* Build a reside that might not match the modulus, to test that
+     * the library function rejects that as expected. */
+    mbedtls_mpi_mod_residue result = {result_digits, result_limbs};
+
+    TEST_EQUAL( mbedtls_mpi_mod_random( &result, min, &N,
+                                        mbedtls_test_rnd_std_rand, NULL ),
+                expected_ret );
+    if( expected_ret == 0 )
+    {
+        /* Success should only be expected when the result has the same
+         * 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 );
+        /* Check result >= min (changes result) */
+        TEST_EQUAL( mbedtls_mpi_core_sub_int( result_digits, result_digits, min,
+                                              result_limbs ),
+                    0 );
+    }
+
+    /* When the result has the right number of limbs, also test mod_raw
+     * (for which this is an unchecked precondition). */
+    if( result_limbs_delta == 0 )
+    {
+        TEST_EQUAL( mbedtls_mpi_mod_raw_random( result_digits, min, &N,
+                                                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_EQUAL( mbedtls_mpi_core_sub_int( result_digits, result.p, min,
+                                                  result_limbs ),
+                        0 );
+        }
+    }
+
+exit:
+    mbedtls_test_mpi_mod_modulus_free_with_limbs( &N );
+    mbedtls_free( result_digits );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mpi_random_fail( int min, data_t *bound_bytes, int expected_ret )
+{
+    mbedtls_mpi upper_bound;
+    mbedtls_mpi result;
+    int actual_ret;
+
+    mbedtls_mpi_init( &upper_bound );
+    mbedtls_mpi_init( &result );
+
+    TEST_EQUAL( 0, mbedtls_mpi_read_binary( &upper_bound,
+                                            bound_bytes->x, bound_bytes->len ) );
+    actual_ret = mbedtls_mpi_random( &result, min, &upper_bound,
+                                     mbedtls_test_rnd_std_rand, NULL );
+    TEST_EQUAL( expected_ret, actual_ret );
+
+exit:
+    mbedtls_mpi_free( &upper_bound );
+    mbedtls_mpi_free( &result );
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_cipher.function b/tests/suites/test_suite_cipher.function
index b7c3b51..ff936df 100644
--- a/tests/suites/test_suite_cipher.function
+++ b/tests/suites/test_suite_cipher.function
@@ -450,8 +450,12 @@
     TEST_ASSERT( 0 == mbedtls_cipher_reset( &ctx_enc ) );
 
 #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C)
-    TEST_ASSERT( 0 == mbedtls_cipher_update_ad( &ctx_dec, ad, sizeof( ad ) - i ) );
-    TEST_ASSERT( 0 == mbedtls_cipher_update_ad( &ctx_enc, ad, sizeof( ad ) - i ) );
+    int expected = ( cipher_info->mode == MBEDTLS_MODE_GCM ||
+                     cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305 ) ?
+                   0 : MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
+
+    TEST_EQUAL( expected, mbedtls_cipher_update_ad( &ctx_dec, ad, sizeof(ad) - i ) );
+    TEST_EQUAL( expected, mbedtls_cipher_update_ad( &ctx_enc, ad, sizeof(ad) - i ) );
 #endif
 
     block_size = mbedtls_cipher_get_block_size( &ctx_enc );
@@ -470,7 +474,7 @@
     total_len += outlen;
 
 #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C)
-    TEST_ASSERT( 0 == mbedtls_cipher_write_tag( &ctx_enc, tag, sizeof( tag ) ) );
+    TEST_EQUAL( expected, mbedtls_cipher_write_tag( &ctx_enc, tag, sizeof(tag) ) );
 #endif
 
     TEST_ASSERT( total_len == length ||
@@ -491,7 +495,7 @@
     total_len += outlen;
 
 #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C)
-    TEST_ASSERT( 0 == mbedtls_cipher_check_tag( &ctx_dec, tag, sizeof( tag ) ) );
+    TEST_EQUAL( expected, mbedtls_cipher_check_tag( &ctx_dec, tag, sizeof(tag) ) );
 #endif
 
     /* check result */
@@ -547,7 +551,11 @@
     TEST_ASSERT( 0 == mbedtls_cipher_set_iv( &ctx, iv, 16 ) );
     TEST_ASSERT( 0 == mbedtls_cipher_reset( &ctx ) );
 #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C)
-    TEST_ASSERT( 0 == mbedtls_cipher_update_ad( &ctx, NULL, 0 ) );
+    int expected = ( cipher_info->mode == MBEDTLS_MODE_GCM ||
+                     cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305 ) ?
+                   0 : MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
+
+    TEST_EQUAL( expected, mbedtls_cipher_update_ad( &ctx, NULL, 0 ) );
 #endif
 
     /* encode length number of bytes from inbuf */
@@ -609,7 +617,11 @@
     TEST_ASSERT( 0 == mbedtls_cipher_reset( &ctx_dec ) );
 
 #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C)
-    TEST_ASSERT( 0 == mbedtls_cipher_update_ad( &ctx_dec, NULL, 0 ) );
+    int expected = ( cipher_info->mode == MBEDTLS_MODE_GCM ||
+                     cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305 ) ?
+                   0 : MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
+
+    TEST_EQUAL( expected, mbedtls_cipher_update_ad( &ctx_dec, NULL, 0 ) );
 #endif
 
     /* decode 0-byte string */
@@ -710,8 +722,12 @@
     TEST_ASSERT( 0 == mbedtls_cipher_reset( &ctx_enc ) );
 
 #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C)
-    TEST_ASSERT( 0 == mbedtls_cipher_update_ad( &ctx_dec, NULL, 0 ) );
-    TEST_ASSERT( 0 == mbedtls_cipher_update_ad( &ctx_enc, NULL, 0 ) );
+    int expected = ( cipher_info->mode == MBEDTLS_MODE_GCM ||
+                     cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305 ) ?
+                   0 : MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
+
+    TEST_EQUAL( expected, mbedtls_cipher_update_ad( &ctx_dec, NULL, 0 ) );
+    TEST_EQUAL( expected, mbedtls_cipher_update_ad( &ctx_enc, NULL, 0 ) );
 #endif
 
     block_size = mbedtls_cipher_get_block_size( &ctx_enc );
@@ -795,7 +811,11 @@
     TEST_ASSERT( 0 == mbedtls_cipher_set_iv( &ctx, iv->x, iv->len ) );
     TEST_ASSERT( 0 == mbedtls_cipher_reset( &ctx ) );
 #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C)
-    TEST_ASSERT( 0 == mbedtls_cipher_update_ad( &ctx, ad->x, ad->len ) );
+    int expected = ( ctx.cipher_info->mode == MBEDTLS_MODE_GCM ||
+                     ctx.cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305 ) ?
+                   0 : MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
+
+    TEST_EQUAL( expected, mbedtls_cipher_update_ad( &ctx, ad->x, ad->len ) );
 #endif
 
     /* decode buffer and check tag->x */
@@ -806,7 +826,11 @@
                                                  &outlen ) );
     total_len += outlen;
 #if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C)
-    TEST_ASSERT( tag_result == mbedtls_cipher_check_tag( &ctx, tag->x, tag->len ) );
+    int tag_expected = ( ctx.cipher_info->mode == MBEDTLS_MODE_GCM ||
+                         ctx.cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305 ) ?
+                       tag_result : MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
+
+    TEST_EQUAL( tag_expected, mbedtls_cipher_check_tag( &ctx, tag->x, tag->len ) );
 #endif
 
     /* check plaintext only if everything went fine */
diff --git a/tests/suites/test_suite_common.data b/tests/suites/test_suite_common.data
new file mode 100644
index 0000000..500852d
--- /dev/null
+++ b/tests/suites/test_suite_common.data
@@ -0,0 +1,20 @@
+Block xor, length 0
+mbedtls_xor:0
+
+Block xor, length 1
+mbedtls_xor:1
+
+Block xor, length 3
+mbedtls_xor:3
+
+Block xor, length 4
+mbedtls_xor:4
+
+Block xor, length 7
+mbedtls_xor:7
+
+Block xor, length 8
+mbedtls_xor:8
+
+Block xor, length 16
+mbedtls_xor:16
diff --git a/tests/suites/test_suite_common.function b/tests/suites/test_suite_common.function
new file mode 100644
index 0000000..4444a52
--- /dev/null
+++ b/tests/suites/test_suite_common.function
@@ -0,0 +1,90 @@
+/* BEGIN_HEADER */
+#include "../library/common.h"
+
+void fill_arrays( unsigned char *a, unsigned char *b, unsigned char *r1, unsigned char *r2, size_t n )
+{
+    for ( size_t i = 0; i < n; i++ )
+    {
+        a[i]  = (unsigned char) i * 3;
+        b[i]  = (unsigned char) i * 3 + 1;
+        r1[i] = (unsigned char) i * 3 + 2;
+        r2[i] = r1[i];
+    }
+}
+/* END_HEADER */
+
+/* BEGIN_CASE */
+void mbedtls_xor( int len )
+{
+    size_t n = (size_t) len;
+    unsigned char *a = NULL, *b = NULL, *r1 = NULL, *r2 = NULL;
+    ASSERT_ALLOC( a, n + 1 );
+    ASSERT_ALLOC( b, n + 1 );
+    ASSERT_ALLOC( r1, n + 1 );
+    ASSERT_ALLOC( r2, n + 1 );
+
+    /* Test non-overlapping */
+    fill_arrays( a, b, r1, r2, n );
+    for ( size_t i = 0; i < n; i++ )
+    {
+        r1[i] = a[i] ^ b[i];
+    }
+    mbedtls_xor( r2, a, b, n );
+    ASSERT_COMPARE( r1, n, r2, n );
+
+    /* Test r == a */
+    fill_arrays( a, b, r1, r2, n );
+    for ( size_t i = 0; i < n; i++ )
+    {
+        r1[i] = r1[i] ^ b[i];
+    }
+    mbedtls_xor( r2, r2, b, n );
+    ASSERT_COMPARE( r1, n, r2, n );
+
+    /* Test r == b */
+    fill_arrays( a, b, r1, r2, n );
+    for ( size_t i = 0; i < n; i++ )
+    {
+        r1[i] = a[i] ^ r1[i];
+    }
+    mbedtls_xor( r2, a, r2, n );
+    ASSERT_COMPARE( r1, n, r2, n );
+
+    /* Test a == b */
+    fill_arrays( a, b, r1, r2, n );
+    for ( size_t i = 0; i < n; i++ )
+    {
+        r1[i] = a[i] ^ a[i];
+    }
+    mbedtls_xor( r2, a, a, n );
+    ASSERT_COMPARE( r1, n, r2, n );
+
+    /* Test a == b == r */
+    fill_arrays( a, b, r1, r2, n );
+    for ( size_t i = 0; i < n; i++ )
+    {
+        r1[i] = r1[i] ^ r1[i];
+    }
+    mbedtls_xor( r2, r2, r2, n );
+    ASSERT_COMPARE( r1, n, r2, n );
+
+    /* Test non-word-aligned buffers, for all combinations of alignedness */
+    for ( int i = 0; i < 7; i++ )
+    {
+        int r_off = i & 1, a_off = (i & 2) >> 1, b_off = (i & 4) >> 2;
+        fill_arrays( a, b, r1, r2, n + 1 );
+
+        for ( size_t j = 0; j < n; j++ )
+        {
+            r1[j + r_off] = a[j + a_off] ^ b[j + b_off];
+        }
+        mbedtls_xor( r2 + r_off, a + a_off, b + b_off, n );
+        ASSERT_COMPARE( r1 + r_off, n, r2 + r_off, n );
+    }
+exit:
+    mbedtls_free( a );
+    mbedtls_free( b );
+    mbedtls_free( r1 );
+    mbedtls_free( r2 );
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_constant_time.data b/tests/suites/test_suite_constant_time.data
new file mode 100644
index 0000000..4504aa4
--- /dev/null
+++ b/tests/suites/test_suite_constant_time.data
@@ -0,0 +1,11 @@
+# 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
+
+# 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
+
+# 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
diff --git a/tests/suites/test_suite_constant_time.function b/tests/suites/test_suite_constant_time.function
new file mode 100644
index 0000000..a3673b7
--- /dev/null
+++ b/tests/suites/test_suite_constant_time.function
@@ -0,0 +1,49 @@
+/* BEGIN_HEADER */
+/** \file test_suite_constant_time.function
+ *
+ * Functional testing of functions in the constant_time module.
+ *
+ * The tests are instrumented with #TEST_CF_SECRET and #TEST_CF_PUBLIC
+ * (see tests/include/test/constant_flow.h) so that running the tests
+ * under MSan or Valgrind will detect a non-constant-time implementation.
+ */
+
+#include <mbedtls/constant_time.h>
+#include <constant_time_internal.h>
+#include <constant_time_invasive.h>
+
+#include <test/constant_flow.h>
+/* END_HEADER */
+
+/* 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 )
+{
+    unsigned char *dst = NULL;
+    unsigned char *src = NULL;
+    size_t src_len = offset_max + len;
+    size_t secret;
+
+    ASSERT_ALLOC( dst, len );
+    ASSERT_ALLOC( src, src_len );
+
+    /* Fill src in a way that we can detect if we copied the right bytes */
+    mbedtls_test_rnd_std_rand( NULL, src, src_len );
+
+    for( secret = offset_min; secret <= (size_t) offset_max; secret++ )
+    {
+        mbedtls_test_set_step( (int) secret );
+
+        TEST_CF_SECRET( &secret, sizeof( secret ) );
+        mbedtls_ct_memcpy_offset( dst, src, secret,
+                                  offset_min, offset_max, len );
+        TEST_CF_PUBLIC( &secret, sizeof( secret ) );
+        TEST_CF_PUBLIC( dst, len );
+
+        ASSERT_COMPARE( dst, len, src + secret, len );
+    }
+
+exit:
+    mbedtls_free( dst );
+    mbedtls_free( src );
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_constant_time_hmac.data b/tests/suites/test_suite_constant_time_hmac.data
new file mode 100644
index 0000000..abf90f0
--- /dev/null
+++ b/tests/suites/test_suite_constant_time_hmac.data
@@ -0,0 +1,15 @@
+Constant-flow HMAC: MD5
+depends_on:MBEDTLS_HAS_ALG_MD5_VIA_MD_OR_PSA_BASED_ON_USE_PSA
+ssl_cf_hmac:MBEDTLS_MD_MD5
+
+Constant-flow HMAC: SHA1
+depends_on:MBEDTLS_HAS_ALG_SHA_1_VIA_MD_OR_PSA_BASED_ON_USE_PSA
+ssl_cf_hmac:MBEDTLS_MD_SHA1
+
+Constant-flow HMAC: SHA256
+depends_on:MBEDTLS_HAS_ALG_SHA_256_VIA_MD_OR_PSA_BASED_ON_USE_PSA
+ssl_cf_hmac:MBEDTLS_MD_SHA256
+
+Constant-flow HMAC: SHA384
+depends_on:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA
+ssl_cf_hmac:MBEDTLS_MD_SHA384
diff --git a/tests/suites/test_suite_constant_time_hmac.function b/tests/suites/test_suite_constant_time_hmac.function
new file mode 100644
index 0000000..f8c1bfc
--- /dev/null
+++ b/tests/suites/test_suite_constant_time_hmac.function
@@ -0,0 +1,160 @@
+/* BEGIN_HEADER */
+
+#include <mbedtls/constant_time.h>
+#include <mbedtls/legacy_or_psa.h>
+#include <mbedtls/md.h>
+#include <constant_time_internal.h>
+#include <hash_info.h>
+
+#include <test/constant_flow.h>
+/* END_HEADER */
+
+/* BEGIN_CASE depends_on:MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC:MBEDTLS_TEST_HOOKS */
+void ssl_cf_hmac( int hash )
+{
+    /*
+     * Test the function mbedtls_ct_hmac() against a reference
+     * implementation.
+     */
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_algorithm_t alg;
+    psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT;
+#else
+    mbedtls_md_context_t ctx, ref_ctx;
+    const mbedtls_md_info_t *md_info;
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+    size_t out_len, block_size;
+    size_t min_in_len, in_len, max_in_len, i;
+    /* TLS additional data is 13 bytes (hence the "lucky 13" name) */
+    unsigned char add_data[13];
+    unsigned char ref_out[MBEDTLS_HASH_MAX_SIZE];
+    unsigned char *data = NULL;
+    unsigned char *out = NULL;
+    unsigned char rec_num = 0;
+
+    USE_PSA_INIT( );
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    alg = PSA_ALG_HMAC( mbedtls_hash_info_psa_from_md( hash ) );
+
+    out_len = PSA_HASH_LENGTH( alg );
+    block_size = PSA_HASH_BLOCK_LENGTH( alg );
+
+    /* mbedtls_ct_hmac() requires the key to be exportable */
+    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_EXPORT |
+                                          PSA_KEY_USAGE_VERIFY_HASH );
+    psa_set_key_algorithm( &attributes, PSA_ALG_HMAC( alg ) );
+    psa_set_key_type( &attributes, PSA_KEY_TYPE_HMAC );
+#else
+    mbedtls_md_init( &ctx );
+    mbedtls_md_init( &ref_ctx );
+
+    md_info = mbedtls_md_info_from_type( hash );
+    TEST_ASSERT( md_info != NULL );
+    out_len = mbedtls_md_get_size( md_info );
+    TEST_ASSERT( out_len != 0 );
+    block_size = hash == MBEDTLS_MD_SHA384 ? 128 : 64;
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+    /* Use allocated out buffer to catch overwrites */
+    ASSERT_ALLOC( out, out_len );
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    /* Set up dummy key */
+    memset( ref_out, 42, sizeof( ref_out ) );
+    TEST_EQUAL( PSA_SUCCESS, psa_import_key( &attributes,
+                                             ref_out, out_len,
+                                             &key ) );
+#else
+    /* Set up contexts with the given hash and a dummy key */
+    TEST_EQUAL( 0, mbedtls_md_setup( &ctx, md_info, 1 ) );
+    TEST_EQUAL( 0, mbedtls_md_setup( &ref_ctx, md_info, 1 ) );
+    memset( ref_out, 42, sizeof( ref_out ) );
+    TEST_EQUAL( 0, mbedtls_md_hmac_starts( &ctx, ref_out, out_len ) );
+    TEST_EQUAL( 0, mbedtls_md_hmac_starts( &ref_ctx, ref_out, out_len ) );
+    memset( ref_out, 0, sizeof( ref_out ) );
+#endif
+
+    /*
+     * Test all possible lengths up to a point. The difference between
+     * max_in_len and min_in_len is at most 255, and make sure they both vary
+     * by at least one block size.
+     */
+    for( max_in_len = 0; max_in_len <= 255 + block_size; max_in_len++ )
+    {
+        mbedtls_test_set_step( max_in_len * 10000 );
+
+        /* Use allocated in buffer to catch overreads */
+        ASSERT_ALLOC( data, max_in_len );
+
+        min_in_len = max_in_len > 255 ? max_in_len - 255 : 0;
+        for( in_len = min_in_len; in_len <= max_in_len; in_len++ )
+        {
+            mbedtls_test_set_step( max_in_len * 10000 + in_len );
+
+            /* Set up dummy data and add_data */
+            rec_num++;
+            memset( add_data, rec_num, sizeof( add_data ) );
+            for( i = 0; i < in_len; i++ )
+                data[i] = ( i & 0xff ) ^ rec_num;
+
+            /* Get the function's result */
+            TEST_CF_SECRET( &in_len, sizeof( in_len ) );
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+            TEST_EQUAL( 0, mbedtls_ct_hmac( key, PSA_ALG_HMAC( alg ),
+                                            add_data, sizeof( add_data ),
+                                            data, in_len,
+                                            min_in_len, max_in_len,
+                                            out ) );
+#else
+            TEST_EQUAL( 0, mbedtls_ct_hmac( &ctx, add_data, sizeof( add_data ),
+                                            data, in_len,
+                                            min_in_len, max_in_len,
+                                            out ) );
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+            TEST_CF_PUBLIC( &in_len, sizeof( in_len ) );
+            TEST_CF_PUBLIC( out, out_len );
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+            TEST_EQUAL( PSA_SUCCESS, psa_mac_verify_setup( &operation,
+                                                           key, alg ) );
+            TEST_EQUAL( PSA_SUCCESS, psa_mac_update( &operation, add_data,
+                                                     sizeof( add_data ) ) );
+            TEST_EQUAL( PSA_SUCCESS, psa_mac_update( &operation,
+                                                     data, in_len ) );
+            TEST_EQUAL( PSA_SUCCESS, psa_mac_verify_finish( &operation,
+                                                            out, out_len ) );
+#else
+            /* Compute the reference result */
+            TEST_EQUAL( 0, mbedtls_md_hmac_update( &ref_ctx, add_data,
+                                                   sizeof( add_data ) ) );
+            TEST_EQUAL( 0, mbedtls_md_hmac_update( &ref_ctx, data, in_len ) );
+            TEST_EQUAL( 0, mbedtls_md_hmac_finish( &ref_ctx, ref_out ) );
+            TEST_EQUAL( 0, mbedtls_md_hmac_reset( &ref_ctx ) );
+
+            /* Compare */
+            ASSERT_COMPARE( out, out_len, ref_out, out_len );
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+        }
+
+        mbedtls_free( data );
+        data = NULL;
+    }
+
+exit:
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    psa_mac_abort( &operation );
+    psa_destroy_key( key );
+#else
+    mbedtls_md_free( &ref_ctx );
+    mbedtls_md_free( &ctx );
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+    mbedtls_free( data );
+    mbedtls_free( out );
+
+    USE_PSA_DONE( );
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_ecjpake.data b/tests/suites/test_suite_ecjpake.data
index 73808c9..c2ec782 100644
--- a/tests/suites/test_suite_ecjpake.data
+++ b/tests/suites/test_suite_ecjpake.data
@@ -35,7 +35,7 @@
 read_round_one:MBEDTLS_ECJPAKE_CLIENT:"0100":MBEDTLS_ERR_ECP_INVALID_KEY
 
 ECJPAKE round one: KKP1: unknown first point format
-read_round_one:MBEDTLS_ECJPAKE_CLIENT:"41057ea6e3a4487037a9e0dbd79262b2cc273e779930fc18409ac5361c5fe669d702e147790aeb4ce7fd6575ab0f6c7fd1c335939aa863ba37ec91b7e32bb013bb2b":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE
+read_round_one:MBEDTLS_ECJPAKE_CLIENT:"41057ea6e3a4487037a9e0dbd79262b2cc273e779930fc18409ac5361c5fe669d702e147790aeb4ce7fd6575ab0f6c7fd1c335939aa863ba37ec91b7e32bb013bb2b":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
 
 ECJPAKE round one: KKP1: nothing after first point
 read_round_one:MBEDTLS_ECJPAKE_CLIENT:"41047ea6e3a4487037a9e0dbd79262b2cc273e779930fc18409ac5361c5fe669d702e147790aeb4ce7fd6575ab0f6c7fd1c335939aa863ba37ec91b7e32bb013bb2b":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
@@ -50,7 +50,7 @@
 read_round_one:MBEDTLS_ECJPAKE_CLIENT:"41047ea6e3a4487037a9e0dbd79262b2cc273e779930fc18409ac5361c5fe669d702e147790aeb4ce7fd6575ab0f6c7fd1c335939aa863ba37ec91b7e32bb013bb2b0104":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
 
 ECJPAKE round one: KKP1: unknown second point format
-read_round_one:MBEDTLS_ECJPAKE_CLIENT:"41047ea6e3a4487037a9e0dbd79262b2cc273e779930fc18409ac5361c5fe669d702e147790aeb4ce7fd6575ab0f6c7fd1c335939aa863ba37ec91b7e32bb013bb2b410509f85b3d20ebd7885ce464c08d056d6428fe4dd9287aa365f131f4360ff386d846898bc4b41583c2a5197f65d78742746c12a5ec0a4ffe2f270a750a1d8fb516":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE
+read_round_one:MBEDTLS_ECJPAKE_CLIENT:"41047ea6e3a4487037a9e0dbd79262b2cc273e779930fc18409ac5361c5fe669d702e147790aeb4ce7fd6575ab0f6c7fd1c335939aa863ba37ec91b7e32bb013bb2b410509f85b3d20ebd7885ce464c08d056d6428fe4dd9287aa365f131f4360ff386d846898bc4b41583c2a5197f65d78742746c12a5ec0a4ffe2f270a750a1d8fb516":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
 
 ECJPAKE round one: KKP1: nothing after second point
 read_round_one:MBEDTLS_ECJPAKE_CLIENT:"41047ea6e3a4487037a9e0dbd79262b2cc273e779930fc18409ac5361c5fe669d702e147790aeb4ce7fd6575ab0f6c7fd1c335939aa863ba37ec91b7e32bb013bb2b410409f85b3d20ebd7885ce464c08d056d6428fe4dd9287aa365f131f4360ff386d846898bc4b41583c2a5197f65d78742746c12a5ec0a4ffe2f270a750a1d8fb516":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
@@ -83,7 +83,7 @@
 read_round_one:MBEDTLS_ECJPAKE_CLIENT:"4104190a07700ffa4be6ae1d79ee0f06aeb544cd5addaabedf70f8623321332c54f355f0fbfec783ed359e5d0bf7377a0fc4ea7ace473c9c112b41ccd41ac56a56124104360a1cea33fce641156458e0a4eac219e96831e6aebc88b3f3752f93a0281d1bf1fb106051db9694a8d6e862a5ef1324a3d9e27894f1ee4f7c59199965a8dd4a2091847d2d22df3ee55faa2a3fb33fd2d1e055a07a7c61ecfb8d80ec00c2c9eb120100":MBEDTLS_ERR_ECP_INVALID_KEY
 
 ECJPAKE round one: KKP2: unknown first point format
-read_round_one:MBEDTLS_ECJPAKE_CLIENT:"4104190a07700ffa4be6ae1d79ee0f06aeb544cd5addaabedf70f8623321332c54f355f0fbfec783ed359e5d0bf7377a0fc4ea7ace473c9c112b41ccd41ac56a56124104360a1cea33fce641156458e0a4eac219e96831e6aebc88b3f3752f93a0281d1bf1fb106051db9694a8d6e862a5ef1324a3d9e27894f1ee4f7c59199965a8dd4a2091847d2d22df3ee55faa2a3fb33fd2d1e055a07a7c61ecfb8d80ec00c2c9eb1241057ea6e3a4487037a9e0dbd79262b2cc273e779930fc18409ac5361c5fe669d702e147790aeb4ce7fd6575ab0f6c7fd1c335939aa863ba37ec91b7e32bb013bb2b":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE
+read_round_one:MBEDTLS_ECJPAKE_CLIENT:"4104190a07700ffa4be6ae1d79ee0f06aeb544cd5addaabedf70f8623321332c54f355f0fbfec783ed359e5d0bf7377a0fc4ea7ace473c9c112b41ccd41ac56a56124104360a1cea33fce641156458e0a4eac219e96831e6aebc88b3f3752f93a0281d1bf1fb106051db9694a8d6e862a5ef1324a3d9e27894f1ee4f7c59199965a8dd4a2091847d2d22df3ee55faa2a3fb33fd2d1e055a07a7c61ecfb8d80ec00c2c9eb1241057ea6e3a4487037a9e0dbd79262b2cc273e779930fc18409ac5361c5fe669d702e147790aeb4ce7fd6575ab0f6c7fd1c335939aa863ba37ec91b7e32bb013bb2b":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
 
 ECJPAKE round one: KKP2: nothing after first point
 read_round_one:MBEDTLS_ECJPAKE_CLIENT:"4104190a07700ffa4be6ae1d79ee0f06aeb544cd5addaabedf70f8623321332c54f355f0fbfec783ed359e5d0bf7377a0fc4ea7ace473c9c112b41ccd41ac56a56124104360a1cea33fce641156458e0a4eac219e96831e6aebc88b3f3752f93a0281d1bf1fb106051db9694a8d6e862a5ef1324a3d9e27894f1ee4f7c59199965a8dd4a2091847d2d22df3ee55faa2a3fb33fd2d1e055a07a7c61ecfb8d80ec00c2c9eb1241047ea6e3a4487037a9e0dbd79262b2cc273e779930fc18409ac5361c5fe669d702e147790aeb4ce7fd6575ab0f6c7fd1c335939aa863ba37ec91b7e32bb013bb2b":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
@@ -98,7 +98,7 @@
 read_round_one:MBEDTLS_ECJPAKE_CLIENT:"4104190a07700ffa4be6ae1d79ee0f06aeb544cd5addaabedf70f8623321332c54f355f0fbfec783ed359e5d0bf7377a0fc4ea7ace473c9c112b41ccd41ac56a56124104360a1cea33fce641156458e0a4eac219e96831e6aebc88b3f3752f93a0281d1bf1fb106051db9694a8d6e862a5ef1324a3d9e27894f1ee4f7c59199965a8dd4a2091847d2d22df3ee55faa2a3fb33fd2d1e055a07a7c61ecfb8d80ec00c2c9eb1241047ea6e3a4487037a9e0dbd79262b2cc273e779930fc18409ac5361c5fe669d702e147790aeb4ce7fd6575ab0f6c7fd1c335939aa863ba37ec91b7e32bb013bb2b0104":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
 
 ECJPAKE round one: KKP2: unknown second point format
-read_round_one:MBEDTLS_ECJPAKE_CLIENT:"4104190a07700ffa4be6ae1d79ee0f06aeb544cd5addaabedf70f8623321332c54f355f0fbfec783ed359e5d0bf7377a0fc4ea7ace473c9c112b41ccd41ac56a56124104360a1cea33fce641156458e0a4eac219e96831e6aebc88b3f3752f93a0281d1bf1fb106051db9694a8d6e862a5ef1324a3d9e27894f1ee4f7c59199965a8dd4a2091847d2d22df3ee55faa2a3fb33fd2d1e055a07a7c61ecfb8d80ec00c2c9eb1241047ea6e3a4487037a9e0dbd79262b2cc273e779930fc18409ac5361c5fe669d702e147790aeb4ce7fd6575ab0f6c7fd1c335939aa863ba37ec91b7e32bb013bb2b410509f85b3d20ebd7885ce464c08d056d6428fe4dd9287aa365f131f4360ff386d846898bc4b41583c2a5197f65d78742746c12a5ec0a4ffe2f270a750a1d8fb516":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE
+read_round_one:MBEDTLS_ECJPAKE_CLIENT:"4104190a07700ffa4be6ae1d79ee0f06aeb544cd5addaabedf70f8623321332c54f355f0fbfec783ed359e5d0bf7377a0fc4ea7ace473c9c112b41ccd41ac56a56124104360a1cea33fce641156458e0a4eac219e96831e6aebc88b3f3752f93a0281d1bf1fb106051db9694a8d6e862a5ef1324a3d9e27894f1ee4f7c59199965a8dd4a2091847d2d22df3ee55faa2a3fb33fd2d1e055a07a7c61ecfb8d80ec00c2c9eb1241047ea6e3a4487037a9e0dbd79262b2cc273e779930fc18409ac5361c5fe669d702e147790aeb4ce7fd6575ab0f6c7fd1c335939aa863ba37ec91b7e32bb013bb2b410509f85b3d20ebd7885ce464c08d056d6428fe4dd9287aa365f131f4360ff386d846898bc4b41583c2a5197f65d78742746c12a5ec0a4ffe2f270a750a1d8fb516":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
 
 ECJPAKE round one: KKP2: nothing after second point
 read_round_one:MBEDTLS_ECJPAKE_CLIENT:"4104190a07700ffa4be6ae1d79ee0f06aeb544cd5addaabedf70f8623321332c54f355f0fbfec783ed359e5d0bf7377a0fc4ea7ace473c9c112b41ccd41ac56a56124104360a1cea33fce641156458e0a4eac219e96831e6aebc88b3f3752f93a0281d1bf1fb106051db9694a8d6e862a5ef1324a3d9e27894f1ee4f7c59199965a8dd4a2091847d2d22df3ee55faa2a3fb33fd2d1e055a07a7c61ecfb8d80ec00c2c9eb1241047ea6e3a4487037a9e0dbd79262b2cc273e779930fc18409ac5361c5fe669d702e147790aeb4ce7fd6575ab0f6c7fd1c335939aa863ba37ec91b7e32bb013bb2b410409f85b3d20ebd7885ce464c08d056d6428fe4dd9287aa365f131f4360ff386d846898bc4b41583c2a5197f65d78742746c12a5ec0a4ffe2f270a750a1d8fb516":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
@@ -149,7 +149,7 @@
 read_round_two_cli:"0300170100":MBEDTLS_ERR_ECP_INVALID_KEY
 
 ECJPAKE round two client: unknown first point format
-read_round_two_cli:"03001741050fb22b1d5d1123e0ef9feb9d8a2e590a1f4d7ced2c2b06586e8f2a16d4eb2fda4328a20b07d8fd667654ca18c54e32a333a0845451e926ee8804fd7af0aaa7a6":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE
+read_round_two_cli:"03001741050fb22b1d5d1123e0ef9feb9d8a2e590a1f4d7ced2c2b06586e8f2a16d4eb2fda4328a20b07d8fd667654ca18c54e32a333a0845451e926ee8804fd7af0aaa7a6":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
 
 ECJPAKE round two client: nothing after first point
 read_round_two_cli:"03001741040fb22b1d5d1123e0ef9feb9d8a2e590a1f4d7ced2c2b06586e8f2a16d4eb2fda4328a20b07d8fd667654ca18c54e32a333a0845451e926ee8804fd7af0aaa7a6":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
@@ -164,7 +164,7 @@
 read_round_two_cli:"03001741040fb22b1d5d1123e0ef9feb9d8a2e590a1f4d7ced2c2b06586e8f2a16d4eb2fda4328a20b07d8fd667654ca18c54e32a333a0845451e926ee8804fd7af0aaa7a60104":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
 
 ECJPAKE round two client: unknown second point format
-read_round_two_cli:"03001741040fb22b1d5d1123e0ef9feb9d8a2e590a1f4d7ced2c2b06586e8f2a16d4eb2fda4328a20b07d8fd667654ca18c54e32a333a0845451e926ee8804fd7af0aaa7a641055516ea3e54a0d5d8b2ce786b38d383370029a5dbe4459c9dd601b408a24ae6465c8ac905b9eb03b5d3691c139ef83f1cd4200f6c9cd4ec392218a59ed243d3c8":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE
+read_round_two_cli:"03001741040fb22b1d5d1123e0ef9feb9d8a2e590a1f4d7ced2c2b06586e8f2a16d4eb2fda4328a20b07d8fd667654ca18c54e32a333a0845451e926ee8804fd7af0aaa7a641055516ea3e54a0d5d8b2ce786b38d383370029a5dbe4459c9dd601b408a24ae6465c8ac905b9eb03b5d3691c139ef83f1cd4200f6c9cd4ec392218a59ed243d3c8":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
 
 ECJPAKE round two client: nothing after second point
 read_round_two_cli:"03001741040fb22b1d5d1123e0ef9feb9d8a2e590a1f4d7ced2c2b06586e8f2a16d4eb2fda4328a20b07d8fd667654ca18c54e32a333a0845451e926ee8804fd7af0aaa7a641045516ea3e54a0d5d8b2ce786b38d383370029a5dbe4459c9dd601b408a24ae6465c8ac905b9eb03b5d3691c139ef83f1cd4200f6c9cd4ec392218a59ed243d3c8":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
@@ -203,7 +203,7 @@
 read_round_two_srv:"0100":MBEDTLS_ERR_ECP_INVALID_KEY
 
 ECJPAKE round two server: unknown first point format
-read_round_two_srv:"410569d54ee85e90ce3f1246742de507e939e81d1dc1c5cb988b58c310c9fdd9524d93720b45541c83ee8841191da7ced86e3312d43623c1d63e74989aba4affd1ee":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE
+read_round_two_srv:"410569d54ee85e90ce3f1246742de507e939e81d1dc1c5cb988b58c310c9fdd9524d93720b45541c83ee8841191da7ced86e3312d43623c1d63e74989aba4affd1ee":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
 
 ECJPAKE round two server: nothing after first point
 read_round_two_srv:"410469d54ee85e90ce3f1246742de507e939e81d1dc1c5cb988b58c310c9fdd9524d93720b45541c83ee8841191da7ced86e3312d43623c1d63e74989aba4affd1ee":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
@@ -218,7 +218,7 @@
 read_round_two_srv:"410469d54ee85e90ce3f1246742de507e939e81d1dc1c5cb988b58c310c9fdd9524d93720b45541c83ee8841191da7ced86e3312d43623c1d63e74989aba4affd1ee0104":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
 
 ECJPAKE round two server: unknown second point format
-read_round_two_srv:"410569d54ee85e90ce3f1246742de507e939e81d1dc1c5cb988b58c310c9fdd9524d93720b45541c83ee8841191da7ced86e3312d43623c1d63e74989aba4affd1ee4104077e8c31e20e6bedb760c13593e69f15be85c27d68cd09ccb8c4183608917c5c3d409fac39fefee82f7292d36f0d23e055913f45a52b85dd8a2052e9e129bb4d":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE
+read_round_two_srv:"410569d54ee85e90ce3f1246742de507e939e81d1dc1c5cb988b58c310c9fdd9524d93720b45541c83ee8841191da7ced86e3312d43623c1d63e74989aba4affd1ee4104077e8c31e20e6bedb760c13593e69f15be85c27d68cd09ccb8c4183608917c5c3d409fac39fefee82f7292d36f0d23e055913f45a52b85dd8a2052e9e129bb4d":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
 
 ECJPAKE round two server: nothing after second point
 read_round_two_srv:"410469d54ee85e90ce3f1246742de507e939e81d1dc1c5cb988b58c310c9fdd9524d93720b45541c83ee8841191da7ced86e3312d43623c1d63e74989aba4affd1ee4104077e8c31e20e6bedb760c13593e69f15be85c27d68cd09ccb8c4183608917c5c3d409fac39fefee82f7292d36f0d23e055913f45a52b85dd8a2052e9e129bb4d":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
diff --git a/tests/suites/test_suite_ecp.data b/tests/suites/test_suite_ecp.data
index 4c0ed1c..9311200 100644
--- a/tests/suites/test_suite_ecp.data
+++ b/tests/suites/test_suite_ecp.data
@@ -227,19 +227,51 @@
 
 ECP read binary #2 (zero, invalid first byte)
 depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
-ecp_read_binary:MBEDTLS_ECP_DP_SECP192R1:"01":"01":"01":"00":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE
+ecp_read_binary:MBEDTLS_ECP_DP_SECP192R1:"01":"01":"01":"00":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
 
 ECP read binary #3 (zero, OK)
 depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
 ecp_read_binary:MBEDTLS_ECP_DP_SECP192R1:"00":"01":"01":"00":0
 
-ECP read binary #4 (non-zero, invalid ilen)
+ECP read binary #4 (non-zero, invalid ilen, too short)
 depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
 ecp_read_binary:MBEDTLS_ECP_DP_SECP192R1:"04001122":"01":"01":"00":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
 
+ECP read binary #4a (non-zero, invalid ilen, too short)
+depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
+ecp_read_binary:MBEDTLS_ECP_DP_SECP192R1:"03001122":"01":"01":"00":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
+
+ECP read binary #4b (non-zero, invalid ilen, too short)
+depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
+ecp_read_binary:MBEDTLS_ECP_DP_SECP192R1:"02001122":"01":"01":"00":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
+
+ECP read binary #4c (non-zero, invalid ilen, too long)
+depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
+ecp_read_binary:MBEDTLS_ECP_DP_SECP192R1:"040011223344556677889900112233445566778899001122334455":"01":"01":"00":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
+
+ECP read binary #4d (non-zero, invalid ilen, too long)
+depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
+ecp_read_binary:MBEDTLS_ECP_DP_SECP192R1:"030011223344556677889900112233445566778899001122334455":"01":"01":"00":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
+
+ECP read binary #4e (non-zero, invalid ilen, too long)
+depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
+ecp_read_binary:MBEDTLS_ECP_DP_SECP192R1:"020011223344556677889900112233445566778899001122334455":"01":"01":"00":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
+
 ECP read binary #5 (non-zero, invalid first byte)
 depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
-ecp_read_binary:MBEDTLS_ECP_DP_SECP192R1:"0548d8082a3a1e3112bc03a8ef2f6d40d0a77a6f8e00cc99336ceed4d7cba482e288669ee1b6415626d6f34d28501e060c":"48d8082a3a1e3112bc03a8ef2f6d40d0a77a6f8e00cc9933":"6ceed4d7cba482e288669ee1b6415626d6f34d28501e060c":"01":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE
+ecp_read_binary:MBEDTLS_ECP_DP_SECP192R1:"0548d8082a3a1e3112bc03a8ef2f6d40d0a77a6f8e00cc99336ceed4d7cba482e288669ee1b6415626d6f34d28501e060c":"48d8082a3a1e3112bc03a8ef2f6d40d0a77a6f8e00cc9933":"6ceed4d7cba482e288669ee1b6415626d6f34d28501e060c":"01":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
+
+ECP read binary #5a (non-zero, compressed format, invalid first byte)
+depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
+ecp_read_binary:MBEDTLS_ECP_DP_SECP192R1:"0548d8082a3a1e3112bc03a8ef2f6d40d0a77a6f8e00cc9933":"48d8082a3a1e3112bc03a8ef2f6d40d0a77a6f8e00cc9933":"6ceed4d7cba482e288669ee1b6415626d6f34d28501e060c":"01":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
+
+ECP read binary #5b (non-zero, compressed format, parity 0, OK)
+depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
+ecp_read_binary:MBEDTLS_ECP_DP_SECP192R1:"0248d8082a3a1e3112bc03a8ef2f6d40d0a77a6f8e00cc9933":"48d8082a3a1e3112bc03a8ef2f6d40d0a77a6f8e00cc9933":"6ceed4d7cba482e288669ee1b6415626d6f34d28501e060c":"01":0
+
+ECP read binary #5c (non-zero, compressed format, parity 1, OK)
+depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
+ecp_read_binary:MBEDTLS_ECP_DP_SECP192R1:"0348d8082a3a1e3112bc03a8ef2f6d40d0a77a6f8e00cc9933":"48d8082a3a1e3112bc03a8ef2f6d40d0a77a6f8e00cc9933":"93112b28345b7d1d7799611e49bea9d8290cb2d7afe1f9f3":"01":0
 
 ECP read binary #6 (non-zero, OK)
 depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
@@ -285,6 +317,14 @@
 depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED
 ecp_read_binary:MBEDTLS_ECP_DP_CURVE448:"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff":"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff":"0":"1":0
 
+ECP read binary #17 (non-zero, compressed format, p != 3 mod 4, secp224r1)
+depends_on:MBEDTLS_ECP_DP_SECP224R1_ENABLED
+ecp_read_binary:MBEDTLS_ECP_DP_SECP224R1:"0200000000000000000000000000000000000000000000000000000000":"01":"01":"01":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE
+
+ECP read binary #17a (non-zero, compressed format, p != 3 mod 4, secp224k1)
+depends_on:MBEDTLS_ECP_DP_SECP224K1_ENABLED
+ecp_read_binary:MBEDTLS_ECP_DP_SECP224K1:"0200000000000000000000000000000000000000000000000000000000":"01":"01":"01":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE
+
 ECP tls read point #1 (zero, invalid length byte)
 depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
 mbedtls_ecp_tls_read_point:MBEDTLS_ECP_DP_SECP192R1:"0200":"01":"01":"00":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function
index 7d29e52..96b9f40 100644
--- a/tests/suites/test_suite_ecp.function
+++ b/tests/suites/test_suite_ecp.function
@@ -237,7 +237,7 @@
 }
 /* END_CASE */
 
-/* BEGIN_CASE depends_on:MBEDTLS_ECP_RESTARTABLE */
+/* BEGIN_CASE depends_on:MBEDTLS_ECP_RESTARTABLE:MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */
 void ecp_muladd_restart( int id, char *xR_str, char *yR_str,
                          char *u1_str, char *u2_str,
                          char *xQ_str, char *yQ_str,
@@ -642,6 +642,19 @@
         {
             TEST_ASSERT( mbedtls_mpi_cmp_mpi( &P.Y, &Y ) == 0 );
             TEST_ASSERT( mbedtls_mpi_cmp_mpi( &P.Z, &Z ) == 0 );
+
+            if( buf->x[0] == 0x04 &&
+                /* (reading compressed format supported only for
+                 *  Short Weierstrass curves with prime p where p = 3 mod 4) */
+                id != MBEDTLS_ECP_DP_SECP224R1 &&
+                id != MBEDTLS_ECP_DP_SECP224K1 )
+            {
+                /* re-encode in compressed format and test read again */
+                mbedtls_mpi_free( &P.Y );
+                buf->x[0] = 0x02 + mbedtls_mpi_get_bit( &Y, 0 );
+                TEST_ASSERT( mbedtls_ecp_point_read_binary( &grp, &P, buf->x, buf->len/2+1 ) == 0 );
+                TEST_ASSERT( mbedtls_mpi_cmp_mpi( &P.Y, &Y ) == 0 );
+            }
         }
     }
 
@@ -703,8 +716,10 @@
     memset( buf, 0x00, sizeof( buf ) ); vbuf = buf;
     TEST_ASSERT( mbedtls_ecp_tls_write_point( &grp, &grp.G,
                     MBEDTLS_ECP_PF_COMPRESSED, &olen, buf, 256 ) == 0 );
-    TEST_ASSERT( mbedtls_ecp_tls_read_point( &grp, &pt, &vbuf, olen )
-                 == MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE );
+    TEST_ASSERT( mbedtls_ecp_tls_read_point( &grp, &pt, &vbuf, olen ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &grp.G.X, &pt.X ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &grp.G.Y, &pt.Y ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &grp.G.Z, &pt.Z ) == 0 );
     TEST_ASSERT( vbuf == buf + olen );
 
     memset( buf, 0x00, sizeof( buf ) ); vbuf = buf;
diff --git a/tests/suites/test_suite_mps.function b/tests/suites/test_suite_mps.function
index c40c50e..ec1122a 100644
--- a/tests/suites/test_suite_mps.function
+++ b/tests/suites/test_suite_mps.function
@@ -295,7 +295,7 @@
     /* This test exercises the behaviour of the MPS reader with accumulator
      * in the situation where upon calling mbedtls_mps_reader_reclaim(), the
      * uncommitted data together with the excess data missing in the last
-     * call to medtls_mps_reader_get() exceeds the bounds of the type
+     * call to mbedtls_mps_reader_get() exceeds the bounds of the type
      * holding the buffer length.
      */
 
diff --git a/tests/suites/test_suite_pkcs7.data b/tests/suites/test_suite_pkcs7.data
new file mode 100644
index 0000000..571d5ad
--- /dev/null
+++ b/tests/suites/test_suite_pkcs7.data
@@ -0,0 +1,83 @@
+PKCS7 Signed Data Parse Pass SHA256 #1
+depends_on:MBEDTLS_SHA256_C:MBEDTLS_RSA_C
+pkcs7_parse:"data_files/pkcs7_data_cert_signed_sha256.der":MBEDTLS_PKCS7_SIGNED_DATA
+
+PKCS7 Signed Data Parse Pass SHA1 #2
+depends_on:MBEDTLS_SHA1_C:MBEDTLS_SHA256_C:MBEDTLS_RSA_C
+pkcs7_parse:"data_files/pkcs7_data_cert_signed_sha1.der":MBEDTLS_PKCS7_SIGNED_DATA
+
+PKCS7 Signed Data Parse Pass Without CERT #3
+depends_on:MBEDTLS_SHA256_C
+pkcs7_parse:"data_files/pkcs7_data_without_cert_signed.der":MBEDTLS_PKCS7_SIGNED_DATA
+
+PKCS7 Signed Data Parse Fail with multiple certs #4
+depends_on:MBEDTLS_SHA256_C:MBEDTLS_RSA_C
+pkcs7_parse:"data_files/pkcs7_data_multiple_certs_signed.der":MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE
+
+PKCS7 Signed Data Parse Fail with corrupted cert #5
+depends_on:MBEDTLS_SHA256_C:MBEDTLS_RSA_C
+pkcs7_parse:"data_files/pkcs7_data_signed_badcert.der":MBEDTLS_ERR_PKCS7_INVALID_CERT
+
+PKCS7 Signed Data Parse Fail with corrupted signer info #6
+depends_on:MBEDTLS_SHA256_C:MBEDTLS_RSA_C
+pkcs7_parse:"data_files/pkcs7_data_signed_badsigner.der":MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO,MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)
+
+PKCS7 Signed Data Parse Fail Version other than 1 #7
+depends_on:MBEDTLS_SHA256_C
+pkcs7_parse:"data_files/pkcs7_data_cert_signed_v2.der":MBEDTLS_ERR_PKCS7_INVALID_VERSION
+
+PKCS7 Signed Data Parse Fail Encrypted Content #8
+depends_on:MBEDTLS_SHA256_C
+pkcs7_parse:"data_files/pkcs7_data_cert_encrypted.der":MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE
+
+PKCS7 Signed Data Verification Pass SHA256 #9
+depends_on:MBEDTLS_SHA256_C
+pkcs7_verify:"data_files/pkcs7_data_cert_signed_sha256.der":"data_files/pkcs7-rsa-sha256-1.der":"data_files/pkcs7_data.bin":0:0
+
+PKCS7 Signed Data Verification Pass SHA256 #9.1
+depends_on:MBEDTLS_SHA256_C
+pkcs7_verify:"data_files/pkcs7_data_cert_signed_sha256.der":"data_files/pkcs7-rsa-sha256-1.der":"data_files/pkcs7_data.bin":MBEDTLS_MD_SHA256:0
+
+PKCS7 Signed Data Verification Pass SHA1 #10
+depends_on:MBEDTLS_SHA1_C:MBEDTLS_SHA256_C
+pkcs7_verify:"data_files/pkcs7_data_cert_signed_sha1.der":"data_files/pkcs7-rsa-sha256-1.der":"data_files/pkcs7_data.bin":0:0
+
+PKCS7 Signed Data Verification Pass SHA512 #11
+depends_on:MBEDTLS_SHA512_C:MBEDTLS_SHA256_C
+pkcs7_verify:"data_files/pkcs7_data_cert_signed_sha512.der":"data_files/pkcs7-rsa-sha256-1.der":"data_files/pkcs7_data.bin":0:0
+
+PKCS7 Signed Data Verification Fail because of different certificate #12
+depends_on:MBEDTLS_SHA256_C
+pkcs7_verify:"data_files/pkcs7_data_cert_signed_sha256.der":"data_files/pkcs7-rsa-sha256-2.der":"data_files/pkcs7_data.bin":0:MBEDTLS_ERR_RSA_VERIFY_FAILED
+
+PKCS7 Signed Data Verification Fail because of different data hash #13
+depends_on:MBEDTLS_SHA256_C
+pkcs7_verify:"data_files/pkcs7_data_cert_signed_sha256.der":"data_files/pkcs7-rsa-sha256-1.der":"data_files/pkcs7_data_1.bin":0:MBEDTLS_ERR_RSA_VERIFY_FAILED
+
+PKCS7 Signed Data Parse Failure Corrupt signerInfo.issuer #15.1
+depends_on:MBEDTLS_SHA256_C
+pkcs7_parse:"data_files/pkcs7_signerInfo_issuer_invalid_size.der":MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO
+
+PKCS7 Signed Data Parse Failure Corrupt signerInfo.serial #15.2
+depends_on:MBEDTLS_SHA256_C
+pkcs7_parse:"data_files/pkcs7_signerInfo_serial_invalid_size.der":MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO
+
+pkcs7_get_signers_info_set error handling (6213931373035520)
+depends_on:MBEDTLS_RIPEMD160_C
+pkcs7_parse:"data_files/pkcs7_get_signers_info_set-missing_free-fuzz_pkcs7-6213931373035520.der":MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG
+
+pkcs7_get_signers_info_set error handling (4541044530479104)
+depends_on:MBEDTLS_RIPEMD160_C
+pkcs7_parse:"data_files/pkcs7_get_signers_info_set-leak-fuzz_pkcs7-4541044530479104.der":MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO
+
+PKCS7 Only Signed Data Parse Pass #15
+depends_on:MBEDTLS_SHA256_C:MBEDTLS_RSA_C
+pkcs7_parse:"data_files/pkcs7_data_cert_signeddata_sha256.der":MBEDTLS_PKCS7_SIGNED_DATA
+
+PKCS7 Signed Data Verify with multiple signers #16
+depends_on:MBEDTLS_SHA256_C
+pkcs7_verify_multiple_signers:"data_files/pkcs7_data_multiple_signed.der":"data_files/pkcs7-rsa-sha256-1.crt":"data_files/pkcs7-rsa-sha256-2.crt":"data_files/pkcs7_data.bin":0:0
+
+PKCS7 Signed Data Hash Verify with multiple signers #17
+depends_on:MBEDTLS_SHA256_C
+pkcs7_verify_multiple_signers:"data_files/pkcs7_data_multiple_signed.der":"data_files/pkcs7-rsa-sha256-1.crt":"data_files/pkcs7-rsa-sha256-2.crt":"data_files/pkcs7_data.bin":MBEDTLS_MD_SHA256:0
diff --git a/tests/suites/test_suite_pkcs7.function b/tests/suites/test_suite_pkcs7.function
new file mode 100644
index 0000000..3d7dec6
--- /dev/null
+++ b/tests/suites/test_suite_pkcs7.function
@@ -0,0 +1,194 @@
+/* BEGIN_HEADER */
+#include "mbedtls/bignum.h"
+#include "mbedtls/pkcs7.h"
+#include "mbedtls/x509.h"
+#include "mbedtls/x509_crt.h"
+#include "mbedtls/x509_crl.h"
+#include "mbedtls/oid.h"
+#include "sys/types.h"
+#include "sys/stat.h"
+/* END_HEADER */
+
+/* BEGIN_DEPENDENCIES
+ * depends_on:MBEDTLS_PKCS7_C:MBEDTLS_RSA_C
+ * END_DEPENDENCIES
+ */
+
+/* BEGIN_CASE depends_on:MBEDTLS_FS_IO */
+void pkcs7_parse( char *pkcs7_file, int res_expect )
+{
+    unsigned char *pkcs7_buf = NULL;
+    size_t buflen;
+    int res;
+
+    mbedtls_pkcs7 pkcs7;
+
+    mbedtls_pkcs7_init( &pkcs7 );
+
+    res = mbedtls_pk_load_file( pkcs7_file, &pkcs7_buf, &buflen );
+    TEST_EQUAL( res, 0 );
+
+    res = mbedtls_pkcs7_parse_der( &pkcs7, pkcs7_buf, buflen );
+    TEST_EQUAL( res, res_expect );
+
+exit:
+    mbedtls_free( pkcs7_buf );
+    mbedtls_pkcs7_free( &pkcs7 );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C:MBEDTLS_PKCS1_V15:MBEDTLS_RSA_C */
+void pkcs7_verify( char *pkcs7_file, char *crt, char *filetobesigned, int do_hash_alg, int res_expect )
+{
+    unsigned char *pkcs7_buf = NULL;
+    size_t buflen;
+    unsigned char *data = NULL;
+    unsigned char hash[32];
+    struct stat st;
+    size_t datalen;
+    int res;
+    FILE *file;
+    const mbedtls_md_info_t *md_info;
+    mbedtls_md_type_t md_alg;
+
+    mbedtls_pkcs7 pkcs7;
+    mbedtls_x509_crt x509;
+
+    mbedtls_pkcs7_init( &pkcs7 );
+    mbedtls_x509_crt_init( &x509 );
+
+    USE_PSA_INIT();
+
+    res = mbedtls_x509_crt_parse_file( &x509, crt );
+    TEST_EQUAL( res, 0 );
+
+    res = mbedtls_pk_load_file( pkcs7_file, &pkcs7_buf, &buflen );
+    TEST_EQUAL( res, 0 );
+
+    res = mbedtls_pkcs7_parse_der( &pkcs7, pkcs7_buf, buflen );
+    TEST_EQUAL( res, MBEDTLS_PKCS7_SIGNED_DATA );
+
+    res = stat( filetobesigned, &st );
+    TEST_EQUAL( res, 0 );
+
+    file = fopen( filetobesigned, "rb" );
+    TEST_ASSERT( file != NULL );
+
+    datalen = st.st_size;
+    ASSERT_ALLOC( data, datalen );
+    TEST_ASSERT( data != NULL );
+
+    buflen = fread( (void *)data , sizeof( unsigned char ), datalen, file );
+    TEST_EQUAL( buflen, datalen );
+    fclose( file );
+
+    if( do_hash_alg )
+    {
+        res = mbedtls_oid_get_md_alg( &pkcs7.signed_data.digest_alg_identifiers, &md_alg );
+        TEST_EQUAL( res, 0 );
+        TEST_EQUAL( md_alg, (mbedtls_md_type_t) do_hash_alg );
+        md_info = mbedtls_md_info_from_type( md_alg );
+
+        res = mbedtls_md( md_info, data, datalen, hash );
+        TEST_EQUAL( res, 0 );
+
+        res = mbedtls_pkcs7_signed_hash_verify( &pkcs7, &x509, hash, sizeof(hash) );
+    }
+    else
+    {
+        res = mbedtls_pkcs7_signed_data_verify( &pkcs7, &x509, data, datalen );
+    }
+    TEST_EQUAL( res, res_expect );
+
+exit:
+    mbedtls_x509_crt_free( &x509 );
+    mbedtls_free( data );
+    mbedtls_pkcs7_free( &pkcs7 );
+    mbedtls_free( pkcs7_buf );
+    USE_PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C:MBEDTLS_PKCS1_V15:MBEDTLS_RSA_C */
+void pkcs7_verify_multiple_signers( char *pkcs7_file, char *crt1, char *crt2, char *filetobesigned, int do_hash_alg, int res_expect )
+{
+    unsigned char *pkcs7_buf = NULL;
+    size_t buflen;
+    unsigned char *data = NULL;
+    unsigned char hash[32];
+    struct stat st;
+    size_t datalen;
+    int res;
+    FILE *file;
+    const mbedtls_md_info_t *md_info;
+    mbedtls_md_type_t md_alg;
+
+    mbedtls_pkcs7 pkcs7;
+    mbedtls_x509_crt x509_1;
+    mbedtls_x509_crt x509_2;
+
+    mbedtls_pkcs7_init( &pkcs7 );
+    mbedtls_x509_crt_init( &x509_1 );
+    mbedtls_x509_crt_init( &x509_2 );
+
+    USE_PSA_INIT();
+
+    res = mbedtls_pk_load_file( pkcs7_file, &pkcs7_buf, &buflen );
+    TEST_EQUAL( res, 0 );
+
+    res = mbedtls_pkcs7_parse_der( &pkcs7, pkcs7_buf, buflen );
+    TEST_EQUAL( res, MBEDTLS_PKCS7_SIGNED_DATA );
+
+    TEST_EQUAL( pkcs7.signed_data.no_of_signers, 2 );
+
+    res = mbedtls_x509_crt_parse_file( &x509_1, crt1 );
+    TEST_EQUAL( res, 0 );
+
+    res = mbedtls_x509_crt_parse_file( &x509_2, crt2 );
+    TEST_EQUAL( res, 0 );
+
+    res = stat( filetobesigned, &st );
+    TEST_EQUAL( res, 0 );
+
+    file = fopen( filetobesigned, "rb" );
+    TEST_ASSERT( file != NULL );
+
+    datalen = st.st_size;
+    ASSERT_ALLOC( data, datalen );
+    buflen = fread( ( void * )data , sizeof( unsigned char ), datalen, file );
+    TEST_EQUAL( buflen, datalen );
+
+    fclose( file );
+
+    if( do_hash_alg )
+    {
+        res = mbedtls_oid_get_md_alg( &pkcs7.signed_data.digest_alg_identifiers, &md_alg );
+        TEST_EQUAL( res, 0 );
+        TEST_EQUAL( md_alg, MBEDTLS_MD_SHA256 );
+
+        md_info = mbedtls_md_info_from_type( md_alg );
+
+        res = mbedtls_md( md_info, data, datalen, hash );
+        TEST_EQUAL( res, 0 );
+
+        res = mbedtls_pkcs7_signed_hash_verify( &pkcs7, &x509_1, hash, sizeof(hash) );
+        TEST_EQUAL( res, res_expect );
+    }
+    else
+    {
+        res = mbedtls_pkcs7_signed_data_verify( &pkcs7, &x509_1, data, datalen );
+        TEST_EQUAL( res, res_expect );
+    }
+
+    res = mbedtls_pkcs7_signed_data_verify( &pkcs7, &x509_2, data, datalen );
+    TEST_EQUAL( res, res_expect );
+
+exit:
+    mbedtls_x509_crt_free( &x509_1 );
+    mbedtls_x509_crt_free( &x509_2 );
+    mbedtls_pkcs7_free( &pkcs7 );
+    mbedtls_free( data );
+    mbedtls_free( pkcs7_buf );
+    USE_PSA_DONE();
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data
index cce3fd0..9ced77c 100644
--- a/tests/suites/test_suite_psa_crypto.data
+++ b/tests/suites/test_suite_psa_crypto.data
@@ -4138,7 +4138,7 @@
 sign_hash_deterministic:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"6a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50f"
 
 PSA sign hash: deterministic ECDSA SECP256R1 SHA-384
-depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_384:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256:MBEDLTS_PSA_BUILTIN_ALG_SHA_384
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_384:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256:MBEDTLS_PSA_BUILTIN_ALG_SHA_384
 sign_hash_deterministic:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_384 ):"59e1748777448c69de6b800d7a33bbfb9ff1b463e44354c3553bcdb9c666fa90125a3c79f90397bdf5f6a13de828684f":"cd40ba1b555ca5994d30ddffc4ad734b1f5c604675b0f249814aa5de3992ef3ddf4d5dc5d2aab1979ce210b560754df671363d99795475882894c048e3b986ca"
 
 PSA sign hash: deterministic ECDSA SECP384R1 SHA-256
@@ -4406,7 +4406,7 @@
 sign_message_deterministic:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256):"616263":"36e5b5a7da1c9c265dc447de3a5a704fcb8c03f7a3749dde48d84c9bf736fc1ed48d8b3660e7d3cbc6b1870730b7ce2a043f69e37ccb340b98d1e65184e03548"
 
 PSA sign message: deterministic ECDSA SECP256R1 SHA-384
-depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_384:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256:MBEDLTS_PSA_BUILTIN_ALG_SHA_384
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_384:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256:MBEDTLS_PSA_BUILTIN_ALG_SHA_384
 sign_message_deterministic:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_384):"616263":"7ea712a20e3a8cbe0c6e64195362ba7635bbe78af51ddedd7a5fd858395250c592654c35d3b0614ae0e3b329c25cf5b4a5fcb243af3e3ad15c8446fe401be066"
 
 PSA sign message: deterministic ECDSA SECP384R1 SHA-256
@@ -4526,7 +4526,7 @@
 sign_verify_message:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_ECDSA(PSA_ALG_SHA_384):"616263"
 
 PSA sign/verify message: deterministic ECDSA SECP256R1 SHA-384
-depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_384:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256:MBEDLTS_PSA_BUILTIN_ALG_SHA_384
+depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_384:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256:MBEDTLS_PSA_BUILTIN_ALG_SHA_384
 sign_verify_message:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_384):"616263"
 
 PSA sign/verify message: randomized ECDSA SECP384R1 SHA-256
@@ -6490,111 +6490,3 @@
 
 PSA derive persistent key: HKDF SHA-256, exportable
 persistent_key_load_key_from_storage:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":PSA_KEY_TYPE_RAW_DATA:1024:PSA_KEY_USAGE_EXPORT:0:DERIVE_KEY
-
-PSA PAKE: invalid alg
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_setup:PSA_ALG_SHA_256:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:"abcd":PSA_ERROR_INVALID_ARGUMENT:0:0:0
-
-PSA PAKE: invalid primitive type
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_DH, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:"abcd":PSA_ERROR_NOT_SUPPORTED:0:0:0
-
-PSA PAKE: invalid primitive family
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_K1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:"abcd":PSA_ERROR_NOT_SUPPORTED:0:0:0
-
-PSA PAKE: invalid primitive bits
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 128):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:"abcd":PSA_ERROR_NOT_SUPPORTED:0:0:0
-
-PSA PAKE: invalid hash
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_1:PSA_PAKE_ROLE_SERVER:0:"abcd":PSA_ERROR_NOT_SUPPORTED:0:0:0
-
-PSA PAKE: ecjpake setup server output step first
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:"abcd":0:0:0:0
-
-PSA PAKE: ecjpake setup server input step first
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:1:"abcd":0:0:0:0
-
-PSA PAKE: ecjpake setup server empty password
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:"":0:0:0:PSA_ERROR_BAD_STATE
-
-PSA PAKE: ecjpake setup client output step first
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_CLIENT:0:"abcd":0:0:0:0
-
-PSA PAKE: ecjpake setup client input step first
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_CLIENT:1:"abcd":0:0:0:0
-
-PSA PAKE: ecjpake setup client empty password
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_CLIENT:0:"":0:0:0:PSA_ERROR_BAD_STATE
-
-PSA PAKE: ecjpake setup client bad password key type
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_DERIVE:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_CLIENT:0:"abcd":0:0:PSA_ERROR_INVALID_ARGUMENT:0
-
-PSA PAKE: ecjpake setup client bad password key usage
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_ENCRYPT:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_CLIENT:0:"abcd":0:0:PSA_ERROR_NOT_PERMITTED:0
-
-PSA PAKE: ecjpake setup invalid role NONE
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_NONE:0:"abcd":0:PSA_ERROR_NOT_SUPPORTED:0:0
-
-PSA PAKE: ecjpake rounds
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256:PSA_WANT_ALG_TLS12_PSK_TO_MS
-ecjpake_rounds:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256):"abcdef":0
-
-PSA PAKE: ecjpake rounds, client input first
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256:PSA_WANT_ALG_TLS12_PSK_TO_MS
-ecjpake_rounds:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256):"abcdef":1
-
-PSA PAKE: ecjpake no input errors
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:0:"abcdef"
-
-PSA PAKE: ecjpake no input errors, client input first
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:0:"abcdef"
-
-PSA PAKE: ecjpake inject input errors, first round client
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:1:"abcdef"
-
-PSA PAKE: ecjpake inject input errors, first round client, client input first
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:1:1:"abcdef"
-
-PSA PAKE: ecjpake inject input errors, first round server
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:2:"abcdef"
-
-PSA PAKE: ecjpake inject input errors, first round server, client input first
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:1:2:"abcdef"
-
-PSA PAKE: ecjpake inject input errors, second round client
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:3:"abcdef"
-
-PSA PAKE: ecjpake inject input errors, second round client, client input first
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:1:3:"abcdef"
-
-PSA PAKE: ecjpake inject input errors, second round server
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:4:"abcdef"
-
-PSA PAKE: ecjpake inject input errors, second round server, client input first
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
-ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:1:4:"abcdef"
-
-PSA PAKE: ecjpake size macros
-depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256
-ecjpake_size_macros:
diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function
index 779f594..a4c19b8 100644
--- a/tests/suites/test_suite_psa_crypto.function
+++ b/tests/suites/test_suite_psa_crypto.function
@@ -4,6 +4,7 @@
 #include "mbedtls/asn1.h"
 #include "mbedtls/asn1write.h"
 #include "mbedtls/oid.h"
+#include "common.h"
 
 /* For MBEDTLS_CTR_DRBG_MAX_REQUEST, knowing that psa_generate_random()
  * uses mbedtls_ctr_drbg internally. */
@@ -31,6 +32,27 @@
 #define ASSERT_OPERATION_IS_ACTIVE(   operation ) TEST_ASSERT( operation.id != 0 )
 #define ASSERT_OPERATION_IS_INACTIVE( operation ) TEST_ASSERT( operation.id == 0 )
 
+#if defined(PSA_WANT_ALG_JPAKE)
+int ecjpake_operation_setup( psa_pake_operation_t *operation,
+                              psa_pake_cipher_suite_t *cipher_suite,
+                              psa_pake_role_t role,
+                              mbedtls_svc_key_id_t key,
+                              size_t key_available )
+{
+    PSA_ASSERT( psa_pake_abort( operation ) );
+
+    PSA_ASSERT( psa_pake_setup( operation, cipher_suite ) );
+
+    PSA_ASSERT( psa_pake_set_role( operation, role) );
+
+    if( key_available )
+        PSA_ASSERT( psa_pake_set_password_key( operation, key ) );
+    return 0;
+exit:
+    return 1;
+}
+#endif
+
 /** An invalid export length that will never be set by psa_export_key(). */
 static const size_t INVALID_EXPORT_LENGTH = ~0U;
 
@@ -600,7 +622,7 @@
  *                                  the data in to be encrypted / decrypted. If
  *                                  -1, no chunking
  * \param expected_output           Expected output
- * \param is_verify                 If non-zero this is an verify operation.
+ * \param is_verify                 If non-zero this is a verify operation.
  * \param do_zero_parts             If non-zero, interleave zero length chunks
  *                                  with normal length chunks.
  * \return int                      Zero on failure, non-zero on success.
@@ -1297,6 +1319,24 @@
 }
 #endif /* PSA_WANT_ALG_JPAKE */
 
+typedef enum
+{
+    INJECT_ERR_NONE = 0,
+    INJECT_ERR_UNINITIALIZED_ACCESS,
+    INJECT_ERR_DUPLICATE_SETUP,
+    INJECT_ERR_INVALID_USER,
+    INJECT_ERR_INVALID_PEER,
+    INJECT_ERR_SET_USER,
+    INJECT_ERR_SET_PEER,
+    INJECT_EMPTY_IO_BUFFER,
+    INJECT_UNKNOWN_STEP,
+    INJECT_INVALID_FIRST_STEP,
+    INJECT_WRONG_BUFFER_SIZE,
+    INJECT_VALID_OPERATION_AFTER_FAILURE,
+    INJECT_ANTICIPATE_KEY_DERIVATION_1,
+    INJECT_ANTICIPATE_KEY_DERIVATION_2,
+} ecjpake_injected_failure_t;
+
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
@@ -1412,6 +1452,7 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
+/* Construct and attempt to import a large unstructured key. */
 void import_large_key( int type_arg, int byte_size_arg,
                        int expected_status_arg )
 {
@@ -1468,6 +1509,9 @@
 /* END_CASE */
 
 /* BEGIN_CASE depends_on:MBEDTLS_ASN1_WRITE_C */
+/* Import an RSA key with a valid structure (but not valid numbers
+ * inside, beyond having sensible size and parity). This is expected to
+ * fail for large keys. */
 void import_rsa_made_up( int bits_arg, int keypair, int expected_status_arg )
 {
     mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
@@ -1513,6 +1557,7 @@
                     int expected_bits,
                     int export_size_delta,
                     int expected_export_status_arg,
+                    /*whether reexport must give the original input exactly*/
                     int canonical_input )
 {
     mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
@@ -1617,7 +1662,7 @@
 
 /* BEGIN_CASE */
 void import_export_public_key( data_t *data,
-                               int type_arg,
+                               int type_arg, // key pair or public key
                                int alg_arg,
                                int lifetime_arg,
                                int export_size_delta,
@@ -3962,7 +4007,7 @@
     TEST_LE_U( length, output_buffer_size );
     output_length += length;
     PSA_ASSERT( psa_cipher_finish( &operation,
-                                   output + output_length,
+                                   mbedtls_buffer_offset( output, output_length ),
                                    output_buffer_size - output_length,
                                    &length ) );
     output_length += length;
@@ -3980,7 +4025,7 @@
     TEST_LE_U( length, output_buffer_size );
     output_length += length;
     PSA_ASSERT( psa_cipher_finish( &operation,
-                                   output + output_length,
+                                   mbedtls_buffer_offset( output, output_length ),
                                    output_buffer_size - output_length,
                                    &length ) );
     output_length += length;
@@ -6091,7 +6136,7 @@
 
     psa_aead_abort( &operation );
 
-    /* Test for calling set lengths with an plaintext length of SIZE_MAX, after setting nonce */
+    /* Test for calling set lengths with a plaintext length of SIZE_MAX, after setting nonce */
     PSA_ASSERT( psa_aead_encrypt_setup( &operation, key, alg ) );
 
     PSA_ASSERT( psa_aead_set_nonce( &operation, nonce->x, nonce->len ) );
@@ -8732,15 +8777,12 @@
 /* BEGIN_CASE depends_on:PSA_WANT_ALG_JPAKE */
 void ecjpake_setup( int alg_arg, int key_type_pw_arg, int key_usage_pw_arg,
                     int primitive_arg, int hash_arg, int role_arg,
-                    int input_first, data_t *pw_data,
-                    int expected_status_setup_arg,
-                    int expected_status_set_role_arg,
-                    int expected_status_set_password_key_arg,
-                    int expected_status_input_output_arg)
+                    int test_input, data_t *pw_data,
+                    int inj_err_type_arg,
+                    int expected_error_arg)
 {
     psa_pake_cipher_suite_t cipher_suite = psa_pake_cipher_suite_init();
     psa_pake_operation_t operation = psa_pake_operation_init();
-    psa_pake_operation_t op_copy = psa_pake_operation_init();
     psa_algorithm_t alg = alg_arg;
     psa_pake_primitive_t primitive = primitive_arg;
     psa_key_type_t key_type_pw = key_type_pw_arg;
@@ -8749,12 +8791,9 @@
     psa_pake_role_t role = role_arg;
     mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-    psa_status_t expected_status_setup = expected_status_setup_arg;
-    psa_status_t expected_status_set_role = expected_status_set_role_arg;
-    psa_status_t expected_status_set_password_key =
-                        expected_status_set_password_key_arg;
-    psa_status_t expected_status_input_output =
-                        expected_status_input_output_arg;
+    ecjpake_injected_failure_t inj_err_type = inj_err_type_arg;
+    psa_status_t expected_error = expected_error_arg;
+    psa_status_t status;
     unsigned char *output_buffer = NULL;
     size_t output_len = 0;
 
@@ -8779,54 +8818,90 @@
 
     PSA_ASSERT( psa_pake_abort( &operation ) );
 
-    TEST_EQUAL( psa_pake_set_user( &operation, NULL, 0 ),
-                PSA_ERROR_BAD_STATE );
-    TEST_EQUAL( psa_pake_set_peer( &operation, NULL, 0 ),
-                PSA_ERROR_BAD_STATE );
-    TEST_EQUAL( psa_pake_set_password_key( &operation, key ),
-                PSA_ERROR_BAD_STATE );
-    TEST_EQUAL( psa_pake_set_role( &operation, role ),
-                PSA_ERROR_BAD_STATE );
-    TEST_EQUAL( psa_pake_output( &operation, PSA_PAKE_STEP_KEY_SHARE,
-                                 NULL, 0, NULL ),
-                PSA_ERROR_BAD_STATE );
-    TEST_EQUAL( psa_pake_input( &operation, PSA_PAKE_STEP_KEY_SHARE, NULL, 0),
-                PSA_ERROR_BAD_STATE );
-
-    PSA_ASSERT( psa_pake_abort( &operation ) );
-
-    TEST_EQUAL( psa_pake_setup( &operation, &cipher_suite ),
-                expected_status_setup );
-    if( expected_status_setup != PSA_SUCCESS )
+    if ( inj_err_type == INJECT_ERR_UNINITIALIZED_ACCESS )
+    {
+        TEST_EQUAL( psa_pake_set_user( &operation, NULL, 0 ),
+                    expected_error );
+        PSA_ASSERT( psa_pake_abort( &operation ) );
+        TEST_EQUAL( psa_pake_set_peer( &operation, NULL, 0 ),
+                    expected_error );
+        PSA_ASSERT( psa_pake_abort( &operation ) );
+        TEST_EQUAL( psa_pake_set_password_key( &operation, key ),
+                    expected_error );
+        PSA_ASSERT( psa_pake_abort( &operation ) );
+        TEST_EQUAL( psa_pake_set_role( &operation, role ),
+                    expected_error );
+        PSA_ASSERT( psa_pake_abort( &operation ) );
+        TEST_EQUAL( psa_pake_output( &operation, PSA_PAKE_STEP_KEY_SHARE,
+                    NULL, 0, NULL ),
+                    expected_error );
+        PSA_ASSERT( psa_pake_abort( &operation ) );
+        TEST_EQUAL( psa_pake_input( &operation, PSA_PAKE_STEP_KEY_SHARE, NULL, 0),
+                    expected_error );
+        PSA_ASSERT( psa_pake_abort( &operation ) );
         goto exit;
+    }
 
-    TEST_EQUAL( psa_pake_setup( &operation, &cipher_suite ),
-                PSA_ERROR_BAD_STATE );
-
-    TEST_EQUAL( psa_pake_set_role( &operation, role),
-                expected_status_set_role );
-    if( expected_status_set_role != PSA_SUCCESS )
+    status = psa_pake_setup( &operation, &cipher_suite );
+    if (status != PSA_SUCCESS)
+    {
+        TEST_EQUAL( status, expected_error );
         goto exit;
+    }
+
+    if( inj_err_type == INJECT_ERR_DUPLICATE_SETUP )
+    {
+        TEST_EQUAL( psa_pake_setup( &operation, &cipher_suite ),
+                expected_error );
+        goto exit;
+    }
+
+    status = psa_pake_set_role( &operation, role);
+    if ( status != PSA_SUCCESS )
+    {
+        TEST_EQUAL( status, expected_error );
+        goto exit;
+    }
 
     if( pw_data->len > 0 )
     {
-        TEST_EQUAL( psa_pake_set_password_key( &operation, key ),
-                    expected_status_set_password_key );
-        if( expected_status_set_password_key != PSA_SUCCESS )
+        status = psa_pake_set_password_key( &operation, key );
+        if ( status != PSA_SUCCESS )
+        {
+            TEST_EQUAL( status, expected_error );
             goto exit;
+        }
     }
 
-    TEST_EQUAL( psa_pake_set_user( &operation, NULL, 0 ),
-                PSA_ERROR_INVALID_ARGUMENT );
-    TEST_EQUAL( psa_pake_set_peer( &operation, NULL, 0 ),
-                PSA_ERROR_INVALID_ARGUMENT );
+    if ( inj_err_type == INJECT_ERR_INVALID_USER )
+    {
+        TEST_EQUAL( psa_pake_set_user( &operation, NULL, 0 ),
+                    PSA_ERROR_INVALID_ARGUMENT );
+        goto exit;
+    }
 
-    const uint8_t unsupported_id[] = "abcd";
+    if ( inj_err_type == INJECT_ERR_INVALID_PEER )
+    {
+        TEST_EQUAL( psa_pake_set_peer( &operation, NULL, 0 ),
+                    PSA_ERROR_INVALID_ARGUMENT );
+        goto exit;
+    }
 
-    TEST_EQUAL( psa_pake_set_user( &operation, unsupported_id, 4 ),
-                PSA_ERROR_NOT_SUPPORTED );
-    TEST_EQUAL( psa_pake_set_peer( &operation, unsupported_id, 4 ),
-                PSA_ERROR_NOT_SUPPORTED );
+    if ( inj_err_type == INJECT_ERR_SET_USER )
+    {
+        const uint8_t unsupported_id[] = "abcd";
+        TEST_EQUAL( psa_pake_set_user( &operation, unsupported_id, 4 ),
+                    PSA_ERROR_NOT_SUPPORTED );
+        goto exit;
+    }
+
+    if ( inj_err_type == INJECT_ERR_SET_PEER )
+    {
+        const uint8_t unsupported_id[] = "abcd";
+        TEST_EQUAL( psa_pake_set_peer( &operation, unsupported_id, 4 ),
+                    PSA_ERROR_NOT_SUPPORTED );
+        goto exit;
+    }
 
     const size_t size_key_share = PSA_PAKE_INPUT_SIZE( alg, primitive,
                                                 PSA_PAKE_STEP_KEY_SHARE );
@@ -8835,79 +8910,109 @@
     const size_t size_zk_proof = PSA_PAKE_INPUT_SIZE( alg, primitive,
                                                 PSA_PAKE_STEP_ZK_PROOF );
 
-    /* First round */
-    if( input_first )
+    if ( test_input )
     {
-        /* Invalid parameters (input) */
-        op_copy = operation;
-        TEST_EQUAL( psa_pake_input( &op_copy, PSA_PAKE_STEP_ZK_PROOF,
-                                    NULL, 0 ),
-                    PSA_ERROR_INVALID_ARGUMENT );
-        /* Invalid parameters (step) */
-        op_copy = operation;
-        TEST_EQUAL( psa_pake_input( &op_copy, PSA_PAKE_STEP_ZK_PROOF + 10,
-                                    output_buffer, size_zk_proof ),
-                    PSA_ERROR_INVALID_ARGUMENT );
-        /* Invalid first step */
-        op_copy = operation;
-        TEST_EQUAL( psa_pake_input( &op_copy, PSA_PAKE_STEP_ZK_PROOF,
-                                    output_buffer, size_zk_proof ),
-                    PSA_ERROR_BAD_STATE );
-
-        /* Possibly valid */
-        TEST_EQUAL( psa_pake_input( &operation, PSA_PAKE_STEP_KEY_SHARE,
-                                    output_buffer, size_key_share ),
-                    expected_status_input_output);
-
-        if( expected_status_input_output == PSA_SUCCESS )
+        if ( inj_err_type == INJECT_EMPTY_IO_BUFFER )
         {
-            /* Buffer too large */
-            TEST_EQUAL( psa_pake_input( &operation, PSA_PAKE_STEP_ZK_PUBLIC,
-                                    output_buffer, size_zk_public + 1 ),
-                        PSA_ERROR_INVALID_ARGUMENT );
+            TEST_EQUAL( psa_pake_input( &operation, PSA_PAKE_STEP_ZK_PROOF, NULL, 0 ),
+                                        PSA_ERROR_INVALID_ARGUMENT );
+            goto exit;
+        }
 
-            /* The operation's state should be invalidated at this point */
+        if ( inj_err_type == INJECT_UNKNOWN_STEP )
+        {
+            TEST_EQUAL( psa_pake_input( &operation, PSA_PAKE_STEP_ZK_PROOF + 10,
+                                        output_buffer, size_zk_proof ),
+                                        PSA_ERROR_INVALID_ARGUMENT );
+            goto exit;
+        }
+
+        if ( inj_err_type == INJECT_INVALID_FIRST_STEP )
+        {
+            TEST_EQUAL( psa_pake_input( &operation, PSA_PAKE_STEP_ZK_PROOF,
+                                        output_buffer, size_zk_proof ),
+                                        PSA_ERROR_BAD_STATE );
+            goto exit;
+        }
+
+        status = psa_pake_input( &operation, PSA_PAKE_STEP_KEY_SHARE,
+                                        output_buffer, size_key_share );
+        if ( status != PSA_SUCCESS )
+        {
+            TEST_EQUAL( status, expected_error);
+            goto exit;
+        }
+
+        if ( inj_err_type == INJECT_WRONG_BUFFER_SIZE )
+        {
+            TEST_EQUAL( psa_pake_input( &operation, PSA_PAKE_STEP_ZK_PUBLIC,
+                                        output_buffer, size_zk_public + 1 ),
+                                        PSA_ERROR_INVALID_ARGUMENT );
+            goto exit;
+        }
+
+        if ( inj_err_type == INJECT_VALID_OPERATION_AFTER_FAILURE )
+        {
+            // Just trigger any kind of error. We don't care about the result here
+            psa_pake_input( &operation, PSA_PAKE_STEP_ZK_PUBLIC,
+                                        output_buffer, size_zk_public + 1 );
             TEST_EQUAL( psa_pake_input( &operation, PSA_PAKE_STEP_ZK_PUBLIC,
                                         output_buffer, size_zk_public ),
-                        PSA_ERROR_BAD_STATE );
+                                        PSA_ERROR_BAD_STATE );
+            goto exit;
         }
-    }
-    else
-    {
-        /* Invalid parameters (output) */
-        op_copy = operation;
-        TEST_EQUAL( psa_pake_output( &op_copy, PSA_PAKE_STEP_ZK_PROOF,
-                                     NULL, 0, NULL ),
-                    PSA_ERROR_INVALID_ARGUMENT );
-        op_copy = operation;
-        /* Invalid parameters (step) */
-        TEST_EQUAL( psa_pake_output( &op_copy, PSA_PAKE_STEP_ZK_PROOF + 10,
-                                     output_buffer, buf_size, &output_len ),
-                    PSA_ERROR_INVALID_ARGUMENT );
-        /* Invalid first step */
-        op_copy = operation;
-        TEST_EQUAL( psa_pake_output( &op_copy, PSA_PAKE_STEP_ZK_PROOF,
-                                     output_buffer, buf_size, &output_len ),
-                    PSA_ERROR_BAD_STATE );
-
-        /* Possibly valid */
-        TEST_EQUAL( psa_pake_output( &operation, PSA_PAKE_STEP_KEY_SHARE,
-                                     output_buffer, buf_size, &output_len ),
-                    expected_status_input_output );
-
-        if( expected_status_input_output == PSA_SUCCESS )
+    } else {
+        if ( inj_err_type == INJECT_EMPTY_IO_BUFFER )
         {
-            TEST_ASSERT( output_len > 0 );
+            TEST_EQUAL( psa_pake_output( &operation, PSA_PAKE_STEP_ZK_PROOF,
+                                        NULL, 0, NULL ),
+                                        PSA_ERROR_INVALID_ARGUMENT );
+            goto exit;
+        }
 
-            /* Buffer too small */
-            TEST_EQUAL( psa_pake_output( &operation, PSA_PAKE_STEP_ZK_PUBLIC,
-                                         output_buffer, size_zk_public - 1, &output_len ),
-                        PSA_ERROR_BUFFER_TOO_SMALL );
+        if ( inj_err_type == INJECT_UNKNOWN_STEP )
+        {
+            TEST_EQUAL( psa_pake_output( &operation, PSA_PAKE_STEP_ZK_PROOF + 10,
+                                        output_buffer, buf_size, &output_len ),
+                                        PSA_ERROR_INVALID_ARGUMENT );
+            goto exit;
+        }
 
-            /* The operation's state should be invalidated at this point */
+        if ( inj_err_type == INJECT_INVALID_FIRST_STEP )
+        {
+            TEST_EQUAL( psa_pake_output( &operation, PSA_PAKE_STEP_ZK_PROOF,
+                                        output_buffer, buf_size, &output_len ),
+                                        PSA_ERROR_BAD_STATE );
+            goto exit;
+        }
+
+        status = psa_pake_output( &operation, PSA_PAKE_STEP_KEY_SHARE,
+                                    output_buffer, buf_size, &output_len );
+        if ( status != PSA_SUCCESS )
+        {
+            TEST_EQUAL( status, expected_error);
+            goto exit;
+        }
+
+        TEST_ASSERT( output_len > 0 );
+
+        if ( inj_err_type == INJECT_WRONG_BUFFER_SIZE )
+        {
             TEST_EQUAL( psa_pake_output( &operation, PSA_PAKE_STEP_ZK_PUBLIC,
-                                         output_buffer, buf_size, &output_len ),
-                        PSA_ERROR_BAD_STATE );
+                                        output_buffer, size_zk_public - 1, &output_len ),
+                                        PSA_ERROR_BUFFER_TOO_SMALL );
+            goto exit;
+        }
+
+        if ( inj_err_type == INJECT_VALID_OPERATION_AFTER_FAILURE )
+        {
+            // Just trigger any kind of error. We don't care about the result here
+            psa_pake_output( &operation, PSA_PAKE_STEP_ZK_PUBLIC,
+                                        output_buffer, size_zk_public - 1, &output_len );
+            TEST_EQUAL( psa_pake_output( &operation, PSA_PAKE_STEP_ZK_PUBLIC,
+                                        output_buffer, buf_size, &output_len ),
+                                        PSA_ERROR_BAD_STATE );
+            goto exit;
         }
     }
 
@@ -8974,7 +9079,7 @@
 /* BEGIN_CASE depends_on:PSA_WANT_ALG_JPAKE */
 void ecjpake_rounds( int alg_arg, int primitive_arg, int hash_arg,
                      int derive_alg_arg, data_t *pw_data,
-                     int client_input_first )
+                     int client_input_first, int inj_err_type_arg )
 {
     psa_pake_cipher_suite_t cipher_suite = psa_pake_cipher_suite_init();
     psa_pake_operation_t server = psa_pake_operation_init();
@@ -8988,6 +9093,7 @@
                             PSA_KEY_DERIVATION_OPERATION_INIT;
     psa_key_derivation_operation_t client_derive =
                             PSA_KEY_DERIVATION_OPERATION_INIT;
+    ecjpake_injected_failure_t inj_err_type = inj_err_type_arg;
 
     PSA_INIT( );
 
@@ -9025,19 +9131,27 @@
     PSA_ASSERT( psa_pake_set_password_key( &server, key ) );
     PSA_ASSERT( psa_pake_set_password_key( &client, key ) );
 
-    TEST_EQUAL( psa_pake_get_implicit_key( &server, &server_derive ),
+    if( inj_err_type == INJECT_ANTICIPATE_KEY_DERIVATION_1 )
+    {
+        TEST_EQUAL( psa_pake_get_implicit_key( &server, &server_derive ),
                 PSA_ERROR_BAD_STATE );
-    TEST_EQUAL( psa_pake_get_implicit_key( &client, &client_derive ),
+        TEST_EQUAL( psa_pake_get_implicit_key( &client, &client_derive ),
                 PSA_ERROR_BAD_STATE );
+        goto exit;
+    }
 
     /* First round */
     ecjpake_do_round( alg, primitive_arg, &server, &client,
                       client_input_first, 1, 0 );
 
-    TEST_EQUAL( psa_pake_get_implicit_key( &server, &server_derive ),
+    if ( inj_err_type == INJECT_ANTICIPATE_KEY_DERIVATION_2 )
+    {
+        TEST_EQUAL( psa_pake_get_implicit_key( &server, &server_derive ),
                 PSA_ERROR_BAD_STATE );
-    TEST_EQUAL( psa_pake_get_implicit_key( &client, &client_derive ),
+        TEST_EQUAL( psa_pake_get_implicit_key( &client, &client_derive ),
                 PSA_ERROR_BAD_STATE );
+        goto exit;
+    }
 
     /* Second round */
     ecjpake_do_round( alg, primitive_arg, &server, &client,
diff --git a/tests/suites/test_suite_psa_crypto_driver_wrappers.data b/tests/suites/test_suite_psa_crypto_driver_wrappers.data
index 0a8d595..6069a69 100644
--- a/tests/suites/test_suite_psa_crypto_driver_wrappers.data
+++ b/tests/suites/test_suite_psa_crypto_driver_wrappers.data
@@ -299,6 +299,22 @@
 depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY:MBEDTLS_PK_PARSE_C:MBEDTLS_PK_WRITE_C:PSA_WANT_ECC_SECP_R1_256
 export_key:PSA_ERROR_GENERIC_ERROR:"":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1):"":PSA_ERROR_GENERIC_ERROR
 
+raw key agreement through driver: fake
+depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+key_agreement:PSA_ALG_ECDH:PSA_SUCCESS:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433":"04d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf6356fbf3ca366cc23e8157854c13c58d6aac23f046ada30f8353e74f33039872ab":"d6840f6b42f6edafd13116e0e12565202fef8e9ece7dce03812464d04b9442de":"0102030405":PSA_SUCCESS
+
+raw key agreement through driver: in-driver
+depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+key_agreement:PSA_ALG_ECDH:PSA_SUCCESS:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433":"04d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf6356fbf3ca366cc23e8157854c13c58d6aac23f046ada30f8353e74f33039872ab":"d6840f6b42f6edafd13116e0e12565202fef8e9ece7dce03812464d04b9442de":"":PSA_SUCCESS
+
+raw key agreement through driver: fallback
+depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256:MBEDTLS_PSA_BUILTIN_ALG_ECDH
+key_agreement:PSA_ALG_ECDH:PSA_ERROR_NOT_SUPPORTED:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433":"04d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf6356fbf3ca366cc23e8157854c13c58d6aac23f046ada30f8353e74f33039872ab":"d6840f6b42f6edafd13116e0e12565202fef8e9ece7dce03812464d04b9442de":"":PSA_SUCCESS
+
+raw key agreement through driver: error
+depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256
+key_agreement:PSA_ALG_ECDH:PSA_ERROR_GENERIC_ERROR:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433":"04d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf6356fbf3ca366cc23e8157854c13c58d6aac23f046ada30f8353e74f33039872ab":"d6840f6b42f6edafd13116e0e12565202fef8e9ece7dce03812464d04b9442de":"":PSA_ERROR_GENERIC_ERROR
+
 PSA symmetric encrypt validation: AES-CTR, 16 bytes, good
 depends_on:PSA_WANT_ALG_CTR:PSA_WANT_KEY_TYPE_AES
 cipher_encrypt_validation:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"6bc1bee22e409f96e93d7e117393172a"
diff --git a/tests/suites/test_suite_psa_crypto_driver_wrappers.function b/tests/suites/test_suite_psa_crypto_driver_wrappers.function
index 128352b..b713cb2 100644
--- a/tests/suites/test_suite_psa_crypto_driver_wrappers.function
+++ b/tests/suites/test_suite_psa_crypto_driver_wrappers.function
@@ -542,6 +542,94 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
+void key_agreement( int alg_arg,
+                    int force_status_arg,
+                    int our_key_type_arg,
+                    data_t *our_key_data,
+                    data_t *peer_key_data,
+                    data_t *expected_output,
+                    data_t* fake_output,
+                    int expected_status_arg )
+{
+    psa_status_t force_status = force_status_arg;
+    psa_status_t expected_status = expected_status_arg;
+    psa_algorithm_t alg = alg_arg;
+    psa_key_type_t our_key_type = our_key_type_arg;
+    mbedtls_svc_key_id_t our_key = MBEDTLS_SVC_KEY_ID_INIT;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    const uint8_t *expected_output_ptr = NULL;
+    size_t expected_output_length = 0;
+    unsigned char *actual_output = NULL;
+    size_t actual_output_length = ~0;
+    size_t key_bits;
+    psa_status_t actual_status;
+    mbedtls_test_driver_key_agreement_hooks =
+        mbedtls_test_driver_key_agreement_hooks_init();
+
+    PSA_ASSERT( psa_crypto_init( ) );
+
+    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DERIVE );
+    psa_set_key_algorithm( &attributes, alg );
+    psa_set_key_type( &attributes, our_key_type );
+    PSA_ASSERT( psa_import_key( &attributes,
+                                our_key_data->x, our_key_data->len,
+                                &our_key ) );
+
+    PSA_ASSERT( psa_get_key_attributes( our_key, &attributes ) );
+    key_bits = psa_get_key_bits( &attributes );
+
+    TEST_LE_U( expected_output->len,
+               PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE( our_key_type, key_bits ) );
+    TEST_LE_U( PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE( our_key_type, key_bits ),
+               PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE );
+
+    if( fake_output->len > 0 )
+    {
+        expected_output_ptr =
+            mbedtls_test_driver_key_agreement_hooks.forced_output =
+            fake_output->x;
+
+        expected_output_length =
+            mbedtls_test_driver_key_agreement_hooks.forced_output_length =
+            fake_output->len;
+    }
+    else
+    {
+        expected_output_ptr = expected_output->x;
+        expected_output_length = expected_output->len;
+    }
+
+    mbedtls_test_driver_key_agreement_hooks.hits = 0;
+    mbedtls_test_driver_key_agreement_hooks.forced_status = force_status;
+
+    ASSERT_ALLOC( actual_output, expected_output->len );
+    actual_status = psa_raw_key_agreement( alg, our_key,
+                                       peer_key_data->x, peer_key_data->len,
+                                       actual_output, expected_output->len,
+                                       &actual_output_length ) ;
+    TEST_EQUAL( actual_status, expected_status );
+    TEST_EQUAL( mbedtls_test_driver_key_agreement_hooks.hits, 1 );
+
+    if( actual_status == PSA_SUCCESS )
+    {
+        ASSERT_COMPARE( actual_output, actual_output_length,
+                        expected_output_ptr, expected_output_length);
+    }
+    mbedtls_free( actual_output );
+    actual_output = NULL;
+    actual_output_length = ~0;
+
+exit:
+    psa_reset_key_attributes( &attributes );
+    psa_destroy_key( our_key );
+    PSA_DONE( );
+    mbedtls_test_driver_key_agreement_hooks =
+        mbedtls_test_driver_key_agreement_hooks_init();
+}
+
+/* END_CASE */
+
+/* BEGIN_CASE */
 void cipher_encrypt_validation( int alg_arg,
                                 int key_type_arg,
                                 data_t *key_data,
@@ -660,14 +748,14 @@
     mbedtls_psa_cipher_operation_t mbedtls_operation =
             MBEDTLS_PSA_CIPHER_OPERATION_INIT;
 
-    mbedtls_transparent_test_driver_cipher_operation_t tranparent_operation =
+    mbedtls_transparent_test_driver_cipher_operation_t transparent_operation =
             MBEDTLS_TRANSPARENT_TEST_DRIVER_CIPHER_OPERATION_INIT;
 
     mbedtls_opaque_test_driver_cipher_operation_t opaque_operation =
             MBEDTLS_OPAQUE_TEST_DRIVER_CIPHER_OPERATION_INIT;
 
     operation.ctx.mbedtls_ctx = mbedtls_operation;
-    operation.ctx.transparent_test_driver_ctx = tranparent_operation;
+    operation.ctx.transparent_test_driver_ctx = transparent_operation;
     operation.ctx.opaque_test_driver_ctx = opaque_operation;
 
     PSA_ASSERT( psa_crypto_init( ) );
@@ -792,14 +880,14 @@
     mbedtls_psa_cipher_operation_t mbedtls_operation =
             MBEDTLS_PSA_CIPHER_OPERATION_INIT;
 
-    mbedtls_transparent_test_driver_cipher_operation_t tranparent_operation =
+    mbedtls_transparent_test_driver_cipher_operation_t transparent_operation =
             MBEDTLS_TRANSPARENT_TEST_DRIVER_CIPHER_OPERATION_INIT;
 
     mbedtls_opaque_test_driver_cipher_operation_t opaque_operation =
             MBEDTLS_OPAQUE_TEST_DRIVER_CIPHER_OPERATION_INIT;
 
     operation.ctx.mbedtls_ctx = mbedtls_operation;
-    operation.ctx.transparent_test_driver_ctx = tranparent_operation;
+    operation.ctx.transparent_test_driver_ctx = transparent_operation;
     operation.ctx.opaque_test_driver_ctx = opaque_operation;
 
     PSA_ASSERT( psa_crypto_init( ) );
diff --git a/tests/suites/test_suite_psa_crypto_generate_key.function b/tests/suites/test_suite_psa_crypto_generate_key.function
index dbe9a0e..6dc6043 100644
--- a/tests/suites/test_suite_psa_crypto_generate_key.function
+++ b/tests/suites/test_suite_psa_crypto_generate_key.function
@@ -18,7 +18,7 @@
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
     mbedtls_svc_key_id_t key_id = INVALID_KEY_ID;
 
-    // key lifetiem, usage flags, algorithm are irrelevant for this test
+    // key lifetime, usage flags, algorithm are irrelevant for this test
     psa_key_type_t key_type = key_type_arg;
     size_t bits = bits_arg;
     psa_status_t expected_status = expected_status_arg;
diff --git a/tests/suites/test_suite_psa_crypto_pake.data b/tests/suites/test_suite_psa_crypto_pake.data
new file mode 100644
index 0000000..f447ef0
--- /dev/null
+++ b/tests/suites/test_suite_psa_crypto_pake.data
@@ -0,0 +1,203 @@
+PSA PAKE: uninitialized access to psa_pake_operation_t
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:ERR_INJECT_UNINITIALIZED_ACCESS:PSA_ERROR_BAD_STATE
+
+PSA PAKE: invalid alg
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_SHA_256:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:ERR_IN_SETUP:PSA_ERROR_INVALID_ARGUMENT
+
+PSA PAKE: invalid primitive type
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_DH, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:ERR_IN_SETUP:PSA_ERROR_NOT_SUPPORTED
+
+PSA PAKE: invalid primitive family
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_K1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:ERR_IN_SETUP:PSA_ERROR_NOT_SUPPORTED
+
+PSA PAKE: invalid primitive bits
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 128):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:ERR_IN_SETUP:PSA_ERROR_NOT_SUPPORTED
+
+PSA PAKE: invalid hash
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_1:PSA_PAKE_ROLE_SERVER:0:ERR_IN_SETUP:PSA_ERROR_NOT_SUPPORTED
+
+PSA PAKE: duplicate a valid setup
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:ERR_INJECT_DUPLICATE_SETUP:PSA_ERROR_BAD_STATE
+
+PSA PAKE: ecjpake setup invalid role NONE
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_NONE:0:ERR_IN_SET_ROLE:PSA_ERROR_NOT_SUPPORTED
+
+PSA PAKE: wrong password key type
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_HMAC:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:ERR_IN_SET_PASSWORD_KEY:PSA_ERROR_INVALID_ARGUMENT
+
+PSA PAKE: wrong password key usage
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_ENCRYPT:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:ERR_IN_SET_PASSWORD_KEY:PSA_ERROR_NOT_PERMITTED
+
+PSA PAKE: set invalid user
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:ERR_INJECT_INVALID_USER:PSA_ERROR_INVALID_ARGUMENT
+
+PSA PAKE: set invalid peer
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:ERR_INJECT_INVALID_PEER:PSA_ERROR_INVALID_ARGUMENT
+
+PSA PAKE: set user
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:ERR_INJECT_SET_USER:PSA_ERROR_NOT_SUPPORTED
+
+PSA PAKE: set peer
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:ERR_INJECT_SET_PEER:PSA_ERROR_NOT_SUPPORTED
+
+PSA PAKE: invalid input
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:1:ERR_INJECT_EMPTY_IO_BUFFER:PSA_ERROR_INVALID_ARGUMENT
+
+PSA PAKE: unkown input step
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:1:ERR_INJECT_UNKNOWN_STEP:PSA_ERROR_INVALID_ARGUMENT
+
+PSA PAKE: invalid first input step
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:1:ERR_INJECT_INVALID_FIRST_STEP:PSA_ERROR_BAD_STATE
+
+PSA PAKE: input buffer too large
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:1:ERR_INJECT_WRONG_BUFFER_SIZE:PSA_ERROR_INVALID_ARGUMENT
+
+PSA PAKE: valid input operation after a failure
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:1:ERR_INJECT_VALID_OPERATION_AFTER_FAILURE:PSA_ERROR_BAD_STATE
+
+PSA PAKE: invalid output
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:ERR_INJECT_EMPTY_IO_BUFFER:PSA_ERROR_INVALID_ARGUMENT
+
+PSA PAKE: unkown output step
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:ERR_INJECT_UNKNOWN_STEP:PSA_ERROR_INVALID_ARGUMENT
+
+PSA PAKE: invalid first output step
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:ERR_INJECT_INVALID_FIRST_STEP:PSA_ERROR_BAD_STATE
+
+PSA PAKE: output buffer too small
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:ERR_INJECT_WRONG_BUFFER_SIZE:PSA_ERROR_BUFFER_TOO_SMALL
+
+PSA PAKE: valid output operation after a failure
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_setup:PSA_ALG_JPAKE:PSA_KEY_TYPE_PASSWORD:PSA_KEY_USAGE_DERIVE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_PAKE_ROLE_SERVER:0:ERR_INJECT_VALID_OPERATION_AFTER_FAILURE:PSA_ERROR_BAD_STATE
+
+PSA PAKE: check rounds w/o forced errors
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256:PSA_WANT_ALG_TLS12_PSK_TO_MS
+ecjpake_rounds:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256):"abcdef":0:0:ERR_NONE
+
+PSA PAKE: check rounds w/o forced errors, TLS12_PRF
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256:PSA_WANT_ALG_TLS12_PRF
+ecjpake_rounds:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_ALG_TLS12_PRF(PSA_ALG_SHA_256):"abcdef":0:0:ERR_NONE
+
+PSA PAKE: check rounds, key is destroyed after being passed to set_password_key
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256:PSA_WANT_ALG_TLS12_PSK_TO_MS
+ecjpake_rounds:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256):"abcdef":0:1:ERR_NONE
+
+PSA PAKE: check rounds w/o forced errors, client input first
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256:PSA_WANT_ALG_TLS12_PSK_TO_MS
+ecjpake_rounds:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256):"abcdef":1:0:ERR_NONE
+
+PSA PAKE: force early key derivation 1
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256:PSA_WANT_ALG_TLS12_PSK_TO_MS
+ecjpake_rounds:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256):"abcdef":0:0:ERR_INJECT_ANTICIPATE_KEY_DERIVATION_1
+
+PSA PAKE: force early key derivation 2
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256:PSA_WANT_ALG_TLS12_PSK_TO_MS
+ecjpake_rounds:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256):"abcdef":0:0:ERR_INJECT_ANTICIPATE_KEY_DERIVATION_2
+
+PSA PAKE: no injected errors
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:"abcdef":ERR_NONE:PSA_SUCCESS
+
+PSA PAKE: no injected errors, client input first
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:1:"abcdef":ERR_NONE:PSA_SUCCESS
+
+PSA PAKE: inject ERR_INJECT_ROUND1_CLIENT_KEY_SHARE_PART1
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:"abcdef":ERR_INJECT_ROUND1_CLIENT_KEY_SHARE_PART1:PSA_ERROR_DATA_INVALID
+
+PSA PAKE: inject ERR_INJECT_ROUND1_CLIENT_ZK_PUBLIC_PART1
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:"abcdef":ERR_INJECT_ROUND1_CLIENT_ZK_PUBLIC_PART1:PSA_ERROR_DATA_INVALID
+
+PSA PAKE: inject ERR_INJECT_ROUND1_CLIENT_ZK_PROOF_PART1
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:"abcdef":ERR_INJECT_ROUND1_CLIENT_ZK_PROOF_PART1:PSA_ERROR_DATA_INVALID
+
+PSA PAKE: inject ERR_INJECT_ROUND1_CLIENT_KEY_SHARE_PART2
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:"abcdef":ERR_INJECT_ROUND1_CLIENT_KEY_SHARE_PART2:PSA_ERROR_DATA_INVALID
+
+PSA PAKE: inject ERR_INJECT_ROUND1_CLIENT_ZK_PUBLIC_PART2
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:"abcdef":ERR_INJECT_ROUND1_CLIENT_ZK_PUBLIC_PART2:PSA_ERROR_DATA_INVALID
+
+PSA PAKE: inject ERR_INJECT_ROUND1_CLIENT_ZK_PROOF_PART2
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:"abcdef":ERR_INJECT_ROUND1_CLIENT_ZK_PROOF_PART2:PSA_ERROR_DATA_INVALID
+
+PSA PAKE: inject ERR_INJECT_ROUND1_SERVER_KEY_SHARE_PART1
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:"abcdef":ERR_INJECT_ROUND1_SERVER_KEY_SHARE_PART1:PSA_ERROR_DATA_INVALID
+
+PSA PAKE: inject ERR_INJECT_ROUND1_SERVER_ZK_PUBLIC_PART1
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:"abcdef":ERR_INJECT_ROUND1_SERVER_ZK_PUBLIC_PART1:PSA_ERROR_DATA_INVALID
+
+PSA PAKE: inject ERR_INJECT_ROUND1_SERVER_ZK_PROOF_PART1
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:"abcdef":ERR_INJECT_ROUND1_SERVER_ZK_PROOF_PART1:PSA_ERROR_DATA_INVALID
+
+PSA PAKE: inject ERR_INJECT_ROUND1_SERVER_KEY_SHARE_PART2
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:"abcdef":ERR_INJECT_ROUND1_SERVER_KEY_SHARE_PART2:PSA_ERROR_DATA_INVALID
+
+PSA PAKE: inject ERR_INJECT_ROUND1_SERVER_ZK_PUBLIC_PART2
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:"abcdef":ERR_INJECT_ROUND1_SERVER_ZK_PUBLIC_PART2:PSA_ERROR_DATA_INVALID
+
+PSA PAKE: inject ERR_INJECT_ROUND1_SERVER_ZK_PROOF_PART2
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:"abcdef":ERR_INJECT_ROUND1_SERVER_ZK_PROOF_PART2:PSA_ERROR_DATA_INVALID
+
+PSA PAKE: inject ERR_INJECT_ROUND2_CLIENT_KEY_SHARE
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:"abcdef":ERR_INJECT_ROUND2_CLIENT_KEY_SHARE:PSA_ERROR_DATA_INVALID
+
+PSA PAKE: inject ERR_INJECT_ROUND2_CLIENT_ZK_PUBLIC
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:"abcdef":ERR_INJECT_ROUND2_CLIENT_ZK_PUBLIC:PSA_ERROR_DATA_INVALID
+
+PSA PAKE: inject ERR_INJECT_ROUND2_CLIENT_ZK_PROOF
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:"abcdef":ERR_INJECT_ROUND2_CLIENT_ZK_PROOF:PSA_ERROR_DATA_INVALID
+
+PSA PAKE: inject ERR_INJECT_ROUND2_SERVER_KEY_SHARE
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:"abcdef":ERR_INJECT_ROUND2_SERVER_KEY_SHARE:PSA_ERROR_DATA_INVALID
+
+PSA PAKE: inject ERR_INJECT_ROUND2_SERVER_ZK_PUBLIC
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:"abcdef":ERR_INJECT_ROUND2_SERVER_ZK_PUBLIC:PSA_ERROR_DATA_INVALID
+
+PSA PAKE: inject ERR_INJECT_ROUND2_SERVER_ZK_PROOF
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256:PSA_WANT_ALG_SHA_256
+ecjpake_rounds_inject:PSA_ALG_JPAKE:PSA_PAKE_PRIMITIVE(PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, 256):PSA_ALG_SHA_256:0:"abcdef":ERR_INJECT_ROUND2_SERVER_ZK_PROOF:PSA_ERROR_DATA_INVALID
+
+PSA PAKE: ecjpake size macros
+depends_on:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:PSA_WANT_ECC_SECP_R1_256
+ecjpake_size_macros:
diff --git a/tests/suites/test_suite_psa_crypto_pake.function b/tests/suites/test_suite_psa_crypto_pake.function
new file mode 100644
index 0000000..4f000c1
--- /dev/null
+++ b/tests/suites/test_suite_psa_crypto_pake.function
@@ -0,0 +1,917 @@
+/* BEGIN_HEADER */
+#include <stdint.h>
+
+#include "psa/crypto.h"
+
+typedef enum
+{
+    ERR_NONE = 0,
+    /* errors forced internally in the code */
+    ERR_INJECT_UNINITIALIZED_ACCESS,
+    ERR_INJECT_DUPLICATE_SETUP,
+    ERR_INJECT_INVALID_USER,
+    ERR_INJECT_INVALID_PEER,
+    ERR_INJECT_SET_USER,
+    ERR_INJECT_SET_PEER,
+    ERR_INJECT_EMPTY_IO_BUFFER,
+    ERR_INJECT_UNKNOWN_STEP,
+    ERR_INJECT_INVALID_FIRST_STEP,
+    ERR_INJECT_WRONG_BUFFER_SIZE,
+    ERR_INJECT_VALID_OPERATION_AFTER_FAILURE,
+    ERR_INJECT_ANTICIPATE_KEY_DERIVATION_1,
+    ERR_INJECT_ANTICIPATE_KEY_DERIVATION_2,
+    ERR_INJECT_ROUND1_CLIENT_KEY_SHARE_PART1,
+    ERR_INJECT_ROUND1_CLIENT_ZK_PUBLIC_PART1,
+    ERR_INJECT_ROUND1_CLIENT_ZK_PROOF_PART1,
+    ERR_INJECT_ROUND1_CLIENT_KEY_SHARE_PART2,
+    ERR_INJECT_ROUND1_CLIENT_ZK_PUBLIC_PART2,
+    ERR_INJECT_ROUND1_CLIENT_ZK_PROOF_PART2,
+    ERR_INJECT_ROUND2_CLIENT_KEY_SHARE,
+    ERR_INJECT_ROUND2_CLIENT_ZK_PUBLIC,
+    ERR_INJECT_ROUND2_CLIENT_ZK_PROOF,
+    ERR_INJECT_ROUND1_SERVER_KEY_SHARE_PART1,
+    ERR_INJECT_ROUND1_SERVER_ZK_PUBLIC_PART1,
+    ERR_INJECT_ROUND1_SERVER_ZK_PROOF_PART1,
+    ERR_INJECT_ROUND1_SERVER_KEY_SHARE_PART2,
+    ERR_INJECT_ROUND1_SERVER_ZK_PUBLIC_PART2,
+    ERR_INJECT_ROUND1_SERVER_ZK_PROOF_PART2,
+    ERR_INJECT_ROUND2_SERVER_KEY_SHARE,
+    ERR_INJECT_ROUND2_SERVER_ZK_PUBLIC,
+    ERR_INJECT_ROUND2_SERVER_ZK_PROOF,
+    /* erros issued from the .data file */
+    ERR_IN_SETUP,
+    ERR_IN_SET_ROLE,
+    ERR_IN_SET_PASSWORD_KEY,
+    ERR_IN_INPUT,
+    ERR_IN_OUTPUT,
+} ecjpake_error_stage_t;
+
+typedef enum
+{
+    PAKE_ROUND_ONE,
+    PAKE_ROUND_TWO
+} pake_round_t;
+
+/*
+ * Inject an error on the specified buffer ONLY it this is the correct stage.
+ * Offset 7 is arbitrary, but chosen because it's "in the middle" of the part
+ * we're corrupting.
+ */
+#define DO_ROUND_CONDITIONAL_INJECT( this_stage, buf ) \
+    if ( this_stage == err_stage )                  \
+    {                                               \
+        *( buf + 7) ^= 1;                           \
+    }
+
+#define DO_ROUND_UPDATE_OFFSETS( main_buf_offset, step_offset, step_size ) \
+    {                                       \
+        step_offset = main_buf_offset;      \
+        main_buf_offset += step_size;        \
+    }
+
+#define DO_ROUND_CHECK_FAILURE(  )                                  \
+    if( err_stage != ERR_NONE && status != PSA_SUCCESS )            \
+    {                                                               \
+        TEST_EQUAL( status, expected_error_arg );                   \
+        break;                                                      \
+    }                                                               \
+    else                                                            \
+    {                                                               \
+        TEST_EQUAL( status, PSA_SUCCESS );                          \
+    }
+
+#if defined(PSA_WANT_ALG_JPAKE)
+static void ecjpake_do_round( psa_algorithm_t alg, unsigned int primitive,
+                              psa_pake_operation_t *server,
+                              psa_pake_operation_t *client,
+                              int client_input_first,
+                              pake_round_t round,
+                              ecjpake_error_stage_t err_stage,
+                              int expected_error_arg )
+{
+    unsigned char *buffer0 = NULL, *buffer1 = NULL;
+    size_t buffer_length = (
+        PSA_PAKE_OUTPUT_SIZE(alg, primitive, PSA_PAKE_STEP_KEY_SHARE) +
+        PSA_PAKE_OUTPUT_SIZE(alg, primitive, PSA_PAKE_STEP_ZK_PUBLIC) +
+        PSA_PAKE_OUTPUT_SIZE(alg, primitive, PSA_PAKE_STEP_ZK_PROOF)) * 2;
+    /* The output should be exactly this size according to the spec */
+    const size_t expected_size_key_share =
+        PSA_PAKE_OUTPUT_SIZE(alg, primitive, PSA_PAKE_STEP_KEY_SHARE);
+    /* The output should be exactly this size according to the spec */
+    const size_t expected_size_zk_public =
+        PSA_PAKE_OUTPUT_SIZE(alg, primitive, PSA_PAKE_STEP_ZK_PUBLIC);
+    /* The output can be smaller: the spec allows stripping leading zeroes */
+    const size_t max_expected_size_zk_proof =
+        PSA_PAKE_OUTPUT_SIZE(alg, primitive, PSA_PAKE_STEP_ZK_PROOF);
+    size_t buffer0_off = 0;
+    size_t buffer1_off = 0;
+    size_t s_g1_len, s_g2_len, s_a_len;
+    size_t s_g1_off, s_g2_off, s_a_off;
+    size_t s_x1_pk_len, s_x2_pk_len, s_x2s_pk_len;
+    size_t s_x1_pk_off, s_x2_pk_off, s_x2s_pk_off;
+    size_t s_x1_pr_len, s_x2_pr_len, s_x2s_pr_len;
+    size_t s_x1_pr_off, s_x2_pr_off, s_x2s_pr_off;
+    size_t c_g1_len, c_g2_len, c_a_len;
+    size_t c_g1_off, c_g2_off, c_a_off;
+    size_t c_x1_pk_len, c_x2_pk_len, c_x2s_pk_len;
+    size_t c_x1_pk_off, c_x2_pk_off, c_x2s_pk_off;
+    size_t c_x1_pr_len, c_x2_pr_len, c_x2s_pr_len;
+    size_t c_x1_pr_off, c_x2_pr_off, c_x2s_pr_off;
+    psa_status_t status;
+
+    ASSERT_ALLOC( buffer0, buffer_length );
+    ASSERT_ALLOC( buffer1, buffer_length );
+
+    switch( round )
+    {
+        case PAKE_ROUND_ONE:
+            /* Server first round Output */
+            PSA_ASSERT( psa_pake_output( server, PSA_PAKE_STEP_KEY_SHARE,
+                                         buffer0 + buffer0_off,
+                                         512 - buffer0_off, &s_g1_len ) );
+            TEST_EQUAL( s_g1_len, expected_size_key_share );
+            DO_ROUND_CONDITIONAL_INJECT(
+                                    ERR_INJECT_ROUND1_SERVER_KEY_SHARE_PART1,
+                                    buffer0 + buffer0_off );
+            DO_ROUND_UPDATE_OFFSETS( buffer0_off, s_g1_off, s_g1_len );
+
+            PSA_ASSERT( psa_pake_output( server, PSA_PAKE_STEP_ZK_PUBLIC,
+                                         buffer0 + buffer0_off,
+                                         512 - buffer0_off, &s_x1_pk_len ) );
+            TEST_EQUAL( s_x1_pk_len, expected_size_zk_public );
+            DO_ROUND_CONDITIONAL_INJECT(
+                                    ERR_INJECT_ROUND1_SERVER_ZK_PUBLIC_PART1,
+                                    buffer0 + buffer0_off );
+            DO_ROUND_UPDATE_OFFSETS( buffer0_off, s_x1_pk_off, s_x1_pk_len );
+
+            PSA_ASSERT( psa_pake_output( server, PSA_PAKE_STEP_ZK_PROOF,
+                                         buffer0 + buffer0_off,
+                                         512 - buffer0_off, &s_x1_pr_len ) );
+            TEST_LE_U( s_x1_pr_len, max_expected_size_zk_proof );
+            DO_ROUND_CONDITIONAL_INJECT(
+                                    ERR_INJECT_ROUND1_SERVER_ZK_PROOF_PART1,
+                                    buffer0 + buffer0_off );
+            DO_ROUND_UPDATE_OFFSETS( buffer0_off, s_x1_pr_off, s_x1_pr_len );
+
+            PSA_ASSERT( psa_pake_output( server, PSA_PAKE_STEP_KEY_SHARE,
+                                         buffer0 + buffer0_off,
+                                         512 - buffer0_off, &s_g2_len ) );
+            TEST_EQUAL( s_g2_len, expected_size_key_share );
+            DO_ROUND_CONDITIONAL_INJECT(
+                                    ERR_INJECT_ROUND1_SERVER_KEY_SHARE_PART2,
+                                    buffer0 + buffer0_off );
+            DO_ROUND_UPDATE_OFFSETS( buffer0_off, s_g2_off, s_g2_len );
+
+            PSA_ASSERT( psa_pake_output( server, PSA_PAKE_STEP_ZK_PUBLIC,
+                                         buffer0 + buffer0_off,
+                                         512 - buffer0_off, &s_x2_pk_len ) );
+            TEST_EQUAL( s_x2_pk_len, expected_size_zk_public );
+            DO_ROUND_CONDITIONAL_INJECT(
+                                    ERR_INJECT_ROUND1_SERVER_ZK_PUBLIC_PART2,
+                                    buffer0 + buffer0_off );
+            DO_ROUND_UPDATE_OFFSETS( buffer0_off, s_x2_pk_off, s_x2_pk_len );
+
+            PSA_ASSERT( psa_pake_output( server, PSA_PAKE_STEP_ZK_PROOF,
+                                         buffer0 + buffer0_off,
+                                         512 - buffer0_off, &s_x2_pr_len ) );
+            TEST_LE_U( s_x2_pr_len, max_expected_size_zk_proof );
+            DO_ROUND_CONDITIONAL_INJECT(
+                                    ERR_INJECT_ROUND1_SERVER_ZK_PROOF_PART2,
+                                    buffer0 + buffer0_off );
+            DO_ROUND_UPDATE_OFFSETS( buffer0_off, s_x2_pr_off, s_x2_pr_len );
+
+            /*
+             * When injecting errors in inputs, the implementation is
+             * free to detect it right away of with a delay.
+             * This permits delaying the error until the end of the input
+             * sequence, if no error appears then, this will be treated
+             * as an error.
+             */
+            if( client_input_first == 1 )
+            {
+                /* Client first round Input */
+                status = psa_pake_input( client, PSA_PAKE_STEP_KEY_SHARE,
+                                         buffer0 + s_g1_off, s_g1_len );
+                DO_ROUND_CHECK_FAILURE(  );
+
+                status = psa_pake_input( client, PSA_PAKE_STEP_ZK_PUBLIC,
+                                         buffer0 + s_x1_pk_off,
+                                         s_x1_pk_len );
+                DO_ROUND_CHECK_FAILURE(  );
+
+                status = psa_pake_input( client, PSA_PAKE_STEP_ZK_PROOF,
+                                         buffer0 + s_x1_pr_off,
+                                         s_x1_pr_len );
+                DO_ROUND_CHECK_FAILURE(  );
+
+                status = psa_pake_input( client, PSA_PAKE_STEP_KEY_SHARE,
+                                         buffer0 + s_g2_off,
+                                         s_g2_len );
+                DO_ROUND_CHECK_FAILURE(  );
+
+                status = psa_pake_input( client, PSA_PAKE_STEP_ZK_PUBLIC,
+                                         buffer0 + s_x2_pk_off,
+                                         s_x2_pk_len );
+                DO_ROUND_CHECK_FAILURE(  );
+
+                status = psa_pake_input( client, PSA_PAKE_STEP_ZK_PROOF,
+                                         buffer0 + s_x2_pr_off,
+                                         s_x2_pr_len );
+                DO_ROUND_CHECK_FAILURE(  );
+
+                /* Error didn't trigger, make test fail */
+                if( ( err_stage >= ERR_INJECT_ROUND1_SERVER_KEY_SHARE_PART1 ) &&
+                    ( err_stage <= ERR_INJECT_ROUND1_SERVER_ZK_PROOF_PART2 ) )
+                {
+                    TEST_ASSERT( ! "One of the last psa_pake_input() calls should have returned the expected error." );
+                }
+            }
+
+            /* Client first round Output */
+            PSA_ASSERT( psa_pake_output( client, PSA_PAKE_STEP_KEY_SHARE,
+                                         buffer1 + buffer1_off,
+                                         512 - buffer1_off, &c_g1_len ) );
+            TEST_EQUAL( c_g1_len, expected_size_key_share );
+            DO_ROUND_CONDITIONAL_INJECT(
+                                    ERR_INJECT_ROUND1_CLIENT_KEY_SHARE_PART1,
+                                    buffer1 + buffer1_off );
+            DO_ROUND_UPDATE_OFFSETS( buffer1_off, c_g1_off, c_g1_len );
+
+            PSA_ASSERT( psa_pake_output( client, PSA_PAKE_STEP_ZK_PUBLIC,
+                                         buffer1 + buffer1_off,
+                                         512 - buffer1_off, &c_x1_pk_len ) );
+            TEST_EQUAL( c_x1_pk_len, expected_size_zk_public );
+            DO_ROUND_CONDITIONAL_INJECT(
+                                    ERR_INJECT_ROUND1_CLIENT_ZK_PUBLIC_PART1,
+                                    buffer1 + buffer1_off );
+            DO_ROUND_UPDATE_OFFSETS( buffer1_off, c_x1_pk_off, c_x1_pk_len );
+
+            PSA_ASSERT( psa_pake_output( client, PSA_PAKE_STEP_ZK_PROOF,
+                                         buffer1 + buffer1_off,
+                                         512 - buffer1_off, &c_x1_pr_len ) );
+            TEST_LE_U( c_x1_pr_len, max_expected_size_zk_proof );
+            DO_ROUND_CONDITIONAL_INJECT(
+                                    ERR_INJECT_ROUND1_CLIENT_ZK_PROOF_PART1,
+                                    buffer1 + buffer1_off );
+            DO_ROUND_UPDATE_OFFSETS( buffer1_off, c_x1_pr_off, c_x1_pr_len );
+
+            PSA_ASSERT( psa_pake_output( client, PSA_PAKE_STEP_KEY_SHARE,
+                                         buffer1 + buffer1_off,
+                                         512 - buffer1_off, &c_g2_len ) );
+            TEST_EQUAL( c_g2_len, expected_size_key_share );
+            DO_ROUND_CONDITIONAL_INJECT(
+                                    ERR_INJECT_ROUND1_CLIENT_KEY_SHARE_PART2,
+                                    buffer1 + buffer1_off );
+            DO_ROUND_UPDATE_OFFSETS( buffer1_off, c_g2_off, c_g2_len );
+
+            PSA_ASSERT( psa_pake_output( client, PSA_PAKE_STEP_ZK_PUBLIC,
+                                         buffer1 + buffer1_off,
+                                         512 - buffer1_off, &c_x2_pk_len ) );
+            TEST_EQUAL( c_x2_pk_len, expected_size_zk_public );
+            DO_ROUND_CONDITIONAL_INJECT(
+                                    ERR_INJECT_ROUND1_CLIENT_ZK_PUBLIC_PART2,
+                                    buffer1 + buffer1_off );
+            DO_ROUND_UPDATE_OFFSETS( buffer1_off, c_x2_pk_off, c_x2_pk_len );
+
+            PSA_ASSERT( psa_pake_output( client, PSA_PAKE_STEP_ZK_PROOF,
+                                         buffer1 + buffer1_off,
+                                         512 - buffer1_off, &c_x2_pr_len ) );
+            TEST_LE_U( c_x2_pr_len, max_expected_size_zk_proof );
+            DO_ROUND_CONDITIONAL_INJECT(
+                                    ERR_INJECT_ROUND1_CLIENT_ZK_PROOF_PART2,
+                                    buffer1 + buffer1_off );
+            DO_ROUND_UPDATE_OFFSETS( buffer1_off, c_x2_pr_off, buffer1_off );
+
+            if( client_input_first == 0 )
+            {
+                /* Client first round Input */
+                status = psa_pake_input( client, PSA_PAKE_STEP_KEY_SHARE,
+                                         buffer0 + s_g1_off, s_g1_len );
+                DO_ROUND_CHECK_FAILURE(  );
+
+                status = psa_pake_input( client, PSA_PAKE_STEP_ZK_PUBLIC,
+                                         buffer0 + s_x1_pk_off,
+                                         s_x1_pk_len );
+                DO_ROUND_CHECK_FAILURE(  );
+
+                status = psa_pake_input( client, PSA_PAKE_STEP_ZK_PROOF,
+                                         buffer0 + s_x1_pr_off,
+                                         s_x1_pr_len );
+                DO_ROUND_CHECK_FAILURE(  );
+
+                status = psa_pake_input( client, PSA_PAKE_STEP_KEY_SHARE,
+                                         buffer0 + s_g2_off,
+                                         s_g2_len );
+                DO_ROUND_CHECK_FAILURE(  );
+
+                status = psa_pake_input( client, PSA_PAKE_STEP_ZK_PUBLIC,
+                                         buffer0 + s_x2_pk_off,
+                                         s_x2_pk_len );
+                DO_ROUND_CHECK_FAILURE(  );
+
+                status = psa_pake_input( client, PSA_PAKE_STEP_ZK_PROOF,
+                                         buffer0 + s_x2_pr_off,
+                                         s_x2_pr_len );
+                DO_ROUND_CHECK_FAILURE(  );
+
+                /* Error didn't trigger, make test fail */
+                if( ( err_stage >= ERR_INJECT_ROUND1_SERVER_KEY_SHARE_PART1 ) &&
+                    ( err_stage <= ERR_INJECT_ROUND1_SERVER_ZK_PROOF_PART2 ) )
+                {
+                    TEST_ASSERT( ! "One of the last psa_pake_input() calls should have returned the expected error." );
+                }
+            }
+
+            /* Server first round Input */
+            status = psa_pake_input( server, PSA_PAKE_STEP_KEY_SHARE,
+                                     buffer1 + c_g1_off, c_g1_len );
+            DO_ROUND_CHECK_FAILURE(  );
+
+            status = psa_pake_input( server, PSA_PAKE_STEP_ZK_PUBLIC,
+                                     buffer1 + c_x1_pk_off, c_x1_pk_len );
+            DO_ROUND_CHECK_FAILURE(  );
+
+            status = psa_pake_input( server, PSA_PAKE_STEP_ZK_PROOF,
+                                     buffer1 + c_x1_pr_off, c_x1_pr_len );
+            DO_ROUND_CHECK_FAILURE(  );
+
+            status = psa_pake_input( server, PSA_PAKE_STEP_KEY_SHARE,
+                                     buffer1 + c_g2_off, c_g2_len );
+            DO_ROUND_CHECK_FAILURE(  );
+
+            status = psa_pake_input( server, PSA_PAKE_STEP_ZK_PUBLIC,
+                                     buffer1 + c_x2_pk_off, c_x2_pk_len );
+            DO_ROUND_CHECK_FAILURE(  );
+
+            status = psa_pake_input( server, PSA_PAKE_STEP_ZK_PROOF,
+                                     buffer1 + c_x2_pr_off, c_x2_pr_len );
+            DO_ROUND_CHECK_FAILURE(  );
+
+            /* Error didn't trigger, make test fail */
+            if( ( err_stage >= ERR_INJECT_ROUND1_CLIENT_KEY_SHARE_PART1 ) &&
+                ( err_stage <= ERR_INJECT_ROUND1_CLIENT_ZK_PROOF_PART2 ) )
+            {
+                TEST_ASSERT( ! "One of the last psa_pake_input() calls should have returned the expected error." );
+            }
+
+            break;
+
+        case PAKE_ROUND_TWO:
+            /* Server second round Output */
+            buffer0_off = 0;
+
+            PSA_ASSERT( psa_pake_output( server, PSA_PAKE_STEP_KEY_SHARE,
+                                         buffer0 + buffer0_off,
+                                         512 - buffer0_off, &s_a_len ) );
+            TEST_EQUAL( s_a_len, expected_size_key_share );
+            DO_ROUND_CONDITIONAL_INJECT(
+                                    ERR_INJECT_ROUND2_SERVER_KEY_SHARE,
+                                    buffer0 + buffer0_off );
+            DO_ROUND_UPDATE_OFFSETS( buffer0_off, s_a_off, s_a_len );
+
+            PSA_ASSERT( psa_pake_output( server, PSA_PAKE_STEP_ZK_PUBLIC,
+                                         buffer0 + buffer0_off,
+                                         512 - buffer0_off, &s_x2s_pk_len ) );
+            TEST_EQUAL( s_x2s_pk_len, expected_size_zk_public );
+            DO_ROUND_CONDITIONAL_INJECT(
+                                    ERR_INJECT_ROUND2_SERVER_ZK_PUBLIC,
+                                    buffer0 + buffer0_off );
+            DO_ROUND_UPDATE_OFFSETS( buffer0_off, s_x2s_pk_off, s_x2s_pk_len );
+
+            PSA_ASSERT( psa_pake_output( server, PSA_PAKE_STEP_ZK_PROOF,
+                                         buffer0 + buffer0_off,
+                                         512 - buffer0_off, &s_x2s_pr_len ) );
+            TEST_LE_U( s_x2s_pr_len, max_expected_size_zk_proof );
+            DO_ROUND_CONDITIONAL_INJECT(
+                                    ERR_INJECT_ROUND2_SERVER_ZK_PROOF,
+                                    buffer0 + buffer0_off );
+            DO_ROUND_UPDATE_OFFSETS( buffer0_off, s_x2s_pr_off, s_x2s_pr_len );
+
+            if( client_input_first == 1 )
+            {
+                /* Client second round Input */
+                status = psa_pake_input( client, PSA_PAKE_STEP_KEY_SHARE,
+                                         buffer0 + s_a_off, s_a_len );
+                DO_ROUND_CHECK_FAILURE(  );
+
+                status = psa_pake_input( client, PSA_PAKE_STEP_ZK_PUBLIC,
+                                         buffer0 + s_x2s_pk_off,
+                                         s_x2s_pk_len );
+                DO_ROUND_CHECK_FAILURE(  );
+
+                status = psa_pake_input( client, PSA_PAKE_STEP_ZK_PROOF,
+                                         buffer0 + s_x2s_pr_off,
+                                         s_x2s_pr_len );
+                DO_ROUND_CHECK_FAILURE(  );
+
+                /* Error didn't trigger, make test fail */
+                if( ( err_stage >= ERR_INJECT_ROUND2_SERVER_KEY_SHARE ) &&
+                    ( err_stage <= ERR_INJECT_ROUND2_SERVER_ZK_PROOF ) )
+                {
+                    TEST_ASSERT( ! "One of the last psa_pake_input() calls should have returned the expected error." );
+                }
+            }
+
+            /* Client second round Output */
+            buffer1_off = 0;
+
+            PSA_ASSERT( psa_pake_output( client, PSA_PAKE_STEP_KEY_SHARE,
+                                         buffer1 + buffer1_off,
+                                         512 - buffer1_off, &c_a_len ) );
+            TEST_EQUAL( c_a_len, expected_size_key_share );
+            DO_ROUND_CONDITIONAL_INJECT(
+                                    ERR_INJECT_ROUND2_CLIENT_KEY_SHARE,
+                                    buffer1 + buffer1_off );
+            DO_ROUND_UPDATE_OFFSETS( buffer1_off, c_a_off, c_a_len );
+
+            PSA_ASSERT( psa_pake_output( client, PSA_PAKE_STEP_ZK_PUBLIC,
+                                         buffer1 + buffer1_off,
+                                         512 - buffer1_off, &c_x2s_pk_len ) );
+            TEST_EQUAL( c_x2s_pk_len, expected_size_zk_public );
+            DO_ROUND_CONDITIONAL_INJECT(
+                                    ERR_INJECT_ROUND2_CLIENT_ZK_PUBLIC,
+                                    buffer1 + buffer1_off );
+            DO_ROUND_UPDATE_OFFSETS( buffer1_off, c_x2s_pk_off, c_x2s_pk_len );
+
+            PSA_ASSERT( psa_pake_output( client, PSA_PAKE_STEP_ZK_PROOF,
+                                         buffer1 + buffer1_off,
+                                         512 - buffer1_off, &c_x2s_pr_len ) );
+            TEST_LE_U( c_x2s_pr_len, max_expected_size_zk_proof );
+            DO_ROUND_CONDITIONAL_INJECT(
+                                    ERR_INJECT_ROUND2_CLIENT_ZK_PROOF,
+                                    buffer1 + buffer1_off );
+            DO_ROUND_UPDATE_OFFSETS( buffer1_off, c_x2s_pr_off, c_x2s_pr_len );
+
+            if( client_input_first == 0 )
+            {
+                /* Client second round Input */
+                status = psa_pake_input( client, PSA_PAKE_STEP_KEY_SHARE,
+                                         buffer0 + s_a_off, s_a_len );
+                DO_ROUND_CHECK_FAILURE(  );
+
+                status = psa_pake_input( client, PSA_PAKE_STEP_ZK_PUBLIC,
+                                         buffer0 + s_x2s_pk_off,
+                                         s_x2s_pk_len );
+                DO_ROUND_CHECK_FAILURE(  );
+
+                status = psa_pake_input( client, PSA_PAKE_STEP_ZK_PROOF,
+                                         buffer0 + s_x2s_pr_off,
+                                         s_x2s_pr_len );
+                DO_ROUND_CHECK_FAILURE(  );
+
+                /* Error didn't trigger, make test fail */
+                if( ( err_stage >= ERR_INJECT_ROUND2_SERVER_KEY_SHARE ) &&
+                    ( err_stage <= ERR_INJECT_ROUND2_SERVER_ZK_PROOF ) )
+                {
+                    TEST_ASSERT( ! "One of the last psa_pake_input() calls should have returned the expected error." );
+                }
+            }
+
+            /* Server second round Input */
+            status = psa_pake_input( server, PSA_PAKE_STEP_KEY_SHARE,
+                                     buffer1 + c_a_off, c_a_len );
+            DO_ROUND_CHECK_FAILURE(  );
+
+            status = psa_pake_input( server, PSA_PAKE_STEP_ZK_PUBLIC,
+                                     buffer1 + c_x2s_pk_off, c_x2s_pk_len );
+            DO_ROUND_CHECK_FAILURE(  );
+
+            status = psa_pake_input( server, PSA_PAKE_STEP_ZK_PROOF,
+                                     buffer1 + c_x2s_pr_off, c_x2s_pr_len );
+            DO_ROUND_CHECK_FAILURE(  );
+
+            /* Error didn't trigger, make test fail */
+            if( ( err_stage >= ERR_INJECT_ROUND2_CLIENT_KEY_SHARE ) &&
+                ( err_stage <= ERR_INJECT_ROUND2_CLIENT_ZK_PROOF ) )
+            {
+                TEST_ASSERT( ! "One of the last psa_pake_input() calls should have returned the expected error." );
+            }
+
+            break;
+
+    }
+
+exit:
+    mbedtls_free( buffer0 );
+    mbedtls_free( buffer1 );
+}
+#endif /* PSA_WANT_ALG_JPAKE */
+
+/*
+ * This check is used for functions that might either succeed or fail depending
+ * on the parameters that are passed in from the *.data file:
+ * - in case of success following functions depend on the current one
+ * - in case of failure the test is always terminated. There are two options
+ *   here
+ *     - terminated successfully if this exact error was expected at this stage
+ *     - terminated with failure otherwise (either no error was expected at this
+ *       stage or a different error code was expected)
+ */
+#define SETUP_ALWAYS_CHECK_STEP( test_function, this_check_err_stage )      \
+    status = test_function;                                                 \
+    if( err_stage != this_check_err_stage )                                 \
+    {                                                                       \
+        PSA_ASSERT( status );                                               \
+    }                                                                       \
+    else                                                                    \
+    {                                                                       \
+        TEST_EQUAL( status, expected_error );                               \
+        goto exit;                                                          \
+    }
+
+/*
+ * This check is used for failures that are injected at code level. There's only
+ * 1 input parameter that is relevant in this case and it's the stage at which
+ * the error should be injected.
+ * The check is conditional in this case because, once the error is triggered,
+ * the pake's context structure is compromised and the setup function cannot
+ * proceed further. As a consequence the test is terminated.
+ * The test succeeds if the returned error is exactly the expected one,
+ * otherwise it fails.
+ */
+#define SETUP_CONDITIONAL_CHECK_STEP( test_function, this_check_err_stage ) \
+    if( err_stage == this_check_err_stage )                                 \
+    {                                                                       \
+        TEST_EQUAL( test_function, expected_error );                        \
+        goto exit;                                                          \
+    }
+/* END_HEADER */
+
+/* BEGIN_DEPENDENCIES
+ * depends_on:MBEDTLS_PSA_CRYPTO_C
+ * END_DEPENDENCIES
+ */
+
+/* BEGIN_CASE depends_on:PSA_WANT_ALG_JPAKE */
+void ecjpake_setup( int alg_arg, int key_type_pw_arg, int key_usage_pw_arg,
+                    int primitive_arg, int hash_arg, int role_arg,
+                    int test_input,
+                    int err_stage_arg,
+                    int expected_error_arg)
+{
+    psa_pake_cipher_suite_t cipher_suite = psa_pake_cipher_suite_init();
+    psa_pake_operation_t operation = psa_pake_operation_init();
+    psa_algorithm_t alg = alg_arg;
+    psa_pake_primitive_t primitive = primitive_arg;
+    psa_key_type_t key_type_pw = key_type_pw_arg;
+    psa_key_usage_t key_usage_pw = key_usage_pw_arg;
+    psa_algorithm_t hash_alg = hash_arg;
+    psa_pake_role_t role = role_arg;
+    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    ecjpake_error_stage_t err_stage = err_stage_arg;
+    psa_status_t expected_error = expected_error_arg;
+    psa_status_t status;
+    unsigned char *output_buffer = NULL;
+    size_t output_len = 0;
+    const uint8_t unsupp_id[] = "abcd";
+    const uint8_t password[] = "abcd";
+    psa_key_derivation_operation_t key_derivation =
+                            PSA_KEY_DERIVATION_OPERATION_INIT;
+
+    PSA_INIT( );
+
+    size_t buf_size = PSA_PAKE_OUTPUT_SIZE( alg, primitive_arg,
+                                       PSA_PAKE_STEP_KEY_SHARE );
+    ASSERT_ALLOC( output_buffer, buf_size );
+
+    psa_set_key_usage_flags( &attributes, key_usage_pw );
+    psa_set_key_algorithm( &attributes, alg );
+    psa_set_key_type( &attributes, key_type_pw );
+    PSA_ASSERT( psa_import_key( &attributes, password, sizeof( password ),
+                &key ) );
+
+    psa_pake_cs_set_algorithm( &cipher_suite, alg );
+    psa_pake_cs_set_primitive( &cipher_suite, primitive );
+    psa_pake_cs_set_hash( &cipher_suite, hash_alg );
+
+    PSA_ASSERT( psa_pake_abort( &operation ) );
+
+    if ( err_stage == ERR_INJECT_UNINITIALIZED_ACCESS )
+    {
+        TEST_EQUAL( psa_pake_set_user( &operation, NULL, 0 ),
+                    expected_error );
+        TEST_EQUAL( psa_pake_set_peer( &operation, NULL, 0 ),
+                    expected_error );
+        TEST_EQUAL( psa_pake_set_password_key( &operation, key ),
+                    expected_error );
+        TEST_EQUAL( psa_pake_set_role( &operation, role ),
+                    expected_error );
+        TEST_EQUAL( psa_pake_output( &operation, PSA_PAKE_STEP_KEY_SHARE,
+                    NULL, 0, NULL ),
+                    expected_error );
+        TEST_EQUAL( psa_pake_input( &operation, PSA_PAKE_STEP_KEY_SHARE,
+                    NULL, 0 ),
+                    expected_error );
+        TEST_EQUAL( psa_pake_get_implicit_key( &operation, &key_derivation ),
+                    expected_error );
+        goto exit;
+    }
+
+    SETUP_ALWAYS_CHECK_STEP( psa_pake_setup( &operation, &cipher_suite ),
+                            ERR_IN_SETUP );
+
+    SETUP_CONDITIONAL_CHECK_STEP( psa_pake_setup( &operation, &cipher_suite ),
+                                    ERR_INJECT_DUPLICATE_SETUP);
+
+    SETUP_ALWAYS_CHECK_STEP( psa_pake_set_role( &operation, role),
+                                ERR_IN_SET_ROLE );
+
+    SETUP_ALWAYS_CHECK_STEP( psa_pake_set_password_key( &operation, key ),
+                                ERR_IN_SET_PASSWORD_KEY );
+
+    SETUP_CONDITIONAL_CHECK_STEP( psa_pake_set_user( &operation, NULL, 0 ),
+                                    ERR_INJECT_INVALID_USER );
+
+    SETUP_CONDITIONAL_CHECK_STEP( psa_pake_set_peer( &operation, NULL, 0 ),
+                                    ERR_INJECT_INVALID_PEER );
+
+    SETUP_CONDITIONAL_CHECK_STEP( psa_pake_set_user( &operation, unsupp_id, 4 ),
+                                    ERR_INJECT_SET_USER );
+
+    SETUP_CONDITIONAL_CHECK_STEP( psa_pake_set_peer( &operation, unsupp_id, 4 ),
+                                    ERR_INJECT_SET_PEER );
+
+    const size_t size_key_share = PSA_PAKE_INPUT_SIZE( alg, primitive,
+                                                PSA_PAKE_STEP_KEY_SHARE );
+    const size_t size_zk_public = PSA_PAKE_INPUT_SIZE( alg, primitive,
+                                                PSA_PAKE_STEP_ZK_PUBLIC );
+    const size_t size_zk_proof = PSA_PAKE_INPUT_SIZE( alg, primitive,
+                                                PSA_PAKE_STEP_ZK_PROOF );
+
+    if ( test_input )
+    {
+        SETUP_CONDITIONAL_CHECK_STEP( psa_pake_input( &operation,
+                                        PSA_PAKE_STEP_ZK_PROOF,  NULL, 0 ),
+                                        ERR_INJECT_EMPTY_IO_BUFFER );
+
+        SETUP_CONDITIONAL_CHECK_STEP( psa_pake_input( &operation,
+                                        PSA_PAKE_STEP_ZK_PROOF + 10,
+                                        output_buffer, size_zk_proof ),
+                                        ERR_INJECT_UNKNOWN_STEP );
+
+        SETUP_CONDITIONAL_CHECK_STEP( psa_pake_input( &operation,
+                                        PSA_PAKE_STEP_ZK_PROOF,
+                                        output_buffer, size_zk_proof ),
+                                        ERR_INJECT_INVALID_FIRST_STEP )
+
+        SETUP_ALWAYS_CHECK_STEP( psa_pake_input( &operation,
+                                    PSA_PAKE_STEP_KEY_SHARE,
+                                    output_buffer, size_key_share ),
+                                    ERR_IN_INPUT );
+
+        SETUP_CONDITIONAL_CHECK_STEP( psa_pake_input( &operation,
+                                        PSA_PAKE_STEP_ZK_PUBLIC,
+                                        output_buffer, size_zk_public + 1 ),
+                                        ERR_INJECT_WRONG_BUFFER_SIZE );
+
+        SETUP_CONDITIONAL_CHECK_STEP(
+                  ( psa_pake_input( &operation, PSA_PAKE_STEP_ZK_PUBLIC,
+                                        output_buffer, size_zk_public + 1 ),
+                    psa_pake_input( &operation, PSA_PAKE_STEP_ZK_PUBLIC,
+                                        output_buffer, size_zk_public ) ),
+                    ERR_INJECT_VALID_OPERATION_AFTER_FAILURE );
+    } else {
+        SETUP_CONDITIONAL_CHECK_STEP( psa_pake_output( &operation,
+                                        PSA_PAKE_STEP_ZK_PROOF,
+                                        NULL, 0, NULL ),
+                                        ERR_INJECT_EMPTY_IO_BUFFER );
+
+        SETUP_CONDITIONAL_CHECK_STEP( psa_pake_output( &operation,
+                                        PSA_PAKE_STEP_ZK_PROOF + 10,
+                                        output_buffer, buf_size, &output_len ),
+                                        ERR_INJECT_UNKNOWN_STEP );
+
+        SETUP_CONDITIONAL_CHECK_STEP( psa_pake_output( &operation,
+                                        PSA_PAKE_STEP_ZK_PROOF,
+                                        output_buffer, buf_size, &output_len ),
+                                        ERR_INJECT_INVALID_FIRST_STEP );
+
+        SETUP_ALWAYS_CHECK_STEP( psa_pake_output( &operation,
+                                    PSA_PAKE_STEP_KEY_SHARE,
+                                    output_buffer, buf_size, &output_len ),
+                                    ERR_IN_OUTPUT );
+
+        TEST_ASSERT( output_len > 0 );
+
+        SETUP_CONDITIONAL_CHECK_STEP( psa_pake_output( &operation,
+                                        PSA_PAKE_STEP_ZK_PUBLIC,
+                                        output_buffer, size_zk_public - 1,
+                                        &output_len ),
+                                        ERR_INJECT_WRONG_BUFFER_SIZE );
+
+        SETUP_CONDITIONAL_CHECK_STEP(
+              ( psa_pake_output( &operation, PSA_PAKE_STEP_ZK_PUBLIC,
+                        output_buffer, size_zk_public - 1, &output_len ),
+                psa_pake_output( &operation, PSA_PAKE_STEP_ZK_PUBLIC,
+                                        output_buffer, buf_size, &output_len ) ),
+                ERR_INJECT_VALID_OPERATION_AFTER_FAILURE );
+    }
+
+exit:
+    PSA_ASSERT( psa_destroy_key( key ) );
+    PSA_ASSERT( psa_pake_abort( &operation ) );
+    mbedtls_free( output_buffer );
+    PSA_DONE( );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:PSA_WANT_ALG_JPAKE */
+void ecjpake_rounds_inject( int alg_arg, int primitive_arg, int hash_arg,
+                            int client_input_first,
+                            data_t *pw_data,
+                            int err_stage_arg,
+                            int expected_error_arg )
+{
+    psa_pake_cipher_suite_t cipher_suite = psa_pake_cipher_suite_init();
+    psa_pake_operation_t server = psa_pake_operation_init();
+    psa_pake_operation_t client = psa_pake_operation_init();
+    psa_algorithm_t alg = alg_arg;
+    psa_algorithm_t hash_alg = hash_arg;
+    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    ecjpake_error_stage_t err_stage = err_stage_arg;
+
+    PSA_INIT( );
+
+    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DERIVE );
+    psa_set_key_algorithm( &attributes, alg );
+    psa_set_key_type( &attributes, PSA_KEY_TYPE_PASSWORD );
+    PSA_ASSERT( psa_import_key( &attributes, pw_data->x, pw_data->len,
+                &key ) );
+
+    psa_pake_cs_set_algorithm( &cipher_suite, alg );
+    psa_pake_cs_set_primitive( &cipher_suite, primitive_arg );
+    psa_pake_cs_set_hash( &cipher_suite, hash_alg );
+
+    PSA_ASSERT( psa_pake_setup( &server, &cipher_suite ) );
+    PSA_ASSERT( psa_pake_setup( &client, &cipher_suite ) );
+
+    PSA_ASSERT( psa_pake_set_role( &server, PSA_PAKE_ROLE_SERVER ) );
+    PSA_ASSERT( psa_pake_set_role( &client, PSA_PAKE_ROLE_CLIENT ) );
+
+    PSA_ASSERT( psa_pake_set_password_key( &server, key ) );
+    PSA_ASSERT( psa_pake_set_password_key( &client, key ) );
+
+    ecjpake_do_round( alg, primitive_arg, &server, &client,
+                      client_input_first, PAKE_ROUND_ONE,
+                      err_stage, expected_error_arg );
+
+    if( err_stage != ERR_NONE )
+        goto exit;
+
+    ecjpake_do_round( alg, primitive_arg, &server, &client,
+                      client_input_first, PAKE_ROUND_TWO,
+                      err_stage, expected_error_arg );
+
+exit:
+    psa_destroy_key( key );
+    psa_pake_abort( &server );
+    psa_pake_abort( &client );
+    PSA_DONE( );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:PSA_WANT_ALG_JPAKE */
+void ecjpake_rounds( int alg_arg, int primitive_arg, int hash_arg,
+                     int derive_alg_arg, data_t *pw_data,
+                     int client_input_first, int destroy_key,
+                     int err_stage_arg )
+{
+    psa_pake_cipher_suite_t cipher_suite = psa_pake_cipher_suite_init();
+    psa_pake_operation_t server = psa_pake_operation_init();
+    psa_pake_operation_t client = psa_pake_operation_init();
+    psa_algorithm_t alg = alg_arg;
+    psa_algorithm_t hash_alg = hash_arg;
+    psa_algorithm_t derive_alg = derive_alg_arg;
+    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
+    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+    psa_key_derivation_operation_t server_derive =
+                            PSA_KEY_DERIVATION_OPERATION_INIT;
+    psa_key_derivation_operation_t client_derive =
+                            PSA_KEY_DERIVATION_OPERATION_INIT;
+    ecjpake_error_stage_t err_stage = err_stage_arg;
+
+    PSA_INIT( );
+
+    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DERIVE );
+    psa_set_key_algorithm( &attributes, alg );
+    psa_set_key_type( &attributes, PSA_KEY_TYPE_PASSWORD );
+    PSA_ASSERT( psa_import_key( &attributes, pw_data->x, pw_data->len,
+                &key ) );
+
+    psa_pake_cs_set_algorithm( &cipher_suite, alg );
+    psa_pake_cs_set_primitive( &cipher_suite, primitive_arg );
+    psa_pake_cs_set_hash( &cipher_suite, hash_alg );
+
+    /* Get shared key */
+    PSA_ASSERT( psa_key_derivation_setup( &server_derive, derive_alg ) );
+    PSA_ASSERT( psa_key_derivation_setup( &client_derive, derive_alg ) );
+
+    if( PSA_ALG_IS_TLS12_PRF( derive_alg ) ||
+        PSA_ALG_IS_TLS12_PSK_TO_MS( derive_alg ) )
+    {
+        PSA_ASSERT( psa_key_derivation_input_bytes( &server_derive,
+                                                PSA_KEY_DERIVATION_INPUT_SEED,
+                                                (const uint8_t*) "", 0) );
+        PSA_ASSERT( psa_key_derivation_input_bytes( &client_derive,
+                                                PSA_KEY_DERIVATION_INPUT_SEED,
+                                                (const uint8_t*) "", 0) );
+    }
+
+    PSA_ASSERT( psa_pake_setup( &server, &cipher_suite ) );
+    PSA_ASSERT( psa_pake_setup( &client, &cipher_suite ) );
+
+    PSA_ASSERT( psa_pake_set_role( &server, PSA_PAKE_ROLE_SERVER ) );
+    PSA_ASSERT( psa_pake_set_role( &client, PSA_PAKE_ROLE_CLIENT ) );
+
+    PSA_ASSERT( psa_pake_set_password_key( &server, key ) );
+    PSA_ASSERT( psa_pake_set_password_key( &client, key ) );
+
+    if( destroy_key == 1 )
+        psa_destroy_key( key );
+
+    if( err_stage == ERR_INJECT_ANTICIPATE_KEY_DERIVATION_1 )
+    {
+        TEST_EQUAL( psa_pake_get_implicit_key( &server, &server_derive ),
+                PSA_ERROR_BAD_STATE );
+        TEST_EQUAL( psa_pake_get_implicit_key( &client, &client_derive ),
+                PSA_ERROR_BAD_STATE );
+        goto exit;
+    }
+
+    /* First round */
+    ecjpake_do_round( alg, primitive_arg, &server, &client,
+                      client_input_first, PAKE_ROUND_ONE,
+                      ERR_NONE, PSA_SUCCESS );
+
+    if ( err_stage == ERR_INJECT_ANTICIPATE_KEY_DERIVATION_2 )
+    {
+        TEST_EQUAL( psa_pake_get_implicit_key( &server, &server_derive ),
+                PSA_ERROR_BAD_STATE );
+        TEST_EQUAL( psa_pake_get_implicit_key( &client, &client_derive ),
+                PSA_ERROR_BAD_STATE );
+        goto exit;
+    }
+
+    /* Second round */
+    ecjpake_do_round( alg, primitive_arg, &server, &client,
+                      client_input_first, PAKE_ROUND_TWO,
+                      ERR_NONE, PSA_SUCCESS );
+
+    PSA_ASSERT( psa_pake_get_implicit_key( &server, &server_derive ) );
+    PSA_ASSERT( psa_pake_get_implicit_key( &client, &client_derive ) );
+
+exit:
+    psa_key_derivation_abort( &server_derive );
+    psa_key_derivation_abort( &client_derive );
+    psa_destroy_key( key );
+    psa_pake_abort( &server );
+    psa_pake_abort( &client );
+    PSA_DONE( );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void ecjpake_size_macros( )
+{
+    const psa_algorithm_t alg = PSA_ALG_JPAKE;
+    const size_t bits = 256;
+    const psa_pake_primitive_t prim = PSA_PAKE_PRIMITIVE(
+            PSA_PAKE_PRIMITIVE_TYPE_ECC, PSA_ECC_FAMILY_SECP_R1, bits );
+    const psa_key_type_t key_type = PSA_KEY_TYPE_ECC_KEY_PAIR(
+            PSA_ECC_FAMILY_SECP_R1 );
+
+    // https://armmbed.github.io/mbed-crypto/1.1_PAKE_Extension.0-bet.0/html/pake.html#pake-step-types
+    /* The output for KEY_SHARE and ZK_PUBLIC is the same as a public key */
+    TEST_EQUAL( PSA_PAKE_OUTPUT_SIZE(alg, prim, PSA_PAKE_STEP_KEY_SHARE),
+                PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE( key_type, bits ) );
+    TEST_EQUAL( PSA_PAKE_OUTPUT_SIZE(alg, prim, PSA_PAKE_STEP_ZK_PUBLIC),
+                PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE( key_type, bits ) );
+    /* The output for ZK_PROOF is the same bitsize as the curve */
+    TEST_EQUAL( PSA_PAKE_OUTPUT_SIZE(alg, prim, PSA_PAKE_STEP_ZK_PROOF),
+                PSA_BITS_TO_BYTES( bits ) );
+
+    /* Input sizes are the same as output sizes */
+    TEST_EQUAL( PSA_PAKE_OUTPUT_SIZE(alg, prim, PSA_PAKE_STEP_KEY_SHARE),
+                PSA_PAKE_INPUT_SIZE(alg, prim, PSA_PAKE_STEP_KEY_SHARE) );
+    TEST_EQUAL( PSA_PAKE_OUTPUT_SIZE(alg, prim, PSA_PAKE_STEP_ZK_PUBLIC),
+                PSA_PAKE_INPUT_SIZE(alg, prim, PSA_PAKE_STEP_ZK_PUBLIC) );
+    TEST_EQUAL( PSA_PAKE_OUTPUT_SIZE(alg, prim, PSA_PAKE_STEP_ZK_PROOF),
+                PSA_PAKE_INPUT_SIZE(alg, prim, PSA_PAKE_STEP_ZK_PROOF) );
+
+    /* These inequalities will always hold even when other PAKEs are added */
+    TEST_LE_U( PSA_PAKE_OUTPUT_SIZE(alg, prim, PSA_PAKE_STEP_KEY_SHARE),
+               PSA_PAKE_OUTPUT_MAX_SIZE );
+    TEST_LE_U( PSA_PAKE_OUTPUT_SIZE(alg, prim, PSA_PAKE_STEP_ZK_PUBLIC),
+               PSA_PAKE_OUTPUT_MAX_SIZE );
+    TEST_LE_U( PSA_PAKE_OUTPUT_SIZE(alg, prim, PSA_PAKE_STEP_ZK_PROOF),
+               PSA_PAKE_OUTPUT_MAX_SIZE );
+    TEST_LE_U( PSA_PAKE_INPUT_SIZE(alg, prim, PSA_PAKE_STEP_KEY_SHARE),
+               PSA_PAKE_INPUT_MAX_SIZE );
+    TEST_LE_U( PSA_PAKE_INPUT_SIZE(alg, prim, PSA_PAKE_STEP_ZK_PUBLIC),
+               PSA_PAKE_INPUT_MAX_SIZE );
+    TEST_LE_U( PSA_PAKE_INPUT_SIZE(alg, prim, PSA_PAKE_STEP_ZK_PROOF),
+               PSA_PAKE_INPUT_MAX_SIZE );
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_psa_crypto_persistent_key.function b/tests/suites/test_suite_psa_crypto_persistent_key.function
index 08db34a..bb87923 100644
--- a/tests/suites/test_suite_psa_crypto_persistent_key.function
+++ b/tests/suites/test_suite_psa_crypto_persistent_key.function
@@ -2,7 +2,7 @@
 
 /* The tests in this module verify the contents of key store files. They
  * access internal key storage functions directly. Some of the tests depend
- * on the the storage format. On the other hand, these tests treat the storage
+ * on the storage format. On the other hand, these tests treat the storage
  * subsystem as a black box, and in particular have no reliance on the
  * internals of the ITS implementation.
  *
diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data
index a35762d..1b5e44b 100644
--- a/tests/suites/test_suite_ssl.data
+++ b/tests/suites/test_suite_ssl.data
@@ -417,59 +417,59 @@
 handshake_ciphersuite_select:"TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384":MBEDTLS_PK_RSA:"":PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_ANY_HASH):PSA_ALG_NONE:PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE:0
 
 Handshake, select ECDHE-ECDSA-WITH-AES-256-CCM, non-opaque
-depends_on:MBEDTLS_HAS_ALG_SHA_256_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_AES_C:MBEDTLS_CCM_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
+depends_on:MBEDTLS_HAS_ALG_SHA_256_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_AES_C:MBEDTLS_CCM_C:MBEDTLS_ECDSA_C:MBEDTLS_ECDH_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
 handshake_ciphersuite_select:"TLS-ECDHE-ECDSA-WITH-AES-256-CCM":MBEDTLS_PK_ECDSA:"":PSA_ALG_NONE:PSA_ALG_NONE:0:0:MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM
 
 Handshake, select ECDHE-ECDSA-WITH-AES-256-CCM, opaque, PSA_ALG_ANY_HASH
-depends_on:MBEDTLS_HAS_ALG_SHA_256_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_AES_C:MBEDTLS_CCM_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
+depends_on:MBEDTLS_HAS_ALG_SHA_256_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_AES_C:MBEDTLS_CCM_C:MBEDTLS_ECDSA_C:MBEDTLS_ECDH_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
 handshake_ciphersuite_select:"TLS-ECDHE-ECDSA-WITH-AES-256-CCM":MBEDTLS_PK_ECDSA:"":PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):PSA_ALG_NONE:PSA_KEY_USAGE_SIGN_HASH:0:MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM
 
 Handshake, select ECDHE-ECDSA-WITH-AES-256-CCM, opaque, PSA_ALG_SHA_256
-depends_on:MBEDTLS_HAS_ALG_SHA_256_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_AES_C:MBEDTLS_CCM_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
+depends_on:MBEDTLS_HAS_ALG_SHA_256_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_AES_C:MBEDTLS_CCM_C:MBEDTLS_ECDSA_C:MBEDTLS_ECDH_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
 handshake_ciphersuite_select:"TLS-ECDHE-ECDSA-WITH-AES-256-CCM":MBEDTLS_PK_ECDSA:"":PSA_ALG_ECDSA(PSA_ALG_SHA_256):PSA_ALG_NONE:PSA_KEY_USAGE_SIGN_HASH:0:MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM
 
 Handshake, select ECDHE-ECDSA-WITH-AES-256-CCM, opaque, bad alg
-depends_on:MBEDTLS_HAS_ALG_SHA_256_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_AES_C:MBEDTLS_CCM_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
+depends_on:MBEDTLS_HAS_ALG_SHA_256_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_AES_C:MBEDTLS_CCM_C:MBEDTLS_ECDSA_C:MBEDTLS_ECDH_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
 handshake_ciphersuite_select:"TLS-ECDHE-ECDSA-WITH-AES-256-CCM":MBEDTLS_PK_ECDSA:"":PSA_ALG_ECDH:PSA_ALG_NONE:PSA_KEY_USAGE_SIGN_HASH:MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE:0
 
 Handshake, select ECDHE-ECDSA-WITH-AES-256-CCM, opaque, bad usage
-depends_on:MBEDTLS_HAS_ALG_SHA_256_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_AES_C:MBEDTLS_CCM_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
+depends_on:MBEDTLS_HAS_ALG_SHA_256_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_AES_C:MBEDTLS_CCM_C:MBEDTLS_ECDSA_C:MBEDTLS_ECDH_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
 handshake_ciphersuite_select:"TLS-ECDHE-ECDSA-WITH-AES-256-CCM":MBEDTLS_PK_ECDSA:"":PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):PSA_ALG_NONE:PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE:0
 
 Handshake, select ECDH-RSA-WITH-AES-256-CBC-SHA384, non-opaque
-depends_on:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_AES_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED
+depends_on:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_AES_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_ECDH_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED
 handshake_ciphersuite_select:"TLS-ECDH-RSA-WITH-AES-256-CBC-SHA384":MBEDTLS_PK_ECDSA:"":PSA_ALG_NONE:PSA_ALG_NONE:0:0:MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
 
 Handshake, select ECDH-RSA-WITH-AES-256-CBC-SHA384, opaque
-depends_on:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_AES_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
+depends_on:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_AES_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_ECDH_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
 handshake_ciphersuite_select:"TLS-ECDH-RSA-WITH-AES-256-CBC-SHA384":MBEDTLS_PK_ECDSA:"":PSA_ALG_ECDH:PSA_ALG_NONE:PSA_KEY_USAGE_DERIVE:0:MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
 
 Handshake, select ECDH-RSA-WITH-AES-256-CBC-SHA384, opaque, bad alg
-depends_on:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_AES_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
+depends_on:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_AES_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_ECDH_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
 handshake_ciphersuite_select:"TLS-ECDH-RSA-WITH-AES-256-CBC-SHA384":MBEDTLS_PK_ECDSA:"":PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):PSA_ALG_NONE:PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE:0
 
 Handshake, select ECDH-RSA-WITH-AES-256-CBC-SHA384, opaque, bad usage
-depends_on:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_AES_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
+depends_on:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_AES_C:MBEDTLS_RSA_C:MBEDTLS_ECDSA_C:MBEDTLS_ECDH_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
 handshake_ciphersuite_select:"TLS-ECDH-RSA-WITH-AES-256-CBC-SHA384":MBEDTLS_PK_ECDSA:"":PSA_ALG_ECDH:PSA_ALG_NONE:PSA_KEY_USAGE_DECRYPT:MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE:0
 
 Handshake, select ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA384, non-opaque
-depends_on:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_CAMELLIA_C:MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED
+depends_on:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_ECDSA_C:MBEDTLS_ECDH_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_CAMELLIA_C:MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED
 handshake_ciphersuite_select:"TLS-ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA384":MBEDTLS_PK_ECDSA:"":PSA_ALG_NONE:PSA_ALG_NONE:0:0:MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
 
 Handshake, select ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA384, opaque, PSA_ALG_ANY_HASH
-depends_on:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_CAMELLIA_C:MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
+depends_on:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_ECDSA_C:MBEDTLS_ECDH_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_CAMELLIA_C:MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
 handshake_ciphersuite_select:"TLS-ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA384":MBEDTLS_PK_ECDSA:"":PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):PSA_ALG_ECDH:PSA_KEY_USAGE_SIGN_HASH|PSA_KEY_USAGE_DERIVE:0:MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
 
 Handshake, select ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA384, opaque, PSA_ALG_SHA_384
-depends_on:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_CAMELLIA_C:MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
+depends_on:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_ECDSA_C:MBEDTLS_ECDH_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_CAMELLIA_C:MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
 handshake_ciphersuite_select:"TLS-ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA384":MBEDTLS_PK_ECDSA:"":PSA_ALG_ECDSA(PSA_ALG_SHA_384):PSA_ALG_ECDH:PSA_KEY_USAGE_SIGN_HASH|PSA_KEY_USAGE_DERIVE:0:MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
 
 Handshake, select ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA384, opaque, missing alg
-depends_on:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_CAMELLIA_C:MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
+depends_on:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_ECDSA_C:MBEDTLS_ECDH_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_CAMELLIA_C:MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
 handshake_ciphersuite_select:"TLS-ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA384":MBEDTLS_PK_ECDSA:"":PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):PSA_ALG_NONE:PSA_KEY_USAGE_SIGN_HASH|PSA_KEY_USAGE_DERIVE:MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE:0
 
 Handshake, select ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA384, opaque, missing usage
-depends_on:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_CAMELLIA_C:MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
+depends_on:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_ECDSA_C:MBEDTLS_ECDH_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_CAMELLIA_C:MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED:MBEDTLS_USE_PSA_CRYPTO
 handshake_ciphersuite_select:"TLS-ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA384":MBEDTLS_PK_ECDSA:"":PSA_ALG_ECDSA(PSA_ALG_ANY_HASH):PSA_ALG_ECDH:PSA_KEY_USAGE_SIGN_HASH:MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE:0
 
 Sending app data via TLS, MFL=512 without fragmentation
@@ -3378,34 +3378,6 @@
 depends_on:MBEDTLS_SSL_PROTO_TLS1_3:MBEDTLS_SSL_SRV_C
 ssl_serialize_session_load_buf_size:0:"":MBEDTLS_SSL_IS_SERVER:MBEDTLS_SSL_VERSION_TLS1_3
 
-Constant-flow HMAC: MD5
-depends_on:MBEDTLS_HAS_ALG_MD5_VIA_MD_OR_PSA_BASED_ON_USE_PSA
-ssl_cf_hmac:MBEDTLS_MD_MD5
-
-Constant-flow HMAC: SHA1
-depends_on:MBEDTLS_HAS_ALG_SHA_1_VIA_MD_OR_PSA_BASED_ON_USE_PSA
-ssl_cf_hmac:MBEDTLS_MD_SHA1
-
-Constant-flow HMAC: SHA256
-depends_on:MBEDTLS_HAS_ALG_SHA_256_VIA_MD_OR_PSA_BASED_ON_USE_PSA
-ssl_cf_hmac:MBEDTLS_MD_SHA256
-
-Constant-flow HMAC: SHA384
-depends_on:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA
-ssl_cf_hmac:MBEDTLS_MD_SHA384
-
-# 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
-
-# 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
-
-# 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
-
 Test configuration of groups for DHE through mbedtls_ssl_conf_curves()
 conf_curve:
 
@@ -3567,3 +3539,11 @@
 
 TLS 1.3 srv Certificate msg - wrong vector lengths
 tls13_server_certificate_msg_invalid_vector_len
+
+EC-JPAKE set password
+depends_on:MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED
+ssl_ecjpake_set_password:0
+
+EC-JPAKE set opaque password
+depends_on:MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED:MBEDTLS_USE_PSA_CRYPTO
+ssl_ecjpake_set_password:1
diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function
index 7447a1d..95fa8ef 100644
--- a/tests/suites/test_suite_ssl.function
+++ b/tests/suites/test_suite_ssl.function
@@ -511,7 +511,7 @@
  * \p peer1 and \p peer2 must have been previously initialized by calling
  * mbedtls_mock_socket_init().
  *
- * The capacites of the internal buffers are set to \p bufsize. Setting this to
+ * The capacities of the internal buffers are set to \p bufsize. Setting this to
  * the correct value allows for simulation of MTU, sanity testing the mock
  * implementation and mocking TCP connections with lower memory cost.
  */
@@ -652,7 +652,7 @@
 }
 
 /*
- * Setup a given mesasge socket context including initialization of
+ * Setup a given message socket context including initialization of
  * input/output queues to a chosen capacity of messages. Also set the
  * corresponding mock socket.
  *
@@ -2582,6 +2582,21 @@
     return( 0 );
 }
 #endif /* MBEDTLS_TEST_HOOKS */
+
+#define ECJPAKE_TEST_PWD        "bla"
+
+#if defined( MBEDTLS_USE_PSA_CRYPTO )
+#define ECJPAKE_TEST_SET_PASSWORD( exp_ret_val )                          \
+    ret = ( use_opaque_arg ) ?                                            \
+        mbedtls_ssl_set_hs_ecjpake_password_opaque( &ssl, pwd_slot ) :    \
+        mbedtls_ssl_set_hs_ecjpake_password( &ssl, pwd_string, pwd_len ); \
+    TEST_EQUAL( ret, exp_ret_val )
+#else
+#define ECJPAKE_TEST_SET_PASSWORD( exp_ret_val )                \
+    ret = mbedtls_ssl_set_hs_ecjpake_password( &ssl,            \
+                                        pwd_string, pwd_len );  \
+    TEST_EQUAL( ret, exp_ret_val )
+#endif
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
@@ -5438,189 +5453,6 @@
 }
 /* END_CASE */
 
-/* BEGIN_CASE depends_on:MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC:MBEDTLS_TEST_HOOKS */
-void ssl_cf_hmac( int hash )
-{
-    /*
-     * Test the function mbedtls_ct_hmac() against a reference
-     * implementation.
-     */
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
-    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
-    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-    psa_algorithm_t alg;
-    psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT;
-#else
-    mbedtls_md_context_t ctx, ref_ctx;
-    const mbedtls_md_info_t *md_info;
-#endif /* MBEDTLS_USE_PSA_CRYPTO */
-    size_t out_len, block_size;
-    size_t min_in_len, in_len, max_in_len, i;
-    /* TLS additional data is 13 bytes (hence the "lucky 13" name) */
-    unsigned char add_data[13];
-    unsigned char ref_out[MBEDTLS_HASH_MAX_SIZE];
-    unsigned char *data = NULL;
-    unsigned char *out = NULL;
-    unsigned char rec_num = 0;
-
-    USE_PSA_INIT( );
-
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
-    alg = PSA_ALG_HMAC( mbedtls_hash_info_psa_from_md( hash ) );
-
-    out_len = PSA_HASH_LENGTH( alg );
-    block_size = PSA_HASH_BLOCK_LENGTH( alg );
-
-    /* mbedtls_ct_hmac() requires the key to be exportable */
-    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_EXPORT |
-                                          PSA_KEY_USAGE_VERIFY_HASH );
-    psa_set_key_algorithm( &attributes, PSA_ALG_HMAC( alg ) );
-    psa_set_key_type( &attributes, PSA_KEY_TYPE_HMAC );
-#else
-    mbedtls_md_init( &ctx );
-    mbedtls_md_init( &ref_ctx );
-
-    md_info = mbedtls_md_info_from_type( hash );
-    TEST_ASSERT( md_info != NULL );
-    out_len = mbedtls_md_get_size( md_info );
-    TEST_ASSERT( out_len != 0 );
-    block_size = hash == MBEDTLS_MD_SHA384 ? 128 : 64;
-#endif /* MBEDTLS_USE_PSA_CRYPTO */
-
-    /* Use allocated out buffer to catch overwrites */
-    ASSERT_ALLOC( out, out_len );
-
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
-    /* Set up dummy key */
-    memset( ref_out, 42, sizeof( ref_out ) );
-    TEST_EQUAL( PSA_SUCCESS, psa_import_key( &attributes,
-                                             ref_out, out_len,
-                                             &key ) );
-#else
-    /* Set up contexts with the given hash and a dummy key */
-    TEST_EQUAL( 0, mbedtls_md_setup( &ctx, md_info, 1 ) );
-    TEST_EQUAL( 0, mbedtls_md_setup( &ref_ctx, md_info, 1 ) );
-    memset( ref_out, 42, sizeof( ref_out ) );
-    TEST_EQUAL( 0, mbedtls_md_hmac_starts( &ctx, ref_out, out_len ) );
-    TEST_EQUAL( 0, mbedtls_md_hmac_starts( &ref_ctx, ref_out, out_len ) );
-    memset( ref_out, 0, sizeof( ref_out ) );
-#endif
-
-    /*
-     * Test all possible lengths up to a point. The difference between
-     * max_in_len and min_in_len is at most 255, and make sure they both vary
-     * by at least one block size.
-     */
-    for( max_in_len = 0; max_in_len <= 255 + block_size; max_in_len++ )
-    {
-        mbedtls_test_set_step( max_in_len * 10000 );
-
-        /* Use allocated in buffer to catch overreads */
-        ASSERT_ALLOC( data, max_in_len );
-
-        min_in_len = max_in_len > 255 ? max_in_len - 255 : 0;
-        for( in_len = min_in_len; in_len <= max_in_len; in_len++ )
-        {
-            mbedtls_test_set_step( max_in_len * 10000 + in_len );
-
-            /* Set up dummy data and add_data */
-            rec_num++;
-            memset( add_data, rec_num, sizeof( add_data ) );
-            for( i = 0; i < in_len; i++ )
-                data[i] = ( i & 0xff ) ^ rec_num;
-
-            /* Get the function's result */
-            TEST_CF_SECRET( &in_len, sizeof( in_len ) );
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
-            TEST_EQUAL( 0, mbedtls_ct_hmac( key, PSA_ALG_HMAC( alg ),
-                                            add_data, sizeof( add_data ),
-                                            data, in_len,
-                                            min_in_len, max_in_len,
-                                            out ) );
-#else
-            TEST_EQUAL( 0, mbedtls_ct_hmac( &ctx, add_data, sizeof( add_data ),
-                                            data, in_len,
-                                            min_in_len, max_in_len,
-                                            out ) );
-#endif /* MBEDTLS_USE_PSA_CRYPTO */
-            TEST_CF_PUBLIC( &in_len, sizeof( in_len ) );
-            TEST_CF_PUBLIC( out, out_len );
-
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
-            TEST_EQUAL( PSA_SUCCESS, psa_mac_verify_setup( &operation,
-                                                           key, alg ) );
-            TEST_EQUAL( PSA_SUCCESS, psa_mac_update( &operation, add_data,
-                                                     sizeof( add_data ) ) );
-            TEST_EQUAL( PSA_SUCCESS, psa_mac_update( &operation,
-                                                     data, in_len ) );
-            TEST_EQUAL( PSA_SUCCESS, psa_mac_verify_finish( &operation,
-                                                            out, out_len ) );
-#else
-            /* Compute the reference result */
-            TEST_EQUAL( 0, mbedtls_md_hmac_update( &ref_ctx, add_data,
-                                                   sizeof( add_data ) ) );
-            TEST_EQUAL( 0, mbedtls_md_hmac_update( &ref_ctx, data, in_len ) );
-            TEST_EQUAL( 0, mbedtls_md_hmac_finish( &ref_ctx, ref_out ) );
-            TEST_EQUAL( 0, mbedtls_md_hmac_reset( &ref_ctx ) );
-
-            /* Compare */
-            ASSERT_COMPARE( out, out_len, ref_out, out_len );
-#endif /* MBEDTLS_USE_PSA_CRYPTO */
-        }
-
-        mbedtls_free( data );
-        data = NULL;
-    }
-
-exit:
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
-    psa_mac_abort( &operation );
-    psa_destroy_key( key );
-#else
-    mbedtls_md_free( &ref_ctx );
-    mbedtls_md_free( &ctx );
-#endif /* MBEDTLS_USE_PSA_CRYPTO */
-
-    mbedtls_free( data );
-    mbedtls_free( out );
-
-    USE_PSA_DONE( );
-}
-/* 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 )
-{
-    unsigned char *dst = NULL;
-    unsigned char *src = NULL;
-    size_t src_len = offset_max + len;
-    size_t secret;
-
-    ASSERT_ALLOC( dst, len );
-    ASSERT_ALLOC( src, src_len );
-
-    /* Fill src in a way that we can detect if we copied the right bytes */
-    mbedtls_test_rnd_std_rand( NULL, src, src_len );
-
-    for( secret = offset_min; secret <= (size_t) offset_max; secret++ )
-    {
-        mbedtls_test_set_step( (int) secret );
-
-        TEST_CF_SECRET( &secret, sizeof( secret ) );
-        mbedtls_ct_memcpy_offset( dst, src, secret,
-                                  offset_min, offset_max, len );
-        TEST_CF_PUBLIC( &secret, sizeof( secret ) );
-        TEST_CF_PUBLIC( dst, len );
-
-        ASSERT_COMPARE( dst, len, src + secret, len );
-    }
-
-exit:
-    mbedtls_free( dst );
-    mbedtls_free( src );
-}
-/* END_CASE */
-
 /* BEGIN_CASE depends_on:MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED */
 void test_multiple_psks()
 {
@@ -6180,3 +6012,85 @@
     USE_PSA_DONE( );
 }
 /* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
+void ssl_ecjpake_set_password( int use_opaque_arg )
+{
+    mbedtls_ssl_context ssl;
+    mbedtls_ssl_config conf;
+#if defined( MBEDTLS_USE_PSA_CRYPTO )
+    mbedtls_svc_key_id_t pwd_slot = MBEDTLS_SVC_KEY_ID_INIT;
+#else   /* MBEDTLS_USE_PSA_CRYPTO */
+    (void) use_opaque_arg;
+#endif  /* MBEDTLS_USE_PSA_CRYPTO */
+    unsigned char pwd_string[ sizeof(ECJPAKE_TEST_PWD) ] = "";
+    size_t pwd_len = 0;
+    int ret;
+
+    USE_PSA_INIT( );
+
+    mbedtls_ssl_init( &ssl );
+
+    /* test with uninitalized SSL context */
+    ECJPAKE_TEST_SET_PASSWORD( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    mbedtls_ssl_config_init( &conf );
+
+    TEST_EQUAL( mbedtls_ssl_config_defaults( &conf,
+                                              MBEDTLS_SSL_IS_CLIENT,
+                                              MBEDTLS_SSL_TRANSPORT_STREAM,
+                                              MBEDTLS_SSL_PRESET_DEFAULT ), 0 );
+
+    TEST_EQUAL( mbedtls_ssl_setup( &ssl, &conf ), 0 );
+
+    /* test with empty password or unitialized password key (depending on use_opaque_arg) */
+    ECJPAKE_TEST_SET_PASSWORD( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    pwd_len = strlen( ECJPAKE_TEST_PWD );
+    memcpy( pwd_string, ECJPAKE_TEST_PWD, pwd_len );
+
+#if defined( MBEDTLS_USE_PSA_CRYPTO )
+    if( use_opaque_arg )
+    {
+        psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+        psa_key_attributes_t check_attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+        /* First try with an invalid usage */
+        psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN_HASH );
+        psa_set_key_algorithm( &attributes, PSA_ALG_JPAKE );
+        psa_set_key_type( &attributes, PSA_KEY_TYPE_PASSWORD );
+
+        PSA_ASSERT( psa_import_key( &attributes, pwd_string,
+                    pwd_len, &pwd_slot ) );
+
+        ECJPAKE_TEST_SET_PASSWORD( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+
+        /* check that the opaque key is still valid after failure */
+        TEST_EQUAL( psa_get_key_attributes( pwd_slot, &check_attributes ),
+                        PSA_SUCCESS );
+
+        psa_destroy_key( pwd_slot );
+
+        /* Then set the correct usage */
+        psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DERIVE );
+
+        PSA_ASSERT( psa_import_key( &attributes, pwd_string,
+                    pwd_len, &pwd_slot ) );
+    }
+#endif  /* MBEDTLS_USE_PSA_CRYPTO */
+
+    /* final check which should work without errors */
+    ECJPAKE_TEST_SET_PASSWORD( 0 );
+
+#if defined( MBEDTLS_USE_PSA_CRYPTO )
+    if( use_opaque_arg )
+    {
+        psa_destroy_key( pwd_slot );
+    }
+#endif  /* MBEDTLS_USE_PSA_CRYPTO */
+    mbedtls_ssl_free( &ssl );
+    mbedtls_ssl_config_free( &conf );
+
+    USE_PSA_DONE( );
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_version.data b/tests/suites/test_suite_version.data
index f131029..ea6fc62 100644
--- a/tests/suites/test_suite_version.data
+++ b/tests/suites/test_suite_version.data
@@ -1,8 +1,8 @@
 Check compile time library version
-check_compiletime_version:"3.2.1"
+check_compiletime_version:"3.3.0"
 
 Check runtime library version
-check_runtime_version:"3.2.1"
+check_runtime_version:"3.3.0"
 
 Check for MBEDTLS_VERSION_C
 check_feature:"MBEDTLS_VERSION_C":0
diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function
index 2585720..dc36b81 100644
--- a/tests/suites/test_suite_x509parse.function
+++ b/tests/suites/test_suite_x509parse.function
@@ -579,6 +579,8 @@
     mbedtls_x509_crt_init( &crt );
     mbedtls_x509_crt_init( &ca );
 
+    USE_PSA_INIT( );
+
     TEST_ASSERT( mbedtls_x509_crt_parse_file( &crt, crt_file ) == 0 );
     TEST_ASSERT( mbedtls_x509_crt_parse_file( &ca, ca_file ) == 0 );
 
@@ -607,6 +609,7 @@
     mbedtls_x509_crt_restart_free( &rs_ctx );
     mbedtls_x509_crt_free( &crt );
     mbedtls_x509_crt_free( &ca );
+    USE_PSA_DONE( );
 }
 /* END_CASE */
 
diff --git a/tests/suites/test_suite_x509write.data b/tests/suites/test_suite_x509write.data
index 8411557..c55c9d1 100644
--- a/tests/suites/test_suite_x509write.data
+++ b/tests/suites/test_suite_x509write.data
@@ -1,30 +1,30 @@
 Certificate Request check Server1 SHA1
 depends_on:MBEDTLS_HAS_ALG_SHA_1_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha1":MBEDTLS_MD_SHA1:0:0:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha1":MBEDTLS_MD_SHA1:0:0:0:0:0
 
 Certificate Request check Server1 SHA224
 depends_on:MBEDTLS_HAS_ALG_SHA_224_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha224":MBEDTLS_MD_SHA224:0:0:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha224":MBEDTLS_MD_SHA224:0:0:0:0:0
 
 Certificate Request check Server1 SHA256
 depends_on:MBEDTLS_HAS_ALG_SHA_256_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha256":MBEDTLS_MD_SHA256:0:0:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha256":MBEDTLS_MD_SHA256:0:0:0:0:0
 
 Certificate Request check Server1 SHA384
 depends_on:MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha384":MBEDTLS_MD_SHA384:0:0:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha384":MBEDTLS_MD_SHA384:0:0:0:0:0
 
 Certificate Request check Server1 SHA512
 depends_on:MBEDTLS_HAS_ALG_SHA_512_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha512":MBEDTLS_MD_SHA512:0:0:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha512":MBEDTLS_MD_SHA512:0:0:0:0:0
 
 Certificate Request check Server1 MD5
 depends_on:MBEDTLS_HAS_ALG_MD5_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.md5":MBEDTLS_MD_MD5:0:0:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.md5":MBEDTLS_MD_MD5:0:0:0:0:0
 
 Certificate Request check Server1 key_usage
 depends_on:MBEDTLS_HAS_ALG_SHA_1_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.key_usage":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION | MBEDTLS_X509_KU_KEY_ENCIPHERMENT:1:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.key_usage":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION | MBEDTLS_X509_KU_KEY_ENCIPHERMENT:1:0:0:0
 
 Certificate Request check opaque Server1 key_usage
 depends_on:MBEDTLS_HAS_ALG_SHA_1_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
@@ -32,23 +32,27 @@
 
 Certificate Request check Server1 key_usage empty
 depends_on:MBEDTLS_HAS_ALG_SHA_1_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.key_usage_empty":MBEDTLS_MD_SHA1:0:1:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.key_usage_empty":MBEDTLS_MD_SHA1:0:1:0:0:0
 
 Certificate Request check Server1 ns_cert_type
 depends_on:MBEDTLS_HAS_ALG_SHA_1_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.cert_type":MBEDTLS_MD_SHA1:0:0:MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER:1
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.cert_type":MBEDTLS_MD_SHA1:0:0:MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER:1:0
 
 Certificate Request check Server1 ns_cert_type empty
 depends_on:MBEDTLS_HAS_ALG_SHA_1_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.cert_type_empty":MBEDTLS_MD_SHA1:0:0:0:1
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.cert_type_empty":MBEDTLS_MD_SHA1:0:0:0:1:0
 
 Certificate Request check Server1 key_usage + ns_cert_type
 depends_on:MBEDTLS_HAS_ALG_SHA_1_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.ku-ct":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION | MBEDTLS_X509_KU_KEY_ENCIPHERMENT:1:MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER:1
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.ku-ct":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION | MBEDTLS_X509_KU_KEY_ENCIPHERMENT:1:MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER:1:0
 
 Certificate Request check Server5 ECDSA, key_usage
 depends_on:MBEDTLS_HAS_ALG_SHA_1_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_ECDSA_C:MBEDTLS_ECDSA_DETERMINISTIC:MBEDTLS_ECP_DP_SECP256R1_ENABLED
-x509_csr_check:"data_files/server5.key":"data_files/server5.req.ku.sha1":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION:1:0:0
+x509_csr_check:"data_files/server5.key":"data_files/server5.req.ku.sha1":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION:1:0:0:0
+
+Certificate Request check Server1, set_extension
+depends_on:MBEDTLS_HAS_ALG_SHA_256_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha256.ext":MBEDTLS_MD_SHA256:0:0:0:0:1
 
 Certificate Request check opaque Server5 ECDSA, key_usage
 depends_on:MBEDTLS_HAS_ALG_SHA_256_VIA_MD_OR_PSA_BASED_ON_USE_PSA:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED
diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function
index aa54072..5bd814a 100644
--- a/tests/suites/test_suite_x509write.function
+++ b/tests/suites/test_suite_x509write.function
@@ -5,6 +5,7 @@
 #include "mbedtls/pem.h"
 #include "mbedtls/oid.h"
 #include "mbedtls/rsa.h"
+#include "mbedtls/asn1write.h"
 
 #include "hash_info.h"
 #include "mbedtls/legacy_or_psa.h"
@@ -74,6 +75,56 @@
 }
 #endif /* MBEDTLS_USE_PSA_CRYPTO && MBEDTLS_PEM_WRITE_C && MBEDTLS_X509_CSR_WRITE_C */
 
+#if defined(MBEDTLS_X509_CSR_WRITE_C)
+
+/*
+ * The size of this temporary buffer is given by the sequence of functions
+ * called hereinafter:
+ * - mbedtls_asn1_write_oid()
+ *     - 8 bytes for MBEDTLS_OID_EXTENDED_KEY_USAGE raw value
+ *     - 1 byte for MBEDTLS_OID_EXTENDED_KEY_USAGE length
+ *     - 1 byte for MBEDTLS_ASN1_OID tag
+ * - mbedtls_asn1_write_len()
+ *     - 1 byte since we're dealing with sizes which are less than 0x80
+ * - mbedtls_asn1_write_tag()
+ *     - 1 byte
+ *
+ * This length is fine as long as this function is called using the
+ * MBEDTLS_OID_SERVER_AUTH OID. If this is changed in the future, then this
+ * buffer's length should be adjusted accordingly.
+ * Unfortunately there's no predefined max size for OIDs which can be used
+ * to set an overall upper boundary which is always guaranteed.
+ */
+#define EXT_KEY_USAGE_TMP_BUF_MAX_LENGTH    12
+
+static int csr_set_extended_key_usage( mbedtls_x509write_csr *ctx,
+                        const char *oid, size_t oid_len )
+{
+    unsigned char buf[EXT_KEY_USAGE_TMP_BUF_MAX_LENGTH] = { 0 };
+    unsigned char *p = buf + sizeof( buf );
+    int ret;
+    size_t len = 0;
+
+    /*
+     * Following functions fail anyway if the temporary buffer is not large,
+     * but we set an extra check here to emphasize a possible source of errors
+     */
+    if ( oid_len > EXT_KEY_USAGE_TMP_BUF_MAX_LENGTH )
+    {
+        return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
+    }
+
+    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( &p, buf, oid, oid_len ) );
+    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &p, buf, ret ) );
+    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &p, buf,
+                        MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) );
+
+    ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_EXTENDED_KEY_USAGE,
+              MBEDTLS_OID_SIZE( MBEDTLS_OID_EXTENDED_KEY_USAGE ), 0, p, len );
+
+    return ret;
+}
+#endif  /* MBEDTLS_X509_CSR_WRITE_C */
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
@@ -84,7 +135,7 @@
 /* BEGIN_CASE depends_on:MBEDTLS_PEM_WRITE_C:MBEDTLS_X509_CSR_WRITE_C */
 void x509_csr_check( char * key_file, char * cert_req_check_file, int md_type,
                      int key_usage, int set_key_usage, int cert_type,
-                     int set_cert_type )
+                     int set_cert_type, int set_extension )
 {
     mbedtls_pk_context key;
     mbedtls_x509write_csr req;
@@ -117,6 +168,9 @@
         TEST_ASSERT( mbedtls_x509write_csr_set_key_usage( &req, key_usage ) == 0 );
     if( set_cert_type != 0 )
         TEST_ASSERT( mbedtls_x509write_csr_set_ns_cert_type( &req, cert_type ) == 0 );
+    if ( set_extension != 0 )
+        TEST_ASSERT( csr_set_extended_key_usage( &req, MBEDTLS_OID_SERVER_AUTH,
+                            MBEDTLS_OID_SIZE( MBEDTLS_OID_SERVER_AUTH ) ) == 0 );
 
     ret = mbedtls_x509write_csr_pem( &req, buf, sizeof( buf ),
                                      mbedtls_test_rnd_pseudo_rand, &rnd_info );