Merge pull request #786 from ARMmbed/dev/yanesca/mbedtls-2.25.0r0-pr

Prepare Release Candidate for Mbed TLS 2.25.0
diff --git a/ChangeLog b/ChangeLog
index 594c3cf..fb231aa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,171 @@
 mbed TLS ChangeLog (Sorted per branch, date)
 
+= mbed TLS 2.25.0 branch released 2020-12-11
+
+API changes
+   * The numerical values of the PSA Crypto API macros have been updated to
+     conform to version 1.0.0 of the specification.
+   * PSA_ALG_STREAM_CIPHER replaces PSA_ALG_CHACHA20 and PSA_ALG_ARC4.
+     The underlying stream cipher is determined by the key type
+     (PSA_KEY_TYPE_CHACHA20 or PSA_KEY_TYPE_ARC4).
+   * The functions mbedtls_cipher_auth_encrypt() and
+     mbedtls_cipher_auth_decrypt() no longer accept NIST_KW contexts,
+     as they have no way to check if the output buffer is large enough.
+     Please use mbedtls_cipher_auth_encrypt_ext() and
+     mbedtls_cipher_auth_decrypt_ext() instead. Credit to OSS-Fuzz and
+     Cryptofuzz. Fixes #3665.
+
+Requirement changes
+   * Update the minimum required CMake version to 2.8.12.  This silences a
+     warning on CMake 3.19.0. #3801
+
+New deprecations
+   * PSA_KEY_TYPE_CHACHA20 and PSA_KEY_TYPE_ARC4 have been deprecated.
+     Use PSA_ALG_STREAM_CIPHER instead.
+   * The functions mbedtls_cipher_auth_encrypt() and
+     mbedtls_cipher_auth_decrypt() are deprecated in favour of the new
+     functions mbedtls_cipher_auth_encrypt_ext() and
+     mbedtls_cipher_auth_decrypt_ext(). Please note that with AEAD ciphers,
+     these new functions always append the tag to the ciphertext, and include
+     the tag in the ciphertext length.
+
+Features
+   * Partial implementation of the new PSA Crypto accelerator APIs. (Symmetric
+     ciphers, asymmetric signing/verification and key generation, validate_key
+     entry point, and export_public_key interface.)
+   * Add support for ECB to the PSA cipher API.
+   * In PSA, allow using a key declared with a base key agreement algorithm
+     in combined key agreement and derivation operations, as long as the key
+     agreement algorithm in use matches the algorithm the key was declared with.
+     This is currently non-standard behaviour, but expected to make it into a
+     future revision of the PSA Crypto standard.
+   * Add MBEDTLS_TARGET_PREFIX CMake variable, which is prefixed to the mbedtls,
+     mbedcrypto, mbedx509 and apidoc CMake target names. This can be used by
+     external CMake projects that include this one to avoid CMake target name
+     clashes.  The default value of this variable is "", so default target names
+     are unchanged.
+   * Add support for DTLS-SRTP as defined in RFC 5764. Contributed by Johan
+     Pascal, improved by Ron Eldor.
+   * In the PSA API, it is no longer necessary to open persistent keys:
+     operations now accept the key identifier. The type psa_key_handle_t is now
+     identical to psa_key_id_t instead of being platform-defined. This bridges
+     the last major gap to compliance with the PSA Cryptography specification
+     version 1.0.0. Opening persistent keys is still supported for backward
+     compatibility, but will be deprecated and later removed in future
+     releases.
+   * PSA_AEAD_NONCE_LENGTH, PSA_AEAD_NONCE_MAX_SIZE, PSA_CIPHER_IV_LENGTH and
+     PSA_CIPHER_IV_MAX_SIZE macros have been added as defined in version
+     1.0.0 of the PSA Crypto API specification.
+
+Security
+   * The functions mbedtls_cipher_auth_encrypt() and
+     mbedtls_cipher_auth_decrypt() would write past the minimum documented
+     size of the output buffer when used with NIST_KW. As a result, code using
+     those functions as documented with NIST_KW could have a buffer overwrite
+     of up to 15 bytes, with consequences ranging up to arbitrary code
+     execution depending on the location of the output buffer.
+   * Limit the size of calculations performed by mbedtls_mpi_exp_mod to
+     MBEDTLS_MPI_MAX_SIZE to prevent a potential denial of service when
+     generating Diffie-Hellman key pairs. Credit to OSS-Fuzz.
+   * A failure of the random generator was ignored in mbedtls_mpi_fill_random(),
+     which is how most uses of randomization in asymmetric cryptography
+     (including key generation, intermediate value randomization and blinding)
+     are implemented. This could cause failures or the silent use of non-random
+     values. A random generator can fail if it needs reseeding and cannot not
+     obtain entropy, or due to an internal failure (which, for Mbed TLS's own
+     CTR_DRBG or HMAC_DRBG, can only happen due to a misconfiguration).
+   * Fix a compliance issue whereby we were not checking the tag on the
+     algorithm parameters (only the size) when comparing the signature in the
+     description part of the cert to the real signature. This meant that a
+     NULL algorithm parameters entry would look identical to an array of REAL
+     (size zero) to the library and thus the certificate would be considered
+     valid. However, if the parameters do not match in *any* way then the
+     certificate should be considered invalid, and indeed OpenSSL marks these
+     certs as invalid when mbedtls did not.
+     Many thanks to guidovranken who found this issue via differential fuzzing
+     and reported it in #3629.
+   * Zeroising of local buffers and variables which are used for calculations
+     in mbedtls_pkcs5_pbkdf2_hmac(), mbedtls_internal_sha*_process(),
+     mbedtls_internal_md*_process() and mbedtls_internal_ripemd160_process()
+     functions to erase sensitive data from memory. Reported by
+     Johan Malmgren and Johan Uppman Bruce from Sectra.
+
+Bugfix
+   * Fix an invalid (but nonzero) return code from mbedtls_pk_parse_subpubkey()
+     when the input has trailing garbage. Fixes #2512.
+   * Fix build failure in configurations where MBEDTLS_USE_PSA_CRYPTO is
+     enabled but ECDSA is disabled. Contributed by jdurkop. Fixes #3294.
+   * Include the psa_constant_names generated source code in the source tree
+     instead of generating it at build time. Fixes #3524.
+   * Fix rsa_prepare_blinding() to retry when the blinding value is not
+     invertible (mod N), instead of returning MBEDTLS_ERR_RSA_RNG_FAILED. This
+     addresses a regression but is rare in practice (approx. 1 in 2/sqrt(N)).
+     Found by Synopsys Coverity, fix contributed by Peter Kolbus (Garmin).
+     Fixes #3647.
+   * Use socklen_t on Android and other POSIX-compliant system
+   * Fix the build when the macro _GNU_SOURCE is defined to a non-empty value.
+     Fix #3432.
+   * Consistently return PSA_ERROR_INVALID_ARGUMENT on invalid cipher input
+     sizes (instead of PSA_ERROR_BAD_STATE in some cases) to make the
+     psa_cipher_* functions compliant with the PSA Crypto API specification.
+   * mbedtls_ecp_curve_list() now lists Curve25519 and Curve448 under the names
+     "x25519" and "x448". These curves support ECDH but not ECDSA. If you need
+     only the curves that support ECDSA, filter the list with
+     mbedtls_ecdsa_can_do().
+   * Fix psa_generate_key() returning an error when asked to generate
+     an ECC key pair on Curve25519 or secp244k1.
+   * Fix psa_key_derivation_output_key() to allow the output of a combined key
+     agreement and subsequent key derivation operation to be used as a key
+     inside of the PSA Crypto core.
+   * Fix handling of EOF against 0xff bytes and on platforms with unsigned
+     chars. Fixes a build failure on platforms where char is unsigned. Fixes
+     #3794.
+   * Fix an off-by-one error in the additional data length check for
+     CCM, which allowed encryption with a non-standard length field.
+     Fixes #3719.
+   * Correct the default IV size for mbedtls_cipher_info_t structures using
+     MBEDTLS_MODE_ECB to 0, since ECB mode ciphers don't use IVs.
+   * Make arc4random_buf available on NetBSD and OpenBSD when _POSIX_C_SOURCE is
+     defined. Fix contributed in #3571.
+   * Fix conditions for including string.h in error.c. Fixes #3866.
+   * psa_set_key_id() now also sets the lifetime to persistent for keys located
+     in a secure element.
+   * Attempting to create a volatile key with a non-zero key identifier now
+     fails. Previously the key identifier was just ignored when creating a
+     volatile key.
+   * Attempting to create or register a key with a key identifier in the vendor
+     range now fails.
+   * Fix build failures on GCC 11. Fixes #3782.
+   * Add missing arguments of debug message in mbedtls_ssl_decrypt_buf.
+   * Fix a memory leak in mbedtls_mpi_sub_abs() when the result was negative
+     (an error condition) and the second operand was aliased to the result.
+   * Fix a case in elliptic curve arithmetic where an out-of-memory condition
+     could go undetected, resulting in an incorrect result.
+   * In CTR_DRBG and HMAC_DRBG, don't reset the reseed interval in seed().
+     Fixes #2927.
+   * In PEM writing functions, fill the trailing part of the buffer with null
+     bytes. This guarantees that the corresponding parsing function can read
+     the buffer back, which was the case for mbedtls_x509write_{crt,csr}_pem
+     until this property was inadvertently broken in Mbed TLS 2.19.0.
+     Fixes #3682.
+   * Fix a build failure that occurred with the MBEDTLS_AES_SETKEY_DEC_ALT
+     option on. In this configuration key management methods that are required
+     for MBEDTLS_CIPHER_MODE_XTS were excluded from the build and made it fail.
+     Fixes #3818. Reported by John Stroebel.
+
+Changes
+   * Reduce stack usage significantly during sliding window exponentiation.
+     Reported in #3591 and fix contributed in #3592 by Daniel Otte.
+   * The PSA persistent storage format is updated to always store the key bits
+     attribute. No automatic upgrade path is provided. Previously stored keys
+     must be erased, or manually upgraded based on the key storage format
+     specification (docs/architecture/mbed-crypto-storage-specification.md).
+     Fixes #3740.
+   * Remove the zeroization of a pointer variable in AES rounds. It was valid
+     but spurious and misleading since it looked like a mistaken attempt to
+     zeroize the pointed-to buffer. Reported by Antonio de la Piedra, CEA
+     Leti, France.
+
 = mbed TLS 2.24.0 branch released 2020-09-01
 
 API changes
diff --git a/ChangeLog.d/_GNU_SOURCE-redefined.txt b/ChangeLog.d/_GNU_SOURCE-redefined.txt
deleted file mode 100644
index 59c8a15..0000000
--- a/ChangeLog.d/_GNU_SOURCE-redefined.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix the build when the macro _GNU_SOURCE is defined to a non-empty value.
-     Fix #3432.
diff --git a/ChangeLog.d/add-aes-ecb-to-psa.txt b/ChangeLog.d/add-aes-ecb-to-psa.txt
deleted file mode 100644
index b0de67c..0000000
--- a/ChangeLog.d/add-aes-ecb-to-psa.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Features
-   * Add support for ECB to the PSA cipher API.
diff --git a/ChangeLog.d/add_MBEDTLS_TARGET_PREFIX_to_cmake.txt b/ChangeLog.d/add_MBEDTLS_TARGET_PREFIX_to_cmake.txt
deleted file mode 100644
index 533f309..0000000
--- a/ChangeLog.d/add_MBEDTLS_TARGET_PREFIX_to_cmake.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Features
-   * Add MBEDTLS_TARGET_PREFIX CMake variable, which is prefixed to the mbedtls,
-     mbedcrypto, mbedx509 and apidoc CMake target names. This can be used by
-     external CMake projects that include this one to avoid CMake target name
-     clashes.  The default value of this variable is "", so default target names
-     are unchanged.
diff --git a/ChangeLog.d/add_cipher_transparent_driver.txt b/ChangeLog.d/add_cipher_transparent_driver.txt
deleted file mode 100644
index ce6f33d..0000000
--- a/ChangeLog.d/add_cipher_transparent_driver.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Features
-   * Partial implementation of the new PSA Crypto accelerator APIs for
-     enabling symmetric cipher acceleration through crypto accelerators.
-     Contributed by Steven Cooreman in #3644.
diff --git a/ChangeLog.d/add_export_public_key_driver.txt b/ChangeLog.d/add_export_public_key_driver.txt
deleted file mode 100644
index a9bffbc..0000000
--- a/ChangeLog.d/add_export_public_key_driver.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Features
-    * Implementation of the export_public_key interface for PSA Crypto
-      accelerator drivers, as defined in #3493. Contributed in #3786.
diff --git a/ChangeLog.d/add_sign_verify_keygen_transparent_driver.txt b/ChangeLog.d/add_sign_verify_keygen_transparent_driver.txt
deleted file mode 100644
index fe43899..0000000
--- a/ChangeLog.d/add_sign_verify_keygen_transparent_driver.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Features
-   * Partial implementation of the new PSA Crypto accelerator APIs for
-     enabling key generation and asymmetric signing/verification through crypto
-     accelerators. Contributed by Steven Cooreman in #3501.
diff --git a/ChangeLog.d/adjusting sliding_window_size_PR3592.txt b/ChangeLog.d/adjusting sliding_window_size_PR3592.txt
deleted file mode 100644
index 6089565..0000000
--- a/ChangeLog.d/adjusting sliding_window_size_PR3592.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Changes
-   * Reduce stack usage significantly during sliding window exponentiation.
-     Reported in #3591 and fix contributed in #3592 by Daniel Otte.
diff --git a/ChangeLog.d/aes-zeroize-pointer.txt b/ChangeLog.d/aes-zeroize-pointer.txt
deleted file mode 100644
index ccc6dc1..0000000
--- a/ChangeLog.d/aes-zeroize-pointer.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Changes
-   * Remove the zeroization of a pointer variable in AES rounds. It was valid
-     but spurious and misleading since it looked like a mistaken attempt to
-     zeroize the pointed-to buffer. Reported by Antonio de la Piedra, CEA
-     Leti, France.
diff --git a/ChangeLog.d/android-socklen_t.txt b/ChangeLog.d/android-socklen_t.txt
deleted file mode 100644
index d795a52..0000000
--- a/ChangeLog.d/android-socklen_t.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Use socklen_t on Android and other POSIX-compliant system
-
diff --git a/ChangeLog.d/arc4random_buf-implicit.txt b/ChangeLog.d/arc4random_buf-implicit.txt
deleted file mode 100644
index 81c245e..0000000
--- a/ChangeLog.d/arc4random_buf-implicit.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Make arc4random_buf available on NetBSD and OpenBSD when _POSIX_C_SOURCE is
-     defined. Fix contributed in #3571.
diff --git a/ChangeLog.d/bugfix-2927.txt b/ChangeLog.d/bugfix-2927.txt
deleted file mode 100644
index 2213c6e..0000000
--- a/ChangeLog.d/bugfix-2927.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * In CTR_DRBG and HMAC_DRBG, don't reset the reseed interval in seed().
-     Fixes #2927.
diff --git a/ChangeLog.d/bugfix_3524.txt b/ChangeLog.d/bugfix_3524.txt
deleted file mode 100644
index e038340..0000000
--- a/ChangeLog.d/bugfix_3524.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-  * Include the psa_constant_names generated source code in the source tree
-    instead of generating it at build time. Fixes #3524.
diff --git a/ChangeLog.d/bugfix_3782.txt b/ChangeLog.d/bugfix_3782.txt
deleted file mode 100644
index 25e18cb..0000000
--- a/ChangeLog.d/bugfix_3782.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Bugfix
-  * Fix build failures on GCC 11. Fixes #3782.
diff --git a/ChangeLog.d/bugfix_3794.txt b/ChangeLog.d/bugfix_3794.txt
deleted file mode 100644
index a483ea7..0000000
--- a/ChangeLog.d/bugfix_3794.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Bugfix
-  * Fix handling of EOF against 0xff bytes and on platforms with
-    unsigned chars.  Fixes a build failure on platforms where char is
-    unsigned.  Fixes #3794.
diff --git a/ChangeLog.d/bugfix_PR3294.txt b/ChangeLog.d/bugfix_PR3294.txt
deleted file mode 100644
index a6ea75e..0000000
--- a/ChangeLog.d/bugfix_PR3294.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Bugfix
-   * Fix build failure in configurations where MBEDTLS_USE_PSA_CRYPTO is
-     enabled but ECDSA is disabled. Contributed by jdurkop. Fixes #3294.
-
diff --git a/ChangeLog.d/clean_pem_buffers.txt b/ChangeLog.d/clean_pem_buffers.txt
deleted file mode 100644
index 818fad9..0000000
--- a/ChangeLog.d/clean_pem_buffers.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Bugfix
-  * In PEM writing functions, fill the trailing part of the buffer with null
-    bytes. This guarantees that the corresponding parsing function can read
-    the buffer back, which was the case for mbedtls_x509write_{crt,csr}_pem
-    until this property was inadvertently broken in Mbed TLS 2.19.0.
-    Fixes #3682.
diff --git a/ChangeLog.d/ecb_iv_fix.txt b/ChangeLog.d/ecb_iv_fix.txt
deleted file mode 100644
index ae2ae25..0000000
--- a/ChangeLog.d/ecb_iv_fix.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Correct the default IV size for mbedtls_cipher_info_t structures using
-     MBEDTLS_MODE_ECB to 0, since ECB mode ciphers don't use IVs.
diff --git a/ChangeLog.d/ecp-bignum-error-checks.txt b/ChangeLog.d/ecp-bignum-error-checks.txt
deleted file mode 100644
index 8cad08e..0000000
--- a/ChangeLog.d/ecp-bignum-error-checks.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Bugfix
-   * Fix a memory leak in mbedtls_mpi_sub_abs() when the result was negative
-     (an error condition) and the second operand was aliased to the result.
-   * Fix a case in elliptic curve arithmetic where an out-of-memory condition
-     could go undetected, resulting in an incorrect result.
diff --git a/ChangeLog.d/ecp_curve_list.txt b/ChangeLog.d/ecp_curve_list.txt
deleted file mode 100644
index 55745d3..0000000
--- a/ChangeLog.d/ecp_curve_list.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Bugfix
-   * mbedtls_ecp_curve_list() now lists Curve25519 and Curve448 under the names
-     "x25519" and "x448". These curves support ECDH but not ECDSA. If you need
-     only the curves that support ECDSA, filter the list with
-     mbedtls_ecdsa_can_do().
diff --git a/ChangeLog.d/error-include-string.txt b/ChangeLog.d/error-include-string.txt
deleted file mode 100644
index 0a12c7b..0000000
--- a/ChangeLog.d/error-include-string.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Bugfix
-   * Fix conditions for including string.h in error.c. Fixes #3866.
diff --git a/ChangeLog.d/feature-dtls-srtp.txt b/ChangeLog.d/feature-dtls-srtp.txt
deleted file mode 100644
index 8b9186b..0000000
--- a/ChangeLog.d/feature-dtls-srtp.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Features
-* Add support for DTLS-SRTP as defined in RFC 5764. Contributed by Johan Pascal, improved by Ron Eldor.
diff --git a/ChangeLog.d/fix-rsa-blinding.txt b/ChangeLog.d/fix-rsa-blinding.txt
deleted file mode 100644
index a13572c..0000000
--- a/ChangeLog.d/fix-rsa-blinding.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Bugfix
-   * Fix rsa_prepare_blinding() to retry when the blinding value is not
-     invertible (mod N), instead of returning MBEDTLS_ERR_RSA_RNG_FAILED. This
-     addresses a regression but is rare in practice (approx. 1 in 2/sqrt(N)).
-     Found by Synopsys Coverity, fix contributed by Peter Kolbus (Garmin).
-     Fixes #3647.
diff --git a/ChangeLog.d/fix_ccm_add_length_check.txt b/ChangeLog.d/fix_ccm_add_length_check.txt
deleted file mode 100644
index 259399f..0000000
--- a/ChangeLog.d/fix_ccm_add_length_check.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Bugfix
-   * Fix an off-by-one error in the additional data length check for
-     CCM, which allowed encryption with a non-standard length field.
-     Fixes #3719.
-
diff --git a/ChangeLog.d/minimum_cmake_version_PR3802.txt b/ChangeLog.d/minimum_cmake_version_PR3802.txt
deleted file mode 100644
index 549f9b1..0000000
--- a/ChangeLog.d/minimum_cmake_version_PR3802.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Requirement changes
-* Update the minimum required CMake version to 2.8.12.
-* This silences a warning on CMake 3.19.0. #3801
diff --git a/ChangeLog.d/missing-debug-message-arguments_mbedtls_ssl_decrypt_buf.txt b/ChangeLog.d/missing-debug-message-arguments_mbedtls_ssl_decrypt_buf.txt
deleted file mode 100644
index e03178f..0000000
--- a/ChangeLog.d/missing-debug-message-arguments_mbedtls_ssl_decrypt_buf.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Bugfix
-  * Add missing arguments of debug message in mbedtls_ssl_decrypt_buf.
diff --git a/ChangeLog.d/psa-crypto-api-values-1.0.0.txt b/ChangeLog.d/psa-crypto-api-values-1.0.0.txt
deleted file mode 100644
index 0bd3764..0000000
--- a/ChangeLog.d/psa-crypto-api-values-1.0.0.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-API changes
-   * The numerical values of the PSA Crypto API macros have been updated to
-     conform to version 1.0.0 of the specification.
-   * PSA_ALG_STREAM_CIPHER replaces PSA_ALG_CHACHA20 and PSA_ALG_ARC4.
-     The underlying stream cipher is determined by the key type
-     (PSA_KEY_TYPE_CHACHA20 or PSA_KEY_TYPE_ARC4).
-New deprecations
-   * PSA_KEY_TYPE_CHACHA20 and PSA_KEY_TYPE_ARC4 have been deprecated.
-     Use PSA_ALG_STREAM_CIPHER instead.
diff --git a/ChangeLog.d/psa-openless.txt b/ChangeLog.d/psa-openless.txt
deleted file mode 100644
index 2e40cdf..0000000
--- a/ChangeLog.d/psa-openless.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-Features
-   * In the PSA API, it is no longer necessary to open persistent keys:
-     operations now accept the key identifier. The type psa_key_handle_t is now
-     identical to psa_key_id_t instead of being platform-defined. This bridges
-     the last major gap to compliance with the PSA Cryptography specification
-     version 1.0.0. Opening persistent keys is still supported for backward
-     compatibility, but will be deprecated and later removed in future
-     releases.
-
-Bugfix
-   * psa_set_key_id() now also sets the lifetime to persistent for keys located
-     in a secure element.
-   * Attempting to create a volatile key with a non-zero key identifier now
-     fails. Previously the key identifier was just ignored when creating a
-     volatile key.
-   * Attempting to create or register a key with a key identifier in the vendor
-     range now fails.
diff --git a/ChangeLog.d/psa_error_invalid_argument_for_invalid_cipher_input_sizes.txt b/ChangeLog.d/psa_error_invalid_argument_for_invalid_cipher_input_sizes.txt
deleted file mode 100644
index 85c363b..0000000
--- a/ChangeLog.d/psa_error_invalid_argument_for_invalid_cipher_input_sizes.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Bugfix
-   * Consistently return PSA_ERROR_INVALID_ARGUMENT on invalid cipher input
-     sizes (instead of PSA_ERROR_BAD_STATE in some cases) to make the
-     psa_cipher_* functions compliant with the PSA Crypto API specification.
diff --git a/ChangeLog.d/psa_generate_key-curve25519.txt b/ChangeLog.d/psa_generate_key-curve25519.txt
deleted file mode 100644
index 24b6fcf..0000000
--- a/ChangeLog.d/psa_generate_key-curve25519.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Bugfix
-   * Fix psa_generate_key() returning an error when asked to generate
-     an ECC key pair on Curve25519 or secp244k1.
diff --git a/ChangeLog.d/support-ecdh-kdf-with-ecdh-key.txt b/ChangeLog.d/support-ecdh-kdf-with-ecdh-key.txt
deleted file mode 100644
index 6660dc3..0000000
--- a/ChangeLog.d/support-ecdh-kdf-with-ecdh-key.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Features
-   * In PSA, allow using a key declared with a base key agreement algorithm
-     in combined key agreement and derivation operations, as long as the key
-     agreement algorithm in use matches the algorithm the key was declared with.
-     This is currently non-standard behaviour, but expected to make it into a
-     future revision of the PSA Crypto standard.
diff --git a/ChangeLog.d/support-key-agreement-and-derivation-output-as-key.txt b/ChangeLog.d/support-key-agreement-and-derivation-output-as-key.txt
deleted file mode 100644
index 3f61481..0000000
--- a/ChangeLog.d/support-key-agreement-and-derivation-output-as-key.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Bugfix
-   * Fix psa_key_derivation_output_key() to allow the output of a combined key
-     agreement and subsequent key derivation operation to be used as a key
-     inside of the PSA Crypto core.
diff --git a/ChangeLog.d/systematically_store_bit_size_3740.txt b/ChangeLog.d/systematically_store_bit_size_3740.txt
deleted file mode 100644
index 9e63bbc..0000000
--- a/ChangeLog.d/systematically_store_bit_size_3740.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Changes
-   * The PSA persistent storage format is updated to always store the key bits
-     attribute. No automatic upgrade path is provided. Previously stored keys
-     must be erased, or manually upgraded based on the key storage format
-     specification (docs/architecture/mbed-crypto-storage-specification.md). #3740
diff --git a/doxygen/input/doc_mainpage.h b/doxygen/input/doc_mainpage.h
index c13b279..5b51bd5 100644
--- a/doxygen/input/doc_mainpage.h
+++ b/doxygen/input/doc_mainpage.h
@@ -22,7 +22,7 @@
  */
 
 /**
- * @mainpage mbed TLS v2.24.0 source code documentation
+ * @mainpage mbed TLS v2.25.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 bf33dab..dd4237a 100644
--- a/doxygen/mbedtls.doxyfile
+++ b/doxygen/mbedtls.doxyfile
@@ -28,7 +28,7 @@
 # identify the project. Note that if you do not use Doxywizard you need
 # to put quotes around the project name if it contains spaces.
 
-PROJECT_NAME           = "mbed TLS v2.24.0"
+PROJECT_NAME           = "mbed TLS v2.25.0"
 
 # The PROJECT_NUMBER tag can be used to enter a project or revision number.
 # This could be handy for archiving the generated documentation or
diff --git a/include/mbedtls/cipher.h b/include/mbedtls/cipher.h
index 8827e0b..1cafa6e 100644
--- a/include/mbedtls/cipher.h
+++ b/include/mbedtls/cipher.h
@@ -857,30 +857,52 @@
                   unsigned char *output, size_t *olen );
 
 #if defined(MBEDTLS_CIPHER_MODE_AEAD)
+#if ! defined(MBEDTLS_DEPRECATED_REMOVED)
+#if defined(MBEDTLS_DEPRECATED_WARNING)
+#define MBEDTLS_DEPRECATED    __attribute__((deprecated))
+#else
+#define MBEDTLS_DEPRECATED
+#endif /* MBEDTLS_DEPRECATED_WARNING */
 /**
- * \brief               The generic autenticated encryption (AEAD) function.
+ * \brief               The generic authenticated encryption (AEAD) function.
+ *
+ * \deprecated          Superseded by mbedtls_cipher_auth_encrypt_ext().
+ *
+ * \note                This function only supports AEAD algorithms, not key
+ *                      wrapping algorithms such as NIST_KW; for this, see
+ *                      mbedtls_cipher_auth_encrypt_ext().
  *
  * \param ctx           The generic cipher context. This must be initialized and
- *                      bound to a key.
- * \param iv            The IV to use, or NONCE_COUNTER for CTR-mode ciphers.
- *                      This must be a readable buffer of at least \p iv_len
- *                      Bytes.
- * \param iv_len        The IV length for ciphers with variable-size IV.
- *                      This parameter is discarded by ciphers with fixed-size IV.
+ *                      bound to a key associated with an AEAD algorithm.
+ * \param iv            The nonce to use. This must be a readable buffer of
+ *                      at least \p iv_len Bytes and must not be \c NULL.
+ * \param iv_len        The length of the nonce. This must satisfy the
+ *                      constraints imposed by the AEAD cipher used.
  * \param ad            The additional data to authenticate. This must be a
- *                      readable buffer of at least \p ad_len Bytes.
+ *                      readable buffer of at least \p ad_len Bytes, and may
+ *                      be \c NULL is \p ad_len is \c 0.
  * \param ad_len        The length of \p ad.
  * \param input         The buffer holding the input data. This must be a
- *                      readable buffer of at least \p ilen Bytes.
+ *                      readable buffer of at least \p ilen Bytes, and may be
+ *                      \c NULL if \p ilen is \c 0.
  * \param ilen          The length of the input data.
- * \param output        The buffer for the output data. This must be able to
- *                      hold at least \p ilen Bytes.
- * \param olen          The length of the output data, to be updated with the
- *                      actual number of Bytes written. This must not be
- *                      \c NULL.
+ * \param output        The buffer for the output data. This must be a
+ *                      writable buffer of at least \p ilen Bytes, and must
+ *                      not be \c NULL.
+ * \param olen          This will be filled with the actual number of Bytes
+ *                      written to the \p output buffer. This must point to a
+ *                      writable object of type \c size_t.
  * \param tag           The buffer for the authentication tag. This must be a
- *                      writable buffer of at least \p tag_len Bytes.
- * \param tag_len       The desired length of the authentication tag.
+ *                      writable buffer of at least \p tag_len Bytes. See note
+ *                      below regarding restrictions with PSA-based contexts.
+ * \param tag_len       The desired length of the authentication tag. This
+ *                      must match the constraints imposed by the AEAD cipher
+ *                      used, and in particular must not be \c 0.
+ *
+ * \note                If the context is based on PSA (that is, it was set up
+ *                      with mbedtls_cipher_setup_psa()), then it is required
+ *                      that \c tag == output + ilen. That is, the tag must be
+ *                      appended to the ciphertext as recommended by RFC 5116.
  *
  * \return              \c 0 on success.
  * \return              #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on
@@ -892,36 +914,53 @@
                          const unsigned char *ad, size_t ad_len,
                          const unsigned char *input, size_t ilen,
                          unsigned char *output, size_t *olen,
-                         unsigned char *tag, size_t tag_len );
+                         unsigned char *tag, size_t tag_len )
+                         MBEDTLS_DEPRECATED;
 
 /**
- * \brief               The generic autenticated decryption (AEAD) function.
+ * \brief               The generic authenticated decryption (AEAD) function.
+ *
+ * \deprecated          Superseded by mbedtls_cipher_auth_decrypt_ext().
+ *
+ * \note                This function only supports AEAD algorithms, not key
+ *                      wrapping algorithms such as NIST_KW; for this, see
+ *                      mbedtls_cipher_auth_decrypt_ext().
  *
  * \note                If the data is not authentic, then the output buffer
  *                      is zeroed out to prevent the unauthentic plaintext being
  *                      used, making this interface safer.
  *
  * \param ctx           The generic cipher context. This must be initialized and
- *                      and bound to a key.
- * \param iv            The IV to use, or NONCE_COUNTER for CTR-mode ciphers.
- *                      This must be a readable buffer of at least \p iv_len
- *                      Bytes.
- * \param iv_len        The IV length for ciphers with variable-size IV.
- *                      This parameter is discarded by ciphers with fixed-size IV.
- * \param ad            The additional data to be authenticated. This must be a
- *                      readable buffer of at least \p ad_len Bytes.
+ *                      bound to a key associated with an AEAD algorithm.
+ * \param iv            The nonce to use. This must be a readable buffer of
+ *                      at least \p iv_len Bytes and must not be \c NULL.
+ * \param iv_len        The length of the nonce. This must satisfy the
+ *                      constraints imposed by the AEAD cipher used.
+ * \param ad            The additional data to authenticate. This must be a
+ *                      readable buffer of at least \p ad_len Bytes, and may
+ *                      be \c NULL is \p ad_len is \c 0.
  * \param ad_len        The length of \p ad.
  * \param input         The buffer holding the input data. This must be a
- *                      readable buffer of at least \p ilen Bytes.
+ *                      readable buffer of at least \p ilen Bytes, and may be
+ *                      \c NULL if \p ilen is \c 0.
  * \param ilen          The length of the input data.
- * \param output        The buffer for the output data.
- *                      This must be able to hold at least \p ilen Bytes.
- * \param olen          The length of the output data, to be updated with the
- *                      actual number of Bytes written. This must not be
- *                      \c NULL.
- * \param tag           The buffer holding the authentication tag. This must be
- *                      a readable buffer of at least \p tag_len Bytes.
- * \param tag_len       The length of the authentication tag.
+ * \param output        The buffer for the output data. This must be a
+ *                      writable buffer of at least \p ilen Bytes, and must
+ *                      not be \c NULL.
+ * \param olen          This will be filled with the actual number of Bytes
+ *                      written to the \p output buffer. This must point to a
+ *                      writable object of type \c size_t.
+ * \param tag           The buffer for the authentication tag. This must be a
+ *                      readable buffer of at least \p tag_len Bytes. See note
+ *                      below regarding restrictions with PSA-based contexts.
+ * \param tag_len       The length of the authentication tag. This must match
+ *                      the constraints imposed by the AEAD cipher used, and in
+ *                      particular must not be \c 0.
+ *
+ * \note                If the context is based on PSA (that is, it was set up
+ *                      with mbedtls_cipher_setup_psa()), then it is required
+ *                      that \c tag == input + len. That is, the tag must be
+ *                      appended to the ciphertext as recommended by RFC 5116.
  *
  * \return              \c 0 on success.
  * \return              #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on
@@ -934,9 +973,120 @@
                          const unsigned char *ad, size_t ad_len,
                          const unsigned char *input, size_t ilen,
                          unsigned char *output, size_t *olen,
-                         const unsigned char *tag, size_t tag_len );
+                         const unsigned char *tag, size_t tag_len )
+                         MBEDTLS_DEPRECATED;
+#undef MBEDTLS_DEPRECATED
+#endif /* MBEDTLS_DEPRECATED_REMOVED */
 #endif /* MBEDTLS_CIPHER_MODE_AEAD */
 
+#if defined(MBEDTLS_CIPHER_MODE_AEAD) || defined(MBEDTLS_NIST_KW_C)
+/**
+ * \brief               The authenticated encryption (AEAD/NIST_KW) function.
+ *
+ * \note                For AEAD modes, the tag will be appended to the
+ *                      ciphertext, as recommended by RFC 5116.
+ *                      (NIST_KW doesn't have a separate tag.)
+ *
+ * \param ctx           The generic cipher context. This must be initialized and
+ *                      bound to a key, with an AEAD algorithm or NIST_KW.
+ * \param iv            The nonce to use. This must be a readable buffer of
+ *                      at least \p iv_len Bytes and may be \c NULL if \p
+ *                      iv_len is \c 0.
+ * \param iv_len        The length of the nonce. For AEAD ciphers, this must
+ *                      satisfy the constraints imposed by the cipher used.
+ *                      For NIST_KW, this must be \c 0.
+ * \param ad            The additional data to authenticate. This must be a
+ *                      readable buffer of at least \p ad_len Bytes, and may
+ *                      be \c NULL is \p ad_len is \c 0.
+ * \param ad_len        The length of \p ad. For NIST_KW, this must be \c 0.
+ * \param input         The buffer holding the input data. This must be a
+ *                      readable buffer of at least \p ilen Bytes, and may be
+ *                      \c NULL if \p ilen is \c 0.
+ * \param ilen          The length of the input data.
+ * \param output        The buffer for the output data. This must be a
+ *                      writable buffer of at least \p output_len Bytes, and
+ *                      must not be \c NULL.
+ * \param output_len    The length of the \p output buffer in Bytes. For AEAD
+ *                      ciphers, this must be at least \p ilen + \p tag_len.
+ *                      For NIST_KW, this must be at least \p ilen + 8
+ *                      (rounded up to a multiple of 8 if KWP is used);
+ *                      \p ilen + 15 is always a safe value.
+ * \param olen          This will be filled with the actual number of Bytes
+ *                      written to the \p output buffer. This must point to a
+ *                      writable object of type \c size_t.
+ * \param tag_len       The desired length of the authentication tag. For AEAD
+ *                      ciphers, this must match the constraints imposed by
+ *                      the cipher used, and in particular must not be \c 0.
+ *                      For NIST_KW, this must be \c 0.
+ *
+ * \return              \c 0 on success.
+ * \return              #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on
+ *                      parameter-verification failure.
+ * \return              A cipher-specific error code on failure.
+ */
+int mbedtls_cipher_auth_encrypt_ext( mbedtls_cipher_context_t *ctx,
+                         const unsigned char *iv, size_t iv_len,
+                         const unsigned char *ad, size_t ad_len,
+                         const unsigned char *input, size_t ilen,
+                         unsigned char *output, size_t output_len,
+                         size_t *olen, size_t tag_len );
+
+/**
+ * \brief               The authenticated encryption (AEAD/NIST_KW) function.
+ *
+ * \note                If the data is not authentic, then the output buffer
+ *                      is zeroed out to prevent the unauthentic plaintext being
+ *                      used, making this interface safer.
+ *
+ * \note                For AEAD modes, the tag must be appended to the
+ *                      ciphertext, as recommended by RFC 5116.
+ *                      (NIST_KW doesn't have a separate tag.)
+ *
+ * \param ctx           The generic cipher context. This must be initialized and
+ *                      bound to a key, with an AEAD algorithm or NIST_KW.
+ * \param iv            The nonce to use. This must be a readable buffer of
+ *                      at least \p iv_len Bytes and may be \c NULL if \p
+ *                      iv_len is \c 0.
+ * \param iv_len        The length of the nonce. For AEAD ciphers, this must
+ *                      satisfy the constraints imposed by the cipher used.
+ *                      For NIST_KW, this must be \c 0.
+ * \param ad            The additional data to authenticate. This must be a
+ *                      readable buffer of at least \p ad_len Bytes, and may
+ *                      be \c NULL is \p ad_len is \c 0.
+ * \param ad_len        The length of \p ad. For NIST_KW, this must be \c 0.
+ * \param input         The buffer holding the input data. This must be a
+ *                      readable buffer of at least \p ilen Bytes, and may be
+ *                      \c NULL if \p ilen is \c 0.
+ * \param ilen          The length of the input data. For AEAD ciphers this
+ *                      must be at least \p tag_len. For NIST_KW this must be
+ *                      at least \c 8.
+ * \param output        The buffer for the output data. This must be a
+ *                      writable buffer of at least \p output_len Bytes, and
+ *                      may be \c NULL if \p output_len is \c 0.
+ * \param output_len    The length of the \p output buffer in Bytes. For AEAD
+ *                      ciphers, this must be at least \p ilen - \p tag_len.
+ *                      For NIST_KW, this must be at least \p ilen - 8.
+ * \param olen          This will be filled with the actual number of Bytes
+ *                      written to the \p output buffer. This must point to a
+ *                      writable object of type \c size_t.
+ * \param tag_len       The actual length of the authentication tag. For AEAD
+ *                      ciphers, this must match the constraints imposed by
+ *                      the cipher used, and in particular must not be \c 0.
+ *                      For NIST_KW, this must be \c 0.
+ *
+ * \return              \c 0 on success.
+ * \return              #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on
+ *                      parameter-verification failure.
+ * \return              #MBEDTLS_ERR_CIPHER_AUTH_FAILED if data is not authentic.
+ * \return              A cipher-specific error code on failure.
+ */
+int mbedtls_cipher_auth_decrypt_ext( mbedtls_cipher_context_t *ctx,
+                         const unsigned char *iv, size_t iv_len,
+                         const unsigned char *ad, size_t ad_len,
+                         const unsigned char *input, size_t ilen,
+                         unsigned char *output, size_t output_len,
+                         size_t *olen, size_t tag_len );
+#endif /* MBEDTLS_CIPHER_MODE_AEAD || MBEDTLS_NIST_KW_C */
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/mbedtls/version.h b/include/mbedtls/version.h
index 665a283..10c4316 100644
--- a/include/mbedtls/version.h
+++ b/include/mbedtls/version.h
@@ -37,7 +37,7 @@
  * Major, Minor, Patchlevel
  */
 #define MBEDTLS_VERSION_MAJOR  2
-#define MBEDTLS_VERSION_MINOR  24
+#define MBEDTLS_VERSION_MINOR  25
 #define MBEDTLS_VERSION_PATCH  0
 
 /**
@@ -45,9 +45,9 @@
  *    MMNNPP00
  *    Major version | Minor version | Patch version
  */
-#define MBEDTLS_VERSION_NUMBER         0x02180000
-#define MBEDTLS_VERSION_STRING         "2.24.0"
-#define MBEDTLS_VERSION_STRING_FULL    "mbed TLS 2.24.0"
+#define MBEDTLS_VERSION_NUMBER         0x02190000
+#define MBEDTLS_VERSION_STRING         "2.25.0"
+#define MBEDTLS_VERSION_STRING_FULL    "mbed TLS 2.25.0"
 
 #if defined(MBEDTLS_VERSION_C)
 
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index 8962555..b309b6e 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -193,15 +193,15 @@
 
 if(USE_SHARED_MBEDTLS_LIBRARY)
     add_library(${mbedcrypto_target} SHARED ${src_crypto})
-    set_target_properties(${mbedcrypto_target} PROPERTIES VERSION 2.24.0 SOVERSION 5)
+    set_target_properties(${mbedcrypto_target} PROPERTIES VERSION 2.25.0 SOVERSION 6)
     target_link_libraries(${mbedcrypto_target} PUBLIC ${libs})
 
     add_library(${mbedx509_target} SHARED ${src_x509})
-    set_target_properties(${mbedx509_target} PROPERTIES VERSION 2.24.0 SOVERSION 1)
+    set_target_properties(${mbedx509_target} PROPERTIES VERSION 2.25.0 SOVERSION 1)
     target_link_libraries(${mbedx509_target} PUBLIC ${libs} ${mbedcrypto_target})
 
     add_library(${mbedtls_target} SHARED ${src_tls})
-    set_target_properties(${mbedtls_target} PROPERTIES VERSION 2.24.0 SOVERSION 13)
+    set_target_properties(${mbedtls_target} PROPERTIES VERSION 2.25.0 SOVERSION 13)
     target_link_libraries(${mbedtls_target} PUBLIC ${libs} ${mbedx509_target})
 endif(USE_SHARED_MBEDTLS_LIBRARY)
 
diff --git a/library/Makefile b/library/Makefile
index a6db9b3..ae33bf2 100644
--- a/library/Makefile
+++ b/library/Makefile
@@ -41,7 +41,7 @@
 
 SOEXT_TLS=so.13
 SOEXT_X509=so.1
-SOEXT_CRYPTO=so.5
+SOEXT_CRYPTO=so.6
 
 # Set AR_DASH= (empty string) to use an ar implementation that does not accept
 # the - prefix for command line options (e.g. llvm-ar)
diff --git a/library/bignum.c b/library/bignum.c
index b11239e..9cc5d66 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -2118,6 +2118,10 @@
     if( mbedtls_mpi_cmp_int( E, 0 ) < 0 )
         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
 
+    if( mbedtls_mpi_bitlen( E ) > MBEDTLS_MPI_MAX_BITS ||
+        mbedtls_mpi_bitlen( N ) > MBEDTLS_MPI_MAX_BITS )
+        return ( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+
     /*
      * Init temps and window size
      */
@@ -2394,7 +2398,7 @@
     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
 
     Xp = (unsigned char*) X->p;
-    f_rng( p_rng, Xp + overhead, size );
+    MBEDTLS_MPI_CHK( f_rng( p_rng, Xp + overhead, size ) );
 
     mpi_bigendian_to_host( X->p, limbs );
 
diff --git a/library/cipher.c b/library/cipher.c
index 853eeec..457f8f6 100644
--- a/library/cipher.c
+++ b/library/cipher.c
@@ -1288,23 +1288,16 @@
 
 #if defined(MBEDTLS_CIPHER_MODE_AEAD)
 /*
- * Packet-oriented encryption for AEAD modes
+ * Packet-oriented encryption for AEAD modes: internal function shared by
+ * mbedtls_cipher_auth_encrypt() and mbedtls_cipher_auth_encrypt_ext().
  */
-int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx,
+static int mbedtls_cipher_aead_encrypt( mbedtls_cipher_context_t *ctx,
                          const unsigned char *iv, size_t iv_len,
                          const unsigned char *ad, size_t ad_len,
                          const unsigned char *input, size_t ilen,
                          unsigned char *output, size_t *olen,
                          unsigned char *tag, size_t tag_len )
 {
-    CIPHER_VALIDATE_RET( ctx != NULL );
-    CIPHER_VALIDATE_RET( iv != NULL );
-    CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL );
-    CIPHER_VALIDATE_RET( ilen == 0 || input != NULL );
-    CIPHER_VALIDATE_RET( output != NULL );
-    CIPHER_VALIDATE_RET( olen != NULL );
-    CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL );
-
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     if( ctx->psa_enabled == 1 )
     {
@@ -1320,7 +1313,7 @@
 
         /* PSA Crypto API always writes the authentication tag
          * at the end of the encrypted message. */
-        if( tag != output + ilen )
+        if( output == NULL || tag != output + ilen )
             return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
 
         status = psa_aead_encrypt( cipher_psa->slot,
@@ -1370,44 +1363,21 @@
                                 ilen, iv, ad, ad_len, input, output, tag ) );
     }
 #endif /* MBEDTLS_CHACHAPOLY_C */
-#if defined(MBEDTLS_NIST_KW_C)
-   if( MBEDTLS_MODE_KW == ctx->cipher_info->mode ||
-       MBEDTLS_MODE_KWP == ctx->cipher_info->mode )
-    {
-        mbedtls_nist_kw_mode_t mode = ( MBEDTLS_MODE_KW == ctx->cipher_info->mode ) ?
-                                        MBEDTLS_KW_MODE_KW : MBEDTLS_KW_MODE_KWP;
-
-        /* There is no iv, tag or ad associated with KW and KWP, these length should be 0 */
-        if( iv_len != 0 || tag_len != 0 || ad_len != 0 )
-        {
-            return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
-        }
-
-        return( mbedtls_nist_kw_wrap( ctx->cipher_ctx, mode, input, ilen, output, olen, SIZE_MAX ) );
-    }
-#endif /* MBEDTLS_NIST_KW_C */
 
     return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
 }
 
 /*
- * Packet-oriented decryption for AEAD modes
+ * Packet-oriented encryption for AEAD modes: internal function shared by
+ * mbedtls_cipher_auth_encrypt() and mbedtls_cipher_auth_encrypt_ext().
  */
-int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx,
+static int mbedtls_cipher_aead_decrypt( mbedtls_cipher_context_t *ctx,
                          const unsigned char *iv, size_t iv_len,
                          const unsigned char *ad, size_t ad_len,
                          const unsigned char *input, size_t ilen,
                          unsigned char *output, size_t *olen,
                          const unsigned char *tag, size_t tag_len )
 {
-    CIPHER_VALIDATE_RET( ctx != NULL );
-    CIPHER_VALIDATE_RET( iv != NULL );
-    CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL );
-    CIPHER_VALIDATE_RET( ilen == 0 || input != NULL );
-    CIPHER_VALIDATE_RET( output != NULL );
-    CIPHER_VALIDATE_RET( olen != NULL );
-    CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL );
-
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     if( ctx->psa_enabled == 1 )
     {
@@ -1423,7 +1393,7 @@
 
         /* PSA Crypto API always writes the authentication tag
          * at the end of the encrypted message. */
-        if( tag != input + ilen )
+        if( input == NULL || tag != input + ilen )
             return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
 
         status = psa_aead_decrypt( cipher_psa->slot,
@@ -1495,25 +1465,169 @@
         return( ret );
     }
 #endif /* MBEDTLS_CHACHAPOLY_C */
+
+    return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
+}
+
+#if !defined(MBEDTLS_DEPRECATED_REMOVED)
+/*
+ * Packet-oriented encryption for AEAD modes: public legacy function.
+ */
+int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx,
+                         const unsigned char *iv, size_t iv_len,
+                         const unsigned char *ad, size_t ad_len,
+                         const unsigned char *input, size_t ilen,
+                         unsigned char *output, size_t *olen,
+                         unsigned char *tag, size_t tag_len )
+{
+    CIPHER_VALIDATE_RET( ctx != NULL );
+    CIPHER_VALIDATE_RET( iv_len == 0 || iv != NULL );
+    CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL );
+    CIPHER_VALIDATE_RET( ilen == 0 || input != NULL );
+    CIPHER_VALIDATE_RET( ilen == 0 || output != NULL );
+    CIPHER_VALIDATE_RET( olen != NULL );
+    CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL );
+
+    return( mbedtls_cipher_aead_encrypt( ctx, iv, iv_len, ad, ad_len,
+                                         input, ilen, output, olen,
+                                         tag, tag_len ) );
+}
+
+/*
+ * Packet-oriented decryption for AEAD modes: public legacy function.
+ */
+int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx,
+                         const unsigned char *iv, size_t iv_len,
+                         const unsigned char *ad, size_t ad_len,
+                         const unsigned char *input, size_t ilen,
+                         unsigned char *output, size_t *olen,
+                         const unsigned char *tag, size_t tag_len )
+{
+    CIPHER_VALIDATE_RET( ctx != NULL );
+    CIPHER_VALIDATE_RET( iv_len == 0 || iv != NULL );
+    CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL );
+    CIPHER_VALIDATE_RET( ilen == 0 || input != NULL );
+    CIPHER_VALIDATE_RET( ilen == 0 || output != NULL );
+    CIPHER_VALIDATE_RET( olen != NULL );
+    CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL );
+
+    return( mbedtls_cipher_aead_decrypt( ctx, iv, iv_len, ad, ad_len,
+                                         input, ilen, output, olen,
+                                         tag, tag_len ) );
+}
+#endif /* !MBEDTLS_DEPRECATED_REMOVED */
+#endif /* MBEDTLS_CIPHER_MODE_AEAD */
+
+#if defined(MBEDTLS_CIPHER_MODE_AEAD) || defined(MBEDTLS_NIST_KW_C)
+/*
+ * Packet-oriented encryption for AEAD/NIST_KW: public function.
+ */
+int mbedtls_cipher_auth_encrypt_ext( mbedtls_cipher_context_t *ctx,
+                         const unsigned char *iv, size_t iv_len,
+                         const unsigned char *ad, size_t ad_len,
+                         const unsigned char *input, size_t ilen,
+                         unsigned char *output, size_t output_len,
+                         size_t *olen, size_t tag_len )
+{
+    CIPHER_VALIDATE_RET( ctx != NULL );
+    CIPHER_VALIDATE_RET( iv_len == 0 || iv != NULL );
+    CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL );
+    CIPHER_VALIDATE_RET( ilen == 0 || input != NULL );
+    CIPHER_VALIDATE_RET( output != NULL );
+    CIPHER_VALIDATE_RET( olen != NULL );
+
 #if defined(MBEDTLS_NIST_KW_C)
-    if( MBEDTLS_MODE_KW == ctx->cipher_info->mode ||
-        MBEDTLS_MODE_KWP == ctx->cipher_info->mode )
+    if(
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+        ctx->psa_enabled == 0 &&
+#endif
+        ( MBEDTLS_MODE_KW == ctx->cipher_info->mode ||
+          MBEDTLS_MODE_KWP == ctx->cipher_info->mode ) )
     {
         mbedtls_nist_kw_mode_t mode = ( MBEDTLS_MODE_KW == ctx->cipher_info->mode ) ?
                                         MBEDTLS_KW_MODE_KW : MBEDTLS_KW_MODE_KWP;
 
-        /* There is no iv, tag or ad associated with KW and KWP, these length should be 0 */
+        /* There is no iv, tag or ad associated with KW and KWP,
+         * so these length should be 0 as documented. */
         if( iv_len != 0 || tag_len != 0 || ad_len != 0 )
-        {
             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
-        }
 
-        return( mbedtls_nist_kw_unwrap( ctx->cipher_ctx, mode, input, ilen, output, olen, SIZE_MAX ) );
+        (void) iv;
+        (void) ad;
+
+        return( mbedtls_nist_kw_wrap( ctx->cipher_ctx, mode, input, ilen,
+                                      output, olen, output_len ) );
     }
 #endif /* MBEDTLS_NIST_KW_C */
 
+#if defined(MBEDTLS_CIPHER_MODE_AEAD)
+    /* AEAD case: check length before passing on to shared function */
+    if( output_len < ilen + tag_len )
+        return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+
+    int ret = mbedtls_cipher_aead_encrypt( ctx, iv, iv_len, ad, ad_len,
+                                       input, ilen, output, olen,
+                                       output + ilen, tag_len );
+    *olen += tag_len;
+    return( ret );
+#else
     return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
-}
 #endif /* MBEDTLS_CIPHER_MODE_AEAD */
+}
+
+/*
+ * Packet-oriented decryption for AEAD/NIST_KW: public function.
+ */
+int mbedtls_cipher_auth_decrypt_ext( mbedtls_cipher_context_t *ctx,
+                         const unsigned char *iv, size_t iv_len,
+                         const unsigned char *ad, size_t ad_len,
+                         const unsigned char *input, size_t ilen,
+                         unsigned char *output, size_t output_len,
+                         size_t *olen, size_t tag_len )
+{
+    CIPHER_VALIDATE_RET( ctx != NULL );
+    CIPHER_VALIDATE_RET( iv_len == 0 || iv != NULL );
+    CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL );
+    CIPHER_VALIDATE_RET( ilen == 0 || input != NULL );
+    CIPHER_VALIDATE_RET( output_len == 0 || output != NULL );
+    CIPHER_VALIDATE_RET( olen != NULL );
+
+#if defined(MBEDTLS_NIST_KW_C)
+    if(
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+        ctx->psa_enabled == 0 &&
+#endif
+        ( MBEDTLS_MODE_KW == ctx->cipher_info->mode ||
+          MBEDTLS_MODE_KWP == ctx->cipher_info->mode ) )
+    {
+        mbedtls_nist_kw_mode_t mode = ( MBEDTLS_MODE_KW == ctx->cipher_info->mode ) ?
+                                        MBEDTLS_KW_MODE_KW : MBEDTLS_KW_MODE_KWP;
+
+        /* There is no iv, tag or ad associated with KW and KWP,
+         * so these length should be 0 as documented. */
+        if( iv_len != 0 || tag_len != 0 || ad_len != 0 )
+            return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+
+        (void) iv;
+        (void) ad;
+
+        return( mbedtls_nist_kw_unwrap( ctx->cipher_ctx, mode, input, ilen,
+                                        output, olen, output_len ) );
+    }
+#endif /* MBEDTLS_NIST_KW_C */
+
+#if defined(MBEDTLS_CIPHER_MODE_AEAD)
+    /* AEAD case: check length before passing on to shared function */
+    if( ilen < tag_len || output_len < ilen - tag_len )
+        return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+
+    return( mbedtls_cipher_aead_decrypt( ctx, iv, iv_len, ad, ad_len,
+                                         input, ilen - tag_len, output, olen,
+                                         input + ilen - tag_len, tag_len ) );
+#else
+    return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
+#endif /* MBEDTLS_CIPHER_MODE_AEAD */
+}
+#endif /* MBEDTLS_CIPHER_MODE_AEAD || MBEDTLS_NIST_KW_C */
 
 #endif /* MBEDTLS_CIPHER_C */
diff --git a/library/md2.c b/library/md2.c
index b4f7cc6..7264e30 100644
--- a/library/md2.c
+++ b/library/md2.c
@@ -147,6 +147,9 @@
         t  = ctx->cksum[i];
     }
 
+    /* Zeroise variables to clear sensitive data from memory. */
+    mbedtls_platform_zeroize( &t, sizeof( t ) );
+
     return( 0 );
 }
 
diff --git a/library/md4.c b/library/md4.c
index 1cac0a4..4fd6bc3 100644
--- a/library/md4.c
+++ b/library/md4.c
@@ -113,31 +113,34 @@
 int mbedtls_internal_md4_process( mbedtls_md4_context *ctx,
                                   const unsigned char data[64] )
 {
-    uint32_t X[16], A, B, C, D;
+    struct
+    {
+        uint32_t X[16], A, B, C, D;
+    } local;
 
-    GET_UINT32_LE( X[ 0], data,  0 );
-    GET_UINT32_LE( X[ 1], data,  4 );
-    GET_UINT32_LE( X[ 2], data,  8 );
-    GET_UINT32_LE( X[ 3], data, 12 );
-    GET_UINT32_LE( X[ 4], data, 16 );
-    GET_UINT32_LE( X[ 5], data, 20 );
-    GET_UINT32_LE( X[ 6], data, 24 );
-    GET_UINT32_LE( X[ 7], data, 28 );
-    GET_UINT32_LE( X[ 8], data, 32 );
-    GET_UINT32_LE( X[ 9], data, 36 );
-    GET_UINT32_LE( X[10], data, 40 );
-    GET_UINT32_LE( X[11], data, 44 );
-    GET_UINT32_LE( X[12], data, 48 );
-    GET_UINT32_LE( X[13], data, 52 );
-    GET_UINT32_LE( X[14], data, 56 );
-    GET_UINT32_LE( X[15], data, 60 );
+    GET_UINT32_LE( local.X[ 0], data,  0 );
+    GET_UINT32_LE( local.X[ 1], data,  4 );
+    GET_UINT32_LE( local.X[ 2], data,  8 );
+    GET_UINT32_LE( local.X[ 3], data, 12 );
+    GET_UINT32_LE( local.X[ 4], data, 16 );
+    GET_UINT32_LE( local.X[ 5], data, 20 );
+    GET_UINT32_LE( local.X[ 6], data, 24 );
+    GET_UINT32_LE( local.X[ 7], data, 28 );
+    GET_UINT32_LE( local.X[ 8], data, 32 );
+    GET_UINT32_LE( local.X[ 9], data, 36 );
+    GET_UINT32_LE( local.X[10], data, 40 );
+    GET_UINT32_LE( local.X[11], data, 44 );
+    GET_UINT32_LE( local.X[12], data, 48 );
+    GET_UINT32_LE( local.X[13], data, 52 );
+    GET_UINT32_LE( local.X[14], data, 56 );
+    GET_UINT32_LE( local.X[15], data, 60 );
 
 #define S(x,n) (((x) << (n)) | (((x) & 0xFFFFFFFF) >> (32 - (n))))
 
-    A = ctx->state[0];
-    B = ctx->state[1];
-    C = ctx->state[2];
-    D = ctx->state[3];
+    local.A = ctx->state[0];
+    local.B = ctx->state[1];
+    local.C = ctx->state[2];
+    local.D = ctx->state[3];
 
 #define F(x, y, z) (((x) & (y)) | ((~(x)) & (z)))
 #define P(a,b,c,d,x,s)                           \
@@ -148,22 +151,22 @@
     } while( 0 )
 
 
-    P( A, B, C, D, X[ 0],  3 );
-    P( D, A, B, C, X[ 1],  7 );
-    P( C, D, A, B, X[ 2], 11 );
-    P( B, C, D, A, X[ 3], 19 );
-    P( A, B, C, D, X[ 4],  3 );
-    P( D, A, B, C, X[ 5],  7 );
-    P( C, D, A, B, X[ 6], 11 );
-    P( B, C, D, A, X[ 7], 19 );
-    P( A, B, C, D, X[ 8],  3 );
-    P( D, A, B, C, X[ 9],  7 );
-    P( C, D, A, B, X[10], 11 );
-    P( B, C, D, A, X[11], 19 );
-    P( A, B, C, D, X[12],  3 );
-    P( D, A, B, C, X[13],  7 );
-    P( C, D, A, B, X[14], 11 );
-    P( B, C, D, A, X[15], 19 );
+    P( local.A, local.B, local.C, local.D, local.X[ 0],  3 );
+    P( local.D, local.A, local.B, local.C, local.X[ 1],  7 );
+    P( local.C, local.D, local.A, local.B, local.X[ 2], 11 );
+    P( local.B, local.C, local.D, local.A, local.X[ 3], 19 );
+    P( local.A, local.B, local.C, local.D, local.X[ 4],  3 );
+    P( local.D, local.A, local.B, local.C, local.X[ 5],  7 );
+    P( local.C, local.D, local.A, local.B, local.X[ 6], 11 );
+    P( local.B, local.C, local.D, local.A, local.X[ 7], 19 );
+    P( local.A, local.B, local.C, local.D, local.X[ 8],  3 );
+    P( local.D, local.A, local.B, local.C, local.X[ 9],  7 );
+    P( local.C, local.D, local.A, local.B, local.X[10], 11 );
+    P( local.B, local.C, local.D, local.A, local.X[11], 19 );
+    P( local.A, local.B, local.C, local.D, local.X[12],  3 );
+    P( local.D, local.A, local.B, local.C, local.X[13],  7 );
+    P( local.C, local.D, local.A, local.B, local.X[14], 11 );
+    P( local.B, local.C, local.D, local.A, local.X[15], 19 );
 
 #undef P
 #undef F
@@ -176,22 +179,22 @@
         (a) = S((a),(s));                               \
     } while( 0 )
 
-    P( A, B, C, D, X[ 0],  3 );
-    P( D, A, B, C, X[ 4],  5 );
-    P( C, D, A, B, X[ 8],  9 );
-    P( B, C, D, A, X[12], 13 );
-    P( A, B, C, D, X[ 1],  3 );
-    P( D, A, B, C, X[ 5],  5 );
-    P( C, D, A, B, X[ 9],  9 );
-    P( B, C, D, A, X[13], 13 );
-    P( A, B, C, D, X[ 2],  3 );
-    P( D, A, B, C, X[ 6],  5 );
-    P( C, D, A, B, X[10],  9 );
-    P( B, C, D, A, X[14], 13 );
-    P( A, B, C, D, X[ 3],  3 );
-    P( D, A, B, C, X[ 7],  5 );
-    P( C, D, A, B, X[11],  9 );
-    P( B, C, D, A, X[15], 13 );
+    P( local.A, local.B, local.C, local.D, local.X[ 0],  3 );
+    P( local.D, local.A, local.B, local.C, local.X[ 4],  5 );
+    P( local.C, local.D, local.A, local.B, local.X[ 8],  9 );
+    P( local.B, local.C, local.D, local.A, local.X[12], 13 );
+    P( local.A, local.B, local.C, local.D, local.X[ 1],  3 );
+    P( local.D, local.A, local.B, local.C, local.X[ 5],  5 );
+    P( local.C, local.D, local.A, local.B, local.X[ 9],  9 );
+    P( local.B, local.C, local.D, local.A, local.X[13], 13 );
+    P( local.A, local.B, local.C, local.D, local.X[ 2],  3 );
+    P( local.D, local.A, local.B, local.C, local.X[ 6],  5 );
+    P( local.C, local.D, local.A, local.B, local.X[10],  9 );
+    P( local.B, local.C, local.D, local.A, local.X[14], 13 );
+    P( local.A, local.B, local.C, local.D, local.X[ 3],  3 );
+    P( local.D, local.A, local.B, local.C, local.X[ 7],  5 );
+    P( local.C, local.D, local.A, local.B, local.X[11],  9 );
+    P( local.B, local.C, local.D, local.A, local.X[15], 13 );
 
 #undef P
 #undef F
@@ -204,30 +207,33 @@
         (a) = S((a),(s));                               \
     } while( 0 )
 
-    P( A, B, C, D, X[ 0],  3 );
-    P( D, A, B, C, X[ 8],  9 );
-    P( C, D, A, B, X[ 4], 11 );
-    P( B, C, D, A, X[12], 15 );
-    P( A, B, C, D, X[ 2],  3 );
-    P( D, A, B, C, X[10],  9 );
-    P( C, D, A, B, X[ 6], 11 );
-    P( B, C, D, A, X[14], 15 );
-    P( A, B, C, D, X[ 1],  3 );
-    P( D, A, B, C, X[ 9],  9 );
-    P( C, D, A, B, X[ 5], 11 );
-    P( B, C, D, A, X[13], 15 );
-    P( A, B, C, D, X[ 3],  3 );
-    P( D, A, B, C, X[11],  9 );
-    P( C, D, A, B, X[ 7], 11 );
-    P( B, C, D, A, X[15], 15 );
+    P( local.A, local.B, local.C, local.D, local.X[ 0],  3 );
+    P( local.D, local.A, local.B, local.C, local.X[ 8],  9 );
+    P( local.C, local.D, local.A, local.B, local.X[ 4], 11 );
+    P( local.B, local.C, local.D, local.A, local.X[12], 15 );
+    P( local.A, local.B, local.C, local.D, local.X[ 2],  3 );
+    P( local.D, local.A, local.B, local.C, local.X[10],  9 );
+    P( local.C, local.D, local.A, local.B, local.X[ 6], 11 );
+    P( local.B, local.C, local.D, local.A, local.X[14], 15 );
+    P( local.A, local.B, local.C, local.D, local.X[ 1],  3 );
+    P( local.D, local.A, local.B, local.C, local.X[ 9],  9 );
+    P( local.C, local.D, local.A, local.B, local.X[ 5], 11 );
+    P( local.B, local.C, local.D, local.A, local.X[13], 15 );
+    P( local.A, local.B, local.C, local.D, local.X[ 3],  3 );
+    P( local.D, local.A, local.B, local.C, local.X[11],  9 );
+    P( local.C, local.D, local.A, local.B, local.X[ 7], 11 );
+    P( local.B, local.C, local.D, local.A, local.X[15], 15 );
 
 #undef F
 #undef P
 
-    ctx->state[0] += A;
-    ctx->state[1] += B;
-    ctx->state[2] += C;
-    ctx->state[3] += D;
+    ctx->state[0] += local.A;
+    ctx->state[1] += local.B;
+    ctx->state[2] += local.C;
+    ctx->state[3] += local.D;
+
+    /* Zeroise variables to clear sensitive data from memory. */
+    mbedtls_platform_zeroize( &local, sizeof( local ) );
 
     return( 0 );
 }
diff --git a/library/md5.c b/library/md5.c
index 1e702b4..c4f2dbf 100644
--- a/library/md5.c
+++ b/library/md5.c
@@ -112,128 +112,134 @@
 int mbedtls_internal_md5_process( mbedtls_md5_context *ctx,
                                   const unsigned char data[64] )
 {
-    uint32_t X[16], A, B, C, D;
+    struct
+    {
+        uint32_t X[16], A, B, C, D;
+    } local;
 
-    GET_UINT32_LE( X[ 0], data,  0 );
-    GET_UINT32_LE( X[ 1], data,  4 );
-    GET_UINT32_LE( X[ 2], data,  8 );
-    GET_UINT32_LE( X[ 3], data, 12 );
-    GET_UINT32_LE( X[ 4], data, 16 );
-    GET_UINT32_LE( X[ 5], data, 20 );
-    GET_UINT32_LE( X[ 6], data, 24 );
-    GET_UINT32_LE( X[ 7], data, 28 );
-    GET_UINT32_LE( X[ 8], data, 32 );
-    GET_UINT32_LE( X[ 9], data, 36 );
-    GET_UINT32_LE( X[10], data, 40 );
-    GET_UINT32_LE( X[11], data, 44 );
-    GET_UINT32_LE( X[12], data, 48 );
-    GET_UINT32_LE( X[13], data, 52 );
-    GET_UINT32_LE( X[14], data, 56 );
-    GET_UINT32_LE( X[15], data, 60 );
+    GET_UINT32_LE( local.X[ 0], data,  0 );
+    GET_UINT32_LE( local.X[ 1], data,  4 );
+    GET_UINT32_LE( local.X[ 2], data,  8 );
+    GET_UINT32_LE( local.X[ 3], data, 12 );
+    GET_UINT32_LE( local.X[ 4], data, 16 );
+    GET_UINT32_LE( local.X[ 5], data, 20 );
+    GET_UINT32_LE( local.X[ 6], data, 24 );
+    GET_UINT32_LE( local.X[ 7], data, 28 );
+    GET_UINT32_LE( local.X[ 8], data, 32 );
+    GET_UINT32_LE( local.X[ 9], data, 36 );
+    GET_UINT32_LE( local.X[10], data, 40 );
+    GET_UINT32_LE( local.X[11], data, 44 );
+    GET_UINT32_LE( local.X[12], data, 48 );
+    GET_UINT32_LE( local.X[13], data, 52 );
+    GET_UINT32_LE( local.X[14], data, 56 );
+    GET_UINT32_LE( local.X[15], data, 60 );
 
 #define S(x,n)                                                          \
     ( ( (x) << (n) ) | ( ( (x) & 0xFFFFFFFF) >> ( 32 - (n) ) ) )
 
-#define P(a,b,c,d,k,s,t)                                        \
-    do                                                          \
-    {                                                           \
-        (a) += F((b),(c),(d)) + X[(k)] + (t);                   \
-        (a) = S((a),(s)) + (b);                                 \
+#define P(a,b,c,d,k,s,t)                                                \
+    do                                                                  \
+    {                                                                   \
+        (a) += F((b),(c),(d)) + local.X[(k)] + (t);                     \
+        (a) = S((a),(s)) + (b);                                         \
     } while( 0 )
 
-    A = ctx->state[0];
-    B = ctx->state[1];
-    C = ctx->state[2];
-    D = ctx->state[3];
+    local.A = ctx->state[0];
+    local.B = ctx->state[1];
+    local.C = ctx->state[2];
+    local.D = ctx->state[3];
 
 #define F(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
 
-    P( A, B, C, D,  0,  7, 0xD76AA478 );
-    P( D, A, B, C,  1, 12, 0xE8C7B756 );
-    P( C, D, A, B,  2, 17, 0x242070DB );
-    P( B, C, D, A,  3, 22, 0xC1BDCEEE );
-    P( A, B, C, D,  4,  7, 0xF57C0FAF );
-    P( D, A, B, C,  5, 12, 0x4787C62A );
-    P( C, D, A, B,  6, 17, 0xA8304613 );
-    P( B, C, D, A,  7, 22, 0xFD469501 );
-    P( A, B, C, D,  8,  7, 0x698098D8 );
-    P( D, A, B, C,  9, 12, 0x8B44F7AF );
-    P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
-    P( B, C, D, A, 11, 22, 0x895CD7BE );
-    P( A, B, C, D, 12,  7, 0x6B901122 );
-    P( D, A, B, C, 13, 12, 0xFD987193 );
-    P( C, D, A, B, 14, 17, 0xA679438E );
-    P( B, C, D, A, 15, 22, 0x49B40821 );
+    P( local.A, local.B, local.C, local.D,  0,  7, 0xD76AA478 );
+    P( local.D, local.A, local.B, local.C,  1, 12, 0xE8C7B756 );
+    P( local.C, local.D, local.A, local.B,  2, 17, 0x242070DB );
+    P( local.B, local.C, local.D, local.A,  3, 22, 0xC1BDCEEE );
+    P( local.A, local.B, local.C, local.D,  4,  7, 0xF57C0FAF );
+    P( local.D, local.A, local.B, local.C,  5, 12, 0x4787C62A );
+    P( local.C, local.D, local.A, local.B,  6, 17, 0xA8304613 );
+    P( local.B, local.C, local.D, local.A,  7, 22, 0xFD469501 );
+    P( local.A, local.B, local.C, local.D,  8,  7, 0x698098D8 );
+    P( local.D, local.A, local.B, local.C,  9, 12, 0x8B44F7AF );
+    P( local.C, local.D, local.A, local.B, 10, 17, 0xFFFF5BB1 );
+    P( local.B, local.C, local.D, local.A, 11, 22, 0x895CD7BE );
+    P( local.A, local.B, local.C, local.D, 12,  7, 0x6B901122 );
+    P( local.D, local.A, local.B, local.C, 13, 12, 0xFD987193 );
+    P( local.C, local.D, local.A, local.B, 14, 17, 0xA679438E );
+    P( local.B, local.C, local.D, local.A, 15, 22, 0x49B40821 );
 
 #undef F
 
 #define F(x,y,z) ((y) ^ ((z) & ((x) ^ (y))))
 
-    P( A, B, C, D,  1,  5, 0xF61E2562 );
-    P( D, A, B, C,  6,  9, 0xC040B340 );
-    P( C, D, A, B, 11, 14, 0x265E5A51 );
-    P( B, C, D, A,  0, 20, 0xE9B6C7AA );
-    P( A, B, C, D,  5,  5, 0xD62F105D );
-    P( D, A, B, C, 10,  9, 0x02441453 );
-    P( C, D, A, B, 15, 14, 0xD8A1E681 );
-    P( B, C, D, A,  4, 20, 0xE7D3FBC8 );
-    P( A, B, C, D,  9,  5, 0x21E1CDE6 );
-    P( D, A, B, C, 14,  9, 0xC33707D6 );
-    P( C, D, A, B,  3, 14, 0xF4D50D87 );
-    P( B, C, D, A,  8, 20, 0x455A14ED );
-    P( A, B, C, D, 13,  5, 0xA9E3E905 );
-    P( D, A, B, C,  2,  9, 0xFCEFA3F8 );
-    P( C, D, A, B,  7, 14, 0x676F02D9 );
-    P( B, C, D, A, 12, 20, 0x8D2A4C8A );
+    P( local.A, local.B, local.C, local.D,  1,  5, 0xF61E2562 );
+    P( local.D, local.A, local.B, local.C,  6,  9, 0xC040B340 );
+    P( local.C, local.D, local.A, local.B, 11, 14, 0x265E5A51 );
+    P( local.B, local.C, local.D, local.A,  0, 20, 0xE9B6C7AA );
+    P( local.A, local.B, local.C, local.D,  5,  5, 0xD62F105D );
+    P( local.D, local.A, local.B, local.C, 10,  9, 0x02441453 );
+    P( local.C, local.D, local.A, local.B, 15, 14, 0xD8A1E681 );
+    P( local.B, local.C, local.D, local.A,  4, 20, 0xE7D3FBC8 );
+    P( local.A, local.B, local.C, local.D,  9,  5, 0x21E1CDE6 );
+    P( local.D, local.A, local.B, local.C, 14,  9, 0xC33707D6 );
+    P( local.C, local.D, local.A, local.B,  3, 14, 0xF4D50D87 );
+    P( local.B, local.C, local.D, local.A,  8, 20, 0x455A14ED );
+    P( local.A, local.B, local.C, local.D, 13,  5, 0xA9E3E905 );
+    P( local.D, local.A, local.B, local.C,  2,  9, 0xFCEFA3F8 );
+    P( local.C, local.D, local.A, local.B,  7, 14, 0x676F02D9 );
+    P( local.B, local.C, local.D, local.A, 12, 20, 0x8D2A4C8A );
 
 #undef F
 
 #define F(x,y,z) ((x) ^ (y) ^ (z))
 
-    P( A, B, C, D,  5,  4, 0xFFFA3942 );
-    P( D, A, B, C,  8, 11, 0x8771F681 );
-    P( C, D, A, B, 11, 16, 0x6D9D6122 );
-    P( B, C, D, A, 14, 23, 0xFDE5380C );
-    P( A, B, C, D,  1,  4, 0xA4BEEA44 );
-    P( D, A, B, C,  4, 11, 0x4BDECFA9 );
-    P( C, D, A, B,  7, 16, 0xF6BB4B60 );
-    P( B, C, D, A, 10, 23, 0xBEBFBC70 );
-    P( A, B, C, D, 13,  4, 0x289B7EC6 );
-    P( D, A, B, C,  0, 11, 0xEAA127FA );
-    P( C, D, A, B,  3, 16, 0xD4EF3085 );
-    P( B, C, D, A,  6, 23, 0x04881D05 );
-    P( A, B, C, D,  9,  4, 0xD9D4D039 );
-    P( D, A, B, C, 12, 11, 0xE6DB99E5 );
-    P( C, D, A, B, 15, 16, 0x1FA27CF8 );
-    P( B, C, D, A,  2, 23, 0xC4AC5665 );
+    P( local.A, local.B, local.C, local.D,  5,  4, 0xFFFA3942 );
+    P( local.D, local.A, local.B, local.C,  8, 11, 0x8771F681 );
+    P( local.C, local.D, local.A, local.B, 11, 16, 0x6D9D6122 );
+    P( local.B, local.C, local.D, local.A, 14, 23, 0xFDE5380C );
+    P( local.A, local.B, local.C, local.D,  1,  4, 0xA4BEEA44 );
+    P( local.D, local.A, local.B, local.C,  4, 11, 0x4BDECFA9 );
+    P( local.C, local.D, local.A, local.B,  7, 16, 0xF6BB4B60 );
+    P( local.B, local.C, local.D, local.A, 10, 23, 0xBEBFBC70 );
+    P( local.A, local.B, local.C, local.D, 13,  4, 0x289B7EC6 );
+    P( local.D, local.A, local.B, local.C,  0, 11, 0xEAA127FA );
+    P( local.C, local.D, local.A, local.B,  3, 16, 0xD4EF3085 );
+    P( local.B, local.C, local.D, local.A,  6, 23, 0x04881D05 );
+    P( local.A, local.B, local.C, local.D,  9,  4, 0xD9D4D039 );
+    P( local.D, local.A, local.B, local.C, 12, 11, 0xE6DB99E5 );
+    P( local.C, local.D, local.A, local.B, 15, 16, 0x1FA27CF8 );
+    P( local.B, local.C, local.D, local.A,  2, 23, 0xC4AC5665 );
 
 #undef F
 
 #define F(x,y,z) ((y) ^ ((x) | ~(z)))
 
-    P( A, B, C, D,  0,  6, 0xF4292244 );
-    P( D, A, B, C,  7, 10, 0x432AFF97 );
-    P( C, D, A, B, 14, 15, 0xAB9423A7 );
-    P( B, C, D, A,  5, 21, 0xFC93A039 );
-    P( A, B, C, D, 12,  6, 0x655B59C3 );
-    P( D, A, B, C,  3, 10, 0x8F0CCC92 );
-    P( C, D, A, B, 10, 15, 0xFFEFF47D );
-    P( B, C, D, A,  1, 21, 0x85845DD1 );
-    P( A, B, C, D,  8,  6, 0x6FA87E4F );
-    P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
-    P( C, D, A, B,  6, 15, 0xA3014314 );
-    P( B, C, D, A, 13, 21, 0x4E0811A1 );
-    P( A, B, C, D,  4,  6, 0xF7537E82 );
-    P( D, A, B, C, 11, 10, 0xBD3AF235 );
-    P( C, D, A, B,  2, 15, 0x2AD7D2BB );
-    P( B, C, D, A,  9, 21, 0xEB86D391 );
+    P( local.A, local.B, local.C, local.D,  0,  6, 0xF4292244 );
+    P( local.D, local.A, local.B, local.C,  7, 10, 0x432AFF97 );
+    P( local.C, local.D, local.A, local.B, 14, 15, 0xAB9423A7 );
+    P( local.B, local.C, local.D, local.A,  5, 21, 0xFC93A039 );
+    P( local.A, local.B, local.C, local.D, 12,  6, 0x655B59C3 );
+    P( local.D, local.A, local.B, local.C,  3, 10, 0x8F0CCC92 );
+    P( local.C, local.D, local.A, local.B, 10, 15, 0xFFEFF47D );
+    P( local.B, local.C, local.D, local.A,  1, 21, 0x85845DD1 );
+    P( local.A, local.B, local.C, local.D,  8,  6, 0x6FA87E4F );
+    P( local.D, local.A, local.B, local.C, 15, 10, 0xFE2CE6E0 );
+    P( local.C, local.D, local.A, local.B,  6, 15, 0xA3014314 );
+    P( local.B, local.C, local.D, local.A, 13, 21, 0x4E0811A1 );
+    P( local.A, local.B, local.C, local.D,  4,  6, 0xF7537E82 );
+    P( local.D, local.A, local.B, local.C, 11, 10, 0xBD3AF235 );
+    P( local.C, local.D, local.A, local.B,  2, 15, 0x2AD7D2BB );
+    P( local.B, local.C, local.D, local.A,  9, 21, 0xEB86D391 );
 
 #undef F
 
-    ctx->state[0] += A;
-    ctx->state[1] += B;
-    ctx->state[2] += C;
-    ctx->state[3] += D;
+    ctx->state[0] += local.A;
+    ctx->state[1] += local.B;
+    ctx->state[2] += local.C;
+    ctx->state[3] += local.D;
+
+    /* Zeroise variables to clear sensitive data from memory. */
+    mbedtls_platform_zeroize( &local, sizeof( local ) );
 
     return( 0 );
 }
diff --git a/library/pkcs5.c b/library/pkcs5.c
index f89cc64..e9e743f 100644
--- a/library/pkcs5.c
+++ b/library/pkcs5.c
@@ -221,7 +221,8 @@
                        unsigned int iteration_count,
                        uint32_t key_length, unsigned char *output )
 {
-    int ret, j;
+    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];
@@ -245,16 +246,16 @@
         // U1 ends up in work
         //
         if( ( ret = mbedtls_md_hmac_update( ctx, salt, slen ) ) != 0 )
-            return( ret );
+            goto cleanup;
 
         if( ( ret = mbedtls_md_hmac_update( ctx, counter, 4 ) ) != 0 )
-            return( ret );
+            goto cleanup;
 
         if( ( ret = mbedtls_md_hmac_finish( ctx, work ) ) != 0 )
-            return( ret );
+            goto cleanup;
 
         if( ( ret = mbedtls_md_hmac_reset( ctx ) ) != 0 )
-           return( ret );
+            goto cleanup;
 
         memcpy( md1, work, md_size );
 
@@ -263,13 +264,13 @@
             // U2 ends up in md1
             //
             if( ( ret = mbedtls_md_hmac_update( ctx, md1, md_size ) ) != 0 )
-                return( ret );
+                goto cleanup;
 
             if( ( ret = mbedtls_md_hmac_finish( ctx, md1 ) ) != 0 )
-                return( ret );
+                goto cleanup;
 
             if( ( ret = mbedtls_md_hmac_reset( ctx ) ) != 0 )
-                return( ret );
+                goto cleanup;
 
             // U1 xor U2
             //
@@ -288,7 +289,12 @@
                 break;
     }
 
-    return( 0 );
+cleanup:
+    /* Zeroise buffers to clear sensitive data from memory. */
+    mbedtls_platform_zeroize( work, MBEDTLS_MD_MAX_SIZE );
+    mbedtls_platform_zeroize( md1, MBEDTLS_MD_MAX_SIZE );
+
+    return( ret );
 }
 
 #if defined(MBEDTLS_SELF_TEST)
diff --git a/library/ripemd160.c b/library/ripemd160.c
index 603b6ba..ae4dee4 100644
--- a/library/ripemd160.c
+++ b/library/ripemd160.c
@@ -117,30 +117,33 @@
 int mbedtls_internal_ripemd160_process( mbedtls_ripemd160_context *ctx,
                                         const unsigned char data[64] )
 {
-    uint32_t A, B, C, D, E, Ap, Bp, Cp, Dp, Ep, X[16];
+    struct
+    {
+        uint32_t A, B, C, D, E, Ap, Bp, Cp, Dp, Ep, X[16];
+    } local;
 
-    GET_UINT32_LE( X[ 0], data,  0 );
-    GET_UINT32_LE( X[ 1], data,  4 );
-    GET_UINT32_LE( X[ 2], data,  8 );
-    GET_UINT32_LE( X[ 3], data, 12 );
-    GET_UINT32_LE( X[ 4], data, 16 );
-    GET_UINT32_LE( X[ 5], data, 20 );
-    GET_UINT32_LE( X[ 6], data, 24 );
-    GET_UINT32_LE( X[ 7], data, 28 );
-    GET_UINT32_LE( X[ 8], data, 32 );
-    GET_UINT32_LE( X[ 9], data, 36 );
-    GET_UINT32_LE( X[10], data, 40 );
-    GET_UINT32_LE( X[11], data, 44 );
-    GET_UINT32_LE( X[12], data, 48 );
-    GET_UINT32_LE( X[13], data, 52 );
-    GET_UINT32_LE( X[14], data, 56 );
-    GET_UINT32_LE( X[15], data, 60 );
+    GET_UINT32_LE( local.X[ 0], data,  0 );
+    GET_UINT32_LE( local.X[ 1], data,  4 );
+    GET_UINT32_LE( local.X[ 2], data,  8 );
+    GET_UINT32_LE( local.X[ 3], data, 12 );
+    GET_UINT32_LE( local.X[ 4], data, 16 );
+    GET_UINT32_LE( local.X[ 5], data, 20 );
+    GET_UINT32_LE( local.X[ 6], data, 24 );
+    GET_UINT32_LE( local.X[ 7], data, 28 );
+    GET_UINT32_LE( local.X[ 8], data, 32 );
+    GET_UINT32_LE( local.X[ 9], data, 36 );
+    GET_UINT32_LE( local.X[10], data, 40 );
+    GET_UINT32_LE( local.X[11], data, 44 );
+    GET_UINT32_LE( local.X[12], data, 48 );
+    GET_UINT32_LE( local.X[13], data, 52 );
+    GET_UINT32_LE( local.X[14], data, 56 );
+    GET_UINT32_LE( local.X[15], data, 60 );
 
-    A = Ap = ctx->state[0];
-    B = Bp = ctx->state[1];
-    C = Cp = ctx->state[2];
-    D = Dp = ctx->state[3];
-    E = Ep = ctx->state[4];
+    local.A = local.Ap = ctx->state[0];
+    local.B = local.Bp = ctx->state[1];
+    local.C = local.Cp = ctx->state[2];
+    local.D = local.Dp = ctx->state[3];
+    local.E = local.Ep = ctx->state[4];
 
 #define F1( x, y, z )   ( (x) ^ (y) ^ (z) )
 #define F2( x, y, z )   ( ( (x) & (y) ) | ( ~(x) & (z) ) )
@@ -150,12 +153,12 @@
 
 #define S( x, n ) ( ( (x) << (n) ) | ( (x) >> (32 - (n)) ) )
 
-#define P( a, b, c, d, e, r, s, f, k )                \
-    do                                                \
-    {                                                 \
-        (a) += f( (b), (c), (d) ) + X[r] + (k);       \
-        (a) = S( (a), (s) ) + (e);                    \
-        (c) = S( (c), 10 );                           \
+#define P( a, b, c, d, e, r, s, f, k )                      \
+    do                                                      \
+    {                                                       \
+        (a) += f( (b), (c), (d) ) + local.X[r] + (k);       \
+        (a) = S( (a), (s) ) + (e);                          \
+        (c) = S( (c), 10 );                                 \
     } while( 0 )
 
 #define P2( a, b, c, d, e, r, s, rp, sp )                               \
@@ -170,22 +173,22 @@
 #define K   0x00000000
 #define Fp  F5
 #define Kp  0x50A28BE6
-    P2( A, B, C, D, E,  0, 11,  5,  8 );
-    P2( E, A, B, C, D,  1, 14, 14,  9 );
-    P2( D, E, A, B, C,  2, 15,  7,  9 );
-    P2( C, D, E, A, B,  3, 12,  0, 11 );
-    P2( B, C, D, E, A,  4,  5,  9, 13 );
-    P2( A, B, C, D, E,  5,  8,  2, 15 );
-    P2( E, A, B, C, D,  6,  7, 11, 15 );
-    P2( D, E, A, B, C,  7,  9,  4,  5 );
-    P2( C, D, E, A, B,  8, 11, 13,  7 );
-    P2( B, C, D, E, A,  9, 13,  6,  7 );
-    P2( A, B, C, D, E, 10, 14, 15,  8 );
-    P2( E, A, B, C, D, 11, 15,  8, 11 );
-    P2( D, E, A, B, C, 12,  6,  1, 14 );
-    P2( C, D, E, A, B, 13,  7, 10, 14 );
-    P2( B, C, D, E, A, 14,  9,  3, 12 );
-    P2( A, B, C, D, E, 15,  8, 12,  6 );
+    P2( local.A, local.B, local.C, local.D, local.E,  0, 11,  5,  8 );
+    P2( local.E, local.A, local.B, local.C, local.D,  1, 14, 14,  9 );
+    P2( local.D, local.E, local.A, local.B, local.C,  2, 15,  7,  9 );
+    P2( local.C, local.D, local.E, local.A, local.B,  3, 12,  0, 11 );
+    P2( local.B, local.C, local.D, local.E, local.A,  4,  5,  9, 13 );
+    P2( local.A, local.B, local.C, local.D, local.E,  5,  8,  2, 15 );
+    P2( local.E, local.A, local.B, local.C, local.D,  6,  7, 11, 15 );
+    P2( local.D, local.E, local.A, local.B, local.C,  7,  9,  4,  5 );
+    P2( local.C, local.D, local.E, local.A, local.B,  8, 11, 13,  7 );
+    P2( local.B, local.C, local.D, local.E, local.A,  9, 13,  6,  7 );
+    P2( local.A, local.B, local.C, local.D, local.E, 10, 14, 15,  8 );
+    P2( local.E, local.A, local.B, local.C, local.D, 11, 15,  8, 11 );
+    P2( local.D, local.E, local.A, local.B, local.C, 12,  6,  1, 14 );
+    P2( local.C, local.D, local.E, local.A, local.B, 13,  7, 10, 14 );
+    P2( local.B, local.C, local.D, local.E, local.A, 14,  9,  3, 12 );
+    P2( local.A, local.B, local.C, local.D, local.E, 15,  8, 12,  6 );
 #undef F
 #undef K
 #undef Fp
@@ -195,22 +198,22 @@
 #define K   0x5A827999
 #define Fp  F4
 #define Kp  0x5C4DD124
-    P2( E, A, B, C, D,  7,  7,  6,  9 );
-    P2( D, E, A, B, C,  4,  6, 11, 13 );
-    P2( C, D, E, A, B, 13,  8,  3, 15 );
-    P2( B, C, D, E, A,  1, 13,  7,  7 );
-    P2( A, B, C, D, E, 10, 11,  0, 12 );
-    P2( E, A, B, C, D,  6,  9, 13,  8 );
-    P2( D, E, A, B, C, 15,  7,  5,  9 );
-    P2( C, D, E, A, B,  3, 15, 10, 11 );
-    P2( B, C, D, E, A, 12,  7, 14,  7 );
-    P2( A, B, C, D, E,  0, 12, 15,  7 );
-    P2( E, A, B, C, D,  9, 15,  8, 12 );
-    P2( D, E, A, B, C,  5,  9, 12,  7 );
-    P2( C, D, E, A, B,  2, 11,  4,  6 );
-    P2( B, C, D, E, A, 14,  7,  9, 15 );
-    P2( A, B, C, D, E, 11, 13,  1, 13 );
-    P2( E, A, B, C, D,  8, 12,  2, 11 );
+    P2( local.E, local.A, local.B, local.C, local.D,  7,  7,  6,  9 );
+    P2( local.D, local.E, local.A, local.B, local.C,  4,  6, 11, 13 );
+    P2( local.C, local.D, local.E, local.A, local.B, 13,  8,  3, 15 );
+    P2( local.B, local.C, local.D, local.E, local.A,  1, 13,  7,  7 );
+    P2( local.A, local.B, local.C, local.D, local.E, 10, 11,  0, 12 );
+    P2( local.E, local.A, local.B, local.C, local.D,  6,  9, 13,  8 );
+    P2( local.D, local.E, local.A, local.B, local.C, 15,  7,  5,  9 );
+    P2( local.C, local.D, local.E, local.A, local.B,  3, 15, 10, 11 );
+    P2( local.B, local.C, local.D, local.E, local.A, 12,  7, 14,  7 );
+    P2( local.A, local.B, local.C, local.D, local.E,  0, 12, 15,  7 );
+    P2( local.E, local.A, local.B, local.C, local.D,  9, 15,  8, 12 );
+    P2( local.D, local.E, local.A, local.B, local.C,  5,  9, 12,  7 );
+    P2( local.C, local.D, local.E, local.A, local.B,  2, 11,  4,  6 );
+    P2( local.B, local.C, local.D, local.E, local.A, 14,  7,  9, 15 );
+    P2( local.A, local.B, local.C, local.D, local.E, 11, 13,  1, 13 );
+    P2( local.E, local.A, local.B, local.C, local.D,  8, 12,  2, 11 );
 #undef F
 #undef K
 #undef Fp
@@ -220,22 +223,22 @@
 #define K   0x6ED9EBA1
 #define Fp  F3
 #define Kp  0x6D703EF3
-    P2( D, E, A, B, C,  3, 11, 15,  9 );
-    P2( C, D, E, A, B, 10, 13,  5,  7 );
-    P2( B, C, D, E, A, 14,  6,  1, 15 );
-    P2( A, B, C, D, E,  4,  7,  3, 11 );
-    P2( E, A, B, C, D,  9, 14,  7,  8 );
-    P2( D, E, A, B, C, 15,  9, 14,  6 );
-    P2( C, D, E, A, B,  8, 13,  6,  6 );
-    P2( B, C, D, E, A,  1, 15,  9, 14 );
-    P2( A, B, C, D, E,  2, 14, 11, 12 );
-    P2( E, A, B, C, D,  7,  8,  8, 13 );
-    P2( D, E, A, B, C,  0, 13, 12,  5 );
-    P2( C, D, E, A, B,  6,  6,  2, 14 );
-    P2( B, C, D, E, A, 13,  5, 10, 13 );
-    P2( A, B, C, D, E, 11, 12,  0, 13 );
-    P2( E, A, B, C, D,  5,  7,  4,  7 );
-    P2( D, E, A, B, C, 12,  5, 13,  5 );
+    P2( local.D, local.E, local.A, local.B, local.C,  3, 11, 15,  9 );
+    P2( local.C, local.D, local.E, local.A, local.B, 10, 13,  5,  7 );
+    P2( local.B, local.C, local.D, local.E, local.A, 14,  6,  1, 15 );
+    P2( local.A, local.B, local.C, local.D, local.E,  4,  7,  3, 11 );
+    P2( local.E, local.A, local.B, local.C, local.D,  9, 14,  7,  8 );
+    P2( local.D, local.E, local.A, local.B, local.C, 15,  9, 14,  6 );
+    P2( local.C, local.D, local.E, local.A, local.B,  8, 13,  6,  6 );
+    P2( local.B, local.C, local.D, local.E, local.A,  1, 15,  9, 14 );
+    P2( local.A, local.B, local.C, local.D, local.E,  2, 14, 11, 12 );
+    P2( local.E, local.A, local.B, local.C, local.D,  7,  8,  8, 13 );
+    P2( local.D, local.E, local.A, local.B, local.C,  0, 13, 12,  5 );
+    P2( local.C, local.D, local.E, local.A, local.B,  6,  6,  2, 14 );
+    P2( local.B, local.C, local.D, local.E, local.A, 13,  5, 10, 13 );
+    P2( local.A, local.B, local.C, local.D, local.E, 11, 12,  0, 13 );
+    P2( local.E, local.A, local.B, local.C, local.D,  5,  7,  4,  7 );
+    P2( local.D, local.E, local.A, local.B, local.C, 12,  5, 13,  5 );
 #undef F
 #undef K
 #undef Fp
@@ -245,22 +248,22 @@
 #define K   0x8F1BBCDC
 #define Fp  F2
 #define Kp  0x7A6D76E9
-    P2( C, D, E, A, B,  1, 11,  8, 15 );
-    P2( B, C, D, E, A,  9, 12,  6,  5 );
-    P2( A, B, C, D, E, 11, 14,  4,  8 );
-    P2( E, A, B, C, D, 10, 15,  1, 11 );
-    P2( D, E, A, B, C,  0, 14,  3, 14 );
-    P2( C, D, E, A, B,  8, 15, 11, 14 );
-    P2( B, C, D, E, A, 12,  9, 15,  6 );
-    P2( A, B, C, D, E,  4,  8,  0, 14 );
-    P2( E, A, B, C, D, 13,  9,  5,  6 );
-    P2( D, E, A, B, C,  3, 14, 12,  9 );
-    P2( C, D, E, A, B,  7,  5,  2, 12 );
-    P2( B, C, D, E, A, 15,  6, 13,  9 );
-    P2( A, B, C, D, E, 14,  8,  9, 12 );
-    P2( E, A, B, C, D,  5,  6,  7,  5 );
-    P2( D, E, A, B, C,  6,  5, 10, 15 );
-    P2( C, D, E, A, B,  2, 12, 14,  8 );
+    P2( local.C, local.D, local.E, local.A, local.B,  1, 11,  8, 15 );
+    P2( local.B, local.C, local.D, local.E, local.A,  9, 12,  6,  5 );
+    P2( local.A, local.B, local.C, local.D, local.E, 11, 14,  4,  8 );
+    P2( local.E, local.A, local.B, local.C, local.D, 10, 15,  1, 11 );
+    P2( local.D, local.E, local.A, local.B, local.C,  0, 14,  3, 14 );
+    P2( local.C, local.D, local.E, local.A, local.B,  8, 15, 11, 14 );
+    P2( local.B, local.C, local.D, local.E, local.A, 12,  9, 15,  6 );
+    P2( local.A, local.B, local.C, local.D, local.E,  4,  8,  0, 14 );
+    P2( local.E, local.A, local.B, local.C, local.D, 13,  9,  5,  6 );
+    P2( local.D, local.E, local.A, local.B, local.C,  3, 14, 12,  9 );
+    P2( local.C, local.D, local.E, local.A, local.B,  7,  5,  2, 12 );
+    P2( local.B, local.C, local.D, local.E, local.A, 15,  6, 13,  9 );
+    P2( local.A, local.B, local.C, local.D, local.E, 14,  8,  9, 12 );
+    P2( local.E, local.A, local.B, local.C, local.D,  5,  6,  7,  5 );
+    P2( local.D, local.E, local.A, local.B, local.C,  6,  5, 10, 15 );
+    P2( local.C, local.D, local.E, local.A, local.B,  2, 12, 14,  8 );
 #undef F
 #undef K
 #undef Fp
@@ -270,33 +273,36 @@
 #define K   0xA953FD4E
 #define Fp  F1
 #define Kp  0x00000000
-    P2( B, C, D, E, A,  4,  9, 12,  8 );
-    P2( A, B, C, D, E,  0, 15, 15,  5 );
-    P2( E, A, B, C, D,  5,  5, 10, 12 );
-    P2( D, E, A, B, C,  9, 11,  4,  9 );
-    P2( C, D, E, A, B,  7,  6,  1, 12 );
-    P2( B, C, D, E, A, 12,  8,  5,  5 );
-    P2( A, B, C, D, E,  2, 13,  8, 14 );
-    P2( E, A, B, C, D, 10, 12,  7,  6 );
-    P2( D, E, A, B, C, 14,  5,  6,  8 );
-    P2( C, D, E, A, B,  1, 12,  2, 13 );
-    P2( B, C, D, E, A,  3, 13, 13,  6 );
-    P2( A, B, C, D, E,  8, 14, 14,  5 );
-    P2( E, A, B, C, D, 11, 11,  0, 15 );
-    P2( D, E, A, B, C,  6,  8,  3, 13 );
-    P2( C, D, E, A, B, 15,  5,  9, 11 );
-    P2( B, C, D, E, A, 13,  6, 11, 11 );
+    P2( local.B, local.C, local.D, local.E, local.A,  4,  9, 12,  8 );
+    P2( local.A, local.B, local.C, local.D, local.E,  0, 15, 15,  5 );
+    P2( local.E, local.A, local.B, local.C, local.D,  5,  5, 10, 12 );
+    P2( local.D, local.E, local.A, local.B, local.C,  9, 11,  4,  9 );
+    P2( local.C, local.D, local.E, local.A, local.B,  7,  6,  1, 12 );
+    P2( local.B, local.C, local.D, local.E, local.A, 12,  8,  5,  5 );
+    P2( local.A, local.B, local.C, local.D, local.E,  2, 13,  8, 14 );
+    P2( local.E, local.A, local.B, local.C, local.D, 10, 12,  7,  6 );
+    P2( local.D, local.E, local.A, local.B, local.C, 14,  5,  6,  8 );
+    P2( local.C, local.D, local.E, local.A, local.B,  1, 12,  2, 13 );
+    P2( local.B, local.C, local.D, local.E, local.A,  3, 13, 13,  6 );
+    P2( local.A, local.B, local.C, local.D, local.E,  8, 14, 14,  5 );
+    P2( local.E, local.A, local.B, local.C, local.D, 11, 11,  0, 15 );
+    P2( local.D, local.E, local.A, local.B, local.C,  6,  8,  3, 13 );
+    P2( local.C, local.D, local.E, local.A, local.B, 15,  5,  9, 11 );
+    P2( local.B, local.C, local.D, local.E, local.A, 13,  6, 11, 11 );
 #undef F
 #undef K
 #undef Fp
 #undef Kp
 
-    C             = ctx->state[1] + C + Dp;
-    ctx->state[1] = ctx->state[2] + D + Ep;
-    ctx->state[2] = ctx->state[3] + E + Ap;
-    ctx->state[3] = ctx->state[4] + A + Bp;
-    ctx->state[4] = ctx->state[0] + B + Cp;
-    ctx->state[0] = C;
+    local.C       = ctx->state[1] + local.C + local.Dp;
+    ctx->state[1] = ctx->state[2] + local.D + local.Ep;
+    ctx->state[2] = ctx->state[3] + local.E + local.Ap;
+    ctx->state[3] = ctx->state[4] + local.A + local.Bp;
+    ctx->state[4] = ctx->state[0] + local.B + local.Cp;
+    ctx->state[0] = local.C;
+
+    /* Zeroise variables to clear sensitive data from memory. */
+    mbedtls_platform_zeroize( &local, sizeof( local ) );
 
     return( 0 );
 }
diff --git a/library/sha1.c b/library/sha1.c
index 593f795..6b0f58e 100644
--- a/library/sha1.c
+++ b/library/sha1.c
@@ -125,35 +125,40 @@
 int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx,
                                    const unsigned char data[64] )
 {
-    uint32_t temp, W[16], A, B, C, D, E;
+    struct
+    {
+        uint32_t temp, W[16], A, B, C, D, E;
+    } local;
 
     SHA1_VALIDATE_RET( ctx != NULL );
     SHA1_VALIDATE_RET( (const unsigned char *)data != NULL );
 
-    GET_UINT32_BE( W[ 0], data,  0 );
-    GET_UINT32_BE( W[ 1], data,  4 );
-    GET_UINT32_BE( W[ 2], data,  8 );
-    GET_UINT32_BE( W[ 3], data, 12 );
-    GET_UINT32_BE( W[ 4], data, 16 );
-    GET_UINT32_BE( W[ 5], data, 20 );
-    GET_UINT32_BE( W[ 6], data, 24 );
-    GET_UINT32_BE( W[ 7], data, 28 );
-    GET_UINT32_BE( W[ 8], data, 32 );
-    GET_UINT32_BE( W[ 9], data, 36 );
-    GET_UINT32_BE( W[10], data, 40 );
-    GET_UINT32_BE( W[11], data, 44 );
-    GET_UINT32_BE( W[12], data, 48 );
-    GET_UINT32_BE( W[13], data, 52 );
-    GET_UINT32_BE( W[14], data, 56 );
-    GET_UINT32_BE( W[15], data, 60 );
+    GET_UINT32_BE( local.W[ 0], data,  0 );
+    GET_UINT32_BE( local.W[ 1], data,  4 );
+    GET_UINT32_BE( local.W[ 2], data,  8 );
+    GET_UINT32_BE( local.W[ 3], data, 12 );
+    GET_UINT32_BE( local.W[ 4], data, 16 );
+    GET_UINT32_BE( local.W[ 5], data, 20 );
+    GET_UINT32_BE( local.W[ 6], data, 24 );
+    GET_UINT32_BE( local.W[ 7], data, 28 );
+    GET_UINT32_BE( local.W[ 8], data, 32 );
+    GET_UINT32_BE( local.W[ 9], data, 36 );
+    GET_UINT32_BE( local.W[10], data, 40 );
+    GET_UINT32_BE( local.W[11], data, 44 );
+    GET_UINT32_BE( local.W[12], data, 48 );
+    GET_UINT32_BE( local.W[13], data, 52 );
+    GET_UINT32_BE( local.W[14], data, 56 );
+    GET_UINT32_BE( local.W[15], data, 60 );
 
 #define S(x,n) (((x) << (n)) | (((x) & 0xFFFFFFFF) >> (32 - (n))))
 
 #define R(t)                                                    \
     (                                                           \
-        temp = W[( (t) -  3 ) & 0x0F] ^ W[( (t) - 8 ) & 0x0F] ^ \
-               W[( (t) - 14 ) & 0x0F] ^ W[  (t)       & 0x0F],  \
-        ( W[(t) & 0x0F] = S(temp,1) )                           \
+        local.temp = local.W[( (t) -  3 ) & 0x0F] ^             \
+                     local.W[( (t) -  8 ) & 0x0F] ^             \
+                     local.W[( (t) - 14 ) & 0x0F] ^             \
+                     local.W[  (t)        & 0x0F],              \
+        ( local.W[(t) & 0x0F] = S(local.temp,1) )               \
     )
 
 #define P(a,b,c,d,e,x)                                          \
@@ -163,35 +168,35 @@
         (b) = S((b),30);                                        \
     } while( 0 )
 
-    A = ctx->state[0];
-    B = ctx->state[1];
-    C = ctx->state[2];
-    D = ctx->state[3];
-    E = ctx->state[4];
+    local.A = ctx->state[0];
+    local.B = ctx->state[1];
+    local.C = ctx->state[2];
+    local.D = ctx->state[3];
+    local.E = ctx->state[4];
 
 #define F(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
 #define K 0x5A827999
 
-    P( A, B, C, D, E, W[0]  );
-    P( E, A, B, C, D, W[1]  );
-    P( D, E, A, B, C, W[2]  );
-    P( C, D, E, A, B, W[3]  );
-    P( B, C, D, E, A, W[4]  );
-    P( A, B, C, D, E, W[5]  );
-    P( E, A, B, C, D, W[6]  );
-    P( D, E, A, B, C, W[7]  );
-    P( C, D, E, A, B, W[8]  );
-    P( B, C, D, E, A, W[9]  );
-    P( A, B, C, D, E, W[10] );
-    P( E, A, B, C, D, W[11] );
-    P( D, E, A, B, C, W[12] );
-    P( C, D, E, A, B, W[13] );
-    P( B, C, D, E, A, W[14] );
-    P( A, B, C, D, E, W[15] );
-    P( E, A, B, C, D, R(16) );
-    P( D, E, A, B, C, R(17) );
-    P( C, D, E, A, B, R(18) );
-    P( B, C, D, E, A, R(19) );
+    P( local.A, local.B, local.C, local.D, local.E, local.W[0]  );
+    P( local.E, local.A, local.B, local.C, local.D, local.W[1]  );
+    P( local.D, local.E, local.A, local.B, local.C, local.W[2]  );
+    P( local.C, local.D, local.E, local.A, local.B, local.W[3]  );
+    P( local.B, local.C, local.D, local.E, local.A, local.W[4]  );
+    P( local.A, local.B, local.C, local.D, local.E, local.W[5]  );
+    P( local.E, local.A, local.B, local.C, local.D, local.W[6]  );
+    P( local.D, local.E, local.A, local.B, local.C, local.W[7]  );
+    P( local.C, local.D, local.E, local.A, local.B, local.W[8]  );
+    P( local.B, local.C, local.D, local.E, local.A, local.W[9]  );
+    P( local.A, local.B, local.C, local.D, local.E, local.W[10] );
+    P( local.E, local.A, local.B, local.C, local.D, local.W[11] );
+    P( local.D, local.E, local.A, local.B, local.C, local.W[12] );
+    P( local.C, local.D, local.E, local.A, local.B, local.W[13] );
+    P( local.B, local.C, local.D, local.E, local.A, local.W[14] );
+    P( local.A, local.B, local.C, local.D, local.E, local.W[15] );
+    P( local.E, local.A, local.B, local.C, local.D, R(16) );
+    P( local.D, local.E, local.A, local.B, local.C, R(17) );
+    P( local.C, local.D, local.E, local.A, local.B, R(18) );
+    P( local.B, local.C, local.D, local.E, local.A, R(19) );
 
 #undef K
 #undef F
@@ -199,26 +204,26 @@
 #define F(x,y,z) ((x) ^ (y) ^ (z))
 #define K 0x6ED9EBA1
 
-    P( A, B, C, D, E, R(20) );
-    P( E, A, B, C, D, R(21) );
-    P( D, E, A, B, C, R(22) );
-    P( C, D, E, A, B, R(23) );
-    P( B, C, D, E, A, R(24) );
-    P( A, B, C, D, E, R(25) );
-    P( E, A, B, C, D, R(26) );
-    P( D, E, A, B, C, R(27) );
-    P( C, D, E, A, B, R(28) );
-    P( B, C, D, E, A, R(29) );
-    P( A, B, C, D, E, R(30) );
-    P( E, A, B, C, D, R(31) );
-    P( D, E, A, B, C, R(32) );
-    P( C, D, E, A, B, R(33) );
-    P( B, C, D, E, A, R(34) );
-    P( A, B, C, D, E, R(35) );
-    P( E, A, B, C, D, R(36) );
-    P( D, E, A, B, C, R(37) );
-    P( C, D, E, A, B, R(38) );
-    P( B, C, D, E, A, R(39) );
+    P( local.A, local.B, local.C, local.D, local.E, R(20) );
+    P( local.E, local.A, local.B, local.C, local.D, R(21) );
+    P( local.D, local.E, local.A, local.B, local.C, R(22) );
+    P( local.C, local.D, local.E, local.A, local.B, R(23) );
+    P( local.B, local.C, local.D, local.E, local.A, R(24) );
+    P( local.A, local.B, local.C, local.D, local.E, R(25) );
+    P( local.E, local.A, local.B, local.C, local.D, R(26) );
+    P( local.D, local.E, local.A, local.B, local.C, R(27) );
+    P( local.C, local.D, local.E, local.A, local.B, R(28) );
+    P( local.B, local.C, local.D, local.E, local.A, R(29) );
+    P( local.A, local.B, local.C, local.D, local.E, R(30) );
+    P( local.E, local.A, local.B, local.C, local.D, R(31) );
+    P( local.D, local.E, local.A, local.B, local.C, R(32) );
+    P( local.C, local.D, local.E, local.A, local.B, R(33) );
+    P( local.B, local.C, local.D, local.E, local.A, R(34) );
+    P( local.A, local.B, local.C, local.D, local.E, R(35) );
+    P( local.E, local.A, local.B, local.C, local.D, R(36) );
+    P( local.D, local.E, local.A, local.B, local.C, R(37) );
+    P( local.C, local.D, local.E, local.A, local.B, R(38) );
+    P( local.B, local.C, local.D, local.E, local.A, R(39) );
 
 #undef K
 #undef F
@@ -226,26 +231,26 @@
 #define F(x,y,z) (((x) & (y)) | ((z) & ((x) | (y))))
 #define K 0x8F1BBCDC
 
-    P( A, B, C, D, E, R(40) );
-    P( E, A, B, C, D, R(41) );
-    P( D, E, A, B, C, R(42) );
-    P( C, D, E, A, B, R(43) );
-    P( B, C, D, E, A, R(44) );
-    P( A, B, C, D, E, R(45) );
-    P( E, A, B, C, D, R(46) );
-    P( D, E, A, B, C, R(47) );
-    P( C, D, E, A, B, R(48) );
-    P( B, C, D, E, A, R(49) );
-    P( A, B, C, D, E, R(50) );
-    P( E, A, B, C, D, R(51) );
-    P( D, E, A, B, C, R(52) );
-    P( C, D, E, A, B, R(53) );
-    P( B, C, D, E, A, R(54) );
-    P( A, B, C, D, E, R(55) );
-    P( E, A, B, C, D, R(56) );
-    P( D, E, A, B, C, R(57) );
-    P( C, D, E, A, B, R(58) );
-    P( B, C, D, E, A, R(59) );
+    P( local.A, local.B, local.C, local.D, local.E, R(40) );
+    P( local.E, local.A, local.B, local.C, local.D, R(41) );
+    P( local.D, local.E, local.A, local.B, local.C, R(42) );
+    P( local.C, local.D, local.E, local.A, local.B, R(43) );
+    P( local.B, local.C, local.D, local.E, local.A, R(44) );
+    P( local.A, local.B, local.C, local.D, local.E, R(45) );
+    P( local.E, local.A, local.B, local.C, local.D, R(46) );
+    P( local.D, local.E, local.A, local.B, local.C, R(47) );
+    P( local.C, local.D, local.E, local.A, local.B, R(48) );
+    P( local.B, local.C, local.D, local.E, local.A, R(49) );
+    P( local.A, local.B, local.C, local.D, local.E, R(50) );
+    P( local.E, local.A, local.B, local.C, local.D, R(51) );
+    P( local.D, local.E, local.A, local.B, local.C, R(52) );
+    P( local.C, local.D, local.E, local.A, local.B, R(53) );
+    P( local.B, local.C, local.D, local.E, local.A, R(54) );
+    P( local.A, local.B, local.C, local.D, local.E, R(55) );
+    P( local.E, local.A, local.B, local.C, local.D, R(56) );
+    P( local.D, local.E, local.A, local.B, local.C, R(57) );
+    P( local.C, local.D, local.E, local.A, local.B, R(58) );
+    P( local.B, local.C, local.D, local.E, local.A, R(59) );
 
 #undef K
 #undef F
@@ -253,35 +258,38 @@
 #define F(x,y,z) ((x) ^ (y) ^ (z))
 #define K 0xCA62C1D6
 
-    P( A, B, C, D, E, R(60) );
-    P( E, A, B, C, D, R(61) );
-    P( D, E, A, B, C, R(62) );
-    P( C, D, E, A, B, R(63) );
-    P( B, C, D, E, A, R(64) );
-    P( A, B, C, D, E, R(65) );
-    P( E, A, B, C, D, R(66) );
-    P( D, E, A, B, C, R(67) );
-    P( C, D, E, A, B, R(68) );
-    P( B, C, D, E, A, R(69) );
-    P( A, B, C, D, E, R(70) );
-    P( E, A, B, C, D, R(71) );
-    P( D, E, A, B, C, R(72) );
-    P( C, D, E, A, B, R(73) );
-    P( B, C, D, E, A, R(74) );
-    P( A, B, C, D, E, R(75) );
-    P( E, A, B, C, D, R(76) );
-    P( D, E, A, B, C, R(77) );
-    P( C, D, E, A, B, R(78) );
-    P( B, C, D, E, A, R(79) );
+    P( local.A, local.B, local.C, local.D, local.E, R(60) );
+    P( local.E, local.A, local.B, local.C, local.D, R(61) );
+    P( local.D, local.E, local.A, local.B, local.C, R(62) );
+    P( local.C, local.D, local.E, local.A, local.B, R(63) );
+    P( local.B, local.C, local.D, local.E, local.A, R(64) );
+    P( local.A, local.B, local.C, local.D, local.E, R(65) );
+    P( local.E, local.A, local.B, local.C, local.D, R(66) );
+    P( local.D, local.E, local.A, local.B, local.C, R(67) );
+    P( local.C, local.D, local.E, local.A, local.B, R(68) );
+    P( local.B, local.C, local.D, local.E, local.A, R(69) );
+    P( local.A, local.B, local.C, local.D, local.E, R(70) );
+    P( local.E, local.A, local.B, local.C, local.D, R(71) );
+    P( local.D, local.E, local.A, local.B, local.C, R(72) );
+    P( local.C, local.D, local.E, local.A, local.B, R(73) );
+    P( local.B, local.C, local.D, local.E, local.A, R(74) );
+    P( local.A, local.B, local.C, local.D, local.E, R(75) );
+    P( local.E, local.A, local.B, local.C, local.D, R(76) );
+    P( local.D, local.E, local.A, local.B, local.C, R(77) );
+    P( local.C, local.D, local.E, local.A, local.B, R(78) );
+    P( local.B, local.C, local.D, local.E, local.A, R(79) );
 
 #undef K
 #undef F
 
-    ctx->state[0] += A;
-    ctx->state[1] += B;
-    ctx->state[2] += C;
-    ctx->state[3] += D;
-    ctx->state[4] += E;
+    ctx->state[0] += local.A;
+    ctx->state[1] += local.B;
+    ctx->state[2] += local.C;
+    ctx->state[3] += local.D;
+    ctx->state[4] += local.E;
+
+    /* Zeroise buffers and variables to clear sensitive data from memory. */
+    mbedtls_platform_zeroize( &local, sizeof( local ) );
 
     return( 0 );
 }
diff --git a/library/sha256.c b/library/sha256.c
index b4c4b36..be373d9 100644
--- a/library/sha256.c
+++ b/library/sha256.c
@@ -179,77 +179,104 @@
 #define F0(x,y,z) (((x) & (y)) | ((z) & ((x) | (y))))
 #define F1(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
 
-#define R(t)                                    \
-    (                                           \
-        W[t] = S1(W[(t) -  2]) + W[(t) -  7] +  \
-               S0(W[(t) - 15]) + W[(t) - 16]    \
+#define R(t)                                                        \
+    (                                                               \
+        local.W[t] = S1(local.W[(t) -  2]) + local.W[(t) -  7] +    \
+                     S0(local.W[(t) - 15]) + local.W[(t) - 16]      \
     )
 
-#define P(a,b,c,d,e,f,g,h,x,K)                          \
-    do                                                  \
-    {                                                   \
-        temp1 = (h) + S3(e) + F1((e),(f),(g)) + (K) + (x);      \
-        temp2 = S2(a) + F0((a),(b),(c));                        \
-        (d) += temp1; (h) = temp1 + temp2;              \
+#define P(a,b,c,d,e,f,g,h,x,K)                                      \
+    do                                                              \
+    {                                                               \
+        local.temp1 = (h) + S3(e) + F1((e),(f),(g)) + (K) + (x);    \
+        local.temp2 = S2(a) + F0((a),(b),(c));                      \
+        (d) += local.temp1; (h) = local.temp1 + local.temp2;        \
     } while( 0 )
 
 int mbedtls_internal_sha256_process( mbedtls_sha256_context *ctx,
                                 const unsigned char data[64] )
 {
-    uint32_t temp1, temp2, W[64];
-    uint32_t A[8];
+    struct
+    {
+        uint32_t temp1, temp2, W[64];
+        uint32_t A[8];
+    } local;
+
     unsigned int i;
 
     SHA256_VALIDATE_RET( ctx != NULL );
     SHA256_VALIDATE_RET( (const unsigned char *)data != NULL );
 
     for( i = 0; i < 8; i++ )
-        A[i] = ctx->state[i];
+        local.A[i] = ctx->state[i];
 
 #if defined(MBEDTLS_SHA256_SMALLER)
     for( i = 0; i < 64; i++ )
     {
         if( i < 16 )
-            GET_UINT32_BE( W[i], data, 4 * i );
+            GET_UINT32_BE( local.W[i], data, 4 * i );
         else
             R( i );
 
-        P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i] );
+        P( local.A[0], local.A[1], local.A[2], local.A[3], local.A[4],
+           local.A[5], local.A[6], local.A[7], local.W[i], K[i] );
 
-        temp1 = A[7]; A[7] = A[6]; A[6] = A[5]; A[5] = A[4]; A[4] = A[3];
-        A[3] = A[2]; A[2] = A[1]; A[1] = A[0]; A[0] = temp1;
+        local.temp1 = local.A[7]; local.A[7] = local.A[6];
+        local.A[6] = local.A[5]; local.A[5] = local.A[4];
+        local.A[4] = local.A[3]; local.A[3] = local.A[2];
+        local.A[2] = local.A[1]; local.A[1] = local.A[0];
+        local.A[0] = local.temp1;
     }
 #else /* MBEDTLS_SHA256_SMALLER */
     for( i = 0; i < 16; i++ )
-        GET_UINT32_BE( W[i], data, 4 * i );
+        GET_UINT32_BE( local.W[i], data, 4 * i );
 
     for( i = 0; i < 16; i += 8 )
     {
-        P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i+0], K[i+0] );
-        P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i+1], K[i+1] );
-        P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i+2], K[i+2] );
-        P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i+3], K[i+3] );
-        P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i+4], K[i+4] );
-        P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i+5], K[i+5] );
-        P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i+6], K[i+6] );
-        P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i+7], K[i+7] );
+        P( local.A[0], local.A[1], local.A[2], local.A[3], local.A[4],
+           local.A[5], local.A[6], local.A[7], local.W[i+0], K[i+0] );
+        P( local.A[7], local.A[0], local.A[1], local.A[2], local.A[3],
+           local.A[4], local.A[5], local.A[6], local.W[i+1], K[i+1] );
+        P( local.A[6], local.A[7], local.A[0], local.A[1], local.A[2],
+           local.A[3], local.A[4], local.A[5], local.W[i+2], K[i+2] );
+        P( local.A[5], local.A[6], local.A[7], local.A[0], local.A[1],
+           local.A[2], local.A[3], local.A[4], local.W[i+3], K[i+3] );
+        P( local.A[4], local.A[5], local.A[6], local.A[7], local.A[0],
+           local.A[1], local.A[2], local.A[3], local.W[i+4], K[i+4] );
+        P( local.A[3], local.A[4], local.A[5], local.A[6], local.A[7],
+           local.A[0], local.A[1], local.A[2], local.W[i+5], K[i+5] );
+        P( local.A[2], local.A[3], local.A[4], local.A[5], local.A[6],
+           local.A[7], local.A[0], local.A[1], local.W[i+6], K[i+6] );
+        P( local.A[1], local.A[2], local.A[3], local.A[4], local.A[5],
+           local.A[6], local.A[7], local.A[0], local.W[i+7], K[i+7] );
     }
 
     for( i = 16; i < 64; i += 8 )
     {
-        P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(i+0), K[i+0] );
-        P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(i+1), K[i+1] );
-        P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(i+2), K[i+2] );
-        P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(i+3), K[i+3] );
-        P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(i+4), K[i+4] );
-        P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(i+5), K[i+5] );
-        P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(i+6), K[i+6] );
-        P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(i+7), K[i+7] );
+        P( local.A[0], local.A[1], local.A[2], local.A[3], local.A[4],
+           local.A[5], local.A[6], local.A[7], R(i+0), K[i+0] );
+        P( local.A[7], local.A[0], local.A[1], local.A[2], local.A[3],
+           local.A[4], local.A[5], local.A[6], R(i+1), K[i+1] );
+        P( local.A[6], local.A[7], local.A[0], local.A[1], local.A[2],
+           local.A[3], local.A[4], local.A[5], R(i+2), K[i+2] );
+        P( local.A[5], local.A[6], local.A[7], local.A[0], local.A[1],
+           local.A[2], local.A[3], local.A[4], R(i+3), K[i+3] );
+        P( local.A[4], local.A[5], local.A[6], local.A[7], local.A[0],
+           local.A[1], local.A[2], local.A[3], R(i+4), K[i+4] );
+        P( local.A[3], local.A[4], local.A[5], local.A[6], local.A[7],
+           local.A[0], local.A[1], local.A[2], R(i+5), K[i+5] );
+        P( local.A[2], local.A[3], local.A[4], local.A[5], local.A[6],
+           local.A[7], local.A[0], local.A[1], R(i+6), K[i+6] );
+        P( local.A[1], local.A[2], local.A[3], local.A[4], local.A[5],
+           local.A[6], local.A[7], local.A[0], R(i+7), K[i+7] );
     }
 #endif /* MBEDTLS_SHA256_SMALLER */
 
     for( i = 0; i < 8; i++ )
-        ctx->state[i] += A[i];
+        ctx->state[i] += local.A[i];
+
+    /* Zeroise buffers and variables to clear sensitive data from memory. */
+    mbedtls_platform_zeroize( &local, sizeof( local ) );
 
     return( 0 );
 }
diff --git a/library/sha512.c b/library/sha512.c
index e881198..06a628a 100644
--- a/library/sha512.c
+++ b/library/sha512.c
@@ -232,8 +232,11 @@
                                      const unsigned char data[128] )
 {
     int i;
-    uint64_t temp1, temp2, W[80];
-    uint64_t A[8];
+    struct
+    {
+        uint64_t temp1, temp2, W[80];
+        uint64_t A[8];
+    } local;
 
     SHA512_VALIDATE_RET( ctx != NULL );
     SHA512_VALIDATE_RET( (const unsigned char *)data != NULL );
@@ -250,64 +253,79 @@
 #define F0(x,y,z) (((x) & (y)) | ((z) & ((x) | (y))))
 #define F1(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
 
-#define P(a,b,c,d,e,f,g,h,x,K)                                  \
-    do                                                          \
-    {                                                           \
-        temp1 = (h) + S3(e) + F1((e),(f),(g)) + (K) + (x);      \
-        temp2 = S2(a) + F0((a),(b),(c));                        \
-        (d) += temp1; (h) = temp1 + temp2;                      \
+#define P(a,b,c,d,e,f,g,h,x,K)                                      \
+    do                                                              \
+    {                                                               \
+        local.temp1 = (h) + S3(e) + F1((e),(f),(g)) + (K) + (x);    \
+        local.temp2 = S2(a) + F0((a),(b),(c));                      \
+        (d) += local.temp1; (h) = local.temp1 + local.temp2;        \
     } while( 0 )
 
     for( i = 0; i < 8; i++ )
-        A[i] = ctx->state[i];
+        local.A[i] = ctx->state[i];
 
 #if defined(MBEDTLS_SHA512_SMALLER)
     for( i = 0; i < 80; i++ )
     {
         if( i < 16 )
         {
-            GET_UINT64_BE( W[i], data, i << 3 );
+            GET_UINT64_BE( local.W[i], data, i << 3 );
         }
         else
         {
-            W[i] = S1(W[i -  2]) + W[i -  7] +
-                   S0(W[i - 15]) + W[i - 16];
+            local.W[i] = S1(local.W[i -  2]) + local.W[i -  7] +
+                   S0(local.W[i - 15]) + local.W[i - 16];
         }
 
-        P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i] );
+        P( local.A[0], local.A[1], local.A[2], local.A[3], local.A[4],
+           local.A[5], local.A[6], local.A[7], local.W[i], K[i] );
 
-        temp1 = A[7]; A[7] = A[6]; A[6] = A[5]; A[5] = A[4]; A[4] = A[3];
-        A[3] = A[2]; A[2] = A[1]; A[1] = A[0]; A[0] = temp1;
+        local.temp1 = local.A[7]; local.A[7] = local.A[6];
+        local.A[6] = local.A[5]; local.A[5] = local.A[4];
+        local.A[4] = local.A[3]; local.A[3] = local.A[2];
+        local.A[2] = local.A[1]; local.A[1] = local.A[0];
+        local.A[0] = local.temp1;
     }
 #else /* MBEDTLS_SHA512_SMALLER */
     for( i = 0; i < 16; i++ )
     {
-        GET_UINT64_BE( W[i], data, i << 3 );
+        GET_UINT64_BE( local.W[i], data, i << 3 );
     }
 
     for( ; i < 80; i++ )
     {
-        W[i] = S1(W[i -  2]) + W[i -  7] +
-               S0(W[i - 15]) + W[i - 16];
+        local.W[i] = S1(local.W[i -  2]) + local.W[i -  7] +
+               S0(local.W[i - 15]) + local.W[i - 16];
     }
 
     i = 0;
     do
     {
-        P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i] ); i++;
-        P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i], K[i] ); i++;
-        P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i], K[i] ); i++;
-        P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i], K[i] ); i++;
-        P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i], K[i] ); i++;
-        P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i], K[i] ); i++;
-        P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i], K[i] ); i++;
-        P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i], K[i] ); i++;
+        P( local.A[0], local.A[1], local.A[2], local.A[3], local.A[4],
+           local.A[5], local.A[6], local.A[7], local.W[i], K[i] ); i++;
+        P( local.A[7], local.A[0], local.A[1], local.A[2], local.A[3],
+           local.A[4], local.A[5], local.A[6], local.W[i], K[i] ); i++;
+        P( local.A[6], local.A[7], local.A[0], local.A[1], local.A[2],
+           local.A[3], local.A[4], local.A[5], local.W[i], K[i] ); i++;
+        P( local.A[5], local.A[6], local.A[7], local.A[0], local.A[1],
+           local.A[2], local.A[3], local.A[4], local.W[i], K[i] ); i++;
+        P( local.A[4], local.A[5], local.A[6], local.A[7], local.A[0],
+           local.A[1], local.A[2], local.A[3], local.W[i], K[i] ); i++;
+        P( local.A[3], local.A[4], local.A[5], local.A[6], local.A[7],
+           local.A[0], local.A[1], local.A[2], local.W[i], K[i] ); i++;
+        P( local.A[2], local.A[3], local.A[4], local.A[5], local.A[6],
+           local.A[7], local.A[0], local.A[1], local.W[i], K[i] ); i++;
+        P( local.A[1], local.A[2], local.A[3], local.A[4], local.A[5],
+           local.A[6], local.A[7], local.A[0], local.W[i], K[i] ); i++;
     }
     while( i < 80 );
 #endif /* MBEDTLS_SHA512_SMALLER */
 
     for( i = 0; i < 8; i++ )
-        ctx->state[i] += A[i];
+        ctx->state[i] += local.A[i];
+
+    /* Zeroise buffers and variables to clear sensitive data from memory. */
+    mbedtls_platform_zeroize( &local, sizeof( local ) );
 
     return( 0 );
 }
diff --git a/library/ssl_msg.c b/library/ssl_msg.c
index 0718d5a..72f09bb 100644
--- a/library/ssl_msg.c
+++ b/library/ssl_msg.c
@@ -850,20 +850,21 @@
          * Encrypt and authenticate
          */
 
-        if( ( ret = mbedtls_cipher_auth_encrypt( &transform->cipher_ctx_enc,
+        if( ( ret = mbedtls_cipher_auth_encrypt_ext( &transform->cipher_ctx_enc,
                    iv, transform->ivlen,
-                   add_data, add_data_len,       /* add data     */
-                   data, rec->data_len,          /* source       */
-                   data, &rec->data_len,         /* destination  */
-                   data + rec->data_len, transform->taglen ) ) != 0 )
+                   add_data, add_data_len,
+                   data, rec->data_len,                     /* src */
+                   data, rec->buf_len - (data - rec->buf),  /* dst */
+                   &rec->data_len,
+                   transform->taglen ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_auth_encrypt", ret );
             return( ret );
         }
         MBEDTLS_SSL_DEBUG_BUF( 4, "after encrypt: tag",
-                               data + rec->data_len, transform->taglen );
+                               data + rec->data_len - transform->taglen,
+                               transform->taglen );
         /* Account for authentication tag. */
-        rec->data_len += transform->taglen;
         post_avail -= transform->taglen;
 
         /*
@@ -1422,12 +1423,11 @@
         /*
          * Decrypt and authenticate
          */
-        if( ( ret = mbedtls_cipher_auth_decrypt( &transform->cipher_ctx_dec,
+        if( ( ret = mbedtls_cipher_auth_decrypt_ext( &transform->cipher_ctx_dec,
                   iv, transform->ivlen,
                   add_data, add_data_len,
-                  data, rec->data_len,
-                  data, &olen,
-                  data + rec->data_len,
+                  data, rec->data_len + transform->taglen,          /* src */
+                  data, rec->buf_len - (data - rec->buf), &olen,    /* dst */
                   transform->taglen ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_auth_decrypt", ret );
diff --git a/library/ssl_ticket.c b/library/ssl_ticket.c
index e3e8023..626d137 100644
--- a/library/ssl_ticket.c
+++ b/library/ssl_ticket.c
@@ -209,7 +209,6 @@
     unsigned char *iv = start + TICKET_KEY_NAME_BYTES;
     unsigned char *state_len_bytes = iv + TICKET_IV_BYTES;
     unsigned char *state = state_len_bytes + TICKET_CRYPT_LEN_BYTES;
-    unsigned char *tag;
     size_t clear_len, ciph_len;
 
     *tlen = 0;
@@ -250,23 +249,23 @@
     state_len_bytes[1] = ( clear_len      ) & 0xff;
 
     /* Encrypt and authenticate */
-    tag = state + clear_len;
-    if( ( ret = mbedtls_cipher_auth_encrypt( &key->ctx,
+    if( ( ret = mbedtls_cipher_auth_encrypt_ext( &key->ctx,
                     iv, TICKET_IV_BYTES,
                     /* Additional data: key name, IV and length */
                     key_name, TICKET_ADD_DATA_LEN,
-                    state, clear_len, state, &ciph_len,
-                    tag, TICKET_AUTH_TAG_BYTES ) ) != 0 )
+                    state, clear_len,
+                    state, end - state, &ciph_len,
+                    TICKET_AUTH_TAG_BYTES ) ) != 0 )
     {
         goto cleanup;
     }
-    if( ciph_len != clear_len )
+    if( ciph_len != clear_len + TICKET_AUTH_TAG_BYTES )
     {
         ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
         goto cleanup;
     }
 
-    *tlen = TICKET_MIN_LEN + ciph_len;
+    *tlen = TICKET_MIN_LEN + ciph_len - TICKET_AUTH_TAG_BYTES;
 
 cleanup:
 #if defined(MBEDTLS_THREADING_C)
@@ -308,7 +307,6 @@
     unsigned char *iv = buf + TICKET_KEY_NAME_BYTES;
     unsigned char *enc_len_p = iv + TICKET_IV_BYTES;
     unsigned char *ticket = enc_len_p + TICKET_CRYPT_LEN_BYTES;
-    unsigned char *tag;
     size_t enc_len, clear_len;
 
     if( ctx == NULL || ctx->f_rng == NULL )
@@ -326,7 +324,6 @@
         goto cleanup;
 
     enc_len = ( enc_len_p[0] << 8 ) | enc_len_p[1];
-    tag = ticket + enc_len;
 
     if( len != TICKET_MIN_LEN + enc_len )
     {
@@ -344,13 +341,13 @@
     }
 
     /* Decrypt and authenticate */
-    if( ( ret = mbedtls_cipher_auth_decrypt( &key->ctx,
+    if( ( ret = mbedtls_cipher_auth_decrypt_ext( &key->ctx,
                     iv, TICKET_IV_BYTES,
                     /* Additional data: key name, IV and length */
                     key_name, TICKET_ADD_DATA_LEN,
-                    ticket, enc_len,
-                    ticket, &clear_len,
-                    tag, TICKET_AUTH_TAG_BYTES ) ) != 0 )
+                    ticket, enc_len + TICKET_AUTH_TAG_BYTES,
+                    ticket, enc_len, &clear_len,
+                    TICKET_AUTH_TAG_BYTES ) ) != 0 )
     {
         if( ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED )
             ret = MBEDTLS_ERR_SSL_INVALID_MAC;
diff --git a/library/x509_crt.c b/library/x509_crt.c
index 71e9cec..a623c57 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -1304,6 +1304,7 @@
 
     if( crt->sig_oid.len != sig_oid2.len ||
         memcmp( crt->sig_oid.p, sig_oid2.p, crt->sig_oid.len ) != 0 ||
+        sig_params1.tag != sig_params2.tag ||
         sig_params1.len != sig_params2.len ||
         ( sig_params1.len != 0 &&
           memcmp( sig_params1.p, sig_params2.p, sig_params1.len ) != 0 ) )
diff --git a/tests/data_files/Makefile b/tests/data_files/Makefile
index bf2f538..b90ce74 100644
--- a/tests/data_files/Makefile
+++ b/tests/data_files/Makefile
@@ -208,7 +208,11 @@
 	$(OPENSSL) x509 -in $< -out $@ -inform PEM -outform DER
 all_final += cli-rsa-sha256.crt.der
 
- cli-rsa.key.der: $(cli_crt_key_file_rsa)
+cli-rsa-sha256-badalg.crt.der: cli-rsa-sha256.crt.der
+	hexdump -ve '1/1 "%.2X"' $< | sed "s/06092A864886F70D01010B0500/06092A864886F70D01010B0900/2" | xxd -r -p > $@
+all_final += cli-rsa-sha256-badalg.crt.der
+
+cli-rsa.key.der: $(cli_crt_key_file_rsa)
 	$(OPENSSL) pkey -in $< -out $@ -inform PEM -outform DER
 all_final += cli-rsa.key.der
 
diff --git a/tests/data_files/cli-rsa-sha256-badalg.crt.der b/tests/data_files/cli-rsa-sha256-badalg.crt.der
new file mode 100644
index 0000000..c40ba2a
--- /dev/null
+++ b/tests/data_files/cli-rsa-sha256-badalg.crt.der
Binary files differ
diff --git a/tests/suites/test_suite_cipher.function b/tests/suites/test_suite_cipher.function
index ea1e9ad..1d98f3d 100644
--- a/tests/suites/test_suite_cipher.function
+++ b/tests/suites/test_suite_cipher.function
@@ -13,6 +13,65 @@
 #include "test/psa_crypto_helpers.h"
 #endif
 
+#if defined(MBEDTLS_CIPHER_MODE_AEAD) || defined(MBEDTLS_NIST_KW_C)
+#define MBEDTLS_CIPHER_AUTH_CRYPT
+#endif
+
+#if defined(MBEDTLS_CIPHER_AUTH_CRYPT)
+/* Helper for resetting key/direction
+ *
+ * The documentation doesn't explicitly say whether calling
+ * mbedtls_cipher_setkey() twice is allowed or not. This currently works with
+ * the default software implementation, but only by accident. It isn't
+ * guaranteed to work with new ciphers or with alternative implementations of
+ * individual ciphers, and it doesn't work with the PSA wrappers. So don't do
+ * it, and instead start with a fresh context.
+ */
+static int cipher_reset_key( mbedtls_cipher_context_t *ctx, int cipher_id,
+        int use_psa, size_t tag_len, const data_t *key, int direction )
+{
+    mbedtls_cipher_free( ctx );
+    mbedtls_cipher_init( ctx );
+
+#if !defined(MBEDTLS_USE_PSA_CRYPTO)
+    (void) use_psa;
+    (void) tag_len;
+#else
+    if( use_psa == 1 )
+    {
+        TEST_ASSERT( 0 == mbedtls_cipher_setup_psa( ctx,
+                              mbedtls_cipher_info_from_type( cipher_id ),
+                              tag_len ) );
+    }
+    else
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+    {
+        TEST_ASSERT( 0 == mbedtls_cipher_setup( ctx,
+                              mbedtls_cipher_info_from_type( cipher_id ) ) );
+    }
+
+    TEST_ASSERT( 0 == mbedtls_cipher_setkey( ctx, key->x, 8 * key->len,
+                                             direction ) );
+    return( 1 );
+
+exit:
+    return( 0 );
+}
+
+/*
+ * Check if a buffer is all-0 bytes:
+ * return   1 if it is,
+ *          0 if it isn't.
+ */
+int buffer_is_all_zero( const uint8_t *buf, size_t size )
+{
+    for( size_t i = 0; i < size; i++ )
+        if( buf[i] != 0 )
+            return 0;
+    return 1;
+}
+#endif /* MBEDTLS_CIPHER_AUTH_CRYPT */
+
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
@@ -485,6 +544,108 @@
                                      NULL, valid_size ) );
 #endif /* defined(MBEDTLS_CIPHER_MODE_AEAD) */
 
+#if defined(MBEDTLS_CIPHER_MODE_AEAD) || defined(MBEDTLS_NIST_KW_C)
+    /* mbedtls_cipher_auth_encrypt_ext */
+    TEST_INVALID_PARAM_RET(
+        MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA,
+        mbedtls_cipher_auth_encrypt_ext( NULL,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size, &size_t_var,
+                                         valid_size ) );
+    TEST_INVALID_PARAM_RET(
+        MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA,
+        mbedtls_cipher_auth_encrypt_ext( &valid_ctx,
+                                         NULL, valid_size,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size, &size_t_var,
+                                         valid_size ) );
+    TEST_INVALID_PARAM_RET(
+        MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA,
+        mbedtls_cipher_auth_encrypt_ext( &valid_ctx,
+                                         valid_buffer, valid_size,
+                                         NULL, valid_size,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size, &size_t_var,
+                                         valid_size ) );
+    TEST_INVALID_PARAM_RET(
+        MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA,
+        mbedtls_cipher_auth_encrypt_ext( &valid_ctx,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size,
+                                         NULL, valid_size,
+                                         valid_buffer, valid_size, &size_t_var,
+                                         valid_size ) );
+    TEST_INVALID_PARAM_RET(
+        MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA,
+        mbedtls_cipher_auth_encrypt_ext( &valid_ctx,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size,
+                                         NULL, valid_size, &size_t_var,
+                                         valid_size ) );
+    TEST_INVALID_PARAM_RET(
+        MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA,
+        mbedtls_cipher_auth_encrypt_ext( &valid_ctx,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size, NULL,
+                                         valid_size ) );
+
+    /* mbedtls_cipher_auth_decrypt_ext */
+    TEST_INVALID_PARAM_RET(
+        MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA,
+        mbedtls_cipher_auth_decrypt_ext( NULL,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size, &size_t_var,
+                                         valid_size ) );
+    TEST_INVALID_PARAM_RET(
+        MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA,
+        mbedtls_cipher_auth_decrypt_ext( &valid_ctx,
+                                         NULL, valid_size,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size, &size_t_var,
+                                         valid_size ) );
+    TEST_INVALID_PARAM_RET(
+        MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA,
+        mbedtls_cipher_auth_decrypt_ext( &valid_ctx,
+                                         valid_buffer, valid_size,
+                                         NULL, valid_size,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size, &size_t_var,
+                                         valid_size ) );
+    TEST_INVALID_PARAM_RET(
+        MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA,
+        mbedtls_cipher_auth_decrypt_ext( &valid_ctx,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size,
+                                         NULL, valid_size,
+                                         valid_buffer, valid_size, &size_t_var,
+                                         valid_size ) );
+    TEST_INVALID_PARAM_RET(
+        MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA,
+        mbedtls_cipher_auth_decrypt_ext( &valid_ctx,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size,
+                                         NULL, valid_size, &size_t_var,
+                                         valid_size ) );
+    TEST_INVALID_PARAM_RET(
+        MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA,
+        mbedtls_cipher_auth_decrypt_ext( &valid_ctx,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size,
+                                         valid_buffer, valid_size, NULL,
+                                         valid_size ) );
+#endif /* MBEDTLS_CIPHER_MODE_AEAD || MBEDTLS_NIST_KW_C */
+
     /* mbedtls_cipher_free() */
     TEST_VALID_PARAM( mbedtls_cipher_free( NULL ) );
 exit:
@@ -959,129 +1120,338 @@
 }
 /* END_CASE */
 
-/* BEGIN_CASE depends_on:MBEDTLS_CIPHER_MODE_AEAD */
+/* BEGIN_CASE depends_on:MBEDTLS_CIPHER_AUTH_CRYPT */
 void auth_crypt_tv( int cipher_id, data_t * key, data_t * iv,
                     data_t * ad, data_t * cipher, data_t * tag,
                     char * result, data_t * clear, int use_psa )
 {
-    /* Takes an AEAD ciphertext + tag and performs a pair
-     * of AEAD decryption and AEAD encryption. It checks that
+    /*
+     * Take an AEAD ciphertext + tag and perform a pair
+     * of AEAD decryption and AEAD encryption. Check that
      * this results in the expected plaintext, and that
-     * decryption and encryption are inverse to one another. */
+     * decryption and encryption are inverse to one another.
+     *
+     * Do that twice:
+     * - once with legacy functions auth_decrypt/auth_encrypt
+     * - once with new functions auth_decrypt_ext/auth_encrypt_ext
+     * This allows testing both without duplicating test cases.
+     */
 
     int ret;
-    unsigned char output[300];        /* Temporary buffer for results of
-                                       * encryption and decryption. */
-    unsigned char *output_tag = NULL; /* Temporary buffer for tag in the
-                                       * encryption step. */
+    int using_nist_kw, using_nist_kw_padding;
 
     mbedtls_cipher_context_t ctx;
     size_t outlen;
 
+    unsigned char *cipher_plus_tag = NULL;
+    size_t cipher_plus_tag_len;
+    unsigned char *decrypt_buf = NULL;
+    size_t decrypt_buf_len = 0;
+    unsigned char *encrypt_buf = NULL;
+    size_t encrypt_buf_len = 0;
+
+#if !defined(MBEDTLS_DEPRECATED_WARNING) && \
+    !defined(MBEDTLS_DEPRECATED_REMOVED)
     unsigned char *tmp_tag    = NULL;
     unsigned char *tmp_cipher = NULL;
+    unsigned char *tag_buf = NULL;
+#endif /* !MBEDTLS_DEPRECATED_WARNING && !MBEDTLS_DEPRECATED_REMOVED */
+
+    /* Null pointers are documented as valid for inputs of length 0.
+     * The test framework passes non-null pointers, so set them to NULL.
+     * key, cipher and tag can't be empty. */
+    if( iv->len == 0 )
+        iv->x = NULL;
+    if( ad->len == 0 )
+        ad->x = NULL;
+    if( clear->len == 0 )
+        clear->x = NULL;
 
     mbedtls_cipher_init( &ctx );
-    memset( output, 0xFF, sizeof( output ) );
 
-    /* Prepare context */
-#if !defined(MBEDTLS_USE_PSA_CRYPTO)
-    (void) use_psa;
-#else
+    /* Initialize PSA Crypto */
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
     if( use_psa == 1 )
-    {
         PSA_ASSERT( psa_crypto_init( ) );
-
-        /* PSA requires that the tag immediately follows the ciphertext. */
-        tmp_cipher = mbedtls_calloc( 1, cipher->len + tag->len );
-        TEST_ASSERT( tmp_cipher != NULL );
-        tmp_tag = tmp_cipher + cipher->len;
-
-        memcpy( tmp_cipher, cipher->x, cipher->len );
-        memcpy( tmp_tag, tag->x, tag->len );
-
-        TEST_ASSERT( 0 == mbedtls_cipher_setup_psa( &ctx,
-                              mbedtls_cipher_info_from_type( cipher_id ),
-                              tag->len ) );
-    }
-    else
+#else
+    (void) use_psa;
 #endif
+
+    /*
+     * Are we using NIST_KW? with padding?
+     */
+    using_nist_kw_padding = cipher_id == MBEDTLS_CIPHER_AES_128_KWP ||
+                            cipher_id == MBEDTLS_CIPHER_AES_192_KWP ||
+                            cipher_id == MBEDTLS_CIPHER_AES_256_KWP;
+    using_nist_kw = cipher_id == MBEDTLS_CIPHER_AES_128_KW ||
+                    cipher_id == MBEDTLS_CIPHER_AES_192_KW ||
+                    cipher_id == MBEDTLS_CIPHER_AES_256_KW ||
+                    using_nist_kw_padding;
+
+    /****************************************************************
+     *                                                              *
+     *  Part 1: non-deprecated API                                  *
+     *                                                              *
+     ****************************************************************/
+
+    /*
+     * Prepare context for decryption
+     */
+    if( ! cipher_reset_key( &ctx, cipher_id, use_psa, tag->len, key,
+                            MBEDTLS_DECRYPT ) )
+        goto exit;
+
+    /*
+     * prepare buffer for decryption
+     * (we need the tag appended to the ciphertext)
+     */
+    cipher_plus_tag_len = cipher->len + tag->len;
+    ASSERT_ALLOC( cipher_plus_tag, cipher_plus_tag_len );
+    memcpy( cipher_plus_tag, cipher->x, cipher->len );
+    memcpy( cipher_plus_tag + cipher->len, tag->x, tag->len );
+
+    /*
+     * Compute length of output buffer according to the documentation
+     */
+    if( using_nist_kw )
+        decrypt_buf_len = cipher_plus_tag_len - 8;
+    else
+        decrypt_buf_len = cipher_plus_tag_len - tag->len;
+
+
+    /*
+     * Try decrypting to a buffer that's 1B too small
+     */
+    if( decrypt_buf_len != 0 )
     {
-        tmp_tag = tag->x;
-        tmp_cipher = cipher->x;
-        TEST_ASSERT( 0 == mbedtls_cipher_setup( &ctx,
-                              mbedtls_cipher_info_from_type( cipher_id ) ) );
+        ASSERT_ALLOC( decrypt_buf, decrypt_buf_len - 1 );
+
+        outlen = 0;
+        ret = mbedtls_cipher_auth_decrypt_ext( &ctx, iv->x, iv->len,
+                ad->x, ad->len, cipher_plus_tag, cipher_plus_tag_len,
+                decrypt_buf, decrypt_buf_len - 1, &outlen, tag->len );
+        TEST_ASSERT( ret == MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+
+        mbedtls_free( decrypt_buf );
+        decrypt_buf = NULL;
     }
 
-    TEST_ASSERT( 0 == mbedtls_cipher_setkey( &ctx, key->x, 8 * key->len,
-                                             MBEDTLS_DECRYPT ) );
+    /*
+     * Authenticate and decrypt, and check result
+     */
+    ASSERT_ALLOC( decrypt_buf, decrypt_buf_len );
 
-    /* decode buffer and check tag->x */
+    outlen = 0;
+    ret = mbedtls_cipher_auth_decrypt_ext( &ctx, iv->x, iv->len,
+            ad->x, ad->len, cipher_plus_tag, cipher_plus_tag_len,
+            decrypt_buf, decrypt_buf_len, &outlen, tag->len );
 
-    /* Sanity check that we don't use overly long inputs. */
-    TEST_ASSERT( sizeof( output ) >= cipher->len );
-
-    ret = mbedtls_cipher_auth_decrypt( &ctx, iv->x, iv->len, ad->x, ad->len,
-                               tmp_cipher, cipher->len, output, &outlen,
-                               tmp_tag, tag->len );
-
-    /* make sure the message is rejected if it should be */
     if( strcmp( result, "FAIL" ) == 0 )
     {
         TEST_ASSERT( ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED );
-        goto exit;
+        TEST_ASSERT( buffer_is_all_zero( decrypt_buf, decrypt_buf_len ) );
+    }
+    else
+    {
+        TEST_ASSERT( ret == 0 );
+        ASSERT_COMPARE( decrypt_buf, outlen, clear->x, clear->len );
     }
 
-    /* otherwise, make sure it was decrypted properly */
-    TEST_ASSERT( ret == 0 );
+    /* Free this, but keep cipher_plus_tag for deprecated function with PSA */
+    mbedtls_free( decrypt_buf );
+    decrypt_buf = NULL;
 
-    TEST_ASSERT( outlen == clear->len );
-    TEST_ASSERT( memcmp( output, clear->x, clear->len ) == 0 );
+    /*
+     * Encrypt back if test data was authentic
+     */
+    if( strcmp( result, "FAIL" ) != 0 )
+    {
+        /* prepare context for encryption */
+        if( ! cipher_reset_key( &ctx, cipher_id, use_psa, tag->len, key,
+                                MBEDTLS_ENCRYPT ) )
+            goto exit;
 
-    /* then encrypt the clear->x and make sure we get the same ciphertext and tag->x */
-    mbedtls_cipher_free( &ctx );
+        /*
+         * Compute size of output buffer according to documentation
+         */
+        if( using_nist_kw )
+        {
+            encrypt_buf_len = clear->len + 8;
+            if( using_nist_kw_padding && encrypt_buf_len % 8 != 0 )
+                encrypt_buf_len += 8 - encrypt_buf_len % 8;
+        }
+        else
+        {
+            encrypt_buf_len = clear->len + tag->len;
+        }
+
+        /*
+         * Try encrypting with an output buffer that's 1B too small
+         */
+        ASSERT_ALLOC( encrypt_buf, encrypt_buf_len - 1 );
+
+        outlen = 0;
+        ret = mbedtls_cipher_auth_encrypt_ext( &ctx, iv->x, iv->len,
+                ad->x, ad->len, clear->x, clear->len,
+                encrypt_buf, encrypt_buf_len - 1, &outlen, tag->len );
+        TEST_ASSERT( ret != 0 );
+
+        mbedtls_free( encrypt_buf );
+        encrypt_buf = NULL;
+
+        /*
+         * Encrypt and check the result
+         */
+        ASSERT_ALLOC( encrypt_buf, encrypt_buf_len );
+
+        outlen = 0;
+        ret = mbedtls_cipher_auth_encrypt_ext( &ctx, iv->x, iv->len,
+                ad->x, ad->len, clear->x, clear->len,
+                encrypt_buf, encrypt_buf_len, &outlen, tag->len );
+        TEST_ASSERT( ret == 0 );
+
+        TEST_ASSERT( outlen == cipher->len + tag->len );
+        TEST_ASSERT( memcmp( encrypt_buf, cipher->x, cipher->len ) == 0 );
+        TEST_ASSERT( memcmp( encrypt_buf + cipher->len,
+                             tag->x, tag->len ) == 0 );
+
+        mbedtls_free( encrypt_buf );
+        encrypt_buf = NULL;
+    }
+
+    /****************************************************************
+     *                                                              *
+     *  Part 2: deprecated API                                      *
+     *                                                              *
+     ****************************************************************/
+
+#if !defined(MBEDTLS_DEPRECATED_WARNING) && \
+    !defined(MBEDTLS_DEPRECATED_REMOVED)
+
+    /*
+     * Prepare context for decryption
+     */
+    if( ! cipher_reset_key( &ctx, cipher_id, use_psa, tag->len, key,
+                            MBEDTLS_DECRYPT ) )
+        goto exit;
+
+    /*
+     * Prepare pointers for decryption
+     */
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     if( use_psa == 1 )
     {
-        TEST_ASSERT( 0 == mbedtls_cipher_setup_psa( &ctx,
-                              mbedtls_cipher_info_from_type( cipher_id ),
-                              tag->len ) );
+        /* PSA requires that the tag immediately follows the ciphertext.
+         * Fortunately, we already have that from testing the new API. */
+        tmp_cipher = cipher_plus_tag;
+        tmp_tag = tmp_cipher + cipher->len;
     }
     else
-#endif
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
     {
-        TEST_ASSERT( 0 == mbedtls_cipher_setup( &ctx,
-                              mbedtls_cipher_info_from_type( cipher_id ) ) );
+        tmp_cipher = cipher->x;
+        tmp_tag = tag->x;
     }
-    TEST_ASSERT( 0 == mbedtls_cipher_setkey( &ctx, key->x, 8 * key->len,
-                                             MBEDTLS_ENCRYPT ) );
 
-    memset( output, 0xFF, sizeof( output ) );
+    /*
+     * Authenticate and decrypt, and check result
+     */
+
+    ASSERT_ALLOC( decrypt_buf, cipher->len );
     outlen = 0;
+    ret = mbedtls_cipher_auth_decrypt( &ctx, iv->x, iv->len, ad->x, ad->len,
+                               tmp_cipher, cipher->len, decrypt_buf, &outlen,
+                               tmp_tag, tag->len );
 
-    /* Sanity check that we don't use overly long inputs. */
-    TEST_ASSERT( sizeof( output ) >= clear->len + tag->len );
+    if( using_nist_kw )
+    {
+        /* NIST_KW with legacy API */
+        TEST_ASSERT( ret == MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
+    }
+    else if( strcmp( result, "FAIL" ) == 0 )
+    {
+        /* unauthentic message */
+        TEST_ASSERT( ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED );
+        TEST_ASSERT( buffer_is_all_zero( decrypt_buf, cipher->len ) );
+    }
+    else
+    {
+        /* authentic message: is the plaintext correct? */
+        TEST_ASSERT( ret == 0 );
+        ASSERT_COMPARE(  decrypt_buf, outlen, clear->x, clear->len );
+    }
 
-    output_tag = output + clear->len;
-    ret = mbedtls_cipher_auth_encrypt( &ctx, iv->x, iv->len, ad->x, ad->len,
-                               clear->x, clear->len, output, &outlen,
-                               output_tag, tag->len );
-    TEST_ASSERT( ret == 0 );
+    mbedtls_free( decrypt_buf );
+    decrypt_buf = NULL;
+    mbedtls_free( cipher_plus_tag );
+    cipher_plus_tag = NULL;
 
-    TEST_ASSERT( outlen == cipher->len );
-    TEST_ASSERT( memcmp( output, cipher->x, cipher->len ) == 0 );
-    TEST_ASSERT( memcmp( output_tag, tag->x, tag->len ) == 0 );
+    /*
+     * Encrypt back if test data was authentic
+     */
+    if( strcmp( result, "FAIL" ) != 0 )
+    {
+        /* prepare context for encryption */
+        if( ! cipher_reset_key( &ctx, cipher_id, use_psa, tag->len, key,
+                                MBEDTLS_ENCRYPT ) )
+            goto exit;
+
+        /* prepare buffers for encryption */
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+        if( use_psa )
+        {
+            ASSERT_ALLOC( cipher_plus_tag, cipher->len + tag->len );
+            tmp_cipher = cipher_plus_tag;
+            tmp_tag = cipher_plus_tag + cipher->len;
+        }
+        else
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+        {
+            ASSERT_ALLOC( encrypt_buf, cipher->len );
+            ASSERT_ALLOC( tag_buf, tag->len );
+            tmp_cipher = encrypt_buf;
+            tmp_tag = tag_buf;
+        }
+
+        /*
+         * Encrypt and check the result
+         */
+        outlen = 0;
+        ret = mbedtls_cipher_auth_encrypt( &ctx, iv->x, iv->len, ad->x, ad->len,
+                                   clear->x, clear->len, tmp_cipher, &outlen,
+                                   tmp_tag, tag->len );
+
+        if( using_nist_kw )
+        {
+            TEST_ASSERT( ret == MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
+        }
+        else
+        {
+            TEST_ASSERT( ret == 0 );
+
+            TEST_ASSERT( outlen == cipher->len );
+            if( cipher->len != 0 )
+                TEST_ASSERT( memcmp( tmp_cipher, cipher->x, cipher->len ) == 0 );
+            TEST_ASSERT( memcmp( tmp_tag, tag->x, tag->len ) == 0 );
+        }
+    }
+
+#endif /* !MBEDTLS_DEPRECATED_WARNING && !MBEDTLS_DEPRECATED_REMOVED */
 
 exit:
 
     mbedtls_cipher_free( &ctx );
+    mbedtls_free( decrypt_buf );
+    mbedtls_free( encrypt_buf );
+    mbedtls_free( cipher_plus_tag );
+#if !defined(MBEDTLS_DEPRECATED_WARNING) && \
+    !defined(MBEDTLS_DEPRECATED_REMOVED)
+    mbedtls_free( tag_buf );
+#endif /* !MBEDTLS_DEPRECATED_WARNING && !MBEDTLS_DEPRECATED_REMOVED */
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     if( use_psa == 1 )
-    {
-        mbedtls_free( tmp_cipher );
         PSA_DONE( );
-    }
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 }
 /* END_CASE */
diff --git a/tests/suites/test_suite_dhm.data b/tests/suites/test_suite_dhm.data
index 4e884f4..c4795b6 100644
--- a/tests/suites/test_suite_dhm.data
+++ b/tests/suites/test_suite_dhm.data
@@ -22,6 +22,12 @@
 Diffie-Hellman zero modulus
 dhm_do_dhm:10:"0":10:"5":MBEDTLS_ERR_DHM_BAD_INPUT_DATA
 
+Diffie-Hellman MPI_MAX_SIZE modulus
+dhm_make_public:MBEDTLS_MPI_MAX_SIZE:10:"5":0
+
+Diffie-Hellman MPI_MAX_SIZE + 1 modulus
+dhm_make_public:MBEDTLS_MPI_MAX_SIZE + 1:10:"5":MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED+MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
 Diffie-Hellman load parameters from file [#1]
 dhm_file:"data_files/dhparams.pem":"9e35f430443a09904f3a39a979797d070df53378e79c2438bef4e761f3c714553328589b041c809be1d6c6b5f1fc9f47d3a25443188253a992a56818b37ba9de5a40d362e56eff0be5417474c125c199272c8fe41dea733df6f662c92ae76556e755d10c64e6a50968f67fc6ea73d0dca8569be2ba204e23580d8bca2f4975b3":"02":128
 
diff --git a/tests/suites/test_suite_dhm.function b/tests/suites/test_suite_dhm.function
index 0a5c617..1726b9e 100644
--- a/tests/suites/test_suite_dhm.function
+++ b/tests/suites/test_suite_dhm.function
@@ -223,6 +223,36 @@
 }
 /* END_CASE */
 
+/* BEGIN_CASE */
+void dhm_make_public( int P_bytes, int radix_G, char *input_G, int result )
+{
+    mbedtls_mpi P, G;
+    mbedtls_dhm_context ctx;
+    unsigned char output[MBEDTLS_MPI_MAX_SIZE];
+
+    mbedtls_mpi_init( &P );
+    mbedtls_mpi_init( &G );
+    mbedtls_dhm_init( &ctx );
+
+    TEST_ASSERT( mbedtls_mpi_lset( &P, 1 ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_shift_l( &P, ( P_bytes * 8 ) - 1 ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_set_bit( &P, 0, 1 ) == 0 );
+
+    TEST_ASSERT( mbedtls_mpi_read_string( &G, radix_G, input_G ) == 0 );
+
+    TEST_ASSERT( mbedtls_dhm_set_group( &ctx, &P, &G ) == 0 );
+    TEST_ASSERT( mbedtls_dhm_make_public( &ctx, (int) mbedtls_mpi_size( &P ),
+                                          output, sizeof(output),
+                                          &mbedtls_test_rnd_pseudo_rand,
+                                          NULL ) == result );
+
+exit:
+    mbedtls_mpi_free( &P );
+    mbedtls_mpi_free( &G );
+    mbedtls_dhm_free( &ctx );
+}
+/* END_CASE */
+
 /* BEGIN_CASE depends_on:MBEDTLS_FS_IO */
 void dhm_file( char * filename, char * p, char * g, int len )
 {
diff --git a/tests/suites/test_suite_mpi.data b/tests/suites/test_suite_mpi.data
index 212c2f3..0966393 100644
--- a/tests/suites/test_suite_mpi.data
+++ b/tests/suites/test_suite_mpi.data
@@ -685,16 +685,36 @@
 Base test mbedtls_mpi_exp_mod #5 (Negative exponent)
 mbedtls_mpi_exp_mod:10:"23":10:"-13":10:"29":10:"":10:"0":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
 
-Base test mbedtls_mpi_exp_mod #7 (Negative base + exponent)
+Base test mbedtls_mpi_exp_mod #6 (Negative base + exponent)
 mbedtls_mpi_exp_mod:10:"-23":10:"-13":10:"29":10:"":10:"0":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
 
+Test mbedtls_mpi_exp_mod: MAX_SIZE exponent
+mbedtls_mpi_exp_mod_size:2:MBEDTLS_MPI_MAX_SIZE:10:10:"":0
+
+Test mbedtls_mpi_exp_mod: MAX_SIZE + 1 exponent
+mbedtls_mpi_exp_mod_size:2:MBEDTLS_MPI_MAX_SIZE + 1:10:10:"":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+Test mbedtls_mpi_exp_mod: MAX_SIZE modulus
+mbedtls_mpi_exp_mod_size:2:2:MBEDTLS_MPI_MAX_SIZE:10:"":0
+
+Test mbedtls_mpi_exp_mod: MAX_SIZE + 1 modulus
+mbedtls_mpi_exp_mod_size:2:2:MBEDTLS_MPI_MAX_SIZE + 1:10:"":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
+Test mbedtls_mpi_exp_mod: MAX_SIZE exponent and modulus
+mbedtls_mpi_exp_mod_size:2:MBEDTLS_MPI_MAX_SIZE:MBEDTLS_MPI_MAX_SIZE:10:"":0
+
+Test mbedtls_mpi_exp_mod: MAX_SIZE + 1 exponent and modulus
+mbedtls_mpi_exp_mod_size:2:MBEDTLS_MPI_MAX_SIZE + 1:MBEDTLS_MPI_MAX_SIZE + 1:10:"":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
+
 Test mbedtls_mpi_exp_mod #1
+depends_on:MPI_MAX_BITS_LARGER_THAN_792
 mbedtls_mpi_exp_mod:10:"433019240910377478217373572959560109819648647016096560523769010881172869083338285573756574557395862965095016483867813043663981946477698466501451832407592327356331263124555137732393938242285782144928753919588632679050799198937132922145084847":10:"5781538327977828897150909166778407659250458379645823062042492461576758526757490910073628008613977550546382774775570888130029763571528699574717583228939535960234464230882573615930384979100379102915657483866755371559811718767760594919456971354184113721":10:"583137007797276923956891216216022144052044091311388601652961409557516421612874571554415606746479105795833145583959622117418531166391184939066520869800857530421873250114773204354963864729386957427276448683092491947566992077136553066273207777134303397724679138833126700957":10:"":10:"114597449276684355144920670007147953232659436380163461553186940113929777196018164149703566472936578890991049344459204199888254907113495794730452699842273939581048142004834330369483813876618772578869083248061616444392091693787039636316845512292127097865026290173004860736":0
 
 Test mbedtls_mpi_exp_mod (Negative base) [#1]
 mbedtls_mpi_exp_mod:10:"-10000000000":10:"10000000000":10:"99999":10:"":10:"1":0
 
 Test mbedtls_mpi_exp_mod (Negative base) [#2]
+depends_on:MPI_MAX_BITS_LARGER_THAN_792
 mbedtls_mpi_exp_mod:16:"-9f13012cd92aa72fb86ac8879d2fde4f7fd661aaae43a00971f081cc60ca277059d5c37e89652e2af2585d281d66ef6a9d38a117e9608e9e7574cd142dc55278838a2161dd56db9470d4c1da2d5df15a908ee2eb886aaa890f23be16de59386663a12f1afbb325431a3e835e3fd89b98b96a6f77382f458ef9a37e1f84a03045c8676ab55291a94c2228ea15448ee96b626b998":16:"40a54d1b9e86789f06d9607fb158672d64867665c73ee9abb545fc7a785634b354c7bae5b962ce8040cf45f2c1f3d3659b2ee5ede17534c8fc2ec85c815e8df1fe7048d12c90ee31b88a68a081f17f0d8ce5f4030521e9400083bcea73a429031d4ca7949c2000d597088e0c39a6014d8bf962b73bb2e8083bd0390a4e00b9b3":16:"eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3":16:"":16:"21acc7199e1b90f9b4844ffe12c19f00ec548c5d32b21c647d48b6015d8eb9ec9db05b4f3d44db4227a2b5659c1a7cceb9d5fa8fa60376047953ce7397d90aaeb7465e14e820734f84aa52ad0fc66701bcbb991d57715806a11531268e1e83dd48288c72b424a6287e9ce4e5cc4db0dd67614aecc23b0124a5776d36e5c89483":0
 
 Base test GCD #1
@@ -935,6 +955,48 @@
 Test bit set (Invalid bit value)
 mbedtls_mpi_set_bit:16:"00":5:2:16:"00":MBEDTLS_ERR_MPI_BAD_INPUT_DATA
 
+Fill random: 0 bytes
+mpi_fill_random:0:0:0
+
+Fill random: 1 byte, good
+mpi_fill_random:1:1:0
+
+Fill random: 2 bytes, good, no leading zero
+mpi_fill_random:2:2:0
+
+Fill random: 2 bytes, good, 1 leading zero
+mpi_fill_random:2:256:0
+
+Fill random: MAX_SIZE - 7, good
+mpi_fill_random:MBEDTLS_MPI_MAX_SIZE - 7:MBEDTLS_MPI_MAX_SIZE - 7:0
+
+Fill random: MAX_SIZE, good
+mpi_fill_random:MBEDTLS_MPI_MAX_SIZE:MBEDTLS_MPI_MAX_SIZE:0
+
+Fill random: 1 byte, RNG failure
+mpi_fill_random:1:0:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
+
+Fill random: 2 bytes, RNG failure after 1 byte
+mpi_fill_random:2:1:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
+
+Fill random: 4 bytes, RNG failure after 3 bytes
+mpi_fill_random:4:3:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
+
+Fill random: 8 bytes, RNG failure after 7 bytes
+mpi_fill_random:8:7:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
+
+Fill random: 16 bytes, RNG failure after 1 bytes
+mpi_fill_random:16:1:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
+
+Fill random: 16 bytes, RNG failure after 8 bytes
+mpi_fill_random:16:8:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
+
+Fill random: 16 bytes, RNG failure after 15 bytes
+mpi_fill_random:16:15:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
+
+Fill random: MAX_SIZE bytes, RNG failure after MAX_SIZE-1 bytes
+mpi_fill_random:MBEDTLS_MPI_MAX_SIZE:MBEDTLS_MPI_MAX_SIZE-1:MBEDTLS_ERR_ENTROPY_SOURCE_FAILED
+
 MPI Selftest
 depends_on:MBEDTLS_SELF_TEST
 mpi_selftest:
diff --git a/tests/suites/test_suite_mpi.function b/tests/suites/test_suite_mpi.function
index 8436742..c5bb5a6 100644
--- a/tests/suites/test_suite_mpi.function
+++ b/tests/suites/test_suite_mpi.function
@@ -1,5 +1,10 @@
 /* BEGIN_HEADER */
 #include "mbedtls/bignum.h"
+#include "mbedtls/entropy.h"
+
+#if MBEDTLS_MPI_MAX_BITS > 792
+#define MPI_MAX_BITS_LARGER_THAN_792
+#endif
 
 typedef struct mbedtls_test_mpi_random
 {
@@ -43,6 +48,22 @@
 
     return( 0 );
 }
+
+/* Random generator that is told how many bytes to return. */
+static int f_rng_bytes_left( void *state, unsigned char *buf, size_t len )
+{
+    size_t *bytes_left = state;
+    size_t i;
+    for( i = 0; i < len; i++ )
+    {
+        if( *bytes_left == 0 )
+            return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
+        buf[i] = *bytes_left & 0xff;
+        --( *bytes_left );
+    }
+    return( 0 );
+}
+
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
@@ -1167,6 +1188,40 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
+void mbedtls_mpi_exp_mod_size( int A_bytes, int E_bytes, int N_bytes,
+                               int radix_RR, char * input_RR, int exp_result )
+{
+    mbedtls_mpi A, E, N, RR, Z;
+    mbedtls_mpi_init( &A  ); mbedtls_mpi_init( &E ); mbedtls_mpi_init( &N );
+    mbedtls_mpi_init( &RR ); mbedtls_mpi_init( &Z );
+
+    /* Set A to 2^(A_bytes - 1) + 1 */
+    TEST_ASSERT( mbedtls_mpi_lset( &A, 1 ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_shift_l( &A, ( A_bytes * 8 ) - 1 ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_set_bit( &A, 0, 1 ) == 0 );
+
+    /* Set E to 2^(E_bytes - 1) + 1 */
+    TEST_ASSERT( mbedtls_mpi_lset( &E, 1 ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_shift_l( &E, ( E_bytes * 8 ) - 1 ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_set_bit( &E, 0, 1 ) == 0 );
+
+    /* Set N to 2^(N_bytes - 1) + 1 */
+    TEST_ASSERT( mbedtls_mpi_lset( &N, 1 ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_shift_l( &N, ( N_bytes * 8 ) - 1 ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_set_bit( &N, 0, 1 ) == 0 );
+
+    if( strlen( input_RR ) )
+        TEST_ASSERT( mbedtls_mpi_read_string( &RR, radix_RR, input_RR ) == 0 );
+
+    TEST_ASSERT( mbedtls_mpi_exp_mod( &Z, &A, &E, &N, &RR ) == exp_result );
+
+exit:
+    mbedtls_mpi_free( &A  ); mbedtls_mpi_free( &E ); mbedtls_mpi_free( &N );
+    mbedtls_mpi_free( &RR ); mbedtls_mpi_free( &Z );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
 void mbedtls_mpi_inv_mod( int radix_X, char * input_X, int radix_Y,
                           char * input_Y, int radix_A, char * input_A,
                           int div_result )
@@ -1310,6 +1365,37 @@
 }
 /* END_CASE */
 
+/* BEGIN_CASE */
+void mpi_fill_random( int wanted_bytes, int rng_bytes, int expected_ret )
+{
+    mbedtls_mpi X;
+    int ret;
+    size_t bytes_left = rng_bytes;
+    mbedtls_mpi_init( &X );
+
+    ret = mbedtls_mpi_fill_random( &X, wanted_bytes,
+                                   f_rng_bytes_left, &bytes_left );
+    TEST_ASSERT( ret == expected_ret );
+
+    if( expected_ret == 0 )
+    {
+        /* mbedtls_mpi_fill_random is documented to use bytes from the RNG
+         * as a big-endian representation of the number. We know when
+         * our RNG function returns null bytes, so we know how many
+         * leading zero bytes the number has. */
+        size_t leading_zeros = 0;
+        if( wanted_bytes > 0 && rng_bytes % 256 == 0 )
+            leading_zeros = 1;
+        TEST_ASSERT( mbedtls_mpi_size( &X ) + leading_zeros ==
+                     (size_t) wanted_bytes );
+        TEST_ASSERT( (int) bytes_left == rng_bytes - wanted_bytes );
+    }
+
+exit:
+    mbedtls_mpi_free( &X );
+}
+/* END_CASE */
+
 /* BEGIN_CASE depends_on:MBEDTLS_SELF_TEST */
 void mpi_selftest(  )
 {
diff --git a/tests/suites/test_suite_version.data b/tests/suites/test_suite_version.data
index bb26246..2b01227 100644
--- a/tests/suites/test_suite_version.data
+++ b/tests/suites/test_suite_version.data
@@ -1,8 +1,8 @@
 Check compiletime library version
-check_compiletime_version:"2.24.0"
+check_compiletime_version:"2.25.0"
 
 Check runtime library version
-check_runtime_version:"2.24.0"
+check_runtime_version:"2.25.0"
 
 Check for MBEDTLS_VERSION_C
 check_feature:"MBEDTLS_VERSION_C":0
diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data
index bfdbab2..3b84609 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -2652,6 +2652,10 @@
 depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_RSA_C
 x509parse_crt_file:"data_files/server7_trailing_space.crt":0
 
+X509 File parse (Algorithm Params Tag mismatch)
+depends_on:MBEDTLS_SHA256_C:MBEDTLS_RSA_C
+x509parse_crt_file:"data_files/cli-rsa-sha256-badalg.crt.der":MBEDTLS_ERR_X509_SIG_MISMATCH
+
 X509 Get time (UTC no issues)
 depends_on:MBEDTLS_X509_USE_C
 x509_get_time:MBEDTLS_ASN1_UTC_TIME:"500101000000Z":0:1950:1:1:0:0:0