Merge development commit f352f7 into development-psa

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 010dffc..18851db 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -50,7 +50,7 @@
 
  2. All bug fixes that correct a defect that is also present in an LTS branch must be backported to that LTS branch. If a bug fix introduces a change to the API such as a new function, the fix should be reworked to avoid the API change. API changes without very strong justification are unlikely to be accepted.
 
- 3. If a contribution is a new feature or enhancement, no backporting is required. Exceptions to this may be addtional test cases or quality improvements such as changes to build or test scripts.
+ 3. If a contribution is a new feature or enhancement, no backporting is required. Exceptions to this may be additional test cases or quality improvements such as changes to build or test scripts.
 
 It would be highly appreciated if contributions are backported to LTS branches in addition to the [development branch](https://github.com/ARMmbed/mbedtls/tree/development) by contributors.
 
diff --git a/ChangeLog b/ChangeLog
index 35478b9..f3fd1ef 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -15,6 +15,10 @@
    * Remove a duplicate #include in a sample program. Fixed by Masashi Honma #2326.
    * Remove the mbedtls namespacing from the header file, to fix a "file not found"
      build error. Fixed by Haijun Gu #2319.
+   * Fix signed-to-unsigned integer conversion warning
+     in X.509 module. Fixes #2212.
+   * Reduce stack usage of `mpi_write_hlp()` by eliminating recursion.
+     Fixes #2190.
 
 Changes
    * Include configuration file in all header files that use configuration,
@@ -32,6 +36,15 @@
   * Add an experimental configuration option, MBEDTLS_PSA_CRYPTO_C, to enable
     the PSA Crypto API from Mbed Crypto when additionally used with the
     USE_CRYPTO_SUBMODULE build option.
+  * Correct many misspellings. Fixed by MisterDA #2371.
+  * Provide an abstraction of vsnprintf to allow alternative implementations
+   for platforms that don't provide it. Based on contributions by Joris Aerts
+   and Nathaniel Wesley Filardo.
+  * Fix clobber list in MIPS assembly for large integer multiplication.
+    Previously, this could lead to functionally incorrect assembly being
+    produced by some optimizing compilers, showing up as failures in
+    e.g. RSA or ECC signature operations. Reported in #1722, fix suggested
+    by Aurelien Jarno and submitted by Jeffrey Martin.
 
 = mbed TLS 2.16.0 branch released 2018-12-21
 
@@ -118,7 +131,6 @@
      and mbedtls_hmac_drbg_update() respectively, but the new functions
      report errors whereas the old functions return void. We recommend that
      applications use the new functions.
->>>>>>> development
 
 = mbed TLS 2.14.0 branch released 2018-11-19
 
@@ -343,7 +355,7 @@
      1.2, that allowed a local attacker, able to execute code on the local
      machine as well as manipulate network packets, to partially recover the
      plaintext of messages under some conditions by using a cache attack
-     targetting an internal MD/SHA buffer. With TLS or if
+     targeting an internal MD/SHA buffer. With TLS or if
      mbedtls_ssl_conf_dtls_badmac_limit() was used, the attack only worked if
      the same secret (for example a HTTP Cookie) has been repeatedly sent over
      connections manipulated by the attacker. Connections using GCM or CCM
@@ -1229,7 +1241,7 @@
    * Fix potential build failures related to the 'apidoc' target, introduced
      in the previous patch release. Found by Robert Scheck. #390 #391
    * Fix issue in Makefile that prevented building using armar. #386
-   * Fix memory leak that occured only when ECJPAKE was enabled and ECDHE and
+   * Fix memory leak that occurred only when ECJPAKE was enabled and ECDHE and
      ECDSA was disabled in config.h . The leak didn't occur by default.
    * Fix an issue that caused valid certificates to be rejected whenever an
      expired or not yet valid certificate was parsed before a valid certificate
@@ -1471,7 +1483,7 @@
      You now need to link to all of them if you use TLS for example.
    * All public identifiers moved to the mbedtls_* or MBEDTLS_* namespace.
      Some names have been further changed to make them more consistent.
-     Migration helpers scripts/rename.pl and include/mbedlts/compat-1.3.h are
+     Migration helpers scripts/rename.pl and include/mbedtls/compat-1.3.h are
      provided. Full list of renamings in scripts/data_files/rename-1.3-2.0.txt
    * Renamings of fields inside structures, not covered by the previous list:
      mbedtls_cipher_info_t.key_length -> key_bitlen
@@ -1526,7 +1538,7 @@
    * net_accept() gained new arguments for the size of the client_ip buffer.
    * In the threading layer, mbedtls_mutex_init() and mbedtls_mutex_free() now
      return void.
-   * ecdsa_write_signature() gained an addtional md_alg argument and
+   * ecdsa_write_signature() gained an additional md_alg argument and
      ecdsa_write_signature_det() was deprecated.
    * pk_sign() no longer accepts md_alg == POLARSSL_MD_NONE with ECDSA.
    * Last argument of x509_crt_check_key_usage() and
@@ -3061,7 +3073,7 @@
       not swapped on PadLock; also fixed compilation on older versions
       of gcc (bug reported by David Barrett)
     * Correctly handle the case in padlock_xcryptcbc() when input or
-      ouput data is non-aligned by falling back to the software
+      output data is non-aligned by falling back to the software
       implementation, as VIA Nehemiah cannot handle non-aligned buffers
     * Fixed a memory leak in x509parse_crt() which was reported by Greg
       Robson-Garth; some x509write.c fixes by Pascal Vizeli, thanks to
diff --git a/README.md b/README.md
index 58e5273..268fcde 100644
--- a/README.md
+++ b/README.md
@@ -47,7 +47,7 @@
 
 Setting the variable `SHARED` in your environment will build shared libraries in addition to the static libraries. Setting `DEBUG` gives you a debug build. You can override `CFLAGS` and `LDFLAGS` by setting them in your environment or on the make command line; compiler warning options may be overridden separately using `WARNING_CFLAGS`. Some directory-specific options (for example, `-I` directives) are still preserved.
 
-Please note that setting `CFLAGS` overrides its default value of `-O2` and setting `WARNING_CFLAGS` overrides its default value (starting with `-Wall -W`), so if you just want to add some warning options to the default ones, you can do so by setting `CFLAGS=-O2 -Werror` for example. Setting `WARNING_CFLAGS` is useful when you want to get rid of its default content (for example because your compiler doesn't accept `-Wall` as an option). Directory-specific options cannot be overriden from the command line.
+Please note that setting `CFLAGS` overrides its default value of `-O2` and setting `WARNING_CFLAGS` overrides its default value (starting with `-Wall -W`), so if you just want to add some warning options to the default ones, you can do so by setting `CFLAGS=-O2 -Werror` for example. Setting `WARNING_CFLAGS` is useful when you want to get rid of its default content (for example because your compiler doesn't accept `-Wall` as an option). Directory-specific options cannot be overridden from the command line.
 
 Depending on your platform, you might run into some issues. Please check the Makefiles in `library/`, `programs/` and `tests/` for options to manually add or remove for specific platforms. You can also check [the Mbed TLS Knowledge Base](https://tls.mbed.org/kb) for articles on your platform or issue.
 
diff --git a/include/mbedtls/bn_mul.h b/include/mbedtls/bn_mul.h
index ac1e3f9..c33bd8d 100644
--- a/include/mbedtls/bn_mul.h
+++ b/include/mbedtls/bn_mul.h
@@ -756,7 +756,7 @@
         "sw     $10, %2         \n\t"   \
         : "=m" (c), "=m" (d), "=m" (s)                      \
         : "m" (s), "m" (d), "m" (c), "m" (b)                \
-        : "$9", "$10", "$11", "$12", "$13", "$14", "$15"    \
+        : "$9", "$10", "$11", "$12", "$13", "$14", "$15", "lo", "hi" \
     );
 
 #endif /* MIPS */
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index ab35e20..6cf117d 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -50,6 +50,11 @@
     !defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO)
 #define MBEDTLS_PLATFORM_SNPRINTF_ALT
 #endif
+
+#if !defined(MBEDTLS_PLATFORM_VSNPRINTF_ALT) && \
+    !defined(MBEDTLS_PLATFORM_VSNPRINTF_MACRO)
+#define MBEDTLS_PLATFORM_VSNPRINTF_ALT
+#endif
 #endif /* _WIN32 */
 
 #if defined(TARGET_LIKE_MBED) && \
@@ -701,7 +706,7 @@
 /*
  * Avoid warning from -pedantic. This is a convenient place for this
  * workaround since this is included by every single file before the
- * #if defined(MBEDTLS_xxx_C) that results in emtpy translation units.
+ * #if defined(MBEDTLS_xxx_C) that results in empty translation units.
  */
 typedef int mbedtls_iso_c_forbids_empty_translation_units;
 
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index f8684ac..fab0107 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -139,7 +139,7 @@
  *
  * System has time.h, time(), and an implementation for
  * mbedtls_platform_gmtime_r() (see below).
- * The time needs to be correct (not necesarily very accurate, but at least
+ * The time needs to be correct (not necessarily very accurate, but at least
  * the date should be correct). This is used to verify the validity period of
  * X.509 certificates.
  *
@@ -226,6 +226,7 @@
 //#define MBEDTLS_PLATFORM_FPRINTF_ALT
 //#define MBEDTLS_PLATFORM_PRINTF_ALT
 //#define MBEDTLS_PLATFORM_SNPRINTF_ALT
+//#define MBEDTLS_PLATFORM_VSNPRINTF_ALT
 //#define MBEDTLS_PLATFORM_NV_SEED_ALT
 //#define MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT
 
@@ -401,7 +402,7 @@
  * \note Because of a signature change, the core AES encryption and decryption routines are
  *       currently named mbedtls_aes_internal_encrypt and mbedtls_aes_internal_decrypt,
  *       respectively. When setting up alternative implementations, these functions should
- *       be overriden, but the wrapper functions mbedtls_aes_decrypt and mbedtls_aes_encrypt
+ *       be overridden, but the wrapper functions mbedtls_aes_decrypt and mbedtls_aes_encrypt
  *       must stay untouched.
  *
  * \note If you use the AES_xxx_ALT macros, then is is recommended to also set
@@ -1538,7 +1539,7 @@
  * \def MBEDTLS_SSL_SESSION_TICKETS
  *
  * Enable support for RFC 5077 session tickets in SSL.
- * Client-side, provides full support for session tickets (maintainance of a
+ * Client-side, provides full support for session tickets (maintenance of a
  * session store remains the responsibility of the application, though).
  * Server-side, you also need to provide callbacks for writing and parsing
  * tickets, including authenticated encryption and key management. Example
@@ -1722,7 +1723,7 @@
  *
  * \warning TLS-level compression MAY REDUCE SECURITY! See for example the
  * CRIME attack. Before enabling this option, you should examine with care if
- * CRIME or similar exploits may be a applicable to your use case.
+ * CRIME or similar exploits may be applicable to your use case.
  *
  * \note Currently compression can't be used with DTLS.
  *
@@ -3053,7 +3054,7 @@
 //#define MBEDTLS_PLATFORM_STD_TIME            time /**< Default time to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */
 //#define MBEDTLS_PLATFORM_STD_FPRINTF      fprintf /**< Default fprintf to use, can be undefined */
 //#define MBEDTLS_PLATFORM_STD_PRINTF        printf /**< Default printf to use, can be undefined */
-/* Note: your snprintf must correclty zero-terminate the buffer! */
+/* Note: your snprintf must correctly zero-terminate the buffer! */
 //#define MBEDTLS_PLATFORM_STD_SNPRINTF    snprintf /**< Default snprintf to use, can be undefined */
 //#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS       0 /**< Default exit value to use, can be undefined */
 //#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE       1 /**< Default exit value to use, can be undefined */
@@ -3070,8 +3071,9 @@
 //#define MBEDTLS_PLATFORM_TIME_TYPE_MACRO       time_t /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */
 //#define MBEDTLS_PLATFORM_FPRINTF_MACRO      fprintf /**< Default fprintf macro to use, can be undefined */
 //#define MBEDTLS_PLATFORM_PRINTF_MACRO        printf /**< Default printf macro to use, can be undefined */
-/* Note: your snprintf must correclty zero-terminate the buffer! */
+/* Note: your snprintf must correctly zero-terminate the buffer! */
 //#define MBEDTLS_PLATFORM_SNPRINTF_MACRO    snprintf /**< Default snprintf macro to use, can be undefined */
+//#define MBEDTLS_PLATFORM_VSNPRINTF_MACRO    vsnprintf /**< Default vsnprintf macro to use, can be undefined */
 //#define MBEDTLS_PLATFORM_NV_SEED_READ_MACRO   mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */
 //#define MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO  mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */
 
diff --git a/include/mbedtls/hmac_drbg.h b/include/mbedtls/hmac_drbg.h
index 7eae32b..f1289cb 100644
--- a/include/mbedtls/hmac_drbg.h
+++ b/include/mbedtls/hmac_drbg.h
@@ -82,7 +82,7 @@
  */
 typedef struct mbedtls_hmac_drbg_context
 {
-    /* Working state: the key K is not stored explicitely,
+    /* Working state: the key K is not stored explicitly,
      * but is implied by the HMAC context */
     mbedtls_md_context_t md_ctx;                    /*!< HMAC context (inc. K)  */
     unsigned char V[MBEDTLS_MD_MAX_SIZE];  /*!< V in the spec          */
diff --git a/include/mbedtls/platform.h b/include/mbedtls/platform.h
index 89fe8a7..801a948 100644
--- a/include/mbedtls/platform.h
+++ b/include/mbedtls/platform.h
@@ -58,17 +58,33 @@
  * \{
  */
 
+/* The older Microsoft Windows common runtime provides non-conforming
+ * implementations of some standard library functions, including snprintf
+ * and vsnprintf. This affects MSVC and MinGW builds.
+ */
+#if defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER <= 1900)
+#define MBEDTLS_PLATFORM_HAS_NON_CONFORMING_SNPRINTF
+#define MBEDTLS_PLATFORM_HAS_NON_CONFORMING_VSNPRINTF
+#endif
+
 #if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS)
 #include <stdio.h>
 #include <stdlib.h>
 #include <time.h>
 #if !defined(MBEDTLS_PLATFORM_STD_SNPRINTF)
-#if defined(_WIN32)
+#if defined(MBEDTLS_PLATFORM_HAS_NON_CONFORMING_SNPRINTF)
 #define MBEDTLS_PLATFORM_STD_SNPRINTF   mbedtls_platform_win32_snprintf /**< The default \c snprintf function to use.  */
 #else
 #define MBEDTLS_PLATFORM_STD_SNPRINTF   snprintf /**< The default \c snprintf function to use.  */
 #endif
 #endif
+#if !defined(MBEDTLS_PLATFORM_STD_VSNPRINTF)
+#if defined(MBEDTLS_PLATFORM_HAS_NON_CONFORMING_VSNPRINTF)
+#define MBEDTLS_PLATFORM_STD_VSNPRINTF   mbedtls_platform_win32_vsnprintf /**< The default \c vsnprintf function to use.  */
+#else
+#define MBEDTLS_PLATFORM_STD_VSNPRINTF   vsnprintf /**< The default \c vsnprintf function to use.  */
+#endif
+#endif
 #if !defined(MBEDTLS_PLATFORM_STD_PRINTF)
 #define MBEDTLS_PLATFORM_STD_PRINTF   printf /**< The default \c printf function to use. */
 #endif
@@ -204,7 +220,7 @@
  * - however it is acceptable to return -1 instead of the required length when
  *   the destination buffer is too short.
  */
-#if defined(_WIN32)
+#if defined(MBEDTLS_PLATFORM_HAS_NON_CONFORMING_SNPRINTF)
 /* For Windows (inc. MSYS2), we provide our own fixed implementation */
 int mbedtls_platform_win32_snprintf( char *s, size_t n, const char *fmt, ... );
 #endif
@@ -231,6 +247,41 @@
 #endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */
 
 /*
+ * The function pointers for vsnprintf
+ *
+ * The vsnprintf implementation should conform to C99:
+ * - it *must* always correctly zero-terminate the buffer
+ *   (except when n == 0, then it must leave the buffer untouched)
+ * - however it is acceptable to return -1 instead of the required length when
+ *   the destination buffer is too short.
+ */
+#if defined(MBEDTLS_PLATFORM_HAS_NON_CONFORMING_VSNPRINTF)
+/* For Older Windows (inc. MSYS2), we provide our own fixed implementation */
+int mbedtls_platform_win32_vsnprintf( char *s, size_t n, const char *fmt, va_list arg );
+#endif
+
+#if defined(MBEDTLS_PLATFORM_VSNPRINTF_ALT)
+#include <stdarg.h>
+extern int (*mbedtls_vsnprintf)( char * s, size_t n, const char * format, va_list arg );
+
+/**
+ * \brief   Set your own snprintf function pointer
+ *
+ * \param   vsnprintf_func   The \c vsnprintf function implementation
+ *
+ * \return  \c 0
+ */
+int mbedtls_platform_set_vsnprintf( int (*vsnprintf_func)( char * s, size_t n,
+                                                 const char * format, va_list arg ) );
+#else /* MBEDTLS_PLATFORM_VSNPRINTF_ALT */
+#if defined(MBEDTLS_PLATFORM_VSNPRINTF_MACRO)
+#define mbedtls_vsnprintf   MBEDTLS_PLATFORM_VSNPRINTF_MACRO
+#else
+#define mbedtls_vsnprintf   vsnprintf
+#endif /* MBEDTLS_PLATFORM_VSNPRINTF_MACRO */
+#endif /* MBEDTLS_PLATFORM_VSNPRINTF_ALT */
+
+/*
  * The function pointers for exit
  */
 #if defined(MBEDTLS_PLATFORM_EXIT_ALT)
diff --git a/include/mbedtls/rsa.h b/include/mbedtls/rsa.h
index 906c427..4ff5bdd 100644
--- a/include/mbedtls/rsa.h
+++ b/include/mbedtls/rsa.h
@@ -150,13 +150,13 @@
  * \note           The choice of padding mode is strictly enforced for private key
  *                 operations, since there might be security concerns in
  *                 mixing padding modes. For public key operations it is
- *                 a default value, which can be overriden by calling specific
+ *                 a default value, which can be overridden by calling specific
  *                 \c rsa_rsaes_xxx or \c rsa_rsassa_xxx functions.
  *
  * \note           The hash selected in \p hash_id is always used for OEAP
  *                 encryption. For PSS signatures, it is always used for
- *                 making signatures, but can be overriden for verifying them.
- *                 If set to #MBEDTLS_MD_NONE, it is always overriden.
+ *                 making signatures, but can be overridden for verifying them.
+ *                 If set to #MBEDTLS_MD_NONE, it is always overridden.
  *
  * \param ctx      The RSA context to initialize. This must not be \c NULL.
  * \param padding  The padding mode to use. This must be either
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 64b6380..46007a7 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -2055,7 +2055,7 @@
  *                 provision more than one cert/key pair (eg one ECDSA, one
  *                 RSA with SHA-256, one RSA with SHA-1). An adequate
  *                 certificate will be selected according to the client's
- *                 advertised capabilities. In case mutliple certificates are
+ *                 advertised capabilities. In case multiple certificates are
  *                 adequate, preference is given to the one set by the first
  *                 call to this function, then second, etc.
  *
@@ -3300,7 +3300,7 @@
  *                 mbedtls_ssl_config_defaults() or mbedtls_ssl_config_free().
  *
  * \note           You need to call mbedtls_ssl_config_defaults() unless you
- *                 manually set all of the relevent fields yourself.
+ *                 manually set all of the relevant fields yourself.
  *
  * \param conf     SSL configuration context
  */
diff --git a/include/mbedtls/ssl_ticket.h b/include/mbedtls/ssl_ticket.h
index a84e781..774a007 100644
--- a/include/mbedtls/ssl_ticket.h
+++ b/include/mbedtls/ssl_ticket.h
@@ -117,14 +117,14 @@
 /**
  * \brief           Implementation of the ticket write callback
  *
- * \note            See \c mbedlts_ssl_ticket_write_t for description
+ * \note            See \c mbedtls_ssl_ticket_write_t for description
  */
 mbedtls_ssl_ticket_write_t mbedtls_ssl_ticket_write;
 
 /**
  * \brief           Implementation of the ticket parse callback
  *
- * \note            See \c mbedlts_ssl_ticket_parse_t for description
+ * \note            See \c mbedtls_ssl_ticket_parse_t for description
  */
 mbedtls_ssl_ticket_parse_t mbedtls_ssl_ticket_parse;
 
diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h
index 9ae825c..63aae32 100644
--- a/include/mbedtls/x509.h
+++ b/include/mbedtls/x509.h
@@ -77,7 +77,7 @@
 #define MBEDTLS_ERR_X509_ALLOC_FAILED                     -0x2880  /**< Allocation of memory failed. */
 #define MBEDTLS_ERR_X509_FILE_IO_ERROR                    -0x2900  /**< Read/write of file failed. */
 #define MBEDTLS_ERR_X509_BUFFER_TOO_SMALL                 -0x2980  /**< Destination buffer is too small. */
-#define MBEDTLS_ERR_X509_FATAL_ERROR                      -0x3000  /**< A fatal error occured, eg the chain is too long or the vrfy callback failed. */
+#define MBEDTLS_ERR_X509_FATAL_ERROR                      -0x3000  /**< A fatal error occurred, eg the chain is too long or the vrfy callback failed. */
 /* \} name */
 
 /**
@@ -250,7 +250,7 @@
  *
  * \param to       mbedtls_x509_time to check
  *
- * \return         1 if the given time is in the past or an error occured,
+ * \return         1 if the given time is in the past or an error occurred,
  *                 0 otherwise.
  */
 int mbedtls_x509_time_is_past( const mbedtls_x509_time *to );
@@ -264,7 +264,7 @@
  *
  * \param from     mbedtls_x509_time to check
  *
- * \return         1 if the given time is in the future or an error occured,
+ * \return         1 if the given time is in the future or an error occurred,
  *                 0 otherwise.
  */
 int mbedtls_x509_time_is_future( const mbedtls_x509_time *from );
diff --git a/include/mbedtls/x509_crl.h b/include/mbedtls/x509_crl.h
index 08a4283..fa838d6 100644
--- a/include/mbedtls/x509_crl.h
+++ b/include/mbedtls/x509_crl.h
@@ -111,7 +111,7 @@
 /**
  * \brief          Parse one or more CRLs and append them to the chained list
  *
- * \note           Mutliple CRLs are accepted only if using PEM format
+ * \note           Multiple CRLs are accepted only if using PEM format
  *
  * \param chain    points to the start of the chain
  * \param buf      buffer holding the CRL data in PEM or DER format
@@ -126,7 +126,7 @@
 /**
  * \brief          Load one or more CRLs and append them to the chained list
  *
- * \note           Mutliple CRLs are accepted only if using PEM format
+ * \note           Multiple CRLs are accepted only if using PEM format
  *
  * \param chain    points to the start of the chain
  * \param path     filename to read the CRLs from (in PEM or DER encoding)
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index bd27349..6d45fe4 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -98,6 +98,12 @@
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-declarations -Wmissing-prototypes -Wdocumentation -Wno-documentation-deprecated-sync -Wunreachable-code")
 endif(CMAKE_COMPILER_IS_CLANG)
 
+if(UNSAFE_BUILD)
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error")
+    set(CMAKE_C_FLAGS_ASAN "${CMAKE_C_FLAGS_ASAN} -Wno-error")
+    set(CMAKE_C_FLAGS_ASANDBG "${CMAKE_C_FLAGS_ASANDBG} -Wno-error")
+endif(UNSAFE_BUILD)
+
 if(WIN32)
     set(libs ${libs} ws2_32)
 endif(WIN32)
diff --git a/library/Makefile b/library/Makefile
index f01b1a1..d10fc41 100644
--- a/library/Makefile
+++ b/library/Makefile
@@ -39,7 +39,7 @@
 SOEXT_X509=so.0
 SOEXT_CRYPTO=so.3
 
-# Set AR_DASH= (empty string) to use an ar implentation that does not accept
+# Set AR_DASH= (empty string) to use an ar implementation that does not accept
 # the - prefix for command line options (e.g. llvm-ar)
 AR_DASH ?= -
 
diff --git a/library/bignum.c b/library/bignum.c
index d3d02b1..87015af 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -527,26 +527,38 @@
 }
 
 /*
- * Helper to write the digits high-order first
+ * Helper to write the digits high-order first.
  */
-static int mpi_write_hlp( mbedtls_mpi *X, int radix, char **p )
+static int mpi_write_hlp( mbedtls_mpi *X, int radix,
+                          char **p, const size_t buflen )
 {
     int ret;
     mbedtls_mpi_uint r;
+    size_t length = 0;
+    char *p_end = *p + buflen;
 
-    if( radix < 2 || radix > 16 )
-        return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+    do
+    {
+        if( length >= buflen )
+        {
+            return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
+        }
 
-    MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, radix ) );
-    MBEDTLS_MPI_CHK( mbedtls_mpi_div_int( X, NULL, X, radix ) );
+        MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, radix ) );
+        MBEDTLS_MPI_CHK( mbedtls_mpi_div_int( X, NULL, X, radix ) );
+        /*
+         * Write the residue in the current position, as an ASCII character.
+         */
+        if( r < 0xA )
+            *(--p_end) = (char)( '0' + r );
+        else
+            *(--p_end) = (char)( 'A' + ( r - 0xA ) );
 
-    if( mbedtls_mpi_cmp_int( X, 0 ) != 0 )
-        MBEDTLS_MPI_CHK( mpi_write_hlp( X, radix, p ) );
+        length++;
+    } while( mbedtls_mpi_cmp_int( X, 0 ) != 0 );
 
-    if( r < 10 )
-        *(*p)++ = (char)( r + 0x30 );
-    else
-        *(*p)++ = (char)( r + 0x37 );
+    memmove( *p, p_end, length );
+    *p += length;
 
 cleanup:
 
@@ -619,7 +631,7 @@
         if( T.s == -1 )
             T.s = 1;
 
-        MBEDTLS_MPI_CHK( mpi_write_hlp( &T, radix, &p ) );
+        MBEDTLS_MPI_CHK( mpi_write_hlp( &T, radix, &p, buflen ) );
     }
 
     *p++ = '\0';
diff --git a/library/cipher.c b/library/cipher.c
index 618277b..2636c09 100644
--- a/library/cipher.c
+++ b/library/cipher.c
@@ -279,7 +279,7 @@
     CIPHER_VALIDATE_RET( ctx != NULL );
     CIPHER_VALIDATE_RET( key != NULL );
     CIPHER_VALIDATE_RET( operation == MBEDTLS_ENCRYPT ||
-                        operation == MBEDTLS_DECRYPT );
+                         operation == MBEDTLS_DECRYPT );
     if( ctx->cipher_info == NULL )
         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
 
@@ -1414,7 +1414,7 @@
     CIPHER_VALIDATE_RET( output != NULL );
     CIPHER_VALIDATE_RET( olen != NULL );
     CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL );
-    
+
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     if( ctx->psa_enabled == 1 )
     {
diff --git a/library/ctr_drbg.c b/library/ctr_drbg.c
index fb12157..0db7beb 100644
--- a/library/ctr_drbg.c
+++ b/library/ctr_drbg.c
@@ -102,7 +102,8 @@
     /*
      * Initialize with an empty key
      */
-    if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, key, MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
+    if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, key,
+                                        MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
     {
         return( ret );
     }
@@ -120,8 +121,9 @@
                    const unsigned char *custom,
                    size_t len )
 {
-    return( mbedtls_ctr_drbg_seed_entropy_len( ctx, f_entropy, p_entropy, custom, len,
-                                       MBEDTLS_CTR_DRBG_ENTROPY_LEN ) );
+    return( mbedtls_ctr_drbg_seed_entropy_len( ctx, f_entropy, p_entropy,
+                                               custom, len,
+                                               MBEDTLS_CTR_DRBG_ENTROPY_LEN ) );
 }
 
 void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx )
@@ -136,17 +138,20 @@
     mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ctr_drbg_context ) );
 }
 
-void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx, int resistance )
+void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx,
+                                                 int resistance )
 {
     ctx->prediction_resistance = resistance;
 }
 
-void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx, size_t len )
+void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx,
+                                       size_t len )
 {
     ctx->entropy_len = len;
 }
 
-void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx, int interval )
+void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx,
+                                           int interval )
 {
     ctx->reseed_interval = interval;
 }
@@ -154,7 +159,8 @@
 static int block_cipher_df( unsigned char *output,
                             const unsigned char *data, size_t data_len )
 {
-    unsigned char buf[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT + MBEDTLS_CTR_DRBG_BLOCKSIZE + 16];
+    unsigned char buf[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT +
+                      MBEDTLS_CTR_DRBG_BLOCKSIZE + 16];
     unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN];
     unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
     unsigned char chain[MBEDTLS_CTR_DRBG_BLOCKSIZE];
@@ -168,7 +174,8 @@
     if( data_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT )
         return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
 
-    memset( buf, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT + MBEDTLS_CTR_DRBG_BLOCKSIZE + 16 );
+    memset( buf, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT +
+            MBEDTLS_CTR_DRBG_BLOCKSIZE + 16 );
     mbedtls_aes_init( &aes_ctx );
 
     /*
@@ -193,7 +200,8 @@
     for( i = 0; i < MBEDTLS_CTR_DRBG_KEYSIZE; i++ )
         key[i] = i;
 
-    if( ( ret = mbedtls_aes_setkey_enc( &aes_ctx, key, MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
+    if( ( ret = mbedtls_aes_setkey_enc( &aes_ctx, key,
+                                        MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
     {
         goto exit;
     }
@@ -215,7 +223,8 @@
             use_len -= ( use_len >= MBEDTLS_CTR_DRBG_BLOCKSIZE ) ?
                        MBEDTLS_CTR_DRBG_BLOCKSIZE : use_len;
 
-            if( ( ret = mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT, chain, chain ) ) != 0 )
+            if( ( ret = mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT,
+                                               chain, chain ) ) != 0 )
             {
                 goto exit;
             }
@@ -232,7 +241,8 @@
     /*
      * Do final encryption with reduced data
      */
-    if( ( ret = mbedtls_aes_setkey_enc( &aes_ctx, tmp, MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
+    if( ( ret = mbedtls_aes_setkey_enc( &aes_ctx, tmp,
+                                        MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
     {
         goto exit;
     }
@@ -241,7 +251,8 @@
 
     for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE )
     {
-        if( ( ret = mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT, iv, iv ) ) != 0 )
+        if( ( ret = mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT,
+                                           iv, iv ) ) != 0 )
         {
             goto exit;
         }
@@ -277,7 +288,7 @@
  *   ctx->counter = V
  */
 static int ctr_drbg_update_internal( mbedtls_ctr_drbg_context *ctx,
-                              const unsigned char data[MBEDTLS_CTR_DRBG_SEEDLEN] )
+                          const unsigned char data[MBEDTLS_CTR_DRBG_SEEDLEN] )
 {
     unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN];
     unsigned char *p = tmp;
@@ -298,8 +309,11 @@
         /*
          * Crypt counter block
          */
-        if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, ctx->counter, p ) ) != 0 )
+        if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT,
+                                           ctx->counter, p ) ) != 0 )
+        {
             goto exit;
+        }
 
         p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
     }
@@ -310,9 +324,13 @@
     /*
      * Update key and counter
      */
-    if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, tmp, MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
+    if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, tmp,
+                                        MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
+    {
         goto exit;
-    memcpy( ctx->counter, tmp + MBEDTLS_CTR_DRBG_KEYSIZE, MBEDTLS_CTR_DRBG_BLOCKSIZE );
+    }
+    memcpy( ctx->counter, tmp + MBEDTLS_CTR_DRBG_KEYSIZE,
+            MBEDTLS_CTR_DRBG_BLOCKSIZE );
 
 exit:
     mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
@@ -496,11 +514,14 @@
         /*
          * Crypt counter block
          */
-        if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, ctx->counter, tmp ) ) != 0 )
+        if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT,
+                                           ctx->counter, tmp ) ) != 0 )
+        {
             goto exit;
+        }
 
-        use_len = ( output_len > MBEDTLS_CTR_DRBG_BLOCKSIZE ) ? MBEDTLS_CTR_DRBG_BLOCKSIZE :
-                                                       output_len;
+        use_len = ( output_len > MBEDTLS_CTR_DRBG_BLOCKSIZE )
+            ? MBEDTLS_CTR_DRBG_BLOCKSIZE : output_len;
         /*
          * Copy random block to destination
          */
@@ -520,7 +541,8 @@
     return( 0 );
 }
 
-int mbedtls_ctr_drbg_random( void *p_rng, unsigned char *output, size_t output_len )
+int mbedtls_ctr_drbg_random( void *p_rng, unsigned char *output,
+                             size_t output_len )
 {
     int ret;
     mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng;
@@ -541,7 +563,8 @@
 }
 
 #if defined(MBEDTLS_FS_IO)
-int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path )
+int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx,
+                                      const char *path )
 {
     int ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
     FILE *f;
@@ -550,13 +573,19 @@
     if( ( f = fopen( path, "wb" ) ) == NULL )
         return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR );
 
-    if( ( ret = mbedtls_ctr_drbg_random( ctx, buf, MBEDTLS_CTR_DRBG_MAX_INPUT ) ) != 0 )
+    if( ( ret = mbedtls_ctr_drbg_random( ctx, buf,
+                                         MBEDTLS_CTR_DRBG_MAX_INPUT ) ) != 0 )
         goto exit;
 
-    if( fwrite( buf, 1, MBEDTLS_CTR_DRBG_MAX_INPUT, f ) != MBEDTLS_CTR_DRBG_MAX_INPUT )
+    if( fwrite( buf, 1, MBEDTLS_CTR_DRBG_MAX_INPUT, f ) !=
+        MBEDTLS_CTR_DRBG_MAX_INPUT )
+    {
         ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
+    }
     else
+    {
         ret = 0;
+    }
 
 exit:
     mbedtls_platform_zeroize( buf, sizeof( buf ) );
@@ -565,7 +594,8 @@
     return( ret );
 }
 
-int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path )
+int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx,
+                                       const char *path )
 {
     int ret = 0;
     FILE *f = NULL;
@@ -679,7 +709,7 @@
 
     test_offset = 0;
     CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy,
-                                (void *) entropy_source_pr, nonce_pers_pr, 16, 32 ) );
+                         (void *) entropy_source_pr, nonce_pers_pr, 16, 32 ) );
     mbedtls_ctr_drbg_set_prediction_resistance( &ctx, MBEDTLS_CTR_DRBG_PR_ON );
     CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) );
     CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) );
@@ -700,7 +730,7 @@
 
     test_offset = 0;
     CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy,
-                            (void *) entropy_source_nopr, nonce_pers_nopr, 16, 32 ) );
+                     (void *) entropy_source_nopr, nonce_pers_nopr, 16, 32 ) );
     CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) );
     CHK( mbedtls_ctr_drbg_reseed( &ctx, NULL, 0 ) );
     CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) );
diff --git a/library/debug.c b/library/debug.c
index 824cd02..6e1efbf 100644
--- a/library/debug.c
+++ b/library/debug.c
@@ -35,6 +35,7 @@
 #define mbedtls_free        free
 #define mbedtls_time_t      time_t
 #define mbedtls_snprintf    snprintf
+#define mbedtls_vsnprintf   vsnprintf
 #endif
 
 #include "mbedtls/debug.h"
@@ -90,20 +91,7 @@
         return;
 
     va_start( argp, format );
-#if defined(_WIN32)
-#if defined(_TRUNCATE) && !defined(__MINGW32__)
-    ret = _vsnprintf_s( str, DEBUG_BUF_SIZE, _TRUNCATE, format, argp );
-#else
-    ret = _vsnprintf( str, DEBUG_BUF_SIZE, format, argp );
-    if( ret < 0 || (size_t) ret == DEBUG_BUF_SIZE )
-    {
-        str[DEBUG_BUF_SIZE-1] = '\0';
-        ret = -1;
-    }
-#endif
-#else
-    ret = vsnprintf( str, DEBUG_BUF_SIZE, format, argp );
-#endif
+    ret = mbedtls_vsnprintf( str, DEBUG_BUF_SIZE, format, argp );
     va_end( argp );
 
     if( ret >= 0 && ret < DEBUG_BUF_SIZE - 1 )
diff --git a/library/ecjpake.c b/library/ecjpake.c
index be941b1..b276514 100644
--- a/library/ecjpake.c
+++ b/library/ecjpake.c
@@ -951,7 +951,7 @@
     0xb4, 0x38, 0xf7, 0x19, 0xd3, 0xc4, 0xf3, 0x51
 };
 
-/* Load my private keys and generate the correponding public keys */
+/* Load my private keys and generate the corresponding public keys */
 static int ecjpake_test_load( mbedtls_ecjpake_context *ctx,
                               const unsigned char *xm1, size_t len1,
                               const unsigned char *xm2, size_t len2 )
diff --git a/library/error.c b/library/error.c
index 12312a0..c596f0b 100644
--- a/library/error.c
+++ b/library/error.c
@@ -567,7 +567,7 @@
         if( use_ret == -(MBEDTLS_ERR_X509_BUFFER_TOO_SMALL) )
             mbedtls_snprintf( buf, buflen, "X509 - Destination buffer is too small" );
         if( use_ret == -(MBEDTLS_ERR_X509_FATAL_ERROR) )
-            mbedtls_snprintf( buf, buflen, "X509 - A fatal error occured, eg the chain is too long or the vrfy callback failed" );
+            mbedtls_snprintf( buf, buflen, "X509 - A fatal error occurred, eg the chain is too long or the vrfy callback failed" );
 #endif /* MBEDTLS_X509_USE_C || MBEDTLS_X509_CREATE_C */
         // END generated code
 
diff --git a/library/platform.c b/library/platform.c
index 73a6db9..5756159 100644
--- a/library/platform.c
+++ b/library/platform.c
@@ -82,28 +82,15 @@
           !( defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&
              defined(MBEDTLS_PLATFORM_FREE_MACRO) ) */
 
-#if defined(_WIN32)
+#if defined(MBEDTLS_PLATFORM_HAS_NON_CONFORMING_SNPRINTF)
 #include <stdarg.h>
 int mbedtls_platform_win32_snprintf( char *s, size_t n, const char *fmt, ... )
 {
     int ret;
     va_list argp;
 
-    /* Avoid calling the invalid parameter handler by checking ourselves */
-    if( s == NULL || n == 0 || fmt == NULL )
-        return( -1 );
-
     va_start( argp, fmt );
-#if defined(_TRUNCATE) && !defined(__MINGW32__)
-    ret = _vsnprintf_s( s, n, _TRUNCATE, fmt, argp );
-#else
-    ret = _vsnprintf( s, n, fmt, argp );
-    if( ret < 0 || (size_t) ret == n )
-    {
-        s[n-1] = '\0';
-        ret = -1;
-    }
-#endif
+    ret = mbedtls_vsnprintf( s, n, fmt, argp );
     va_end( argp );
 
     return( ret );
@@ -140,6 +127,62 @@
 }
 #endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */
 
+#if defined(MBEDTLS_PLATFORM_HAS_NON_CONFORMING_VSNPRINTF)
+#include <stdarg.h>
+int mbedtls_platform_win32_vsnprintf( char *s, size_t n, const char *fmt, va_list arg )
+{
+    int ret;
+
+    /* Avoid calling the invalid parameter handler by checking ourselves */
+    if( s == NULL || n == 0 || fmt == NULL )
+        return( -1 );
+
+#if defined(_TRUNCATE)
+    ret = vsnprintf_s( s, n, _TRUNCATE, fmt, arg );
+#else
+    ret = vsnprintf( s, n, fmt, arg );
+    if( ret < 0 || (size_t) ret == n )
+    {
+        s[n-1] = '\0';
+        ret = -1;
+    }
+#endif
+
+    return( ret );
+}
+#endif
+
+#if defined(MBEDTLS_PLATFORM_VSNPRINTF_ALT)
+#if !defined(MBEDTLS_PLATFORM_STD_VSNPRINTF)
+/*
+ * Make dummy function to prevent NULL pointer dereferences
+ */
+static int platform_vsnprintf_uninit( char * s, size_t n,
+                                     const char * format, va_list arg )
+{
+    ((void) s);
+    ((void) n);
+    ((void) format);
+    ((void) arg);
+    return( -1 );
+}
+
+#define MBEDTLS_PLATFORM_STD_VSNPRINTF    platform_vsnprintf_uninit
+#endif /* !MBEDTLS_PLATFORM_STD_VSNPRINTF */
+
+int (*mbedtls_vsnprintf)( char * s, size_t n,
+                          const char * format,
+                          va_list arg ) = MBEDTLS_PLATFORM_STD_VSNPRINTF;
+
+int mbedtls_platform_set_vsnprintf( int (*vsnprintf_func)( char * s, size_t n,
+                                                 const char * format,
+                                                 va_list arg ) )
+{
+    mbedtls_vsnprintf = vsnprintf_func;
+    return( 0 );
+}
+#endif /* MBEDTLS_PLATFORM_VSNPRINTF_ALT */
+
 #if defined(MBEDTLS_PLATFORM_PRINTF_ALT)
 #if !defined(MBEDTLS_PLATFORM_STD_PRINTF)
 /*
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index 8a90288..46e24e4 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -1489,7 +1489,7 @@
      */
 
     /*
-     * Minimal length (with everything empty and extensions ommitted) is
+     * Minimal length (with everything empty and extensions omitted) is
      * 2 + 32 + 1 + 2 + 1 = 38 bytes. Check that first, so that we can
      * read at least up to session id length without worrying.
      */
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index cf44ed5..0664627 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -2772,7 +2772,7 @@
         }
 
         /*
-         * A record can't be split accross datagrams. If we need to read but
+         * A record can't be split across datagrams. If we need to read but
          * are not at the beginning of a new record, the caller did something
          * wrong.
          */
diff --git a/library/version_features.c b/library/version_features.c
index b8cada9..1a4b6de 100644
--- a/library/version_features.c
+++ b/library/version_features.c
@@ -72,6 +72,9 @@
 #if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT)
     "MBEDTLS_PLATFORM_SNPRINTF_ALT",
 #endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */
+#if defined(MBEDTLS_PLATFORM_VSNPRINTF_ALT)
+    "MBEDTLS_PLATFORM_VSNPRINTF_ALT",
+#endif /* MBEDTLS_PLATFORM_VSNPRINTF_ALT */
 #if defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
     "MBEDTLS_PLATFORM_NV_SEED_ALT",
 #endif /* MBEDTLS_PLATFORM_NV_SEED_ALT */
diff --git a/library/x509.c b/library/x509.c
index 52b5b64..6b7899f 100644
--- a/library/x509.c
+++ b/library/x509.c
@@ -116,7 +116,7 @@
 }
 
 /*
- * Parse an algorithm identifier with (optional) paramaters
+ * Parse an algorithm identifier with (optional) parameters
  */
 int mbedtls_x509_get_alg( unsigned char **p, const unsigned char *end,
                   mbedtls_x509_buf *alg, mbedtls_x509_buf *params )
diff --git a/library/x509_crt.c b/library/x509_crt.c
index 3a3c0a0..1b1f0a7 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -373,7 +373,7 @@
     for( i = 0; i < MBEDTLS_X509_MAX_VERIFY_CHAIN_SIZE; i++ )
     {
         ver_chain->items[i].crt = NULL;
-        ver_chain->items[i].flags = -1;
+        ver_chain->items[i].flags = (uint32_t) -1;
     }
 
     ver_chain->len = 0;
@@ -2261,7 +2261,7 @@
  * Tests for (aspects of) this function should include at least:
  * - trusted EE
  * - EE -> trusted root
- * - EE -> intermedate CA -> trusted root
+ * - EE -> intermediate CA -> trusted root
  * - if relevant: EE untrusted
  * - if relevant: EE -> intermediate, untrusted
  * with the aspect under test checked at each relevant level (EE, int, root).
diff --git a/tests/compat.sh b/tests/compat.sh
index bf65e5e..1814528 100755
--- a/tests/compat.sh
+++ b/tests/compat.sh
@@ -21,7 +21,7 @@
 SKIPPED=0
 SRVMEM=0
 
-# default commands, can be overriden by the environment
+# default commands, can be overridden by the environment
 : ${M_SRV:=../programs/ssl/ssl_server2}
 : ${M_CLI:=../programs/ssl/ssl_client2}
 : ${OPENSSL_CMD:=openssl} # OPENSSL would conflict with the build system
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index cc5aa52..925f203 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -55,21 +55,46 @@
 # Notes for maintainers
 # ---------------------
 #
+# The bulk of the code is organized into functions that follow one of the
+# following naming conventions:
+#  * pre_XXX: things to do before running the tests, in order.
+#  * component_XXX: independent components. They can be run in any order.
+#      * component_check_XXX: quick tests that aren't worth parallelizing.
+#      * component_build_XXX: build things but don't run them.
+#      * component_test_XXX: build and test.
+#  * support_XXX: if support_XXX exists and returns false then
+#    component_XXX is not run by default.
+#  * post_XXX: things to do after running the tests.
+#  * other: miscellaneous support functions.
+#
+# Each component must start by invoking `msg` with a short informative message.
+#
+# The framework performs some cleanup tasks after each component. This
+# means that components can assume that the working directory is in a
+# cleaned-up state, and don't need to perform the cleanup themselves.
+# * Run `make clean`.
+# * Restore `include/mbedtks/config.h` from a backup made before running
+#   the component.
+# * Check out `Makefile`, `library/Makefile`, `programs/Makefile` and
+#   `tests/Makefile` from git. This cleans up after an in-tree use of
+#   CMake.
+#
+# Any command that is expected to fail must be protected so that the
+# script keeps running in --keep-going mode despite `set -e`. In keep-going
+# mode, if a protected command fails, this is logged as a failure and the
+# script will exit with a failure status once it has run all components.
+# Commands can be protected in any of the following ways:
+# * `make` is a function which runs the `make` command with protection.
+#   Note that you must write `make VAR=value`, not `VAR=value make`,
+#   because the `VAR=value make` syntax doesn't work with functions.
+# * Put `report_status` before the command to protect it.
+# * Put `if_build_successful` before a command. This protects it, and
+#   additionally skips it if a prior invocation of `make` in the same
+#   component failed.
+#
 # The tests are roughly in order from fastest to slowest. This doesn't
 # have to be exact, but in general you should add slower tests towards
 # the end and fast checks near the beginning.
-#
-# Sanity checks have the following form:
-#   1. msg "short description of what is about to be done"
-#   2. run sanity check (failure stops the script)
-#
-# Build or build-and-test steps have the following form:
-#   1. msg "short description of what is about to be done"
-#   2. cleanup
-#   3. preparation (config.pl, cmake, ...) (failure stops the script)
-#   4. make
-#   5. Run tests if relevant. All tests must be prefixed with
-#      if_build_successful for the sake of --keep-going.
 
 
 
@@ -80,55 +105,98 @@
 # Abort on errors (and uninitialised variables)
 set -eu
 
-if [ "$( uname )" != "Linux" ]; then
-    echo "This script only works in Linux" >&2
-    exit 1
-elif [ -d library -a -d include -a -d tests ]; then :; else
-    echo "Must be run from mbed TLS root" >&2
-    exit 1
-fi
+pre_check_environment () {
+    if [ -d library -a -d include -a -d tests ]; then :; else
+        echo "Must be run from mbed TLS root" >&2
+        exit 1
+    fi
+}
 
 if ! [ -f crypto/Makefile ]; then
     echo "Please initialize the crypto submodule" >&2
     exit 1
 fi
 
-CONFIG_H='include/mbedtls/config.h'
-CONFIG_BAK="$CONFIG_H.bak"
+pre_initialize_variables () {
+    CONFIG_H='include/mbedtls/config.h'
+    CONFIG_BAK="$CONFIG_H.bak"
 
-MEMORY=0
-FORCE=0
-KEEP_GOING=0
-RUN_ARMCC=1
+    MEMORY=0
+    FORCE=0
+    KEEP_GOING=0
 
-# Default commands, can be overriden by the environment
-: ${OPENSSL:="openssl"}
-: ${OPENSSL_LEGACY:="$OPENSSL"}
-: ${OPENSSL_NEXT:="$OPENSSL"}
-: ${GNUTLS_CLI:="gnutls-cli"}
-: ${GNUTLS_SERV:="gnutls-serv"}
-: ${GNUTLS_LEGACY_CLI:="$GNUTLS_CLI"}
-: ${GNUTLS_LEGACY_SERV:="$GNUTLS_SERV"}
-: ${OUT_OF_SOURCE_DIR:=./mbedtls_out_of_source_build}
-: ${ARMC5_BIN_DIR:=/usr/bin}
-: ${ARMC6_BIN_DIR:=/usr/bin}
+    # Default commands, can be overridden by the environment
+    : ${OPENSSL:="openssl"}
+    : ${OPENSSL_LEGACY:="$OPENSSL"}
+    : ${OPENSSL_NEXT:="$OPENSSL"}
+    : ${GNUTLS_CLI:="gnutls-cli"}
+    : ${GNUTLS_SERV:="gnutls-serv"}
+    : ${GNUTLS_LEGACY_CLI:="$GNUTLS_CLI"}
+    : ${GNUTLS_LEGACY_SERV:="$GNUTLS_SERV"}
+    : ${OUT_OF_SOURCE_DIR:=./mbedtls_out_of_source_build}
+    : ${ARMC5_BIN_DIR:=/usr/bin}
+    : ${ARMC6_BIN_DIR:=/usr/bin}
 
-# if MAKEFLAGS is not set add the -j option to speed up invocations of make
-if [ -n "${MAKEFLAGS+set}" ]; then
-    export MAKEFLAGS="-j"
-fi
+    # if MAKEFLAGS is not set add the -j option to speed up invocations of make
+    if [ -z "${MAKEFLAGS+set}" ]; then
+        export MAKEFLAGS="-j"
+    fi
+
+    # Gather the list of available components. These are the functions
+    # defined in this script whose name starts with "component_".
+    # Parse the script with sed, because in sh there is no way to list
+    # defined functions.
+    ALL_COMPONENTS=$(sed -n 's/^ *component_\([0-9A-Z_a-z]*\) *().*/\1/p' <"$0")
+
+    # Exclude components that are not supported on this platform.
+    SUPPORTED_COMPONENTS=
+    for component in $ALL_COMPONENTS; do
+        case $(type "support_$component" 2>&1) in
+            *' function'*)
+                if ! support_$component; then continue; fi;;
+        esac
+        SUPPORTED_COMPONENTS="$SUPPORTED_COMPONENTS $component"
+    done
+}
+
+# Test whether the component $1 is included in the command line patterns.
+is_component_included()
+{
+    set -f
+    for pattern in $COMMAND_LINE_COMPONENTS; do
+        set +f
+        case ${1#component_} in $pattern) return 0;; esac
+    done
+    set +f
+    return 1
+}
 
 usage()
 {
     cat <<EOF
-Usage: $0 [OPTION]...
-  -h|--help             Print this help.
+Usage: $0 [OPTION]... [COMPONENT]...
+Run mbedtls release validation tests.
+By default, run all tests. With one or more COMPONENT, run only those.
+COMPONENT can be the name of a component or a shell wildcard pattern.
+
+Examples:
+  $0 "check_*"
+    Run all sanity checks.
+  $0 --no-armcc --except test_memsan
+    Run everything except builds that require armcc and MemSan.
+
+Special options:
+  -h|--help             Print this help and exit.
+  --list-all-components List all available test components and exit.
+  --list-components     List components supported on this platform and exit.
 
 General options:
   -f|--force            Force the tests to overwrite any modified files.
   -k|--keep-going       Run all tests and report errors at the end.
   -m|--memory           Additional optional memory tests.
      --armcc            Run ARM Compiler builds (on by default).
+     --except           Exclude the COMPONENTs listed on the command line,
+                        instead of running only those.
      --no-armcc         Skip ARM Compiler builds.
      --no-force         Refuse to overwrite modified files (default).
      --no-keep-going    Stop at the first error (default).
@@ -202,25 +270,27 @@
 
 msg()
 {
+    if [ -n "${current_component:-}" ]; then
+        current_section="${current_component#component_}: $1"
+    else
+        current_section="$1"
+    fi
     echo ""
     echo "******************************************************************"
-    echo "* $1 "
+    echo "* $current_section "
     printf "* "; date
     echo "******************************************************************"
-    current_section=$1
 }
 
-if [ $RUN_ARMCC -ne 0 ]; then
-    armc6_build_test()
-    {
-        FLAGS="$1"
+armc6_build_test()
+{
+    FLAGS="$1"
 
-        msg "build: ARM Compiler 6 ($FLAGS), make"
-        ARM_TOOL_VARIANT="ult" CC="$ARMC6_CC" AR="$ARMC6_AR" CFLAGS="$FLAGS" \
-                        WARNING_CFLAGS='-xc -std=c99' make lib
-        make clean
-    }
-fi
+    msg "build: ARM Compiler 6 ($FLAGS), make"
+    ARM_TOOL_VARIANT="ult" CC="$ARMC6_CC" AR="$ARMC6_AR" CFLAGS="$FLAGS" \
+                    WARNING_CFLAGS='-xc -std=c99' make lib
+    make clean
+}
 
 err_msg()
 {
@@ -245,61 +315,95 @@
     rm headers.txt
 }
 
-while [ $# -gt 0 ]; do
-    case "$1" in
-        --armcc) RUN_ARMCC=1;;
-        --armc5-bin-dir) shift; ARMC5_BIN_DIR="$1";;
-        --armc6-bin-dir) shift; ARMC6_BIN_DIR="$1";;
-        --force|-f) FORCE=1;;
-        --gnutls-cli) shift; GNUTLS_CLI="$1";;
-        --gnutls-legacy-cli) shift; GNUTLS_LEGACY_CLI="$1";;
-        --gnutls-legacy-serv) shift; GNUTLS_LEGACY_SERV="$1";;
-        --gnutls-serv) shift; GNUTLS_SERV="$1";;
-        --help|-h) usage; exit;;
-        --keep-going|-k) KEEP_GOING=1;;
-        --memory|-m) MEMORY=1;;
-        --no-armcc) RUN_ARMCC=0;;
-        --no-force) FORCE=0;;
-        --no-keep-going) KEEP_GOING=0;;
-        --no-memory) MEMORY=0;;
-        --openssl) shift; OPENSSL="$1";;
-        --openssl-legacy) shift; OPENSSL_LEGACY="$1";;
-        --openssl-next) shift; OPENSSL_NEXT="$1";;
-        --out-of-source-dir) shift; OUT_OF_SOURCE_DIR="$1";;
-        --random-seed) unset SEED;;
-        --release-test|-r) SEED=1;;
-        --seed|-s) shift; SEED="$1";;
-        *)
-            echo >&2 "Unknown option: $1"
-            echo >&2 "Run $0 --help for usage."
-            exit 120
-            ;;
-    esac
-    shift
-done
+pre_parse_command_line () {
+    COMMAND_LINE_COMPONENTS=
+    all_except=0
+    no_armcc=
 
-if [ $FORCE -eq 1 ]; then
-    git checkout-index -f -q $CONFIG_H
-    cleanup
-else
+    while [ $# -gt 0 ]; do
+        case "$1" in
+            --armcc) no_armcc=;;
+            --armc5-bin-dir) shift; ARMC5_BIN_DIR="$1";;
+            --armc6-bin-dir) shift; ARMC6_BIN_DIR="$1";;
+            --except) all_except=1;;
+            --force|-f) FORCE=1;;
+            --gnutls-cli) shift; GNUTLS_CLI="$1";;
+            --gnutls-legacy-cli) shift; GNUTLS_LEGACY_CLI="$1";;
+            --gnutls-legacy-serv) shift; GNUTLS_LEGACY_SERV="$1";;
+            --gnutls-serv) shift; GNUTLS_SERV="$1";;
+            --help|-h) usage; exit;;
+            --keep-going|-k) KEEP_GOING=1;;
+            --list-all-components) printf '%s\n' $ALL_COMPONENTS; exit;;
+            --list-components) printf '%s\n' $SUPPORTED_COMPONENTS; exit;;
+            --memory|-m) MEMORY=1;;
+            --no-armcc) no_armcc=1;;
+            --no-force) FORCE=0;;
+            --no-keep-going) KEEP_GOING=0;;
+            --no-memory) MEMORY=0;;
+            --openssl) shift; OPENSSL="$1";;
+            --openssl-legacy) shift; OPENSSL_LEGACY="$1";;
+            --openssl-next) shift; OPENSSL_NEXT="$1";;
+            --out-of-source-dir) shift; OUT_OF_SOURCE_DIR="$1";;
+            --random-seed) unset SEED;;
+            --release-test|-r) SEED=1;;
+            --seed|-s) shift; SEED="$1";;
+            -*)
+                echo >&2 "Unknown option: $1"
+                echo >&2 "Run $0 --help for usage."
+                exit 120
+                ;;
+            *) COMMAND_LINE_COMPONENTS="$COMMAND_LINE_COMPONENTS $1";;
+        esac
+        shift
+    done
 
-    if [ -d "$OUT_OF_SOURCE_DIR" ]; then
-        echo "Warning - there is an existing directory at '$OUT_OF_SOURCE_DIR'" >&2
-        echo "You can either delete this directory manually, or force the test by rerunning"
-        echo "the script as: $0 --force --out-of-source-dir $OUT_OF_SOURCE_DIR"
-        exit 1
+    # With no list of components, run everything.
+    if [ -z "$COMMAND_LINE_COMPONENTS" ]; then
+        all_except=1
     fi
 
-    if ! git diff-files --quiet include/mbedtls/config.h; then
-        err_msg "Warning - the configuration file 'include/mbedtls/config.h' has been edited. "
-        echo "You can either delete or preserve your work, or force the test by rerunning the"
-        echo "script as: $0 --force"
-        exit 1
+    # --no-armcc is a legacy option. The modern way is --except '*_armcc*'.
+    # Ignore it if components are listed explicitly on the command line.
+    if [ -n "$no_armcc" ] && [ $all_except -eq 1 ]; then
+        COMMAND_LINE_COMPONENTS="$COMMAND_LINE_COMPONENTS *_armcc*"
     fi
-fi
 
-build_status=0
-if [ $KEEP_GOING -eq 1 ]; then
+    # Build the list of components to run.
+    RUN_COMPONENTS=
+    for component in $SUPPORTED_COMPONENTS; do
+        if is_component_included "$component"; [ $? -eq $all_except ]; then
+            RUN_COMPONENTS="$RUN_COMPONENTS $component"
+        fi
+    done
+
+    unset all_except
+    unset no_armcc
+}
+
+pre_check_git () {
+    if [ $FORCE -eq 1 ]; then
+        rm -rf "$OUT_OF_SOURCE_DIR"
+        git checkout-index -f -q $CONFIG_H
+        cleanup
+    else
+
+        if [ -d "$OUT_OF_SOURCE_DIR" ]; then
+            echo "Warning - there is an existing directory at '$OUT_OF_SOURCE_DIR'" >&2
+            echo "You can either delete this directory manually, or force the test by rerunning"
+            echo "the script as: $0 --force --out-of-source-dir $OUT_OF_SOURCE_DIR"
+            exit 1
+        fi
+
+        if ! git diff --quiet include/mbedtls/config.h; then
+            err_msg "Warning - the configuration file 'include/mbedtls/config.h' has been edited. "
+            echo "You can either delete or preserve your work, or force the test by rerunning the"
+            echo "script as: $0 --force"
+            exit 1
+        fi
+    fi
+}
+
+pre_setup_keep_going () {
     failure_summary=
     failure_count=0
     start_red=
@@ -353,11 +457,8 @@
             echo "Killed by SIG$1."
         fi
     }
-else
-    record_status () {
-        "$@"
-    }
-fi
+}
+
 if_build_succeeded () {
     if [ $build_status -eq 0 ]; then
         record_status "$@"
@@ -370,44 +471,84 @@
     ! "$@"
 }
 
-msg "info: $0 configuration"
-echo "MEMORY: $MEMORY"
-echo "FORCE: $FORCE"
-echo "SEED: ${SEED-"UNSET"}"
-echo "OPENSSL: $OPENSSL"
-echo "OPENSSL_LEGACY: $OPENSSL_LEGACY"
-echo "OPENSSL_NEXT: $OPENSSL_NEXT"
-echo "GNUTLS_CLI: $GNUTLS_CLI"
-echo "GNUTLS_SERV: $GNUTLS_SERV"
-echo "GNUTLS_LEGACY_CLI: $GNUTLS_LEGACY_CLI"
-echo "GNUTLS_LEGACY_SERV: $GNUTLS_LEGACY_SERV"
-echo "ARMC5_BIN_DIR: $ARMC5_BIN_DIR"
-echo "ARMC6_BIN_DIR: $ARMC6_BIN_DIR"
-
-ARMC5_CC="$ARMC5_BIN_DIR/armcc"
-ARMC5_AR="$ARMC5_BIN_DIR/armar"
-ARMC6_CC="$ARMC6_BIN_DIR/armclang"
-ARMC6_AR="$ARMC6_BIN_DIR/armar"
-
-# To avoid setting OpenSSL and GnuTLS for each call to compat.sh and ssl-opt.sh
-# we just export the variables they require
-export OPENSSL_CMD="$OPENSSL"
-export GNUTLS_CLI="$GNUTLS_CLI"
-export GNUTLS_SERV="$GNUTLS_SERV"
-
-# Avoid passing --seed flag in every call to ssl-opt.sh
-if [ -n "${SEED-}" ]; then
-  export SEED
-fi
+pre_print_configuration () {
+    msg "info: $0 configuration"
+    echo "MEMORY: $MEMORY"
+    echo "FORCE: $FORCE"
+    echo "SEED: ${SEED-"UNSET"}"
+    echo "OPENSSL: $OPENSSL"
+    echo "OPENSSL_LEGACY: $OPENSSL_LEGACY"
+    echo "OPENSSL_NEXT: $OPENSSL_NEXT"
+    echo "GNUTLS_CLI: $GNUTLS_CLI"
+    echo "GNUTLS_SERV: $GNUTLS_SERV"
+    echo "GNUTLS_LEGACY_CLI: $GNUTLS_LEGACY_CLI"
+    echo "GNUTLS_LEGACY_SERV: $GNUTLS_LEGACY_SERV"
+    echo "ARMC5_BIN_DIR: $ARMC5_BIN_DIR"
+    echo "ARMC6_BIN_DIR: $ARMC6_BIN_DIR"
+}
 
 # Make sure the tools we need are available.
-check_tools "$OPENSSL" "$OPENSSL_LEGACY" "$OPENSSL_NEXT" \
-            "$GNUTLS_CLI" "$GNUTLS_SERV" \
-            "$GNUTLS_LEGACY_CLI" "$GNUTLS_LEGACY_SERV" "doxygen" "dot" \
-            "arm-none-eabi-gcc" "i686-w64-mingw32-gcc" "gdb"
-if [ $RUN_ARMCC -ne 0 ]; then
-    check_tools "$ARMC5_CC" "$ARMC5_AR" "$ARMC6_CC" "$ARMC6_AR"
-fi
+pre_check_tools () {
+    # Build the list of variables to pass to output_env.sh.
+    set env
+
+    case " $RUN_COMPONENTS " in
+        # Require OpenSSL and GnuTLS if running any tests (as opposed to
+        # only doing builds). Not all tests run OpenSSL and GnuTLS, but this
+        # is a good enough approximation in practice.
+        *" test_"*)
+            # To avoid setting OpenSSL and GnuTLS for each call to compat.sh
+            # and ssl-opt.sh, we just export the variables they require.
+            export OPENSSL_CMD="$OPENSSL"
+            export GNUTLS_CLI="$GNUTLS_CLI"
+            export GNUTLS_SERV="$GNUTLS_SERV"
+            # Avoid passing --seed flag in every call to ssl-opt.sh
+            if [ -n "${SEED-}" ]; then
+                export SEED
+            fi
+            set "$@" OPENSSL="$OPENSSL" OPENSSL_LEGACY="$OPENSSL_LEGACY"
+            set "$@" GNUTLS_CLI="$GNUTLS_CLI" GNUTLS_SERV="$GNUTLS_SERV"
+            set "$@" GNUTLS_LEGACY_CLI="$GNUTLS_LEGACY_CLI"
+            set "$@" GNUTLS_LEGACY_SERV="$GNUTLS_LEGACY_SERV"
+            check_tools "$OPENSSL" "$OPENSSL_LEGACY" "$OPENSSL_NEXT" \
+                        "$GNUTLS_CLI" "$GNUTLS_SERV" \
+                        "$GNUTLS_LEGACY_CLI" "$GNUTLS_LEGACY_SERV"
+            ;;
+    esac
+
+    case " $RUN_COMPONENTS " in
+        *_doxygen[_\ ]*) check_tools "doxygen" "dot";;
+    esac
+
+    case " $RUN_COMPONENTS " in
+        *_arm_none_eabi_gcc[_\ ]*) check_tools "arm-none-eabi-gcc";;
+    esac
+
+    case " $RUN_COMPONENTS " in
+        *_mingw[_\ ]*) check_tools "i686-w64-mingw32-gcc";;
+    esac
+
+    case " $RUN_COMPONENTS " in
+        *" test_zeroize "*) check_tools "gdb";;
+    esac
+
+    case " $RUN_COMPONENTS " in
+        *_armcc*)
+            ARMC5_CC="$ARMC5_BIN_DIR/armcc"
+            ARMC5_AR="$ARMC5_BIN_DIR/armar"
+            ARMC6_CC="$ARMC6_BIN_DIR/armclang"
+            ARMC6_AR="$ARMC6_BIN_DIR/armar"
+            check_tools "$ARMC5_CC" "$ARMC5_AR" "$ARMC6_CC" "$ARMC6_AR";;
+    esac
+
+    msg "info: output_env.sh"
+    case $RUN_COMPONENTS in
+        *_armcc*)
+            set "$@" ARMC5_CC="$ARMC5_CC" ARMC6_CC="$ARMC6_CC" RUN_ARMCC=1;;
+        *) set "$@" RUN_ARMCC=0;;
+    esac
+    "$@" scripts/output_env.sh
+}
 
 
 
@@ -426,32 +567,35 @@
 #
 # Indicative running times are given for reference.
 
-msg "info: output_env.sh"
-OPENSSL="$OPENSSL" OPENSSL_LEGACY="$OPENSSL_LEGACY" GNUTLS_CLI="$GNUTLS_CLI" \
-    GNUTLS_SERV="$GNUTLS_SERV" GNUTLS_LEGACY_CLI="$GNUTLS_LEGACY_CLI" \
-    GNUTLS_LEGACY_SERV="$GNUTLS_LEGACY_SERV" ARMC5_CC="$ARMC5_CC" \
-    ARMC6_CC="$ARMC6_CC" RUN_ARMCC="$RUN_ARMCC" scripts/output_env.sh
+component_check_recursion () {
+    msg "test: recursion.pl" # < 1s
+    record_status tests/scripts/recursion.pl library/*.c
+}
 
-msg "test: recursion.pl" # < 1s
-record_status tests/scripts/recursion.pl library/*.c
+component_check_generated_files () {
+    msg "test: freshness of generated source files" # < 1s
+    record_status tests/scripts/check-generated-files.sh
+}
 
-msg "test: freshness of generated source files" # < 1s
-record_status tests/scripts/check-generated-files.sh
+component_check_doxy_blocks () {
+    msg "test: doxygen markup outside doxygen blocks" # < 1s
+    record_status tests/scripts/check-doxy-blocks.pl
+}
 
-msg "test: doxygen markup outside doxygen blocks" # < 1s
-record_status tests/scripts/check-doxy-blocks.pl
+component_check_files () {
+    msg "test: check-files.py" # < 1s
+    record_status tests/scripts/check-files.py
+}
 
-msg "test: check-files.py" # < 1s
-cleanup
-record_status tests/scripts/check-files.py
+component_check_names () {
+    msg "test/build: declared and exported names" # < 3s
+    record_status tests/scripts/check-names.sh
+}
 
-msg "test/build: declared and exported names" # < 3s
-cleanup
-record_status tests/scripts/check-names.sh
-
-msg "test: doxygen warnings" # ~ 3s
-cleanup
-record_status tests/scripts/doxygen.sh
+component_check_doxygen_warnings () {
+    msg "test: doxygen warnings" # ~ 3s
+    record_status tests/scripts/doxygen.sh
+}
 
 
 
@@ -459,589 +603,601 @@
 #### Build and test many configurations and targets
 ################################################################
 
-msg "build: cmake, gcc, ASan" # ~ 1 min 50s
-cleanup
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+component_test_default_cmake_gcc_asan () {
+    msg "build: cmake, gcc, ASan" # ~ 1 min 50s
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "test: main suites (inc. selftests) (ASan build)" # ~ 50s
-make test
+    msg "test: main suites (inc. selftests) (ASan build)" # ~ 50s
+    make test
 
-msg "test: ssl-opt.sh (ASan build)" # ~ 1 min
-if_build_succeeded tests/ssl-opt.sh
+    msg "test: ssl-opt.sh (ASan build)" # ~ 1 min
+    if_build_succeeded tests/ssl-opt.sh
 
-msg "test/build: ref-configs (ASan build)" # ~ 6 min 20s
-record_status tests/scripts/test-ref-configs.pl
+    msg "test: compat.sh (ASan build)" # ~ 6 min
+    if_build_succeeded tests/compat.sh
+}
 
-msg "build: with ASan (rebuild after ref-configs)" # ~ 1 min
-make
+component_test_ref_configs () {
+    msg "test/build: ref-configs (ASan build)" # ~ 6 min 20s
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    record_status tests/scripts/test-ref-configs.pl
+}
 
-msg "test: compat.sh (ASan build)" # ~ 6 min
-if_build_succeeded tests/compat.sh
+component_test_sslv3 () {
+    msg "build: Default + SSLv3 (ASan build)" # ~ 6 min
+    scripts/config.pl set MBEDTLS_SSL_PROTO_SSL3
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "build: Default + SSLv3 (ASan build)" # ~ 6 min
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_SSL_PROTO_SSL3
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+    msg "test: SSLv3 - main suites (inc. selftests) (ASan build)" # ~ 50s
+    make test
 
-msg "test: SSLv3 - main suites (inc. selftests) (ASan build)" # ~ 50s
-make test
+    msg "build: SSLv3 - compat.sh (ASan build)" # ~ 6 min
+    if_build_succeeded tests/compat.sh -m 'tls1 tls1_1 tls1_2 dtls1 dtls1_2'
+    if_build_succeeded env OPENSSL_CMD="$OPENSSL_LEGACY" tests/compat.sh -m 'ssl3'
 
-msg "build: SSLv3 - compat.sh (ASan build)" # ~ 6 min
-if_build_succeeded tests/compat.sh -m 'tls1 tls1_1 tls1_2 dtls1 dtls1_2'
-if_build_succeeded env OPENSSL_CMD="$OPENSSL_LEGACY" tests/compat.sh -m 'ssl3'
+    msg "build: SSLv3 - ssl-opt.sh (ASan build)" # ~ 6 min
+    if_build_succeeded tests/ssl-opt.sh
+}
 
-msg "build: SSLv3 - ssl-opt.sh (ASan build)" # ~ 6 min
-if_build_succeeded tests/ssl-opt.sh
+component_test_no_renegotiation () {
+    msg "build: Default + !MBEDTLS_SSL_RENEGOTIATION (ASan build)" # ~ 6 min
+    scripts/config.pl unset MBEDTLS_SSL_RENEGOTIATION
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "build: Default + !MBEDTLS_SSL_RENEGOTIATION (ASan build)" # ~ 6 min
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl unset MBEDTLS_SSL_RENEGOTIATION
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+    msg "test: !MBEDTLS_SSL_RENEGOTIATION - main suites (inc. selftests) (ASan build)" # ~ 50s
+    make test
 
-msg "test: !MBEDTLS_SSL_RENEGOTIATION - main suites (inc. selftests) (ASan build)" # ~ 50s
-make test
+    msg "test: !MBEDTLS_SSL_RENEGOTIATION - ssl-opt.sh (ASan build)" # ~ 6 min
+    if_build_succeeded tests/ssl-opt.sh
+}
 
-msg "test: !MBEDTLS_SSL_RENEGOTIATION - ssl-opt.sh (ASan build)" # ~ 6 min
-if_build_succeeded tests/ssl-opt.sh
+component_test_rsa_no_crt () {
+    msg "build: Default + RSA_NO_CRT (ASan build)" # ~ 6 min
+    scripts/config.pl set MBEDTLS_RSA_NO_CRT
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "build: Default + RSA_NO_CRT (ASan build)" # ~ 6 min
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_RSA_NO_CRT
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+    msg "test: RSA_NO_CRT - main suites (inc. selftests) (ASan build)" # ~ 50s
+    make test
 
-msg "test: RSA_NO_CRT - main suites (inc. selftests) (ASan build)" # ~ 50s
-make test
+    msg "test: RSA_NO_CRT - RSA-related part of ssl-opt.sh (ASan build)" # ~ 5s
+    if_build_succeeded tests/ssl-opt.sh -f RSA
 
-msg "test: RSA_NO_CRT - RSA-related part of ssl-opt.sh (ASan build)" # ~ 5s
-if_build_succeeded tests/ssl-opt.sh -f RSA
+    msg "test: RSA_NO_CRT - RSA-related part of compat.sh (ASan build)" # ~ 3 min
+    if_build_succeeded tests/compat.sh -t RSA
+}
 
-msg "test: RSA_NO_CRT - RSA-related part of compat.sh (ASan build)" # ~ 3 min
-if_build_succeeded tests/compat.sh -t RSA
+component_test_small_ssl_out_content_len () {
+    msg "build: small SSL_OUT_CONTENT_LEN (ASan build)"
+    scripts/config.pl set MBEDTLS_SSL_IN_CONTENT_LEN 16384
+    scripts/config.pl set MBEDTLS_SSL_OUT_CONTENT_LEN 4096
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "build: small SSL_OUT_CONTENT_LEN (ASan build)"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_SSL_IN_CONTENT_LEN 16384
-scripts/config.pl set MBEDTLS_SSL_OUT_CONTENT_LEN 4096
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+    msg "test: small SSL_OUT_CONTENT_LEN - ssl-opt.sh MFL and large packet tests"
+    if_build_succeeded tests/ssl-opt.sh -f "Max fragment\|Large packet"
+}
 
-msg "test: small SSL_OUT_CONTENT_LEN - ssl-opt.sh MFL and large packet tests"
-if_build_succeeded tests/ssl-opt.sh -f "Max fragment\|Large packet"
+component_test_small_ssl_in_content_len () {
+    msg "build: small SSL_IN_CONTENT_LEN (ASan build)"
+    scripts/config.pl set MBEDTLS_SSL_IN_CONTENT_LEN 4096
+    scripts/config.pl set MBEDTLS_SSL_OUT_CONTENT_LEN 16384
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "build: small SSL_IN_CONTENT_LEN (ASan build)"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_SSL_IN_CONTENT_LEN 4096
-scripts/config.pl set MBEDTLS_SSL_OUT_CONTENT_LEN 16384
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+    msg "test: small SSL_IN_CONTENT_LEN - ssl-opt.sh MFL tests"
+    if_build_succeeded tests/ssl-opt.sh -f "Max fragment"
+}
 
-msg "test: small SSL_IN_CONTENT_LEN - ssl-opt.sh MFL tests"
-if_build_succeeded tests/ssl-opt.sh -f "Max fragment"
+component_test_small_ssl_dtls_max_buffering () {
+    msg "build: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #0"
+    scripts/config.pl set MBEDTLS_SSL_DTLS_MAX_BUFFERING 1000
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "build: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #0"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_SSL_DTLS_MAX_BUFFERING 1000
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+    msg "test: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #0 - ssl-opt.sh specific reordering test"
+    if_build_succeeded tests/ssl-opt.sh -f "DTLS reordering: Buffer out-of-order hs msg before reassembling next, free buffered msg"
+}
 
-msg "test: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #0 - ssl-opt.sh specific reordering test"
-if_build_succeeded tests/ssl-opt.sh -f "DTLS reordering: Buffer out-of-order hs msg before reassembling next, free buffered msg"
+component_test_small_mbedtls_ssl_dtls_max_buffering () {
+    msg "build: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #1"
+    scripts/config.pl set MBEDTLS_SSL_DTLS_MAX_BUFFERING 240
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "build: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #1"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_SSL_DTLS_MAX_BUFFERING 240
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+    msg "test: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #1 - ssl-opt.sh specific reordering test"
+    if_build_succeeded tests/ssl-opt.sh -f "DTLS reordering: Buffer encrypted Finished message, drop for fragmented NewSessionTicket"
+}
 
-msg "test: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #1 - ssl-opt.sh specific reordering test"
-if_build_succeeded tests/ssl-opt.sh -f "DTLS reordering: Buffer encrypted Finished message, drop for fragmented NewSessionTicket"
+component_test_full_cmake_clang () {
+    msg "build: cmake, full config, clang" # ~ 50s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
+    CC=clang cmake -D CMAKE_BUILD_TYPE:String=Check -D ENABLE_TESTING=On .
+    make
 
-msg "build: cmake, full config, clang" # ~ 50s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
-CC=clang cmake -D CMAKE_BUILD_TYPE:String=Check -D ENABLE_TESTING=On .
-make
+    msg "test: main suites (full config)" # ~ 5s
+    make test
 
-msg "test: main suites (full config)" # ~ 5s
-make test
+    msg "test: ssl-opt.sh default, ECJPAKE, SSL async (full config)" # ~ 1s
+    if_build_succeeded tests/ssl-opt.sh -f 'Default\|ECJPAKE\|SSL async private'
 
-msg "test: ssl-opt.sh default, ECJPAKE, SSL async (full config)" # ~ 1s
-if_build_succeeded tests/ssl-opt.sh -f 'Default\|ECJPAKE\|SSL async private'
+    msg "test: compat.sh RC4, DES & NULL (full config)" # ~ 2 min
+    if_build_succeeded env OPENSSL_CMD="$OPENSSL_LEGACY" GNUTLS_CLI="$GNUTLS_LEGACY_CLI" GNUTLS_SERV="$GNUTLS_LEGACY_SERV" tests/compat.sh -e '3DES\|DES-CBC3' -f 'NULL\|DES\|RC4\|ARCFOUR'
 
-msg "test: compat.sh RC4, DES & NULL (full config)" # ~ 2 min
-if_build_succeeded env OPENSSL_CMD="$OPENSSL_LEGACY" GNUTLS_CLI="$GNUTLS_LEGACY_CLI" GNUTLS_SERV="$GNUTLS_LEGACY_SERV" tests/compat.sh -e '3DES\|DES-CBC3' -f 'NULL\|DES\|RC4\|ARCFOUR'
+    msg "test: compat.sh ARIA + ChachaPoly"
+    if_build_succeeded env OPENSSL_CMD="$OPENSSL_NEXT" tests/compat.sh -e '^$' -f 'ARIA\|CHACHA'
+}
 
-msg "test: compat.sh ARIA + ChachaPoly"
-if_build_succeeded env OPENSSL_CMD="$OPENSSL_NEXT" tests/compat.sh -e '^$' -f 'ARIA\|CHACHA'
+component_build_deprecated () {
+    msg "build: make, full config + DEPRECATED_WARNING, gcc -O" # ~ 30s
+    scripts/config.pl full
+    scripts/config.pl set MBEDTLS_DEPRECATED_WARNING
+    # Build with -O -Wextra to catch a maximum of issues.
+    make CC=gcc CFLAGS='-O -Werror -Wall -Wextra' lib programs
+    make CC=gcc CFLAGS='-O -Werror -Wall -Wextra -Wno-unused-function' tests
 
-# USE_CRYPTO_SUBMODULE: check that the build works with CMake
-msg "build: cmake, full config + USE_CRYPTO_SUBMODULE, gcc+debug"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full # enables md4 and submodule doesn't enable md4
-scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
-CC=gcc cmake -D USE_CRYPTO_SUBMODULE=1 -D CMAKE_BUILD_TYPE=Debug .
-make
-msg "test: top-level libmbedcrypto wasn't built (USE_CRYPTO_SUBMODULE, cmake)"
-if_build_succeeded not test -f library/libmbedcrypto.a
-msg "test: libmbedcrypto symbols are from crypto files (USE_CRYPTO_SUBMODULE, cmake)"
-if_build_succeeded objdump -g crypto/library/libmbedcrypto.a | grep -E 'crypto/library$' > /dev/null
-msg "test: libmbedcrypto uses top-level config (USE_CRYPTO_SUBMODULE, cmake)"
-if_build_succeeded objdump -g crypto/library/libmbedcrypto.a | grep 'md4.c' > /dev/null
-msg "test: main suites (USE_CRYPTO_SUBMODULE, cmake)"
-make test
-msg "test: ssl-opt.sh (USE_CRYPTO_SUBMODULE, cmake)"
-if_build_succeeded tests/ssl-opt.sh
+    msg "build: make, full config + DEPRECATED_REMOVED, clang -O" # ~ 30s
+    # No cleanup, just tweak the configuration and rebuild
+    make clean
+    scripts/config.pl unset MBEDTLS_DEPRECATED_WARNING
+    scripts/config.pl set MBEDTLS_DEPRECATED_REMOVED
+    # Build with -O -Wextra to catch a maximum of issues.
+    make CC=clang CFLAGS='-O -Werror -Wall -Wextra' lib programs
+    make CC=clang CFLAGS='-O -Werror -Wall -Wextra -Wno-unused-function' tests
+}
 
-# USE_CRYPTO_SUBMODULE: check that the build works with make
-msg "build: make, full config + USE_CRYPTO_SUBMODULE, gcc+debug"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full # enables md4 and submodule doesn't enable md4
-scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
-make CC=gcc CFLAGS='-g' USE_CRYPTO_SUBMODULE=1
-msg "test: top-level libmbedcrypto wasn't built (USE_CRYPTO_SUBMODULE, make)"
-if_build_succeeded not test -f library/libmbedcrypto.a
-msg "test: libmbedcrypto symbols are from crypto files (USE_CRYPTO_SUBMODULE, make)"
-if_build_succeeded objdump -g crypto/library/libmbedcrypto.a | grep -E 'crypto/library$' > /dev/null
-msg "test: libmbedcrypto uses top-level config (USE_CRYPTO_SUBMODULE, make)"
-if_build_succeeded objdump -g crypto/library/libmbedcrypto.a | grep 'md4.c' > /dev/null
-msg "test: main suites (USE_CRYPTO_SUBMODULE, make)"
-make CC=gcc USE_CRYPTO_SUBMODULE=1 test
-msg "test: ssl-opt.sh (USE_CRYPTO_SUBMODULE, make)"
-if_build_succeeded tests/ssl-opt.sh
 
-# Don't USE_CRYPTO_SUBMODULE: check that the submodule is not used with make
-msg "build: make, full config - USE_CRYPTO_SUBMODULE, gcc+debug"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-make CC=gcc CFLAGS='-g'
-msg "test: submodule libmbedcrypto wasn't built (USE_CRYPTO_SUBMODULE, make)"
-if_build_succeeded not test -f crypto/library/libmbedcrypto.a
-msg "test: libmbedcrypto symbols are from library files (USE_CRYPTO_SUBMODULE, make)"
-if_build_succeeded objdump -g library/libmbedcrypto.a | grep -E 'library$' | not grep 'crypto' > /dev/null
+component_test_depends_curves () {
+    msg "test/build: curves.pl (gcc)" # ~ 4 min
+    record_status tests/scripts/curves.pl
+}
 
-# Don't USE_CRYPTO_SUBMODULE: check that the submodule is not used with CMake
-msg "build: cmake, full config - USE_CRYPTO_SUBMODULE, gcc+debug"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-CC=gcc cmake -D CMAKE_BUILD_TYPE=Debug .
-make
-msg "test: submodule libmbedcrypto wasn't built (USE_CRYPTO_SUBMODULE, cmake)"
-if_build_succeeded not test -f crypto/library/libmbedcrypto.a
-msg "test: libmbedcrypto symbols are from library files (USE_CRYPTO_SUBMODULE, cmake)"
-if_build_succeeded objdump -g library/libmbedcrypto.a | grep -E 'library$' | not grep 'crypto' > /dev/null
+component_test_depends_hashes () {
+    msg "test/build: depends-hashes.pl (gcc)" # ~ 2 min
+    record_status tests/scripts/depends-hashes.pl
+}
 
-# MBEDTLS_USE_PSA_CRYPTO: run the same set of tests as basic-build-test.sh
-msg "build: cmake, full config + MBEDTLS_USE_PSA_CRYPTO, ASan"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
-scripts/config.pl set MBEDTLS_PSA_CRYPTO_C
-scripts/config.pl set MBEDTLS_USE_PSA_CRYPTO
-CC=gcc cmake -D USE_CRYPTO_SUBMODULE=1 -D CMAKE_BUILD_TYPE:String=Asan .
-make
+component_test_depends_pkalgs () {
+    msg "test/build: depends-pkalgs.pl (gcc)" # ~ 2 min
+    record_status tests/scripts/depends-pkalgs.pl
+}
 
-msg "test: main suites (MBEDTLS_USE_PSA_CRYPTO)"
-make test
+component_build_key_exchanges () {
+    msg "test/build: key-exchanges (gcc)" # ~ 1 min
+    record_status tests/scripts/key-exchanges.pl
+}
 
-msg "test: ssl-opt.sh (MBEDTLS_USE_PSA_CRYPTO)"
-if_build_succeeded tests/ssl-opt.sh
+component_build_default_make_gcc_and_cxx () {
+    msg "build: Unix make, -Os (gcc)" # ~ 30s
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -Os'
 
-msg "test: compat.sh default (MBEDTLS_USE_PSA_CRYPTO)"
-if_build_succeeded tests/compat.sh
+    msg "test: verify header list in cpp_dummy_build.cpp"
+    record_status check_headers_in_cpp
 
-msg "test: compat.sh ssl3 (MBEDTLS_USE_PSA_CRYPTO)"
-if_build_succeeded env OPENSSL_CMD="$OPENSSL_LEGACY" tests/compat.sh -m 'ssl3'
+    msg "build: Unix make, incremental g++"
+    make TEST_CPP=1
+}
 
-msg "test: compat.sh RC4, DES & NULL (MBEDTLS_USE_PSA_CRYPTO)"
-if_build_succeeded env OPENSSL_CMD="$OPENSSL_LEGACY" GNUTLS_CLI="$GNUTLS_LEGACY_CLI" GNUTLS_SERV="$GNUTLS_LEGACY_SERV" tests/compat.sh -e '3DES\|DES-CBC3' -f 'NULL\|DES\|RC4\|ARCFOUR'
+component_test_submodule_cmake () {
+    # USE_CRYPTO_SUBMODULE: check that the build works with CMake
+    msg "build: cmake, full config + USE_CRYPTO_SUBMODULE, gcc+debug"
+    scripts/config.pl full # enables md4 and submodule doesn't enable md4
+    scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
+    CC=gcc cmake -D USE_CRYPTO_SUBMODULE=1 -D CMAKE_BUILD_TYPE=Debug .
+    make
+    msg "test: top-level libmbedcrypto wasn't built (USE_CRYPTO_SUBMODULE, cmake)"
+    if_build_succeeded not test -f library/libmbedcrypto.a
+    msg "test: libmbedcrypto symbols are from crypto files (USE_CRYPTO_SUBMODULE, cmake)"
+    if_build_succeeded objdump -g crypto/library/libmbedcrypto.a | grep -E 'crypto/library$' > /dev/null
+    msg "test: libmbedcrypto uses top-level config (USE_CRYPTO_SUBMODULE, cmake)"
+    if_build_succeeded objdump -g crypto/library/libmbedcrypto.a | grep 'md4.c' > /dev/null
+    msg "test: main suites (USE_CRYPTO_SUBMODULE, cmake)"
+    make test
+    msg "test: ssl-opt.sh (USE_CRYPTO_SUBMODULE, cmake)"
+    if_build_succeeded tests/ssl-opt.sh
+}
 
-msg "test: compat.sh ARIA + ChachaPoly (MBEDTLS_USE_PSA_CRYPTO)"
-if_build_succeeded env OPENSSL_CMD="$OPENSSL_NEXT" tests/compat.sh -e '^$' -f 'ARIA\|CHACHA'
+component_test_submodule_make () {
+    # USE_CRYPTO_SUBMODULE: check that the build works with make
+    msg "build: make, full config + USE_CRYPTO_SUBMODULE, gcc+debug"
+    scripts/config.pl full # enables md4 and submodule doesn't enable md4
+    scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
+    make CC=gcc CFLAGS='-g' USE_CRYPTO_SUBMODULE=1
+    msg "test: top-level libmbedcrypto wasn't built (USE_CRYPTO_SUBMODULE, make)"
+    if_build_succeeded not test -f library/libmbedcrypto.a
+    msg "test: libmbedcrypto symbols are from crypto files (USE_CRYPTO_SUBMODULE, make)"
+    if_build_succeeded objdump -g crypto/library/libmbedcrypto.a | grep -E 'crypto/library$' > /dev/null
+    msg "test: libmbedcrypto uses top-level config (USE_CRYPTO_SUBMODULE, make)"
+    if_build_succeeded objdump -g crypto/library/libmbedcrypto.a | grep 'md4.c' > /dev/null
+    msg "test: main suites (USE_CRYPTO_SUBMODULE, make)"
+    make CC=gcc USE_CRYPTO_SUBMODULE=1 test
+    msg "test: ssl-opt.sh (USE_CRYPTO_SUBMODULE, make)"
+    if_build_succeeded tests/ssl-opt.sh
+}
 
-msg "build: make, full config + DEPRECATED_WARNING, gcc -O" # ~ 30s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl set MBEDTLS_DEPRECATED_WARNING
-# Build with -O -Wextra to catch a maximum of issues.
-make CC=gcc CFLAGS='-O -Werror -Wall -Wextra' lib programs
-make CC=gcc CFLAGS='-O -Werror -Wall -Wextra -Wno-unused-function' tests
-
-msg "build: make, full config + DEPRECATED_REMOVED, clang -O" # ~ 30s
-# No cleanup, just tweak the configuration and rebuild
-make clean
-scripts/config.pl unset MBEDTLS_DEPRECATED_WARNING
-scripts/config.pl set MBEDTLS_DEPRECATED_REMOVED
-# Build with -O -Wextra to catch a maximum of issues.
-make CC=clang CFLAGS='-O -Werror -Wall -Wextra' lib programs
-make CC=clang CFLAGS='-O -Werror -Wall -Wextra -Wno-unused-function' tests
-
-msg "test/build: curves.pl (gcc)" # ~ 4 min
-cleanup
-record_status tests/scripts/curves.pl
+component_test_no_submodule_make () {
+    # Don't USE_CRYPTO_SUBMODULE: check that the submodule is not used with make
+    msg "build: make, full config - USE_CRYPTO_SUBMODULE, gcc+debug"
+    scripts/config.pl full
+    make CC=gcc CFLAGS='-g'
+    msg "test: submodule libmbedcrypto wasn't built (USE_CRYPTO_SUBMODULE, make)"
+    if_build_succeeded not test -f crypto/library/libmbedcrypto.a
+    msg "test: libmbedcrypto symbols are from library files (USE_CRYPTO_SUBMODULE, make)"
+    if_build_succeeded objdump -g library/libmbedcrypto.a | grep -E 'library$' | not grep 'crypto' > /dev/null
+}
 
-msg "test/build: depends-hashes.pl (gcc)" # ~ 2 min
-cleanup
-record_status tests/scripts/depends-hashes.pl
+component_test_no_submodule_cmake () {
+    # Don't USE_CRYPTO_SUBMODULE: check that the submodule is not used with CMake
+    msg "build: cmake, full config - USE_CRYPTO_SUBMODULE, gcc+debug"
+    scripts/config.pl full
+    CC=gcc cmake -D CMAKE_BUILD_TYPE=Debug .
+    make
+    msg "test: submodule libmbedcrypto wasn't built (USE_CRYPTO_SUBMODULE, cmake)"
+    if_build_succeeded not test -f crypto/library/libmbedcrypto.a
+    msg "test: libmbedcrypto symbols are from library files (USE_CRYPTO_SUBMODULE, cmake)"
+    if_build_succeeded objdump -g library/libmbedcrypto.a | grep -E 'library$' | not grep 'crypto' > /dev/null
+}
 
-msg "test/build: depends-pkalgs.pl (gcc)" # ~ 2 min
-cleanup
-record_status tests/scripts/depends-pkalgs.pl
+component_test_submodule_full_cmake_asan() {
+    # MBEDTLS_USE_PSA_CRYPTO: run the same set of tests as basic-build-test.sh
+    msg "build: cmake, full config + MBEDTLS_USE_PSA_CRYPTO, ASan"
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
+    scripts/config.pl set MBEDTLS_PSA_CRYPTO_C
+    scripts/config.pl set MBEDTLS_USE_PSA_CRYPTO
+    CC=gcc cmake -D USE_CRYPTO_SUBMODULE=1 -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "test/build: key-exchanges (gcc)" # ~ 1 min
-cleanup
-record_status tests/scripts/key-exchanges.pl
+    msg "test: main suites (MBEDTLS_USE_PSA_CRYPTO)"
+    make test
 
-msg "build: Unix make, -Os (gcc)" # ~ 30s
-cleanup
-make CC=gcc CFLAGS='-Werror -Wall -Wextra -Os'
+    msg "test: ssl-opt.sh (MBEDTLS_USE_PSA_CRYPTO)"
+    if_build_succeeded tests/ssl-opt.sh
 
-msg "test: verify header list in cpp_dummy_build.cpp"
-record_status check_headers_in_cpp
+    msg "test: compat.sh default (MBEDTLS_USE_PSA_CRYPTO)"
+    if_build_succeeded tests/compat.sh
 
-msg "build: Unix make, incremental g++"
-make TEST_CPP=1
+    msg "test: compat.sh ssl3 (MBEDTLS_USE_PSA_CRYPTO)"
+    if_build_succeeded env OPENSSL_CMD="$OPENSSL_LEGACY" tests/compat.sh -m 'ssl3'
 
+    msg "test: compat.sh RC4, DES & NULL (MBEDTLS_USE_PSA_CRYPTO)"
+    if_build_succeeded env OPENSSL_CMD="$OPENSSL_LEGACY" GNUTLS_CLI="$GNUTLS_LEGACY_CLI" GNUTLS_SERV="$GNUTLS_LEGACY_SERV" tests/compat.sh -e '3DES\|DES-CBC3' -f 'NULL\|DES\|RC4\|ARCFOUR'
 
-msg "build+test: MBEDTLS_CHECK_PARAMS without MBEDTLS_PLATFORM_C"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full # includes CHECK_PARAMS
-scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
-scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C
-scripts/config.pl unset MBEDTLS_PLATFORM_EXIT_ALT
-scripts/config.pl unset MBEDTLS_PLATFORM_TIME_ALT
-scripts/config.pl unset MBEDTLS_PLATFORM_FPRINTF_ALT
-scripts/config.pl unset MBEDTLS_PLATFORM_MEMORY
-scripts/config.pl unset MBEDTLS_PLATFORM_PRINTF_ALT
-scripts/config.pl unset MBEDTLS_PLATFORM_SNPRINTF_ALT
-scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
-scripts/config.pl unset MBEDTLS_PLATFORM_C
-make CC=gcc CFLAGS='-Werror -O1' all test
+    msg "test: compat.sh ARIA + ChachaPoly (MBEDTLS_USE_PSA_CRYPTO)"
+    if_build_succeeded env OPENSSL_CMD="$OPENSSL_NEXT" tests/compat.sh -e '^$' -f 'ARIA\|CHACHA'
+}
 
-msg "build+test: MBEDTLS_CHECK_PARAMS with alternative MBEDTLS_PARAM_FAILED()"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full # includes CHECK_PARAMS
-scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
-sed -i 's/.*\(#define MBEDTLS_PARAM_FAILED( cond )\).*/\1/' "$CONFIG_H"
-make CC=gcc CFLAGS='-Werror -O1' all test
+component_test_check_params_without_platform () {
+    msg "build+test: MBEDTLS_CHECK_PARAMS without MBEDTLS_PLATFORM_C"
+    scripts/config.pl full # includes CHECK_PARAMS
+    scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
+    scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C
+    scripts/config.pl unset MBEDTLS_PLATFORM_EXIT_ALT
+    scripts/config.pl unset MBEDTLS_PLATFORM_TIME_ALT
+    scripts/config.pl unset MBEDTLS_PLATFORM_FPRINTF_ALT
+    scripts/config.pl unset MBEDTLS_PLATFORM_MEMORY
+    scripts/config.pl unset MBEDTLS_PLATFORM_PRINTF_ALT
+    scripts/config.pl unset MBEDTLS_PLATFORM_SNPRINTF_ALT
+    scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
+    scripts/config.pl unset MBEDTLS_PLATFORM_C
+    make CC=gcc CFLAGS='-Werror -O1' all test
+}
 
+component_test_check_params_silent () {
+    msg "build+test: MBEDTLS_CHECK_PARAMS with alternative MBEDTLS_PARAM_FAILED()"
+    scripts/config.pl full # includes CHECK_PARAMS
+    scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
+    sed -i 's/.*\(#define MBEDTLS_PARAM_FAILED( cond )\).*/\1/' "$CONFIG_H"
+    make CC=gcc CFLAGS='-Werror -O1' all test
+}
 
-# Full configuration build, without platform support, file IO and net sockets.
-# This should catch missing mbedtls_printf definitions, and by disabling file
-# IO, it should catch missing '#include <stdio.h>'
-msg "build: full config except platform/fsio/net, make, gcc, C99" # ~ 30s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_PLATFORM_C
-scripts/config.pl unset MBEDTLS_NET_C
-scripts/config.pl unset MBEDTLS_PLATFORM_MEMORY
-scripts/config.pl unset MBEDTLS_PLATFORM_PRINTF_ALT
-scripts/config.pl unset MBEDTLS_PLATFORM_FPRINTF_ALT
-scripts/config.pl unset MBEDTLS_PLATFORM_SNPRINTF_ALT
-scripts/config.pl unset MBEDTLS_PLATFORM_TIME_ALT
-scripts/config.pl unset MBEDTLS_PLATFORM_EXIT_ALT
-scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
-scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C
-scripts/config.pl unset MBEDTLS_FS_IO
-# Note, _DEFAULT_SOURCE needs to be defined for platforms using glibc version >2.19,
-# to re-enable platform integration features otherwise disabled in C99 builds
-make CC=gcc CFLAGS='-Werror -Wall -Wextra -std=c99 -pedantic -O0 -D_DEFAULT_SOURCE' lib programs
-make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0' test
+component_test_no_platform () {
+    # Full configuration build, without platform support, file IO and net sockets.
+    # This should catch missing mbedtls_printf definitions, and by disabling file
+    # IO, it should catch missing '#include <stdio.h>'
+    msg "build: full config except platform/fsio/net, make, gcc, C99" # ~ 30s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_PLATFORM_C
+    scripts/config.pl unset MBEDTLS_NET_C
+    scripts/config.pl unset MBEDTLS_PLATFORM_MEMORY
+    scripts/config.pl unset MBEDTLS_PLATFORM_PRINTF_ALT
+    scripts/config.pl unset MBEDTLS_PLATFORM_FPRINTF_ALT
+    scripts/config.pl unset MBEDTLS_PLATFORM_SNPRINTF_ALT
+    scripts/config.pl unset MBEDTLS_PLATFORM_TIME_ALT
+    scripts/config.pl unset MBEDTLS_PLATFORM_EXIT_ALT
+    scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
+    scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C
+    scripts/config.pl unset MBEDTLS_FS_IO
+    # Note, _DEFAULT_SOURCE needs to be defined for platforms using glibc version >2.19,
+    # to re-enable platform integration features otherwise disabled in C99 builds
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -std=c99 -pedantic -O0 -D_DEFAULT_SOURCE' lib programs
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0' test
+}
 
-# catch compile bugs in _uninit functions
-msg "build: full config with NO_STD_FUNCTION, make, gcc" # ~ 30s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl set MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
-scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
-make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0'
+component_build_no_std_function () {
+    # catch compile bugs in _uninit functions
+    msg "build: full config with NO_STD_FUNCTION, make, gcc" # ~ 30s
+    scripts/config.pl full
+    scripts/config.pl set MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
+    scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0'
+}
 
-msg "build: full config except ssl_srv.c, make, gcc" # ~ 30s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_SSL_SRV_C
-make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0'
+component_build_no_ssl_srv () {
+    msg "build: full config except ssl_srv.c, make, gcc" # ~ 30s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_SSL_SRV_C
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0'
+}
 
-msg "build: full config except ssl_cli.c, make, gcc" # ~ 30s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_SSL_CLI_C
-make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0'
+component_build_no_ssl_cli () {
+    msg "build: full config except ssl_cli.c, make, gcc" # ~ 30s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_SSL_CLI_C
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0'
+}
 
-# Note, C99 compliance can also be tested with the sockets support disabled,
-# as that requires a POSIX platform (which isn't the same as C99).
-msg "build: full config except net_sockets.c, make, gcc -std=c99 -pedantic" # ~ 30s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_NET_C # getaddrinfo() undeclared, etc.
-scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY # uses syscall() on GNU/Linux
-make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0 -std=c99 -pedantic' lib
+component_build_no_sockets () {
+    # Note, C99 compliance can also be tested with the sockets support disabled,
+    # as that requires a POSIX platform (which isn't the same as C99).
+    msg "build: full config except net_sockets.c, make, gcc -std=c99 -pedantic" # ~ 30s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_NET_C # getaddrinfo() undeclared, etc.
+    scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY # uses syscall() on GNU/Linux
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0 -std=c99 -pedantic' lib
+}
 
-# Run max fragment length tests with MFL disabled
-msg "build: default config except MFL extension (ASan build)" # ~ 30s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl unset MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+component_test_no_max_fragment_length () {
+    # Run max fragment length tests with MFL disabled
+    msg "build: default config except MFL extension (ASan build)" # ~ 30s
+    scripts/config.pl unset MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "test: ssl-opt.sh, MFL-related tests"
-if_build_succeeded tests/ssl-opt.sh -f "Max fragment length"
+    msg "test: ssl-opt.sh, MFL-related tests"
+    if_build_succeeded tests/ssl-opt.sh -f "Max fragment length"
+}
 
-msg "build: no MFL extension, small SSL_OUT_CONTENT_LEN (ASan build)"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl unset MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
-scripts/config.pl set MBEDTLS_SSL_IN_CONTENT_LEN 16384
-scripts/config.pl set MBEDTLS_SSL_OUT_CONTENT_LEN 4096
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+component_test_no_max_fragment_length_small_ssl_out_content_len () {
+    msg "build: no MFL extension, small SSL_OUT_CONTENT_LEN (ASan build)"
+    scripts/config.pl unset MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+    scripts/config.pl set MBEDTLS_SSL_IN_CONTENT_LEN 16384
+    scripts/config.pl set MBEDTLS_SSL_OUT_CONTENT_LEN 4096
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "test: MFL tests (disabled MFL extension case) & large packet tests"
-if_build_succeeded tests/ssl-opt.sh -f "Max fragment length\|Large buffer"
+    msg "test: MFL tests (disabled MFL extension case) & large packet tests"
+    if_build_succeeded tests/ssl-opt.sh -f "Max fragment length\|Large buffer"
+}
 
-msg "build: default config with  MBEDTLS_TEST_NULL_ENTROPY (ASan build)"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_TEST_NULL_ENTROPY
-scripts/config.pl set MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
-scripts/config.pl set MBEDTLS_ENTROPY_C
-scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
-scripts/config.pl unset MBEDTLS_ENTROPY_HARDWARE_ALT
-scripts/config.pl unset MBEDTLS_HAVEGE_C
-CC=gcc cmake  -D UNSAFE_BUILD=ON -D CMAKE_C_FLAGS:String="-fsanitize=address -fno-common -O3" .
-make
+component_test_null_entropy () {
+    msg "build: default config with  MBEDTLS_TEST_NULL_ENTROPY (ASan build)"
+    scripts/config.pl set MBEDTLS_TEST_NULL_ENTROPY
+    scripts/config.pl set MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
+    scripts/config.pl set MBEDTLS_ENTROPY_C
+    scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
+    scripts/config.pl unset MBEDTLS_ENTROPY_HARDWARE_ALT
+    scripts/config.pl unset MBEDTLS_HAVEGE_C
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan -D UNSAFE_BUILD=ON .
+    make
 
-msg "test: MBEDTLS_TEST_NULL_ENTROPY - main suites (inc. selftests) (ASan build)"
-make test
+    msg "test: MBEDTLS_TEST_NULL_ENTROPY - main suites (inc. selftests) (ASan build)"
+    make test
+}
 
-msg "build: MBEDTLS_PLATFORM_{CALLOC/FREE}_MACRO enabled (ASan build)"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_PLATFORM_MEMORY
-scripts/config.pl set MBEDTLS_PLATFORM_CALLOC_MACRO calloc
-scripts/config.pl set MBEDTLS_PLATFORM_FREE_MACRO   free
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+component_test_platform_calloc_macro () {
+    msg "build: MBEDTLS_PLATFORM_{CALLOC/FREE}_MACRO enabled (ASan build)"
+    scripts/config.pl set MBEDTLS_PLATFORM_MEMORY
+    scripts/config.pl set MBEDTLS_PLATFORM_CALLOC_MACRO calloc
+    scripts/config.pl set MBEDTLS_PLATFORM_FREE_MACRO   free
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
 
-msg "test: MBEDTLS_PLATFORM_{CALLOC/FREE}_MACRO enabled (ASan build)"
-make test
+    msg "test: MBEDTLS_PLATFORM_{CALLOC/FREE}_MACRO enabled (ASan build)"
+    make test
+}
 
-msg "build: default config with AES_FEWER_TABLES enabled"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_AES_FEWER_TABLES
-make CC=gcc CFLAGS='-Werror -Wall -Wextra'
+component_test_aes_fewer_tables () {
+    msg "build: default config with AES_FEWER_TABLES enabled"
+    scripts/config.pl set MBEDTLS_AES_FEWER_TABLES
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra'
 
-msg "test: AES_FEWER_TABLES"
-make test
+    msg "test: AES_FEWER_TABLES"
+    make test
+}
 
-msg "build: default config with AES_ROM_TABLES enabled"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_AES_ROM_TABLES
-make CC=gcc CFLAGS='-Werror -Wall -Wextra'
+component_test_aes_rom_tables () {
+    msg "build: default config with AES_ROM_TABLES enabled"
+    scripts/config.pl set MBEDTLS_AES_ROM_TABLES
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra'
 
-msg "test: AES_ROM_TABLES"
-make test
+    msg "test: AES_ROM_TABLES"
+    make test
+}
 
-msg "build: default config with AES_ROM_TABLES and AES_FEWER_TABLES enabled"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_AES_FEWER_TABLES
-scripts/config.pl set MBEDTLS_AES_ROM_TABLES
-make CC=gcc CFLAGS='-Werror -Wall -Wextra'
+component_test_aes_fewer_tables_and_rom_tables () {
+    msg "build: default config with AES_ROM_TABLES and AES_FEWER_TABLES enabled"
+    scripts/config.pl set MBEDTLS_AES_FEWER_TABLES
+    scripts/config.pl set MBEDTLS_AES_ROM_TABLES
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra'
 
-msg "test: AES_FEWER_TABLES + AES_ROM_TABLES"
-make test
+    msg "test: AES_FEWER_TABLES + AES_ROM_TABLES"
+    make test
+}
 
-if uname -a | grep -F Linux >/dev/null; then
+component_test_make_shared () {
     msg "build/test: make shared" # ~ 40s
-    cleanup
     make SHARED=1 all check
-fi
+}
 
-if uname -a | grep -F x86_64 >/dev/null; then
+component_test_m32_o0 () {
     # Build once with -O0, to compile out the i386 specific inline assembly
     msg "build: i386, make, gcc -O0 (ASan build)" # ~ 30s
-    cleanup
-    cp "$CONFIG_H" "$CONFIG_BAK"
     scripts/config.pl full
     make CC=gcc CFLAGS='-O0 -Werror -Wall -Wextra -m32 -fsanitize=address'
 
     msg "test: i386, make, gcc -O0 (ASan build)"
     make test
+}
+support_test_m32_o0 () {
+    case $(uname -m) in
+        *64*) true;;
+        *) false;;
+    esac
+}
 
+component_test_m32_o1 () {
     # Build again with -O1, to compile in the i386 specific inline assembly
     msg "build: i386, make, gcc -O1 (ASan build)" # ~ 30s
-    cleanup
-    cp "$CONFIG_H" "$CONFIG_BAK"
     scripts/config.pl full
     make CC=gcc CFLAGS='-O1 -Werror -Wall -Wextra -m32 -fsanitize=address'
 
     msg "test: i386, make, gcc -O1 (ASan build)"
     make test
+}
+support_test_m32_o1 () {
+    support_test_m32_o0 "$@"
+}
 
+component_test_mx32 () {
     msg "build: 64-bit ILP32, make, gcc" # ~ 30s
-    cleanup
-    cp "$CONFIG_H" "$CONFIG_BAK"
     scripts/config.pl full
     make CC=gcc CFLAGS='-Werror -Wall -Wextra -mx32'
 
     msg "test: 64-bit ILP32, make, gcc"
     make test
-fi # x86_64
+}
+support_test_mx32 () {
+    case $(uname -m) in
+        amd64|x86_64) true;;
+        *) false;;
+    esac
+}
 
-msg "build: gcc, force 32-bit bignum limbs"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl unset MBEDTLS_HAVE_ASM
-scripts/config.pl unset MBEDTLS_AESNI_C
-scripts/config.pl unset MBEDTLS_PADLOCK_C
-make CC=gcc CFLAGS='-Werror -Wall -Wextra -DMBEDTLS_HAVE_INT32'
+component_test_have_int32 () {
+    msg "build: gcc, force 32-bit bignum limbs"
+    scripts/config.pl unset MBEDTLS_HAVE_ASM
+    scripts/config.pl unset MBEDTLS_AESNI_C
+    scripts/config.pl unset MBEDTLS_PADLOCK_C
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -DMBEDTLS_HAVE_INT32'
 
-msg "test: gcc, force 32-bit bignum limbs"
-make test
+    msg "test: gcc, force 32-bit bignum limbs"
+    make test
+}
 
-msg "build: gcc, force 64-bit bignum limbs"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl unset MBEDTLS_HAVE_ASM
-scripts/config.pl unset MBEDTLS_AESNI_C
-scripts/config.pl unset MBEDTLS_PADLOCK_C
-make CC=gcc CFLAGS='-Werror -Wall -Wextra -DMBEDTLS_HAVE_INT64'
+component_test_have_int64 () {
+    msg "build: gcc, force 64-bit bignum limbs"
+    scripts/config.pl unset MBEDTLS_HAVE_ASM
+    scripts/config.pl unset MBEDTLS_AESNI_C
+    scripts/config.pl unset MBEDTLS_PADLOCK_C
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -DMBEDTLS_HAVE_INT64'
 
-msg "test: gcc, force 64-bit bignum limbs"
-make test
+    msg "test: gcc, force 64-bit bignum limbs"
+    make test
+}
 
+component_test_no_udbl_division () {
+    msg "build: MBEDTLS_NO_UDBL_DIVISION native" # ~ 10s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
+    scripts/config.pl set MBEDTLS_NO_UDBL_DIVISION
+    make CFLAGS='-Werror -O1'
 
-msg "build: MBEDTLS_NO_UDBL_DIVISION native" # ~ 10s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
-scripts/config.pl set MBEDTLS_NO_UDBL_DIVISION
-make CFLAGS='-Werror -O1'
+    msg "test: MBEDTLS_NO_UDBL_DIVISION native" # ~ 10s
+    make test
+}
 
-msg "test: MBEDTLS_NO_UDBL_DIVISION native" # ~ 10s
-make test
+component_test_no_64bit_multiplication () {
+    msg "build: MBEDTLS_NO_64BIT_MULTIPLICATION native" # ~ 10s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
+    scripts/config.pl set MBEDTLS_NO_64BIT_MULTIPLICATION
+    make CFLAGS='-Werror -O1'
 
+    msg "test: MBEDTLS_NO_64BIT_MULTIPLICATION native" # ~ 10s
+    make test
+}
 
-msg "build: MBEDTLS_NO_64BIT_MULTIPLICATION native" # ~ 10s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
-scripts/config.pl set MBEDTLS_NO_64BIT_MULTIPLICATION
-make CFLAGS='-Werror -O1'
+component_build_arm_none_eabi_gcc () {
+    msg "build: arm-none-eabi-gcc, make" # ~ 10s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_NET_C
+    scripts/config.pl unset MBEDTLS_TIMING_C
+    scripts/config.pl unset MBEDTLS_FS_IO
+    scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
+    scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY
+    # following things are not in the default config
+    scripts/config.pl unset MBEDTLS_HAVEGE_C # depends on timing.c
+    scripts/config.pl unset MBEDTLS_THREADING_PTHREAD
+    scripts/config.pl unset MBEDTLS_THREADING_C
+    scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # execinfo.h
+    scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C # calls exit
+    make CC=arm-none-eabi-gcc AR=arm-none-eabi-ar LD=arm-none-eabi-ld CFLAGS='-Werror -Wall -Wextra' lib
+}
 
-msg "test: MBEDTLS_NO_64BIT_MULTIPLICATION native" # ~ 10s
-make test
+component_build_arm_none_eabi_gcc_no_udbl_division () {
+    msg "build: arm-none-eabi-gcc -DMBEDTLS_NO_UDBL_DIVISION, make" # ~ 10s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_NET_C
+    scripts/config.pl unset MBEDTLS_TIMING_C
+    scripts/config.pl unset MBEDTLS_FS_IO
+    scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
+    scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY
+    # following things are not in the default config
+    scripts/config.pl unset MBEDTLS_HAVEGE_C # depends on timing.c
+    scripts/config.pl unset MBEDTLS_THREADING_PTHREAD
+    scripts/config.pl unset MBEDTLS_THREADING_C
+    scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # execinfo.h
+    scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C # calls exit
+    scripts/config.pl set MBEDTLS_NO_UDBL_DIVISION
+    make CC=arm-none-eabi-gcc AR=arm-none-eabi-ar LD=arm-none-eabi-ld CFLAGS='-Werror -Wall -Wextra' lib
+    echo "Checking that software 64-bit division is not required"
+    if_build_succeeded not grep __aeabi_uldiv library/*.o
+}
 
+component_build_arm_none_eabi_gcc_no_64bit_multiplication () {
+    msg "build: arm-none-eabi-gcc MBEDTLS_NO_64BIT_MULTIPLICATION, make" # ~ 10s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_NET_C
+    scripts/config.pl unset MBEDTLS_TIMING_C
+    scripts/config.pl unset MBEDTLS_FS_IO
+    scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
+    scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY
+    # following things are not in the default config
+    scripts/config.pl unset MBEDTLS_HAVEGE_C # depends on timing.c
+    scripts/config.pl unset MBEDTLS_THREADING_PTHREAD
+    scripts/config.pl unset MBEDTLS_THREADING_C
+    scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # execinfo.h
+    scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C # calls exit
+    scripts/config.pl set MBEDTLS_NO_64BIT_MULTIPLICATION
+    make CC=arm-none-eabi-gcc AR=arm-none-eabi-ar LD=arm-none-eabi-ld CFLAGS='-Werror -O1 -march=armv6-m -mthumb' lib
+    echo "Checking that software 64-bit multiplication is not required"
+    if_build_succeeded not grep __aeabi_lmul library/*.o
+}
 
-msg "build: arm-none-eabi-gcc, make" # ~ 10s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_NET_C
-scripts/config.pl unset MBEDTLS_TIMING_C
-scripts/config.pl unset MBEDTLS_FS_IO
-scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
-scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY
-# following things are not in the default config
-scripts/config.pl unset MBEDTLS_HAVEGE_C # depends on timing.c
-scripts/config.pl unset MBEDTLS_THREADING_PTHREAD
-scripts/config.pl unset MBEDTLS_THREADING_C
-scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # execinfo.h
-scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C # calls exit
-make CC=arm-none-eabi-gcc AR=arm-none-eabi-ar LD=arm-none-eabi-ld CFLAGS='-Werror -Wall -Wextra' lib
+component_build_armcc () {
+    msg "build: ARM Compiler 5, make"
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_NET_C
+    scripts/config.pl unset MBEDTLS_TIMING_C
+    scripts/config.pl unset MBEDTLS_FS_IO
+    scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
+    scripts/config.pl unset MBEDTLS_HAVE_TIME
+    scripts/config.pl unset MBEDTLS_HAVE_TIME_DATE
+    scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY
+    # following things are not in the default config
+    scripts/config.pl unset MBEDTLS_DEPRECATED_WARNING
+    scripts/config.pl unset MBEDTLS_HAVEGE_C # depends on timing.c
+    scripts/config.pl unset MBEDTLS_THREADING_PTHREAD
+    scripts/config.pl unset MBEDTLS_THREADING_C
+    scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # execinfo.h
+    scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C # calls exit
+    scripts/config.pl unset MBEDTLS_PLATFORM_TIME_ALT # depends on MBEDTLS_HAVE_TIME
 
-msg "build: arm-none-eabi-gcc -DMBEDTLS_NO_UDBL_DIVISION, make" # ~ 10s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_NET_C
-scripts/config.pl unset MBEDTLS_TIMING_C
-scripts/config.pl unset MBEDTLS_FS_IO
-scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
-scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY
-# following things are not in the default config
-scripts/config.pl unset MBEDTLS_HAVEGE_C # depends on timing.c
-scripts/config.pl unset MBEDTLS_THREADING_PTHREAD
-scripts/config.pl unset MBEDTLS_THREADING_C
-scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # execinfo.h
-scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C # calls exit
-scripts/config.pl set MBEDTLS_NO_UDBL_DIVISION
-make CC=arm-none-eabi-gcc AR=arm-none-eabi-ar LD=arm-none-eabi-ld CFLAGS='-Werror -Wall -Wextra' lib
-echo "Checking that software 64-bit division is not required"
-if_build_succeeded not grep __aeabi_uldiv library/*.o
-
-msg "build: arm-none-eabi-gcc MBEDTLS_NO_64BIT_MULTIPLICATION, make" # ~ 10s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_NET_C
-scripts/config.pl unset MBEDTLS_TIMING_C
-scripts/config.pl unset MBEDTLS_FS_IO
-scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
-scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY
-# following things are not in the default config
-scripts/config.pl unset MBEDTLS_HAVEGE_C # depends on timing.c
-scripts/config.pl unset MBEDTLS_THREADING_PTHREAD
-scripts/config.pl unset MBEDTLS_THREADING_C
-scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # execinfo.h
-scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C # calls exit
-scripts/config.pl set MBEDTLS_NO_64BIT_MULTIPLICATION
-make CC=arm-none-eabi-gcc AR=arm-none-eabi-ar LD=arm-none-eabi-ld CFLAGS='-Werror -O1 -march=armv6-m -mthumb' lib
-echo "Checking that software 64-bit multiplication is not required"
-if_build_succeeded not grep __aeabi_lmul library/*.o
-
-msg "build: ARM Compiler 5, make"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl full
-scripts/config.pl unset MBEDTLS_NET_C
-scripts/config.pl unset MBEDTLS_TIMING_C
-scripts/config.pl unset MBEDTLS_FS_IO
-scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
-scripts/config.pl unset MBEDTLS_HAVE_TIME
-scripts/config.pl unset MBEDTLS_HAVE_TIME_DATE
-scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY
-# following things are not in the default config
-scripts/config.pl unset MBEDTLS_DEPRECATED_WARNING
-scripts/config.pl unset MBEDTLS_HAVEGE_C # depends on timing.c
-scripts/config.pl unset MBEDTLS_THREADING_PTHREAD
-scripts/config.pl unset MBEDTLS_THREADING_C
-scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # execinfo.h
-scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C # calls exit
-scripts/config.pl unset MBEDTLS_PLATFORM_TIME_ALT # depends on MBEDTLS_HAVE_TIME
-
-if [ $RUN_ARMCC -ne 0 ]; then
     make CC="$ARMC5_CC" AR="$ARMC5_AR" WARNING_CFLAGS='--strict --c99' lib
     make clean
 
@@ -1059,46 +1215,33 @@
 
     # ARM Compiler 6 - Target ARMv8-A - AArch64
     armc6_build_test "--target=aarch64-arm-none-eabi -march=armv8.2-a"
-fi
+}
 
-msg "build: allow SHA1 in certificates by default"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES
-make CFLAGS='-Werror -Wall -Wextra'
-msg "test: allow SHA1 in certificates by default"
-make test
-if_build_succeeded tests/ssl-opt.sh -f SHA-1
+component_test_allow_sha1 () {
+    msg "build: allow SHA1 in certificates by default"
+    scripts/config.pl set MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES
+    make CFLAGS='-Werror -Wall -Wextra'
+    msg "test: allow SHA1 in certificates by default"
+    make test
+    if_build_succeeded tests/ssl-opt.sh -f SHA-1
+}
 
-msg "build: Default + MBEDTLS_RSA_NO_CRT (ASan build)" # ~ 6 min
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl set MBEDTLS_RSA_NO_CRT
-CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
-make
+component_build_mingw () {
+    msg "build: Windows cross build - mingw64, make (Link Library)" # ~ 30s
+    make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 lib programs
 
-msg "test: MBEDTLS_RSA_NO_CRT - main suites (inc. selftests) (ASan build)"
-make test
+    # note Make tests only builds the tests, but doesn't run them
+    make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror' WINDOWS_BUILD=1 tests
+    make WINDOWS_BUILD=1 clean
 
-msg "build: Windows cross build - mingw64, make (Link Library)" # ~ 30s
-cleanup
-make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 lib programs
+    msg "build: Windows cross build - mingw64, make (DLL)" # ~ 30s
+    make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 SHARED=1 lib programs
+    make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 SHARED=1 tests
+    make WINDOWS_BUILD=1 clean
+}
 
-# note Make tests only builds the tests, but doesn't run them
-make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror' WINDOWS_BUILD=1 tests
-make WINDOWS_BUILD=1 clean
-
-msg "build: Windows cross build - mingw64, make (DLL)" # ~ 30s
-make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 SHARED=1 lib programs
-make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 SHARED=1 tests
-make WINDOWS_BUILD=1 clean
-
-# MemSan currently only available on Linux 64 bits
-if uname -a | grep 'Linux.*x86_64' >/dev/null; then
-
+component_test_memsan () {
     msg "build: MSan (clang)" # ~ 1 min 20s
-    cleanup
-    cp "$CONFIG_H" "$CONFIG_BAK"
     scripts/config.pl unset MBEDTLS_AESNI_C # memsan doesn't grok asm
     CC=clang cmake -D CMAKE_BUILD_TYPE:String=MemSan .
     make
@@ -1115,11 +1258,10 @@
         msg "test: compat.sh (MSan)" # ~ 6 min 20s
         if_build_succeeded tests/compat.sh
     fi
+}
 
-else # no MemSan
-
+component_test_valgrind () {
     msg "build: Release (clang)"
-    cleanup
     CC=clang cmake -D CMAKE_BUILD_TYPE:String=Release .
     make
 
@@ -1139,63 +1281,123 @@
         msg "test: compat.sh --memcheck (Release)"
         if_build_succeeded tests/compat.sh --memcheck
     fi
+}
 
-fi # MemSan
+component_test_cmake_out_of_source () {
+    msg "build: cmake 'out-of-source' build"
+    MBEDTLS_ROOT_DIR="$PWD"
+    mkdir "$OUT_OF_SOURCE_DIR"
+    cd "$OUT_OF_SOURCE_DIR"
+    cmake "$MBEDTLS_ROOT_DIR"
+    make
 
-msg "build: cmake 'out-of-source' build"
-cleanup
-MBEDTLS_ROOT_DIR="$PWD"
-mkdir "$OUT_OF_SOURCE_DIR"
-cd "$OUT_OF_SOURCE_DIR"
-cmake "$MBEDTLS_ROOT_DIR"
-make
+    msg "test: cmake 'out-of-source' build"
+    make test
+    # Test an SSL option that requires an auxiliary script in test/scripts/.
+    # Also ensure that there are no error messages such as
+    # "No such file or directory", which would indicate that some required
+    # file is missing (ssl-opt.sh tolerates the absence of some files so
+    # may exit with status 0 but emit errors).
+    if_build_succeeded ./tests/ssl-opt.sh -f 'Fallback SCSV: beginning of list' 2>ssl-opt.err
+    if [ -s ssl-opt.err ]; then
+        cat ssl-opt.err >&2
+        record_status [ ! -s ssl-opt.err ]
+        rm ssl-opt.err
+    fi
+    cd "$MBEDTLS_ROOT_DIR"
+    rm -rf "$OUT_OF_SOURCE_DIR"
+    unset MBEDTLS_ROOT_DIR
+}
 
-msg "test: cmake 'out-of-source' build"
-make test
-# Test an SSL option that requires an auxiliary script in test/scripts/.
-# Also ensure that there are no error messages such as
-# "No such file or directory", which would indicate that some required
-# file is missing (ssl-opt.sh tolerates the absence of some files so
-# may exit with status 0 but emit errors).
-if_build_succeeded ./tests/ssl-opt.sh -f 'Fallback SCSV: beginning of list' 2>ssl-opt.err
-if [ -s ssl-opt.err ]; then
-  cat ssl-opt.err >&2
-  record_status [ ! -s ssl-opt.err ]
-  rm ssl-opt.err
-fi
-cd "$MBEDTLS_ROOT_DIR"
-rm -rf "$OUT_OF_SOURCE_DIR"
-unset MBEDTLS_ROOT_DIR
+component_test_zeroize () {
+    # Test that the function mbedtls_platform_zeroize() is not optimized away by
+    # different combinations of compilers and optimization flags by using an
+    # auxiliary GDB script. Unfortunately, GDB does not return error values to the
+    # system in all cases that the script fails, so we must manually search the
+    # output to check whether the pass string is present and no failure strings
+    # were printed.
 
-# Test that the function mbedtls_platform_zeroize() is not optimized away by
-# different combinations of compilers and optimization flags by using an
-# auxiliary GDB script. Unfortunately, GDB does not return error values to the
-# system in all cases that the script fails, so we must manually search the
-# output to check whether the pass string is present and no failure strings
-# were printed.
-for optimization_flag in -O2 -O3 -Ofast -Os; do
-    for compiler in clang gcc; do
-        msg "test: $compiler $optimization_flag, mbedtls_platform_zeroize()"
-        cleanup
-        make programs CC="$compiler" DEBUG=1 CFLAGS="$optimization_flag"
-        if_build_succeeded gdb -x tests/scripts/test_zeroize.gdb -nw -batch -nx 2>&1 | tee test_zeroize.log
-        if_build_succeeded grep "The buffer was correctly zeroized" test_zeroize.log
-        if_build_succeeded not grep -i "error" test_zeroize.log
-        rm -f test_zeroize.log
+    # Don't try to disable ASLR. We don't care about ASLR here. We do care
+    # about a spurious message if Gdb tries and fails, so suppress that.
+    gdb_disable_aslr=
+    if [ -z "$(gdb -batch -nw -ex 'set disable-randomization off' 2>&1)" ]; then
+        gdb_disable_aslr='set disable-randomization off'
+    fi
+
+    for optimization_flag in -O2 -O3 -Ofast -Os; do
+        for compiler in clang gcc; do
+            msg "test: $compiler $optimization_flag, mbedtls_platform_zeroize()"
+            make programs CC="$compiler" DEBUG=1 CFLAGS="$optimization_flag"
+            if_build_succeeded gdb -ex "$gdb_disable_aslr" -x tests/scripts/test_zeroize.gdb -nw -batch -nx 2>&1 | tee test_zeroize.log
+            if_build_succeeded grep "The buffer was correctly zeroized" test_zeroize.log
+            if_build_succeeded not grep -i "error" test_zeroize.log
+            rm -f test_zeroize.log
+            make clean
+        done
     done
-done
 
-msg "Lint: Python scripts"
-record_status tests/scripts/check-python-files.sh
+    unset gdb_disable_aslr
+}
 
-msg "uint test: generate_test_code.py"
-record_status ./tests/scripts/test_generate_test_code.py
+component_check_python_files () {
+    msg "Lint: Python scripts"
+    record_status tests/scripts/check-python-files.sh
+}
+
+component_check_generate_test_code () {
+    msg "uint test: generate_test_code.py"
+    record_status ./tests/scripts/test_generate_test_code.py
+}
 
 ################################################################
 #### Termination
 ################################################################
 
-msg "Done, cleaning up"
+post_report () {
+    msg "Done, cleaning up"
+    cleanup
+
+    final_report
+}
+
+
+
+################################################################
+#### Run all the things
+################################################################
+
+# Run one component and clean up afterwards.
+run_component () {
+    # Back up the configuration in case the component modifies it.
+    # The cleanup function will restore it.
+    cp -p "$CONFIG_H" "$CONFIG_BAK"
+    current_component="$1"
+    "$@"
+    cleanup
+}
+
+# Preliminary setup
+pre_check_environment
+pre_initialize_variables
+pre_parse_command_line "$@"
+
+pre_check_git
+build_status=0
+if [ $KEEP_GOING -eq 1 ]; then
+    pre_setup_keep_going
+else
+    record_status () {
+        "$@"
+    }
+fi
+pre_print_configuration
+pre_check_tools
 cleanup
 
-final_report
+# Run the requested tests.
+for component in $RUN_COMPONENTS; do
+    run_component "component_$component"
+done
+
+# We're done.
+post_report
diff --git a/tests/scripts/mbedtls_test.py b/tests/scripts/mbedtls_test.py
index f9e88cf..c702765 100755
--- a/tests/scripts/mbedtls_test.py
+++ b/tests/scripts/mbedtls_test.py
@@ -75,11 +75,10 @@
         :param split_char: Split character
         :return: List of splits
         """
+        split_colon_fn = lambda x: re.sub(r'\\' + split_char, split_char, x)
         if len(split_char) > 1:
             raise ValueError('Expected split character. Found string!')
-        out = re.sub(r'(\\.)|' + split_char,
-                     lambda m: m.group(1) or '\n', inp_str,
-                     len(inp_str)).split('\n')
+        out = map(split_colon_fn, re.split(r'(?<!\\)' + split_char, inp_str))
         out = [x for x in out if x]
         return out
 
@@ -112,8 +111,8 @@
             args = parts[1:]
             args_count = len(args)
             if args_count % 2 != 0:
-                raise TestDataParserError("Number of test arguments should "
-                                          "be even: %s" % line)
+                err_str_fmt = "Number of test arguments({}) should be even: {}"
+                raise TestDataParserError(err_str_fmt.format(args_count, line))
             grouped_args = [(args[i * 2], args[(i * 2) + 1])
                             for i in range(len(args)/2)]
             self.tests.append((name, function_name, dependencies,
@@ -163,6 +162,7 @@
         self.tests = []
         self.test_index = -1
         self.dep_index = 0
+        self.suite_passed = True
         self.error_str = dict()
         self.error_str[self.DEPENDENCY_SUPPORTED] = \
             'DEPENDENCY_SUPPORTED'
@@ -293,7 +293,7 @@
             name, function_id, dependencies, args = self.tests[self.test_index]
             self.run_test(name, function_id, dependencies, args)
         else:
-            self.notify_complete(True)
+            self.notify_complete(self.suite_passed)
 
     def run_test(self, name, function_id, dependencies, args):
         """
@@ -353,6 +353,8 @@
         self.log('{{__testcase_start;%s}}' % name)
         self.log('{{__testcase_finish;%s;%d;%d}}' % (name, int_val == 0,
                                                      int_val != 0))
+        if int_val != 0:
+            self.suite_passed = False
         self.run_next_test()
 
     @event_callback("F")
diff --git a/tests/scripts/test_zeroize.gdb b/tests/scripts/test_zeroize.gdb
index 77c812a..c929c88 100644
--- a/tests/scripts/test_zeroize.gdb
+++ b/tests/scripts/test_zeroize.gdb
@@ -17,7 +17,7 @@
 # seem to be a mechanism to reliably check whether the zeroize calls are being
 # eliminated by compiler optimizations from within the compiled program. The
 # problem is that a compiler would typically remove what it considers to be
-# "unecessary" assignments as part of redundant code elimination. To identify
+# "unnecessary" assignments as part of redundant code elimination. To identify
 # such code, the compilar will create some form dependency graph between
 # reads and writes to variables (among other situations). It will then use this
 # data structure to remove redundant code that does not have an impact on the
@@ -41,8 +41,6 @@
 # number does not need to be updated often.
 
 set confirm off
-# We don't need to turn off ASLR, so don't try.
-set disable-randomization off
 
 file ./programs/test/zeroize
 break zeroize.c:100
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 94ce14e..791c2c3 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -26,7 +26,7 @@
     exit 1
 fi
 
-# default values, can be overriden by the environment
+# default values, can be overridden by the environment
 : ${P_SRV:=../programs/ssl/ssl_server2}
 : ${P_CLI:=../programs/ssl/ssl_client2}
 : ${P_PXY:=../programs/test/udp_proxy}
@@ -167,7 +167,7 @@
 get_config_value_or_default() {
     NAME="$1"
     DEF_VAL=$( grep ".*#define.*${NAME}" ../include/mbedtls/config.h |
-               sed 's/^.*\s\([0-9]*\)$/\1/' )
+               sed 's/^.* \([0-9]*\)$/\1/' )
     ../scripts/config.pl get $NAME || echo "$DEF_VAL"
 }
 
@@ -689,7 +689,7 @@
 
                 # The filtering in the following two options (-u and -U) do the following
                 #   - ignore valgrind output
-                #   - filter out everything but lines right after the pattern occurances
+                #   - filter out everything but lines right after the pattern occurrences
                 #   - keep one of each non-unique line
                 #   - count how many lines remain
                 # A line with '--' will remain in the result from previous outputs, so the number of lines in the result will be 1
@@ -2802,7 +2802,7 @@
                     key_file=data_files/dir-maxpath/09.key" \
             "$P_CLI server_name=CA09 ca_file=data_files/dir-maxpath/00.crt" \
             0 \
-            -C "X509 - A fatal error occured"
+            -C "X509 - A fatal error occurred"
 
 requires_full_size_output_buffer
 run_test    "Authentication: server max_int+1 chain, client default" \
@@ -2810,7 +2810,7 @@
                     key_file=data_files/dir-maxpath/10.key" \
             "$P_CLI server_name=CA10 ca_file=data_files/dir-maxpath/00.crt" \
             1 \
-            -c "X509 - A fatal error occured"
+            -c "X509 - A fatal error occurred"
 
 requires_full_size_output_buffer
 run_test    "Authentication: server max_int+1 chain, client optional" \
@@ -2819,7 +2819,7 @@
             "$P_CLI server_name=CA10 ca_file=data_files/dir-maxpath/00.crt \
                     auth_mode=optional" \
             1 \
-            -c "X509 - A fatal error occured"
+            -c "X509 - A fatal error occurred"
 
 requires_full_size_output_buffer
 run_test    "Authentication: server max_int+1 chain, client none" \
@@ -2828,7 +2828,7 @@
             "$P_CLI server_name=CA10 ca_file=data_files/dir-maxpath/00.crt \
                     auth_mode=none" \
             0 \
-            -C "X509 - A fatal error occured"
+            -C "X509 - A fatal error occurred"
 
 requires_full_size_output_buffer
 run_test    "Authentication: client max_int+1 chain, server default" \
@@ -2836,7 +2836,7 @@
             "$P_CLI crt_file=data_files/dir-maxpath/c10.pem \
                     key_file=data_files/dir-maxpath/10.key" \
             0 \
-            -S "X509 - A fatal error occured"
+            -S "X509 - A fatal error occurred"
 
 requires_full_size_output_buffer
 run_test    "Authentication: client max_int+1 chain, server optional" \
@@ -2844,7 +2844,7 @@
             "$P_CLI crt_file=data_files/dir-maxpath/c10.pem \
                     key_file=data_files/dir-maxpath/10.key" \
             1 \
-            -s "X509 - A fatal error occured"
+            -s "X509 - A fatal error occurred"
 
 requires_full_size_output_buffer
 run_test    "Authentication: client max_int+1 chain, server required" \
@@ -2852,7 +2852,7 @@
             "$P_CLI crt_file=data_files/dir-maxpath/c10.pem \
                     key_file=data_files/dir-maxpath/10.key" \
             1 \
-            -s "X509 - A fatal error occured"
+            -s "X509 - A fatal error occurred"
 
 requires_full_size_output_buffer
 run_test    "Authentication: client max_int chain, server required" \
@@ -2860,7 +2860,7 @@
             "$P_CLI crt_file=data_files/dir-maxpath/c09.pem \
                     key_file=data_files/dir-maxpath/09.key" \
             0 \
-            -S "X509 - A fatal error occured"
+            -S "X509 - A fatal error occurred"
 
 # Tests for CA list in CertificateRequest messages
 
diff --git a/tests/suites/test_suite_ccm.data b/tests/suites/test_suite_ccm.data
index ac9c565..46c172b 100644
--- a/tests/suites/test_suite_ccm.data
+++ b/tests/suites/test_suite_ccm.data
@@ -41,7 +41,7 @@
 CCM lengths #6 tag length not even
 ccm_lengths:5:10:5:7:MBEDTLS_ERR_CCM_BAD_INPUT
 
-CCM lenghts #7 AD too long (2^16 - 2^8 + 1)
+CCM lengths #7 AD too long (2^16 - 2^8 + 1)
 depends_on:!MBEDTLS_CCM_ALT
 ccm_lengths:5:10:65281:8:MBEDTLS_ERR_CCM_BAD_INPUT
 
diff --git a/tests/suites/test_suite_ecdh.function b/tests/suites/test_suite_ecdh.function
index 20df55b..7db0ed1 100644
--- a/tests/suites/test_suite_ecdh.function
+++ b/tests/suites/test_suite_ecdh.function
@@ -278,7 +278,7 @@
     mbedtls_ecdh_init( &cli );
     memset( &rnd_info, 0x00, sizeof( rnd_pseudo_info ) );
 
-	TEST_ASSERT( mbedtls_ecdh_setup( &srv, id ) == 0 );
+    TEST_ASSERT( mbedtls_ecdh_setup( &srv, id ) == 0 );
 
     memset( buf, 0x00, sizeof( buf ) ); vbuf = buf;
     TEST_ASSERT( mbedtls_ecdh_make_params( &srv, &len, buf, 1000,
@@ -351,7 +351,7 @@
         mbedtls_ecdh_enable_restart( &cli );
     }
 
-    /* server writes its paramaters */
+    /* server writes its parameters */
     memset( buf, 0x00, sizeof( buf ) );
     len = 0;
 
diff --git a/tests/suites/test_suite_nist_kw.function b/tests/suites/test_suite_nist_kw.function
index ae3ef80..f1acde9 100644
--- a/tests/suites/test_suite_nist_kw.function
+++ b/tests/suites/test_suite_nist_kw.function
@@ -30,7 +30,7 @@
     memset( key, 0, sizeof( key ) );
 
     /*
-     * 1. Check wrap and unwrap with two seperate contexts
+     * 1. Check wrap and unwrap with two separate contexts
      */
     mbedtls_nist_kw_init( &ctx1 );
     mbedtls_nist_kw_init( &ctx2 );
diff --git a/tests/suites/test_suite_rsa.data b/tests/suites/test_suite_rsa.data
index 5f49ad6..953b1ff 100644
--- a/tests/suites/test_suite_rsa.data
+++ b/tests/suites/test_suite_rsa.data
@@ -478,7 +478,7 @@
 RSA Import (N,-,-,D,E)
 mbedtls_rsa_import:16:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":16:"":16:"":16:"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC2672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":16:"3":0:1:0:0
 
-RSA Import (N,-,-,D,E), succesive
+RSA Import (N,-,-,D,E), successive
 mbedtls_rsa_import:16:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":16:"":16:"":16:"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC2672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":16:"3":1:1:0:0
 
 RSA Import (N,P,Q,-,E)
@@ -565,7 +565,7 @@
 RSA Export (N,-,-,D,E)
 mbedtls_rsa_export:16:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":16:"":16:"":16:"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC2672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":16:"3":1:0
 
-RSA Export (N,-,-,D,E), succesive
+RSA Export (N,-,-,D,E), successive
 mbedtls_rsa_export:16:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":16:"":16:"":16:"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC2672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":16:"3":1:1
 
 RSA Export (N,P,Q,-,E)
@@ -586,7 +586,7 @@
 RSA Export Raw (N,-,-,D,E)
 mbedtls_rsa_export_raw:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"":"":"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC2672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":"03":1:0
 
-RSA Export Raw (N,-,-,D,E), succesive
+RSA Export Raw (N,-,-,D,E), successive
 mbedtls_rsa_export_raw:"b38ac65c8141f7f5c96e14470e851936a67bf94cc6821a39ac12c05f7c0b06d9e6ddba2224703b02e25f31452f9c4a8417b62675fdc6df46b94813bc7b9769a892c482b830bfe0ad42e46668ace68903617faf6681f4babf1cc8e4b0420d3c7f61dc45434c6b54e2c3ee0fc07908509d79c9826e673bf8363255adb0add2401039a7bcd1b4ecf0fbe6ec8369d2da486eec59559dd1d54c9b24190965eafbdab203b35255765261cd0909acf93c3b8b8428cbb448de4715d1b813d0c94829c229543d391ce0adab5351f97a3810c1f73d7b1458b97daed4209c50e16d064d2d5bfda8c23893d755222793146d0a78c3d64f35549141486c3b0961a7b4c1a2034f":"":"":"77B1D99300D6A54E864962DA09AE10CF19A7FB888456BC2672B72AEA52B204914493D16C184AD201EC3F762E1FBD8702BA796EF953D9EA2F26300D285264F11B0C8301D0207FEB1E2C984445C899B0ACEBAA74EF014DD1D4BDDB43202C08D2FF9692D8D788478DEC829EB52AFB5AE068FBDBAC499A27FACECC391E75C936D55F07BB45EE184DAB45808E15722502F279F89B38C1CB292557E5063597F52C75D61001EDC33F4739353E33E56AD273B067C1A2760208529EA421774A5FFFCB3423B1E0051E7702A55D80CBF2141569F18F87BFF538A1DA8EDBB2693A539F68E0D62D77743F89EACF3B1723BDB25CE2F333FA63CACF0E67DF1A431893BB9B352FCB":"03":1:1
 
 RSA Export Raw (N,P,Q,-,E)