Merge pull request #3905 from gilles-peskine-arm/ssl-opt-less-grep-2.16

Backport 2.16: Speed up ssl-opt.sh when running a small number of test cases
diff --git a/ChangeLog b/ChangeLog
index c68bd1b..fe7aecd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,120 @@
 mbed TLS ChangeLog (Sorted per branch, date)
 
+= mbed TLS 2.16.10 branch released 2021-03-12
+
+Default behavior changes
+   * In mbedtls_rsa_context objects, the ver field was formerly documented
+     as always 0. It is now reserved for internal purposes and may take
+     different values.
+
+Security
+   * Fix a buffer overflow in mbedtls_mpi_sub_abs() when calculating
+     |A| - |B| where |B| is larger than |A| and has more limbs (so the
+     function should return MBEDTLS_ERR_MPI_NEGATIVE_VALUE). Only
+     applications calling mbedtls_mpi_sub_abs() directly are affected:
+     all calls inside the library were safe since this function is
+     only called with |A| >= |B|. Reported by Guido Vranken in #4042.
+   * Fix an errorneous estimation for an internal buffer in
+     mbedtls_pk_write_key_pem(). If MBEDTLS_MPI_MAX_SIZE is set to an odd
+     value the function might fail to write a private RSA keys of the largest
+     supported size.
+     Found by Daniel Otte, reported in #4093 and fixed in #4094,
+     backported in #4100.
+   * Fix a stack buffer overflow with mbedtls_net_poll() and
+     mbedtls_net_recv_timeout() when given a file descriptor that is
+     beyond FD_SETSIZE. Reported by FigBug in #4169.
+   * Guard against strong local side channel attack against base64 tables by
+     making access aceess to them use constant flow code.
+
+Bugfix
+   * Fix an incorrect error code if an RSA private operation glitched.
+   * Fix a resource leak in CTR_DRBG and HMAC_DRBG when MBEDTLS_THREADING_C
+     is enabled, on platforms where initializing a mutex allocates resources.
+     This was a regression introduced in the previous release. Reported in
+     #4017, #4045 and #4071.
+   * Ensure that calling mbedtls_rsa_free() or mbedtls_entropy_free()
+     twice is safe. This happens for RSA when some Mbed TLS library functions
+     fail. Such a double-free was not safe when MBEDTLS_THREADING_C was
+     enabled on platforms where freeing a mutex twice is not safe.
+   * Fix a resource leak in a bad-arguments case of mbedtls_rsa_gen_key()
+     when MBEDTLS_THREADING_C is enabled on platforms where initializing
+     a mutex allocates resources.
+   * This change makes 'mbedtls_x509write_crt_set_basic_constraints'
+     consistent with RFC 5280 4.2.1.9 which says: "Conforming CAs MUST
+     include this extension in all CA certificates that contain public keys
+     used to validate digital signatures on certificates and MUST mark the
+     extension as critical in such certificates." Previous to this change,
+     the extension was always marked as non-critical. This was fixed by
+     #4044.
+
+= mbed TLS 2.16.9 branch released 2020-12-11
+
+Security
+   * 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 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.
+   * Fix the build when the macro _GNU_SOURCE is defined to a non-empty value.
+     Fix #3432.
+   * 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. Adopted for LTS branch 2.16 in #3602.
+   * Fix build failures on GCC 11. Fixes #3782.
+   * 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.
+   * 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.16.8 branch released 2020-09-01
 
 Features
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/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/arc4random_buf-implicit.txt b/ChangeLog.d/arc4random_buf-implicit.txt
deleted file mode 100644
index d20e4c8..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. Adopted for LTS branch 2.16 in #3602.
diff --git a/ChangeLog.d/bugfix_PR3616.txt b/ChangeLog.d/bugfix_PR3616.txt
new file mode 100644
index 0000000..47d1044
--- /dev/null
+++ b/ChangeLog.d/bugfix_PR3616.txt
@@ -0,0 +1,5 @@
+Bugfix
+   * Fix premature fopen() call in mbedtls_entropy_write_seed_file which may
+     lead to the seed file corruption in case if the path to the seed file is
+     equal to MBEDTLS_PLATFORM_STD_NV_SEED_FILE. Contributed by Victor
+     Krasnoshchok in #3616.
diff --git a/ChangeLog.d/dtls_sample_use_read_timeout.txt b/ChangeLog.d/dtls_sample_use_read_timeout.txt
new file mode 100644
index 0000000..e3150d6
--- /dev/null
+++ b/ChangeLog.d/dtls_sample_use_read_timeout.txt
@@ -0,0 +1,2 @@
+Changes
+   * Fix the setting of the read timeout in the DTLS sample programs.
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/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/Makefile b/Makefile
index 3942fbd..ffa3aa0 100644
--- a/Makefile
+++ b/Makefile
@@ -124,11 +124,11 @@
 ## Editor navigation files
 C_SOURCE_FILES = $(wildcard include/*/*.h library/*.[hc] programs/*/*.[hc] tests/suites/*.function)
 # Exuberant-ctags invocation. Other ctags implementations may require different options.
-CTAGS = ctags --langmap=c:+.h.function -o
+CTAGS = ctags --langmap=c:+.h.function --line-directives=no -o
 tags: $(C_SOURCE_FILES)
 	$(CTAGS) $@ $(C_SOURCE_FILES)
 TAGS: $(C_SOURCE_FILES)
-	etags -o $@ $(C_SOURCE_FILES)
+	etags --no-line-directive -o $@ $(C_SOURCE_FILES)
 global: GPATH GRTAGS GSYMS GTAGS
 GPATH GRTAGS GSYMS GTAGS: $(C_SOURCE_FILES)
 	ls $(C_SOURCE_FILES) | gtags -f - --gtagsconf .globalrc
diff --git a/doxygen/input/doc_mainpage.h b/doxygen/input/doc_mainpage.h
index acd8be1..e640c7b 100644
--- a/doxygen/input/doc_mainpage.h
+++ b/doxygen/input/doc_mainpage.h
@@ -49,7 +49,7 @@
  */
 
 /**
- * @mainpage mbed TLS v2.16.8 source code documentation
+ * @mainpage mbed TLS v2.16.10 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 45398b7..61a42c4 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.16.8"
+PROJECT_NAME           = "mbed TLS v2.16.10"
 
 # 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/config.h b/include/mbedtls/config.h
index 6b45021..fff4240 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -1747,6 +1747,23 @@
 //#define MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT
 
 /**
+ * \def MBEDTLS_TEST_HOOKS
+ *
+ * Enable features for invasive testing such as introspection functions and
+ * hooks for fault injection. This enables additional unit tests.
+ *
+ * Merely enabling this feature should not change the behavior of the product.
+ * It only adds new code, and new branching points where the default behavior
+ * is the same as when this feature is disabled.
+ * However, this feature increases the attack surface: there is an added
+ * risk of vulnerabilities, and more gadgets that can make exploits easier.
+ * Therefore this feature must never be enabled in production.
+ *
+ * Uncomment to enable invasive tests.
+ */
+//#define MBEDTLS_TEST_HOOKS
+
+/**
  * \def MBEDTLS_THREADING_ALT
  *
  * Provide your own alternate threading implementation.
diff --git a/include/mbedtls/ctr_drbg.h b/include/mbedtls/ctr_drbg.h
index 7e5f2e5..6c099ad 100644
--- a/include/mbedtls/ctr_drbg.h
+++ b/include/mbedtls/ctr_drbg.h
@@ -214,6 +214,13 @@
     void *p_entropy;            /*!< The context for the entropy function. */
 
 #if defined(MBEDTLS_THREADING_C)
+    /* Invariant: the mutex is initialized if and only if f_entropy != NULL.
+     * This means that the mutex is initialized during the initial seeding
+     * in mbedtls_ctr_drbg_seed() and freed in mbedtls_ctr_drbg_free().
+     *
+     * Note that this invariant may change without notice. Do not rely on it
+     * and do not access the mutex directly in application code.
+     */
     mbedtls_threading_mutex_t mutex;
 #endif
 }
@@ -224,6 +231,11 @@
  *                      and prepares it for mbedtls_ctr_drbg_seed()
  *                      or mbedtls_ctr_drbg_free().
  *
+ * \note                The reseed interval is
+ *                      #MBEDTLS_CTR_DRBG_RESEED_INTERVAL by default.
+ *                      You can override it by calling
+ *                      mbedtls_ctr_drbg_set_reseed_interval().
+ *
  * \param ctx           The CTR_DRBG context to initialize.
  */
 void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx );
@@ -272,6 +284,15 @@
  *                      device.
  */
 #endif
+#if defined(MBEDTLS_THREADING_C)
+/**
+ * \note                When Mbed TLS is built with threading support,
+ *                      after this function returns successfully,
+ *                      it is safe to call mbedtls_ctr_drbg_random()
+ *                      from multiple threads. Other operations, including
+ *                      reseeding, are not thread-safe.
+ */
+#endif /* MBEDTLS_THREADING_C */
 /**
  * \param ctx           The CTR_DRBG context to seed.
  *                      It must have been initialized with
@@ -281,6 +302,8 @@
  *                      the same context unless you call
  *                      mbedtls_ctr_drbg_free() and mbedtls_ctr_drbg_init()
  *                      again first.
+ *                      After a failed call to mbedtls_ctr_drbg_seed(),
+ *                      you must call mbedtls_ctr_drbg_free().
  * \param f_entropy     The entropy callback, taking as arguments the
  *                      \p p_entropy context, the buffer to fill, and the
  *                      length of the buffer.
@@ -305,7 +328,8 @@
                    size_t len );
 
 /**
- * \brief               This function clears CTR_CRBG context data.
+ * \brief               This function resets CTR_DRBG context to the state immediately
+ *                      after initial call of mbedtls_ctr_drbg_init().
  *
  * \param ctx           The CTR_DRBG context to clear.
  */
@@ -371,6 +395,11 @@
  * \brief               This function reseeds the CTR_DRBG context, that is
  *                      extracts data from the entropy source.
  *
+ * \note                This function is not thread-safe. It is not safe
+ *                      to call this function if another thread might be
+ *                      concurrently obtaining random numbers from the same
+ *                      context or updating or reseeding the same context.
+ *
  * \param ctx           The CTR_DRBG context.
  * \param additional    Additional data to add to the state. Can be \c NULL.
  * \param len           The length of the additional data.
@@ -388,6 +417,11 @@
 /**
  * \brief              This function updates the state of the CTR_DRBG context.
  *
+ * \note               This function is not thread-safe. It is not safe
+ *                     to call this function if another thread might be
+ *                     concurrently obtaining random numbers from the same
+ *                     context or updating or reseeding the same context.
+ *
  * \param ctx          The CTR_DRBG context.
  * \param additional   The data to update the state with. This must not be
  *                     \c NULL unless \p add_len is \c 0.
@@ -411,6 +445,11 @@
  * This function automatically reseeds if the reseed counter is exceeded
  * or prediction resistance is enabled.
  *
+ * \note                This function is not thread-safe. It is not safe
+ *                      to call this function if another thread might be
+ *                      concurrently obtaining random numbers from the same
+ *                      context or updating or reseeding the same context.
+ *
  * \param p_rng         The CTR_DRBG context. This must be a pointer to a
  *                      #mbedtls_ctr_drbg_context structure.
  * \param output        The buffer to fill.
@@ -439,8 +478,16 @@
  *
  * This function automatically reseeds if the reseed counter is exceeded
  * or prediction resistance is enabled.
- *
- *
+ */
+#if defined(MBEDTLS_THREADING_C)
+/**
+ * \note                When Mbed TLS is built with threading support,
+ *                      it is safe to call mbedtls_ctr_drbg_random()
+ *                      from multiple threads. Other operations, including
+ *                      reseeding, are not thread-safe.
+ */
+#endif /* MBEDTLS_THREADING_C */
+/**
  * \param p_rng         The CTR_DRBG context. This must be a pointer to a
  *                      #mbedtls_ctr_drbg_context structure.
  * \param output        The buffer to fill.
diff --git a/include/mbedtls/entropy.h b/include/mbedtls/entropy.h
index 1e1d3f5..1d6e9b8 100644
--- a/include/mbedtls/entropy.h
+++ b/include/mbedtls/entropy.h
@@ -147,13 +147,15 @@
  */
 typedef struct mbedtls_entropy_context
 {
-    int accumulator_started;
+    int accumulator_started; /* 0 after init.
+                              * 1 after the first update.
+                              * -1 after free. */
 #if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR)
     mbedtls_sha512_context  accumulator;
 #else
     mbedtls_sha256_context  accumulator;
 #endif
-    int             source_count;
+    int             source_count; /* Number of entries used in source. */
     mbedtls_entropy_source_state    source[MBEDTLS_ENTROPY_MAX_SOURCES];
 #if defined(MBEDTLS_HAVEGE_C)
     mbedtls_havege_state    havege_data;
diff --git a/include/mbedtls/hmac_drbg.h b/include/mbedtls/hmac_drbg.h
index 6883678..5718e18 100644
--- a/include/mbedtls/hmac_drbg.h
+++ b/include/mbedtls/hmac_drbg.h
@@ -128,6 +128,14 @@
     void *p_entropy;            /*!< context for the entropy function        */
 
 #if defined(MBEDTLS_THREADING_C)
+    /* Invariant: the mutex is initialized if and only if
+     * md_ctx->md_info != NULL. This means that the mutex is initialized
+     * during the initial seeding in mbedtls_hmac_drbg_seed() or
+     * mbedtls_hmac_drbg_seed_buf() and freed in mbedtls_ctr_drbg_free().
+     *
+     * Note that this invariant may change without notice. Do not rely on it
+     * and do not access the mutex directly in application code.
+     */
     mbedtls_threading_mutex_t mutex;
 #endif
 } mbedtls_hmac_drbg_context;
@@ -138,6 +146,10 @@
  * This function makes the context ready for mbedtls_hmac_drbg_seed(),
  * mbedtls_hmac_drbg_seed_buf() or mbedtls_hmac_drbg_free().
  *
+ * \note                The reseed interval is #MBEDTLS_HMAC_DRBG_RESEED_INTERVAL
+ *                      by default. Override this value by calling
+ *                      mbedtls_hmac_drbg_set_reseed_interval().
+ *
  * \param ctx           HMAC_DRBG context to be initialized.
  */
 void mbedtls_hmac_drbg_init( mbedtls_hmac_drbg_context *ctx );
@@ -173,7 +185,17 @@
  * \note                During the initial seeding, this function calls
  *                      the entropy source to obtain a nonce
  *                      whose length is half the entropy length.
- *
+ */
+#if defined(MBEDTLS_THREADING_C)
+/**
+ * \note                When Mbed TLS is built with threading support,
+ *                      after this function returns successfully,
+ *                      it is safe to call mbedtls_hmac_drbg_random()
+ *                      from multiple threads. Other operations, including
+ *                      reseeding, are not thread-safe.
+ */
+#endif /* MBEDTLS_THREADING_C */
+/**
  * \param ctx           HMAC_DRBG context to be seeded.
  * \param md_info       MD algorithm to use for HMAC_DRBG.
  * \param f_entropy     The entropy callback, taking as arguments the
@@ -212,7 +234,17 @@
  *
  * This function is meant for use in algorithms that need a pseudorandom
  * input such as deterministic ECDSA.
- *
+ */
+#if defined(MBEDTLS_THREADING_C)
+/**
+ * \note                When Mbed TLS is built with threading support,
+ *                      after this function returns successfully,
+ *                      it is safe to call mbedtls_hmac_drbg_random()
+ *                      from multiple threads. Other operations, including
+ *                      reseeding, are not thread-safe.
+ */
+#endif /* MBEDTLS_THREADING_C */
+/**
  * \param ctx           HMAC_DRBG context to be initialised.
  * \param md_info       MD algorithm to use for HMAC_DRBG.
  * \param data          Concatenation of the initial entropy string and
@@ -275,6 +307,11 @@
 /**
  * \brief               This function updates the state of the HMAC_DRBG context.
  *
+ * \note                This function is not thread-safe. It is not safe
+ *                      to call this function if another thread might be
+ *                      concurrently obtaining random numbers from the same
+ *                      context or updating or reseeding the same context.
+ *
  * \param ctx           The HMAC_DRBG context.
  * \param additional    The data to update the state with.
  *                      If this is \c NULL, there is no additional data.
@@ -291,6 +328,11 @@
  * \brief               This function reseeds the HMAC_DRBG context, that is
  *                      extracts data from the entropy source.
  *
+ * \note                This function is not thread-safe. It is not safe
+ *                      to call this function if another thread might be
+ *                      concurrently obtaining random numbers from the same
+ *                      context or updating or reseeding the same context.
+ *
  * \param ctx           The HMAC_DRBG context.
  * \param additional    Additional data to add to the state.
  *                      If this is \c NULL, there is no additional data
@@ -316,6 +358,11 @@
  * This function automatically reseeds if the reseed counter is exceeded
  * or prediction resistance is enabled.
  *
+ * \note                This function is not thread-safe. It is not safe
+ *                      to call this function if another thread might be
+ *                      concurrently obtaining random numbers from the same
+ *                      context or updating or reseeding the same context.
+ *
  * \param p_rng         The HMAC_DRBG context. This must be a pointer to a
  *                      #mbedtls_hmac_drbg_context structure.
  * \param output        The buffer to fill.
@@ -345,7 +392,16 @@
  *
  * This function automatically reseeds if the reseed counter is exceeded
  * or prediction resistance is enabled.
- *
+ */
+#if defined(MBEDTLS_THREADING_C)
+/**
+ * \note                When Mbed TLS is built with threading support,
+ *                      it is safe to call mbedtls_ctr_drbg_random()
+ *                      from multiple threads. Other operations, including
+ *                      reseeding, are not thread-safe.
+ */
+#endif /* MBEDTLS_THREADING_C */
+/**
  * \param p_rng         The HMAC_DRBG context. This must be a pointer to a
  *                      #mbedtls_hmac_drbg_context structure.
  * \param output        The buffer to fill.
@@ -361,7 +417,8 @@
 int mbedtls_hmac_drbg_random( void *p_rng, unsigned char *output, size_t out_len );
 
 /**
- * \brief               Free an HMAC_DRBG context
+ * \brief               This function resets HMAC_DRBG context to the state immediately
+ *                      after initial call of mbedtls_hmac_drbg_init().
  *
  * \param ctx           The HMAC_DRBG context to free.
  */
diff --git a/include/mbedtls/net_sockets.h b/include/mbedtls/net_sockets.h
index 00fea7d..c6e1a02 100644
--- a/include/mbedtls/net_sockets.h
+++ b/include/mbedtls/net_sockets.h
@@ -151,6 +151,7 @@
  *
  * \return         0 if successful, or one of:
  *                      MBEDTLS_ERR_NET_SOCKET_FAILED,
+ *                      MBEDTLS_ERR_NET_UNKNOWN_HOST,
  *                      MBEDTLS_ERR_NET_BIND_FAILED,
  *                      MBEDTLS_ERR_NET_LISTEN_FAILED
  *
@@ -170,6 +171,8 @@
  *                  can be NULL if client_ip is null
  *
  * \return          0 if successful, or
+ *                  MBEDTLS_ERR_NET_SOCKET_FAILED,
+ *                  MBEDTLS_ERR_NET_BIND_FAILED,
  *                  MBEDTLS_ERR_NET_ACCEPT_FAILED, or
  *                  MBEDTLS_ERR_NET_BUFFER_TOO_SMALL if buf_size is too small,
  *                  MBEDTLS_ERR_SSL_WANT_READ if bind_fd was set to
@@ -182,6 +185,10 @@
 /**
  * \brief          Check and wait for the context to be ready for read/write
  *
+ * \note           The current implementation of this function uses
+ *                 select() and returns an error if the file descriptor
+ *                 is \c FD_SETSIZE or greater.
+ *
  * \param ctx      Socket to check
  * \param rw       Bitflag composed of MBEDTLS_NET_POLL_READ and
  *                 MBEDTLS_NET_POLL_WRITE specifying the events
@@ -263,16 +270,21 @@
  *                 'timeout' seconds. If no error occurs, the actual amount
  *                 read is returned.
  *
+ * \note           The current implementation of this function uses
+ *                 select() and returns an error if the file descriptor
+ *                 is \c FD_SETSIZE or greater.
+ *
  * \param ctx      Socket
  * \param buf      The buffer to write to
  * \param len      Maximum length of the buffer
  * \param timeout  Maximum number of milliseconds to wait for data
  *                 0 means no timeout (wait forever)
  *
- * \return         the number of bytes received,
- *                 or a non-zero error code:
- *                 MBEDTLS_ERR_SSL_TIMEOUT if the operation timed out,
+ * \return         The number of bytes received if successful.
+ *                 MBEDTLS_ERR_SSL_TIMEOUT if the operation timed out.
  *                 MBEDTLS_ERR_SSL_WANT_READ if interrupted by a signal.
+ *                 Another negative error code (MBEDTLS_ERR_NET_xxx)
+ *                 for other failures.
  *
  * \note           This function will block (until data becomes available or
  *                 timeout is reached) even if the socket is set to
diff --git a/include/mbedtls/rsa.h b/include/mbedtls/rsa.h
index 188c37c..b2f6533 100644
--- a/include/mbedtls/rsa.h
+++ b/include/mbedtls/rsa.h
@@ -124,7 +124,10 @@
  */
 typedef struct mbedtls_rsa_context
 {
-    int ver;                    /*!<  Always 0.*/
+    int ver;                    /*!<  Reserved for internal purposes.
+                                 *    Do not set this field in application
+                                 *    code. Its meaning might change without
+                                 *    notice. */
     size_t len;                 /*!<  The size of \p N in Bytes. */
 
     mbedtls_mpi N;              /*!<  The public modulus. */
@@ -154,6 +157,7 @@
                                      mask generating function used in the
                                      EME-OAEP and EMSA-PSS encodings. */
 #if defined(MBEDTLS_THREADING_C)
+    /* Invariant: the mutex is initialized iff ver != 0. */
     mbedtls_threading_mutex_t mutex;    /*!<  Thread-safety mutex. */
 #endif
 }
diff --git a/include/mbedtls/sha512.h b/include/mbedtls/sha512.h
index 9ff78ec..5e5a15e 100644
--- a/include/mbedtls/sha512.h
+++ b/include/mbedtls/sha512.h
@@ -152,8 +152,7 @@
 
 /**
  * \brief          This function finishes the SHA-512 operation, and writes
- *                 the result to the output buffer. This function is for
- *                 internal use only.
+ *                 the result to the output buffer.
  *
  * \param ctx      The SHA-512 context. This must be initialized
  *                 and have a hash operation started.
@@ -169,6 +168,7 @@
 /**
  * \brief          This function processes a single data block within
  *                 the ongoing SHA-512 computation.
+ *                 This function is for internal use only.
  *
  * \param ctx      The SHA-512 context. This must be initialized.
  * \param data     The buffer holding one block of data. This
diff --git a/include/mbedtls/threading.h b/include/mbedtls/threading.h
index a8183a6..45161ce 100644
--- a/include/mbedtls/threading.h
+++ b/include/mbedtls/threading.h
@@ -73,6 +73,9 @@
 typedef struct mbedtls_threading_mutex_t
 {
     pthread_mutex_t mutex;
+    /* is_valid is 0 after a failed init or a free, and nonzero after a
+     * successful init. This field is not considered part of the public
+     * API of Mbed TLS and may change without notice. */
     char is_valid;
 } mbedtls_threading_mutex_t;
 #endif
diff --git a/include/mbedtls/version.h b/include/mbedtls/version.h
index d09b450..bd5c730 100644
--- a/include/mbedtls/version.h
+++ b/include/mbedtls/version.h
@@ -65,16 +65,16 @@
  */
 #define MBEDTLS_VERSION_MAJOR  2
 #define MBEDTLS_VERSION_MINOR  16
-#define MBEDTLS_VERSION_PATCH  8
+#define MBEDTLS_VERSION_PATCH  10
 
 /**
  * The single version number has the following structure:
  *    MMNNPP00
  *    Major version | Minor version | Patch version
  */
-#define MBEDTLS_VERSION_NUMBER         0x02100800
-#define MBEDTLS_VERSION_STRING         "2.16.8"
-#define MBEDTLS_VERSION_STRING_FULL    "mbed TLS 2.16.8"
+#define MBEDTLS_VERSION_NUMBER         0x02100A00
+#define MBEDTLS_VERSION_STRING         "2.16.10"
+#define MBEDTLS_VERSION_STRING_FULL    "mbed TLS 2.16.10"
 
 #if defined(MBEDTLS_VERSION_C)
 
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index beec785..4f61f99 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -165,15 +165,15 @@
 
 if(USE_SHARED_MBEDTLS_LIBRARY)
     add_library(mbedcrypto SHARED ${src_crypto})
-    set_target_properties(mbedcrypto PROPERTIES VERSION 2.16.8 SOVERSION 3)
+    set_target_properties(mbedcrypto PROPERTIES VERSION 2.16.10 SOVERSION 3)
     target_link_libraries(mbedcrypto ${libs})
 
     add_library(mbedx509 SHARED ${src_x509})
-    set_target_properties(mbedx509 PROPERTIES VERSION 2.16.8 SOVERSION 0)
+    set_target_properties(mbedx509 PROPERTIES VERSION 2.16.10 SOVERSION 0)
     target_link_libraries(mbedx509 ${libs} mbedcrypto)
 
     add_library(mbedtls SHARED ${src_tls})
-    set_target_properties(mbedtls PROPERTIES VERSION 2.16.8 SOVERSION 12)
+    set_target_properties(mbedtls PROPERTIES VERSION 2.16.10 SOVERSION 12)
     target_link_libraries(mbedtls ${libs} mbedx509)
 
     install(TARGETS mbedtls mbedx509 mbedcrypto
diff --git a/library/base64.c b/library/base64.c
index bfafb05..692e11e 100644
--- a/library/base64.c
+++ b/library/base64.c
@@ -97,6 +97,99 @@
 #define BASE64_SIZE_T_MAX   ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
 
 /*
+ * Constant flow conditional assignment to unsigned char
+ */
+static void mbedtls_base64_cond_assign_uchar( unsigned char * dest, const unsigned char * const src,
+                                       unsigned char condition )
+{
+    /* MSVC has a warning about unary minus on unsigned integer types,
+     * but this is well-defined and precisely what we want to do here. */
+#if defined(_MSC_VER)
+#pragma warning( push )
+#pragma warning( disable : 4146 )
+#endif
+
+    /* Generate bitmask from condition, mask will either be 0xFF or 0 */
+    unsigned char mask = ( condition | -condition );
+    mask >>= 7;
+    mask = -mask;
+
+#if defined(_MSC_VER)
+#pragma warning( pop )
+#endif
+
+    *dest = ( ( *src ) & mask ) | ( ( *dest ) & ~mask );
+}
+
+/*
+ * Constant flow conditional assignment to uint_32
+ */
+static void mbedtls_base64_cond_assign_uint32( uint32_t * dest, const uint32_t src,
+                                       uint32_t condition )
+{
+    /* MSVC has a warning about unary minus on unsigned integer types,
+     * but this is well-defined and precisely what we want to do here. */
+#if defined(_MSC_VER)
+#pragma warning( push )
+#pragma warning( disable : 4146 )
+#endif
+
+    /* Generate bitmask from condition, mask will either be 0xFFFFFFFF or 0 */
+    uint32_t mask = ( condition | -condition );
+    mask >>= 31;
+    mask = -mask;
+
+#if defined(_MSC_VER)
+#pragma warning( pop )
+#endif
+
+    *dest = ( src & mask ) | ( ( *dest ) & ~mask );
+}
+
+/*
+ * Constant flow check for equality
+ */
+static unsigned char mbedtls_base64_eq( size_t in_a, size_t in_b )
+{
+    size_t difference = in_a ^ in_b;
+
+    /* MSVC has a warning about unary minus on unsigned integer types,
+     * but this is well-defined and precisely what we want to do here. */
+#if defined(_MSC_VER)
+#pragma warning( push )
+#pragma warning( disable : 4146 )
+#endif
+
+    difference |= -difference;
+
+#if defined(_MSC_VER)
+#pragma warning( pop )
+#endif
+
+    /* cope with the varying size of size_t per platform */
+    difference >>= ( sizeof( difference ) * 8 - 1 );
+
+    return (unsigned char) ( 1 ^ difference );
+}
+
+/*
+ * Constant flow lookup into table.
+ */
+static unsigned char mbedtls_base64_table_lookup( const unsigned char * const table,
+                                                 const size_t table_size, const size_t table_index )
+{
+    size_t i;
+    unsigned char result = 0;
+
+    for( i = 0; i < table_size; ++i )
+    {
+        mbedtls_base64_cond_assign_uchar( &result, &table[i], mbedtls_base64_eq( i, table_index ) );
+    }
+
+    return result;
+}
+
+/*
  * Encode a buffer into base64 format
  */
 int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
@@ -136,10 +229,17 @@
         C2 = *src++;
         C3 = *src++;
 
-        *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
-        *p++ = base64_enc_map[(((C1 &  3) << 4) + (C2 >> 4)) & 0x3F];
-        *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
-        *p++ = base64_enc_map[C3 & 0x3F];
+        *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
+                                            ( ( C1 >> 2 ) & 0x3F ) );
+
+        *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
+                                            ( ( ( ( C1 &  3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) );
+
+        *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
+                                            ( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) ) & 0x3F ) );
+
+        *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
+                                            ( C3 & 0x3F ) );
     }
 
     if( i < slen )
@@ -147,11 +247,15 @@
         C1 = *src++;
         C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
 
-        *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
-        *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
+        *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
+                                            ( ( C1 >> 2 ) & 0x3F ) );
+
+        *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
+                                            ( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) ) & 0x3F ) );
 
         if( ( i + 1 ) < slen )
-             *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
+             *p++ = mbedtls_base64_table_lookup( base64_enc_map, sizeof( base64_enc_map ),
+                                                 ( ( ( C2 & 15 ) << 2 ) & 0x3F ) );
         else *p++ = '=';
 
         *p++ = '=';
@@ -172,6 +276,7 @@
     size_t i, n;
     uint32_t j, x;
     unsigned char *p;
+    unsigned char dec_map_lookup;
 
     /* First pass: check for validity and get output length */
     for( i = n = j = 0; i < slen; i++ )
@@ -202,10 +307,12 @@
         if( src[i] == '=' && ++j > 2 )
             return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
 
-        if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
+        dec_map_lookup = mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), src[i] );
+
+        if( src[i] > 127 || dec_map_lookup == 127 )
             return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
 
-        if( base64_dec_map[src[i]] < 64 && j != 0 )
+        if( dec_map_lookup < 64 && j != 0 )
             return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
 
         n++;
@@ -235,8 +342,10 @@
         if( *src == '\r' || *src == '\n' || *src == ' ' )
             continue;
 
-        j -= ( base64_dec_map[*src] == 64 );
-        x  = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F );
+        dec_map_lookup = mbedtls_base64_table_lookup( base64_dec_map, sizeof( base64_dec_map ), *src );
+
+        mbedtls_base64_cond_assign_uint32( &j, j - 1, mbedtls_base64_eq( dec_map_lookup, 64 ) );
+        x  = ( x << 6 ) | ( dec_map_lookup & 0x3F );
 
         if( ++n == 4 )
         {
diff --git a/library/bignum.c b/library/bignum.c
index 6d0a67c..f133f6c 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -1354,6 +1354,12 @@
     for( n = B->n; n > 0; n-- )
         if( B->p[n - 1] != 0 )
             break;
+    if( n > A->n )
+    {
+        /* B >= (2^ciL)^n > A */
+        ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
+        goto cleanup;
+    }
 
     carry = mpi_sub_hlp( n, X->p, B->p );
     if( carry != 0 )
@@ -1364,7 +1370,10 @@
         /* If we ran out of space for the carry, it means that the result
          * is negative. */
         if( n == X->n )
-            return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE );
+        {
+            ret = MBEDTLS_ERR_MPI_NEGATIVE_VALUE;
+            goto cleanup;
+        }
         --X->p[n];
     }
 
@@ -2058,6 +2067,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
      */
@@ -2334,7 +2347,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/cmac.c b/library/cmac.c
index 1a1200b..409f679 100644
--- a/library/cmac.c
+++ b/library/cmac.c
@@ -450,7 +450,7 @@
  */
 int mbedtls_aes_cmac_prf_128( const unsigned char *key, size_t key_length,
                               const unsigned char *input, size_t in_len,
-                              unsigned char *output )
+                              unsigned char output[16] )
 {
     int ret;
     const mbedtls_cipher_info_t *cipher_info;
diff --git a/library/ctr_drbg.c b/library/ctr_drbg.c
index b98df29..90264e8 100644
--- a/library/ctr_drbg.c
+++ b/library/ctr_drbg.c
@@ -82,21 +82,26 @@
 {
     memset( ctx, 0, sizeof( mbedtls_ctr_drbg_context ) );
 
-#if defined(MBEDTLS_THREADING_C)
-    mbedtls_mutex_init( &ctx->mutex );
-#endif
+    ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
 }
 
+/*
+ *  This function resets CTR_DRBG context to the state immediately
+ *  after initial call of mbedtls_ctr_drbg_init().
+ */
 void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx )
 {
     if( ctx == NULL )
         return;
 
 #if defined(MBEDTLS_THREADING_C)
-    mbedtls_mutex_free( &ctx->mutex );
+    /* The mutex is initialized iff f_entropy is set. */
+    if( ctx->f_entropy != NULL )
+        mbedtls_mutex_free( &ctx->mutex );
 #endif
     mbedtls_aes_free( &ctx->aes_ctx );
     mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ctr_drbg_context ) );
+    ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
 }
 
 void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx, int resistance )
@@ -412,6 +417,11 @@
 
     memset( key, 0, MBEDTLS_CTR_DRBG_KEYSIZE );
 
+    /* The mutex is initialized iff f_entropy is set. */
+#if defined(MBEDTLS_THREADING_C)
+    mbedtls_mutex_init( &ctx->mutex );
+#endif
+
     mbedtls_aes_init( &ctx->aes_ctx );
 
     ctx->f_entropy = f_entropy;
@@ -419,7 +429,6 @@
 
     if( ctx->entropy_len == 0 )
         ctx->entropy_len = MBEDTLS_CTR_DRBG_ENTROPY_LEN;
-    ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
 
     /*
      * Initialize with an empty key
diff --git a/library/ecdsa.c b/library/ecdsa.c
index da8df9c..2456238 100644
--- a/library/ecdsa.c
+++ b/library/ecdsa.c
@@ -247,6 +247,9 @@
 
 #endif /* MBEDTLS_ECP_RESTARTABLE */
 
+#if defined(MBEDTLS_ECDSA_DETERMINISTIC) || \
+    !defined(MBEDTLS_ECDSA_SIGN_ALT)     || \
+    !defined(MBEDTLS_ECDSA_VERIFY_ALT)
 /*
  * Derive a suitable integer for group grp from a buffer of length len
  * SEC1 4.1.3 step 5 aka SEC1 4.1.4 step 3
@@ -269,6 +272,7 @@
 cleanup:
     return( ret );
 }
+#endif /* ECDSA_DETERMINISTIC || !ECDSA_SIGN_ALT || !ECDSA_VERIFY_ALT */
 
 #if !defined(MBEDTLS_ECDSA_SIGN_ALT)
 /*
@@ -780,6 +784,8 @@
     (void) md_alg;
 
 #if defined(MBEDTLS_ECDSA_SIGN_ALT)
+    (void) rs_ctx;
+
     MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ctx->grp, &r, &s, &ctx->d,
                          hash, hlen, f_rng, p_rng ) );
 #else
@@ -888,6 +894,8 @@
         goto cleanup;
     }
 #if defined(MBEDTLS_ECDSA_VERIFY_ALT)
+    (void) rs_ctx;
+
     if( ( ret = mbedtls_ecdsa_verify( &ctx->grp, hash, hlen,
                                       &ctx->Q, &r, &s ) ) != 0 )
         goto cleanup;
diff --git a/library/ecjpake.c b/library/ecjpake.c
index f6e2458..0532a29 100644
--- a/library/ecjpake.c
+++ b/library/ecjpake.c
@@ -850,6 +850,8 @@
     0x65, 0x73, 0x74
 };
 
+#if !defined(MBEDTLS_ECJPAKE_ALT)
+
 static const unsigned char ecjpake_test_x1[] = {
     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
     0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
@@ -994,6 +996,8 @@
     return( ret );
 }
 
+#endif /* ! MBEDTLS_ECJPAKE_ALT */
+
 /* For tests we don't need a secure RNG;
  * use the LGC from Numerical Recipes for simplicity */
 static int ecjpake_lgc( void *p, unsigned char *out, size_t len )
@@ -1089,6 +1093,12 @@
     if( verbose != 0 )
         mbedtls_printf( "passed\n" );
 
+#if !defined(MBEDTLS_ECJPAKE_ALT)
+    /* 'reference handshake' tests can only be run against implementations
+     * for which we have 100% control over how the random ephemeral keys
+     * are generated. This is only the case for the internal mbed TLS
+     * implementation, so these tests are skipped in case the internal
+     * implementation is swapped out for an alternative one. */
     if( verbose != 0 )
         mbedtls_printf( "  ECJPAKE test #2 (reference handshake): " );
 
@@ -1137,6 +1147,7 @@
 
     if( verbose != 0 )
         mbedtls_printf( "passed\n" );
+#endif /* ! MBEDTLS_ECJPAKE_ALT */
 
 cleanup:
     mbedtls_ecjpake_free( &cli );
diff --git a/library/ecp_curves.c b/library/ecp_curves.c
index cc4c5b7..b04596b 100644
--- a/library/ecp_curves.c
+++ b/library/ecp_curves.c
@@ -1044,7 +1044,7 @@
     STORE32; i++;                               \
     cur = c > 0 ? c : 0; STORE32;               \
     cur = 0; while( ++i < MAX32 ) { STORE32; }  \
-    if( c < 0 ) fix_negative( N, c, &C, bits );
+    if( c < 0 ) MBEDTLS_MPI_CHK( fix_negative( N, c, &C, bits ) );
 
 /*
  * If the result is negative, we get it in the form
diff --git a/library/entropy.c b/library/entropy.c
index 666c556..9f1a32b 100644
--- a/library/entropy.c
+++ b/library/entropy.c
@@ -146,6 +146,11 @@
 
 void mbedtls_entropy_free( mbedtls_entropy_context *ctx )
 {
+    /* If the context was already free, don't call free() again.
+     * This is important for mutexes which don't allow double-free. */
+    if( ctx->accumulator_started == -1 )
+        return;
+
 #if defined(MBEDTLS_HAVEGE_C)
     mbedtls_havege_free( &ctx->havege_data );
 #endif
@@ -162,7 +167,7 @@
 #endif
     ctx->source_count = 0;
     mbedtls_platform_zeroize( ctx->source, sizeof( ctx->source ) );
-    ctx->accumulator_started = 0;
+    ctx->accumulator_started = -1;
 }
 
 int mbedtls_entropy_add_source( mbedtls_entropy_context *ctx,
@@ -489,14 +494,20 @@
 int mbedtls_entropy_write_seed_file( mbedtls_entropy_context *ctx, const char *path )
 {
     int ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;
-    FILE *f;
+    FILE *f = NULL;
     unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
 
-    if( ( f = fopen( path, "wb" ) ) == NULL )
-        return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR );
-
     if( ( ret = mbedtls_entropy_func( ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) ) != 0 )
+    {
+        ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
         goto exit;
+    }
+
+    if( ( f = fopen( path, "wb" ) ) == NULL )
+    {
+        ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;
+        goto exit;
+    }
 
     if( fwrite( buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f ) != MBEDTLS_ENTROPY_BLOCK_SIZE )
     {
@@ -509,7 +520,9 @@
 exit:
     mbedtls_platform_zeroize( buf, sizeof( buf ) );
 
-    fclose( f );
+    if( f != NULL )
+        fclose( f );
+
     return( ret );
 }
 
diff --git a/library/hmac_drbg.c b/library/hmac_drbg.c
index 9fbfc30..b45d616 100644
--- a/library/hmac_drbg.c
+++ b/library/hmac_drbg.c
@@ -83,9 +83,7 @@
 {
     memset( ctx, 0, sizeof( mbedtls_hmac_drbg_context ) );
 
-#if defined(MBEDTLS_THREADING_C)
-    mbedtls_mutex_init( &ctx->mutex );
-#endif
+    ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL;
 }
 
 /*
@@ -157,6 +155,10 @@
     if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 )
         return( ret );
 
+#if defined(MBEDTLS_THREADING_C)
+    mbedtls_mutex_init( &ctx->mutex );
+#endif
+
     /*
      * Set initial working state.
      * Use the V memory location, which is currently all 0, to initialize the
@@ -282,6 +284,11 @@
     if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 )
         return( ret );
 
+    /* The mutex is initialized iff the md context is set up. */
+#if defined(MBEDTLS_THREADING_C)
+    mbedtls_mutex_init( &ctx->mutex );
+#endif
+
     md_size = mbedtls_md_get_size( md_info );
 
     /*
@@ -296,8 +303,6 @@
     ctx->f_entropy = f_entropy;
     ctx->p_entropy = p_entropy;
 
-    ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL;
-
     if( ctx->entropy_len == 0 )
     {
         /*
@@ -442,7 +447,8 @@
 }
 
 /*
- * Free an HMAC_DRBG context
+ *  This function resets HMAC_DRBG context to the state immediately
+ *  after initial call of mbedtls_hmac_drbg_init().
  */
 void mbedtls_hmac_drbg_free( mbedtls_hmac_drbg_context *ctx )
 {
@@ -450,10 +456,13 @@
         return;
 
 #if defined(MBEDTLS_THREADING_C)
-    mbedtls_mutex_free( &ctx->mutex );
+    /* The mutex is initialized iff the md context is set up. */
+    if( ctx->md_ctx.md_info != NULL )
+        mbedtls_mutex_free( &ctx->mutex );
 #endif
     mbedtls_md_free( &ctx->md_ctx );
     mbedtls_platform_zeroize( ctx, sizeof( mbedtls_hmac_drbg_context ) );
+    ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL;
 }
 
 #if defined(MBEDTLS_FS_IO)
diff --git a/library/md2.c b/library/md2.c
index cbdaaab..fdcb630 100644
--- a/library/md2.c
+++ b/library/md2.c
@@ -177,6 +177,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 cb16dce..95e893e 100644
--- a/library/md4.c
+++ b/library/md4.c
@@ -143,31 +143,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)                           \
@@ -178,22 +181,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
@@ -206,22 +209,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
@@ -234,30 +237,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 fe25925..d2b634f 100644
--- a/library/md5.c
+++ b/library/md5.c
@@ -142,128 +142,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/net_sockets.c b/library/net_sockets.c
index 1130408..671115f 100644
--- a/library/net_sockets.c
+++ b/library/net_sockets.c
@@ -496,6 +496,13 @@
     if( fd < 0 )
         return( MBEDTLS_ERR_NET_INVALID_CONTEXT );
 
+    /* A limitation of select() is that it only works with file descriptors
+     * that are strictly less than FD_SETSIZE. This is a limitation of the
+     * fd_set type. Error out early, because attempting to call FD_SET on a
+     * large file descriptor is a buffer overflow on typical platforms. */
+    if( fd >= FD_SETSIZE )
+        return( MBEDTLS_ERR_NET_POLL_FAILED );
+
 #if defined(__has_feature)
 #if __has_feature(memory_sanitizer)
     /* Ensure that memory sanitizers consider read_fds and write_fds as
@@ -615,6 +622,13 @@
     if( fd < 0 )
         return( MBEDTLS_ERR_NET_INVALID_CONTEXT );
 
+    /* A limitation of select() is that it only works with file descriptors
+     * that are strictly less than FD_SETSIZE. This is a limitation of the
+     * fd_set type. Error out early, because attempting to call FD_SET on a
+     * large file descriptor is a buffer overflow on typical platforms. */
+    if( fd >= FD_SETSIZE )
+        return( MBEDTLS_ERR_NET_POLL_FAILED );
+
     FD_ZERO( &read_fds );
     FD_SET( fd, &read_fds );
 
diff --git a/library/pem.c b/library/pem.c
index a7a2f7f..50e663c 100644
--- a/library/pem.c
+++ b/library/pem.c
@@ -508,8 +508,12 @@
     *p++ = '\0';
     *olen = p - buf;
 
+     /* Clean any remaining data previously written to the buffer */
+    memset( buf + *olen, 0, buf_len - *olen );
+
     mbedtls_free( encode_buf );
     return( 0 );
 }
 #endif /* MBEDTLS_PEM_WRITE_C */
 #endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */
+
diff --git a/library/pkcs5.c b/library/pkcs5.c
index 8a80aa5..c4447f1 100644
--- a/library/pkcs5.c
+++ b/library/pkcs5.c
@@ -247,7 +247,7 @@
                        unsigned int iteration_count,
                        uint32_t key_length, unsigned char *output )
 {
-    int ret, j;
+    int ret = 0, j;
     unsigned int i;
     unsigned char md1[MBEDTLS_MD_MAX_SIZE];
     unsigned char work[MBEDTLS_MD_MAX_SIZE];
@@ -269,16 +269,16 @@
         // U1 ends up in work
         //
         if( ( ret = mbedtls_md_hmac_starts( ctx, password, plen ) ) != 0 )
-            return( ret );
+            goto cleanup;
 
         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;
 
         memcpy( md1, work, md_size );
 
@@ -287,13 +287,13 @@
             // U2 ends up in md1
             //
             if( ( ret = mbedtls_md_hmac_starts( ctx, password, plen ) ) != 0 )
-                return( ret );
+                goto cleanup;
 
             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;
 
             // U1 xor U2
             //
@@ -312,7 +312,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/pkwrite.c b/library/pkwrite.c
index 150626c..a770dfb 100644
--- a/library/pkwrite.c
+++ b/library/pkwrite.c
@@ -455,7 +455,7 @@
  *      publicExponent    INTEGER   -- e            1 + 3 + MPI_MAX + 1
  *  }
  */
-#define RSA_PUB_DER_MAX_BYTES   38 + 2 * MBEDTLS_MPI_MAX_SIZE
+#define RSA_PUB_DER_MAX_BYTES   ( 38 + 2 * MBEDTLS_MPI_MAX_SIZE )
 
 /*
  * RSA private keys:
@@ -472,10 +472,10 @@
  *      otherPrimeInfos   OtherPrimeInfos OPTIONAL  0 (not supported)
  *  }
  */
-#define MPI_MAX_SIZE_2          MBEDTLS_MPI_MAX_SIZE / 2 + \
-                                MBEDTLS_MPI_MAX_SIZE % 2
-#define RSA_PRV_DER_MAX_BYTES   47 + 3 * MBEDTLS_MPI_MAX_SIZE \
-                                   + 5 * MPI_MAX_SIZE_2
+#define MPI_MAX_SIZE_2          ( MBEDTLS_MPI_MAX_SIZE / 2 + \
+                                  MBEDTLS_MPI_MAX_SIZE % 2 )
+#define RSA_PRV_DER_MAX_BYTES   ( 47 + 3 * MBEDTLS_MPI_MAX_SIZE \
+                                   + 5 * MPI_MAX_SIZE_2 )
 
 #else /* MBEDTLS_RSA_C */
 
@@ -496,7 +496,7 @@
  *                                            + 2 * ECP_MAX (coords)    [1]
  *  }
  */
-#define ECP_PUB_DER_MAX_BYTES   30 + 2 * MBEDTLS_ECP_MAX_BYTES
+#define ECP_PUB_DER_MAX_BYTES   ( 30 + 2 * MBEDTLS_ECP_MAX_BYTES )
 
 /*
  * EC private keys:
@@ -507,7 +507,7 @@
  *      publicKey  [1] BIT STRING OPTIONAL      1 + 2 + [1] above
  *    }
  */
-#define ECP_PRV_DER_MAX_BYTES   29 + 3 * MBEDTLS_ECP_MAX_BYTES
+#define ECP_PRV_DER_MAX_BYTES   ( 29 + 3 * MBEDTLS_ECP_MAX_BYTES )
 
 #else /* MBEDTLS_ECP_C */
 
@@ -516,10 +516,10 @@
 
 #endif /* MBEDTLS_ECP_C */
 
-#define PUB_DER_MAX_BYTES   RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
-                            RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES
-#define PRV_DER_MAX_BYTES   RSA_PRV_DER_MAX_BYTES > ECP_PRV_DER_MAX_BYTES ? \
-                            RSA_PRV_DER_MAX_BYTES : ECP_PRV_DER_MAX_BYTES
+#define PUB_DER_MAX_BYTES   ( RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
+                              RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES )
+#define PRV_DER_MAX_BYTES   ( RSA_PRV_DER_MAX_BYTES > ECP_PRV_DER_MAX_BYTES ? \
+                              RSA_PRV_DER_MAX_BYTES : ECP_PRV_DER_MAX_BYTES )
 
 int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *key, unsigned char *buf, size_t size )
 {
diff --git a/library/platform_util.c b/library/platform_util.c
index 3ba2aea..c8cd52d 100644
--- a/library/platform_util.c
+++ b/library/platform_util.c
@@ -115,7 +115,7 @@
 
 #if !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) ||     \
        ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) &&                     \
-         _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) )
+         _POSIX_THREAD_SAFE_FUNCTIONS >= 200112L ) )
 /*
  * This is a convenience shorthand macro to avoid checking the long
  * preprocessor conditions above. Ideally, we could expose this macro in
@@ -129,7 +129,7 @@
 
 #endif /* !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) ||     \
              ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) &&                     \
-                _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) */
+                _POSIX_THREAD_SAFE_FUNCTIONS >= 200112L ) ) */
 
 struct tm *mbedtls_platform_gmtime_r( const mbedtls_time_t *tt,
                                       struct tm *tm_buf )
diff --git a/library/ripemd160.c b/library/ripemd160.c
index 0b6efcb..d6ee933 100644
--- a/library/ripemd160.c
+++ b/library/ripemd160.c
@@ -147,30 +147,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) ) )
@@ -180,12 +183,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 )                               \
@@ -200,22 +203,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
@@ -225,22 +228,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
@@ -250,22 +253,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
@@ -275,22 +278,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
@@ -300,33 +303,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/rsa.c b/library/rsa.c
index a25c633..c8c23db 100644
--- a/library/rsa.c
+++ b/library/rsa.c
@@ -520,6 +520,9 @@
     mbedtls_rsa_set_padding( ctx, padding, hash_id );
 
 #if defined(MBEDTLS_THREADING_C)
+    /* Set ctx->ver to nonzero to indicate that the mutex has been
+     * initialized and will need to be freed. */
+    ctx->ver = 1;
     mbedtls_mutex_init( &ctx->mutex );
 #endif
 }
@@ -567,9 +570,6 @@
     RSA_VALIDATE_RET( ctx != NULL );
     RSA_VALIDATE_RET( f_rng != NULL );
 
-    if( nbits < 128 || exponent < 3 || nbits % 2 != 0 )
-        return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
-
     /*
      * If the modulus is 1024 bit long or shorter, then the security strength of
      * the RSA algorithm is less than or equal to 80 bits and therefore an error
@@ -582,6 +582,12 @@
     mbedtls_mpi_init( &G );
     mbedtls_mpi_init( &L );
 
+    if( nbits < 128 || exponent < 3 || nbits % 2 != 0 )
+    {
+        ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
+        goto cleanup;
+    }
+
     /*
      * find primes P and Q with Q < P so that:
      * 1.  |P-Q| > 2^( nbits / 2 - 100 )
@@ -659,7 +665,9 @@
     if( ret != 0 )
     {
         mbedtls_rsa_free( ctx );
-        return( MBEDTLS_ERR_RSA_KEY_GEN_FAILED + ret );
+        if( ( -ret & ~0x7f ) == 0 )
+            ret = MBEDTLS_ERR_RSA_KEY_GEN_FAILED + ret;
+        return( ret );
     }
 
     return( 0 );
@@ -1106,10 +1114,10 @@
     mbedtls_mpi_free( &C );
     mbedtls_mpi_free( &I );
 
-    if( ret != 0 )
+    if( ret != 0 && ret >= -0x007f )
         return( MBEDTLS_ERR_RSA_PRIVATE_FAILED + ret );
 
-    return( 0 );
+    return( ret );
 }
 
 #if defined(MBEDTLS_PKCS1_V21)
@@ -2502,7 +2510,6 @@
     RSA_VALIDATE_RET( dst != NULL );
     RSA_VALIDATE_RET( src != NULL );
 
-    dst->ver = src->ver;
     dst->len = src->len;
 
     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->N, &src->N ) );
@@ -2561,7 +2568,12 @@
 #endif /* MBEDTLS_RSA_NO_CRT */
 
 #if defined(MBEDTLS_THREADING_C)
-    mbedtls_mutex_free( &ctx->mutex );
+    /* Free the mutex, but only if it hasn't been freed already. */
+    if( ctx->ver != 0 )
+    {
+        mbedtls_mutex_free( &ctx->mutex );
+        ctx->ver = 0;
+    }
 #endif
 }
 
diff --git a/library/sha1.c b/library/sha1.c
index 8682abd..e99a5e8 100644
--- a/library/sha1.c
+++ b/library/sha1.c
@@ -155,35 +155,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)                                          \
@@ -193,35 +198,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
@@ -229,26 +234,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
@@ -256,26 +261,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
@@ -283,35 +288,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 5169584..75a8f8a 100644
--- a/library/sha256.c
+++ b/library/sha256.c
@@ -209,77 +209,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 36d5d96..986037a 100644
--- a/library/sha512.c
+++ b/library/sha512.c
@@ -243,8 +243,11 @@
                                      const unsigned char data[128] )
 {
     int i;
-    uint64_t temp1, temp2, W[80];
-    uint64_t A, B, C, D, E, F, G, H;
+    struct
+    {
+        uint64_t temp1, temp2, W[80];
+        uint64_t A, B, C, D, E, F, G, H;
+    } local;
 
     SHA512_VALIDATE_RET( ctx != NULL );
     SHA512_VALIDATE_RET( (const unsigned char *)data != NULL );
@@ -261,56 +264,67 @@
 #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 < 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];
     }
 
-    A = ctx->state[0];
-    B = ctx->state[1];
-    C = ctx->state[2];
-    D = ctx->state[3];
-    E = ctx->state[4];
-    F = ctx->state[5];
-    G = ctx->state[6];
-    H = ctx->state[7];
+    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];
+    local.F = ctx->state[5];
+    local.G = ctx->state[6];
+    local.H = ctx->state[7];
     i = 0;
 
     do
     {
-        P( A, B, C, D, E, F, G, H, W[i], K[i] ); i++;
-        P( H, A, B, C, D, E, F, G, W[i], K[i] ); i++;
-        P( G, H, A, B, C, D, E, F, W[i], K[i] ); i++;
-        P( F, G, H, A, B, C, D, E, W[i], K[i] ); i++;
-        P( E, F, G, H, A, B, C, D, W[i], K[i] ); i++;
-        P( D, E, F, G, H, A, B, C, W[i], K[i] ); i++;
-        P( C, D, E, F, G, H, A, B, W[i], K[i] ); i++;
-        P( B, C, D, E, F, G, H, A, W[i], K[i] ); i++;
+        P( local.A, local.B, local.C, local.D, local.E,
+           local.F, local.G, local.H, local.W[i], K[i] ); i++;
+        P( local.H, local.A, local.B, local.C, local.D,
+           local.E, local.F, local.G, local.W[i], K[i] ); i++;
+        P( local.G, local.H, local.A, local.B, local.C,
+           local.D, local.E, local.F, local.W[i], K[i] ); i++;
+        P( local.F, local.G, local.H, local.A, local.B,
+           local.C, local.D, local.E, local.W[i], K[i] ); i++;
+        P( local.E, local.F, local.G, local.H, local.A,
+           local.B, local.C, local.D, local.W[i], K[i] ); i++;
+        P( local.D, local.E, local.F, local.G, local.H,
+           local.A, local.B, local.C, local.W[i], K[i] ); i++;
+        P( local.C, local.D, local.E, local.F, local.G,
+           local.H, local.A, local.B, local.W[i], K[i] ); i++;
+        P( local.B, local.C, local.D, local.E, local.F,
+           local.G, local.H, local.A, local.W[i], K[i] ); i++;
     }
     while( i < 80 );
 
-    ctx->state[0] += A;
-    ctx->state[1] += B;
-    ctx->state[2] += C;
-    ctx->state[3] += D;
-    ctx->state[4] += E;
-    ctx->state[5] += F;
-    ctx->state[6] += G;
-    ctx->state[7] += H;
+    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;
+    ctx->state[5] += local.F;
+    ctx->state[6] += local.G;
+    ctx->state[7] += local.H;
+
+    /* Zeroise buffers and variables to clear sensitive data from memory. */
+    mbedtls_platform_zeroize( &local, sizeof( local ) );
 
     return( 0 );
 }
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 2471600..c749a86 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -621,7 +621,7 @@
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
 #if defined(MBEDTLS_SHA256_C)
 static void ssl_update_checksum_sha256( mbedtls_ssl_context *, const unsigned char *, size_t );
-static void ssl_calc_verify_tls_sha256( mbedtls_ssl_context *,unsigned char * );
+static void ssl_calc_verify_tls_sha256( mbedtls_ssl_context *, unsigned char * );
 static void ssl_calc_finished_tls_sha256( mbedtls_ssl_context *,unsigned char *, int );
 #endif
 
@@ -1142,7 +1142,7 @@
 }
 
 #if defined(MBEDTLS_SSL_PROTO_SSL3)
-void ssl_calc_verify_ssl( mbedtls_ssl_context *ssl, unsigned char hash[36] )
+void ssl_calc_verify_ssl( mbedtls_ssl_context *ssl, unsigned char *hash )
 {
     mbedtls_md5_context md5;
     mbedtls_sha1_context sha1;
@@ -1191,7 +1191,7 @@
 #endif /* MBEDTLS_SSL_PROTO_SSL3 */
 
 #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1)
-void ssl_calc_verify_tls( mbedtls_ssl_context *ssl, unsigned char hash[36] )
+void ssl_calc_verify_tls( mbedtls_ssl_context *ssl, unsigned char *hash )
 {
     mbedtls_md5_context md5;
     mbedtls_sha1_context sha1;
@@ -1219,7 +1219,7 @@
 
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
 #if defined(MBEDTLS_SHA256_C)
-void ssl_calc_verify_tls_sha256( mbedtls_ssl_context *ssl, unsigned char hash[32] )
+void ssl_calc_verify_tls_sha256( mbedtls_ssl_context *ssl, unsigned char *hash )
 {
     mbedtls_sha256_context sha256;
 
@@ -1240,7 +1240,7 @@
 #endif /* MBEDTLS_SHA256_C */
 
 #if defined(MBEDTLS_SHA512_C)
-void ssl_calc_verify_tls_sha384( mbedtls_ssl_context *ssl, unsigned char hash[48] )
+void ssl_calc_verify_tls_sha384( mbedtls_ssl_context *ssl, unsigned char *hash )
 {
     mbedtls_sha512_context sha512;
 
@@ -6363,6 +6363,9 @@
 #endif /* MBEDTLS_SHA256_C */
 
 #if defined(MBEDTLS_SHA512_C)
+
+typedef int (*finish_sha384_t)(mbedtls_sha512_context*, unsigned char*);
+
 static void ssl_calc_finished_tls_sha384(
                 mbedtls_ssl_context *ssl, unsigned char *buf, int from )
 {
@@ -6370,6 +6373,12 @@
     const char *sender;
     mbedtls_sha512_context sha512;
     unsigned char padbuf[48];
+    /*
+     * For SHA-384, we can save 16 bytes by keeping padbuf 48 bytes long.
+     * However, to avoid stringop-overflow warning in gcc, we have to cast
+     * mbedtls_sha512_finish_ret().
+     */
+    finish_sha384_t finish_sha384 = (finish_sha384_t)mbedtls_sha512_finish_ret;
 
     mbedtls_ssl_session *session = ssl->session_negotiate;
     if( !session )
@@ -6396,7 +6405,7 @@
              ? "client finished"
              : "server finished";
 
-    mbedtls_sha512_finish_ret( &sha512, padbuf );
+    finish_sha384( &sha512, padbuf );
 
     ssl->handshake->tls_prf( session->master, 48, sender,
                              padbuf, 48, buf, len );
diff --git a/library/threading.c b/library/threading.c
index 61c4b94..0dc5488 100644
--- a/library/threading.c
+++ b/library/threading.c
@@ -73,7 +73,7 @@
 
 #if !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) ||     \
        ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) &&                     \
-         _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) )
+         _POSIX_THREAD_SAFE_FUNCTIONS >= 200112L ) )
 /*
  * This is a convenience shorthand macro to avoid checking the long
  * preprocessor conditions above. Ideally, we could expose this macro in
@@ -88,7 +88,7 @@
 
 #endif /* !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) ||     \
              ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) &&                     \
-                _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) */
+                _POSIX_THREAD_SAFE_FUNCTIONS >= 200112L ) ) */
 
 #endif /* MBEDTLS_HAVE_TIME_DATE && !MBEDTLS_PLATFORM_GMTIME_R_ALT */
 
@@ -98,6 +98,12 @@
     if( mutex == NULL )
         return;
 
+    /* A nonzero value of is_valid indicates a successfully initialized
+     * mutex. This is a workaround for not being able to return an error
+     * code for this function. The lock/unlock functions return an error
+     * if is_valid is nonzero. The Mbed TLS unit test code uses this field
+     * to distinguish more states of the mutex; see helpers.function for
+     * details. */
     mutex->is_valid = pthread_mutex_init( &mutex->mutex, NULL ) == 0;
 }
 
diff --git a/library/version_features.c b/library/version_features.c
index cbf38dc..8c8e815 100644
--- a/library/version_features.c
+++ b/library/version_features.c
@@ -553,6 +553,9 @@
 #if defined(MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT)
     "MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT",
 #endif /* MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT */
+#if defined(MBEDTLS_TEST_HOOKS)
+    "MBEDTLS_TEST_HOOKS",
+#endif /* MBEDTLS_TEST_HOOKS */
 #if defined(MBEDTLS_THREADING_ALT)
     "MBEDTLS_THREADING_ALT",
 #endif /* MBEDTLS_THREADING_ALT */
diff --git a/library/x509_crt.c b/library/x509_crt.c
index fadd28e..4b53d1a 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -1088,6 +1088,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/programs/ssl/dtls_client.c b/programs/ssl/dtls_client.c
index 69d4f33..fa7a087 100644
--- a/programs/ssl/dtls_client.c
+++ b/programs/ssl/dtls_client.c
@@ -218,6 +218,7 @@
     mbedtls_ssl_conf_ca_chain( &conf, &cacert, NULL );
     mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
     mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
+    mbedtls_ssl_conf_read_timeout( &conf, READ_TIMEOUT_MS );
 
     if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
     {
diff --git a/programs/ssl/dtls_server.c b/programs/ssl/dtls_server.c
index 8339d9d..cebeffa 100644
--- a/programs/ssl/dtls_server.c
+++ b/programs/ssl/dtls_server.c
@@ -114,7 +114,7 @@
 #include "mbedtls/ssl_cache.h"
 #endif
 
-#define READ_TIMEOUT_MS 10000   /* 5 seconds */
+#define READ_TIMEOUT_MS 10000   /* 10 seconds */
 #define DEBUG_LEVEL 0
 
 
@@ -250,6 +250,7 @@
 
     mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
     mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
+    mbedtls_ssl_conf_read_timeout( &conf, READ_TIMEOUT_MS );
 
 #if defined(MBEDTLS_SSL_CACHE_C)
     mbedtls_ssl_conf_session_cache( &conf, &cache,
diff --git a/programs/ssl/query_config.c b/programs/ssl/query_config.c
index 798c917..0a7eb1a 100644
--- a/programs/ssl/query_config.c
+++ b/programs/ssl/query_config.c
@@ -1475,6 +1475,14 @@
     }
 #endif /* MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT */
 
+#if defined(MBEDTLS_TEST_HOOKS)
+    if( strcmp( "MBEDTLS_TEST_HOOKS", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_TEST_HOOKS );
+        return( 0 );
+    }
+#endif /* MBEDTLS_TEST_HOOKS */
+
 #if defined(MBEDTLS_THREADING_ALT)
     if( strcmp( "MBEDTLS_THREADING_ALT", config ) == 0 )
     {
diff --git a/programs/test/selftest.c b/programs/test/selftest.c
index 9bc9a9c..fe35bb1 100644
--- a/programs/test/selftest.c
+++ b/programs/test/selftest.c
@@ -185,7 +185,7 @@
 }
 #endif /* MBEDTLS_SELF_TEST */
 
-static int test_snprintf( size_t n, const char ref_buf[10], int ref_ret )
+static int test_snprintf( size_t n, const char *ref_buf, int ref_ret )
 {
     int ret;
     char buf[10] = "xxxxxxxxx";
diff --git a/tests/data_files/Makefile b/tests/data_files/Makefile
index f5a2715..db4ee3b 100644
--- a/tests/data_files/Makefile
+++ b/tests/data_files/Makefile
@@ -157,7 +157,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/scripts/all.sh b/tests/scripts/all.sh
index a2a26b4..1e56c3e 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -890,11 +890,21 @@
     CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
     make
 
-    msg "test: no HMAC_DRBG"
+    msg "test: Full minus HMAC_DRBG - main suites"
     make test
 
-    # No ssl-opt.sh/compat.sh as they never use HMAC_DRBG so far,
-    # so there's little value in running those lengthy tests here.
+    # Normally our ECDSA implementation uses deterministic ECDSA. But since
+    # HMAC_DRBG is disabled in this configuration, randomized ECDSA is used
+    # instead.
+    # Test SSL with non-deterministic ECDSA. Only test features that
+    # might be affected by how ECDSA signature is performed.
+    msg "test: Full minus HMAC_DRBG - ssl-opt.sh (subset)"
+    if_build_succeeded tests/ssl-opt.sh -f 'Default\|SSL async private: sign'
+
+    # To save time, only test one protocol version, since this part of
+    # the protocol is identical in (D)TLS up to 1.2.
+    msg "test: Full minus HMAC_DRBG - compat.sh (ECDSA)"
+    if_build_succeeded tests/compat.sh -m tls1_2 -t 'ECDSA'
 }
 
 component_test_no_drbg_all_hashes () {
@@ -1314,7 +1324,7 @@
     msg "build: malloc(0) returns NULL (ASan+UBSan build)"
     scripts/config.pl full
     scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C
-    make CC=gcc CFLAGS="'-DMBEDTLS_CONFIG_FILE=\"$PWD/tests/configs/config-wrapper-malloc-0-null.h\"' -O -Werror -Wall -Wextra -fsanitize=address,undefined" LDFLAGS='-fsanitize=address,undefined'
+    make CC=gcc CFLAGS="'-DMBEDTLS_CONFIG_FILE=\"$PWD/tests/configs/config-wrapper-malloc-0-null.h\"' -O $ASAN_CFLAGS" LDFLAGS="$ASAN_CFLAGS"
 
     msg "test: malloc(0) returns NULL (ASan+UBSan build)"
     make test
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index f97f087..7ec83d2 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -688,6 +688,7 @@
         # terminate the server (and the proxy)
         kill $SRV_PID
         wait $SRV_PID
+        SRV_RET=$?
 
         if [ -n "$PXY_CMD" ]; then
             kill $PXY_PID >/dev/null 2>&1
@@ -721,9 +722,11 @@
         fi
     fi
 
-    # check server exit code
-    if [ $? != 0 ]; then
-        fail "server fail"
+    # Check server exit code (only for Mbed TLS: GnuTLS and OpenSSL don't
+    # exit with status 0 when interrupted by a signal, and we don't really
+    # care anyway), in case e.g. the server reports a memory leak.
+    if [ $SRV_RET != 0 ] && is_polar "$SRV_CMD"; then
+        fail "Server exited with status $SRV_RET"
         return
     fi
 
diff --git a/tests/suites/helpers.function b/tests/suites/helpers.function
index 9403d99..ceac670 100644
--- a/tests/suites/helpers.function
+++ b/tests/suites/helpers.function
@@ -46,6 +46,12 @@
 #include <strings.h>
 #endif
 
+#if defined(MBEDTLS_THREADING_C) && defined(MBEDTLS_THREADING_PTHREAD) && \
+    defined(MBEDTLS_TEST_HOOKS)
+#include "mbedtls/threading.h"
+#define MBEDTLS_TEST_MUTEX_USAGE
+#endif
+
 /*
  * Define the two macros
  *
@@ -371,6 +377,9 @@
     const char *test;
     const char *filename;
     int line_no;
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+    const char *mutex_usage_error;
+#endif
 }
 test_info;
 
@@ -777,3 +786,202 @@
     }
     return ret;
 }
+
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+/** Mutex usage verification framework.
+ *
+ * The mutex usage verification code below aims to detect bad usage of
+ * Mbed TLS's mutex abstraction layer at runtime. Note that this is solely
+ * about the use of the mutex itself, not about checking whether the mutex
+ * correctly protects whatever it is supposed to protect.
+ *
+ * The normal usage of a mutex is:
+ * ```
+ * digraph mutex_states {
+ *   "UNINITIALIZED"; // the initial state
+ *   "IDLE";
+ *   "FREED";
+ *   "LOCKED";
+ *   "UNINITIALIZED" -> "IDLE" [label="init"];
+ *   "FREED" -> "IDLE" [label="init"];
+ *   "IDLE" -> "LOCKED" [label="lock"];
+ *   "LOCKED" -> "IDLE" [label="unlock"];
+ *   "IDLE" -> "FREED" [label="free"];
+ * }
+ * ```
+ *
+ * All bad transitions that can be unambiguously detected are reported.
+ * An attempt to use an uninitialized mutex cannot be detected in general
+ * since the memory content may happen to denote a valid state. For the same
+ * reason, a double init cannot be detected.
+ * All-bits-zero is the state of a freed mutex, which is distinct from an
+ * initialized mutex, so attempting to use zero-initialized memory as a mutex
+ * without calling the init function is detected.
+ *
+ * The framework attempts to detect missing calls to init and free by counting
+ * calls to init and free. If there are more calls to init than free, this
+ * means that a mutex is not being freed somewhere, which is a memory leak
+ * on platforms where a mutex consumes resources other than the
+ * mbedtls_threading_mutex_t object itself. If there are more calls to free
+ * than init, this indicates a missing init, which is likely to be detected
+ * by an attempt to lock the mutex as well. A limitation of this framework is
+ * that it cannot detect scenarios where there is exactly the same number of
+ * calls to init and free but the calls don't match. A bug like this is
+ * unlikely to happen uniformly throughout the whole test suite though.
+ *
+ * If an error is detected, this framework will report what happened and the
+ * test case will be marked as failed. Unfortunately, the error report cannot
+ * indicate the exact location of the problematic call. To locate the error,
+ * use a debugger and set a breakpoint on mbedtls_test_mutex_usage_error().
+ */
+enum value_of_mutex_is_valid_field
+{
+    /* Potential values for the is_valid field of mbedtls_threading_mutex_t.
+     * Note that MUTEX_FREED must be 0 and MUTEX_IDLE must be 1 for
+     * compatibility with threading_mutex_init_pthread() and
+     * threading_mutex_free_pthread(). MUTEX_LOCKED could be any nonzero
+     * value. */
+    MUTEX_FREED = 0, //!< Set by threading_mutex_free_pthread
+    MUTEX_IDLE = 1, //!< Set by threading_mutex_init_pthread and by our unlock
+    MUTEX_LOCKED = 2, //!< Set by our lock
+};
+
+typedef struct
+{
+    void (*init)( mbedtls_threading_mutex_t * );
+    void (*free)( mbedtls_threading_mutex_t * );
+    int (*lock)( mbedtls_threading_mutex_t * );
+    int (*unlock)( mbedtls_threading_mutex_t * );
+} mutex_functions_t;
+static mutex_functions_t mutex_functions;
+
+/** The total number of calls to mbedtls_mutex_init(), minus the total number
+ * of calls to mbedtls_mutex_free().
+ *
+ * Reset to 0 after each test case.
+ */
+static int live_mutexes;
+
+static void mbedtls_test_mutex_usage_error( mbedtls_threading_mutex_t *mutex,
+                                            const char *msg )
+{
+    (void) mutex;
+    if( test_info.mutex_usage_error == NULL )
+        test_info.mutex_usage_error = msg;
+    mbedtls_fprintf( stdout, "[mutex: %s] ", msg );
+    /* Don't mark the test as failed yet. This way, if the test fails later
+     * for a functional reason, the test framework will report the message
+     * and location for this functional reason. If the test passes,
+     * mbedtls_test_mutex_usage_check() will mark it as failed. */
+}
+
+static void mbedtls_test_wrap_mutex_init( mbedtls_threading_mutex_t *mutex )
+{
+    mutex_functions.init( mutex );
+    if( mutex->is_valid )
+        ++live_mutexes;
+}
+
+static void mbedtls_test_wrap_mutex_free( mbedtls_threading_mutex_t *mutex )
+{
+    switch( mutex->is_valid )
+    {
+        case MUTEX_FREED:
+            mbedtls_test_mutex_usage_error( mutex, "free without init or double free" );
+            break;
+        case MUTEX_IDLE:
+            /* Do nothing. The underlying free function will reset is_valid
+             * to 0. */
+            break;
+        case MUTEX_LOCKED:
+            mbedtls_test_mutex_usage_error( mutex, "free without unlock" );
+            break;
+        default:
+            mbedtls_test_mutex_usage_error( mutex, "corrupted state" );
+            break;
+    }
+    if( mutex->is_valid )
+        --live_mutexes;
+    mutex_functions.free( mutex );
+}
+
+static int mbedtls_test_wrap_mutex_lock( mbedtls_threading_mutex_t *mutex )
+{
+    int ret = mutex_functions.lock( mutex );
+    switch( mutex->is_valid )
+    {
+        case MUTEX_FREED:
+            mbedtls_test_mutex_usage_error( mutex, "lock without init" );
+            break;
+        case MUTEX_IDLE:
+            if( ret == 0 )
+                mutex->is_valid = 2;
+            break;
+        case MUTEX_LOCKED:
+            mbedtls_test_mutex_usage_error( mutex, "double lock" );
+            break;
+        default:
+            mbedtls_test_mutex_usage_error( mutex, "corrupted state" );
+            break;
+    }
+    return( ret );
+}
+
+static int mbedtls_test_wrap_mutex_unlock( mbedtls_threading_mutex_t *mutex )
+{
+    int ret = mutex_functions.unlock( mutex );
+    switch( mutex->is_valid )
+    {
+        case MUTEX_FREED:
+            mbedtls_test_mutex_usage_error( mutex, "unlock without init" );
+            break;
+        case MUTEX_IDLE:
+            mbedtls_test_mutex_usage_error( mutex, "unlock without lock" );
+            break;
+        case MUTEX_LOCKED:
+            if( ret == 0 )
+                mutex->is_valid = MUTEX_IDLE;
+            break;
+        default:
+            mbedtls_test_mutex_usage_error( mutex, "corrupted state" );
+            break;
+    }
+    return( ret );
+}
+
+static void mbedtls_test_mutex_usage_init( void )
+{
+    mutex_functions.init = mbedtls_mutex_init;
+    mutex_functions.free = mbedtls_mutex_free;
+    mutex_functions.lock = mbedtls_mutex_lock;
+    mutex_functions.unlock = mbedtls_mutex_unlock;
+    mbedtls_mutex_init = &mbedtls_test_wrap_mutex_init;
+    mbedtls_mutex_free = &mbedtls_test_wrap_mutex_free;
+    mbedtls_mutex_lock = &mbedtls_test_wrap_mutex_lock;
+    mbedtls_mutex_unlock = &mbedtls_test_wrap_mutex_unlock;
+}
+
+static void mbedtls_test_mutex_usage_check( void )
+{
+    if( live_mutexes != 0 )
+    {
+        /* A positive number (more init than free) means that a mutex resource
+         * is leaking (on platforms where a mutex consumes more than the
+         * mbedtls_threading_mutex_t object itself). The rare case of a
+         * negative number means a missing init somewhere. */
+        mbedtls_fprintf( stdout, "[mutex: %d leaked] ", live_mutexes );
+        live_mutexes = 0;
+        if( test_info.mutex_usage_error == NULL )
+            test_info.mutex_usage_error = "missing free";
+    }
+    if( test_info.mutex_usage_error != NULL &&
+        test_info.result != TEST_RESULT_FAILED )
+    {
+        /* Functionally, the test passed. But there was a mutex usage error,
+         * so mark the test as failed after all. */
+        test_fail( "Mutex usage error", __LINE__, __FILE__ );
+    }
+    test_info.mutex_usage_error = NULL;
+}
+
+#endif /* MBEDTLS_TEST_MUTEX_USAGE */
diff --git a/tests/suites/host_test.function b/tests/suites/host_test.function
index ca51e7b..3f8a945 100644
--- a/tests/suites/host_test.function
+++ b/tests/suites/host_test.function
@@ -330,7 +330,7 @@
 #if defined(__GNUC__)
 __attribute__((__noinline__))
 #endif
-static int test_snprintf( size_t n, const char ref_buf[10], int ref_ret )
+static int test_snprintf( size_t n, const char *ref_buf, int ref_ret )
 {
     int ret;
     char buf[10] = "xxxxxxxxx";
@@ -412,6 +412,10 @@
     mbedtls_memory_buffer_alloc_init( alloc_buf, sizeof( alloc_buf ) );
 #endif
 
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+    mbedtls_test_mutex_usage_init( );
+#endif
+
     /*
      * The C standard doesn't guarantee that all-bits-0 is the representation
      * of a NULL pointer. We do however use that in our code for initializing
diff --git a/tests/suites/main_test.function b/tests/suites/main_test.function
index 9f36690..2aecf81 100644
--- a/tests/suites/main_test.function
+++ b/tests/suites/main_test.function
@@ -176,6 +176,10 @@
 #else
     fp( params );
 #endif
+
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+    mbedtls_test_mutex_usage_check( );
+#endif /* MBEDTLS_TEST_MUTEX_USAGE */
 }
 
 /**
diff --git a/tests/suites/test_suite_base64.data b/tests/suites/test_suite_base64.data
index da99ffa..3a892f4 100644
--- a/tests/suites/test_suite_base64.data
+++ b/tests/suites/test_suite_base64.data
@@ -151,6 +151,20 @@
 Base64 encode hex #4
 base64_encode_hex:"01020304050607":"AQIDBAUGBw==":13:0
 
+# Rotate the bytes around so that they end up at each offset modulo 3 in
+# successive test cases.
+Base64 encode hex all valid input bytes #0
+base64_encode_hex:"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff":"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==":345:0
+
+Base64 encode hex all valid input bytes #1
+base64_encode_hex:"0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00":"AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AA==":345:0
+
+Base64 encode hex all valid input bytes #2
+base64_encode_hex:"02030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff0001":"AgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQ==":345:0
+
+Base64 encode all valid output characters at all offsets
+base64_encode_hex:"00108310518720928b30d38f41149351559761969b71d79f8218a39259a7a29aabb2dbafc31cb3d35db7e39ebbf3dfbff800420c41461c824a2cc34e3d04524d45565d865a6dc75e7e08628e49669e8a6aaecb6ebf0c72cf4d76df8e7aefcf7effe00108310518720928b30d38f41149351559761969b71d79f8218a39259a7a29aabb2dbafc31cb3d35db7e39ebbf3dfbff800420c41461c824a2cc34e3d04524d45565d865a6dc75e7e08628e49669e8a6aaecb6ebf0c72cf4d76df8e7aefcf7efd0":"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/Q":261:0
+
 Base64 decode hex #1
 base64_decode_hex:"AQIDBAUGBwgJ":"010203040506070809":9:0
 
@@ -166,6 +180,9 @@
 Base64 decode hex #5 (buffer too small)
 base64_decode_hex:"AQIDBAUGBw==":"01020304050607":6:MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL
 
+Base64 decode all valid input characters at all offsets
+base64_decode_hex:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/Q":"00108310518720928b30d38f41149351559761969b71d79f8218a39259a7a29aabb2dbafc31cb3d35db7e39ebbf3dfbff800420c41461c824a2cc34e3d04524d45565d865a6dc75e7e08628e49669e8a6aaecb6ebf0c72cf4d76df8e7aefcf7effe00108310518720928b30d38f41149351559761969b71d79f8218a39259a7a29aabb2dbafc31cb3d35db7e39ebbf3dfbff800420c41461c824a2cc34e3d04524d45565d865a6dc75e7e08628e49669e8a6aaecb6ebf0c72cf4d76df8e7aefcf7efd0":195:0
+
 Base64 Selftest
 depends_on:MBEDTLS_SELF_TEST
 base64_selftest:
diff --git a/tests/suites/test_suite_base64.function b/tests/suites/test_suite_base64.function
index 3a8bf43..0185f3b 100644
--- a/tests/suites/test_suite_base64.function
+++ b/tests/suites/test_suite_base64.function
@@ -13,13 +13,22 @@
 {
     unsigned char src_str[1000];
     unsigned char dst_str[1000];
-    size_t len;
+    size_t len, src_len;
 
     memset(src_str, 0x00, 1000);
     memset(dst_str, 0x00, 1000);
 
     strncpy( (char *) src_str, src_string, sizeof(src_str) - 1 );
-    TEST_ASSERT( mbedtls_base64_encode( dst_str, dst_buf_size, &len, src_str, strlen( (char *) src_str ) ) == result );
+    src_len = strlen( (char *) src_str );
+
+    TEST_CF_SECRET( src_str, sizeof( src_str ) );
+    TEST_ASSERT( mbedtls_base64_encode( dst_str, dst_buf_size, &len, src_str, src_len) == result );
+    TEST_CF_PUBLIC( src_str, sizeof( src_str ) );
+
+    /* dest_str will have had tainted data copied to it, prevent the TEST_ASSERT below from triggering
+       CF failures by unmarking it. */
+    TEST_CF_PUBLIC( dst_str, len );
+
     if( result == 0 )
     {
         TEST_ASSERT( strcmp( (char *) dst_str, dst_string ) == 0 );
@@ -57,7 +66,14 @@
 
     res = zero_alloc( dst_buf_size );
 
+    TEST_CF_SECRET( src->x, src->len );
     TEST_ASSERT( mbedtls_base64_encode( res, dst_buf_size, &len, src->x, src->len ) == result );
+    TEST_CF_PUBLIC( src->x, src->len );
+
+    /* res will have had tainted data copied to it, prevent the TEST_ASSERT below from triggering
+       CF failures by unmarking it. */
+    TEST_CF_PUBLIC( res, len );
+
     if( result == 0 )
     {
         TEST_ASSERT( len == strlen( dst ) );
diff --git a/tests/suites/test_suite_ccm.function b/tests/suites/test_suite_ccm.function
index 1bba531..1b3a25f 100644
--- a/tests/suites/test_suite_ccm.function
+++ b/tests/suites/test_suite_ccm.function
@@ -200,12 +200,11 @@
     unsigned char iv[13];
     unsigned char result[50];
     mbedtls_ccm_context ctx;
-    size_t i, iv_len, tag_len;
+    size_t iv_len, tag_len;
     int ret;
 
     mbedtls_ccm_init( &ctx );
 
-    memset( iv, 0x00, sizeof( iv ) );
     memset( result, 0x00, sizeof( result ) );
 
     if( sec_level % 4 == 0)
@@ -213,12 +212,10 @@
     else
         tag_len = 1 << ( sec_level % 4 + 1);
 
-    for( i = 0; i < source_address->len; i++ )
-        iv[i] = source_address->x[i];
-
-    for( i = 0; i < frame_counter->len; i++ )
-        iv[source_address->len + i] = frame_counter->x[i];
-
+    TEST_ASSERT( source_address->len == 8 );
+    TEST_ASSERT( frame_counter->len == 4 );
+    memcpy( iv, source_address->x, source_address->len );
+    memcpy( iv + source_address->len, frame_counter->x, frame_counter->len );
     iv[source_address->len + frame_counter->len] = sec_level;
     iv_len = sizeof( iv );
 
@@ -253,7 +250,7 @@
     unsigned char iv[13];
     unsigned char result[50];
     mbedtls_ccm_context ctx;
-    size_t i, iv_len, tag_len;
+    size_t iv_len, tag_len;
     int ret;
 
     mbedtls_ccm_init( &ctx );
@@ -266,12 +263,10 @@
     else
         tag_len = 1 << ( sec_level % 4 + 1);
 
-    for( i = 0; i < source_address->len; i++ )
-        iv[i] = source_address->x[i];
-
-    for( i = 0; i < frame_counter->len; i++ )
-        iv[source_address->len + i] = frame_counter->x[i];
-
+    TEST_ASSERT( source_address->len == 8 );
+    TEST_ASSERT( frame_counter->len == 4 );
+    memcpy( iv, source_address->x, source_address->len );
+    memcpy( iv + source_address->len, frame_counter->x, frame_counter->len );
     iv[source_address->len + frame_counter->len] = sec_level;
     iv_len = sizeof( iv );
 
diff --git a/tests/suites/test_suite_ctr_drbg.function b/tests/suites/test_suite_ctr_drbg.function
index 01050d9..d6cf828 100644
--- a/tests/suites/test_suite_ctr_drbg.function
+++ b/tests/suites/test_suite_ctr_drbg.function
@@ -206,13 +206,16 @@
     memset( out, 0, sizeof( out ) );
     memset( add, 0, sizeof( add ) );
 
+    /* Set reseed interval before seed */
+    mbedtls_ctr_drbg_set_reseed_interval( &ctx, 2 * reps );
+
     /* Init must use entropy */
     last_idx = test_offset_idx;
     TEST_ASSERT( mbedtls_ctr_drbg_seed( &ctx, mbedtls_test_entropy_func, entropy, NULL, 0 ) == 0 );
     TEST_ASSERT( last_idx < test_offset_idx );
 
-    /* By default, PR is off and reseed_interval is large,
-     * so the next few calls should not use entropy */
+    /* By default, PR is off, and reseed interval was set to
+     * 2 * reps so the next few calls should not use entropy */
     last_idx = test_offset_idx;
     for( i = 0; i < reps; i++ )
     {
@@ -228,15 +231,16 @@
     TEST_ASSERT( out[sizeof( out ) - 2] == 0 );
     TEST_ASSERT( out[sizeof( out ) - 1] == 0 );
 
-    /* Set reseed_interval to the number of calls done,
-     * so the next call should reseed */
-    mbedtls_ctr_drbg_set_reseed_interval( &ctx, 2 * reps );
+    /* There have been 2 * reps calls to random. The next call should reseed */
     TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
     TEST_ASSERT( last_idx < test_offset_idx );
 
-    /* The new few calls should not reseed */
+    /* Set reseed interval after seed */
+    mbedtls_ctr_drbg_set_reseed_interval( &ctx, 4 * reps + 1 );
+
+    /* The next few calls should not reseed */
     last_idx = test_offset_idx;
-    for( i = 0; i < reps / 2; i++ )
+    for( i = 0; i < (2 * reps); i++ )
     {
         TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
         TEST_ASSERT( mbedtls_ctr_drbg_random_with_add( &ctx, out, sizeof( out ) ,
diff --git a/tests/suites/test_suite_dhm.data b/tests/suites/test_suite_dhm.data
index edebce0..c4795b6 100644
--- a/tests/suites/test_suite_dhm.data
+++ b/tests/suites/test_suite_dhm.data
@@ -22,10 +22,16 @@
 Diffie-Hellman zero modulus
 dhm_do_dhm:10:"0":10:"5":MBEDTLS_ERR_DHM_BAD_INPUT_DATA
 
-Diffie-Hellman load parameters from file
+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
 
-Diffie-Hellman load parameters from file
+Diffie-Hellman load parameters from file [#2]
 dhm_file:"data_files/dh.optlen.pem":"b3126aeaf47153c7d67f403030b292b5bd5a6c9eae1c137af34087fce2a36a578d70c5c560ad2bdb924c4a4dbee20a1671be7103ce87defa76908936803dbeca60c33e1289c1a03ac2c6c4e49405e5902fa0596a1cbaa895cc402d5213ed4a5f1f5ba8b5e1ed3da951a4c475afeb0ca660b7368c38c8e809f382d96ae19e60dc984e61cb42b5dfd723322acf327f9e413cda6400c15c5b2ea1fa34405d83982fba40e6d852da3d91019bf23511314254dc211a90833e5b1798ee52a78198c555644729ad92f060367c74ded37704adfc273a4a33fec821bd2ebd3bc051730e97a4dd14d2b766062592f5eec09d16bb50efebf2cc00dd3e0e3418e60ec84870f7":"800abfe7dc667aa17bcd7c04614bc221a65482ccc04b604602b0e131908a938ea11b48dc515dab7abcbb1e0c7fd66511edc0d86551b7632496e03df94357e1c4ea07a7ce1e381a2fcafdff5f5bf00df828806020e875c00926e4d011f88477a1b01927d73813cad4847c6396b9244621be2b00b63c659253318413443cd244215cd7fd4cbe796e82c6cf70f89cc0c528fb8e344809b31876e7ef739d5160d095c9684188b0c8755c7a468d47f56d6db9ea012924ecb0556fb71312a8d7c93bb2898ea08ee54eeb594548285f06a973cbbe2a0cb02e90f323fe045521f34c68354a6d3e95dbfff1eb64692edc0a44f3d3e408d0e479a541e779a6054259e2d854":256
 
 Diffie-Hellman selftest
diff --git a/tests/suites/test_suite_dhm.function b/tests/suites/test_suite_dhm.function
index 8a05a38..6ec1e7e8 100644
--- a/tests/suites/test_suite_dhm.function
+++ b/tests/suites/test_suite_dhm.function
@@ -206,6 +206,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),
+                                          &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_entropy.data b/tests/suites/test_suite_entropy.data
index 5cff399..25fd57f 100644
--- a/tests/suites/test_suite_entropy.data
+++ b/tests/suites/test_suite_entropy.data
@@ -1,3 +1,9 @@
+Entropy init-free-free
+entropy_init_free:0
+
+Entropy init-free-init-free
+entropy_init_free:1
+
 Create NV seed_file
 nv_seed_file_create:
 
@@ -7,6 +13,9 @@
 Entropy write/update seed file
 entropy_seed_file:"no_such_dir/file":MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR
 
+Entropy write/update seed file: base NV seed file
+entropy_write_base_seed_file:0
+
 Entropy too many sources
 entropy_too_many_sources:
 
diff --git a/tests/suites/test_suite_entropy.function b/tests/suites/test_suite_entropy.function
index 889d3bc..6aa8dd3 100644
--- a/tests/suites/test_suite_entropy.function
+++ b/tests/suites/test_suite_entropy.function
@@ -125,6 +125,28 @@
  * END_DEPENDENCIES
  */
 
+/* BEGIN_CASE */
+void entropy_init_free( int reinit )
+{
+    mbedtls_entropy_context ctx;
+
+    /* Double free is not explicitly documented to work, but it is convenient
+     * to call mbedtls_entropy_free() unconditionally on an error path without
+     * checking whether it has already been called in the success path. */
+
+    mbedtls_entropy_init( &ctx );
+    mbedtls_entropy_free( &ctx );
+
+    if( reinit )
+        mbedtls_entropy_init( &ctx );
+    mbedtls_entropy_free( &ctx );
+
+    /* This test case always succeeds, functionally speaking. A plausible
+     * bug might trigger an invalid pointer dereference or a memory leak. */
+    goto exit;
+}
+/* END_CASE */
+
 /* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */
 void entropy_seed_file( char * path, int ret )
 {
@@ -140,6 +162,21 @@
 }
 /* END_CASE */
 
+/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_NV_SEED:MBEDTLS_FS_IO */
+void entropy_write_base_seed_file( int ret )
+{
+    mbedtls_entropy_context ctx;
+
+    mbedtls_entropy_init( &ctx );
+
+    TEST_ASSERT( mbedtls_entropy_write_seed_file( &ctx, MBEDTLS_PLATFORM_STD_NV_SEED_FILE ) == ret );
+    TEST_ASSERT( mbedtls_entropy_update_seed_file( &ctx, MBEDTLS_PLATFORM_STD_NV_SEED_FILE ) == ret );
+
+exit:
+    mbedtls_entropy_free( &ctx );
+}
+/* END_CASE */
+
 /* BEGIN_CASE */
 void entropy_too_many_sources(  )
 {
@@ -191,6 +228,9 @@
 
     for( j = len; j < sizeof( buf ); j++ )
         TEST_ASSERT( acc[j] == 0 );
+
+exit:
+    mbedtls_entropy_free( &ctx );
 }
 /* END_CASE */
 
diff --git a/tests/suites/test_suite_hmac_drbg.function b/tests/suites/test_suite_hmac_drbg.function
index 13bc400..fbbb1bd 100644
--- a/tests/suites/test_suite_hmac_drbg.function
+++ b/tests/suites/test_suite_hmac_drbg.function
@@ -49,14 +49,17 @@
     md_info = mbedtls_md_info_from_type( md_alg );
     TEST_ASSERT( md_info != NULL );
 
+    /* Set reseed interval before seed */
+    mbedtls_hmac_drbg_set_reseed_interval( &ctx, 2 * reps );
+
     /* Init must use entropy */
     last_len = entropy.len;
     TEST_ASSERT( mbedtls_hmac_drbg_seed( &ctx, md_info, mbedtls_test_entropy_func, &entropy,
                                  NULL, 0 ) == 0 );
     TEST_ASSERT( entropy.len < last_len );
 
-    /* By default, PR is off and reseed_interval is large,
-     * so the next few calls should not use entropy */
+    /* By default, PR is off, and reseed interval was set to
+     * 2 * reps so the next few calls should not use entropy */
     last_len = entropy.len;
     for( i = 0; i < reps; i++ )
     {
@@ -72,15 +75,16 @@
     TEST_ASSERT( out[sizeof( out ) - 2] == 0 );
     TEST_ASSERT( out[sizeof( out ) - 1] == 0 );
 
-    /* Set reseed_interval to the number of calls done,
-     * so the next call should reseed */
-    mbedtls_hmac_drbg_set_reseed_interval( &ctx, 2 * reps );
+    /* There have been 2 * reps calls to random. The next call should reseed */
     TEST_ASSERT( mbedtls_hmac_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
     TEST_ASSERT( entropy.len < last_len );
 
+    /* Set reseed interval after seed */
+    mbedtls_hmac_drbg_set_reseed_interval( &ctx, 4 * reps + 1);
+
     /* The new few calls should not reseed */
     last_len = entropy.len;
-    for( i = 0; i < reps / 2; i++ )
+    for( i = 0; i < (2 * reps); i++ )
     {
         TEST_ASSERT( mbedtls_hmac_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
         TEST_ASSERT( mbedtls_hmac_drbg_random_with_add( &ctx, out, sizeof( out ) ,
@@ -189,7 +193,7 @@
     TEST_ASSERT( mbedtls_hmac_drbg_random_with_add( &ctx, my_output, output->len,
                                             add2->x, add2->len ) == 0 );
 
-    /* clear for second run */
+    /* Reset context for second run */
     mbedtls_hmac_drbg_free( &ctx );
 
     TEST_ASSERT( memcmp( my_output, output->x, output->len ) == 0 );
diff --git a/tests/suites/test_suite_mpi.data b/tests/suites/test_suite_mpi.data
index 00926ff..5229253 100644
--- a/tests/suites/test_suite_mpi.data
+++ b/tests/suites/test_suite_mpi.data
@@ -433,12 +433,6 @@
 Test mbedtls_mpi_add_abs #1
 mbedtls_mpi_add_abs:10:"-643808006803554439230129854961492699151386107534013432918073439524138264842370630061369715394739134090922937332590384720397133335969549256322620979036686633213903952966175107096769180017646161851573147596390153":10:"56125680981752282333498088313568935051383833838594899821664631784577337171193624243181360054669678410455329112434552942717084003541384594864129940145043086760031292483340068923506115878221189886491132772739661669044958531131327771":10:"56125680981752282334141896320372489490613963693556392520816017892111350604111697682705498319512049040516698827829292076808006940873974979584527073481012636016353913462376755556720019831187364993587901952757307830896531678727717924"
 
-Test mbedtls_mpi_add_abs #2 (add to first value)
-mpi_add_abs_add_first:10:"123123":10:"123123":10:"246246"
-
-Test mbedtls_mpi_add_abs #3 (add to second value)
-mpi_add_abs_add_second:10:"123123":10:"123123":10:"246246"
-
 Regression mbedtls_mpi_add_abs (add small to very large MPI with carry rollover)
 mbedtls_mpi_add_abs:16:"FFFFFFFFFFFFFFFFFFFFFFFFFFFFF8":16:"08":16:"1000000000000000000000000000000"
 
@@ -478,18 +472,30 @@
 Test mbedtls_mpi_add_int #2
 mbedtls_mpi_add_int:10:"2039568783564019774057658669290345772801939933143482630947726464532830627227012776329":-9871232:10:"2039568783564019774057658669290345772801939933143482630947726464532830627227002905097"
 
-Base test mbedtls_mpi_sub_abs #1 (Test with larger second input)
+Base test mbedtls_mpi_sub_abs #1 (|B| > |A|)
 mbedtls_mpi_sub_abs:10:"5":10:"7":10:"0":MBEDTLS_ERR_MPI_NEGATIVE_VALUE
 
-Base test mbedtls_mpi_sub_abs #2 (Test with larger second input)
+Base test mbedtls_mpi_sub_abs #2 (|B| > |A|)
 mbedtls_mpi_sub_abs:10:"-5":10:"-7":10:"0":MBEDTLS_ERR_MPI_NEGATIVE_VALUE
 
-Base test mbedtls_mpi_sub_abs #3 (Test with larger second input)
+Base test mbedtls_mpi_sub_abs #3 (|B| > |A|)
 mbedtls_mpi_sub_abs:10:"-5":10:"7":10:"0":MBEDTLS_ERR_MPI_NEGATIVE_VALUE
 
-Base test mbedtls_mpi_sub_abs #4 (Test with larger second input)
+Base test mbedtls_mpi_sub_abs #4 (|B| > |A|)
 mbedtls_mpi_sub_abs:10:"5":10:"-7":10:"0":MBEDTLS_ERR_MPI_NEGATIVE_VALUE
 
+Base test mbedtls_mpi_sub_abs #1 (|B| >> |A| with more limbs)
+mbedtls_mpi_sub_abs:10:"5":16:"123456789abcdef01":10:"0":MBEDTLS_ERR_MPI_NEGATIVE_VALUE
+
+Base test mbedtls_mpi_sub_abs #2 (|B| >> |A| with more limbs)
+mbedtls_mpi_sub_abs:10:"-5":16:"-123456789abcdef01":10:"0":MBEDTLS_ERR_MPI_NEGATIVE_VALUE
+
+Base test mbedtls_mpi_sub_abs #3 (|B| >> |A| with more limbs)
+mbedtls_mpi_sub_abs:10:"-5":16:"123456789abcdef01":10:"0":MBEDTLS_ERR_MPI_NEGATIVE_VALUE
+
+Base test mbedtls_mpi_sub_abs #4 (|B| >> |A| with more limbs)
+mbedtls_mpi_sub_abs:10:"5":16:"-123456789abcdef01":10:"0":MBEDTLS_ERR_MPI_NEGATIVE_VALUE
+
 Base test mbedtls_mpi_sub_abs #1
 mbedtls_mpi_sub_abs:10:"7":10:"5":10:"2":0
 
@@ -679,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)
 mbedtls_mpi_exp_mod:10:"-10000000000":10:"10000000000":10:"99999":10:"":10:"1":0
 
-Test mbedtls_mpi_exp_mod (Negative base)
+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
@@ -929,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 dcb0aaf..2384d12 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
@@ -777,6 +798,15 @@
     TEST_ASSERT( mbedtls_mpi_add_mpi( &Z, &X, &Y ) == 0 );
     TEST_ASSERT( mbedtls_mpi_cmp_mpi( &Z, &A ) == 0 );
 
+    /* result == first operand */
+    TEST_ASSERT( mbedtls_mpi_add_mpi( &X, &X, &Y ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &X, &A ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_read_string( &X, radix_X, input_X ) == 0 );
+
+    /* result == second operand */
+    TEST_ASSERT( mbedtls_mpi_add_mpi( &Y, &X, &Y ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &Y, &A ) == 0 );
+
 exit:
     mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z ); mbedtls_mpi_free( &A );
 }
@@ -822,44 +852,17 @@
     TEST_ASSERT( mbedtls_mpi_add_abs( &Z, &X, &Y ) == 0 );
     TEST_ASSERT( mbedtls_mpi_cmp_mpi( &Z, &A ) == 0 );
 
-exit:
-    mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z ); mbedtls_mpi_free( &A );
-}
-/* END_CASE */
-
-/* BEGIN_CASE */
-void mpi_add_abs_add_first( int radix_X, char * input_X, int radix_Y,
-                            char * input_Y, int radix_A, char * input_A )
-{
-    mbedtls_mpi X, Y, A;
-    mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &A );
-
-    TEST_ASSERT( mbedtls_mpi_read_string( &X, radix_X, input_X ) == 0 );
-    TEST_ASSERT( mbedtls_mpi_read_string( &Y, radix_Y, input_Y ) == 0 );
-    TEST_ASSERT( mbedtls_mpi_read_string( &A, radix_A, input_A ) == 0 );
+    /* result == first operand */
     TEST_ASSERT( mbedtls_mpi_add_abs( &X, &X, &Y ) == 0 );
     TEST_ASSERT( mbedtls_mpi_cmp_mpi( &X, &A ) == 0 );
-
-exit:
-    mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &A );
-}
-/* END_CASE */
-
-/* BEGIN_CASE */
-void mpi_add_abs_add_second( int radix_X, char * input_X, int radix_Y,
-                             char * input_Y, int radix_A, char * input_A )
-{
-    mbedtls_mpi X, Y, A;
-    mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &A );
-
     TEST_ASSERT( mbedtls_mpi_read_string( &X, radix_X, input_X ) == 0 );
-    TEST_ASSERT( mbedtls_mpi_read_string( &Y, radix_Y, input_Y ) == 0 );
-    TEST_ASSERT( mbedtls_mpi_read_string( &A, radix_A, input_A ) == 0 );
+
+    /* result == second operand */
     TEST_ASSERT( mbedtls_mpi_add_abs( &Y, &X, &Y ) == 0 );
     TEST_ASSERT( mbedtls_mpi_cmp_mpi( &Y, &A ) == 0 );
 
 exit:
-    mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &A );
+    mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z ); mbedtls_mpi_free( &A );
 }
 /* END_CASE */
 
@@ -893,6 +896,15 @@
     TEST_ASSERT( mbedtls_mpi_sub_mpi( &Z, &X, &Y ) == 0 );
     TEST_ASSERT( mbedtls_mpi_cmp_mpi( &Z, &A ) == 0 );
 
+    /* result == first operand */
+    TEST_ASSERT( mbedtls_mpi_sub_mpi( &X, &X, &Y ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &X, &A ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_read_string( &X, radix_X, input_X ) == 0 );
+
+    /* result == second operand */
+    TEST_ASSERT( mbedtls_mpi_sub_mpi( &Y, &X, &Y ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_cmp_mpi( &Y, &A ) == 0 );
+
 exit:
     mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z ); mbedtls_mpi_free( &A );
 }
@@ -916,6 +928,17 @@
     if( res == 0 )
         TEST_ASSERT( mbedtls_mpi_cmp_mpi( &Z, &A ) == 0 );
 
+    /* result == first operand */
+    TEST_ASSERT( mbedtls_mpi_sub_abs( &X, &X, &Y ) == sub_result );
+    if( sub_result == 0 )
+        TEST_ASSERT( mbedtls_mpi_cmp_mpi( &X, &A ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_read_string( &X, radix_X, input_X ) == 0 );
+
+    /* result == second operand */
+    TEST_ASSERT( mbedtls_mpi_sub_abs( &Y, &X, &Y ) == sub_result );
+    if( sub_result == 0 )
+        TEST_ASSERT( mbedtls_mpi_cmp_mpi( &Y, &A ) == 0 );
+
 exit:
     mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z ); mbedtls_mpi_free( &A );
 }
@@ -1113,6 +1136,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 )
@@ -1253,6 +1310,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_pkwrite.function b/tests/suites/test_suite_pkwrite.function
index 43c275e..2bad4ed 100644
--- a/tests/suites/test_suite_pkwrite.function
+++ b/tests/suites/test_suite_pkwrite.function
@@ -17,7 +17,7 @@
     unsigned char check_buf[5000];
     int ret;
     FILE *f;
-    size_t ilen;
+    size_t ilen, pem_len, buf_index;
 
     memset( buf, 0, sizeof( buf ) );
     memset( check_buf, 0, sizeof( check_buf ) );
@@ -28,12 +28,20 @@
     ret = mbedtls_pk_write_pubkey_pem( &key, buf, sizeof( buf ));
     TEST_ASSERT( ret == 0 );
 
+    pem_len = strlen( (char *) buf );
+
+    // check that the rest of the buffer remains clear
+    for( buf_index = pem_len; buf_index < sizeof( buf ); ++buf_index )
+    {
+        TEST_ASSERT( buf[buf_index] == 0 );
+    }
+
     f = fopen( key_file, "r" );
     TEST_ASSERT( f != NULL );
     ilen = fread( check_buf, 1, sizeof( check_buf ), f );
     fclose( f );
 
-    TEST_ASSERT( ilen == strlen( (char *) buf ) );
+    TEST_ASSERT( ilen == pem_len );
     TEST_ASSERT( memcmp( (char *) buf, (char *) check_buf, ilen ) == 0 );
 
 exit:
@@ -49,7 +57,7 @@
     unsigned char check_buf[5000];
     int ret;
     FILE *f;
-    size_t ilen;
+    size_t ilen, pem_len, buf_index;
 
     memset( buf, 0, sizeof( buf ) );
     memset( check_buf, 0, sizeof( check_buf ) );
@@ -60,6 +68,14 @@
     ret = mbedtls_pk_write_key_pem( &key, buf, sizeof( buf ));
     TEST_ASSERT( ret == 0 );
 
+    pem_len = strlen( (char *) buf );
+
+    // check that the rest of the buffer remains clear
+    for( buf_index = pem_len; buf_index < sizeof( buf ); ++buf_index )
+    {
+        TEST_ASSERT( buf[buf_index] == 0 );
+    }
+
     f = fopen( key_file, "r" );
     TEST_ASSERT( f != NULL );
     ilen = fread( check_buf, 1, sizeof( check_buf ), f );
diff --git a/tests/suites/test_suite_rsa.data b/tests/suites/test_suite_rsa.data
index 5e4de17..4ed8339 100644
--- a/tests/suites/test_suite_rsa.data
+++ b/tests/suites/test_suite_rsa.data
@@ -1,6 +1,12 @@
 RSA parameter validation
 rsa_invalid_param:
 
+RSA init-free-free
+rsa_init_free:0
+
+RSA init-free-init-free
+rsa_init_free:1
+
 RSA PKCS1 Verify v1.5 CAVS #1
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_PKCS1_V15
 # Good padding but wrong hash
diff --git a/tests/suites/test_suite_rsa.function b/tests/suites/test_suite_rsa.function
index f8a2dad..89b419f 100644
--- a/tests/suites/test_suite_rsa.function
+++ b/tests/suites/test_suite_rsa.function
@@ -466,6 +466,29 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
+void rsa_init_free( int reinit )
+{
+    mbedtls_rsa_context ctx;
+
+    /* Double free is not explicitly documented to work, but we rely on it
+     * even inside the library so that you can call mbedtls_rsa_free()
+     * unconditionally on an error path without checking whether it has
+     * already been called in the success path. */
+
+    mbedtls_rsa_init( &ctx, 0, 0 );
+    mbedtls_rsa_free( &ctx );
+
+    if( reinit )
+        mbedtls_rsa_init( &ctx, 0, 0 );
+    mbedtls_rsa_free( &ctx );
+
+    /* This test case always succeeds, functionally speaking. A plausible
+     * bug might trigger an invalid pointer dereference or a memory leak. */
+    goto exit;
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
 void mbedtls_rsa_pkcs1_sign( data_t * message_str, int padding_mode,
                              int digest, int mod, int radix_P, char * input_P,
                              int radix_Q, char * input_Q, int radix_N,
diff --git a/tests/suites/test_suite_version.data b/tests/suites/test_suite_version.data
index cc907b6..66ee453 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.16.8"
+check_compiletime_version:"2.16.10"
 
 Check runtime library version
-check_runtime_version:"2.16.8"
+check_runtime_version:"2.16.10"
 
 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 fe84474..2d1aeca 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -1884,6 +1884,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
diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function
index 535807e..40bccd6 100644
--- a/tests/suites/test_suite_x509write.function
+++ b/tests/suites/test_suite_x509write.function
@@ -45,7 +45,7 @@
     unsigned char buf[4096];
     unsigned char check_buf[4000];
     int ret;
-    size_t olen = 0, pem_len = 0;
+    size_t olen = 0, pem_len = 0, buf_index;
     int der_len = -1;
     FILE *f;
     const char *subject_name = "C=NL,O=PolarSSL,CN=PolarSSL Server 1";
@@ -71,6 +71,11 @@
 
     pem_len = strlen( (char *) buf );
 
+    for( buf_index = pem_len; buf_index < sizeof( buf ); ++buf_index )
+    {
+        TEST_ASSERT( buf[buf_index] == 0 );
+    }
+
     f = fopen( cert_req_check_file, "r" );
     TEST_ASSERT( f != NULL );
     olen = fread( check_buf, 1, sizeof( check_buf ), f );
@@ -113,7 +118,7 @@
     unsigned char check_buf[5000];
     mbedtls_mpi serial;
     int ret;
-    size_t olen = 0, pem_len = 0;
+    size_t olen = 0, pem_len = 0, buf_index = 0;
     int der_len = -1;
     FILE *f;
     rnd_pseudo_info rnd_info;
@@ -182,6 +187,12 @@
 
     pem_len = strlen( (char *) buf );
 
+    // check that the rest of the buffer remains clear
+    for( buf_index = pem_len; buf_index < sizeof( buf ); ++buf_index )
+    {
+        TEST_ASSERT( buf[buf_index] == 0 );
+    }
+
     f = fopen( cert_check_file, "r" );
     TEST_ASSERT( f != NULL );
     olen = fread( check_buf, 1, sizeof( check_buf ), f );