Merge remote-tracking branch 'origin/pr/2464' into development

* origin/pr/2464:
  Allow main() to lack a docstring.
  Silence pylint
  check-files.py: readability improvement in permission check
  check-files.py: use class fields for class-wide constants
  check-files.py: clean up class structure
  abi_check.py: Document more methods
  check-files.py: document some classes and methods
  Fix pylint errors going uncaught
  Call pylint3, not pylint
  New, documented pylint configuration
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 19ab4eb..ecfa40e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -195,6 +195,9 @@
     enable_testing()
 
     add_subdirectory(tests)
+    if(USE_CRYPTO_SUBMODULE)
+        add_subdirectory(crypto/tests)
+    endif()
 
     # additional convenience targets for Unix only
     if(UNIX)
diff --git a/ChangeLog b/ChangeLog
index 606f8f0..3a83ed7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,72 @@
 mbed TLS ChangeLog (Sorted per branch, date)
 
-= mbed TLS 2.x.x branch released xxxx-xx-xx
+= mbed TLS x.x.x branch released xxxx-xx-xx
+
+Features
+   * Add the Any Policy certificate policy oid, as defined in
+     rfc 5280 section 4.2.1.4.
+   * It is now possible to use NIST key wrap mode via the mbedtls_cipher API.
+     Contributed by Jack Lloyd and Fortanix Inc.
+
+Bugfix
+   * Fix private key DER output in the key_app_writer example. File contents
+     were shifted by one byte, creating an invalid ASN.1 tag. Fixed by
+     Christian Walther in #2239.
+   * Fix potential memory leak in X.509 self test. Found and fixed by
+     Junhwan Park, #2106.
+   * Reduce stack usage of hkdf tests. Fixes #2195.
+   * Fix 1-byte buffer overflow in mbedtls_mpi_write_string() when
+     used with negative inputs. Found by Guido Vranken in #2404.
+   * Fix bugs in the AEAD test suite which would be exposed by ciphers which
+     either used both encrypt and decrypt key schedules, or which perform padding.
+     GCM and CCM were not affected. Fixed by Jack Lloyd.
+
+Changes
+   * Server's RSA certificate in certs.c was SHA-1 signed. In the default
+     mbedTLS configuration only SHA-2 signed certificates are accepted.
+     This certificate is used in the demo server programs, which lead the
+     client programs to fail at the peer's certificate verification
+     due to an unacceptable hash signature. The certificate has been
+     updated to one that is SHA-256 signed. Fix contributed by
+     Illya Gerasymchuk.
+   * Return from various debugging routines immediately if the
+     provided SSL context is unset.
+   * Remove dead code from bignum.c in the default configuration.
+     Found by Coverity, reported and fixed by Peter Kolbus (Garmin). Fixes #2309.
+   * Add test for minimal value of MBEDTLS_MPI_WINDOW_SIZE to all.sh.
+     Contributed by Peter Kolbus (Garmin).
+
+= mbed TLS 2.17.0 branch released 2019-03-19
+
+Features
+   * Add a new X.509 API call `mbedtls_x509_parse_der_nocopy()`
+     which allows copy-less parsing of DER encoded X.509 CRTs,
+     at the cost of additional lifetime constraints on the input
+     buffer, but at the benefit of reduced RAM consumption.
+   * Add a new function mbedtls_asn1_write_named_bitstring() to write ASN.1
+     named bitstring in DER as required by RFC 5280 Appendix B.
+   * Add MBEDTLS_REMOVE_3DES_CIPHERSUITES to allow removing 3DES ciphersuites
+     from the default list (enabled by default). See
+     https://sweet32.info/SWEET32_CCS16.pdf.
+
+API Changes
+   * Add a new X.509 API call `mbedtls_x509_parse_der_nocopy()`.
+     See the Features section for more information.
+   * Allow to opt in to the removal the API mbedtls_ssl_get_peer_cert()
+     for the benefit of saving RAM, by disabling the new compile-time
+     option MBEDTLS_SSL_KEEP_PEER_CERTIFICATE (enabled by default for
+     API stability). Disabling this option makes mbedtls_ssl_get_peer_cert()
+     always return NULL, and removes the peer_cert field from the
+     mbedtls_ssl_session structure which otherwise stores the peer's
+     certificate.
+
+Security
+   * Make mbedtls_ecdh_get_params return an error if the second key
+     belongs to a different group from the first. Before, if an application
+     passed keys that belonged to different group, the first key's data was
+     interpreted according to the second group, which could lead to either
+     an error or a meaningless output from mbedtls_ecdh_get_params. In the
+     latter case, this could expose at most 5 bits of the private key.
 
 Bugfix
    * Fix a compilation issue with mbedtls_ecp_restart_ctx not being defined
@@ -19,8 +85,18 @@
      in X.509 module. Fixes #2212.
    * Reduce stack usage of `mpi_write_hlp()` by eliminating recursion.
      Fixes #2190.
+   * Fix false failure in all.sh when backup files exist in include/mbedtls
+     (e.g. config.h.bak). Fixed by Peter Kolbus (Garmin) #2407.
+   * Ensure that unused bits are zero when writing ASN.1 bitstrings when using
+     mbedtls_asn1_write_bitstring().
+   * Fix issue when writing the named bitstrings in KeyUsage and NsCertType
+     extensions in CSRs and CRTs that caused these bitstrings to not be encoded
+     correctly as trailing zeroes were not accounted for as unused bits in the
+     leading content octet. Fixes #1610.
 
 Changes
+   * Reduce RAM consumption during session renegotiation by not storing
+     the peer CRT chain and session ticket twice.
    * Include configuration file in all header files that use configuration,
      instead of relying on other header files that they include.
      Inserted as an enhancement for #1371
@@ -35,6 +111,14 @@
      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.
+   * Reduce the complexity of the timing tests. They were assuming more than the
+     underlying OS actually guarantees.
+   * Fix configuration queries in ssl-opt.h. #2030
+   * Ensure that ssl-opt.h can be run in OS X. #2029
+   * Re-enable certain interoperability tests in ssl-opt.sh which had previously
+     been disabled for lack of a sufficiently recent version of GnuTLS on the CI.
+   * Ciphersuites based on 3DES now have the lowest priority by default when
+     they are enabled.
 
 = mbed TLS 2.16.0 branch released 2018-12-21
 
diff --git a/Makefile b/Makefile
index 87b5a0c..a5b8b61 100644
--- a/Makefile
+++ b/Makefile
@@ -19,6 +19,9 @@
 
 tests: lib
 	$(MAKE) -C tests
+ifdef USE_CRYPTO_SUBMODULE
+	$(MAKE) CRYPTO_INCLUDES:="-I../../include -I../include" -C crypto/tests
+endif
 
 ifndef WINDOWS
 install: no_test
@@ -103,6 +106,9 @@
 
 check: lib tests
 	$(MAKE) -C tests check
+ifdef USE_CRYPTO_SUBMODULE
+	$(MAKE) CRYPTO_INCLUDES:="-I../../include -I../include" -C crypto/tests check
+endif
 
 test: check
 
diff --git a/README.md b/README.md
index 268fcde..91ccf8d 100644
--- a/README.md
+++ b/README.md
@@ -35,7 +35,7 @@
 
     make check
 
-The tests need Perl to be built and run. If you don't have Perl installed, you can skip building the tests with:
+The tests need Python to be built and Perl to be run. If you don't have one of them installed, you can skip building the tests with:
 
     make no_test
 
@@ -65,7 +65,7 @@
 
     make test
 
-The test suites need Perl to be built. If you don't have Perl installed, you'll want to disable the test suites with:
+The test suites need Python to be built and Perl to be executed. If you don't have one of these installed, you'll want to disable the test suites with:
 
     cmake -DENABLE_TESTING=Off /path/to/mbedtls_source
 
@@ -133,7 +133,7 @@
 
 The build files for Microsoft Visual Studio are generated for Visual Studio 2010.
 
-The solution file `mbedTLS.sln` contains all the basic projects needed to build the library and all the programs. The files in tests are not generated and compiled, as these need a perl environment as well. However, the selftest program in `programs/test/` is still available.
+The solution file `mbedTLS.sln` contains all the basic projects needed to build the library and all the programs. The files in tests are not generated and compiled, as these need Python and perl environments as well. However, the selftest program in `programs/test/` is still available.
 
 Example programs
 ----------------
@@ -143,7 +143,7 @@
 Tests
 -----
 
-Mbed TLS includes an elaborate test suite in `tests/` that initially requires Perl to generate the tests files (e.g. `test\_suite\_mpi.c`). These files are generated from a `function file` (e.g. `suites/test\_suite\_mpi.function`) and a `data file` (e.g. `suites/test\_suite\_mpi.data`). The `function file` contains the test functions. The `data file` contains the test cases, specified as parameters that will be passed to the test function.
+Mbed TLS includes an elaborate test suite in `tests/` that initially requires Python to generate the tests files (e.g. `test\_suite\_mpi.c`). These files are generated from a `function file` (e.g. `suites/test\_suite\_mpi.function`) and a `data file` (e.g. `suites/test\_suite\_mpi.data`). The `function file` contains the test functions. The `data file` contains the test cases, specified as parameters that will be passed to the test function.
 
 For machines with a Unix shell and OpenSSL (and optionally GnuTLS) installed, additional test scripts are available:
 
diff --git a/circle.yml b/circle.yml
deleted file mode 100644
index eaed02a..0000000
--- a/circle.yml
+++ /dev/null
@@ -1,44 +0,0 @@
-# Purpose:
-# - To test and prove that a new commit in  the mbed TLS repository builds
-# and integrates with mbed-os properly.
-#           AND
-# - To test and prove that the current development head of mbed TLS builds
-# and integrates with the current mbed-os master branch.
-#
-# The script fetches all the prerequisites and builds the mbed TLS 'tls-client'
-# example. This script is triggered by every commit and once each night and the
-# exact behaviour depends on how it was triggered:
-# - If it is a nightly build then it builds the mbed TLS development head with
-#   mbed-os master.
-# - If it was triggered by the commit, then it builds the example with mbed TLS
-#   at that commit and mbed-os at the commit pointed by mbed-os.lib in the
-#   example repository.
-
-test:
-    override:
-        - cd ../mbed-os-example-tls/tls-client/ && mbed compile -m K64F -t GCC_ARM -c
-
-dependencies:
-    pre:
-        # Install gcc-arm
-        - cd .. && wget "https://launchpad.net/gcc-arm-embedded/4.9/4.9-2015-q3-update/+download/gcc-arm-none-eabi-4_9-2015q3-20150921-linux.tar.bz2"
-        - cd .. && tar -xvjf gcc-arm-none-eabi-4_9-2015q3-20150921-linux.tar.bz2
-        - ln -s ../gcc-arm-none-eabi-4_9-2015q3/bin/* ../bin/
-        # Install mbed-cli
-        - cd ../ && git clone https://github.com/ARMmbed/mbed-cli.git
-        - cd ../mbed-cli && sudo -H pip install -e .
-        # Get the sample application
-        - cd ../ && git clone git@github.com:ARMmbed/mbed-os-example-tls.git
-        # Get mbed-os
-        - cd ../mbed-os-example-tls/tls-client && mbed deploy
-        # Update mbed-os to master only if it is a nightly build
-        - >
-            if [ -n "${RUN_NIGHTLY_BUILD}" ]; then
-                cd ../mbed-os-example-tls/tls-client/mbed-os/ && mbed update master;
-            fi
-        # Import mbedtls current revision
-        - ln -s ../../../../../../../mbedtls/ ../mbed-os-example-tls/tls-client/mbed-os/features/mbedtls/importer/TARGET_IGNORE/mbedtls
-        - cd ../mbed-os-example-tls/tls-client/mbed-os/features/mbedtls/importer/ && make
-    override:
-        # Install the missing python packages
-        - cd ../mbed-os-example-tls/tls-client/mbed-os/ && sudo -H pip install -r requirements.txt
diff --git a/crypto b/crypto
index 0574e6a..82b3b83 160000
--- a/crypto
+++ b/crypto
@@ -1 +1 @@
-Subproject commit 0574e6a7bd0bec47e45bbd30db2e5236896b38ea
+Subproject commit 82b3b83d540ec9611277ca3e9b645b335f80846a
diff --git a/doxygen/input/doc_mainpage.h b/doxygen/input/doc_mainpage.h
index ffc3cec..4eff836 100644
--- a/doxygen/input/doc_mainpage.h
+++ b/doxygen/input/doc_mainpage.h
@@ -24,7 +24,7 @@
  */
 
 /**
- * @mainpage mbed TLS v2.16.0 source code documentation
+ * @mainpage mbed TLS v2.17.0 source code documentation
  *
  * This documentation describes the internal structure of mbed TLS.  It was
  * automatically generated from specially formatted comment blocks in
diff --git a/doxygen/mbedtls.doxyfile b/doxygen/mbedtls.doxyfile
index 574db8d..ce58d6b 100644
--- a/doxygen/mbedtls.doxyfile
+++ b/doxygen/mbedtls.doxyfile
@@ -28,7 +28,7 @@
 # identify the project. Note that if you do not use Doxywizard you need
 # to put quotes around the project name if it contains spaces.
 
-PROJECT_NAME           = "mbed TLS v2.16.0"
+PROJECT_NAME           = "mbed TLS v2.17.0"
 
 # The PROJECT_NUMBER tag can be used to enter a project or revision number.
 # This could be handy for archiving the generated documentation or
diff --git a/include/mbedtls/asn1write.h b/include/mbedtls/asn1write.h
index 360540a..dc81782 100644
--- a/include/mbedtls/asn1write.h
+++ b/include/mbedtls/asn1write.h
@@ -283,6 +283,28 @@
                                   const unsigned char *buf, size_t bits );
 
 /**
+ * \brief           This function writes a named bitstring tag
+ *                  (#MBEDTLS_ASN1_BIT_STRING) and value in ASN.1 format.
+ *
+ *                  As stated in RFC 5280 Appendix B, trailing zeroes are
+ *                  omitted when encoding named bitstrings in DER.
+ *
+ * \note            This function works backwards within the data buffer.
+ *
+ * \param p         The reference to the current position pointer.
+ * \param start     The start of the buffer which is used for bounds-checking.
+ * \param buf       The bitstring to write.
+ * \param bits      The total number of bits in the bitstring.
+ *
+ * \return          The number of bytes written to \p p on success.
+ * \return          A negative error code on failure.
+ */
+int mbedtls_asn1_write_named_bitstring( unsigned char **p,
+                                        unsigned char *start,
+                                        const unsigned char *buf,
+                                        size_t bits );
+
+/**
  * \brief           Write an octet string tag (#MBEDTLS_ASN1_OCTET_STRING)
  *                  and value in ASN.1 format.
  *
diff --git a/include/mbedtls/bignum.h b/include/mbedtls/bignum.h
index a54c18e..c4d7686 100644
--- a/include/mbedtls/bignum.h
+++ b/include/mbedtls/bignum.h
@@ -490,8 +490,24 @@
                              size_t buflen );
 
 /**
- * \brief          Export an MPI into unsigned big endian binary data
- *                 of fixed size.
+ * \brief          Import X from unsigned binary data, little endian
+ *
+ * \param X        The destination MPI. This must point to an initialized MPI.
+ * \param buf      The input buffer. This must be a readable buffer of length
+ *                 \p buflen Bytes.
+ * \param buflen   The length of the input buffer \p p in Bytes.
+ *
+ * \return         \c 0 if successful.
+ * \return         #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed.
+ * \return         Another negative error code on different kinds of failure.
+ */
+int mbedtls_mpi_read_binary_le( mbedtls_mpi *X,
+                                const unsigned char *buf, size_t buflen );
+
+/**
+ * \brief          Export X into unsigned binary data, big endian.
+ *                 Always fills the whole buffer, which will start with zeros
+ *                 if the number is smaller.
  *
  * \param X        The source MPI. This must point to an initialized MPI.
  * \param buf      The output buffer. This must be a writable buffer of length
@@ -507,6 +523,24 @@
                               size_t buflen );
 
 /**
+ * \brief          Export X into unsigned binary data, little endian.
+ *                 Always fills the whole buffer, which will end with zeros
+ *                 if the number is smaller.
+ *
+ * \param X        The source MPI. This must point to an initialized MPI.
+ * \param buf      The output buffer. This must be a writable buffer of length
+ *                 \p buflen Bytes.
+ * \param buflen   The size of the output buffer \p buf in Bytes.
+ *
+ * \return         \c 0 if successful.
+ * \return         #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p buf isn't
+ *                 large enough to hold the value of \p X.
+ * \return         Another negative error code on different kinds of failure.
+ */
+int mbedtls_mpi_write_binary_le( const mbedtls_mpi *X,
+                                 unsigned char *buf, size_t buflen );
+
+/**
  * \brief          Perform a left-shift on an MPI: X <<= count
  *
  * \param X        The MPI to shift. This must point to an initialized MPI.
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index 3d47899..0fa74f0 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -114,14 +114,20 @@
 #endif
 
 #if defined(MBEDTLS_ECP_RESTARTABLE)           && \
-    ( defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT) || \
+    ( defined(MBEDTLS_USE_PSA_CRYPTO)          || \
+      defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT) || \
       defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT)     || \
       defined(MBEDTLS_ECDSA_SIGN_ALT)          || \
       defined(MBEDTLS_ECDSA_VERIFY_ALT)        || \
       defined(MBEDTLS_ECDSA_GENKEY_ALT)        || \
       defined(MBEDTLS_ECP_INTERNAL_ALT)        || \
       defined(MBEDTLS_ECP_ALT) )
-#error "MBEDTLS_ECP_RESTARTABLE defined, but it cannot coexist with an alternative ECP implementation"
+#error "MBEDTLS_ECP_RESTARTABLE defined, but it cannot coexist with an alternative or PSA-based ECP implementation"
+#endif
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)           && \
+    ! defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
+#error "MBEDTLS_ECP_RESTARTABLE defined, but not MBEDTLS_ECDH_LEGACY_CONTEXT"
 #endif
 
 #if defined(MBEDTLS_ECDSA_DETERMINISTIC) && !defined(MBEDTLS_HMAC_DRBG_C)
@@ -279,6 +285,14 @@
 #error "MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED defined, but not all prerequisites"
 #endif
 
+#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) &&        \
+    !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) &&              \
+    ( !defined(MBEDTLS_SHA256_C) &&                             \
+      !defined(MBEDTLS_SHA512_C) &&                             \
+      !defined(MBEDTLS_SHA1_C) )
+#error "!MBEDTLS_SSL_KEEP_PEER_CERTIFICATE requires MBEDTLS_SHA512_C, MBEDTLS_SHA256_C or MBEDTLS_SHA1_C"
+#endif
+
 #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) &&                          \
     ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) )
 #error "MBEDTLS_MEMORY_BUFFER_ALLOC_C defined, but not all prerequisites"
@@ -516,26 +530,25 @@
 #error "MBEDTLS_PSA_CRYPTO_SPM defined, but not all prerequisites"
 #endif
 
-#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C) && defined(MBEDTLS_PSA_CRYPTO_STORAGE_ITS_C)
-#error "Only one of MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C or MBEDTLS_PSA_CRYPTO_STORAGE_ITS_C can be defined"
-#endif
-
 #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) &&            \
-    !( defined(MBEDTLS_PSA_CRYPTO_C) &&                 \
-       ( defined(MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C) ||  \
-         defined(MBEDTLS_PSA_CRYPTO_STORAGE_ITS_C) ) )
+    ! defined(MBEDTLS_PSA_CRYPTO_C)
 #error "MBEDTLS_PSA_CRYPTO_STORAGE_C defined, but not all prerequisites"
 #endif
 
-#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C) &&            \
-    !( defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) &&           \
-       defined(MBEDTLS_FS_IO) )
-#error "MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C defined, but not all prerequisites"
+#if defined(MBEDTLS_PSA_INJECT_ENTROPY) &&      \
+    !( defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) && \
+       defined(MBEDTLS_ENTROPY_NV_SEED) )
+#error "MBEDTLS_PSA_INJECT_ENTROPY defined, but not all prerequisites"
 #endif
 
-#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_ITS_C) &&             \
-    ! defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
-#error "MBEDTLS_PSA_CRYPTO_STORAGE_ITS_C defined, but not all prerequisites"
+#if defined(MBEDTLS_PSA_INJECT_ENTROPY) &&              \
+    !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES)
+#error "MBEDTLS_PSA_INJECT_ENTROPY is not compatible with actual entropy sources"
+#endif
+
+#if defined(MBEDTLS_PSA_ITS_FILE_C) && \
+    !defined(MBEDTLS_FS_IO)
+#error "MBEDTLS_PSA_ITS_FILE_C defined, but not all prerequisites"
 #endif
 
 #if defined(MBEDTLS_RSA_C) && ( !defined(MBEDTLS_BIGNUM_C) ||         \
diff --git a/include/mbedtls/cipher.h b/include/mbedtls/cipher.h
index 2d609db..ea00703 100644
--- a/include/mbedtls/cipher.h
+++ b/include/mbedtls/cipher.h
@@ -176,6 +176,12 @@
     MBEDTLS_CIPHER_AES_256_XTS,          /**< AES 256-bit cipher in XTS block mode. */
     MBEDTLS_CIPHER_CHACHA20,             /**< ChaCha20 stream cipher. */
     MBEDTLS_CIPHER_CHACHA20_POLY1305,    /**< ChaCha20-Poly1305 AEAD cipher. */
+    MBEDTLS_CIPHER_AES_128_KW,           /**< AES cipher with 128-bit NIST KW mode. */
+    MBEDTLS_CIPHER_AES_192_KW,           /**< AES cipher with 192-bit NIST KW mode. */
+    MBEDTLS_CIPHER_AES_256_KW,           /**< AES cipher with 256-bit NIST KW mode. */
+    MBEDTLS_CIPHER_AES_128_KWP,          /**< AES cipher with 128-bit NIST KWP mode. */
+    MBEDTLS_CIPHER_AES_192_KWP,          /**< AES cipher with 192-bit NIST KWP mode. */
+    MBEDTLS_CIPHER_AES_256_KWP,          /**< AES cipher with 256-bit NIST KWP mode. */
 } mbedtls_cipher_type_t;
 
 /** Supported cipher modes. */
@@ -191,6 +197,8 @@
     MBEDTLS_MODE_CCM,                    /**< The CCM cipher mode.         */
     MBEDTLS_MODE_XTS,                    /**< The XTS cipher mode.         */
     MBEDTLS_MODE_CHACHAPOLY,             /**< The ChaCha-Poly cipher mode. */
+    MBEDTLS_MODE_KW,                     /**< The SP800-38F KW mode */
+    MBEDTLS_MODE_KWP,                    /**< The SP800-38F KWP mode */
 } mbedtls_cipher_mode_t;
 
 /** Supported cipher padding types. */
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index e6abf24..0fe2574 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -688,6 +688,26 @@
 #define MBEDTLS_REMOVE_ARC4_CIPHERSUITES
 
 /**
+ * \def MBEDTLS_REMOVE_3DES_CIPHERSUITES
+ *
+ * Remove 3DES ciphersuites by default in SSL / TLS.
+ * This flag removes the ciphersuites based on 3DES from the default list as
+ * returned by mbedtls_ssl_list_ciphersuites(). However, it is still possible
+ * to enable (some of) them with mbedtls_ssl_conf_ciphersuites() by including
+ * them explicitly.
+ *
+ * A man-in-the-browser attacker can recover authentication tokens sent through
+ * a TLS connection using a 3DES based cipher suite (see "On the Practical
+ * (In-)Security of 64-bit Block Ciphers" by Karthikeyan Bhargavan and Gaëtan
+ * Leurent, see https://sweet32.info/SWEET32_CCS16.pdf). If this attack falls
+ * in your threat model or you are unsure, then you should keep this option
+ * enabled to remove 3DES based cipher suites.
+ *
+ * Comment this macro to keep 3DES in the default ciphersuite list.
+ */
+#define MBEDTLS_REMOVE_3DES_CIPHERSUITES
+
+/**
  * \def MBEDTLS_ECP_DP_SECP192R1_ENABLED
  *
  * MBEDTLS_ECP_XXXX_ENABLED: Enables specific curves within the Elliptic Curve
@@ -740,11 +760,40 @@
  *
  * \note  This option only works with the default software implementation of
  *        elliptic curve functionality. It is incompatible with
- *        MBEDTLS_ECP_ALT, MBEDTLS_ECDH_XXX_ALT and MBEDTLS_ECDSA_XXX_ALT.
+ *        MBEDTLS_ECP_ALT, MBEDTLS_ECDH_XXX_ALT, MBEDTLS_ECDSA_XXX_ALT
+ *        and MBEDTLS_ECDH_LEGACY_CONTEXT.
  */
 //#define MBEDTLS_ECP_RESTARTABLE
 
 /**
+ * \def MBEDTLS_ECDH_LEGACY_CONTEXT
+ *
+ * Use a backward compatible ECDH context.
+ *
+ * Mbed TLS supports two formats for ECDH contexts (#mbedtls_ecdh_context
+ * defined in `ecdh.h`). For most applications, the choice of format makes
+ * no difference, since all library functions can work with either format,
+ * except that the new format is incompatible with MBEDTLS_ECP_RESTARTABLE.
+
+ * The new format used when this option is disabled is smaller
+ * (56 bytes on a 32-bit platform). In future versions of the library, it
+ * will support alternative implementations of ECDH operations.
+ * The new format is incompatible with applications that access
+ * context fields directly and with restartable ECP operations.
+ *
+ * Define this macro if you enable MBEDTLS_ECP_RESTARTABLE or if you
+ * want to access ECDH context fields directly. Otherwise you should
+ * comment out this macro definition.
+ *
+ * This option has no effect if #MBEDTLS_ECDH_C is not enabled.
+ *
+ * \note This configuration option is experimental. Future versions of the
+ *       library may modify the way the ECDH context layout is configured
+ *       and may modify the layout of the new context type.
+ */
+#define MBEDTLS_ECDH_LEGACY_CONTEXT
+
+/**
  * \def MBEDTLS_ECDSA_DETERMINISTIC
  *
  * Enable deterministic ECDSA (RFC 6979).
@@ -1217,14 +1266,17 @@
 //#define MBEDTLS_PSA_CRYPTO_SPM
 
 /**
- * \def MBEDTLS_PSA_HAS_ITS_IO
+ * \def MBEDTLS_PSA_INJECT_ENTROPY
  *
- * Enable the non-volatile secure storage usage.
+ * Enable support for entropy injection at first boot. This feature is
+ * required on systems that do not have a built-in entropy source (TRNG).
+ * This feature is currently not supported on systems that have a built-in
+ * entropy source.
  *
- * This is crucial on systems that do not have a HW TRNG support.
+ * Requires: MBEDTLS_PSA_CRYPTO_STORAGE_C, MBEDTLS_ENTROPY_NV_SEED
  *
  */
-//#define MBEDTLS_PSA_HAS_ITS_IO
+//#define MBEDTLS_PSA_INJECT_ENTROPY
 
 /**
  * \def MBEDTLS_RSA_NO_CRT
@@ -1355,6 +1407,28 @@
 #define MBEDTLS_SSL_FALLBACK_SCSV
 
 /**
+ * \def MBEDTLS_SSL_KEEP_PEER_CERTIFICATE
+ *
+ * This option controls the availability of the API mbedtls_ssl_get_peer_cert()
+ * giving access to the peer's certificate after completion of the handshake.
+ *
+ * Unless you need mbedtls_ssl_peer_cert() in your application, it is
+ * recommended to disable this option for reduced RAM usage.
+ *
+ * \note If this option is disabled, mbedtls_ssl_get_peer_cert() is still
+ *       defined, but always returns \c NULL.
+ *
+ * \note This option has no influence on the protection against the
+ *       triple handshake attack. Even if it is disabled, Mbed TLS will
+ *       still ensure that certificates do not change during renegotiation,
+ *       for exaple by keeping a hash of the peer's certificate.
+ *
+ * Comment this macro to disable storing the peer's certificate
+ * after the handshake.
+ */
+#define MBEDTLS_SSL_KEEP_PEER_CERTIFICATE
+
+/**
  * \def MBEDTLS_SSL_HW_RECORD_ACCEL
  *
  * Enable hooking functions in SSL module for hardware acceleration of
@@ -2699,40 +2773,26 @@
  *
  * Enable the Platform Security Architecture persistent key storage.
  *
- * Module:  library/psa_crypto_storage.c
+ * Module:  crypto/library/psa_crypto_storage.c
  *
- * Requires: MBEDTLS_PSA_CRYPTO_C and one of either
- * MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C or MBEDTLS_PSA_CRYPTO_STORAGE_ITS_C
- * (but not both)
- *
+ * Requires: MBEDTLS_PSA_CRYPTO_C,
+ *           either MBEDTLS_PSA_ITS_FILE_C or a native implementation of
+ *           the PSA ITS interface
  */
 //#define MBEDTLS_PSA_CRYPTO_STORAGE_C
 
 /**
- * \def MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C
+ * \def MBEDTLS_PSA_ITS_FILE_C
  *
- * Enable persistent key storage over files for the
- * Platform Security Architecture cryptography API.
+ * Enable the emulation of the Platform Security Architecture
+ * Internal Trusted Storage (PSA ITS) over files.
  *
- * Module:  library/psa_crypto_storage_file.c
+ * Module:  crypto/library/psa_its_file.c
  *
- * Requires: MBEDTLS_PSA_CRYPTO_C, MBEDTLS_FS_IO
+ * Requires: MBEDTLS_FS_IO
  *
  */
-//#define MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C
-
-/**
- * \def MBEDTLS_PSA_CRYPTO_STORAGE_ITS_C
- *
- * Enable persistent key storage over PSA ITS for the
- * Platform Security Architecture cryptography API.
- *
- * Module:  library/psa_crypto_storage_its.c
- *
- * Requires: MBEDTLS_PSA_CRYPTO_C, MBEDTLS_PSA_HAS_ITS_IO
- *
- */
-//#define MBEDTLS_PSA_CRYPTO_STORAGE_ITS_C
+//#define MBEDTLS_PSA_ITS_FILE_C
 
 /**
  * \def MBEDTLS_RIPEMD160_C
diff --git a/include/mbedtls/ecdh.h b/include/mbedtls/ecdh.h
index 4479a1d..384c3dc 100644
--- a/include/mbedtls/ecdh.h
+++ b/include/mbedtls/ecdh.h
@@ -42,18 +42,6 @@
 
 #include "ecp.h"
 
-/*
- * Use a backward compatible ECDH context.
- *
- * This flag is always enabled for now and future versions might add a
- * configuration option that conditionally undefines this flag.
- * The configuration option in question may have a different name.
- *
- * Features undefining this flag, must have a warning in their description in
- * config.h stating that the feature breaks backward compatibility.
- */
-#define MBEDTLS_ECDH_LEGACY_CONTEXT
-
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h
index 2401778..0b2504e 100644
--- a/include/mbedtls/ecp.h
+++ b/include/mbedtls/ecp.h
@@ -99,6 +99,16 @@
  */
 #define MBEDTLS_ECP_DP_MAX     12
 
+/*
+ * Curve types
+ */
+typedef enum
+{
+    MBEDTLS_ECP_TYPE_NONE = 0,
+    MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS,    /* y^2 = x^3 + a x + b      */
+    MBEDTLS_ECP_TYPE_MONTGOMERY,           /* y^2 = x^3 + a x^2 + x    */
+} mbedtls_ecp_curve_type;
+
 /**
  * Curve information, for use by other modules.
  */
@@ -417,6 +427,11 @@
 int mbedtls_ecp_restart_is_enabled( void );
 #endif /* MBEDTLS_ECP_RESTARTABLE */
 
+/*
+ * Get the type of a curve
+ */
+mbedtls_ecp_curve_type mbedtls_ecp_get_type( const mbedtls_ecp_group *grp );
+
 /**
  * \brief           This function retrieves the information defined in
  *                  mbedtls_ecp_curve_info() for all supported curves in order
@@ -482,7 +497,7 @@
  *
  * \note            After this function is called, domain parameters
  *                  for various ECP groups can be loaded through the
- *                  mbedtls_ecp_load() or mbedtls_ecp_tls_read_group()
+ *                  mbedtls_ecp_group_load() or mbedtls_ecp_tls_read_group()
  *                  functions.
  */
 void mbedtls_ecp_group_init( mbedtls_ecp_group *grp );
@@ -626,6 +641,9 @@
  * \param P         The point to export. This must be initialized.
  * \param format    The point format. This must be either
  *                  #MBEDTLS_ECP_PF_COMPRESSED or #MBEDTLS_ECP_PF_UNCOMPRESSED.
+ *                  (For groups without these formats, this parameter is
+ *                  ignored. But it still has to be either of the above
+ *                  values.)
  * \param olen      The address at which to store the length of
  *                  the output in Bytes. This must not be \c NULL.
  * \param buf       The output buffer. This must be a writable buffer
@@ -635,11 +653,14 @@
  * \return          \c 0 on success.
  * \return          #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the output buffer
  *                  is too small to hold the point.
+ * \return          #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the point format
+ *                  or the export for the given group is not implemented.
  * \return          Another negative error code on other kinds of failure.
  */
-int mbedtls_ecp_point_write_binary( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *P,
-                            int format, size_t *olen,
-                            unsigned char *buf, size_t buflen );
+int mbedtls_ecp_point_write_binary( const mbedtls_ecp_group *grp,
+                                    const mbedtls_ecp_point *P,
+                                    int format, size_t *olen,
+                                    unsigned char *buf, size_t buflen );
 
 /**
  * \brief           This function imports a point from unsigned binary data.
@@ -660,8 +681,8 @@
  * \return          \c 0 on success.
  * \return          #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the input is invalid.
  * \return          #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure.
- * \return          #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the point format
- *                  is not implemented.
+ * \return          #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the import for the
+ *                  given group is not implemented.
  */
 int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp,
                                    mbedtls_ecp_point *P,
@@ -1094,6 +1115,26 @@
                          void *p_rng );
 
 /**
+ * \brief           This function reads an elliptic curve private key.
+ *
+ * \param grp_id    The ECP group identifier.
+ * \param key       The destination key.
+ * \param buf       The the buffer containing the binary representation of the
+ *                  key. (Big endian integer for Weierstrass curves, byte
+ *                  string for Montgomery curves.)
+ * \param buflen    The length of the buffer in bytes.
+ *
+ * \return          \c 0 on success.
+ * \return          #MBEDTLS_ERR_ECP_INVALID_KEY error if the key is
+ *                  invalid.
+ * \return          #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed.
+ * \return          #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the operation for
+ *                  the group is not implemented.
+ * \return          Another negative error code on different kinds of failure.
+ */
+int mbedtls_ecp_read_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key,
+                          const unsigned char *buf, size_t buflen );
+/**
  * \brief           This function checks that the keypair objects
  *                  \p pub and \p prv have the same group and the
  *                  same public point, and that the private key in
diff --git a/include/mbedtls/oid.h b/include/mbedtls/oid.h
index 6fbd018..342ef75 100644
--- a/include/mbedtls/oid.h
+++ b/include/mbedtls/oid.h
@@ -43,13 +43,31 @@
 #include "md.h"
 #endif
 
-#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
-#include "x509.h"
-#endif
-
 #define MBEDTLS_ERR_OID_NOT_FOUND                         -0x002E  /**< OID is not found. */
 #define MBEDTLS_ERR_OID_BUF_TOO_SMALL                     -0x000B  /**< output buffer is too small */
 
+/* This is for the benefit of X.509, but defined here in order to avoid
+ * having a "backwards" include of x.509.h here */
+/*
+ * X.509 extension types (internal, arbitrary values for bitsets)
+ */
+#define MBEDTLS_OID_X509_EXT_AUTHORITY_KEY_IDENTIFIER    (1 << 0)
+#define MBEDTLS_OID_X509_EXT_SUBJECT_KEY_IDENTIFIER      (1 << 1)
+#define MBEDTLS_OID_X509_EXT_KEY_USAGE                   (1 << 2)
+#define MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES        (1 << 3)
+#define MBEDTLS_OID_X509_EXT_POLICY_MAPPINGS             (1 << 4)
+#define MBEDTLS_OID_X509_EXT_SUBJECT_ALT_NAME            (1 << 5)
+#define MBEDTLS_OID_X509_EXT_ISSUER_ALT_NAME             (1 << 6)
+#define MBEDTLS_OID_X509_EXT_SUBJECT_DIRECTORY_ATTRS     (1 << 7)
+#define MBEDTLS_OID_X509_EXT_BASIC_CONSTRAINTS           (1 << 8)
+#define MBEDTLS_OID_X509_EXT_NAME_CONSTRAINTS            (1 << 9)
+#define MBEDTLS_OID_X509_EXT_POLICY_CONSTRAINTS          (1 << 10)
+#define MBEDTLS_OID_X509_EXT_EXTENDED_KEY_USAGE          (1 << 11)
+#define MBEDTLS_OID_X509_EXT_CRL_DISTRIBUTION_POINTS     (1 << 12)
+#define MBEDTLS_OID_X509_EXT_INIHIBIT_ANYPOLICY          (1 << 13)
+#define MBEDTLS_OID_X509_EXT_FRESHEST_CRL                (1 << 14)
+#define MBEDTLS_OID_X509_EXT_NS_CERT_TYPE                (1 << 16)
+
 /*
  * Top level OID tuples
  */
@@ -150,6 +168,11 @@
 #define MBEDTLS_OID_FRESHEST_CRL                MBEDTLS_OID_ID_CE "\x2E" /**< id-ce-freshestCRL OBJECT IDENTIFIER ::=  { id-ce 46 } */
 
 /*
+ * Certificate policies
+ */
+#define MBEDTLS_OID_ANY_POLICY              MBEDTLS_OID_CERTIFICATE_POLICIES "\x00" /**< anyPolicy OBJECT IDENTIFIER ::= { id-ce-certificatePolicies 0 } */
+
+/*
  * Netscape certificate extensions
  */
 #define MBEDTLS_OID_NS_CERT                 MBEDTLS_OID_NETSCAPE "\x01"
@@ -424,7 +447,6 @@
  */
 int mbedtls_oid_get_numeric_string( char *buf, size_t size, const mbedtls_asn1_buf *oid );
 
-#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
 /**
  * \brief          Translate an X.509 extension OID into local values
  *
@@ -434,7 +456,6 @@
  * \return         0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
  */
 int mbedtls_oid_get_x509_ext_type( const mbedtls_asn1_buf *oid, int *ext_type );
-#endif
 
 /**
  * \brief          Translate an X.509 attribute type OID into the short name
@@ -561,6 +582,16 @@
 int mbedtls_oid_get_extended_key_usage( const mbedtls_asn1_buf *oid, const char **desc );
 
 /**
+ * \brief          Translate certificate policies OID into description
+ *
+ * \param oid      OID to use
+ * \param desc     place to store string pointer
+ *
+ * \return         0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND
+ */
+int mbedtls_oid_get_certificate_policies( const mbedtls_asn1_buf *oid, const char **desc );
+
+/**
  * \brief          Translate md_type into hash algorithm OID
  *
  * \param md_alg   message digest algorithm
diff --git a/include/mbedtls/psa_util.h b/include/mbedtls/psa_util.h
index fbf25e6..b0c0428 100644
--- a/include/mbedtls/psa_util.h
+++ b/include/mbedtls/psa_util.h
@@ -43,6 +43,8 @@
 #include "pk.h"
 #include "oid.h"
 
+#include <string.h>
+
 /* Translations for symmetric crypto. */
 
 static inline psa_key_type_t mbedtls_psa_translate_cipher_type(
@@ -233,6 +235,86 @@
      return( -1 );
 }
 
+#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH 1
+
+#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED)
+#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 192 + 7 ) / 8 ) + 1 )
+#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH
+#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 192 + 7 ) / 8 ) + 1 )
+#endif
+#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED)
+#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 224 + 7 ) / 8 ) + 1 )
+#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH
+#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 224 + 7 ) / 8 ) + 1 )
+#endif
+#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED)
+#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 256 + 7 ) / 8 ) + 1 )
+#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH
+#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 256 + 7 ) / 8 ) + 1 )
+#endif
+#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED)
+#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 384 + 7 ) / 8 ) + 1 )
+#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH
+#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 384 + 7 ) / 8 ) + 1 )
+#endif
+#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED)
+#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 521 + 7 ) / 8 ) + 1 )
+#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH
+#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 521 + 7 ) / 8 ) + 1 )
+#endif
+#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED)
+#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 192 + 7 ) / 8 ) + 1 )
+#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH
+#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 192 + 7 ) / 8 ) + 1 )
+#endif
+#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED)
+#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 224 + 7 ) / 8 ) + 1 )
+#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH
+#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 224 + 7 ) / 8 ) + 1 )
+#endif
+#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED)
+#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 256 + 7 ) / 8 ) + 1 )
+#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH
+#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 256 + 7 ) / 8 ) + 1 )
+#endif
+#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED)
+#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 256 + 7 ) / 8 ) + 1 )
+#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH
+#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 256 + 7 ) / 8 ) + 1 )
+#endif
+#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED)
+#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 384 + 7 ) / 8 ) + 1 )
+#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH
+#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 384 + 7 ) / 8 ) + 1 )
+#endif
+#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED)
+#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 512 + 7 ) / 8 ) + 1 )
+#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH
+#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 512 + 7 ) / 8 ) + 1 )
+#endif
+#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */
+
+
 static inline psa_ecc_curve_t mbedtls_psa_translate_ecc_group( mbedtls_ecp_group_id grpid )
 {
     switch( grpid )
@@ -294,6 +376,7 @@
     }
 }
 
+
 #define MBEDTLS_PSA_ECC_KEY_BITS_OF_CURVE( curve )                \
     ( curve == PSA_ECC_CURVE_SECP192R1        ? 192 :             \
       curve == PSA_ECC_CURVE_SECP224R1        ? 224 :             \
@@ -352,6 +435,48 @@
     return( (psa_ecc_curve_t) tls_ecc_grp_reg_id );
 }
 
+/* This function takes a buffer holding an EC public key
+ * exported through psa_export_public_key(), and converts
+ * it into an ECPoint structure to be put into a ClientKeyExchange
+ * message in an ECDHE exchange.
+ *
+ * Both the present and the foreseeable future format of EC public keys
+ * used by PSA have the ECPoint structure contained in the exported key
+ * as a subbuffer, and the function merely selects this subbuffer instead
+ * of making a copy.
+ */
+static inline int mbedtls_psa_tls_psa_ec_to_ecpoint( unsigned char *src,
+                                                     size_t srclen,
+                                                     unsigned char **dst,
+                                                     size_t *dstlen )
+{
+    *dst = src;
+    *dstlen = srclen;
+    return( 0 );
+}
+
+/* This function takes a buffer holding an ECPoint structure
+ * (as contained in a TLS ServerKeyExchange message for ECDHE
+ * exchanges) and converts it into a format that the PSA key
+ * agreement API understands.
+ */
+static inline int mbedtls_psa_tls_ecpoint_to_psa_ec( psa_ecc_curve_t curve,
+                                                     unsigned char const *src,
+                                                     size_t srclen,
+                                                     unsigned char *dst,
+                                                     size_t dstlen,
+                                                     size_t *olen )
+{
+    ((void) curve);
+
+    if( srclen > dstlen )
+        return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
+
+    memcpy( dst, src, srclen );
+    *olen = srclen;
+    return( 0 );
+}
+
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
 #endif /* MBEDTLS_PSA_UTIL_H */
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 46007a7..b793ac0 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -787,6 +787,25 @@
 typedef void mbedtls_ssl_async_cancel_t( mbedtls_ssl_context *ssl );
 #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
 
+#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) &&        \
+    !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+#define MBEDTLS_SSL_PEER_CERT_DIGEST_MAX_LEN  48
+#if defined(MBEDTLS_SHA256_C)
+#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE MBEDTLS_MD_SHA256
+#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN  32
+#elif defined(MBEDTLS_SHA512_C)
+#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE MBEDTLS_MD_SHA384
+#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN  48
+#elif defined(MBEDTLS_SHA1_C)
+#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE MBEDTLS_MD_SHA1
+#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN  20
+#else
+/* This is already checked in check_config.h, but be sure. */
+#error "Bad configuration - need SHA-1, SHA-256 or SHA-512 enabled to compute digest of peer CRT."
+#endif
+#endif /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED &&
+          !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+
 /*
  * This structure is used for storing current session data.
  */
@@ -802,7 +821,15 @@
     unsigned char master[48];   /*!< the master secret  */
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
-    mbedtls_x509_crt *peer_cert;        /*!< peer X.509 cert chain */
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    mbedtls_x509_crt *peer_cert;       /*!< peer X.509 cert chain */
+#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+    /*! The digest of the peer's end-CRT. This must be kept to detect CRT
+     *  changes during renegotiation, mitigating the triple handshake attack. */
+    unsigned char *peer_cert_digest;
+    size_t peer_cert_digest_len;
+    mbedtls_md_type_t peer_cert_digest_type;
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
     uint32_t verify_result;          /*!<  verification result     */
 
@@ -2972,18 +2999,34 @@
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
 /**
- * \brief          Return the peer certificate from the current connection
+ * \brief          Return the peer certificate from the current connection.
  *
- *                 Note: Can be NULL in case no certificate was sent during
- *                 the handshake. Different calls for the same connection can
- *                 return the same or different pointers for the same
- *                 certificate and even a different certificate altogether.
- *                 The peer cert CAN change in a single connection if
- *                 renegotiation is performed.
+ * \param  ssl     The SSL context to use. This must be initialized and setup.
  *
- * \param ssl      SSL context
+ * \return         The current peer certificate, if available.
+ *                 The returned certificate is owned by the SSL context and
+ *                 is valid only until the next call to the SSL API.
+ * \return         \c NULL if no peer certificate is available. This might
+ *                 be because the chosen ciphersuite doesn't use CRTs
+ *                 (PSK-based ciphersuites, for example), or because
+ *                 #MBEDTLS_SSL_KEEP_PEER_CERTIFICATE has been disabled,
+ *                 allowing the stack to free the peer's CRT to save memory.
  *
- * \return         the current peer certificate
+ * \note           For one-time inspection of the peer's certificate during
+ *                 the handshake, consider registering an X.509 CRT verification
+ *                 callback through mbedtls_ssl_conf_verify() instead of calling
+ *                 this function. Using mbedtls_ssl_conf_verify() also comes at
+ *                 the benefit of allowing you to influence the verification
+ *                 process, for example by masking expected and tolerated
+ *                 verification failures.
+ *
+ * \warning        You must not use the pointer returned by this function
+ *                 after any further call to the SSL API, including
+ *                 mbedtls_ssl_read() and mbedtls_ssl_write(); this is
+ *                 because the pointer might change during renegotiation,
+ *                 which happens transparently to the user.
+ *                 If you want to use the certificate across API calls,
+ *                 you must make a copy.
  */
 const mbedtls_x509_crt *mbedtls_ssl_get_peer_cert( const mbedtls_ssl_context *ssl );
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
diff --git a/include/mbedtls/ssl_cache.h b/include/mbedtls/ssl_cache.h
index 52ba094..84254d3 100644
--- a/include/mbedtls/ssl_cache.h
+++ b/include/mbedtls/ssl_cache.h
@@ -70,7 +70,8 @@
     mbedtls_time_t timestamp;           /*!< entry timestamp    */
 #endif
     mbedtls_ssl_session session;        /*!< entry session      */
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
+    defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
     mbedtls_x509_buf peer_cert;         /*!< entry peer_cert    */
 #endif
     mbedtls_ssl_cache_entry *next;      /*!< chain pointer      */
diff --git a/include/mbedtls/ssl_ciphersuites.h b/include/mbedtls/ssl_ciphersuites.h
index 71053e5..7126783 100644
--- a/include/mbedtls/ssl_ciphersuites.h
+++ b/include/mbedtls/ssl_ciphersuites.h
@@ -486,6 +486,24 @@
     }
 }
 
+static inline int mbedtls_ssl_ciphersuite_uses_srv_cert( const mbedtls_ssl_ciphersuite_t *info )
+{
+    switch( info->key_exchange )
+    {
+        case MBEDTLS_KEY_EXCHANGE_RSA:
+        case MBEDTLS_KEY_EXCHANGE_RSA_PSK:
+        case MBEDTLS_KEY_EXCHANGE_DHE_RSA:
+        case MBEDTLS_KEY_EXCHANGE_ECDH_RSA:
+        case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA:
+        case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA:
+        case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA:
+            return( 1 );
+
+        default:
+            return( 0 );
+    }
+}
+
 #if defined(MBEDTLS_KEY_EXCHANGE__SOME__DHE_ENABLED)
 static inline int mbedtls_ssl_ciphersuite_uses_dhe( const mbedtls_ssl_ciphersuite_t *info )
 {
diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h
index 3159cd3..5dde239 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -57,6 +57,11 @@
 #include "ecjpake.h"
 #endif
 
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+#include "psa/crypto.h"
+#include "psa_util.h"
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
 #if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
     !defined(inline) && !defined(__cplusplus)
 #define inline __inline
@@ -280,7 +285,15 @@
 #endif
 #if defined(MBEDTLS_ECDH_C)
     mbedtls_ecdh_context ecdh_ctx;              /*!<  ECDH key exchange       */
-#endif
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    psa_ecc_curve_t ecdh_psa_curve;
+    psa_key_handle_t ecdh_psa_privkey;
+    unsigned char ecdh_psa_peerkey[MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH];
+    size_t ecdh_psa_peerkey_len;
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+#endif /* MBEDTLS_ECDH_C */
+
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
     mbedtls_ecjpake_context ecjpake_ctx;        /*!< EC J-PAKE key exchange */
 #if defined(MBEDTLS_SSL_CLI_C)
@@ -318,8 +331,13 @@
         ssl_ecrs_cke_ecdh_calc_secret,  /*!< ClientKeyExchange: ECDH step 2 */
         ssl_ecrs_crt_vrfy_sign,         /*!< CertificateVerify: pk_sign()   */
     } ecrs_state;                       /*!< current (or last) operation    */
+    mbedtls_x509_crt *ecrs_peer_cert;   /*!< The peer's CRT chain.          */
     size_t ecrs_n;                      /*!< place for saving a length      */
 #endif
+#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
+    !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    mbedtls_pk_context peer_pubkey;     /*!< The public key from the peer.  */
+#endif /* MBEDTLS_X509_CRT_PARSE_C && !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
     unsigned int out_msg_seq;           /*!<  Outgoing handshake sequence number */
     unsigned int in_msg_seq;            /*!<  Incoming handshake sequence number */
@@ -753,6 +771,9 @@
 void mbedtls_ssl_dtls_replay_update( mbedtls_ssl_context *ssl );
 #endif
 
+int mbedtls_ssl_session_copy( mbedtls_ssl_session *dst,
+                              const mbedtls_ssl_session *src );
+
 /* constant-time buffer comparison */
 static inline int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n )
 {
diff --git a/include/mbedtls/version.h b/include/mbedtls/version.h
index 56e7398..79b42b2 100644
--- a/include/mbedtls/version.h
+++ b/include/mbedtls/version.h
@@ -39,7 +39,7 @@
  * Major, Minor, Patchlevel
  */
 #define MBEDTLS_VERSION_MAJOR  2
-#define MBEDTLS_VERSION_MINOR  16
+#define MBEDTLS_VERSION_MINOR  17
 #define MBEDTLS_VERSION_PATCH  0
 
 /**
@@ -47,9 +47,9 @@
  *    MMNNPP00
  *    Major version | Minor version | Patch version
  */
-#define MBEDTLS_VERSION_NUMBER         0x02100000
-#define MBEDTLS_VERSION_STRING         "2.16.0"
-#define MBEDTLS_VERSION_STRING_FULL    "mbed TLS 2.16.0"
+#define MBEDTLS_VERSION_NUMBER         0x02110000
+#define MBEDTLS_VERSION_STRING         "2.17.0"
+#define MBEDTLS_VERSION_STRING_FULL    "mbed TLS 2.17.0"
 
 #if defined(MBEDTLS_VERSION_C)
 
diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h
index 63aae32..b63e864 100644
--- a/include/mbedtls/x509.h
+++ b/include/mbedtls/x509.h
@@ -142,24 +142,26 @@
  *
  * Comments refer to the status for using certificates. Status can be
  * different for writing certificates or reading CRLs or CSRs.
+ *
+ * Those are defined in oid.h as oid.c needs them in a data structure. Since
+ * these were previously defined here, let's have aliases for compatibility.
  */
-#define MBEDTLS_X509_EXT_AUTHORITY_KEY_IDENTIFIER    (1 << 0)
-#define MBEDTLS_X509_EXT_SUBJECT_KEY_IDENTIFIER      (1 << 1)
-#define MBEDTLS_X509_EXT_KEY_USAGE                   (1 << 2)
-#define MBEDTLS_X509_EXT_CERTIFICATE_POLICIES        (1 << 3)
-#define MBEDTLS_X509_EXT_POLICY_MAPPINGS             (1 << 4)
-#define MBEDTLS_X509_EXT_SUBJECT_ALT_NAME            (1 << 5)    /* Supported (DNS) */
-#define MBEDTLS_X509_EXT_ISSUER_ALT_NAME             (1 << 6)
-#define MBEDTLS_X509_EXT_SUBJECT_DIRECTORY_ATTRS     (1 << 7)
-#define MBEDTLS_X509_EXT_BASIC_CONSTRAINTS           (1 << 8)    /* Supported */
-#define MBEDTLS_X509_EXT_NAME_CONSTRAINTS            (1 << 9)
-#define MBEDTLS_X509_EXT_POLICY_CONSTRAINTS          (1 << 10)
-#define MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE          (1 << 11)
-#define MBEDTLS_X509_EXT_CRL_DISTRIBUTION_POINTS     (1 << 12)
-#define MBEDTLS_X509_EXT_INIHIBIT_ANYPOLICY          (1 << 13)
-#define MBEDTLS_X509_EXT_FRESHEST_CRL                (1 << 14)
-
-#define MBEDTLS_X509_EXT_NS_CERT_TYPE                (1 << 16)
+#define MBEDTLS_X509_EXT_AUTHORITY_KEY_IDENTIFIER MBEDTLS_OID_X509_EXT_AUTHORITY_KEY_IDENTIFIER
+#define MBEDTLS_X509_EXT_SUBJECT_KEY_IDENTIFIER   MBEDTLS_OID_X509_EXT_SUBJECT_KEY_IDENTIFIER
+#define MBEDTLS_X509_EXT_KEY_USAGE                MBEDTLS_OID_X509_EXT_KEY_USAGE
+#define MBEDTLS_X509_EXT_CERTIFICATE_POLICIES     MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES
+#define MBEDTLS_X509_EXT_POLICY_MAPPINGS          MBEDTLS_OID_X509_EXT_POLICY_MAPPINGS
+#define MBEDTLS_X509_EXT_SUBJECT_ALT_NAME         MBEDTLS_OID_X509_EXT_SUBJECT_ALT_NAME         /* Supported (DNS) */
+#define MBEDTLS_X509_EXT_ISSUER_ALT_NAME          MBEDTLS_OID_X509_EXT_ISSUER_ALT_NAME
+#define MBEDTLS_X509_EXT_SUBJECT_DIRECTORY_ATTRS  MBEDTLS_OID_X509_EXT_SUBJECT_DIRECTORY_ATTRS
+#define MBEDTLS_X509_EXT_BASIC_CONSTRAINTS        MBEDTLS_OID_X509_EXT_BASIC_CONSTRAINTS        /* Supported */
+#define MBEDTLS_X509_EXT_NAME_CONSTRAINTS         MBEDTLS_OID_X509_EXT_NAME_CONSTRAINTS
+#define MBEDTLS_X509_EXT_POLICY_CONSTRAINTS       MBEDTLS_OID_X509_EXT_POLICY_CONSTRAINTS
+#define MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE       MBEDTLS_OID_X509_EXT_EXTENDED_KEY_USAGE
+#define MBEDTLS_X509_EXT_CRL_DISTRIBUTION_POINTS  MBEDTLS_OID_X509_EXT_CRL_DISTRIBUTION_POINTS
+#define MBEDTLS_X509_EXT_INIHIBIT_ANYPOLICY       MBEDTLS_OID_X509_EXT_INIHIBIT_ANYPOLICY
+#define MBEDTLS_X509_EXT_FRESHEST_CRL             MBEDTLS_OID_X509_EXT_FRESHEST_CRL
+#define MBEDTLS_X509_EXT_NS_CERT_TYPE             MBEDTLS_OID_X509_EXT_NS_CERT_TYPE
 
 /*
  * Storage format identifiers
diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h
index 3dd5922..b3f27be 100644
--- a/include/mbedtls/x509_crt.h
+++ b/include/mbedtls/x509_crt.h
@@ -52,6 +52,8 @@
  */
 typedef struct mbedtls_x509_crt
 {
+    int own_buffer;                     /**< Indicates if \c raw is owned
+                                         *   by the structure or not.        */
     mbedtls_x509_buf raw;               /**< The raw certificate data (DER). */
     mbedtls_x509_buf tbs;               /**< The raw certificate body (DER). The part that is To Be Signed. */
 
@@ -68,6 +70,7 @@
     mbedtls_x509_time valid_from;       /**< Start time of certificate validity. */
     mbedtls_x509_time valid_to;         /**< End time of certificate validity. */
 
+    mbedtls_x509_buf pk_raw;
     mbedtls_pk_context pk;              /**< Container for the public key context. */
 
     mbedtls_x509_buf issuer_id;         /**< Optional X.509 v2/v3 issuer unique identifier. */
@@ -220,16 +223,58 @@
 
 /**
  * \brief          Parse a single DER formatted certificate and add it
- *                 to the chained list.
+ *                 to the end of the provided chained list.
  *
- * \param chain    points to the start of the chain
- * \param buf      buffer holding the certificate DER data
- * \param buflen   size of the buffer
+ * \param chain    The pointer to the start of the CRT chain to attach to.
+ *                 When parsing the first CRT in a chain, this should point
+ *                 to an instance of ::mbedtls_x509_crt initialized through
+ *                 mbedtls_x509_crt_init().
+ * \param buf      The buffer holding the DER encoded certificate.
+ * \param buflen   The size in Bytes of \p buf.
  *
- * \return         0 if successful, or a specific X509 or PEM error code
+ * \note           This function makes an internal copy of the CRT buffer
+ *                 \p buf. In particular, \p buf may be destroyed or reused
+ *                 after this call returns. To avoid duplicating the CRT
+ *                 buffer (at the cost of stricter lifetime constraints),
+ *                 use mbedtls_x509_crt_parse_der_nocopy() instead.
+ *
+ * \return         \c 0 if successful.
+ * \return         A negative error code on failure.
  */
-int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *buf,
-                        size_t buflen );
+int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain,
+                                const unsigned char *buf,
+                                size_t buflen );
+
+/**
+ * \brief          Parse a single DER formatted certificate and add it
+ *                 to the end of the provided chained list. This is a
+ *                 variant of mbedtls_x509_crt_parse_der() which takes
+ *                 temporary ownership of the CRT buffer until the CRT
+ *                 is destroyed.
+ *
+ * \param chain    The pointer to the start of the CRT chain to attach to.
+ *                 When parsing the first CRT in a chain, this should point
+ *                 to an instance of ::mbedtls_x509_crt initialized through
+ *                 mbedtls_x509_crt_init().
+ * \param buf      The address of the readable buffer holding the DER encoded
+ *                 certificate to use. On success, this buffer must be
+ *                 retained and not be changed for the liftetime of the
+ *                 CRT chain \p chain, that is, until \p chain is destroyed
+ *                 through a call to mbedtls_x509_crt_free().
+ * \param buflen   The size in Bytes of \p buf.
+ *
+ * \note           This call is functionally equivalent to
+ *                 mbedtls_x509_crt_parse_der(), but it avoids creating a
+ *                 copy of the input buffer at the cost of stronger lifetime
+ *                 constraints. This is useful in constrained environments
+ *                 where duplication of the CRT cannot be tolerated.
+ *
+ * \return         \c 0 if successful.
+ * \return         A negative error code on failure.
+ */
+int mbedtls_x509_crt_parse_der_nocopy( mbedtls_x509_crt *chain,
+                                       const unsigned char *buf,
+                                       size_t buflen );
 
 /**
  * \brief          Parse one DER-encoded or one or more concatenated PEM-encoded
diff --git a/include/mbedtls/x509_csr.h b/include/mbedtls/x509_csr.h
index 0c6ccad..a3c2804 100644
--- a/include/mbedtls/x509_csr.h
+++ b/include/mbedtls/x509_csr.h
@@ -205,6 +205,14 @@
  * \param key_usage key usage flags to set
  *
  * \return          0 if successful, or MBEDTLS_ERR_X509_ALLOC_FAILED
+ *
+ * \note            The <code>decipherOnly</code> flag from the Key Usage
+ *                  extension is represented by bit 8 (i.e.
+ *                  <code>0x8000</code>), which cannot typically be represented
+ *                  in an unsigned char. Therefore, the flag
+ *                  <code>decipherOnly</code> (i.e.
+ *                  #MBEDTLS_X509_KU_DECIPHER_ONLY) cannot be set using this
+ *                  function.
  */
 int mbedtls_x509write_csr_set_key_usage( mbedtls_x509write_csr *ctx, unsigned char key_usage );
 
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index 6d45fe4..fb43fd0 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -182,20 +182,20 @@
 if(USE_SHARED_MBEDTLS_LIBRARY)
     if(NOT USE_CRYPTO_SUBMODULE)
         add_library(mbedcrypto SHARED ${src_crypto})
-        set_target_properties(mbedcrypto PROPERTIES VERSION 2.16.0 SOVERSION 3)
+        set_target_properties(mbedcrypto PROPERTIES VERSION 2.17.0 SOVERSION 3)
         target_link_libraries(mbedcrypto ${libs})
         target_include_directories(mbedcrypto PUBLIC ${CMAKE_SOURCE_DIR}/include/)
     endif()
 
     add_library(mbedx509 SHARED ${src_x509})
-    set_target_properties(mbedx509 PROPERTIES VERSION 2.16.0 SOVERSION 0)
+    set_target_properties(mbedx509 PROPERTIES VERSION 2.17.0 SOVERSION 0)
     target_link_libraries(mbedx509 ${libs} mbedcrypto)
     target_include_directories(mbedx509
         PUBLIC ${CMAKE_SOURCE_DIR}/include/
         PUBLIC ${CMAKE_SOURCE_DIR}/crypto/include/)
 
     add_library(mbedtls SHARED ${src_tls})
-    set_target_properties(mbedtls PROPERTIES VERSION 2.16.0 SOVERSION 12)
+    set_target_properties(mbedtls PROPERTIES VERSION 2.17.0 SOVERSION 12)
     target_link_libraries(mbedtls ${libs} mbedx509)
     target_include_directories(mbedtls
         PUBLIC ${CMAKE_SOURCE_DIR}/include/
diff --git a/library/asn1write.c b/library/asn1write.c
index a4d23f6..b54e26b 100644
--- a/library/asn1write.c
+++ b/library/asn1write.c
@@ -290,26 +290,75 @@
     return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_IA5_STRING, text, text_len) );
 }
 
+int mbedtls_asn1_write_named_bitstring( unsigned char **p,
+                                        unsigned char *start,
+                                        const unsigned char *buf,
+                                        size_t bits )
+{
+    size_t unused_bits, byte_len;
+    const unsigned char *cur_byte;
+    unsigned char cur_byte_shifted;
+    unsigned char bit;
+
+    byte_len = ( bits + 7 ) / 8;
+    unused_bits = ( byte_len * 8 ) - bits;
+
+    /*
+     * Named bitstrings require that trailing 0s are excluded in the encoding
+     * of the bitstring. Trailing 0s are considered part of the 'unused' bits
+     * when encoding this value in the first content octet
+     */
+    if( bits != 0 )
+    {
+        cur_byte = buf + byte_len - 1;
+        cur_byte_shifted = *cur_byte >> unused_bits;
+
+        for( ; ; )
+        {
+            bit = cur_byte_shifted & 0x1;
+            cur_byte_shifted >>= 1;
+
+            if( bit != 0 )
+                break;
+
+            bits--;
+            if( bits == 0 )
+                break;
+
+            if( bits % 8 == 0 )
+                cur_byte_shifted = *--cur_byte;
+        }
+    }
+
+    return( mbedtls_asn1_write_bitstring( p, start, buf, bits ) );
+}
+
 int mbedtls_asn1_write_bitstring( unsigned char **p, unsigned char *start,
                           const unsigned char *buf, size_t bits )
 {
     int ret;
-    size_t len = 0, size;
+    size_t len = 0;
+    size_t unused_bits, byte_len;
 
-    size = ( bits / 8 ) + ( ( bits % 8 ) ? 1 : 0 );
+    byte_len = ( bits + 7 ) / 8;
+    unused_bits = ( byte_len * 8 ) - bits;
 
-    // Calculate byte length
-    //
-    if( *p < start || (size_t)( *p - start ) < size + 1 )
+    if( *p < start || (size_t)( *p - start ) < byte_len + 1 )
         return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
 
-    len = size + 1;
-    (*p) -= size;
-    memcpy( *p, buf, size );
+    len = byte_len + 1;
 
-    // Write unused bits
-    //
-    *--(*p) = (unsigned char) (size * 8 - bits);
+    /* Write the bitstring. Ensure the unused bits are zeroed */
+    if( byte_len > 0 )
+    {
+        byte_len--;
+        *--( *p ) = buf[byte_len] & ~( ( 0x1 << unused_bits ) - 1 );
+        ( *p ) -= byte_len;
+        memcpy( *p, buf, byte_len );
+    }
+
+    /* Write unused bits */
+    *--( *p ) = (unsigned char)unused_bits;
 
     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BIT_STRING ) );
diff --git a/library/bignum.c b/library/bignum.c
index 87015af..98ee12a 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -582,15 +582,20 @@
     if( radix < 2 || radix > 16 )
         return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
 
-    n = mbedtls_mpi_bitlen( X );
-    if( radix >=  4 ) n >>= 1;
-    if( radix >= 16 ) n >>= 1;
-    /*
-     * Round up the buffer length to an even value to ensure that there is
-     * enough room for hexadecimal values that can be represented in an odd
-     * number of digits.
-     */
-    n += 3 + ( ( n + 1 ) & 1 );
+    n = mbedtls_mpi_bitlen( X ); /* Number of bits necessary to present `n`. */
+    if( radix >=  4 ) n >>= 1;   /* Number of 4-adic digits necessary to present
+                                  * `n`. If radix > 4, this might be a strict
+                                  * overapproximation of the number of
+                                  * radix-adic digits needed to present `n`. */
+    if( radix >= 16 ) n >>= 1;   /* Number of hexadecimal digits necessary to
+                                  * present `n`. */
+
+    n += 1; /* Terminating null byte */
+    n += 1; /* Compensate for the divisions above, which round down `n`
+             * in case it's not even. */
+    n += 1; /* Potential '-'-sign. */
+    n += ( n & 1 ); /* Make n even to have enough space for hexadecimal writing,
+                     * which always uses an even number of hex-digits. */
 
     if( buflen < n )
     {
@@ -602,7 +607,10 @@
     mbedtls_mpi_init( &T );
 
     if( X->s == -1 )
+    {
         *p++ = '-';
+        buflen--;
+    }
 
     if( radix == 16 )
     {
@@ -814,6 +822,39 @@
 }
 
 /*
+ * Import X from unsigned binary data, little endian
+ */
+int mbedtls_mpi_read_binary_le( mbedtls_mpi *X,
+                                const unsigned char *buf, size_t buflen )
+{
+    int ret;
+    size_t i;
+    size_t const limbs = CHARS_TO_LIMBS( buflen );
+
+    /* Ensure that target MPI has exactly the necessary number of limbs */
+    if( X->n != limbs )
+    {
+        mbedtls_mpi_free( X );
+        mbedtls_mpi_init( X );
+        MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, limbs ) );
+    }
+
+    MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
+
+    for( i = 0; i < buflen; i++ )
+        X->p[i / ciL] |= ((mbedtls_mpi_uint) buf[i]) << ((i % ciL) << 3);
+
+cleanup:
+
+    /*
+     * This function is also used to import keys. However, wiping the buffers
+     * upon failure is not necessary because failure only can happen before any
+     * input is copied.
+     */
+    return( ret );
+}
+
+/*
  * Import X from unsigned binary data, big endian
  */
 int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen )
@@ -847,10 +888,54 @@
 
 cleanup:
 
+    /*
+     * This function is also used to import keys. However, wiping the buffers
+     * upon failure is not necessary because failure only can happen before any
+     * input is copied.
+     */
     return( ret );
 }
 
 /*
+ * Export X into unsigned binary data, little endian
+ */
+int mbedtls_mpi_write_binary_le( const mbedtls_mpi *X,
+                                 unsigned char *buf, size_t buflen )
+{
+    size_t stored_bytes = X->n * ciL;
+    size_t bytes_to_copy;
+    size_t i;
+
+    if( stored_bytes < buflen )
+    {
+        bytes_to_copy = stored_bytes;
+    }
+    else
+    {
+        bytes_to_copy = buflen;
+
+        /* The output buffer is smaller than the allocated size of X.
+         * However X may fit if its leading bytes are zero. */
+        for( i = bytes_to_copy; i < stored_bytes; i++ )
+        {
+            if( GET_BYTE( X, i ) != 0 )
+                return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL );
+        }
+    }
+
+    for( i = 0; i < bytes_to_copy; i++ )
+        buf[i] = GET_BYTE( X, i );
+
+    if( stored_bytes < buflen )
+    {
+        /* Write trailing 0 bytes */
+        memset( buf + stored_bytes, 0, buflen - stored_bytes );
+    }
+
+    return( 0 );
+}
+
+/*
  * Export X into unsigned binary data, big endian
  */
 int mbedtls_mpi_write_binary( const mbedtls_mpi *X,
@@ -1869,8 +1954,10 @@
     wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
             ( i >  79 ) ? 4 : ( i >  23 ) ? 3 : 1;
 
+#if( MBEDTLS_MPI_WINDOW_SIZE < 6 )
     if( wsize > MBEDTLS_MPI_WINDOW_SIZE )
         wsize = MBEDTLS_MPI_WINDOW_SIZE;
+#endif
 
     j = N->n + 1;
     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
diff --git a/library/ccm.c b/library/ccm.c
index 01e58b0..2c87b3e 100644
--- a/library/ccm.c
+++ b/library/ccm.c
@@ -80,7 +80,8 @@
     CCM_VALIDATE_RET( ctx != NULL );
     CCM_VALIDATE_RET( key != NULL );
 
-    cipher_info = mbedtls_cipher_info_from_values( cipher, keybits, MBEDTLS_MODE_ECB );
+    cipher_info = mbedtls_cipher_info_from_values( cipher, keybits,
+                                                   MBEDTLS_MODE_ECB );
     if( cipher_info == NULL )
         return( MBEDTLS_ERR_CCM_BAD_INPUT );
 
@@ -423,34 +424,34 @@
 /*
  * The data is the same for all tests, only the used length changes
  */
-static const unsigned char key[] = {
+static const unsigned char key_test_data[] = {
     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
     0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
 };
 
-static const unsigned char iv[] = {
+static const unsigned char iv_test_data[] = {
     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
     0x18, 0x19, 0x1a, 0x1b
 };
 
-static const unsigned char ad[] = {
+static const unsigned char ad_test_data[] = {
     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
     0x10, 0x11, 0x12, 0x13
 };
 
-static const unsigned char msg[CCM_SELFTEST_PT_MAX_LEN] = {
+static const unsigned char msg_test_data[CCM_SELFTEST_PT_MAX_LEN] = {
     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
     0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
 };
 
-static const size_t iv_len [NB_TESTS] = { 7, 8,  12 };
-static const size_t add_len[NB_TESTS] = { 8, 16, 20 };
-static const size_t msg_len[NB_TESTS] = { 4, 16, 24 };
-static const size_t tag_len[NB_TESTS] = { 4, 6,  8  };
+static const size_t iv_len_test_data [NB_TESTS] = { 7, 8,  12 };
+static const size_t add_len_test_data[NB_TESTS] = { 8, 16, 20 };
+static const size_t msg_len_test_data[NB_TESTS] = { 4, 16, 24 };
+static const size_t tag_len_test_data[NB_TESTS] = { 4, 6,  8  };
 
-static const unsigned char res[NB_TESTS][CCM_SELFTEST_CT_MAX_LEN] = {
+static const unsigned char res_test_data[NB_TESTS][CCM_SELFTEST_CT_MAX_LEN] = {
     {   0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d },
     {   0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62,
         0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d,
@@ -476,7 +477,8 @@
 
     mbedtls_ccm_init( &ctx );
 
-    if( mbedtls_ccm_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, key, 8 * sizeof key ) != 0 )
+    if( mbedtls_ccm_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, key_test_data,
+                            8 * sizeof key_test_data ) != 0 )
     {
         if( verbose != 0 )
             mbedtls_printf( "  CCM: setup failed" );
@@ -491,15 +493,18 @@
 
         memset( plaintext, 0, CCM_SELFTEST_PT_MAX_LEN );
         memset( ciphertext, 0, CCM_SELFTEST_CT_MAX_LEN );
-        memcpy( plaintext, msg, msg_len[i] );
+        memcpy( plaintext, msg_test_data, msg_len_test_data[i] );
 
-        ret = mbedtls_ccm_encrypt_and_tag( &ctx, msg_len[i],
-                                           iv, iv_len[i], ad, add_len[i],
+        ret = mbedtls_ccm_encrypt_and_tag( &ctx, msg_len_test_data[i],
+                                           iv_test_data, iv_len_test_data[i],
+                                           ad_test_data, add_len_test_data[i],
                                            plaintext, ciphertext,
-                                           ciphertext + msg_len[i], tag_len[i] );
+                                           ciphertext + msg_len_test_data[i],
+                                           tag_len_test_data[i] );
 
         if( ret != 0 ||
-            memcmp( ciphertext, res[i], msg_len[i] + tag_len[i] ) != 0 )
+            memcmp( ciphertext, res_test_data[i],
+                    msg_len_test_data[i] + tag_len_test_data[i] ) != 0 )
         {
             if( verbose != 0 )
                 mbedtls_printf( "failed\n" );
@@ -508,13 +513,15 @@
         }
         memset( plaintext, 0, CCM_SELFTEST_PT_MAX_LEN );
 
-        ret = mbedtls_ccm_auth_decrypt( &ctx, msg_len[i],
-                                        iv, iv_len[i], ad, add_len[i],
+        ret = mbedtls_ccm_auth_decrypt( &ctx, msg_len_test_data[i],
+                                        iv_test_data, iv_len_test_data[i],
+                                        ad_test_data, add_len_test_data[i],
                                         ciphertext, plaintext,
-                                        ciphertext + msg_len[i], tag_len[i] );
+                                        ciphertext + msg_len_test_data[i],
+                                        tag_len_test_data[i] );
 
         if( ret != 0 ||
-            memcmp( plaintext, msg, msg_len[i] ) != 0 )
+            memcmp( plaintext, msg_test_data, msg_len_test_data[i] ) != 0 )
         {
             if( verbose != 0 )
                 mbedtls_printf( "failed\n" );
diff --git a/library/certs.c b/library/certs.c
index ff0f11e..b54ff61 100644
--- a/library/certs.c
+++ b/library/certs.c
@@ -116,7 +116,6 @@
 #endif /* MBEDTLS_ECDSA_C */
 
 #if defined(MBEDTLS_RSA_C)
-
 #if defined(MBEDTLS_SHA256_C)
 #define TEST_CA_CRT_RSA_SHA256                                          \
 "-----BEGIN CERTIFICATE-----\r\n"                                       \
@@ -141,13 +140,11 @@
 "n20NRVA1Vjs6GAROr4NqW4k/+LofY9y0LLDE+p0oIEKXIsIvhPr39swxSA==\r\n"      \
 "-----END CERTIFICATE-----\r\n"
 
+static const char mbedtls_test_ca_crt_rsa_sha256[] = TEST_CA_CRT_RSA_SHA256;
 const char   mbedtls_test_ca_crt_rsa[]   = TEST_CA_CRT_RSA_SHA256;
 const size_t mbedtls_test_ca_crt_rsa_len = sizeof( mbedtls_test_ca_crt_rsa );
 #define TEST_CA_CRT_RSA_SOME
-
-static const char mbedtls_test_ca_crt_rsa_sha256[] = TEST_CA_CRT_RSA_SHA256;
-
-#endif
+#endif /* MBEDTLS_SHA256_C */
 
 #if !defined(TEST_CA_CRT_RSA_SOME) || defined(MBEDTLS_SHA1_C)
 #define TEST_CA_CRT_RSA_SHA1                                            \
@@ -173,14 +170,72 @@
 "7Z2mCGDNMhjQc+BYcdnl0lPXjdDK6V0qCg1dVewhUBcW5gZKzV7e9+DpVA==\r\n"      \
 "-----END CERTIFICATE-----\r\n"
 
+static const char mbedtls_test_ca_crt_rsa_sha1[] = TEST_CA_CRT_RSA_SHA1;
+
 #if !defined (TEST_CA_CRT_RSA_SOME)
 const char   mbedtls_test_ca_crt_rsa[]   = TEST_CA_CRT_RSA_SHA1;
 const size_t mbedtls_test_ca_crt_rsa_len = sizeof( mbedtls_test_ca_crt_rsa );
-#endif
+#endif /* !TEST_CA_CRT_RSA_SOME */
+#endif /* !TEST_CA_CRT_RSA_COME || MBEDTLS_SHA1_C */
 
-static const char mbedtls_test_ca_crt_rsa_sha1[] = TEST_CA_CRT_RSA_SHA1;
+#if defined(MBEDTLS_SHA256_C)
+/* tests/data_files/server2-sha256.crt */
+#define TEST_SRV_CRT_RSA_SHA256                                          \
+"-----BEGIN CERTIFICATE-----\r\n"                                        \
+"MIIDNzCCAh+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER\r\n"   \
+"MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n"   \
+"MTEwMjEyMTQ0NDA2WhcNMjEwMjEyMTQ0NDA2WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n"   \
+"A1UECgwIUG9sYXJTU0wxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN\r\n"   \
+"AQEBBQADggEPADCCAQoCggEBAMFNo93nzR3RBNdJcriZrA545Do8Ss86ExbQWuTN\r\n"   \
+"owCIp+4ea5anUrSQ7y1yej4kmvy2NKwk9XfgJmSMnLAofaHa6ozmyRyWvP7BBFKz\r\n"   \
+"NtSj+uGxdtiQwWG0ZlI2oiZTqqt0Xgd9GYLbKtgfoNkNHC1JZvdbJXNG6AuKT2kM\r\n"   \
+"tQCQ4dqCEGZ9rlQri2V5kaHiYcPNQEkI7mgM8YuG0ka/0LiqEQMef1aoGh5EGA8P\r\n"   \
+"hYvai0Re4hjGYi/HZo36Xdh98yeJKQHFkA4/J/EwyEoO79bex8cna8cFPXrEAjya\r\n"   \
+"HT4P6DSYW8tzS1KW2BGiLICIaTla0w+w3lkvEcf36hIBMJcCAwEAAaNNMEswCQYD\r\n"   \
+"VR0TBAIwADAdBgNVHQ4EFgQUpQXoZLjc32APUBJNYKhkr02LQ5MwHwYDVR0jBBgw\r\n"   \
+"FoAUtFrkpbPe0lL2udWmlQ/rPrzH/f8wDQYJKoZIhvcNAQELBQADggEBAGGEshT5\r\n"   \
+"kvnRmLVScVeUEdwIrvW7ezbGbUvJ8VxeJ79/HSjlLiGbMc4uUathwtzEdi9R/4C5\r\n"   \
+"DXBNeEPTkbB+fhG1W06iHYj/Dp8+aaG7fuDxKVKHVZSqBnmQLn73ymyclZNHii5A\r\n"   \
+"3nTS8WUaHAzxN/rajOtoM7aH1P9tULpHrl+7HOeLMpxUnwI12ZqZaLIzxbcdJVcr\r\n"   \
+"ra2F00aXCGkYVLvyvbZIq7LC+yVysej5gCeQYD7VFOEks0jhFjrS06gP0/XnWv6v\r\n"   \
+"eBoPez9d+CCjkrhseiWzXOiriIMICX48EloO/DrsMRAtvlwq7EDz4QhILz6ffndm\r\n"   \
+"e4K1cVANRPN2o9Y=\r\n"                                                   \
+"-----END CERTIFICATE-----\r\n"
 
-#endif
+const char mbedtls_test_srv_crt_rsa[]     =  TEST_SRV_CRT_RSA_SHA256;
+const size_t mbedtls_test_srv_crt_rsa_len = sizeof( mbedtls_test_srv_crt_rsa );
+#define TEST_SRV_CRT_RSA_SOME
+#endif /* MBEDTLS_SHA256_C */
+
+#if !defined(TEST_SRV_CRT_RSA_SOME) || defined(MBEDTLS_SHA1_C)
+/* tests/data_files/server2.crt */
+#define TEST_SRV_CRT_RSA_SHA1                                          \
+"-----BEGIN CERTIFICATE-----\r\n"                                      \
+"MIIDNzCCAh+gAwIBAgIBAjANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n" \
+"MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" \
+"MTEwMjEyMTQ0NDA2WhcNMjEwMjEyMTQ0NDA2WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n" \
+"A1UECgwIUG9sYXJTU0wxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN\r\n" \
+"AQEBBQADggEPADCCAQoCggEBAMFNo93nzR3RBNdJcriZrA545Do8Ss86ExbQWuTN\r\n" \
+"owCIp+4ea5anUrSQ7y1yej4kmvy2NKwk9XfgJmSMnLAofaHa6ozmyRyWvP7BBFKz\r\n" \
+"NtSj+uGxdtiQwWG0ZlI2oiZTqqt0Xgd9GYLbKtgfoNkNHC1JZvdbJXNG6AuKT2kM\r\n" \
+"tQCQ4dqCEGZ9rlQri2V5kaHiYcPNQEkI7mgM8YuG0ka/0LiqEQMef1aoGh5EGA8P\r\n" \
+"hYvai0Re4hjGYi/HZo36Xdh98yeJKQHFkA4/J/EwyEoO79bex8cna8cFPXrEAjya\r\n" \
+"HT4P6DSYW8tzS1KW2BGiLICIaTla0w+w3lkvEcf36hIBMJcCAwEAAaNNMEswCQYD\r\n" \
+"VR0TBAIwADAdBgNVHQ4EFgQUpQXoZLjc32APUBJNYKhkr02LQ5MwHwYDVR0jBBgw\r\n" \
+"FoAUtFrkpbPe0lL2udWmlQ/rPrzH/f8wDQYJKoZIhvcNAQEFBQADggEBAAFzC0rF\r\n" \
+"y6De8WMcdgQrEw3AhBHFjzqnxZw1ene4IBSC7lTw8rBSy3jOWQdPUWn+0y/pCeeF\r\n" \
+"kti6sevFdl1hLemGtd4q+T9TKEKGg3ND4ARfB5AUZZ9uEHq8WBkiwus5clGS17Qd\r\n" \
+"dS/TOisB59tQruLx1E1bPLtBKyqk4koC5WAULJwfpswGSyWJTpYwIpxcWE3D2tBu\r\n" \
+"UB6MZfXZFzWmWEOyKbeoXjXe8GBCGgHLywvYDsGQ36HSGtEsAvR2QaTLSxWYcfk1\r\n" \
+"fbDn4jSWkb4yZy1r01UEigFQtONieGwRFaUqEcFJHJvEEGVgh9keaVlOj2vrwf5r\r\n" \
+"4mN4lW7gLdenN6g=\r\n"                                                 \
+"-----END CERTIFICATE-----\r\n";
+
+#if !defined(TEST_SRV_CRT_RSA_SOME)
+const char mbedtls_test_srv_crt_rsa[]     =  TEST_SRV_CRT_RSA_SHA1;
+const size_t mbedtls_test_srv_crt_rsa_len = sizeof( mbedtls_test_srv_crt_rsa );
+#endif /* TEST_SRV_CRT_RSA_SOME */
+#endif /* !TEST_CA_CRT_RSA_SOME || MBEDTLS_SHA1_C */
 
 const char mbedtls_test_ca_key_rsa[] =
 "-----BEGIN RSA PRIVATE KEY-----\r\n"
@@ -218,31 +273,6 @@
 const char mbedtls_test_ca_pwd_rsa[] = "PolarSSLTest";
 const size_t mbedtls_test_ca_pwd_rsa_len = sizeof( mbedtls_test_ca_pwd_rsa ) - 1;
 
-/* tests/data_files/server2.crt */
-const char mbedtls_test_srv_crt_rsa[] =
-"-----BEGIN CERTIFICATE-----\r\n"
-"MIIDNzCCAh+gAwIBAgIBAjANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n"
-"MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n"
-"MTEwMjEyMTQ0NDA2WhcNMjEwMjEyMTQ0NDA2WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n"
-"A1UECgwIUG9sYXJTU0wxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN\r\n"
-"AQEBBQADggEPADCCAQoCggEBAMFNo93nzR3RBNdJcriZrA545Do8Ss86ExbQWuTN\r\n"
-"owCIp+4ea5anUrSQ7y1yej4kmvy2NKwk9XfgJmSMnLAofaHa6ozmyRyWvP7BBFKz\r\n"
-"NtSj+uGxdtiQwWG0ZlI2oiZTqqt0Xgd9GYLbKtgfoNkNHC1JZvdbJXNG6AuKT2kM\r\n"
-"tQCQ4dqCEGZ9rlQri2V5kaHiYcPNQEkI7mgM8YuG0ka/0LiqEQMef1aoGh5EGA8P\r\n"
-"hYvai0Re4hjGYi/HZo36Xdh98yeJKQHFkA4/J/EwyEoO79bex8cna8cFPXrEAjya\r\n"
-"HT4P6DSYW8tzS1KW2BGiLICIaTla0w+w3lkvEcf36hIBMJcCAwEAAaNNMEswCQYD\r\n"
-"VR0TBAIwADAdBgNVHQ4EFgQUpQXoZLjc32APUBJNYKhkr02LQ5MwHwYDVR0jBBgw\r\n"
-"FoAUtFrkpbPe0lL2udWmlQ/rPrzH/f8wDQYJKoZIhvcNAQEFBQADggEBAAFzC0rF\r\n"
-"y6De8WMcdgQrEw3AhBHFjzqnxZw1ene4IBSC7lTw8rBSy3jOWQdPUWn+0y/pCeeF\r\n"
-"kti6sevFdl1hLemGtd4q+T9TKEKGg3ND4ARfB5AUZZ9uEHq8WBkiwus5clGS17Qd\r\n"
-"dS/TOisB59tQruLx1E1bPLtBKyqk4koC5WAULJwfpswGSyWJTpYwIpxcWE3D2tBu\r\n"
-"UB6MZfXZFzWmWEOyKbeoXjXe8GBCGgHLywvYDsGQ36HSGtEsAvR2QaTLSxWYcfk1\r\n"
-"fbDn4jSWkb4yZy1r01UEigFQtONieGwRFaUqEcFJHJvEEGVgh9keaVlOj2vrwf5r\r\n"
-"4mN4lW7gLdenN6g=\r\n"
-"-----END CERTIFICATE-----\r\n";
-const size_t mbedtls_test_srv_crt_rsa_len = sizeof( mbedtls_test_srv_crt_rsa );
-
-/* tests/data_files/server2.key */
 const char mbedtls_test_srv_key_rsa[] =
 "-----BEGIN RSA PRIVATE KEY-----\r\n"
 "MIIEpAIBAAKCAQEAwU2j3efNHdEE10lyuJmsDnjkOjxKzzoTFtBa5M2jAIin7h5r\r\n"
diff --git a/library/cipher.c b/library/cipher.c
index 2465536..3cdd07f 100644
--- a/library/cipher.c
+++ b/library/cipher.c
@@ -63,6 +63,10 @@
 #include "mbedtls/psa_util.h"
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
+#if defined(MBEDTLS_NIST_KW_C)
+#include "mbedtls/nist_kw.h"
+#endif
+
 #if defined(MBEDTLS_PLATFORM_C)
 #include "mbedtls/platform.h"
 #else
@@ -1238,7 +1242,7 @@
             (mbedtls_cipher_context_psa *) ctx->cipher_ctx;
 
         psa_status_t status;
-        psa_cipher_operation_t cipher_op;
+        psa_cipher_operation_t cipher_op = PSA_CIPHER_OPERATION_INIT;
         size_t part_len;
 
         if( ctx->operation == MBEDTLS_DECRYPT )
@@ -1387,6 +1391,22 @@
                                 ilen, iv, ad, ad_len, input, output, tag ) );
     }
 #endif /* MBEDTLS_CHACHAPOLY_C */
+#if defined(MBEDTLS_NIST_KW_C)
+   if( MBEDTLS_MODE_KW == ctx->cipher_info->mode ||
+       MBEDTLS_MODE_KWP == ctx->cipher_info->mode )
+    {
+        mbedtls_nist_kw_mode_t mode = ( MBEDTLS_MODE_KW == ctx->cipher_info->mode ) ?
+                                        MBEDTLS_KW_MODE_KW : MBEDTLS_KW_MODE_KWP;
+
+        /* There is no iv, tag or ad associated with KW and KWP, these length should be 0 */
+        if( iv_len != 0 || tag_len != 0 || ad_len != 0 )
+        {
+            return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+        }
+
+        return( mbedtls_nist_kw_wrap( ctx->cipher_ctx, mode, input, ilen, output, olen, SIZE_MAX ) );
+    }
+#endif /* MBEDTLS_NIST_KW_C */
 
     return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
 }
@@ -1496,6 +1516,22 @@
         return( ret );
     }
 #endif /* MBEDTLS_CHACHAPOLY_C */
+#if defined(MBEDTLS_NIST_KW_C)
+    if( MBEDTLS_MODE_KW == ctx->cipher_info->mode ||
+        MBEDTLS_MODE_KWP == ctx->cipher_info->mode )
+    {
+        mbedtls_nist_kw_mode_t mode = ( MBEDTLS_MODE_KW == ctx->cipher_info->mode ) ?
+                                        MBEDTLS_KW_MODE_KW : MBEDTLS_KW_MODE_KWP;
+
+        /* There is no iv, tag or ad associated with KW and KWP, these length should be 0 */
+        if( iv_len != 0 || tag_len != 0 || ad_len != 0 )
+        {
+            return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
+        }
+
+        return( mbedtls_nist_kw_unwrap( ctx->cipher_ctx, mode, input, ilen, output, olen, SIZE_MAX ) );
+    }
+#endif /* MBEDTLS_NIST_KW_C */
 
     return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
 }
diff --git a/library/cipher_wrap.c b/library/cipher_wrap.c
index d4538ed..7fc40b5 100644
--- a/library/cipher_wrap.c
+++ b/library/cipher_wrap.c
@@ -73,6 +73,10 @@
 #include "mbedtls/ccm.h"
 #endif
 
+#if defined(MBEDTLS_NIST_KW_C)
+#include "mbedtls/nist_kw.h"
+#endif
+
 #if defined(MBEDTLS_CIPHER_NULL_CIPHER)
 #include <string.h>
 #endif
@@ -2119,6 +2123,131 @@
 };
 #endif /* defined(MBEDTLS_CIPHER_NULL_CIPHER) */
 
+#if defined(MBEDTLS_NIST_KW_C)
+static void *kw_ctx_alloc( void )
+{
+    void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_nist_kw_context ) );
+
+    if( ctx != NULL )
+        mbedtls_nist_kw_init( (mbedtls_nist_kw_context *) ctx );
+
+    return( ctx );
+}
+
+static void kw_ctx_free( void *ctx )
+{
+    mbedtls_nist_kw_free( ctx );
+    mbedtls_free( ctx );
+}
+
+static int kw_aes_setkey_wrap( void *ctx, const unsigned char *key,
+                                unsigned int key_bitlen )
+{
+    return mbedtls_nist_kw_setkey( (mbedtls_nist_kw_context *) ctx,
+                                   MBEDTLS_CIPHER_ID_AES, key, key_bitlen, 1 );
+}
+
+static int kw_aes_setkey_unwrap( void *ctx, const unsigned char *key,
+                                unsigned int key_bitlen )
+{
+   return mbedtls_nist_kw_setkey( (mbedtls_nist_kw_context *) ctx,
+                                  MBEDTLS_CIPHER_ID_AES, key, key_bitlen, 0 );
+}
+
+static const mbedtls_cipher_base_t kw_aes_info = {
+    MBEDTLS_CIPHER_ID_AES,
+    NULL,
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+    NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+    NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_OFB)
+    NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+    NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_XTS)
+    NULL,
+#endif
+#if defined(MBEDTLS_CIPHER_MODE_STREAM)
+    NULL,
+#endif
+    kw_aes_setkey_wrap,
+    kw_aes_setkey_unwrap,
+    kw_ctx_alloc,
+    kw_ctx_free,
+};
+
+static const mbedtls_cipher_info_t aes_128_nist_kw_info = {
+    MBEDTLS_CIPHER_AES_128_KW,
+    MBEDTLS_MODE_KW,
+    128,
+    "AES-128-KW",
+    0,
+    0,
+    16,
+    &kw_aes_info
+};
+
+static const mbedtls_cipher_info_t aes_192_nist_kw_info = {
+    MBEDTLS_CIPHER_AES_192_KW,
+    MBEDTLS_MODE_KW,
+    192,
+    "AES-192-KW",
+    0,
+    0,
+    16,
+    &kw_aes_info
+};
+
+static const mbedtls_cipher_info_t aes_256_nist_kw_info = {
+    MBEDTLS_CIPHER_AES_256_KW,
+    MBEDTLS_MODE_KW,
+    256,
+    "AES-256-KW",
+    0,
+    0,
+    16,
+    &kw_aes_info
+};
+
+static const mbedtls_cipher_info_t aes_128_nist_kwp_info = {
+    MBEDTLS_CIPHER_AES_128_KWP,
+    MBEDTLS_MODE_KWP,
+    128,
+    "AES-128-KWP",
+    0,
+    0,
+    16,
+    &kw_aes_info
+};
+
+static const mbedtls_cipher_info_t aes_192_nist_kwp_info = {
+    MBEDTLS_CIPHER_AES_192_KWP,
+    MBEDTLS_MODE_KWP,
+    192,
+    "AES-192-KWP",
+    0,
+    0,
+    16,
+    &kw_aes_info
+};
+
+static const mbedtls_cipher_info_t aes_256_nist_kwp_info = {
+    MBEDTLS_CIPHER_AES_256_KWP,
+    MBEDTLS_MODE_KWP,
+    256,
+    "AES-256-KWP",
+    0,
+    0,
+    16,
+    &kw_aes_info
+};
+#endif /* MBEDTLS_NIST_KW_C */
+
 const mbedtls_cipher_definition_t mbedtls_cipher_definitions[] =
 {
 #if defined(MBEDTLS_AES_C)
@@ -2259,6 +2388,15 @@
     { MBEDTLS_CIPHER_CHACHA20_POLY1305,    &chachapoly_info },
 #endif
 
+#if defined(MBEDTLS_NIST_KW_C)
+    { MBEDTLS_CIPHER_AES_128_KW,          &aes_128_nist_kw_info },
+    { MBEDTLS_CIPHER_AES_192_KW,          &aes_192_nist_kw_info },
+    { MBEDTLS_CIPHER_AES_256_KW,          &aes_256_nist_kw_info },
+    { MBEDTLS_CIPHER_AES_128_KWP,         &aes_128_nist_kwp_info },
+    { MBEDTLS_CIPHER_AES_192_KWP,         &aes_192_nist_kwp_info },
+    { MBEDTLS_CIPHER_AES_256_KWP,         &aes_256_nist_kwp_info },
+#endif
+
 #if defined(MBEDTLS_CIPHER_NULL_CIPHER)
     { MBEDTLS_CIPHER_NULL,                 &null_cipher_info },
 #endif /* MBEDTLS_CIPHER_NULL_CIPHER */
diff --git a/library/debug.c b/library/debug.c
index 6e1efbf..0c46c06 100644
--- a/library/debug.c
+++ b/library/debug.c
@@ -87,8 +87,13 @@
     char str[DEBUG_BUF_SIZE];
     int ret;
 
-    if( NULL == ssl || NULL == ssl->conf || NULL == ssl->conf->f_dbg || level > debug_threshold )
+    if( NULL == ssl              ||
+        NULL == ssl->conf        ||
+        NULL == ssl->conf->f_dbg ||
+        level > debug_threshold )
+    {
         return;
+    }
 
     va_start( argp, format );
     ret = mbedtls_vsnprintf( str, DEBUG_BUF_SIZE, format, argp );
@@ -109,8 +114,13 @@
 {
     char str[DEBUG_BUF_SIZE];
 
-    if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || level > debug_threshold )
+    if( NULL == ssl              ||
+        NULL == ssl->conf        ||
+        NULL == ssl->conf->f_dbg ||
+        level > debug_threshold )
+    {
         return;
+    }
 
     /*
      * With non-blocking I/O and examples that just retry immediately,
@@ -134,8 +144,13 @@
     char txt[17];
     size_t i, idx = 0;
 
-    if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || level > debug_threshold )
+    if( NULL == ssl              ||
+        NULL == ssl->conf        ||
+        NULL == ssl->conf->f_dbg ||
+        level > debug_threshold )
+    {
         return;
+    }
 
     mbedtls_snprintf( str + idx, sizeof( str ) - idx, "dumping '%s' (%u bytes)\n",
               text, (unsigned int) len );
@@ -187,8 +202,13 @@
 {
     char str[DEBUG_BUF_SIZE];
 
-    if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || level > debug_threshold )
+    if( NULL == ssl              ||
+        NULL == ssl->conf        ||
+        NULL == ssl->conf->f_dbg ||
+        level > debug_threshold )
+    {
         return;
+    }
 
     mbedtls_snprintf( str, sizeof( str ), "%s(X)", text );
     mbedtls_debug_print_mpi( ssl, level, file, line, str, &X->X );
@@ -207,8 +227,14 @@
     int j, k, zeros = 1;
     size_t i, n, idx = 0;
 
-    if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || X == NULL || level > debug_threshold )
+    if( NULL == ssl              ||
+        NULL == ssl->conf        ||
+        NULL == ssl->conf->f_dbg ||
+        NULL == X                ||
+        level > debug_threshold )
+    {
         return;
+    }
 
     for( n = X->n - 1; n > 0; n-- )
         if( X->p[n] != 0 )
@@ -333,8 +359,14 @@
     char str[DEBUG_BUF_SIZE];
     int i = 0;
 
-    if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || crt == NULL || level > debug_threshold )
+    if( NULL == ssl              ||
+        NULL == ssl->conf        ||
+        NULL == ssl->conf->f_dbg ||
+        NULL == crt              ||
+        level > debug_threshold )
+    {
         return;
+    }
 
     while( crt != NULL )
     {
diff --git a/library/ecdh.c b/library/ecdh.c
index da95c60..eecae91 100644
--- a/library/ecdh.c
+++ b/library/ecdh.c
@@ -49,6 +49,16 @@
 typedef mbedtls_ecdh_context mbedtls_ecdh_context_mbed;
 #endif
 
+static mbedtls_ecp_group_id mbedtls_ecdh_grp_id(
+    const mbedtls_ecdh_context *ctx )
+{
+#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
+    return( ctx->grp.id );
+#else
+    return( ctx->grp_id );
+#endif
+}
+
 #if !defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT)
 /*
  * Generate public key (restartable version)
@@ -442,8 +452,21 @@
     ECDH_VALIDATE_RET( side == MBEDTLS_ECDH_OURS ||
                        side == MBEDTLS_ECDH_THEIRS );
 
-    if( ( ret = mbedtls_ecdh_setup( ctx, key->grp.id ) ) != 0 )
-        return( ret );
+    if( mbedtls_ecdh_grp_id( ctx ) == MBEDTLS_ECP_DP_NONE )
+    {
+        /* This is the first call to get_params(). Set up the context
+         * for use with the group. */
+        if( ( ret = mbedtls_ecdh_setup( ctx, key->grp.id ) ) != 0 )
+            return( ret );
+    }
+    else
+    {
+        /* This is not the first call to get_params(). Check that the
+         * current key's group is the same as the context's, which was set
+         * from the first key's group. */
+        if( mbedtls_ecdh_grp_id( ctx ) != key->grp.id )
+            return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
+    }
 
 #if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
     return( ecdh_get_params_internal( ctx, key, side ) );
@@ -614,6 +637,10 @@
         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
 
     *olen = ctx->grp.pbits / 8 + ( ( ctx->grp.pbits % 8 ) != 0 );
+
+    if( mbedtls_ecp_get_type( &ctx->grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY )
+        return mbedtls_mpi_write_binary_le( &ctx->z, buf, *olen );
+
     return mbedtls_mpi_write_binary( &ctx->z, buf, *olen );
 }
 
diff --git a/library/ecp.c b/library/ecp.c
index ecea591..c3c5ce5 100644
--- a/library/ecp.c
+++ b/library/ecp.c
@@ -364,16 +364,6 @@
 #endif
 
 /*
- * Curve types: internal for now, might be exposed later
- */
-typedef enum
-{
-    ECP_TYPE_NONE = 0,
-    ECP_TYPE_SHORT_WEIERSTRASS,    /* y^2 = x^3 + a x + b      */
-    ECP_TYPE_MONTGOMERY,           /* y^2 = x^3 + a x^2 + x    */
-} ecp_curve_type;
-
-/*
  * List of supported curves:
  *  - internal ID
  *  - TLS NamedCurve ID (RFC 4492 sec. 5.1.1, RFC 7071 sec. 2)
@@ -522,15 +512,15 @@
 /*
  * Get the type of a curve
  */
-static inline ecp_curve_type ecp_get_type( const mbedtls_ecp_group *grp )
+mbedtls_ecp_curve_type mbedtls_ecp_get_type( const mbedtls_ecp_group *grp )
 {
     if( grp->G.X.p == NULL )
-        return( ECP_TYPE_NONE );
+        return( MBEDTLS_ECP_TYPE_NONE );
 
     if( grp->G.Y.p == NULL )
-        return( ECP_TYPE_MONTGOMERY );
+        return( MBEDTLS_ECP_TYPE_MONTGOMERY );
     else
-        return( ECP_TYPE_SHORT_WEIERSTRASS );
+        return( MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS );
 }
 
 /*
@@ -729,14 +719,14 @@
 }
 
 /*
- * Export a point into unsigned binary data (SEC1 2.3.3)
+ * Export a point into unsigned binary data (SEC1 2.3.3 and RFC7748)
  */
 int mbedtls_ecp_point_write_binary( const mbedtls_ecp_group *grp,
                                     const mbedtls_ecp_point *P,
                                     int format, size_t *olen,
                                     unsigned char *buf, size_t buflen )
 {
-    int ret = 0;
+    int ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
     size_t plen;
     ECP_VALIDATE_RET( grp  != NULL );
     ECP_VALIDATE_RET( P    != NULL );
@@ -745,56 +735,71 @@
     ECP_VALIDATE_RET( format == MBEDTLS_ECP_PF_UNCOMPRESSED ||
                       format == MBEDTLS_ECP_PF_COMPRESSED );
 
-    /*
-     * Common case: P == 0
-     */
-    if( mbedtls_mpi_cmp_int( &P->Z, 0 ) == 0 )
-    {
-        if( buflen < 1 )
-            return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
-
-        buf[0] = 0x00;
-        *olen = 1;
-
-        return( 0 );
-    }
-
     plen = mbedtls_mpi_size( &grp->P );
 
-    if( format == MBEDTLS_ECP_PF_UNCOMPRESSED )
+#if defined(ECP_MONTGOMERY)
+    if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY )
     {
-        *olen = 2 * plen + 1;
-
+        *olen = plen;
         if( buflen < *olen )
             return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
 
-        buf[0] = 0x04;
-        MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &P->X, buf + 1, plen ) );
-        MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &P->Y, buf + 1 + plen, plen ) );
+        MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary_le( &P->X, buf, plen ) );
     }
-    else if( format == MBEDTLS_ECP_PF_COMPRESSED )
+#endif
+#if defined(ECP_SHORTWEIERSTRASS)
+    if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS )
     {
-        *olen = plen + 1;
+        /*
+         * Common case: P == 0
+         */
+        if( mbedtls_mpi_cmp_int( &P->Z, 0 ) == 0 )
+        {
+            if( buflen < 1 )
+                return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
 
-        if( buflen < *olen )
-            return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
+            buf[0] = 0x00;
+            *olen = 1;
 
-        buf[0] = 0x02 + mbedtls_mpi_get_bit( &P->Y, 0 );
-        MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &P->X, buf + 1, plen ) );
+            return( 0 );
+        }
+
+        if( format == MBEDTLS_ECP_PF_UNCOMPRESSED )
+        {
+            *olen = 2 * plen + 1;
+
+            if( buflen < *olen )
+                return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
+
+            buf[0] = 0x04;
+            MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &P->X, buf + 1, plen ) );
+            MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &P->Y, buf + 1 + plen, plen ) );
+        }
+        else if( format == MBEDTLS_ECP_PF_COMPRESSED )
+        {
+            *olen = plen + 1;
+
+            if( buflen < *olen )
+                return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
+
+            buf[0] = 0x02 + mbedtls_mpi_get_bit( &P->Y, 0 );
+            MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &P->X, buf + 1, plen ) );
+        }
     }
+#endif
 
 cleanup:
     return( ret );
 }
 
 /*
- * Import a point from unsigned binary data (SEC1 2.3.4)
+ * Import a point from unsigned binary data (SEC1 2.3.4 and RFC7748)
  */
 int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp,
                                    mbedtls_ecp_point *pt,
                                    const unsigned char *buf, size_t ilen )
 {
-    int ret;
+    int ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
     size_t plen;
     ECP_VALIDATE_RET( grp != NULL );
     ECP_VALIDATE_RET( pt  != NULL );
@@ -803,25 +808,47 @@
     if( ilen < 1 )
         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
 
-    if( buf[0] == 0x00 )
-    {
-        if( ilen == 1 )
-            return( mbedtls_ecp_set_zero( pt ) );
-        else
-            return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
-    }
-
     plen = mbedtls_mpi_size( &grp->P );
 
-    if( buf[0] != 0x04 )
-        return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE );
+#if defined(ECP_MONTGOMERY)
+    if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY )
+    {
+        if( plen != ilen )
+            return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
 
-    if( ilen != 2 * plen + 1 )
-        return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
+        MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary_le( &pt->X, buf, plen ) );
+        mbedtls_mpi_free( &pt->Y );
 
-    MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &pt->X, buf + 1, plen ) );
-    MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &pt->Y, buf + 1 + plen, plen ) );
-    MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Z, 1 ) );
+        if( grp->id == MBEDTLS_ECP_DP_CURVE25519 )
+            /* Set most significant bit to 0 as prescribed in RFC7748 §5 */
+            MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( &pt->X, plen * 8 - 1, 0 ) );
+
+        MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Z, 1 ) );
+    }
+#endif
+#if defined(ECP_SHORTWEIERSTRASS)
+    if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS )
+    {
+        if( buf[0] == 0x00 )
+        {
+            if( ilen == 1 )
+                return( mbedtls_ecp_set_zero( pt ) );
+            else
+                return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
+        }
+
+        if( buf[0] != 0x04 )
+            return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE );
+
+        if( ilen != 2 * plen + 1 )
+            return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
+
+        MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &pt->X, buf + 1, plen ) );
+        MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &pt->Y,
+                                                  buf + 1 + plen, plen ) );
+        MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Z, 1 ) );
+    }
+#endif
 
 cleanup:
     return( ret );
@@ -2357,11 +2384,11 @@
 
     ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
 #if defined(ECP_MONTGOMERY)
-    if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY )
+    if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY )
         MBEDTLS_MPI_CHK( ecp_mul_mxz( grp, R, m, P, f_rng, p_rng ) );
 #endif
 #if defined(ECP_SHORTWEIERSTRASS)
-    if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS )
+    if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS )
         MBEDTLS_MPI_CHK( ecp_mul_comb( grp, R, m, P, f_rng, p_rng, rs_ctx ) );
 #endif
 
@@ -2500,7 +2527,7 @@
     ECP_VALIDATE_RET( n   != NULL );
     ECP_VALIDATE_RET( Q   != NULL );
 
-    if( ecp_get_type( grp ) != ECP_TYPE_SHORT_WEIERSTRASS )
+    if( mbedtls_ecp_get_type( grp ) != MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS )
         return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE );
 
     mbedtls_ecp_point_init( &mP );
@@ -2620,11 +2647,11 @@
         return( MBEDTLS_ERR_ECP_INVALID_KEY );
 
 #if defined(ECP_MONTGOMERY)
-    if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY )
+    if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY )
         return( ecp_check_pubkey_mx( grp, pt ) );
 #endif
 #if defined(ECP_SHORTWEIERSTRASS)
-    if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS )
+    if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS )
         return( ecp_check_pubkey_sw( grp, pt ) );
 #endif
     return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
@@ -2640,7 +2667,7 @@
     ECP_VALIDATE_RET( d   != NULL );
 
 #if defined(ECP_MONTGOMERY)
-    if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY )
+    if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY )
     {
         /* see RFC 7748 sec. 5 para. 5 */
         if( mbedtls_mpi_get_bit( d, 0 ) != 0 ||
@@ -2656,7 +2683,7 @@
     }
 #endif /* ECP_MONTGOMERY */
 #if defined(ECP_SHORTWEIERSTRASS)
-    if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS )
+    if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS )
     {
         /* see SEC1 3.2 */
         if( mbedtls_mpi_cmp_int( d, 1 ) < 0 ||
@@ -2688,7 +2715,7 @@
     n_size = ( grp->nbits + 7 ) / 8;
 
 #if defined(ECP_MONTGOMERY)
-    if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY )
+    if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY )
     {
         /* [M225] page 5 */
         size_t b;
@@ -2716,7 +2743,7 @@
 #endif /* ECP_MONTGOMERY */
 
 #if defined(ECP_SHORTWEIERSTRASS)
-    if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS )
+    if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS )
     {
         /* SEC1 3.2.1: Generate d such that 1 <= n < N */
         int count = 0;
@@ -2809,6 +2836,75 @@
     return( mbedtls_ecp_gen_keypair( &key->grp, &key->d, &key->Q, f_rng, p_rng ) );
 }
 
+#define ECP_CURVE25519_KEY_SIZE 32
+/*
+ * Read a private key.
+ */
+int mbedtls_ecp_read_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key,
+                          const unsigned char *buf, size_t buflen )
+{
+    int ret = 0;
+
+    ECP_VALIDATE_RET( key  != NULL );
+    ECP_VALIDATE_RET( buf  != NULL );
+
+    if( ( ret = mbedtls_ecp_group_load( &key->grp, grp_id ) ) != 0 )
+        return( ret );
+
+    ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
+
+#if defined(ECP_MONTGOMERY)
+    if( mbedtls_ecp_get_type( &key->grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY )
+    {
+        /*
+         * If it is Curve25519 curve then mask the key as mandated by RFC7748
+         */
+        if( grp_id == MBEDTLS_ECP_DP_CURVE25519 )
+        {
+            if( buflen != ECP_CURVE25519_KEY_SIZE )
+                return MBEDTLS_ERR_ECP_INVALID_KEY;
+
+            MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary_le( &key->d, buf, buflen ) );
+
+            /* Set the three least significant bits to 0 */
+            MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( &key->d, 0, 0 ) );
+            MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( &key->d, 1, 0 ) );
+            MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( &key->d, 2, 0 ) );
+
+            /* Set the most significant bit to 0 */
+            MBEDTLS_MPI_CHK(
+                    mbedtls_mpi_set_bit( &key->d,
+                                         ECP_CURVE25519_KEY_SIZE * 8 - 1, 0 )
+                    );
+
+            /* Set the second most significant bit to 1 */
+            MBEDTLS_MPI_CHK(
+                    mbedtls_mpi_set_bit( &key->d,
+                                         ECP_CURVE25519_KEY_SIZE * 8 - 2, 1 )
+                    );
+        }
+        else
+            ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
+    }
+
+#endif
+#if defined(ECP_SHORTWEIERSTRASS)
+    if( mbedtls_ecp_get_type( &key->grp ) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS )
+    {
+        MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &key->d, buf, buflen ) );
+
+        MBEDTLS_MPI_CHK( mbedtls_ecp_check_privkey( &key->grp, &key->d ) );
+    }
+
+#endif
+cleanup:
+
+    if( ret != 0 )
+        mbedtls_mpi_free( &key->d );
+
+    return( ret );
+}
+
 /*
  * Check a public-private key pair
  */
diff --git a/library/gcm.c b/library/gcm.c
index 675926a..5121a7a 100644
--- a/library/gcm.c
+++ b/library/gcm.c
@@ -175,7 +175,8 @@
     GCM_VALIDATE_RET( key != NULL );
     GCM_VALIDATE_RET( keybits == 128 || keybits == 192 || keybits == 256 );
 
-    cipher_info = mbedtls_cipher_info_from_values( cipher, keybits, MBEDTLS_MODE_ECB );
+    cipher_info = mbedtls_cipher_info_from_values( cipher, keybits,
+                                                   MBEDTLS_MODE_ECB );
     if( cipher_info == NULL )
         return( MBEDTLS_ERR_GCM_BAD_INPUT );
 
@@ -335,8 +336,8 @@
         gcm_mult( ctx, ctx->y, ctx->y );
     }
 
-    if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ctx->base_ectr,
-                             &olen ) ) != 0 )
+    if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16,
+                                       ctx->base_ectr, &olen ) ) != 0 )
     {
         return( ret );
     }
@@ -557,10 +558,10 @@
  */
 #define MAX_TESTS   6
 
-static const int key_index[MAX_TESTS] =
+static const int key_index_test_data[MAX_TESTS] =
     { 0, 0, 1, 1, 1, 1 };
 
-static const unsigned char key[MAX_TESTS][32] =
+static const unsigned char key_test_data[MAX_TESTS][32] =
 {
     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -572,13 +573,13 @@
       0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 },
 };
 
-static const size_t iv_len[MAX_TESTS] =
+static const size_t iv_len_test_data[MAX_TESTS] =
     { 12, 12, 12, 12, 8, 60 };
 
-static const int iv_index[MAX_TESTS] =
+static const int iv_index_test_data[MAX_TESTS] =
     { 0, 0, 1, 1, 1, 2 };
 
-static const unsigned char iv[MAX_TESTS][64] =
+static const unsigned char iv_test_data[MAX_TESTS][64] =
 {
     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00 },
@@ -594,13 +595,13 @@
       0xa6, 0x37, 0xb3, 0x9b },
 };
 
-static const size_t add_len[MAX_TESTS] =
+static const size_t add_len_test_data[MAX_TESTS] =
     { 0, 0, 0, 20, 20, 20 };
 
-static const int add_index[MAX_TESTS] =
+static const int add_index_test_data[MAX_TESTS] =
     { 0, 0, 0, 1, 1, 1 };
 
-static const unsigned char additional[MAX_TESTS][64] =
+static const unsigned char additional_test_data[MAX_TESTS][64] =
 {
     { 0x00 },
     { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
@@ -608,13 +609,13 @@
       0xab, 0xad, 0xda, 0xd2 },
 };
 
-static const size_t pt_len[MAX_TESTS] =
+static const size_t pt_len_test_data[MAX_TESTS] =
     { 0, 16, 64, 60, 60, 60 };
 
-static const int pt_index[MAX_TESTS] =
+static const int pt_index_test_data[MAX_TESTS] =
     { 0, 0, 1, 1, 1, 1 };
 
-static const unsigned char pt[MAX_TESTS][64] =
+static const unsigned char pt_test_data[MAX_TESTS][64] =
 {
     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
@@ -628,7 +629,7 @@
       0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 },
 };
 
-static const unsigned char ct[MAX_TESTS * 3][64] =
+static const unsigned char ct_test_data[MAX_TESTS * 3][64] =
 {
     { 0x00 },
     { 0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92,
@@ -737,7 +738,7 @@
       0x44, 0xae, 0x7e, 0x3f },
 };
 
-static const unsigned char tag[MAX_TESTS * 3][16] =
+static const unsigned char tag_test_data[MAX_TESTS * 3][16] =
 {
     { 0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61,
       0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7, 0x45, 0x5a },
@@ -797,7 +798,8 @@
                 mbedtls_printf( "  AES-GCM-%3d #%d (%s): ",
                                 key_len, i, "enc" );
 
-            ret = mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]],
+            ret = mbedtls_gcm_setkey( &ctx, cipher,
+                                      key_test_data[key_index_test_data[i]],
                                       key_len );
             /*
              * AES-192 is an optional feature that may be unavailable when
@@ -815,15 +817,19 @@
             }
 
             ret = mbedtls_gcm_crypt_and_tag( &ctx, MBEDTLS_GCM_ENCRYPT,
-                                        pt_len[i],
-                                        iv[iv_index[i]], iv_len[i],
-                                        additional[add_index[i]], add_len[i],
-                                        pt[pt_index[i]], buf, 16, tag_buf );
+                                pt_len_test_data[i],
+                                iv_test_data[iv_index_test_data[i]],
+                                iv_len_test_data[i],
+                                additional_test_data[add_index_test_data[i]],
+                                add_len_test_data[i],
+                                pt_test_data[pt_index_test_data[i]],
+                                buf, 16, tag_buf );
             if( ret != 0 )
                 goto exit;
 
-            if ( memcmp( buf, ct[j * 6 + i], pt_len[i] ) != 0 ||
-                 memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 )
+            if ( memcmp( buf, ct_test_data[j * 6 + i],
+                         pt_len_test_data[i] ) != 0 ||
+                 memcmp( tag_buf, tag_test_data[j * 6 + i], 16 ) != 0 )
             {
                 ret = 1;
                 goto exit;
@@ -840,22 +846,26 @@
                 mbedtls_printf( "  AES-GCM-%3d #%d (%s): ",
                                 key_len, i, "dec" );
 
-            ret = mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]],
+            ret = mbedtls_gcm_setkey( &ctx, cipher,
+                                      key_test_data[key_index_test_data[i]],
                                       key_len );
             if( ret != 0 )
                 goto exit;
 
             ret = mbedtls_gcm_crypt_and_tag( &ctx, MBEDTLS_GCM_DECRYPT,
-                                        pt_len[i],
-                                        iv[iv_index[i]], iv_len[i],
-                                        additional[add_index[i]], add_len[i],
-                                        ct[j * 6 + i], buf, 16, tag_buf );
+                                pt_len_test_data[i],
+                                iv_test_data[iv_index_test_data[i]],
+                                iv_len_test_data[i],
+                                additional_test_data[add_index_test_data[i]],
+                                add_len_test_data[i],
+                                ct_test_data[j * 6 + i], buf, 16, tag_buf );
 
             if( ret != 0 )
                 goto exit;
 
-            if( memcmp( buf, pt[pt_index[i]], pt_len[i] ) != 0 ||
-                memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 )
+            if( memcmp( buf, pt_test_data[pt_index_test_data[i]],
+                        pt_len_test_data[i] ) != 0 ||
+                memcmp( tag_buf, tag_test_data[j * 6 + i], 16 ) != 0 )
             {
                 ret = 1;
                 goto exit;
@@ -872,32 +882,40 @@
                 mbedtls_printf( "  AES-GCM-%3d #%d split (%s): ",
                                 key_len, i, "enc" );
 
-            ret = mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]],
+            ret = mbedtls_gcm_setkey( &ctx, cipher,
+                                      key_test_data[key_index_test_data[i]],
                                       key_len );
             if( ret != 0 )
                 goto exit;
 
             ret = mbedtls_gcm_starts( &ctx, MBEDTLS_GCM_ENCRYPT,
-                                      iv[iv_index[i]], iv_len[i],
-                                      additional[add_index[i]], add_len[i] );
+                                  iv_test_data[iv_index_test_data[i]],
+                                  iv_len_test_data[i],
+                                  additional_test_data[add_index_test_data[i]],
+                                  add_len_test_data[i] );
             if( ret != 0 )
                 goto exit;
 
-            if( pt_len[i] > 32 )
+            if( pt_len_test_data[i] > 32 )
             {
-                size_t rest_len = pt_len[i] - 32;
-                ret = mbedtls_gcm_update( &ctx, 32, pt[pt_index[i]], buf );
+                size_t rest_len = pt_len_test_data[i] - 32;
+                ret = mbedtls_gcm_update( &ctx, 32,
+                                          pt_test_data[pt_index_test_data[i]],
+                                          buf );
                 if( ret != 0 )
                     goto exit;
 
-                ret = mbedtls_gcm_update( &ctx, rest_len, pt[pt_index[i]] + 32,
-                                  buf + 32 );
+                ret = mbedtls_gcm_update( &ctx, rest_len,
+                                      pt_test_data[pt_index_test_data[i]] + 32,
+                                      buf + 32 );
                 if( ret != 0 )
                     goto exit;
             }
             else
             {
-                ret = mbedtls_gcm_update( &ctx, pt_len[i], pt[pt_index[i]], buf );
+                ret = mbedtls_gcm_update( &ctx, pt_len_test_data[i],
+                                          pt_test_data[pt_index_test_data[i]],
+                                          buf );
                 if( ret != 0 )
                     goto exit;
             }
@@ -906,8 +924,9 @@
             if( ret != 0 )
                 goto exit;
 
-            if( memcmp( buf, ct[j * 6 + i], pt_len[i] ) != 0 ||
-                memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 )
+            if( memcmp( buf, ct_test_data[j * 6 + i],
+                        pt_len_test_data[i] ) != 0 ||
+                memcmp( tag_buf, tag_test_data[j * 6 + i], 16 ) != 0 )
             {
                 ret = 1;
                 goto exit;
@@ -924,32 +943,38 @@
                 mbedtls_printf( "  AES-GCM-%3d #%d split (%s): ",
                                 key_len, i, "dec" );
 
-            ret = mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]],
+            ret = mbedtls_gcm_setkey( &ctx, cipher,
+                                      key_test_data[key_index_test_data[i]],
                                       key_len );
             if( ret != 0 )
                 goto exit;
 
             ret = mbedtls_gcm_starts( &ctx, MBEDTLS_GCM_DECRYPT,
-                              iv[iv_index[i]], iv_len[i],
-                              additional[add_index[i]], add_len[i] );
+                              iv_test_data[iv_index_test_data[i]],
+                              iv_len_test_data[i],
+                              additional_test_data[add_index_test_data[i]],
+                              add_len_test_data[i] );
             if( ret != 0 )
                 goto exit;
 
-            if( pt_len[i] > 32 )
+            if( pt_len_test_data[i] > 32 )
             {
-                size_t rest_len = pt_len[i] - 32;
-                ret = mbedtls_gcm_update( &ctx, 32, ct[j * 6 + i], buf );
+                size_t rest_len = pt_len_test_data[i] - 32;
+                ret = mbedtls_gcm_update( &ctx, 32, ct_test_data[j * 6 + i],
+                                          buf );
                 if( ret != 0 )
                     goto exit;
 
-                ret = mbedtls_gcm_update( &ctx, rest_len, ct[j * 6 + i] + 32,
+                ret = mbedtls_gcm_update( &ctx, rest_len,
+                                          ct_test_data[j * 6 + i] + 32,
                                           buf + 32 );
                 if( ret != 0 )
                     goto exit;
             }
             else
             {
-                ret = mbedtls_gcm_update( &ctx, pt_len[i], ct[j * 6 + i],
+                ret = mbedtls_gcm_update( &ctx, pt_len_test_data[i],
+                                          ct_test_data[j * 6 + i],
                                           buf );
                 if( ret != 0 )
                     goto exit;
@@ -959,8 +984,9 @@
             if( ret != 0 )
                 goto exit;
 
-            if( memcmp( buf, pt[pt_index[i]], pt_len[i] ) != 0 ||
-                memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 )
+            if( memcmp( buf, pt_test_data[pt_index_test_data[i]],
+                        pt_len_test_data[i] ) != 0 ||
+                memcmp( tag_buf, tag_test_data[j * 6 + i], 16 ) != 0 )
             {
                 ret = 1;
                 goto exit;
diff --git a/library/oid.c b/library/oid.c
index edea950..4e10f8a 100644
--- a/library/oid.c
+++ b/library/oid.c
@@ -41,10 +41,6 @@
 #define mbedtls_snprintf snprintf
 #endif
 
-#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
-#include "mbedtls/x509.h"
-#endif
-
 /*
  * Macro to automatically add the size of #define'd OIDs
  */
@@ -152,7 +148,6 @@
     return( MBEDTLS_ERR_OID_NOT_FOUND );                                   \
 }
 
-#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
 /*
  * For X520 attribute types
  */
@@ -260,23 +255,23 @@
 {
     {
         { ADD_LEN( MBEDTLS_OID_BASIC_CONSTRAINTS ),    "id-ce-basicConstraints",   "Basic Constraints" },
-        MBEDTLS_X509_EXT_BASIC_CONSTRAINTS,
+        MBEDTLS_OID_X509_EXT_BASIC_CONSTRAINTS,
     },
     {
         { ADD_LEN( MBEDTLS_OID_KEY_USAGE ),            "id-ce-keyUsage",           "Key Usage" },
-        MBEDTLS_X509_EXT_KEY_USAGE,
+        MBEDTLS_OID_X509_EXT_KEY_USAGE,
     },
     {
         { ADD_LEN( MBEDTLS_OID_EXTENDED_KEY_USAGE ),   "id-ce-extKeyUsage",        "Extended Key Usage" },
-        MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE,
+        MBEDTLS_OID_X509_EXT_EXTENDED_KEY_USAGE,
     },
     {
         { ADD_LEN( MBEDTLS_OID_SUBJECT_ALT_NAME ),     "id-ce-subjectAltName",     "Subject Alt Name" },
-        MBEDTLS_X509_EXT_SUBJECT_ALT_NAME,
+        MBEDTLS_OID_X509_EXT_SUBJECT_ALT_NAME,
     },
     {
         { ADD_LEN( MBEDTLS_OID_NS_CERT_TYPE ),         "id-netscape-certtype",     "Netscape Certificate Type" },
-        MBEDTLS_X509_EXT_NS_CERT_TYPE,
+        MBEDTLS_OID_X509_EXT_NS_CERT_TYPE,
     },
     {
         { NULL, 0, NULL, NULL },
@@ -300,7 +295,15 @@
 
 FN_OID_TYPED_FROM_ASN1(mbedtls_oid_descriptor_t, ext_key_usage, oid_ext_key_usage)
 FN_OID_GET_ATTR1(mbedtls_oid_get_extended_key_usage, mbedtls_oid_descriptor_t, ext_key_usage, const char *, description)
-#endif /* MBEDTLS_X509_USE_C || MBEDTLS_X509_CREATE_C */
+
+static const mbedtls_oid_descriptor_t oid_certificate_policies[] =
+{
+    { ADD_LEN( MBEDTLS_OID_ANY_POLICY ),      "anyPolicy",       "Any Policy" },
+    { NULL, 0, NULL, NULL },
+};
+
+FN_OID_TYPED_FROM_ASN1(mbedtls_oid_descriptor_t, certificate_policies, oid_certificate_policies)
+FN_OID_GET_ATTR1(mbedtls_oid_get_certificate_policies, mbedtls_oid_descriptor_t, certificate_policies, const char *, description)
 
 #if defined(MBEDTLS_MD_C)
 /*
diff --git a/library/pkcs5.c b/library/pkcs5.c
index 5013343..e7d805c 100644
--- a/library/pkcs5.c
+++ b/library/pkcs5.c
@@ -76,7 +76,8 @@
      *  }
      *
      */
-    if( ( ret = mbedtls_asn1_get_tag( &p, end, &salt->len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
+    if( ( ret = mbedtls_asn1_get_tag( &p, end, &salt->len,
+                                      MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
         return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret );
 
     salt->p = p;
@@ -141,7 +142,8 @@
         return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT +
                 MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
 
-    if( ( ret = mbedtls_asn1_get_alg( &p, end, &kdf_alg_oid, &kdf_alg_params ) ) != 0 )
+    if( ( ret = mbedtls_asn1_get_alg( &p, end, &kdf_alg_oid,
+                                      &kdf_alg_params ) ) != 0 )
         return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret );
 
     // Only PBKDF2 supported at the moment
@@ -202,7 +204,8 @@
     if( ( ret = mbedtls_cipher_setup( &cipher_ctx, cipher_info ) ) != 0 )
         goto exit;
 
-    if( ( ret = mbedtls_cipher_setkey( &cipher_ctx, key, 8 * keylen, (mbedtls_operation_t) mode ) ) != 0 )
+    if( ( ret = mbedtls_cipher_setkey( &cipher_ctx, key, 8 * keylen,
+                                       (mbedtls_operation_t) mode ) ) != 0 )
         goto exit;
 
     if( ( ret = mbedtls_cipher_crypt( &cipher_ctx, iv, enc_scheme_params.len,
@@ -217,7 +220,8 @@
 }
 #endif /* MBEDTLS_ASN1_PARSE_C */
 
-int mbedtls_pkcs5_pbkdf2_hmac( mbedtls_md_context_t *ctx, const unsigned char *password,
+int mbedtls_pkcs5_pbkdf2_hmac( mbedtls_md_context_t *ctx,
+                       const unsigned char *password,
                        size_t plen, const unsigned char *salt, size_t slen,
                        unsigned int iteration_count,
                        uint32_t key_length, unsigned char *output )
@@ -304,10 +308,10 @@
 
 #define MAX_TESTS   6
 
-static const size_t plen[MAX_TESTS] =
+static const size_t plen_test_data[MAX_TESTS] =
     { 8, 8, 8, 24, 9 };
 
-static const unsigned char password[MAX_TESTS][32] =
+static const unsigned char password_test_data[MAX_TESTS][32] =
 {
     "password",
     "password",
@@ -316,10 +320,10 @@
     "pass\0word",
 };
 
-static const size_t slen[MAX_TESTS] =
+static const size_t slen_test_data[MAX_TESTS] =
     { 4, 4, 4, 36, 5 };
 
-static const unsigned char salt[MAX_TESTS][40] =
+static const unsigned char salt_test_data[MAX_TESTS][40] =
 {
     "salt",
     "salt",
@@ -328,13 +332,13 @@
     "sa\0lt",
 };
 
-static const uint32_t it_cnt[MAX_TESTS] =
+static const uint32_t it_cnt_test_data[MAX_TESTS] =
     { 1, 2, 4096, 4096, 4096 };
 
-static const uint32_t key_len[MAX_TESTS] =
+static const uint32_t key_len_test_data[MAX_TESTS] =
     { 20, 20, 20, 25, 16 };
 
-static const unsigned char result_key[MAX_TESTS][32] =
+static const unsigned char result_key_test_data[MAX_TESTS][32] =
 {
     { 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71,
       0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06,
@@ -380,10 +384,12 @@
         if( verbose != 0 )
             mbedtls_printf( "  PBKDF2 (SHA1) #%d: ", i );
 
-        ret = mbedtls_pkcs5_pbkdf2_hmac( &sha1_ctx, password[i], plen[i], salt[i],
-                                  slen[i], it_cnt[i], key_len[i], key );
+        ret = mbedtls_pkcs5_pbkdf2_hmac( &sha1_ctx, password_test_data[i],
+                                         plen_test_data[i], salt_test_data[i],
+                                         slen_test_data[i], it_cnt_test_data[i],
+                                         key_len_test_data[i], key );
         if( ret != 0 ||
-            memcmp( result_key[i], key, key_len[i] ) != 0 )
+            memcmp( result_key_test_data[i], key, key_len_test_data[i] ) != 0 )
         {
             if( verbose != 0 )
                 mbedtls_printf( "failed\n" );
diff --git a/library/ssl_cache.c b/library/ssl_cache.c
index 47867f1..62a0a29 100644
--- a/library/ssl_cache.c
+++ b/library/ssl_cache.c
@@ -40,6 +40,7 @@
 #endif
 
 #include "mbedtls/ssl_cache.h"
+#include "mbedtls/ssl_internal.h"
 
 #include <string.h>
 
@@ -92,16 +93,24 @@
                     entry->session.id_len ) != 0 )
             continue;
 
-        memcpy( session->master, entry->session.master, 48 );
+        ret = mbedtls_ssl_session_copy( session, &entry->session );
+        if( ret != 0 )
+        {
+            ret = 1;
+            goto exit;
+        }
 
-        session->verify_result = entry->session.verify_result;
-
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
+    defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
         /*
          * Restore peer certificate (without rest of the original chain)
          */
         if( entry->peer_cert.p != NULL )
         {
+            /* `session->peer_cert` is NULL after the call to
+             * mbedtls_ssl_session_copy(), because cache entries
+             * have the `peer_cert` field set to NULL. */
+
             if( ( session->peer_cert = mbedtls_calloc( 1,
                                  sizeof(mbedtls_x509_crt) ) ) == NULL )
             {
@@ -119,7 +128,7 @@
                 goto exit;
             }
         }
-#endif /* MBEDTLS_X509_CRT_PARSE_C */
+#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 
         ret = 0;
         goto exit;
@@ -239,9 +248,8 @@
 #endif
     }
 
-    memcpy( &cur->session, session, sizeof( mbedtls_ssl_session ) );
-
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
+    defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
     /*
      * If we're reusing an entry, free its certificate first
      */
@@ -250,26 +258,43 @@
         mbedtls_free( cur->peer_cert.p );
         memset( &cur->peer_cert, 0, sizeof(mbedtls_x509_buf) );
     }
+#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 
-    /*
-     * Store peer certificate
-     */
-    if( session->peer_cert != NULL )
+    /* Copy the entire session; this temporarily makes a copy of the
+     * X.509 CRT structure even though we only want to store the raw CRT.
+     * This inefficiency will go away as soon as we implement on-demand
+     * parsing of CRTs, in which case there's no need for the `peer_cert`
+     * field anymore in the first place, and we're done after this call. */
+    ret = mbedtls_ssl_session_copy( &cur->session, session );
+    if( ret != 0 )
     {
-        cur->peer_cert.p = mbedtls_calloc( 1, session->peer_cert->raw.len );
+        ret = 1;
+        goto exit;
+    }
+
+#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
+    defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    /* If present, free the X.509 structure and only store the raw CRT data. */
+    if( cur->session.peer_cert != NULL )
+    {
+        cur->peer_cert.p =
+            mbedtls_calloc( 1, cur->session.peer_cert->raw.len );
         if( cur->peer_cert.p == NULL )
         {
             ret = 1;
             goto exit;
         }
 
-        memcpy( cur->peer_cert.p, session->peer_cert->raw.p,
-                session->peer_cert->raw.len );
+        memcpy( cur->peer_cert.p,
+                cur->session.peer_cert->raw.p,
+                cur->session.peer_cert->raw.len );
         cur->peer_cert.len = session->peer_cert->raw.len;
 
+        mbedtls_x509_crt_free( cur->session.peer_cert );
+        mbedtls_free( cur->session.peer_cert );
         cur->session.peer_cert = NULL;
     }
-#endif /* MBEDTLS_X509_CRT_PARSE_C */
+#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 
     ret = 0;
 
@@ -311,9 +336,10 @@
 
         mbedtls_ssl_session_free( &prv->session );
 
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
+    defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
         mbedtls_free( prv->peer_cert.p );
-#endif /* MBEDTLS_X509_CRT_PARSE_C */
+#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 
         mbedtls_free( prv );
     }
diff --git a/library/ssl_ciphersuites.c b/library/ssl_ciphersuites.c
index 745474e..518f7dd 100644
--- a/library/ssl_ciphersuites.c
+++ b/library/ssl_ciphersuites.c
@@ -43,11 +43,11 @@
 /*
  * Ordered from most preferred to least preferred in terms of security.
  *
- * Current rule (except rc4, weak and null which come last):
+ * Current rule (except RC4 and 3DES, weak and null which come last):
  * 1. By key exchange:
  *    Forward-secure non-PSK > forward-secure PSK > ECJPAKE > other non-PSK > other PSK
  * 2. By key length and cipher:
- *    ChaCha > AES-256 > Camellia-256 > ARIA-256 > AES-128 > Camellia-128 > ARIA-128 > 3DES
+ *    ChaCha > AES-256 > Camellia-256 > ARIA-256 > AES-128 > Camellia-128 > ARIA-128
  * 3. By cipher mode when relevant GCM > CCM > CBC > CCM_8
  * 4. By hash function used when relevant
  * 5. By key exchange/auth again: EC > non-EC
@@ -126,11 +126,6 @@
     MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256,
     MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256,
 
-    /* All remaining >= 128-bit ephemeral suites */
-    MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
-    MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
-    MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
-
     /* The PSK ephemeral suites */
     MBEDTLS_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
     MBEDTLS_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
@@ -162,9 +157,6 @@
     MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256,
     MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256,
 
-    MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA,
-    MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
-
     /* The ECJPAKE suite */
     MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8,
 
@@ -228,11 +220,6 @@
     MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256,
     MBEDTLS_TLS_RSA_WITH_ARIA_128_CBC_SHA256,
 
-    /* All remaining >= 128-bit suites */
-    MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA,
-    MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
-    MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
-
     /* The RSA PSK suites */
     MBEDTLS_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256,
     MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384,
@@ -251,8 +238,6 @@
     MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256,
     MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256,
 
-    MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
-
     /* The PSK suites */
     MBEDTLS_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256,
     MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384,
@@ -275,6 +260,16 @@
     MBEDTLS_TLS_PSK_WITH_ARIA_128_GCM_SHA256,
     MBEDTLS_TLS_PSK_WITH_ARIA_128_CBC_SHA256,
 
+    /* 3DES suites */
+    MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+    MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+    MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+    MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA,
+    MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
+    MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+    MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+    MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+    MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
     MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA,
 
     /* RC4 suites */
@@ -2187,6 +2182,26 @@
 static int supported_ciphersuites[MAX_CIPHERSUITES];
 static int supported_init = 0;
 
+static int ciphersuite_is_removed( const mbedtls_ssl_ciphersuite_t *cs_info )
+{
+    (void)cs_info;
+
+#if defined(MBEDTLS_REMOVE_ARC4_CIPHERSUITES)
+    if( cs_info->cipher == MBEDTLS_CIPHER_ARC4_128 )
+        return( 1 );
+#endif /* MBEDTLS_REMOVE_ARC4_CIPHERSUITES */
+
+#if defined(MBEDTLS_REMOVE_3DES_CIPHERSUITES)
+    if( cs_info->cipher == MBEDTLS_CIPHER_DES_EDE3_ECB ||
+        cs_info->cipher == MBEDTLS_CIPHER_DES_EDE3_CBC )
+    {
+        return( 1 );
+    }
+#endif /* MBEDTLS_REMOVE_3DES_CIPHERSUITES */
+
+    return( 0 );
+}
+
 const int *mbedtls_ssl_list_ciphersuites( void )
 {
     /*
@@ -2202,14 +2217,12 @@
              *p != 0 && q < supported_ciphersuites + MAX_CIPHERSUITES - 1;
              p++ )
         {
-#if defined(MBEDTLS_REMOVE_ARC4_CIPHERSUITES)
             const mbedtls_ssl_ciphersuite_t *cs_info;
             if( ( cs_info = mbedtls_ssl_ciphersuite_from_id( *p ) ) != NULL &&
-                cs_info->cipher != MBEDTLS_CIPHER_ARC4_128 )
-#else
-            if( mbedtls_ssl_ciphersuite_from_id( *p ) != NULL )
-#endif
+                !ciphersuite_is_removed( cs_info ) )
+            {
                 *(q++) = *p;
+            }
         }
         *q = 0;
 
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index 06bcc73..4e5b3a6 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -39,6 +39,10 @@
 #include "mbedtls/ssl.h"
 #include "mbedtls/ssl_internal.h"
 
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+#include "mbedtls/psa_util.h"
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
 #include <string.h>
 
 #include <stdint.h>
@@ -2109,6 +2113,64 @@
           MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED ||
           MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */
 
+#if defined(MBEDTLS_USE_PSA_CRYPTO) &&                           \
+        ( defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) ||     \
+          defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) )
+static int ssl_parse_server_ecdh_params_psa( mbedtls_ssl_context *ssl,
+                                             unsigned char **p,
+                                             unsigned char *end )
+{
+    uint16_t tls_id;
+    uint8_t ecpoint_len;
+    mbedtls_ssl_handshake_params *handshake = ssl->handshake;
+
+    /*
+     * Parse ECC group
+     */
+
+    if( end - *p < 4 )
+        return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
+
+    /* First byte is curve_type; only named_curve is handled */
+    if( *(*p)++ != MBEDTLS_ECP_TLS_NAMED_CURVE )
+        return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
+
+    /* Next two bytes are the namedcurve value */
+    tls_id = *(*p)++;
+    tls_id <<= 8;
+    tls_id |= *(*p)++;
+
+    /* Convert EC group to PSA key type. */
+    if( ( handshake->ecdh_psa_curve =
+          mbedtls_psa_parse_tls_ecc_group( tls_id ) ) == 0 )
+    {
+        return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
+    }
+
+    /*
+     * Put peer's ECDH public key in the format understood by PSA.
+     */
+
+    ecpoint_len = *(*p)++;
+    if( (size_t)( end - *p ) < ecpoint_len )
+        return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
+
+    if( mbedtls_psa_tls_ecpoint_to_psa_ec( handshake->ecdh_psa_curve,
+                                    *p, ecpoint_len,
+                                    handshake->ecdh_psa_peerkey,
+                                    sizeof( handshake->ecdh_psa_peerkey ),
+                                    &handshake->ecdh_psa_peerkey_len ) != 0 )
+    {
+        return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+    }
+
+    *p += ecpoint_len;
+    return( 0 );
+}
+#endif /* MBEDTLS_USE_PSA_CRYPTO &&
+            ( MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED ||
+              MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED ) */
+
 #if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) ||                     \
     defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) ||                   \
     defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED)
@@ -2203,6 +2265,7 @@
     int ret;
     size_t len_bytes = ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ? 0 : 2;
     unsigned char *p = ssl->handshake->premaster + pms_offset;
+    mbedtls_pk_context * peer_pk;
 
     if( offset + len_bytes > MBEDTLS_SSL_OUT_CONTENT_LEN )
     {
@@ -2228,23 +2291,28 @@
 
     ssl->handshake->pmslen = 48;
 
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    peer_pk = &ssl->handshake->peer_pubkey;
+#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
     if( ssl->session_negotiate->peer_cert == NULL )
     {
-        MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) );
-        return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
+        /* Should never happen */
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
+        return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
     }
+    peer_pk = &ssl->session_negotiate->peer_cert->pk;
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 
     /*
      * Now write it out, encrypted
      */
-    if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk,
-                MBEDTLS_PK_RSA ) )
+    if( ! mbedtls_pk_can_do( peer_pk, MBEDTLS_PK_RSA ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "certificate key type mismatch" ) );
         return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH );
     }
 
-    if( ( ret = mbedtls_pk_encrypt( &ssl->session_negotiate->peer_cert->pk,
+    if( ( ret = mbedtls_pk_encrypt( peer_pk,
                             p, ssl->handshake->pmslen,
                             ssl->out_msg + offset + len_bytes, olen,
                             MBEDTLS_SSL_OUT_CONTENT_LEN - offset - len_bytes,
@@ -2264,6 +2332,10 @@
     }
 #endif
 
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    /* We don't need the peer's public key anymore. Free it. */
+    mbedtls_pk_free( peer_pk );
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
     return( 0 );
 }
 #endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED ||
@@ -2339,21 +2411,27 @@
 {
     int ret;
     const mbedtls_ecp_keypair *peer_key;
+    mbedtls_pk_context * peer_pk;
 
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    peer_pk = &ssl->handshake->peer_pubkey;
+#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
     if( ssl->session_negotiate->peer_cert == NULL )
     {
-        MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) );
-        return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
+        /* Should never happen */
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
+        return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
     }
+    peer_pk = &ssl->session_negotiate->peer_cert->pk;
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 
-    if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk,
-                     MBEDTLS_PK_ECKEY ) )
+    if( ! mbedtls_pk_can_do( peer_pk, MBEDTLS_PK_ECKEY ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "server key not ECDH capable" ) );
         return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH );
     }
 
-    peer_key = mbedtls_pk_ec( ssl->session_negotiate->peer_cert->pk );
+    peer_key = mbedtls_pk_ec( *peer_pk );
 
     if( ( ret = mbedtls_ecdh_get_params( &ssl->handshake->ecdh_ctx, peer_key,
                                  MBEDTLS_ECDH_THEIRS ) ) != 0 )
@@ -2368,6 +2446,13 @@
         return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
     }
 
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    /* We don't need the peer's public key anymore. Free it,
+     * so that more RAM is available for upcoming expensive
+     * operations like ECDHE. */
+    mbedtls_pk_free( peer_pk );
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+
     return( ret );
 }
 #endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) ||
@@ -2510,6 +2595,24 @@
     else
 #endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED ||
           MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */
+#if defined(MBEDTLS_USE_PSA_CRYPTO) &&                           \
+        ( defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) ||     \
+          defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) )
+    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA ||
+        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA )
+    {
+        if( ssl_parse_server_ecdh_params_psa( ssl, &p, end ) != 0 )
+        {
+            MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
+            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                                            MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+            return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
+        }
+    }
+    else
+#endif /* MBEDTLS_USE_PSA_CRYPTO &&
+            ( MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED ||
+              MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED ) */
 #if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) ||                     \
     defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) ||                     \
     defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
@@ -2560,6 +2663,8 @@
         size_t params_len = p - params;
         void *rs_ctx = NULL;
 
+        mbedtls_pk_context * peer_pk;
+
         /*
          * Handle the digitally-signed structure
          */
@@ -2662,18 +2767,22 @@
 
         MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen );
 
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+        peer_pk = &ssl->handshake->peer_pubkey;
+#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
         if( ssl->session_negotiate->peer_cert == NULL )
         {
-            MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
-            return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
+            /* Should never happen */
+            MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
+            return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
         }
+        peer_pk = &ssl->session_negotiate->peer_cert->pk;
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 
         /*
          * Verify signature
          */
-        if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk, pk_alg ) )
+        if( !mbedtls_pk_can_do( peer_pk, pk_alg ) )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
             mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
@@ -2686,8 +2795,7 @@
             rs_ctx = &ssl->handshake->ecrs_ctx.pk;
 #endif
 
-        if( ( ret = mbedtls_pk_verify_restartable(
-                        &ssl->session_negotiate->peer_cert->pk,
+        if( ( ret = mbedtls_pk_verify_restartable( peer_pk,
                         md_alg, hash, hashlen, p, sig_len, rs_ctx ) ) != 0 )
         {
 #if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
@@ -2702,6 +2810,13 @@
 #endif
             return( ret );
         }
+
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+        /* We don't need the peer's public key anymore. Free it,
+         * so that more RAM is available for upcoming expensive
+         * operations like ECDHE. */
+        mbedtls_pk_free( peer_pk );
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
     }
 #endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */
 
@@ -2938,7 +3053,9 @@
 static int ssl_write_client_key_exchange( mbedtls_ssl_context *ssl )
 {
     int ret;
-    size_t i, n;
+
+    size_t header_len;
+    size_t content_len;
     const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
         ssl->transform_negotiate->ciphersuite_info;
 
@@ -2950,16 +3067,16 @@
         /*
          * DHM key exchange -- send G^X mod P
          */
-        n = ssl->handshake->dhm_ctx.len;
+        content_len = ssl->handshake->dhm_ctx.len;
 
-        ssl->out_msg[4] = (unsigned char)( n >> 8 );
-        ssl->out_msg[5] = (unsigned char)( n      );
-        i = 6;
+        ssl->out_msg[4] = (unsigned char)( content_len >> 8 );
+        ssl->out_msg[5] = (unsigned char)( content_len      );
+        header_len = 6;
 
         ret = mbedtls_dhm_make_public( &ssl->handshake->dhm_ctx,
-                                (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ),
-                               &ssl->out_msg[i], n,
-                                ssl->conf->f_rng, ssl->conf->p_rng );
+                           (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ),
+                           &ssl->out_msg[header_len], content_len,
+                           ssl->conf->f_rng, ssl->conf->p_rng );
         if( ret != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_make_public", ret );
@@ -2970,10 +3087,10 @@
         MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: GX", &ssl->handshake->dhm_ctx.GX );
 
         if( ( ret = mbedtls_dhm_calc_secret( &ssl->handshake->dhm_ctx,
-                                      ssl->handshake->premaster,
-                                      MBEDTLS_PREMASTER_SIZE,
-                                     &ssl->handshake->pmslen,
-                                      ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
+                                   ssl->handshake->premaster,
+                                   MBEDTLS_PREMASTER_SIZE,
+                                   &ssl->handshake->pmslen,
+                                   ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_calc_secret", ret );
             return( ret );
@@ -2983,6 +3100,119 @@
     }
     else
 #endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED */
+#if defined(MBEDTLS_USE_PSA_CRYPTO) &&                           \
+        ( defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) ||     \
+          defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) )
+    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA ||
+        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA )
+    {
+        psa_status_t status;
+        psa_key_policy_t policy;
+
+        mbedtls_ssl_handshake_params *handshake = ssl->handshake;
+
+        unsigned char own_pubkey[MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH];
+        size_t own_pubkey_len;
+        unsigned char *own_pubkey_ecpoint;
+        size_t own_pubkey_ecpoint_len;
+
+        psa_crypto_generator_t generator = PSA_CRYPTO_GENERATOR_INIT;
+
+        header_len = 4;
+
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "Perform PSA-based ECDH computation." ) );
+
+        /*
+         * Generate EC private key for ECDHE exchange.
+         */
+
+        /* Allocate a new key slot for the private key. */
+
+        status = psa_allocate_key( &handshake->ecdh_psa_privkey );
+        if( status != PSA_SUCCESS )
+            return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+
+        /* The master secret is obtained from the shared ECDH secret by
+         * applying the TLS 1.2 PRF with a specific salt and label. While
+         * the PSA Crypto API encourages combining key agreement schemes
+         * such as ECDH with fixed KDFs such as TLS 1.2 PRF, it does not
+         * yet support the provisioning of salt + label to the KDF.
+         * For the time being, we therefore need to split the computation
+         * of the ECDH secret and the application of the TLS 1.2 PRF. */
+        policy = psa_key_policy_init();
+        psa_key_policy_set_usage( &policy,
+                                  PSA_KEY_USAGE_DERIVE,
+                                  PSA_ALG_ECDH( PSA_ALG_SELECT_RAW ) );
+        status = psa_set_key_policy( handshake->ecdh_psa_privkey, &policy );
+        if( status != PSA_SUCCESS )
+            return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+
+        /* Generate ECDH private key. */
+        status = psa_generate_key( handshake->ecdh_psa_privkey,
+                          PSA_KEY_TYPE_ECC_KEYPAIR( handshake->ecdh_psa_curve ),
+                          MBEDTLS_PSA_ECC_KEY_BITS_OF_CURVE( handshake->ecdh_psa_curve ),
+                          NULL, 0 );
+        if( status != PSA_SUCCESS )
+            return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+
+        /* Export the public part of the ECDH private key from PSA
+         * and convert it to ECPoint format used in ClientKeyExchange. */
+        status = psa_export_public_key( handshake->ecdh_psa_privkey,
+                                        own_pubkey, sizeof( own_pubkey ),
+                                        &own_pubkey_len );
+        if( status != PSA_SUCCESS )
+            return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+
+        if( mbedtls_psa_tls_psa_ec_to_ecpoint( own_pubkey,
+                                               own_pubkey_len,
+                                               &own_pubkey_ecpoint,
+                                               &own_pubkey_ecpoint_len ) != 0 )
+        {
+            return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+        }
+
+        /* Copy ECPoint structure to outgoing message buffer. */
+        ssl->out_msg[header_len] = own_pubkey_ecpoint_len;
+        memcpy( ssl->out_msg + header_len + 1,
+                own_pubkey_ecpoint, own_pubkey_ecpoint_len );
+        content_len = own_pubkey_ecpoint_len + 1;
+
+        /* Compute ECDH shared secret. */
+        status = psa_key_agreement( &generator,
+                                    handshake->ecdh_psa_privkey,
+                                    handshake->ecdh_psa_peerkey,
+                                    handshake->ecdh_psa_peerkey_len,
+                                    PSA_ALG_ECDH( PSA_ALG_SELECT_RAW ) );
+        if( status != PSA_SUCCESS )
+            return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+
+        /* The ECDH secret is the premaster secret used for key derivation. */
+
+        ssl->handshake->pmslen =
+            MBEDTLS_PSA_ECC_KEY_BYTES_OF_CURVE( handshake->ecdh_psa_curve );
+
+        status = psa_generator_read( &generator,
+                                     ssl->handshake->premaster,
+                                     ssl->handshake->pmslen );
+        if( status != PSA_SUCCESS )
+        {
+            psa_generator_abort( &generator );
+            return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+        }
+
+        status = psa_generator_abort( &generator );
+        if( status != PSA_SUCCESS )
+            return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+
+        status = psa_destroy_key( handshake->ecdh_psa_privkey );
+        if( status != PSA_SUCCESS )
+            return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+        handshake->ecdh_psa_privkey = 0;
+    }
+    else
+#endif /* MBEDTLS_USE_PSA_CRYPTO &&
+            ( MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED ||
+              MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED ) */
 #if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) ||                     \
     defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) ||                   \
     defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) ||                      \
@@ -2995,7 +3225,7 @@
         /*
          * ECDH key exchange -- send client public value
          */
-        i = 4;
+        header_len = 4;
 
 #if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
         if( ssl->handshake->ecrs_enabled )
@@ -3008,8 +3238,8 @@
 #endif
 
         ret = mbedtls_ecdh_make_public( &ssl->handshake->ecdh_ctx,
-                                &n,
-                                &ssl->out_msg[i], 1000,
+                                &content_len,
+                                &ssl->out_msg[header_len], 1000,
                                 ssl->conf->f_rng, ssl->conf->p_rng );
         if( ret != 0 )
         {
@@ -3027,19 +3257,19 @@
 #if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
         if( ssl->handshake->ecrs_enabled )
         {
-            ssl->handshake->ecrs_n = n;
+            ssl->handshake->ecrs_n = content_len;
             ssl->handshake->ecrs_state = ssl_ecrs_cke_ecdh_calc_secret;
         }
 
 ecdh_calc_secret:
         if( ssl->handshake->ecrs_enabled )
-            n = ssl->handshake->ecrs_n;
+            content_len = ssl->handshake->ecrs_n;
 #endif
         if( ( ret = mbedtls_ecdh_calc_secret( &ssl->handshake->ecdh_ctx,
-                                      &ssl->handshake->pmslen,
-                                       ssl->handshake->premaster,
-                                       MBEDTLS_MPI_MAX_SIZE,
-                                       ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
+                                   &ssl->handshake->pmslen,
+                                   ssl->handshake->premaster,
+                                   MBEDTLS_MPI_MAX_SIZE,
+                                   ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_calc_secret", ret );
 #if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
@@ -3071,26 +3301,28 @@
             return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
         }
 
-        i = 4;
-        n = ssl->conf->psk_identity_len;
+        header_len = 4;
+        content_len = ssl->conf->psk_identity_len;
 
-        if( i + 2 + n > MBEDTLS_SSL_OUT_CONTENT_LEN )
+        if( header_len + 2 + content_len > MBEDTLS_SSL_OUT_CONTENT_LEN )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "psk identity too long or "
                                         "SSL buffer too short" ) );
             return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
         }
 
-        ssl->out_msg[i++] = (unsigned char)( n >> 8 );
-        ssl->out_msg[i++] = (unsigned char)( n      );
+        ssl->out_msg[header_len++] = (unsigned char)( content_len >> 8 );
+        ssl->out_msg[header_len++] = (unsigned char)( content_len      );
 
-        memcpy( ssl->out_msg + i, ssl->conf->psk_identity, ssl->conf->psk_identity_len );
-        i += ssl->conf->psk_identity_len;
+        memcpy( ssl->out_msg + header_len,
+                ssl->conf->psk_identity,
+                ssl->conf->psk_identity_len );
+        header_len += ssl->conf->psk_identity_len;
 
 #if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
         if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK )
         {
-            n = 0;
+            content_len = 0;
         }
         else
 #endif
@@ -3103,7 +3335,8 @@
                 return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
-            if( ( ret = ssl_write_encrypted_pms( ssl, i, &n, 2 ) ) != 0 )
+            if( ( ret = ssl_write_encrypted_pms( ssl, header_len,
+                                                 &content_len, 2 ) ) != 0 )
                 return( ret );
         }
         else
@@ -3120,21 +3353,22 @@
             /*
              * ClientDiffieHellmanPublic public (DHM send G^X mod P)
              */
-            n = ssl->handshake->dhm_ctx.len;
+            content_len = ssl->handshake->dhm_ctx.len;
 
-            if( i + 2 + n > MBEDTLS_SSL_OUT_CONTENT_LEN )
+            if( header_len + 2 + content_len >
+                MBEDTLS_SSL_OUT_CONTENT_LEN )
             {
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "psk identity or DHM size too long"
                                             " or SSL buffer too short" ) );
                 return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
             }
 
-            ssl->out_msg[i++] = (unsigned char)( n >> 8 );
-            ssl->out_msg[i++] = (unsigned char)( n      );
+            ssl->out_msg[header_len++] = (unsigned char)( content_len >> 8 );
+            ssl->out_msg[header_len++] = (unsigned char)( content_len      );
 
             ret = mbedtls_dhm_make_public( &ssl->handshake->dhm_ctx,
                     (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ),
-                    &ssl->out_msg[i], n,
+                    &ssl->out_msg[header_len], content_len,
                     ssl->conf->f_rng, ssl->conf->p_rng );
             if( ret != 0 )
             {
@@ -3156,8 +3390,10 @@
             /*
              * ClientECDiffieHellmanPublic public;
              */
-            ret = mbedtls_ecdh_make_public( &ssl->handshake->ecdh_ctx, &n,
-                    &ssl->out_msg[i], MBEDTLS_SSL_OUT_CONTENT_LEN - i,
+            ret = mbedtls_ecdh_make_public( &ssl->handshake->ecdh_ctx,
+                    &content_len,
+                    &ssl->out_msg[header_len],
+                    MBEDTLS_SSL_OUT_CONTENT_LEN - header_len,
                     ssl->conf->f_rng, ssl->conf->p_rng );
             if( ret != 0 )
             {
@@ -3198,8 +3434,9 @@
 #if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)
     if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA )
     {
-        i = 4;
-        if( ( ret = ssl_write_encrypted_pms( ssl, i, &n, 0 ) ) != 0 )
+        header_len = 4;
+        if( ( ret = ssl_write_encrypted_pms( ssl, header_len,
+                                             &content_len, 0 ) ) != 0 )
             return( ret );
     }
     else
@@ -3207,10 +3444,12 @@
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
     if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
     {
-        i = 4;
+        header_len = 4;
 
         ret = mbedtls_ecjpake_write_round_two( &ssl->handshake->ecjpake_ctx,
-                ssl->out_msg + i, MBEDTLS_SSL_OUT_CONTENT_LEN - i, &n,
+                ssl->out_msg + header_len,
+                MBEDTLS_SSL_OUT_CONTENT_LEN - header_len,
+                &content_len,
                 ssl->conf->f_rng, ssl->conf->p_rng );
         if( ret != 0 )
         {
@@ -3235,7 +3474,7 @@
         return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
     }
 
-    ssl->out_msglen  = i + n;
+    ssl->out_msglen  = header_len + content_len;
     ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE;
     ssl->out_msg[0]  = MBEDTLS_SSL_HS_CLIENT_KEY_EXCHANGE;
 
@@ -3252,12 +3491,7 @@
     return( 0 );
 }
 
-#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)       && \
-    !defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)   && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED)  && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)&& \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
+#if !defined(MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED)
 static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl )
 {
     const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
@@ -3272,11 +3506,7 @@
         return( ret );
     }
 
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) );
         ssl->state++;
@@ -3286,7 +3516,7 @@
     MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
     return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
 }
-#else
+#else /* !MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */
 static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
@@ -3315,11 +3545,7 @@
         return( ret );
     }
 
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) );
         ssl->state++;
@@ -3462,12 +3688,7 @@
 
     return( ret );
 }
-#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */
+#endif /* MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
 static int ssl_parse_new_session_ticket( mbedtls_ssl_context *ssl )
@@ -3541,6 +3762,15 @@
     if( ticket_len == 0 )
         return( 0 );
 
+    if( ssl->session != NULL && ssl->session->ticket != NULL )
+    {
+        mbedtls_platform_zeroize( ssl->session->ticket,
+                                  ssl->session->ticket_len );
+        mbedtls_free( ssl->session->ticket );
+        ssl->session->ticket = NULL;
+        ssl->session->ticket_len = 0;
+    }
+
     mbedtls_platform_zeroize( ssl->session_negotiate->ticket,
                               ssl->session_negotiate->ticket_len );
     mbedtls_free( ssl->session_negotiate->ticket );
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index 46e24e4..c969089 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -2680,12 +2680,7 @@
     return( ret );
 }
 
-#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)       && \
-    !defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)   && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED)  && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)&& \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
+#if !defined(MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED)
 static int ssl_write_certificate_request( mbedtls_ssl_context *ssl )
 {
     const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
@@ -2693,11 +2688,7 @@
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate request" ) );
 
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate request" ) );
         ssl->state++;
@@ -2707,7 +2698,7 @@
     MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
     return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
 }
-#else
+#else /* !MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */
 static int ssl_write_certificate_request( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
@@ -2731,11 +2722,7 @@
 #endif
         authmode = ssl->conf->authmode;
 
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ||
+    if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) ||
         authmode == MBEDTLS_SSL_VERIFY_NONE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate request" ) );
@@ -2874,12 +2861,7 @@
 
     return( ret );
 }
-#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */
+#endif /* MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */
 
 #if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \
     defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)
@@ -4048,12 +4030,7 @@
     return( 0 );
 }
 
-#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)       && \
-    !defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)   && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED)  && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)&& \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
+#if !defined(MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED)
 static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
 {
     const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
@@ -4061,11 +4038,7 @@
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) );
 
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) );
         ssl->state++;
@@ -4075,7 +4048,7 @@
     MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
     return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
 }
-#else
+#else /* !MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */
 static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
@@ -4089,21 +4062,33 @@
     mbedtls_md_type_t md_alg;
     const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
         ssl->transform_negotiate->ciphersuite_info;
+    mbedtls_pk_context * peer_pk;
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) );
 
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ||
-        ssl->session_negotiate->peer_cert == NULL )
+    if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) );
         ssl->state++;
         return( 0 );
     }
 
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    if( ssl->session_negotiate->peer_cert == NULL )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) );
+        ssl->state++;
+        return( 0 );
+    }
+#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+    if( ssl->session_negotiate->peer_cert_digest == NULL )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) );
+        ssl->state++;
+        return( 0 );
+    }
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+
     /* Read the message without adding it to the checksum */
     ret = mbedtls_ssl_read_record( ssl, 0 /* no checksum update */ );
     if( 0 != ret )
@@ -4124,6 +4109,17 @@
 
     i = mbedtls_ssl_hs_hdr_len( ssl );
 
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    peer_pk = &ssl->handshake->peer_pubkey;
+#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+    if( ssl->session_negotiate->peer_cert == NULL )
+    {
+        /* Should never happen */
+        return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+    }
+    peer_pk = &ssl->session_negotiate->peer_cert->pk;
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+
     /*
      *  struct {
      *     SignatureAndHashAlgorithm algorithm; -- TLS 1.2 only
@@ -4138,8 +4134,7 @@
         hashlen = 36;
 
         /* For ECDSA, use SHA-1, not MD-5 + SHA-1 */
-        if( mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk,
-                        MBEDTLS_PK_ECDSA ) )
+        if( mbedtls_pk_can_do( peer_pk, MBEDTLS_PK_ECDSA ) )
         {
             hash_start += 16;
             hashlen -= 16;
@@ -4194,7 +4189,7 @@
         /*
          * Check the certificate's key type matches the signature alg
          */
-        if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk, pk_alg ) )
+        if( !mbedtls_pk_can_do( peer_pk, pk_alg ) )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "sig_alg doesn't match cert key" ) );
             return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
@@ -4227,7 +4222,7 @@
     /* Calculate hash and verify signature */
     ssl->handshake->calc_verify( ssl, hash );
 
-    if( ( ret = mbedtls_pk_verify( &ssl->session_negotiate->peer_cert->pk,
+    if( ( ret = mbedtls_pk_verify( peer_pk,
                            md_alg, hash_start, hashlen,
                            ssl->in_msg + i, sig_len ) ) != 0 )
     {
@@ -4241,12 +4236,7 @@
 
     return( ret );
 }
-#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED &&
-          !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */
+#endif /* MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
 static int ssl_write_new_session_ticket( mbedtls_ssl_context *ssl )
diff --git a/library/ssl_ticket.c b/library/ssl_ticket.c
index 7de4e66..ed65bcd 100644
--- a/library/ssl_ticket.c
+++ b/library/ssl_ticket.c
@@ -187,9 +187,16 @@
 
 /*
  * Serialize a session in the following format:
- *  0   .   n-1     session structure, n = sizeof(mbedtls_ssl_session)
- *  n   .   n+2     peer_cert length = m (0 if no certificate)
- *  n+3 .   n+2+m   peer cert ASN.1
+ *
+ * - If MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is enabled:
+ *    0       .   n-1   session structure, n = sizeof(mbedtls_ssl_session)
+ *    n       .   n+2   peer_cert length = m (0 if no certificate)
+ *    n+3     .   n+2+m peer cert ASN.1
+ *
+ * - If MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is disabled:
+ *    0       .   n-1   session structure, n = sizeof(mbedtls_ssl_session)
+ *    n       .   n     length of peer certificate digest = k (0 if no digest)
+ *    n+1     .   n+k   peer certificate digest (digest type encoded in session)
  */
 static int ssl_save_session( const mbedtls_ssl_session *session,
                              unsigned char *buf, size_t buf_len,
@@ -198,17 +205,25 @@
     unsigned char *p = buf;
     size_t left = buf_len;
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
     size_t cert_len;
+#else
+    size_t cert_digest_len;
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
     if( left < sizeof( mbedtls_ssl_session ) )
         return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
 
+    /* This also copies the values of pointer fields in the
+     * session to be serialized, but they'll be ignored when
+     * loading the session through ssl_load_session(). */
     memcpy( p, session, sizeof( mbedtls_ssl_session ) );
     p += sizeof( mbedtls_ssl_session );
     left -= sizeof( mbedtls_ssl_session );
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
     if( session->peer_cert == NULL )
         cert_len = 0;
     else
@@ -220,11 +235,31 @@
     *p++ = (unsigned char)( ( cert_len >> 16 ) & 0xFF );
     *p++ = (unsigned char)( ( cert_len >>  8 ) & 0xFF );
     *p++ = (unsigned char)( ( cert_len       ) & 0xFF );
+    left -= 3;
 
     if( session->peer_cert != NULL )
         memcpy( p, session->peer_cert->raw.p, cert_len );
 
     p += cert_len;
+    left -= cert_len;
+#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+    if( session->peer_cert_digest != NULL )
+        cert_digest_len = 0;
+    else
+        cert_digest_len = session->peer_cert_digest_len;
+
+    if( left < 1 + cert_digest_len )
+        return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
+
+    *p++ = (unsigned char) cert_digest_len;
+    left--;
+
+    if( session->peer_cert_digest != NULL )
+        memcpy( p, session->peer_cert_digest, cert_digest_len );
+
+    p    += cert_digest_len;
+    left -= cert_digest_len;
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
     *olen = p - buf;
@@ -241,7 +276,11 @@
     const unsigned char *p = buf;
     const unsigned char * const end = buf + len;
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
     size_t cert_len;
+#else
+    size_t cert_digest_len;
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
     if( sizeof( mbedtls_ssl_session ) > (size_t)( end - p ) )
@@ -250,18 +289,29 @@
     memcpy( session, p, sizeof( mbedtls_ssl_session ) );
     p += sizeof( mbedtls_ssl_session );
 
+    /* Non-NULL pointer fields of `session` are meaningless
+     * and potentially harmful. Zeroize them for safety. */
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    session->peer_cert = NULL;
+#else
+    session->peer_cert_digest = NULL;
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
+    session->ticket = NULL;
+#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */
+
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    /* Deserialize CRT from the end of the ticket. */
     if( 3 > (size_t)( end - p ) )
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
 
     cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2];
     p += 3;
 
-    if( cert_len == 0 )
-    {
-        session->peer_cert = NULL;
-    }
-    else
+    if( cert_len != 0 )
     {
         int ret;
 
@@ -286,6 +336,30 @@
 
         p += cert_len;
     }
+#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+    /* Deserialize CRT digest from the end of the ticket. */
+    if( 1 > (size_t)( end - p ) )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    cert_digest_len = (size_t) p[0];
+    p++;
+
+    if( cert_digest_len != 0 )
+    {
+        if( cert_digest_len > (size_t)( end - p ) ||
+            cert_digest_len != session->peer_cert_digest_len )
+        {
+            return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+        }
+
+        session->peer_cert_digest = mbedtls_calloc( 1, cert_digest_len );
+        if( session->peer_cert_digest == NULL )
+            return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
+
+        memcpy( session->peer_cert_digest, p, cert_digest_len );
+        p += cert_digest_len;
+    }
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
     if( p != end )
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index f224d5e..660d548 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -279,13 +279,15 @@
 }
 #endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
 
-#if defined(MBEDTLS_SSL_CLI_C)
-static int ssl_session_copy( mbedtls_ssl_session *dst, const mbedtls_ssl_session *src )
+int mbedtls_ssl_session_copy( mbedtls_ssl_session *dst,
+                              const mbedtls_ssl_session *src )
 {
     mbedtls_ssl_session_free( dst );
     memcpy( dst, src, sizeof( mbedtls_ssl_session ) );
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
+
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
     if( src->peer_cert != NULL )
     {
         int ret;
@@ -304,6 +306,21 @@
             return( ret );
         }
     }
+#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+    if( src->peer_cert_digest != NULL )
+    {
+        dst->peer_cert_digest =
+            mbedtls_calloc( 1, src->peer_cert_digest_len );
+        if( dst->peer_cert_digest == NULL )
+            return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
+
+        memcpy( dst->peer_cert_digest, src->peer_cert_digest,
+                src->peer_cert_digest_len );
+        dst->peer_cert_digest_type = src->peer_cert_digest_type;
+        dst->peer_cert_digest_len = src->peer_cert_digest_len;
+    }
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
@@ -319,7 +336,6 @@
 
     return( 0 );
 }
-#endif /* MBEDTLS_SSL_CLI_C */
 
 #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL)
 int (*mbedtls_ssl_hw_record_init)( mbedtls_ssl_context *ssl,
@@ -5554,16 +5570,33 @@
     return( 0 );
 }
 
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+static void ssl_clear_peer_cert( mbedtls_ssl_session *session )
+{
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    if( session->peer_cert != NULL )
+    {
+        mbedtls_x509_crt_free( session->peer_cert );
+        mbedtls_free( session->peer_cert );
+        session->peer_cert = NULL;
+    }
+#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+    if( session->peer_cert_digest != NULL )
+    {
+        /* Zeroization is not necessary. */
+        mbedtls_free( session->peer_cert_digest );
+        session->peer_cert_digest      = NULL;
+        session->peer_cert_digest_type = MBEDTLS_MD_NONE;
+        session->peer_cert_digest_len  = 0;
+    }
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+}
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
 /*
  * Handshake functions
  */
-#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)         && \
-    !defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED)     && \
-    !defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)     && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED)   && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED)    && \
-    !defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)
+#if !defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED)
 /* No certificate support -> dummy functions */
 int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl )
 {
@@ -5571,10 +5604,7 @@
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate" ) );
 
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    if( !mbedtls_ssl_ciphersuite_uses_srv_cert( ciphersuite_info ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) );
         ssl->state++;
@@ -5591,10 +5621,7 @@
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) );
 
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    if( !mbedtls_ssl_ciphersuite_uses_srv_cert( ciphersuite_info ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
         ssl->state++;
@@ -5605,7 +5632,7 @@
     return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
 }
 
-#else
+#else /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */
 /* Some certificate support -> implement write and parse */
 
 int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl )
@@ -5617,10 +5644,7 @@
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate" ) );
 
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    if( !mbedtls_ssl_ciphersuite_uses_srv_cert( ciphersuite_info ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) );
         ssl->state++;
@@ -5724,63 +5748,68 @@
     return( ret );
 }
 
+#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C)
+
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+static int ssl_check_peer_crt_unchanged( mbedtls_ssl_context *ssl,
+                                         unsigned char *crt_buf,
+                                         size_t crt_buf_len )
+{
+    mbedtls_x509_crt const * const peer_crt = ssl->session->peer_cert;
+
+    if( peer_crt == NULL )
+        return( -1 );
+
+    if( peer_crt->raw.len != crt_buf_len )
+        return( -1 );
+
+    return( memcmp( peer_crt->raw.p, crt_buf, crt_buf_len ) );
+}
+#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+static int ssl_check_peer_crt_unchanged( mbedtls_ssl_context *ssl,
+                                         unsigned char *crt_buf,
+                                         size_t crt_buf_len )
+{
+    int ret;
+    unsigned char const * const peer_cert_digest =
+        ssl->session->peer_cert_digest;
+    mbedtls_md_type_t const peer_cert_digest_type =
+        ssl->session->peer_cert_digest_type;
+    mbedtls_md_info_t const * const digest_info =
+        mbedtls_md_info_from_type( peer_cert_digest_type );
+    unsigned char tmp_digest[MBEDTLS_SSL_PEER_CERT_DIGEST_MAX_LEN];
+    size_t digest_len;
+
+    if( peer_cert_digest == NULL || digest_info == NULL )
+        return( -1 );
+
+    digest_len = mbedtls_md_get_size( digest_info );
+    if( digest_len > MBEDTLS_SSL_PEER_CERT_DIGEST_MAX_LEN )
+        return( -1 );
+
+    ret = mbedtls_md( digest_info, crt_buf, crt_buf_len, tmp_digest );
+    if( ret != 0 )
+        return( -1 );
+
+    return( memcmp( tmp_digest, peer_cert_digest, digest_len ) );
+}
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+#endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */
+
 /*
  * Once the certificate message is read, parse it into a cert chain and
  * perform basic checks, but leave actual verification to the caller
  */
-static int ssl_parse_certificate_chain( mbedtls_ssl_context *ssl )
+static int ssl_parse_certificate_chain( mbedtls_ssl_context *ssl,
+                                        mbedtls_x509_crt *chain )
 {
     int ret;
+#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C)
+    int crt_cnt=0;
+#endif
     size_t i, n;
     uint8_t alert;
 
-#if defined(MBEDTLS_SSL_SRV_C)
-#if defined(MBEDTLS_SSL_PROTO_SSL3)
-    /*
-     * Check if the client sent an empty certificate
-     */
-    if( ssl->conf->endpoint  == MBEDTLS_SSL_IS_SERVER &&
-        ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 )
-    {
-        if( ssl->in_msglen  == 2                        &&
-            ssl->in_msgtype == MBEDTLS_SSL_MSG_ALERT            &&
-            ssl->in_msg[0]  == MBEDTLS_SSL_ALERT_LEVEL_WARNING  &&
-            ssl->in_msg[1]  == MBEDTLS_SSL_ALERT_MSG_NO_CERT )
-        {
-            MBEDTLS_SSL_DEBUG_MSG( 1, ( "SSLv3 client has no certificate" ) );
-
-            /* The client was asked for a certificate but didn't send
-               one. The client should know what's going on, so we
-               don't send an alert. */
-            ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING;
-            return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE );
-        }
-    }
-#endif /* MBEDTLS_SSL_PROTO_SSL3 */
-
-#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
-    defined(MBEDTLS_SSL_PROTO_TLS1_2)
-    if( ssl->conf->endpoint  == MBEDTLS_SSL_IS_SERVER &&
-        ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_0 )
-    {
-        if( ssl->in_hslen   == 3 + mbedtls_ssl_hs_hdr_len( ssl ) &&
-            ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE    &&
-            ssl->in_msg[0]  == MBEDTLS_SSL_HS_CERTIFICATE   &&
-            memcmp( ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ), "\0\0\0", 3 ) == 0 )
-        {
-            MBEDTLS_SSL_DEBUG_MSG( 1, ( "TLSv1 client has no certificate" ) );
-
-            /* The client was asked for a certificate but didn't send
-               one. The client should know what's going on, so we
-               don't send an alert. */
-            ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING;
-            return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE );
-        }
-    }
-#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \
-          MBEDTLS_SSL_PROTO_TLS1_2 */
-#endif /* MBEDTLS_SSL_SRV_C */
-
     if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
@@ -5814,43 +5843,32 @@
         return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
     }
 
-    /* In case we tried to reuse a session but it failed */
-    if( ssl->session_negotiate->peer_cert != NULL )
-    {
-        mbedtls_x509_crt_free( ssl->session_negotiate->peer_cert );
-        mbedtls_free( ssl->session_negotiate->peer_cert );
-    }
-
-    if( ( ssl->session_negotiate->peer_cert = mbedtls_calloc( 1,
-                    sizeof( mbedtls_x509_crt ) ) ) == NULL )
-    {
-        MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed",
-                       sizeof( mbedtls_x509_crt ) ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
-        return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
-    }
-
-    mbedtls_x509_crt_init( ssl->session_negotiate->peer_cert );
-
+    /* Make &ssl->in_msg[i] point to the beginning of the CRT chain. */
     i += 3;
 
+    /* Iterate through and parse the CRTs in the provided chain. */
     while( i < ssl->in_hslen )
     {
+        /* Check that there's room for the next CRT's length fields. */
         if ( i + 3 > ssl->in_hslen ) {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                           MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            mbedtls_ssl_send_alert_message( ssl,
+                              MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                              MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
         }
+        /* In theory, the CRT can be up to 2**24 Bytes, but we don't support
+         * anything beyond 2**16 ~ 64K. */
         if( ssl->in_msg[i] != 0 )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            mbedtls_ssl_send_alert_message( ssl,
+                            MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                            MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
         }
 
+        /* Read length of the next CRT in the chain. */
         n = ( (unsigned int) ssl->in_msg[i + 1] << 8 )
             | (unsigned int) ssl->in_msg[i + 2];
         i += 3;
@@ -5858,80 +5876,359 @@
         if( n < 128 || i + n > ssl->in_hslen )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            mbedtls_ssl_send_alert_message( ssl,
+                                 MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                                 MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
         }
 
-        ret = mbedtls_x509_crt_parse_der( ssl->session_negotiate->peer_cert,
-                                  ssl->in_msg + i, n );
+        /* Check if we're handling the first CRT in the chain. */
+#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C)
+        if( crt_cnt++ == 0 &&
+            ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT &&
+            ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS )
+        {
+            /* During client-side renegotiation, check that the server's
+             * end-CRTs hasn't changed compared to the initial handshake,
+             * mitigating the triple handshake attack. On success, reuse
+             * the original end-CRT instead of parsing it again. */
+            MBEDTLS_SSL_DEBUG_MSG( 3, ( "Check that peer CRT hasn't changed during renegotiation" ) );
+            if( ssl_check_peer_crt_unchanged( ssl,
+                                              &ssl->in_msg[i],
+                                              n ) != 0 )
+            {
+                MBEDTLS_SSL_DEBUG_MSG( 1, ( "new server cert during renegotiation" ) );
+                mbedtls_ssl_send_alert_message( ssl,
+                                                MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                                                MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED );
+                return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
+            }
+
+            /* Now we can safely free the original chain. */
+            ssl_clear_peer_cert( ssl->session );
+        }
+#endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */
+
+        /* Parse the next certificate in the chain. */
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+        ret = mbedtls_x509_crt_parse_der( chain, ssl->in_msg + i, n );
+#else
+        /* If we don't need to store the CRT chain permanently, parse
+         * it in-place from the input buffer instead of making a copy. */
+        ret = mbedtls_x509_crt_parse_der_nocopy( chain, ssl->in_msg + i, n );
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
         switch( ret )
         {
-        case 0: /*ok*/
-        case MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG + MBEDTLS_ERR_OID_NOT_FOUND:
-            /* Ignore certificate with an unknown algorithm: maybe a
-               prior certificate was already trusted. */
-            break;
+            case 0: /*ok*/
+            case MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG + MBEDTLS_ERR_OID_NOT_FOUND:
+                /* Ignore certificate with an unknown algorithm: maybe a
+                   prior certificate was already trusted. */
+                break;
 
-        case MBEDTLS_ERR_X509_ALLOC_FAILED:
-            alert = MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR;
-            goto crt_parse_der_failed;
+            case MBEDTLS_ERR_X509_ALLOC_FAILED:
+                alert = MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR;
+                goto crt_parse_der_failed;
 
-        case MBEDTLS_ERR_X509_UNKNOWN_VERSION:
-            alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
-            goto crt_parse_der_failed;
+            case MBEDTLS_ERR_X509_UNKNOWN_VERSION:
+                alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
+                goto crt_parse_der_failed;
 
-        default:
-            alert = MBEDTLS_SSL_ALERT_MSG_BAD_CERT;
-        crt_parse_der_failed:
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, alert );
-            MBEDTLS_SSL_DEBUG_RET( 1, " mbedtls_x509_crt_parse_der", ret );
-            return( ret );
+            default:
+                alert = MBEDTLS_SSL_ALERT_MSG_BAD_CERT;
+            crt_parse_der_failed:
+                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, alert );
+                MBEDTLS_SSL_DEBUG_RET( 1, " mbedtls_x509_crt_parse_der", ret );
+                return( ret );
         }
 
         i += n;
     }
 
-    MBEDTLS_SSL_DEBUG_CRT( 3, "peer certificate", ssl->session_negotiate->peer_cert );
-
-    /*
-     * On client, make sure the server cert doesn't change during renego to
-     * avoid "triple handshake" attack: https://secure-resumption.com/
-     */
-#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C)
-    if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT &&
-        ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS )
-    {
-        if( ssl->session->peer_cert == NULL )
-        {
-            MBEDTLS_SSL_DEBUG_MSG( 1, ( "new server cert during renegotiation" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED );
-            return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
-        }
-
-        if( ssl->session->peer_cert->raw.len !=
-            ssl->session_negotiate->peer_cert->raw.len ||
-            memcmp( ssl->session->peer_cert->raw.p,
-                    ssl->session_negotiate->peer_cert->raw.p,
-                    ssl->session->peer_cert->raw.len ) != 0 )
-        {
-            MBEDTLS_SSL_DEBUG_MSG( 1, ( "server cert changed during renegotiation" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED );
-            return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
-        }
-    }
-#endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */
-
+    MBEDTLS_SSL_DEBUG_CRT( 3, "peer certificate", chain );
     return( 0 );
 }
 
-int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
+#if defined(MBEDTLS_SSL_SRV_C)
+static int ssl_srv_check_client_no_crt_notification( mbedtls_ssl_context *ssl )
+{
+    if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT )
+        return( -1 );
+
+#if defined(MBEDTLS_SSL_PROTO_SSL3)
+    /*
+     * Check if the client sent an empty certificate
+     */
+    if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 )
+    {
+        if( ssl->in_msglen  == 2                        &&
+            ssl->in_msgtype == MBEDTLS_SSL_MSG_ALERT            &&
+            ssl->in_msg[0]  == MBEDTLS_SSL_ALERT_LEVEL_WARNING  &&
+            ssl->in_msg[1]  == MBEDTLS_SSL_ALERT_MSG_NO_CERT )
+        {
+            MBEDTLS_SSL_DEBUG_MSG( 1, ( "SSLv3 client has no certificate" ) );
+            return( 0 );
+        }
+
+        return( -1 );
+    }
+#endif /* MBEDTLS_SSL_PROTO_SSL3 */
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
+    defined(MBEDTLS_SSL_PROTO_TLS1_2)
+    if( ssl->in_hslen   == 3 + mbedtls_ssl_hs_hdr_len( ssl ) &&
+        ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE    &&
+        ssl->in_msg[0]  == MBEDTLS_SSL_HS_CERTIFICATE   &&
+        memcmp( ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ), "\0\0\0", 3 ) == 0 )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "TLSv1 client has no certificate" ) );
+        return( 0 );
+    }
+
+    return( -1 );
+#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \
+          MBEDTLS_SSL_PROTO_TLS1_2 */
+}
+#endif /* MBEDTLS_SSL_SRV_C */
+
+/* Check if a certificate message is expected.
+ * Return either
+ * - SSL_CERTIFICATE_EXPECTED, or
+ * - SSL_CERTIFICATE_SKIP
+ * indicating whether a Certificate message is expected or not.
+ */
+#define SSL_CERTIFICATE_EXPECTED 0
+#define SSL_CERTIFICATE_SKIP     1
+static int ssl_parse_certificate_coordinate( mbedtls_ssl_context *ssl,
+                                             int authmode )
+{
+    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
+        ssl->transform_negotiate->ciphersuite_info;
+
+    if( !mbedtls_ssl_ciphersuite_uses_srv_cert( ciphersuite_info ) )
+        return( SSL_CERTIFICATE_SKIP );
+
+#if defined(MBEDTLS_SSL_SRV_C)
+    if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER )
+    {
+        if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK )
+            return( SSL_CERTIFICATE_SKIP );
+
+        if( authmode == MBEDTLS_SSL_VERIFY_NONE )
+        {
+            ssl->session_negotiate->verify_result =
+                MBEDTLS_X509_BADCERT_SKIP_VERIFY;
+            return( SSL_CERTIFICATE_SKIP );
+        }
+    }
+#else
+    ((void) authmode);
+#endif /* MBEDTLS_SSL_SRV_C */
+
+    return( SSL_CERTIFICATE_EXPECTED );
+}
+
+static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl,
+                                         int authmode,
+                                         mbedtls_x509_crt *chain,
+                                         void *rs_ctx )
+{
+    int ret = 0;
+    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
+        ssl->transform_negotiate->ciphersuite_info;
+    mbedtls_x509_crt *ca_chain;
+    mbedtls_x509_crl *ca_crl;
+
+    if( authmode == MBEDTLS_SSL_VERIFY_NONE )
+        return( 0 );
+
+#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
+    if( ssl->handshake->sni_ca_chain != NULL )
+    {
+        ca_chain = ssl->handshake->sni_ca_chain;
+        ca_crl   = ssl->handshake->sni_ca_crl;
+    }
+    else
+#endif
+    {
+        ca_chain = ssl->conf->ca_chain;
+        ca_crl   = ssl->conf->ca_crl;
+    }
+
+    /*
+     * Main check: verify certificate
+     */
+    ret = mbedtls_x509_crt_verify_restartable(
+        chain,
+        ca_chain, ca_crl,
+        ssl->conf->cert_profile,
+        ssl->hostname,
+        &ssl->session_negotiate->verify_result,
+        ssl->conf->f_vrfy, ssl->conf->p_vrfy, rs_ctx );
+
+    if( ret != 0 )
+    {
+        MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", ret );
+    }
+
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+    if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
+        return( MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS );
+#endif
+
+    /*
+     * Secondary checks: always done, but change 'ret' only if it was 0
+     */
+
+#if defined(MBEDTLS_ECP_C)
+    {
+        const mbedtls_pk_context *pk = &chain->pk;
+
+        /* If certificate uses an EC key, make sure the curve is OK */
+        if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) &&
+            mbedtls_ssl_check_curve( ssl, mbedtls_pk_ec( *pk )->grp.id ) != 0 )
+        {
+            ssl->session_negotiate->verify_result |= MBEDTLS_X509_BADCERT_BAD_KEY;
+
+            MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (EC key curve)" ) );
+            if( ret == 0 )
+                ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE;
+        }
+    }
+#endif /* MBEDTLS_ECP_C */
+
+    if( mbedtls_ssl_check_cert_usage( chain,
+                                      ciphersuite_info,
+                                      ! ssl->conf->endpoint,
+                                      &ssl->session_negotiate->verify_result ) != 0 )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (usage extensions)" ) );
+        if( ret == 0 )
+            ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE;
+    }
+
+    /* mbedtls_x509_crt_verify_with_profile is supposed to report a
+     * verification failure through MBEDTLS_ERR_X509_CERT_VERIFY_FAILED,
+     * with details encoded in the verification flags. All other kinds
+     * of error codes, including those from the user provided f_vrfy
+     * functions, are treated as fatal and lead to a failure of
+     * ssl_parse_certificate even if verification was optional. */
+    if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL &&
+        ( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ||
+          ret == MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ) )
+    {
+        ret = 0;
+    }
+
+    if( ca_chain == NULL && authmode == MBEDTLS_SSL_VERIFY_REQUIRED )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no CA chain" ) );
+        ret = MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED;
+    }
+
+    if( ret != 0 )
+    {
+        uint8_t alert;
+
+        /* The certificate may have been rejected for several reasons.
+           Pick one and send the corresponding alert. Which alert to send
+           may be a subject of debate in some cases. */
+        if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_OTHER )
+            alert = MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED;
+        else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_CN_MISMATCH )
+            alert = MBEDTLS_SSL_ALERT_MSG_BAD_CERT;
+        else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_KEY_USAGE )
+            alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
+        else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXT_KEY_USAGE )
+            alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
+        else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NS_CERT_TYPE )
+            alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
+        else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_PK )
+            alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
+        else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_KEY )
+            alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
+        else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXPIRED )
+            alert = MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED;
+        else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_REVOKED )
+            alert = MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED;
+        else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NOT_TRUSTED )
+            alert = MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA;
+        else
+            alert = MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN;
+        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                                        alert );
+    }
+
+#if defined(MBEDTLS_DEBUG_C)
+    if( ssl->session_negotiate->verify_result != 0 )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 3, ( "! Certificate verification flags %x",
+                                    ssl->session_negotiate->verify_result ) );
+    }
+    else
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 3, ( "Certificate verification flags clear" ) );
+    }
+#endif /* MBEDTLS_DEBUG_C */
+
+    return( ret );
+}
+
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+static int ssl_remember_peer_crt_digest( mbedtls_ssl_context *ssl,
+                                         unsigned char *start, size_t len )
 {
     int ret;
-    const mbedtls_ssl_ciphersuite_t * const ciphersuite_info =
-          ssl->transform_negotiate->ciphersuite_info;
+    /* Remember digest of the peer's end-CRT. */
+    ssl->session_negotiate->peer_cert_digest =
+        mbedtls_calloc( 1, MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN );
+    if( ssl->session_negotiate->peer_cert_digest == NULL )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed",
+                                    sizeof( MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN ) ) );
+        mbedtls_ssl_send_alert_message( ssl,
+                                        MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                                        MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
+
+        return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
+    }
+
+    ret = mbedtls_md( mbedtls_md_info_from_type(
+                          MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE ),
+                      start, len,
+                      ssl->session_negotiate->peer_cert_digest );
+
+    ssl->session_negotiate->peer_cert_digest_type =
+        MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE;
+    ssl->session_negotiate->peer_cert_digest_len =
+        MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN;
+
+    return( ret );
+}
+
+static int ssl_remember_peer_pubkey( mbedtls_ssl_context *ssl,
+                                     unsigned char *start, size_t len )
+{
+    unsigned char *end = start + len;
+    int ret;
+
+    /* Make a copy of the peer's raw public key. */
+    mbedtls_pk_init( &ssl->handshake->peer_pubkey );
+    ret = mbedtls_pk_parse_subpubkey( &start, end,
+                                      &ssl->handshake->peer_pubkey );
+    if( ret != 0 )
+    {
+        /* We should have parsed the public key before. */
+        return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+    }
+
+    return( 0 );
+}
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+
+int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
+{
+    int ret = 0;
+    int crt_expected;
 #if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
     const int authmode = ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET
                        ? ssl->handshake->sni_authmode
@@ -5940,43 +6237,23 @@
     const int authmode = ssl->conf->authmode;
 #endif
     void *rs_ctx = NULL;
+    mbedtls_x509_crt *chain = NULL;
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) );
 
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    crt_expected = ssl_parse_certificate_coordinate( ssl, authmode );
+    if( crt_expected == SSL_CERTIFICATE_SKIP )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
-        ssl->state++;
-        return( 0 );
+        goto exit;
     }
 
-#if defined(MBEDTLS_SSL_SRV_C)
-    if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER &&
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK )
-    {
-        MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
-        ssl->state++;
-        return( 0 );
-    }
-
-    if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER &&
-        authmode == MBEDTLS_SSL_VERIFY_NONE )
-    {
-        ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_SKIP_VERIFY;
-        MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) );
-
-        ssl->state++;
-        return( 0 );
-    }
-#endif
-
 #if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
     if( ssl->handshake->ecrs_enabled &&
         ssl->handshake->ecrs_state == ssl_ecrs_crt_verify )
     {
+        chain = ssl->handshake->ecrs_peer_cert;
+        ssl->handshake->ecrs_peer_cert = NULL;
         goto crt_verify;
     }
 #endif
@@ -5986,22 +6263,44 @@
         /* mbedtls_ssl_read_record may have sent an alert already. We
            let it decide whether to alert. */
         MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
-        return( ret );
+        goto exit;
     }
 
-    if( ( ret = ssl_parse_certificate_chain( ssl ) ) != 0 )
-    {
 #if defined(MBEDTLS_SSL_SRV_C)
-        if( ret == MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE &&
-            authmode == MBEDTLS_SSL_VERIFY_OPTIONAL )
-        {
-            ret = 0;
-        }
-#endif
+    if( ssl_srv_check_client_no_crt_notification( ssl ) == 0 )
+    {
+        ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING;
 
-        ssl->state++;
-        return( ret );
+        if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL )
+            ret = 0;
+        else
+            ret = MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE;
+
+        goto exit;
     }
+#endif /* MBEDTLS_SSL_SRV_C */
+
+    /* Clear existing peer CRT structure in case we tried to
+     * reuse a session but it failed, and allocate a new one. */
+    ssl_clear_peer_cert( ssl->session_negotiate );
+
+    chain = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) );
+    if( chain == NULL )
+    {
+        MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed",
+                                    sizeof( mbedtls_x509_crt ) ) );
+        mbedtls_ssl_send_alert_message( ssl,
+                                        MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                                        MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
+
+        ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
+        goto exit;
+    }
+    mbedtls_x509_crt_init( chain );
+
+    ret = ssl_parse_certificate_chain( ssl, chain );
+    if( ret != 0 )
+        goto exit;
 
 #if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
     if( ssl->handshake->ecrs_enabled)
@@ -6012,154 +6311,71 @@
         rs_ctx = &ssl->handshake->ecrs_ctx;
 #endif
 
-    if( authmode != MBEDTLS_SSL_VERIFY_NONE )
+    ret = ssl_parse_certificate_verify( ssl, authmode,
+                                        chain, rs_ctx );
+    if( ret != 0 )
+        goto exit;
+
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
     {
-        mbedtls_x509_crt *ca_chain;
-        mbedtls_x509_crl *ca_crl;
+        unsigned char *crt_start, *pk_start;
+        size_t crt_len, pk_len;
 
-#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
-        if( ssl->handshake->sni_ca_chain != NULL )
-        {
-            ca_chain = ssl->handshake->sni_ca_chain;
-            ca_crl   = ssl->handshake->sni_ca_crl;
-        }
-        else
-#endif
-        {
-            ca_chain = ssl->conf->ca_chain;
-            ca_crl   = ssl->conf->ca_crl;
-        }
+        /* We parse the CRT chain without copying, so
+         * these pointers point into the input buffer,
+         * and are hence still valid after freeing the
+         * CRT chain. */
 
-        /*
-         * Main check: verify certificate
-         */
-        ret = mbedtls_x509_crt_verify_restartable(
-                                ssl->session_negotiate->peer_cert,
-                                ca_chain, ca_crl,
-                                ssl->conf->cert_profile,
-                                ssl->hostname,
-                               &ssl->session_negotiate->verify_result,
-                                ssl->conf->f_vrfy, ssl->conf->p_vrfy, rs_ctx );
+        crt_start = chain->raw.p;
+        crt_len   = chain->raw.len;
 
+        pk_start = chain->pk_raw.p;
+        pk_len   = chain->pk_raw.len;
+
+        /* Free the CRT structures before computing
+         * digest and copying the peer's public key. */
+        mbedtls_x509_crt_free( chain );
+        mbedtls_free( chain );
+        chain = NULL;
+
+        ret = ssl_remember_peer_crt_digest( ssl, crt_start, crt_len );
         if( ret != 0 )
-        {
-            MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", ret );
-        }
+            goto exit;
 
-#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
-        if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
-            return( MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS );
-#endif
-
-        /*
-         * Secondary checks: always done, but change 'ret' only if it was 0
-         */
-
-#if defined(MBEDTLS_ECP_C)
-        {
-            const mbedtls_pk_context *pk = &ssl->session_negotiate->peer_cert->pk;
-
-            /* If certificate uses an EC key, make sure the curve is OK */
-            if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) &&
-                mbedtls_ssl_check_curve( ssl, mbedtls_pk_ec( *pk )->grp.id ) != 0 )
-            {
-                ssl->session_negotiate->verify_result |= MBEDTLS_X509_BADCERT_BAD_KEY;
-
-                MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (EC key curve)" ) );
-                if( ret == 0 )
-                    ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE;
-            }
-        }
-#endif /* MBEDTLS_ECP_C */
-
-        if( mbedtls_ssl_check_cert_usage( ssl->session_negotiate->peer_cert,
-                                 ciphersuite_info,
-                                 ! ssl->conf->endpoint,
-                                 &ssl->session_negotiate->verify_result ) != 0 )
-        {
-            MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (usage extensions)" ) );
-            if( ret == 0 )
-                ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE;
-        }
-
-        /* mbedtls_x509_crt_verify_with_profile is supposed to report a
-         * verification failure through MBEDTLS_ERR_X509_CERT_VERIFY_FAILED,
-         * with details encoded in the verification flags. All other kinds
-         * of error codes, including those from the user provided f_vrfy
-         * functions, are treated as fatal and lead to a failure of
-         * ssl_parse_certificate even if verification was optional. */
-        if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL &&
-            ( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ||
-              ret == MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ) )
-        {
-            ret = 0;
-        }
-
-        if( ca_chain == NULL && authmode == MBEDTLS_SSL_VERIFY_REQUIRED )
-        {
-            MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no CA chain" ) );
-            ret = MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED;
-        }
-
+        ret = ssl_remember_peer_pubkey( ssl, pk_start, pk_len );
         if( ret != 0 )
-        {
-            uint8_t alert;
-
-            /* The certificate may have been rejected for several reasons.
-               Pick one and send the corresponding alert. Which alert to send
-               may be a subject of debate in some cases. */
-            if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_OTHER )
-                alert = MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED;
-            else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_CN_MISMATCH )
-                alert = MBEDTLS_SSL_ALERT_MSG_BAD_CERT;
-            else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_KEY_USAGE )
-                alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
-            else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXT_KEY_USAGE )
-                alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
-            else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NS_CERT_TYPE )
-                alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
-            else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_PK )
-                alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
-            else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_KEY )
-                alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT;
-            else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXPIRED )
-                alert = MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED;
-            else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_REVOKED )
-                alert = MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED;
-            else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NOT_TRUSTED )
-                alert = MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA;
-            else
-                alert = MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN;
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            alert );
-        }
-
-#if defined(MBEDTLS_DEBUG_C)
-        if( ssl->session_negotiate->verify_result != 0 )
-        {
-            MBEDTLS_SSL_DEBUG_MSG( 3, ( "! Certificate verification flags %x",
-                                        ssl->session_negotiate->verify_result ) );
-        }
-        else
-        {
-            MBEDTLS_SSL_DEBUG_MSG( 3, ( "Certificate verification flags clear" ) );
-        }
-#endif /* MBEDTLS_DEBUG_C */
+            goto exit;
     }
-
-    ssl->state++;
+#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+    /* Pass ownership to session structure. */
+    ssl->session_negotiate->peer_cert = chain;
+    chain = NULL;
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) );
 
+exit:
+
+    if( ret == 0 )
+        ssl->state++;
+
+#if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
+    if( ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS )
+    {
+        ssl->handshake->ecrs_peer_cert = chain;
+        chain = NULL;
+    }
+#endif
+
+    if( chain != NULL )
+    {
+        mbedtls_x509_crt_free( chain );
+        mbedtls_free( chain );
+    }
+
     return( ret );
 }
-#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
-          !MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED
-          !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED
-          !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED
-          !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
-          !MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED
-          !MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */
+#endif /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */
 
 int mbedtls_ssl_write_change_cipher_spec( mbedtls_ssl_context *ssl )
 {
@@ -6529,7 +6745,7 @@
     unsigned char padbuf[32];
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     size_t hash_size;
-    psa_hash_operation_t sha256_psa;
+    psa_hash_operation_t sha256_psa = PSA_HASH_OPERATION_INIT;
     psa_status_t status;
 #else
     mbedtls_sha256_context sha256;
@@ -6605,7 +6821,7 @@
     unsigned char padbuf[48];
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     size_t hash_size;
-    psa_hash_operation_t sha384_psa;
+    psa_hash_operation_t sha384_psa = PSA_HASH_OPERATION_INIT;
     psa_status_t status;
 #else
     mbedtls_sha512_context sha512;
@@ -7022,6 +7238,11 @@
 #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
     handshake->sni_authmode = MBEDTLS_SSL_VERIFY_UNSET;
 #endif
+
+#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
+    !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    mbedtls_pk_init( &handshake->peer_pubkey );
+#endif
 }
 
 static void ssl_transform_init( mbedtls_ssl_transform *transform )
@@ -7571,7 +7792,8 @@
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
     }
 
-    if( ( ret = ssl_session_copy( ssl->session_negotiate, session ) ) != 0 )
+    if( ( ret = mbedtls_ssl_session_copy( ssl->session_negotiate,
+                                          session ) ) != 0 )
         return( ret );
 
     ssl->handshake->resume = 1;
@@ -8490,12 +8712,17 @@
     if( ssl == NULL || ssl->session == NULL )
         return( NULL );
 
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
     return( ssl->session->peer_cert );
+#else
+    return( NULL );
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 }
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
 #if defined(MBEDTLS_SSL_CLI_C)
-int mbedtls_ssl_get_session( const mbedtls_ssl_context *ssl, mbedtls_ssl_session *dst )
+int mbedtls_ssl_get_session( const mbedtls_ssl_context *ssl,
+                             mbedtls_ssl_session *dst )
 {
     if( ssl == NULL ||
         dst == NULL ||
@@ -8505,7 +8732,7 @@
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
     }
 
-    return( ssl_session_copy( dst, ssl->session ) );
+    return( mbedtls_ssl_session_copy( dst, ssl->session ) );
 }
 #endif /* MBEDTLS_SSL_CLI_C */
 
@@ -9359,14 +9586,29 @@
 
 #if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
     mbedtls_x509_crt_restart_free( &handshake->ecrs_ctx );
+    if( handshake->ecrs_peer_cert != NULL )
+    {
+        mbedtls_x509_crt_free( handshake->ecrs_peer_cert );
+        mbedtls_free( handshake->ecrs_peer_cert );
+    }
 #endif
 
+#if defined(MBEDTLS_X509_CRT_PARSE_C) &&        \
+    !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    mbedtls_pk_free( &handshake->peer_pubkey );
+#endif /* MBEDTLS_X509_CRT_PARSE_C && !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
     mbedtls_free( handshake->verify_cookie );
     ssl_flight_free( handshake->flight );
     ssl_buffering_free( ssl );
 #endif
 
+#if defined(MBEDTLS_ECDH_C) &&                  \
+    defined(MBEDTLS_USE_PSA_CRYPTO)
+    psa_destroy_key( handshake->ecdh_psa_privkey );
+#endif /* MBEDTLS_ECDH_C && MBEDTLS_USE_PSA_CRYPTO */
+
     mbedtls_platform_zeroize( handshake,
                               sizeof( mbedtls_ssl_handshake_params ) );
 }
@@ -9377,11 +9619,7 @@
         return;
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
-    if( session->peer_cert != NULL )
-    {
-        mbedtls_x509_crt_free( session->peer_cert );
-        mbedtls_free( session->peer_cert );
-    }
+    ssl_clear_peer_cert( session );
 #endif
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
@@ -10203,7 +10441,7 @@
                                             mbedtls_md_type_t md_alg )
 {
     psa_status_t status;
-    psa_hash_operation_t hash_operation;
+    psa_hash_operation_t hash_operation = PSA_HASH_OPERATION_INIT;
     psa_algorithm_t hash_alg = mbedtls_psa_translate_md( md_alg );
 
     MBEDTLS_SSL_DEBUG_MSG( 1, ( "Perform PSA-based computation of digest of ServerKeyExchange" ) );
diff --git a/library/version_features.c b/library/version_features.c
index 61094d4..59eacc4 100644
--- a/library/version_features.c
+++ b/library/version_features.c
@@ -303,6 +303,9 @@
 #if defined(MBEDTLS_REMOVE_ARC4_CIPHERSUITES)
     "MBEDTLS_REMOVE_ARC4_CIPHERSUITES",
 #endif /* MBEDTLS_REMOVE_ARC4_CIPHERSUITES */
+#if defined(MBEDTLS_REMOVE_3DES_CIPHERSUITES)
+    "MBEDTLS_REMOVE_3DES_CIPHERSUITES",
+#endif /* MBEDTLS_REMOVE_3DES_CIPHERSUITES */
 #if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED)
     "MBEDTLS_ECP_DP_SECP192R1_ENABLED",
 #endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */
@@ -348,6 +351,9 @@
 #if defined(MBEDTLS_ECP_RESTARTABLE)
     "MBEDTLS_ECP_RESTARTABLE",
 #endif /* MBEDTLS_ECP_RESTARTABLE */
+#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
+    "MBEDTLS_ECDH_LEGACY_CONTEXT",
+#endif /* MBEDTLS_ECDH_LEGACY_CONTEXT */
 #if defined(MBEDTLS_ECDSA_DETERMINISTIC)
     "MBEDTLS_ECDSA_DETERMINISTIC",
 #endif /* MBEDTLS_ECDSA_DETERMINISTIC */
@@ -426,9 +432,9 @@
 #if defined(MBEDTLS_PSA_CRYPTO_SPM)
     "MBEDTLS_PSA_CRYPTO_SPM",
 #endif /* MBEDTLS_PSA_CRYPTO_SPM */
-#if defined(MBEDTLS_PSA_HAS_ITS_IO)
-    "MBEDTLS_PSA_HAS_ITS_IO",
-#endif /* MBEDTLS_PSA_HAS_ITS_IO */
+#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
+    "MBEDTLS_PSA_INJECT_ENTROPY",
+#endif /* MBEDTLS_PSA_INJECT_ENTROPY */
 #if defined(MBEDTLS_RSA_NO_CRT)
     "MBEDTLS_RSA_NO_CRT",
 #endif /* MBEDTLS_RSA_NO_CRT */
@@ -456,6 +462,9 @@
 #if defined(MBEDTLS_SSL_FALLBACK_SCSV)
     "MBEDTLS_SSL_FALLBACK_SCSV",
 #endif /* MBEDTLS_SSL_FALLBACK_SCSV */
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    "MBEDTLS_SSL_KEEP_PEER_CERTIFICATE",
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL)
     "MBEDTLS_SSL_HW_RECORD_ACCEL",
 #endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */
@@ -702,12 +711,9 @@
 #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
     "MBEDTLS_PSA_CRYPTO_STORAGE_C",
 #endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */
-#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C)
-    "MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C",
-#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C */
-#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_ITS_C)
-    "MBEDTLS_PSA_CRYPTO_STORAGE_ITS_C",
-#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_ITS_C */
+#if defined(MBEDTLS_PSA_ITS_FILE_C)
+    "MBEDTLS_PSA_ITS_FILE_C",
+#endif /* MBEDTLS_PSA_ITS_FILE_C */
 #if defined(MBEDTLS_RIPEMD160_C)
     "MBEDTLS_RIPEMD160_C",
 #endif /* MBEDTLS_RIPEMD160_C */
diff --git a/library/x509.c b/library/x509.c
index 6b7899f..3f8e290 100644
--- a/library/x509.c
+++ b/library/x509.c
@@ -1001,8 +1001,8 @@
  */
 int mbedtls_x509_self_test( int verbose )
 {
+    int ret = 0;
 #if defined(MBEDTLS_CERTS_C) && defined(MBEDTLS_SHA256_C)
-    int ret;
     uint32_t flags;
     mbedtls_x509_crt cacert;
     mbedtls_x509_crt clicert;
@@ -1010,6 +1010,7 @@
     if( verbose != 0 )
         mbedtls_printf( "  X.509 certificate load: " );
 
+    mbedtls_x509_crt_init( &cacert );
     mbedtls_x509_crt_init( &clicert );
 
     ret = mbedtls_x509_crt_parse( &clicert, (const unsigned char *) mbedtls_test_cli_crt,
@@ -1019,11 +1020,9 @@
         if( verbose != 0 )
             mbedtls_printf( "failed\n" );
 
-        return( ret );
+        goto cleanup;
     }
 
-    mbedtls_x509_crt_init( &cacert );
-
     ret = mbedtls_x509_crt_parse( &cacert, (const unsigned char *) mbedtls_test_ca_crt,
                           mbedtls_test_ca_crt_len );
     if( ret != 0 )
@@ -1031,7 +1030,7 @@
         if( verbose != 0 )
             mbedtls_printf( "failed\n" );
 
-        return( ret );
+        goto cleanup;
     }
 
     if( verbose != 0 )
@@ -1043,20 +1042,19 @@
         if( verbose != 0 )
             mbedtls_printf( "failed\n" );
 
-        return( ret );
+        goto cleanup;
     }
 
     if( verbose != 0 )
         mbedtls_printf( "passed\n\n");
 
+cleanup:
     mbedtls_x509_crt_free( &cacert  );
     mbedtls_x509_crt_free( &clicert );
-
-    return( 0 );
 #else
     ((void) verbose);
-    return( 0 );
 #endif /* MBEDTLS_CERTS_C && MBEDTLS_SHA1_C */
+    return( ret );
 }
 
 #endif /* MBEDTLS_SELF_TEST */
diff --git a/library/x509_crt.c b/library/x509_crt.c
index 1b1f0a7..5d82816 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -834,8 +834,10 @@
 /*
  * Parse and fill a single X.509 certificate in DER format
  */
-static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, const unsigned char *buf,
-                                    size_t buflen )
+static int x509_crt_parse_der_core( mbedtls_x509_crt *crt,
+                                    const unsigned char *buf,
+                                    size_t buflen,
+                                    int make_copy )
 {
     int ret;
     size_t len;
@@ -852,7 +854,7 @@
     if( crt == NULL || buf == NULL )
         return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
 
-    // Use the original buffer until we figure out actual length
+    /* Use the original buffer until we figure out actual length. */
     p = (unsigned char*) buf;
     len = buflen;
     end = p + len;
@@ -870,25 +872,26 @@
         return( MBEDTLS_ERR_X509_INVALID_FORMAT );
     }
 
-    if( len > (size_t) ( end - p ) )
-    {
-        mbedtls_x509_crt_free( crt );
-        return( MBEDTLS_ERR_X509_INVALID_FORMAT +
-                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
-    }
-    crt_end = p + len;
-
-    // Create and populate a new buffer for the raw field
-    crt->raw.len = crt_end - buf;
-    crt->raw.p = p = mbedtls_calloc( 1, crt->raw.len );
-    if( p == NULL )
-        return( MBEDTLS_ERR_X509_ALLOC_FAILED );
-
-    memcpy( p, buf, crt->raw.len );
-
-    // Direct pointers to the new buffer
-    p += crt->raw.len - len;
     end = crt_end = p + len;
+    crt->raw.len = crt_end - buf;
+    if( make_copy != 0 )
+    {
+        /* Create and populate a new buffer for the raw field. */
+        crt->raw.p = p = mbedtls_calloc( 1, crt->raw.len );
+        if( crt->raw.p == NULL )
+            return( MBEDTLS_ERR_X509_ALLOC_FAILED );
+
+        memcpy( crt->raw.p, buf, crt->raw.len );
+        crt->own_buffer = 1;
+
+        p += crt->raw.len - len;
+        end = crt_end = p + len;
+    }
+    else
+    {
+        crt->raw.p = (unsigned char*) buf;
+        crt->own_buffer = 0;
+    }
 
     /*
      * TBSCertificate  ::=  SEQUENCE  {
@@ -993,11 +996,13 @@
     /*
      * SubjectPublicKeyInfo
      */
+    crt->pk_raw.p = p;
     if( ( ret = mbedtls_pk_parse_subpubkey( &p, end, &crt->pk ) ) != 0 )
     {
         mbedtls_x509_crt_free( crt );
         return( ret );
     }
+    crt->pk_raw.len = p - crt->pk_raw.p;
 
     /*
      *  issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
@@ -1091,8 +1096,10 @@
  * Parse one X.509 certificate in DER format from a buffer and add them to a
  * chained list
  */
-int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *buf,
-                        size_t buflen )
+static int mbedtls_x509_crt_parse_der_internal( mbedtls_x509_crt *chain,
+                                                const unsigned char *buf,
+                                                size_t buflen,
+                                                int make_copy )
 {
     int ret;
     mbedtls_x509_crt *crt = chain, *prev = NULL;
@@ -1124,7 +1131,7 @@
         crt = crt->next;
     }
 
-    if( ( ret = x509_crt_parse_der_core( crt, buf, buflen ) ) != 0 )
+    if( ( ret = x509_crt_parse_der_core( crt, buf, buflen, make_copy ) ) != 0 )
     {
         if( prev )
             prev->next = NULL;
@@ -1138,11 +1145,27 @@
     return( 0 );
 }
 
+int mbedtls_x509_crt_parse_der_nocopy( mbedtls_x509_crt *chain,
+                                       const unsigned char *buf,
+                                       size_t buflen )
+{
+    return( mbedtls_x509_crt_parse_der_internal( chain, buf, buflen, 0 ) );
+}
+
+int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain,
+                                const unsigned char *buf,
+                                size_t buflen )
+{
+    return( mbedtls_x509_crt_parse_der_internal( chain, buf, buflen, 1 ) );
+}
+
 /*
  * Parse one or more PEM certificates from a buffer and add them to the chained
  * list
  */
-int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, size_t buflen )
+int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain,
+                            const unsigned char *buf,
+                            size_t buflen )
 {
 #if defined(MBEDTLS_PEM_PARSE_C)
     int success = 0, first_error = 0, total_failed = 0;
@@ -1908,7 +1931,7 @@
     if( mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ) != 0 )
         return( -1 );
 #else
-    psa_hash_operation_t hash_operation;
+    psa_hash_operation_t hash_operation = PSA_HASH_OPERATION_INIT;
     psa_algorithm_t hash_alg = mbedtls_psa_translate_md( child->sig_md );
 
     if( psa_hash_setup( &hash_operation, hash_alg ) != PSA_SUCCESS )
@@ -2699,7 +2722,7 @@
             mbedtls_free( seq_prv );
         }
 
-        if( cert_cur->raw.p != NULL )
+        if( cert_cur->raw.p != NULL && cert_cur->own_buffer )
         {
             mbedtls_platform_zeroize( cert_cur->raw.p, cert_cur->raw.len );
             mbedtls_free( cert_cur->raw.p );
diff --git a/library/x509write_crt.c b/library/x509write_crt.c
index b1ef216..b6cb745 100644
--- a/library/x509write_crt.c
+++ b/library/x509write_crt.c
@@ -221,23 +221,36 @@
 int mbedtls_x509write_crt_set_key_usage( mbedtls_x509write_cert *ctx,
                                          unsigned int key_usage )
 {
-    unsigned char buf[4], ku;
+    unsigned char buf[5], ku[2];
     unsigned char *c;
     int ret;
+    const unsigned int allowed_bits = MBEDTLS_X509_KU_DIGITAL_SIGNATURE |
+        MBEDTLS_X509_KU_NON_REPUDIATION   |
+        MBEDTLS_X509_KU_KEY_ENCIPHERMENT  |
+        MBEDTLS_X509_KU_DATA_ENCIPHERMENT |
+        MBEDTLS_X509_KU_KEY_AGREEMENT     |
+        MBEDTLS_X509_KU_KEY_CERT_SIGN     |
+        MBEDTLS_X509_KU_CRL_SIGN          |
+        MBEDTLS_X509_KU_ENCIPHER_ONLY     |
+        MBEDTLS_X509_KU_DECIPHER_ONLY;
 
-    /* We currently only support 7 bits, from 0x80 to 0x02 */
-    if( ( key_usage & ~0xfe ) != 0 )
+    /* Check that nothing other than the allowed flags is set */
+    if( ( key_usage & ~allowed_bits ) != 0 )
         return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE );
 
-    c = buf + 4;
-    ku = (unsigned char) key_usage;
+    c = buf + 5;
+    ku[0] = (unsigned char)( key_usage      );
+    ku[1] = (unsigned char)( key_usage >> 8 );
+    ret = mbedtls_asn1_write_named_bitstring( &c, buf, ku, 9 );
 
-    if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ku, 7 ) ) != 4 )
+    if( ret < 0 )
         return( ret );
+    else if( ret < 3 || ret > 5 )
+        return( MBEDTLS_ERR_X509_INVALID_FORMAT );
 
     ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_KEY_USAGE,
                                        MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ),
-                                       1, buf, 4 );
+                                       1, c, (size_t)ret );
     if( ret != 0 )
         return( ret );
 
@@ -253,12 +266,13 @@
 
     c = buf + 4;
 
-    if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 )
+    ret = mbedtls_asn1_write_named_bitstring( &c, buf, &ns_cert_type, 8 );
+    if( ret < 3 || ret > 4 )
         return( ret );
 
     ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE,
                                        MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ),
-                                       0, buf, 4 );
+                                       0, c, (size_t)ret );
     if( ret != 0 )
         return( ret );
 
diff --git a/library/x509write_csr.c b/library/x509write_csr.c
index f2950ad..8dc39e7 100644
--- a/library/x509write_csr.c
+++ b/library/x509write_csr.c
@@ -94,12 +94,13 @@
 
     c = buf + 4;
 
-    if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &key_usage, 7 ) ) != 4 )
+    ret = mbedtls_asn1_write_named_bitstring( &c, buf, &key_usage, 8 );
+    if( ret < 3 || ret > 4 )
         return( ret );
 
     ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_KEY_USAGE,
                                        MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ),
-                                       buf, 4 );
+                                       c, (size_t)ret );
     if( ret != 0 )
         return( ret );
 
@@ -115,12 +116,13 @@
 
     c = buf + 4;
 
-    if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 )
+    ret = mbedtls_asn1_write_named_bitstring( &c, buf, &ns_cert_type, 8 );
+    if( ret < 3 || ret > 4 )
         return( ret );
 
     ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE,
                                        MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ),
-                                       buf, 4 );
+                                       c, (size_t)ret );
     if( ret != 0 )
         return( ret );
 
@@ -142,7 +144,7 @@
     size_t len = 0;
     mbedtls_pk_type_t pk_alg;
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
-    psa_hash_operation_t hash_operation;
+    psa_hash_operation_t hash_operation = PSA_HASH_OPERATION_INIT;
     size_t hash_len;
     psa_algorithm_t hash_alg = mbedtls_psa_translate_md( ctx->md_alg );
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
diff --git a/programs/.gitignore b/programs/.gitignore
index 0241896..4d78930 100644
--- a/programs/.gitignore
+++ b/programs/.gitignore
@@ -49,6 +49,7 @@
 test/ssl_cert_test
 test/udp_proxy
 test/zeroize
+test/query_compile_time_config
 util/pem2der
 util/strerror
 x509/cert_app
diff --git a/programs/Makefile b/programs/Makefile
index c88a6c7..753524c 100644
--- a/programs/Makefile
+++ b/programs/Makefile
@@ -76,6 +76,7 @@
 	test/ssl_cert_test$(EXEXT)	test/benchmark$(EXEXT)		\
 	test/selftest$(EXEXT)		test/udp_proxy$(EXEXT)		\
 	test/zeroize$(EXEXT)						\
+	test/query_compile_time_config$(EXEXT)				\
 	util/pem2der$(EXEXT)		util/strerror$(EXEXT)		\
 	x509/cert_app$(EXEXT)		x509/crl_app$(EXEXT)		\
 	x509/cert_req$(EXEXT)		x509/cert_write$(EXEXT)		\
@@ -218,17 +219,17 @@
 	echo "  CC    ssl/ssl_client1.c"
 	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) ssl/ssl_client1.c  $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
 
-ssl/ssl_client2$(EXEXT): ssl/ssl_client2.c $(DEP)
+ssl/ssl_client2$(EXEXT): ssl/ssl_client2.c ssl/query_config.c $(DEP)
 	echo "  CC    ssl/ssl_client2.c"
-	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) ssl/ssl_client2.c  $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
+	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) ssl/ssl_client2.c ssl/query_config.c $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
 
 ssl/ssl_server$(EXEXT): ssl/ssl_server.c $(DEP)
 	echo "  CC    ssl/ssl_server.c"
 	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) ssl/ssl_server.c   $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
 
-ssl/ssl_server2$(EXEXT): ssl/ssl_server2.c $(DEP)
+ssl/ssl_server2$(EXEXT): ssl/ssl_server2.c ssl/query_config.c $(DEP)
 	echo "  CC    ssl/ssl_server2.c"
-	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) ssl/ssl_server2.c   $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
+	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) ssl/ssl_server2.c ssl/query_config.c $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
 
 ssl/ssl_fork_server$(EXEXT): ssl/ssl_fork_server.c $(DEP)
 	echo "  CC    ssl/ssl_fork_server.c"
@@ -270,6 +271,10 @@
 	echo "  CC    test/zeroize.c"
 	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) test/zeroize.c    $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
 
+test/query_compile_time_config$(EXEXT): test/query_compile_time_config.c ssl/query_config.c $(DEP)
+	echo "  CC    test/query_compile_time_config.c"
+	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) test/query_compile_time_config.c ssl/query_config.c $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
+
 util/pem2der$(EXEXT): util/pem2der.c $(DEP)
 	echo "  CC    util/pem2der.c"
 	$(CC) $(LOCAL_CFLAGS) $(CFLAGS) util/pem2der.c    $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@
diff --git a/programs/pkey/key_app_writer.c b/programs/pkey/key_app_writer.c
index 500e258..b81530c 100644
--- a/programs/pkey/key_app_writer.c
+++ b/programs/pkey/key_app_writer.c
@@ -189,7 +189,7 @@
             return( ret );
 
         len = ret;
-        c = output_buf + sizeof(output_buf) - len - 1;
+        c = output_buf + sizeof(output_buf) - len;
     }
 
     if( ( f = fopen( output_file, "w" ) ) == NULL )
diff --git a/programs/ssl/CMakeLists.txt b/programs/ssl/CMakeLists.txt
index 1e65633..803920c 100644
--- a/programs/ssl/CMakeLists.txt
+++ b/programs/ssl/CMakeLists.txt
@@ -34,12 +34,14 @@
 target_link_libraries(ssl_client1 ${libs})
 
 add_executable(ssl_client2 ssl_client2.c)
+target_sources(ssl_client2 PUBLIC query_config.c)
 target_link_libraries(ssl_client2 ${libs})
 
 add_executable(ssl_server ssl_server.c)
 target_link_libraries(ssl_server ${libs})
 
 add_executable(ssl_server2 ssl_server2.c)
+target_sources(ssl_server2 PUBLIC query_config.c)
 target_link_libraries(ssl_server2 ${libs})
 
 add_executable(ssl_fork_server ssl_fork_server.c)
diff --git a/programs/ssl/query_config.c b/programs/ssl/query_config.c
new file mode 100644
index 0000000..6ea9012
--- /dev/null
+++ b/programs/ssl/query_config.c
@@ -0,0 +1,2595 @@
+/*
+ *  Query Mbed TLS compile time configurations from config.h
+ *
+ *  Copyright (C) 2018, Arm Limited, All Rights Reserved
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  This file is part of Mbed TLS (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include <stdio.h>
+#define mbedtls_printf printf
+#endif /* MBEDTLS_PLATFORM_C */
+
+/*
+ * Include all the headers with public APIs in case they define a macro to its
+ * default value when that configuration is not set in the config.h.
+ */
+#include "mbedtls/aes.h"
+#include "mbedtls/aesni.h"
+#include "mbedtls/arc4.h"
+#include "mbedtls/aria.h"
+#include "mbedtls/asn1.h"
+#include "mbedtls/asn1write.h"
+#include "mbedtls/base64.h"
+#include "mbedtls/bignum.h"
+#include "mbedtls/blowfish.h"
+#include "mbedtls/camellia.h"
+#include "mbedtls/ccm.h"
+#include "mbedtls/certs.h"
+#include "mbedtls/chacha20.h"
+#include "mbedtls/chachapoly.h"
+#include "mbedtls/cipher.h"
+#include "mbedtls/cmac.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/debug.h"
+#include "mbedtls/des.h"
+#include "mbedtls/dhm.h"
+#include "mbedtls/ecdh.h"
+#include "mbedtls/ecdsa.h"
+#include "mbedtls/ecjpake.h"
+#include "mbedtls/ecp.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/entropy_poll.h"
+#include "mbedtls/error.h"
+#include "mbedtls/gcm.h"
+#include "mbedtls/havege.h"
+#include "mbedtls/hkdf.h"
+#include "mbedtls/hmac_drbg.h"
+#include "mbedtls/md.h"
+#include "mbedtls/md2.h"
+#include "mbedtls/md4.h"
+#include "mbedtls/md5.h"
+#include "mbedtls/memory_buffer_alloc.h"
+#include "mbedtls/net_sockets.h"
+#include "mbedtls/nist_kw.h"
+#include "mbedtls/oid.h"
+#include "mbedtls/padlock.h"
+#include "mbedtls/pem.h"
+#include "mbedtls/pk.h"
+#include "mbedtls/pkcs11.h"
+#include "mbedtls/pkcs12.h"
+#include "mbedtls/pkcs5.h"
+#include "mbedtls/platform_time.h"
+#include "mbedtls/platform_util.h"
+#include "mbedtls/poly1305.h"
+#include "mbedtls/ripemd160.h"
+#include "mbedtls/rsa.h"
+#include "mbedtls/sha1.h"
+#include "mbedtls/sha256.h"
+#include "mbedtls/sha512.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/ssl_cache.h"
+#include "mbedtls/ssl_ciphersuites.h"
+#include "mbedtls/ssl_cookie.h"
+#include "mbedtls/ssl_internal.h"
+#include "mbedtls/ssl_ticket.h"
+#include "mbedtls/threading.h"
+#include "mbedtls/timing.h"
+#include "mbedtls/version.h"
+#include "mbedtls/x509.h"
+#include "mbedtls/x509_crl.h"
+#include "mbedtls/x509_crt.h"
+#include "mbedtls/x509_csr.h"
+#include "mbedtls/xtea.h"
+
+#include <string.h>
+
+/*
+ * Helper macros to convert a macro or its expansion into a string
+ * WARNING: This does not work for expanding function-like macros. However,
+ * Mbed TLS does not currently have configuration options used in this fashion.
+ */
+#define MACRO_EXPANSION_TO_STR(macro)   MACRO_NAME_TO_STR(macro)
+#define MACRO_NAME_TO_STR(macro)                                        \
+    mbedtls_printf( "%s", strlen( #macro "" ) > 0 ? #macro "\n" : "" )
+
+#if defined(_MSC_VER)
+/*
+ * Visual Studio throws the warning 4003 because many Mbed TLS feature macros
+ * are defined empty. This means that from the preprocessor's point of view
+ * the macro MBEDTLS_EXPANSION_TO_STR is being invoked without arguments as
+ * some macros expand to nothing. We suppress that specific warning to get a
+ * clean build and to ensure that tests treating warnings as errors do not
+ * fail.
+ */
+#pragma warning(push)
+#pragma warning(disable:4003)
+#endif /* _MSC_VER */
+
+int query_config( const char *config )
+{
+#if defined(MBEDTLS_HAVE_ASM)
+    if( strcmp( "MBEDTLS_HAVE_ASM", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_HAVE_ASM );
+        return( 0 );
+    }
+#endif /* MBEDTLS_HAVE_ASM */
+
+#if defined(MBEDTLS_NO_UDBL_DIVISION)
+    if( strcmp( "MBEDTLS_NO_UDBL_DIVISION", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_NO_UDBL_DIVISION );
+        return( 0 );
+    }
+#endif /* MBEDTLS_NO_UDBL_DIVISION */
+
+#if defined(MBEDTLS_NO_64BIT_MULTIPLICATION)
+    if( strcmp( "MBEDTLS_NO_64BIT_MULTIPLICATION", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_NO_64BIT_MULTIPLICATION );
+        return( 0 );
+    }
+#endif /* MBEDTLS_NO_64BIT_MULTIPLICATION */
+
+#if defined(MBEDTLS_HAVE_SSE2)
+    if( strcmp( "MBEDTLS_HAVE_SSE2", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_HAVE_SSE2 );
+        return( 0 );
+    }
+#endif /* MBEDTLS_HAVE_SSE2 */
+
+#if defined(MBEDTLS_HAVE_TIME)
+    if( strcmp( "MBEDTLS_HAVE_TIME", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_HAVE_TIME );
+        return( 0 );
+    }
+#endif /* MBEDTLS_HAVE_TIME */
+
+#if defined(MBEDTLS_HAVE_TIME_DATE)
+    if( strcmp( "MBEDTLS_HAVE_TIME_DATE", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_HAVE_TIME_DATE );
+        return( 0 );
+    }
+#endif /* MBEDTLS_HAVE_TIME_DATE */
+
+#if defined(MBEDTLS_PLATFORM_MEMORY)
+    if( strcmp( "MBEDTLS_PLATFORM_MEMORY", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_MEMORY );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_MEMORY */
+
+#if defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS)
+    if( strcmp( "MBEDTLS_PLATFORM_NO_STD_FUNCTIONS", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_NO_STD_FUNCTIONS );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */
+
+#if defined(MBEDTLS_PLATFORM_EXIT_ALT)
+    if( strcmp( "MBEDTLS_PLATFORM_EXIT_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_EXIT_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_EXIT_ALT */
+
+#if defined(MBEDTLS_PLATFORM_TIME_ALT)
+    if( strcmp( "MBEDTLS_PLATFORM_TIME_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_TIME_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_TIME_ALT */
+
+#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT)
+    if( strcmp( "MBEDTLS_PLATFORM_FPRINTF_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_FPRINTF_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_FPRINTF_ALT */
+
+#if defined(MBEDTLS_PLATFORM_PRINTF_ALT)
+    if( strcmp( "MBEDTLS_PLATFORM_PRINTF_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_PRINTF_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_PRINTF_ALT */
+
+#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT)
+    if( strcmp( "MBEDTLS_PLATFORM_SNPRINTF_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_SNPRINTF_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */
+
+#if defined(MBEDTLS_PLATFORM_VSNPRINTF_ALT)
+    if( strcmp( "MBEDTLS_PLATFORM_VSNPRINTF_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_VSNPRINTF_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_VSNPRINTF_ALT */
+
+#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
+    if( strcmp( "MBEDTLS_PLATFORM_NV_SEED_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_NV_SEED_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_NV_SEED_ALT */
+
+#if defined(MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT)
+    if( strcmp( "MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT */
+
+#if defined(MBEDTLS_DEPRECATED_WARNING)
+    if( strcmp( "MBEDTLS_DEPRECATED_WARNING", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_DEPRECATED_WARNING );
+        return( 0 );
+    }
+#endif /* MBEDTLS_DEPRECATED_WARNING */
+
+#if defined(MBEDTLS_DEPRECATED_REMOVED)
+    if( strcmp( "MBEDTLS_DEPRECATED_REMOVED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_DEPRECATED_REMOVED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_DEPRECATED_REMOVED */
+
+#if defined(MBEDTLS_CHECK_PARAMS)
+    if( strcmp( "MBEDTLS_CHECK_PARAMS", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CHECK_PARAMS );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CHECK_PARAMS */
+
+#if defined(MBEDTLS_TIMING_ALT)
+    if( strcmp( "MBEDTLS_TIMING_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_TIMING_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_TIMING_ALT */
+
+#if defined(MBEDTLS_AES_ALT)
+    if( strcmp( "MBEDTLS_AES_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_AES_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_AES_ALT */
+
+#if defined(MBEDTLS_ARC4_ALT)
+    if( strcmp( "MBEDTLS_ARC4_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ARC4_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ARC4_ALT */
+
+#if defined(MBEDTLS_ARIA_ALT)
+    if( strcmp( "MBEDTLS_ARIA_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ARIA_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ARIA_ALT */
+
+#if defined(MBEDTLS_BLOWFISH_ALT)
+    if( strcmp( "MBEDTLS_BLOWFISH_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_BLOWFISH_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_BLOWFISH_ALT */
+
+#if defined(MBEDTLS_CAMELLIA_ALT)
+    if( strcmp( "MBEDTLS_CAMELLIA_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CAMELLIA_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CAMELLIA_ALT */
+
+#if defined(MBEDTLS_CCM_ALT)
+    if( strcmp( "MBEDTLS_CCM_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CCM_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CCM_ALT */
+
+#if defined(MBEDTLS_CHACHA20_ALT)
+    if( strcmp( "MBEDTLS_CHACHA20_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CHACHA20_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CHACHA20_ALT */
+
+#if defined(MBEDTLS_CHACHAPOLY_ALT)
+    if( strcmp( "MBEDTLS_CHACHAPOLY_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CHACHAPOLY_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CHACHAPOLY_ALT */
+
+#if defined(MBEDTLS_CMAC_ALT)
+    if( strcmp( "MBEDTLS_CMAC_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CMAC_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CMAC_ALT */
+
+#if defined(MBEDTLS_DES_ALT)
+    if( strcmp( "MBEDTLS_DES_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_DES_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_DES_ALT */
+
+#if defined(MBEDTLS_DHM_ALT)
+    if( strcmp( "MBEDTLS_DHM_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_DHM_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_DHM_ALT */
+
+#if defined(MBEDTLS_ECJPAKE_ALT)
+    if( strcmp( "MBEDTLS_ECJPAKE_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECJPAKE_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECJPAKE_ALT */
+
+#if defined(MBEDTLS_GCM_ALT)
+    if( strcmp( "MBEDTLS_GCM_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_GCM_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_GCM_ALT */
+
+#if defined(MBEDTLS_NIST_KW_ALT)
+    if( strcmp( "MBEDTLS_NIST_KW_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_NIST_KW_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_NIST_KW_ALT */
+
+#if defined(MBEDTLS_MD2_ALT)
+    if( strcmp( "MBEDTLS_MD2_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_MD2_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_MD2_ALT */
+
+#if defined(MBEDTLS_MD4_ALT)
+    if( strcmp( "MBEDTLS_MD4_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_MD4_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_MD4_ALT */
+
+#if defined(MBEDTLS_MD5_ALT)
+    if( strcmp( "MBEDTLS_MD5_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_MD5_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_MD5_ALT */
+
+#if defined(MBEDTLS_POLY1305_ALT)
+    if( strcmp( "MBEDTLS_POLY1305_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_POLY1305_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_POLY1305_ALT */
+
+#if defined(MBEDTLS_RIPEMD160_ALT)
+    if( strcmp( "MBEDTLS_RIPEMD160_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_RIPEMD160_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_RIPEMD160_ALT */
+
+#if defined(MBEDTLS_RSA_ALT)
+    if( strcmp( "MBEDTLS_RSA_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_RSA_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_RSA_ALT */
+
+#if defined(MBEDTLS_SHA1_ALT)
+    if( strcmp( "MBEDTLS_SHA1_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SHA1_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SHA1_ALT */
+
+#if defined(MBEDTLS_SHA256_ALT)
+    if( strcmp( "MBEDTLS_SHA256_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SHA256_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SHA256_ALT */
+
+#if defined(MBEDTLS_SHA512_ALT)
+    if( strcmp( "MBEDTLS_SHA512_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SHA512_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SHA512_ALT */
+
+#if defined(MBEDTLS_XTEA_ALT)
+    if( strcmp( "MBEDTLS_XTEA_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_XTEA_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_XTEA_ALT */
+
+#if defined(MBEDTLS_ECP_ALT)
+    if( strcmp( "MBEDTLS_ECP_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_ALT */
+
+#if defined(MBEDTLS_MD2_PROCESS_ALT)
+    if( strcmp( "MBEDTLS_MD2_PROCESS_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_MD2_PROCESS_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_MD2_PROCESS_ALT */
+
+#if defined(MBEDTLS_MD4_PROCESS_ALT)
+    if( strcmp( "MBEDTLS_MD4_PROCESS_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_MD4_PROCESS_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_MD4_PROCESS_ALT */
+
+#if defined(MBEDTLS_MD5_PROCESS_ALT)
+    if( strcmp( "MBEDTLS_MD5_PROCESS_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_MD5_PROCESS_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_MD5_PROCESS_ALT */
+
+#if defined(MBEDTLS_RIPEMD160_PROCESS_ALT)
+    if( strcmp( "MBEDTLS_RIPEMD160_PROCESS_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_RIPEMD160_PROCESS_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_RIPEMD160_PROCESS_ALT */
+
+#if defined(MBEDTLS_SHA1_PROCESS_ALT)
+    if( strcmp( "MBEDTLS_SHA1_PROCESS_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SHA1_PROCESS_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SHA1_PROCESS_ALT */
+
+#if defined(MBEDTLS_SHA256_PROCESS_ALT)
+    if( strcmp( "MBEDTLS_SHA256_PROCESS_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SHA256_PROCESS_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SHA256_PROCESS_ALT */
+
+#if defined(MBEDTLS_SHA512_PROCESS_ALT)
+    if( strcmp( "MBEDTLS_SHA512_PROCESS_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SHA512_PROCESS_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SHA512_PROCESS_ALT */
+
+#if defined(MBEDTLS_DES_SETKEY_ALT)
+    if( strcmp( "MBEDTLS_DES_SETKEY_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_DES_SETKEY_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_DES_SETKEY_ALT */
+
+#if defined(MBEDTLS_DES_CRYPT_ECB_ALT)
+    if( strcmp( "MBEDTLS_DES_CRYPT_ECB_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_DES_CRYPT_ECB_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_DES_CRYPT_ECB_ALT */
+
+#if defined(MBEDTLS_DES3_CRYPT_ECB_ALT)
+    if( strcmp( "MBEDTLS_DES3_CRYPT_ECB_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_DES3_CRYPT_ECB_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_DES3_CRYPT_ECB_ALT */
+
+#if defined(MBEDTLS_AES_SETKEY_ENC_ALT)
+    if( strcmp( "MBEDTLS_AES_SETKEY_ENC_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_AES_SETKEY_ENC_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_AES_SETKEY_ENC_ALT */
+
+#if defined(MBEDTLS_AES_SETKEY_DEC_ALT)
+    if( strcmp( "MBEDTLS_AES_SETKEY_DEC_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_AES_SETKEY_DEC_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_AES_SETKEY_DEC_ALT */
+
+#if defined(MBEDTLS_AES_ENCRYPT_ALT)
+    if( strcmp( "MBEDTLS_AES_ENCRYPT_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_AES_ENCRYPT_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_AES_ENCRYPT_ALT */
+
+#if defined(MBEDTLS_AES_DECRYPT_ALT)
+    if( strcmp( "MBEDTLS_AES_DECRYPT_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_AES_DECRYPT_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_AES_DECRYPT_ALT */
+
+#if defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT)
+    if( strcmp( "MBEDTLS_ECDH_GEN_PUBLIC_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECDH_GEN_PUBLIC_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECDH_GEN_PUBLIC_ALT */
+
+#if defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT)
+    if( strcmp( "MBEDTLS_ECDH_COMPUTE_SHARED_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECDH_COMPUTE_SHARED_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECDH_COMPUTE_SHARED_ALT */
+
+#if defined(MBEDTLS_ECDSA_VERIFY_ALT)
+    if( strcmp( "MBEDTLS_ECDSA_VERIFY_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECDSA_VERIFY_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECDSA_VERIFY_ALT */
+
+#if defined(MBEDTLS_ECDSA_SIGN_ALT)
+    if( strcmp( "MBEDTLS_ECDSA_SIGN_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECDSA_SIGN_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECDSA_SIGN_ALT */
+
+#if defined(MBEDTLS_ECDSA_GENKEY_ALT)
+    if( strcmp( "MBEDTLS_ECDSA_GENKEY_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECDSA_GENKEY_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECDSA_GENKEY_ALT */
+
+#if defined(MBEDTLS_ECP_INTERNAL_ALT)
+    if( strcmp( "MBEDTLS_ECP_INTERNAL_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_INTERNAL_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_INTERNAL_ALT */
+
+#if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT)
+    if( strcmp( "MBEDTLS_ECP_RANDOMIZE_JAC_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_RANDOMIZE_JAC_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_RANDOMIZE_JAC_ALT */
+
+#if defined(MBEDTLS_ECP_ADD_MIXED_ALT)
+    if( strcmp( "MBEDTLS_ECP_ADD_MIXED_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_ADD_MIXED_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_ADD_MIXED_ALT */
+
+#if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT)
+    if( strcmp( "MBEDTLS_ECP_DOUBLE_JAC_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_DOUBLE_JAC_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_DOUBLE_JAC_ALT */
+
+#if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT)
+    if( strcmp( "MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT */
+
+#if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT)
+    if( strcmp( "MBEDTLS_ECP_NORMALIZE_JAC_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_NORMALIZE_JAC_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_NORMALIZE_JAC_ALT */
+
+#if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT)
+    if( strcmp( "MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT */
+
+#if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT)
+    if( strcmp( "MBEDTLS_ECP_RANDOMIZE_MXZ_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_RANDOMIZE_MXZ_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_RANDOMIZE_MXZ_ALT */
+
+#if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT)
+    if( strcmp( "MBEDTLS_ECP_NORMALIZE_MXZ_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_NORMALIZE_MXZ_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_NORMALIZE_MXZ_ALT */
+
+#if defined(MBEDTLS_TEST_NULL_ENTROPY)
+    if( strcmp( "MBEDTLS_TEST_NULL_ENTROPY", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_TEST_NULL_ENTROPY );
+        return( 0 );
+    }
+#endif /* MBEDTLS_TEST_NULL_ENTROPY */
+
+#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
+    if( strcmp( "MBEDTLS_ENTROPY_HARDWARE_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ENTROPY_HARDWARE_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */
+
+#if defined(MBEDTLS_AES_ROM_TABLES)
+    if( strcmp( "MBEDTLS_AES_ROM_TABLES", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_AES_ROM_TABLES );
+        return( 0 );
+    }
+#endif /* MBEDTLS_AES_ROM_TABLES */
+
+#if defined(MBEDTLS_AES_FEWER_TABLES)
+    if( strcmp( "MBEDTLS_AES_FEWER_TABLES", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_AES_FEWER_TABLES );
+        return( 0 );
+    }
+#endif /* MBEDTLS_AES_FEWER_TABLES */
+
+#if defined(MBEDTLS_CAMELLIA_SMALL_MEMORY)
+    if( strcmp( "MBEDTLS_CAMELLIA_SMALL_MEMORY", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CAMELLIA_SMALL_MEMORY );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CAMELLIA_SMALL_MEMORY */
+
+#if defined(MBEDTLS_CIPHER_MODE_CBC)
+    if( strcmp( "MBEDTLS_CIPHER_MODE_CBC", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CIPHER_MODE_CBC );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CIPHER_MODE_CBC */
+
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+    if( strcmp( "MBEDTLS_CIPHER_MODE_CFB", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CIPHER_MODE_CFB );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CIPHER_MODE_CFB */
+
+#if defined(MBEDTLS_CIPHER_MODE_CTR)
+    if( strcmp( "MBEDTLS_CIPHER_MODE_CTR", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CIPHER_MODE_CTR );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CIPHER_MODE_CTR */
+
+#if defined(MBEDTLS_CIPHER_MODE_OFB)
+    if( strcmp( "MBEDTLS_CIPHER_MODE_OFB", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CIPHER_MODE_OFB );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CIPHER_MODE_OFB */
+
+#if defined(MBEDTLS_CIPHER_MODE_XTS)
+    if( strcmp( "MBEDTLS_CIPHER_MODE_XTS", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CIPHER_MODE_XTS );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CIPHER_MODE_XTS */
+
+#if defined(MBEDTLS_CIPHER_NULL_CIPHER)
+    if( strcmp( "MBEDTLS_CIPHER_NULL_CIPHER", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CIPHER_NULL_CIPHER );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CIPHER_NULL_CIPHER */
+
+#if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
+    if( strcmp( "MBEDTLS_CIPHER_PADDING_PKCS7", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CIPHER_PADDING_PKCS7 );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */
+
+#if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS)
+    if( strcmp( "MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */
+
+#if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN)
+    if( strcmp( "MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */
+
+#if defined(MBEDTLS_CIPHER_PADDING_ZEROS)
+    if( strcmp( "MBEDTLS_CIPHER_PADDING_ZEROS", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CIPHER_PADDING_ZEROS );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CIPHER_PADDING_ZEROS */
+
+#if defined(MBEDTLS_ENABLE_WEAK_CIPHERSUITES)
+    if( strcmp( "MBEDTLS_ENABLE_WEAK_CIPHERSUITES", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ENABLE_WEAK_CIPHERSUITES );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ENABLE_WEAK_CIPHERSUITES */
+
+#if defined(MBEDTLS_REMOVE_ARC4_CIPHERSUITES)
+    if( strcmp( "MBEDTLS_REMOVE_ARC4_CIPHERSUITES", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_REMOVE_ARC4_CIPHERSUITES );
+        return( 0 );
+    }
+#endif /* MBEDTLS_REMOVE_ARC4_CIPHERSUITES */
+
+#if defined(MBEDTLS_REMOVE_3DES_CIPHERSUITES)
+    if( strcmp( "MBEDTLS_REMOVE_3DES_CIPHERSUITES", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_REMOVE_3DES_CIPHERSUITES );
+        return( 0 );
+    }
+#endif /* MBEDTLS_REMOVE_3DES_CIPHERSUITES */
+
+#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED)
+    if( strcmp( "MBEDTLS_ECP_DP_SECP192R1_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_DP_SECP192R1_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED)
+    if( strcmp( "MBEDTLS_ECP_DP_SECP224R1_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_DP_SECP224R1_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED)
+    if( strcmp( "MBEDTLS_ECP_DP_SECP256R1_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_DP_SECP256R1_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED)
+    if( strcmp( "MBEDTLS_ECP_DP_SECP384R1_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_DP_SECP384R1_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED)
+    if( strcmp( "MBEDTLS_ECP_DP_SECP521R1_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_DP_SECP521R1_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED)
+    if( strcmp( "MBEDTLS_ECP_DP_SECP192K1_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_DP_SECP192K1_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED)
+    if( strcmp( "MBEDTLS_ECP_DP_SECP224K1_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_DP_SECP224K1_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED)
+    if( strcmp( "MBEDTLS_ECP_DP_SECP256K1_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_DP_SECP256K1_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED)
+    if( strcmp( "MBEDTLS_ECP_DP_BP256R1_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_DP_BP256R1_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED)
+    if( strcmp( "MBEDTLS_ECP_DP_BP384R1_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_DP_BP384R1_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED)
+    if( strcmp( "MBEDTLS_ECP_DP_BP512R1_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_DP_BP512R1_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED)
+    if( strcmp( "MBEDTLS_ECP_DP_CURVE25519_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_DP_CURVE25519_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED)
+    if( strcmp( "MBEDTLS_ECP_DP_CURVE448_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_DP_CURVE448_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */
+
+#if defined(MBEDTLS_ECP_NIST_OPTIM)
+    if( strcmp( "MBEDTLS_ECP_NIST_OPTIM", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_NIST_OPTIM );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_NIST_OPTIM */
+
+#if defined(MBEDTLS_ECP_RESTARTABLE)
+    if( strcmp( "MBEDTLS_ECP_RESTARTABLE", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_RESTARTABLE );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_RESTARTABLE */
+
+#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT)
+    if( strcmp( "MBEDTLS_ECDH_LEGACY_CONTEXT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECDH_LEGACY_CONTEXT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECDH_LEGACY_CONTEXT */
+
+#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
+    if( strcmp( "MBEDTLS_ECDSA_DETERMINISTIC", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECDSA_DETERMINISTIC );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECDSA_DETERMINISTIC */
+
+#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
+    if( strcmp( "MBEDTLS_KEY_EXCHANGE_PSK_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_KEY_EXCHANGE_PSK_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */
+
+#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED)
+    if( strcmp( "MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED)
+    if( strcmp( "MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */
+
+#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED)
+    if( strcmp( "MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */
+
+#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)
+    if( strcmp( "MBEDTLS_KEY_EXCHANGE_RSA_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_KEY_EXCHANGE_RSA_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */
+
+#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)
+    if( strcmp( "MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED */
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED)
+    if( strcmp( "MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED */
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
+    if( strcmp( "MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)
+    if( strcmp( "MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED)
+    if( strcmp( "MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED */
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+    if( strcmp( "MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
+
+#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED)
+    if( strcmp( "MBEDTLS_PK_PARSE_EC_EXTENDED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PK_PARSE_EC_EXTENDED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PK_PARSE_EC_EXTENDED */
+
+#if defined(MBEDTLS_ERROR_STRERROR_DUMMY)
+    if( strcmp( "MBEDTLS_ERROR_STRERROR_DUMMY", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ERROR_STRERROR_DUMMY );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ERROR_STRERROR_DUMMY */
+
+#if defined(MBEDTLS_GENPRIME)
+    if( strcmp( "MBEDTLS_GENPRIME", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_GENPRIME );
+        return( 0 );
+    }
+#endif /* MBEDTLS_GENPRIME */
+
+#if defined(MBEDTLS_FS_IO)
+    if( strcmp( "MBEDTLS_FS_IO", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_FS_IO );
+        return( 0 );
+    }
+#endif /* MBEDTLS_FS_IO */
+
+#if defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES)
+    if( strcmp( "MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES );
+        return( 0 );
+    }
+#endif /* MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES */
+
+#if defined(MBEDTLS_NO_PLATFORM_ENTROPY)
+    if( strcmp( "MBEDTLS_NO_PLATFORM_ENTROPY", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_NO_PLATFORM_ENTROPY );
+        return( 0 );
+    }
+#endif /* MBEDTLS_NO_PLATFORM_ENTROPY */
+
+#if defined(MBEDTLS_ENTROPY_FORCE_SHA256)
+    if( strcmp( "MBEDTLS_ENTROPY_FORCE_SHA256", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ENTROPY_FORCE_SHA256 );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ENTROPY_FORCE_SHA256 */
+
+#if defined(MBEDTLS_ENTROPY_NV_SEED)
+    if( strcmp( "MBEDTLS_ENTROPY_NV_SEED", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ENTROPY_NV_SEED );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ENTROPY_NV_SEED */
+
+#if defined(MBEDTLS_MEMORY_DEBUG)
+    if( strcmp( "MBEDTLS_MEMORY_DEBUG", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_MEMORY_DEBUG );
+        return( 0 );
+    }
+#endif /* MBEDTLS_MEMORY_DEBUG */
+
+#if defined(MBEDTLS_MEMORY_BACKTRACE)
+    if( strcmp( "MBEDTLS_MEMORY_BACKTRACE", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_MEMORY_BACKTRACE );
+        return( 0 );
+    }
+#endif /* MBEDTLS_MEMORY_BACKTRACE */
+
+#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT)
+    if( strcmp( "MBEDTLS_PK_RSA_ALT_SUPPORT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PK_RSA_ALT_SUPPORT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */
+
+#if defined(MBEDTLS_PKCS1_V15)
+    if( strcmp( "MBEDTLS_PKCS1_V15", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PKCS1_V15 );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PKCS1_V15 */
+
+#if defined(MBEDTLS_PKCS1_V21)
+    if( strcmp( "MBEDTLS_PKCS1_V21", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PKCS1_V21 );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PKCS1_V21 */
+
+#if defined(MBEDTLS_PSA_CRYPTO_SPM)
+    if( strcmp( "MBEDTLS_PSA_CRYPTO_SPM", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PSA_CRYPTO_SPM );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PSA_CRYPTO_SPM */
+
+#if defined(MBEDTLS_PSA_INJECT_ENTROPY)
+    if( strcmp( "MBEDTLS_PSA_INJECT_ENTROPY", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PSA_INJECT_ENTROPY );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PSA_INJECT_ENTROPY */
+
+#if defined(MBEDTLS_RSA_NO_CRT)
+    if( strcmp( "MBEDTLS_RSA_NO_CRT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_RSA_NO_CRT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_RSA_NO_CRT */
+
+#if defined(MBEDTLS_SELF_TEST)
+    if( strcmp( "MBEDTLS_SELF_TEST", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SELF_TEST );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SELF_TEST */
+
+#if defined(MBEDTLS_SHA256_SMALLER)
+    if( strcmp( "MBEDTLS_SHA256_SMALLER", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SHA256_SMALLER );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SHA256_SMALLER */
+
+#if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES)
+    if( strcmp( "MBEDTLS_SSL_ALL_ALERT_MESSAGES", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_ALL_ALERT_MESSAGES );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_ALL_ALERT_MESSAGES */
+
+#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
+    if( strcmp( "MBEDTLS_SSL_ASYNC_PRIVATE", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_ASYNC_PRIVATE );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+
+#if defined(MBEDTLS_SSL_DEBUG_ALL)
+    if( strcmp( "MBEDTLS_SSL_DEBUG_ALL", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_DEBUG_ALL );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_DEBUG_ALL */
+
+#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+    if( strcmp( "MBEDTLS_SSL_ENCRYPT_THEN_MAC", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_ENCRYPT_THEN_MAC );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */
+
+#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
+    if( strcmp( "MBEDTLS_SSL_EXTENDED_MASTER_SECRET", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_EXTENDED_MASTER_SECRET );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */
+
+#if defined(MBEDTLS_SSL_FALLBACK_SCSV)
+    if( strcmp( "MBEDTLS_SSL_FALLBACK_SCSV", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_FALLBACK_SCSV );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_FALLBACK_SCSV */
+
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    if( strcmp( "MBEDTLS_SSL_KEEP_PEER_CERTIFICATE", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_KEEP_PEER_CERTIFICATE );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+
+#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL)
+    if( strcmp( "MBEDTLS_SSL_HW_RECORD_ACCEL", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_HW_RECORD_ACCEL );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */
+
+#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING)
+    if( strcmp( "MBEDTLS_SSL_CBC_RECORD_SPLITTING", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CBC_RECORD_SPLITTING );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */
+
+#if defined(MBEDTLS_SSL_RENEGOTIATION)
+    if( strcmp( "MBEDTLS_SSL_RENEGOTIATION", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_RENEGOTIATION );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_RENEGOTIATION */
+
+#if defined(MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO)
+    if( strcmp( "MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO */
+
+#if defined(MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE)
+    if( strcmp( "MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE */
+
+#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
+    if( strcmp( "MBEDTLS_SSL_MAX_FRAGMENT_LENGTH", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_MAX_FRAGMENT_LENGTH );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
+
+#if defined(MBEDTLS_SSL_PROTO_SSL3)
+    if( strcmp( "MBEDTLS_SSL_PROTO_SSL3", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_PROTO_SSL3 );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_PROTO_SSL3 */
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1)
+    if( strcmp( "MBEDTLS_SSL_PROTO_TLS1", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_PROTO_TLS1 );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_PROTO_TLS1 */
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_1)
+    if( strcmp( "MBEDTLS_SSL_PROTO_TLS1_1", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_PROTO_TLS1_1 );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_PROTO_TLS1_1 */
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
+    if( strcmp( "MBEDTLS_SSL_PROTO_TLS1_2", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_PROTO_TLS1_2 );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+    if( strcmp( "MBEDTLS_SSL_PROTO_DTLS", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_PROTO_DTLS );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
+#if defined(MBEDTLS_SSL_ALPN)
+    if( strcmp( "MBEDTLS_SSL_ALPN", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_ALPN );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_ALPN */
+
+#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
+    if( strcmp( "MBEDTLS_SSL_DTLS_ANTI_REPLAY", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_DTLS_ANTI_REPLAY );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */
+
+#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY)
+    if( strcmp( "MBEDTLS_SSL_DTLS_HELLO_VERIFY", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_DTLS_HELLO_VERIFY );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */
+
+#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE)
+    if( strcmp( "MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE */
+
+#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT)
+    if( strcmp( "MBEDTLS_SSL_DTLS_BADMAC_LIMIT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_DTLS_BADMAC_LIMIT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */
+
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+    if( strcmp( "MBEDTLS_SSL_SESSION_TICKETS", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_SESSION_TICKETS );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_SESSION_TICKETS */
+
+#if defined(MBEDTLS_SSL_EXPORT_KEYS)
+    if( strcmp( "MBEDTLS_SSL_EXPORT_KEYS", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_EXPORT_KEYS );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_EXPORT_KEYS */
+
+#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION)
+    if( strcmp( "MBEDTLS_SSL_SERVER_NAME_INDICATION", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_SERVER_NAME_INDICATION );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */
+
+#if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
+    if( strcmp( "MBEDTLS_SSL_TRUNCATED_HMAC", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_TRUNCATED_HMAC );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */
+
+#if defined(MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT)
+    if( strcmp( "MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT */
+
+#if defined(MBEDTLS_THREADING_ALT)
+    if( strcmp( "MBEDTLS_THREADING_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_THREADING_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_THREADING_ALT */
+
+#if defined(MBEDTLS_THREADING_PTHREAD)
+    if( strcmp( "MBEDTLS_THREADING_PTHREAD", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_THREADING_PTHREAD );
+        return( 0 );
+    }
+#endif /* MBEDTLS_THREADING_PTHREAD */
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    if( strcmp( "MBEDTLS_USE_PSA_CRYPTO", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_USE_PSA_CRYPTO );
+        return( 0 );
+    }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+#if defined(MBEDTLS_VERSION_FEATURES)
+    if( strcmp( "MBEDTLS_VERSION_FEATURES", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_VERSION_FEATURES );
+        return( 0 );
+    }
+#endif /* MBEDTLS_VERSION_FEATURES */
+
+#if defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3)
+    if( strcmp( "MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 );
+        return( 0 );
+    }
+#endif /* MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 */
+
+#if defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION)
+    if( strcmp( "MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION );
+        return( 0 );
+    }
+#endif /* MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION */
+
+#if defined(MBEDTLS_X509_CHECK_KEY_USAGE)
+    if( strcmp( "MBEDTLS_X509_CHECK_KEY_USAGE", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_X509_CHECK_KEY_USAGE );
+        return( 0 );
+    }
+#endif /* MBEDTLS_X509_CHECK_KEY_USAGE */
+
+#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE)
+    if( strcmp( "MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE );
+        return( 0 );
+    }
+#endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */
+
+#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT)
+    if( strcmp( "MBEDTLS_X509_RSASSA_PSS_SUPPORT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_X509_RSASSA_PSS_SUPPORT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */
+
+#if defined(MBEDTLS_ZLIB_SUPPORT)
+    if( strcmp( "MBEDTLS_ZLIB_SUPPORT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ZLIB_SUPPORT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ZLIB_SUPPORT */
+
+#if defined(MBEDTLS_AESNI_C)
+    if( strcmp( "MBEDTLS_AESNI_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_AESNI_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_AESNI_C */
+
+#if defined(MBEDTLS_AES_C)
+    if( strcmp( "MBEDTLS_AES_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_AES_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_AES_C */
+
+#if defined(MBEDTLS_ARC4_C)
+    if( strcmp( "MBEDTLS_ARC4_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ARC4_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ARC4_C */
+
+#if defined(MBEDTLS_ASN1_PARSE_C)
+    if( strcmp( "MBEDTLS_ASN1_PARSE_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ASN1_PARSE_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ASN1_PARSE_C */
+
+#if defined(MBEDTLS_ASN1_WRITE_C)
+    if( strcmp( "MBEDTLS_ASN1_WRITE_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ASN1_WRITE_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ASN1_WRITE_C */
+
+#if defined(MBEDTLS_BASE64_C)
+    if( strcmp( "MBEDTLS_BASE64_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_BASE64_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_BASE64_C */
+
+#if defined(MBEDTLS_BIGNUM_C)
+    if( strcmp( "MBEDTLS_BIGNUM_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_BIGNUM_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_BIGNUM_C */
+
+#if defined(MBEDTLS_BLOWFISH_C)
+    if( strcmp( "MBEDTLS_BLOWFISH_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_BLOWFISH_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_BLOWFISH_C */
+
+#if defined(MBEDTLS_CAMELLIA_C)
+    if( strcmp( "MBEDTLS_CAMELLIA_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CAMELLIA_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CAMELLIA_C */
+
+#if defined(MBEDTLS_ARIA_C)
+    if( strcmp( "MBEDTLS_ARIA_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ARIA_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ARIA_C */
+
+#if defined(MBEDTLS_CCM_C)
+    if( strcmp( "MBEDTLS_CCM_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CCM_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CCM_C */
+
+#if defined(MBEDTLS_CERTS_C)
+    if( strcmp( "MBEDTLS_CERTS_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CERTS_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CERTS_C */
+
+#if defined(MBEDTLS_CHACHA20_C)
+    if( strcmp( "MBEDTLS_CHACHA20_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CHACHA20_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CHACHA20_C */
+
+#if defined(MBEDTLS_CHACHAPOLY_C)
+    if( strcmp( "MBEDTLS_CHACHAPOLY_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CHACHAPOLY_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CHACHAPOLY_C */
+
+#if defined(MBEDTLS_CIPHER_C)
+    if( strcmp( "MBEDTLS_CIPHER_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CIPHER_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CIPHER_C */
+
+#if defined(MBEDTLS_CMAC_C)
+    if( strcmp( "MBEDTLS_CMAC_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CMAC_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CMAC_C */
+
+#if defined(MBEDTLS_CTR_DRBG_C)
+    if( strcmp( "MBEDTLS_CTR_DRBG_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CTR_DRBG_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CTR_DRBG_C */
+
+#if defined(MBEDTLS_DEBUG_C)
+    if( strcmp( "MBEDTLS_DEBUG_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_DEBUG_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_DEBUG_C */
+
+#if defined(MBEDTLS_DES_C)
+    if( strcmp( "MBEDTLS_DES_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_DES_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_DES_C */
+
+#if defined(MBEDTLS_DHM_C)
+    if( strcmp( "MBEDTLS_DHM_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_DHM_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_DHM_C */
+
+#if defined(MBEDTLS_ECDH_C)
+    if( strcmp( "MBEDTLS_ECDH_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECDH_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECDH_C */
+
+#if defined(MBEDTLS_ECDSA_C)
+    if( strcmp( "MBEDTLS_ECDSA_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECDSA_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECDSA_C */
+
+#if defined(MBEDTLS_ECJPAKE_C)
+    if( strcmp( "MBEDTLS_ECJPAKE_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECJPAKE_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECJPAKE_C */
+
+#if defined(MBEDTLS_ECP_C)
+    if( strcmp( "MBEDTLS_ECP_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_C */
+
+#if defined(MBEDTLS_ENTROPY_C)
+    if( strcmp( "MBEDTLS_ENTROPY_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ENTROPY_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ENTROPY_C */
+
+#if defined(MBEDTLS_ERROR_C)
+    if( strcmp( "MBEDTLS_ERROR_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ERROR_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ERROR_C */
+
+#if defined(MBEDTLS_GCM_C)
+    if( strcmp( "MBEDTLS_GCM_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_GCM_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_GCM_C */
+
+#if defined(MBEDTLS_HAVEGE_C)
+    if( strcmp( "MBEDTLS_HAVEGE_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_HAVEGE_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_HAVEGE_C */
+
+#if defined(MBEDTLS_HKDF_C)
+    if( strcmp( "MBEDTLS_HKDF_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_HKDF_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_HKDF_C */
+
+#if defined(MBEDTLS_HMAC_DRBG_C)
+    if( strcmp( "MBEDTLS_HMAC_DRBG_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_HMAC_DRBG_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_HMAC_DRBG_C */
+
+#if defined(MBEDTLS_NIST_KW_C)
+    if( strcmp( "MBEDTLS_NIST_KW_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_NIST_KW_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_NIST_KW_C */
+
+#if defined(MBEDTLS_MD_C)
+    if( strcmp( "MBEDTLS_MD_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_MD_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_MD_C */
+
+#if defined(MBEDTLS_MD2_C)
+    if( strcmp( "MBEDTLS_MD2_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_MD2_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_MD2_C */
+
+#if defined(MBEDTLS_MD4_C)
+    if( strcmp( "MBEDTLS_MD4_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_MD4_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_MD4_C */
+
+#if defined(MBEDTLS_MD5_C)
+    if( strcmp( "MBEDTLS_MD5_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_MD5_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_MD5_C */
+
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
+    if( strcmp( "MBEDTLS_MEMORY_BUFFER_ALLOC_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_MEMORY_BUFFER_ALLOC_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */
+
+#if defined(MBEDTLS_NET_C)
+    if( strcmp( "MBEDTLS_NET_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_NET_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_NET_C */
+
+#if defined(MBEDTLS_OID_C)
+    if( strcmp( "MBEDTLS_OID_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_OID_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_OID_C */
+
+#if defined(MBEDTLS_PADLOCK_C)
+    if( strcmp( "MBEDTLS_PADLOCK_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PADLOCK_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PADLOCK_C */
+
+#if defined(MBEDTLS_PEM_PARSE_C)
+    if( strcmp( "MBEDTLS_PEM_PARSE_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PEM_PARSE_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PEM_PARSE_C */
+
+#if defined(MBEDTLS_PEM_WRITE_C)
+    if( strcmp( "MBEDTLS_PEM_WRITE_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PEM_WRITE_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PEM_WRITE_C */
+
+#if defined(MBEDTLS_PK_C)
+    if( strcmp( "MBEDTLS_PK_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PK_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PK_C */
+
+#if defined(MBEDTLS_PK_PARSE_C)
+    if( strcmp( "MBEDTLS_PK_PARSE_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PK_PARSE_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PK_PARSE_C */
+
+#if defined(MBEDTLS_PK_WRITE_C)
+    if( strcmp( "MBEDTLS_PK_WRITE_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PK_WRITE_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PK_WRITE_C */
+
+#if defined(MBEDTLS_PKCS5_C)
+    if( strcmp( "MBEDTLS_PKCS5_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PKCS5_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PKCS5_C */
+
+#if defined(MBEDTLS_PKCS11_C)
+    if( strcmp( "MBEDTLS_PKCS11_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PKCS11_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PKCS11_C */
+
+#if defined(MBEDTLS_PKCS12_C)
+    if( strcmp( "MBEDTLS_PKCS12_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PKCS12_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PKCS12_C */
+
+#if defined(MBEDTLS_PLATFORM_C)
+    if( strcmp( "MBEDTLS_PLATFORM_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_C */
+
+#if defined(MBEDTLS_POLY1305_C)
+    if( strcmp( "MBEDTLS_POLY1305_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_POLY1305_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_POLY1305_C */
+
+#if defined(MBEDTLS_PSA_CRYPTO_C)
+    if( strcmp( "MBEDTLS_PSA_CRYPTO_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PSA_CRYPTO_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PSA_CRYPTO_C */
+
+#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
+    if( strcmp( "MBEDTLS_PSA_CRYPTO_STORAGE_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PSA_CRYPTO_STORAGE_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */
+
+#if defined(MBEDTLS_PSA_ITS_FILE_C)
+    if( strcmp( "MBEDTLS_PSA_ITS_FILE_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PSA_ITS_FILE_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PSA_ITS_FILE_C */
+
+#if defined(MBEDTLS_RIPEMD160_C)
+    if( strcmp( "MBEDTLS_RIPEMD160_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_RIPEMD160_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_RIPEMD160_C */
+
+#if defined(MBEDTLS_RSA_C)
+    if( strcmp( "MBEDTLS_RSA_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_RSA_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_RSA_C */
+
+#if defined(MBEDTLS_SHA1_C)
+    if( strcmp( "MBEDTLS_SHA1_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SHA1_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SHA1_C */
+
+#if defined(MBEDTLS_SHA256_C)
+    if( strcmp( "MBEDTLS_SHA256_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SHA256_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SHA256_C */
+
+#if defined(MBEDTLS_SHA512_C)
+    if( strcmp( "MBEDTLS_SHA512_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SHA512_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SHA512_C */
+
+#if defined(MBEDTLS_SSL_CACHE_C)
+    if( strcmp( "MBEDTLS_SSL_CACHE_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CACHE_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CACHE_C */
+
+#if defined(MBEDTLS_SSL_COOKIE_C)
+    if( strcmp( "MBEDTLS_SSL_COOKIE_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_COOKIE_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_COOKIE_C */
+
+#if defined(MBEDTLS_SSL_TICKET_C)
+    if( strcmp( "MBEDTLS_SSL_TICKET_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_TICKET_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_TICKET_C */
+
+#if defined(MBEDTLS_SSL_CLI_C)
+    if( strcmp( "MBEDTLS_SSL_CLI_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CLI_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CLI_C */
+
+#if defined(MBEDTLS_SSL_SRV_C)
+    if( strcmp( "MBEDTLS_SSL_SRV_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_SRV_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_SRV_C */
+
+#if defined(MBEDTLS_SSL_TLS_C)
+    if( strcmp( "MBEDTLS_SSL_TLS_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_TLS_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_TLS_C */
+
+#if defined(MBEDTLS_THREADING_C)
+    if( strcmp( "MBEDTLS_THREADING_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_THREADING_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_THREADING_C */
+
+#if defined(MBEDTLS_TIMING_C)
+    if( strcmp( "MBEDTLS_TIMING_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_TIMING_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_TIMING_C */
+
+#if defined(MBEDTLS_VERSION_C)
+    if( strcmp( "MBEDTLS_VERSION_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_VERSION_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_VERSION_C */
+
+#if defined(MBEDTLS_X509_USE_C)
+    if( strcmp( "MBEDTLS_X509_USE_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_X509_USE_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_X509_USE_C */
+
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+    if( strcmp( "MBEDTLS_X509_CRT_PARSE_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_X509_CRT_PARSE_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
+#if defined(MBEDTLS_X509_CRL_PARSE_C)
+    if( strcmp( "MBEDTLS_X509_CRL_PARSE_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_X509_CRL_PARSE_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_X509_CRL_PARSE_C */
+
+#if defined(MBEDTLS_X509_CSR_PARSE_C)
+    if( strcmp( "MBEDTLS_X509_CSR_PARSE_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_X509_CSR_PARSE_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_X509_CSR_PARSE_C */
+
+#if defined(MBEDTLS_X509_CREATE_C)
+    if( strcmp( "MBEDTLS_X509_CREATE_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_X509_CREATE_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_X509_CREATE_C */
+
+#if defined(MBEDTLS_X509_CRT_WRITE_C)
+    if( strcmp( "MBEDTLS_X509_CRT_WRITE_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_X509_CRT_WRITE_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_X509_CRT_WRITE_C */
+
+#if defined(MBEDTLS_X509_CSR_WRITE_C)
+    if( strcmp( "MBEDTLS_X509_CSR_WRITE_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_X509_CSR_WRITE_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_X509_CSR_WRITE_C */
+
+#if defined(MBEDTLS_XTEA_C)
+    if( strcmp( "MBEDTLS_XTEA_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_XTEA_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_XTEA_C */
+
+#if defined(MBEDTLS_MPI_WINDOW_SIZE)
+    if( strcmp( "MBEDTLS_MPI_WINDOW_SIZE", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_MPI_WINDOW_SIZE );
+        return( 0 );
+    }
+#endif /* MBEDTLS_MPI_WINDOW_SIZE */
+
+#if defined(MBEDTLS_MPI_MAX_SIZE)
+    if( strcmp( "MBEDTLS_MPI_MAX_SIZE", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_MPI_MAX_SIZE );
+        return( 0 );
+    }
+#endif /* MBEDTLS_MPI_MAX_SIZE */
+
+#if defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN)
+    if( strcmp( "MBEDTLS_CTR_DRBG_ENTROPY_LEN", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CTR_DRBG_ENTROPY_LEN );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CTR_DRBG_ENTROPY_LEN */
+
+#if defined(MBEDTLS_CTR_DRBG_RESEED_INTERVAL)
+    if( strcmp( "MBEDTLS_CTR_DRBG_RESEED_INTERVAL", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CTR_DRBG_RESEED_INTERVAL );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CTR_DRBG_RESEED_INTERVAL */
+
+#if defined(MBEDTLS_CTR_DRBG_MAX_INPUT)
+    if( strcmp( "MBEDTLS_CTR_DRBG_MAX_INPUT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CTR_DRBG_MAX_INPUT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CTR_DRBG_MAX_INPUT */
+
+#if defined(MBEDTLS_CTR_DRBG_MAX_REQUEST)
+    if( strcmp( "MBEDTLS_CTR_DRBG_MAX_REQUEST", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CTR_DRBG_MAX_REQUEST );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CTR_DRBG_MAX_REQUEST */
+
+#if defined(MBEDTLS_CTR_DRBG_MAX_SEED_INPUT)
+    if( strcmp( "MBEDTLS_CTR_DRBG_MAX_SEED_INPUT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CTR_DRBG_MAX_SEED_INPUT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CTR_DRBG_MAX_SEED_INPUT */
+
+#if defined(MBEDTLS_CTR_DRBG_USE_128_BIT_KEY)
+    if( strcmp( "MBEDTLS_CTR_DRBG_USE_128_BIT_KEY", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_CTR_DRBG_USE_128_BIT_KEY );
+        return( 0 );
+    }
+#endif /* MBEDTLS_CTR_DRBG_USE_128_BIT_KEY */
+
+#if defined(MBEDTLS_HMAC_DRBG_RESEED_INTERVAL)
+    if( strcmp( "MBEDTLS_HMAC_DRBG_RESEED_INTERVAL", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_HMAC_DRBG_RESEED_INTERVAL );
+        return( 0 );
+    }
+#endif /* MBEDTLS_HMAC_DRBG_RESEED_INTERVAL */
+
+#if defined(MBEDTLS_HMAC_DRBG_MAX_INPUT)
+    if( strcmp( "MBEDTLS_HMAC_DRBG_MAX_INPUT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_HMAC_DRBG_MAX_INPUT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_HMAC_DRBG_MAX_INPUT */
+
+#if defined(MBEDTLS_HMAC_DRBG_MAX_REQUEST)
+    if( strcmp( "MBEDTLS_HMAC_DRBG_MAX_REQUEST", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_HMAC_DRBG_MAX_REQUEST );
+        return( 0 );
+    }
+#endif /* MBEDTLS_HMAC_DRBG_MAX_REQUEST */
+
+#if defined(MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT)
+    if( strcmp( "MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT */
+
+#if defined(MBEDTLS_ECP_MAX_BITS)
+    if( strcmp( "MBEDTLS_ECP_MAX_BITS", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_MAX_BITS );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_MAX_BITS */
+
+#if defined(MBEDTLS_ECP_WINDOW_SIZE)
+    if( strcmp( "MBEDTLS_ECP_WINDOW_SIZE", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_WINDOW_SIZE );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_WINDOW_SIZE */
+
+#if defined(MBEDTLS_ECP_FIXED_POINT_OPTIM)
+    if( strcmp( "MBEDTLS_ECP_FIXED_POINT_OPTIM", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ECP_FIXED_POINT_OPTIM );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ECP_FIXED_POINT_OPTIM */
+
+#if defined(MBEDTLS_ENTROPY_MAX_SOURCES)
+    if( strcmp( "MBEDTLS_ENTROPY_MAX_SOURCES", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ENTROPY_MAX_SOURCES );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ENTROPY_MAX_SOURCES */
+
+#if defined(MBEDTLS_ENTROPY_MAX_GATHER)
+    if( strcmp( "MBEDTLS_ENTROPY_MAX_GATHER", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ENTROPY_MAX_GATHER );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ENTROPY_MAX_GATHER */
+
+#if defined(MBEDTLS_ENTROPY_MIN_HARDWARE)
+    if( strcmp( "MBEDTLS_ENTROPY_MIN_HARDWARE", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_ENTROPY_MIN_HARDWARE );
+        return( 0 );
+    }
+#endif /* MBEDTLS_ENTROPY_MIN_HARDWARE */
+
+#if defined(MBEDTLS_MEMORY_ALIGN_MULTIPLE)
+    if( strcmp( "MBEDTLS_MEMORY_ALIGN_MULTIPLE", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_MEMORY_ALIGN_MULTIPLE );
+        return( 0 );
+    }
+#endif /* MBEDTLS_MEMORY_ALIGN_MULTIPLE */
+
+#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR)
+    if( strcmp( "MBEDTLS_PLATFORM_STD_MEM_HDR", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_STD_MEM_HDR );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_STD_MEM_HDR */
+
+#if defined(MBEDTLS_PLATFORM_STD_CALLOC)
+    if( strcmp( "MBEDTLS_PLATFORM_STD_CALLOC", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_STD_CALLOC );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_STD_CALLOC */
+
+#if defined(MBEDTLS_PLATFORM_STD_FREE)
+    if( strcmp( "MBEDTLS_PLATFORM_STD_FREE", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_STD_FREE );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_STD_FREE */
+
+#if defined(MBEDTLS_PLATFORM_STD_EXIT)
+    if( strcmp( "MBEDTLS_PLATFORM_STD_EXIT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_STD_EXIT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_STD_EXIT */
+
+#if defined(MBEDTLS_PLATFORM_STD_TIME)
+    if( strcmp( "MBEDTLS_PLATFORM_STD_TIME", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_STD_TIME );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_STD_TIME */
+
+#if defined(MBEDTLS_PLATFORM_STD_FPRINTF)
+    if( strcmp( "MBEDTLS_PLATFORM_STD_FPRINTF", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_STD_FPRINTF );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_STD_FPRINTF */
+
+#if defined(MBEDTLS_PLATFORM_STD_PRINTF)
+    if( strcmp( "MBEDTLS_PLATFORM_STD_PRINTF", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_STD_PRINTF );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_STD_PRINTF */
+
+#if defined(MBEDTLS_PLATFORM_STD_SNPRINTF)
+    if( strcmp( "MBEDTLS_PLATFORM_STD_SNPRINTF", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_STD_SNPRINTF );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_STD_SNPRINTF */
+
+#if defined(MBEDTLS_PLATFORM_STD_EXIT_SUCCESS)
+    if( strcmp( "MBEDTLS_PLATFORM_STD_EXIT_SUCCESS", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_STD_EXIT_SUCCESS );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_STD_EXIT_SUCCESS */
+
+#if defined(MBEDTLS_PLATFORM_STD_EXIT_FAILURE)
+    if( strcmp( "MBEDTLS_PLATFORM_STD_EXIT_FAILURE", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_STD_EXIT_FAILURE );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_STD_EXIT_FAILURE */
+
+#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ)
+    if( strcmp( "MBEDTLS_PLATFORM_STD_NV_SEED_READ", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_STD_NV_SEED_READ );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_STD_NV_SEED_READ */
+
+#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE)
+    if( strcmp( "MBEDTLS_PLATFORM_STD_NV_SEED_WRITE", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_STD_NV_SEED_WRITE );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_STD_NV_SEED_WRITE */
+
+#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_FILE)
+    if( strcmp( "MBEDTLS_PLATFORM_STD_NV_SEED_FILE", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_STD_NV_SEED_FILE );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_STD_NV_SEED_FILE */
+
+#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO)
+    if( strcmp( "MBEDTLS_PLATFORM_CALLOC_MACRO", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_CALLOC_MACRO );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_CALLOC_MACRO */
+
+#if defined(MBEDTLS_PLATFORM_FREE_MACRO)
+    if( strcmp( "MBEDTLS_PLATFORM_FREE_MACRO", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_FREE_MACRO );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_FREE_MACRO */
+
+#if defined(MBEDTLS_PLATFORM_EXIT_MACRO)
+    if( strcmp( "MBEDTLS_PLATFORM_EXIT_MACRO", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_EXIT_MACRO );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_EXIT_MACRO */
+
+#if defined(MBEDTLS_PLATFORM_TIME_MACRO)
+    if( strcmp( "MBEDTLS_PLATFORM_TIME_MACRO", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_TIME_MACRO );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_TIME_MACRO */
+
+#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO)
+    if( strcmp( "MBEDTLS_PLATFORM_TIME_TYPE_MACRO", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_TIME_TYPE_MACRO );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_TIME_TYPE_MACRO */
+
+#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO)
+    if( strcmp( "MBEDTLS_PLATFORM_FPRINTF_MACRO", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_FPRINTF_MACRO );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_FPRINTF_MACRO */
+
+#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO)
+    if( strcmp( "MBEDTLS_PLATFORM_PRINTF_MACRO", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_PRINTF_MACRO );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_PRINTF_MACRO */
+
+#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO)
+    if( strcmp( "MBEDTLS_PLATFORM_SNPRINTF_MACRO", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_SNPRINTF_MACRO );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_SNPRINTF_MACRO */
+
+#if defined(MBEDTLS_PLATFORM_VSNPRINTF_MACRO)
+    if( strcmp( "MBEDTLS_PLATFORM_VSNPRINTF_MACRO", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_VSNPRINTF_MACRO );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_VSNPRINTF_MACRO */
+
+#if defined(MBEDTLS_PLATFORM_NV_SEED_READ_MACRO)
+    if( strcmp( "MBEDTLS_PLATFORM_NV_SEED_READ_MACRO", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_NV_SEED_READ_MACRO );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_NV_SEED_READ_MACRO */
+
+#if defined(MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO)
+    if( strcmp( "MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO */
+
+#if defined(MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT)
+    if( strcmp( "MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT */
+
+#if defined(MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES)
+    if( strcmp( "MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES */
+
+#if defined(MBEDTLS_SSL_MAX_CONTENT_LEN)
+    if( strcmp( "MBEDTLS_SSL_MAX_CONTENT_LEN", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_MAX_CONTENT_LEN );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_MAX_CONTENT_LEN */
+
+#if defined(MBEDTLS_SSL_IN_CONTENT_LEN)
+    if( strcmp( "MBEDTLS_SSL_IN_CONTENT_LEN", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_IN_CONTENT_LEN );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_IN_CONTENT_LEN */
+
+#if defined(MBEDTLS_SSL_OUT_CONTENT_LEN)
+    if( strcmp( "MBEDTLS_SSL_OUT_CONTENT_LEN", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_OUT_CONTENT_LEN );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_OUT_CONTENT_LEN */
+
+#if defined(MBEDTLS_SSL_DTLS_MAX_BUFFERING)
+    if( strcmp( "MBEDTLS_SSL_DTLS_MAX_BUFFERING", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_DTLS_MAX_BUFFERING );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_DTLS_MAX_BUFFERING */
+
+#if defined(MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME)
+    if( strcmp( "MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME */
+
+#if defined(MBEDTLS_PSK_MAX_LEN)
+    if( strcmp( "MBEDTLS_PSK_MAX_LEN", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PSK_MAX_LEN );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PSK_MAX_LEN */
+
+#if defined(MBEDTLS_SSL_COOKIE_TIMEOUT)
+    if( strcmp( "MBEDTLS_SSL_COOKIE_TIMEOUT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_COOKIE_TIMEOUT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_COOKIE_TIMEOUT */
+
+#if defined(MBEDTLS_X509_MAX_INTERMEDIATE_CA)
+    if( strcmp( "MBEDTLS_X509_MAX_INTERMEDIATE_CA", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_X509_MAX_INTERMEDIATE_CA );
+        return( 0 );
+    }
+#endif /* MBEDTLS_X509_MAX_INTERMEDIATE_CA */
+
+#if defined(MBEDTLS_X509_MAX_FILE_PATH_LEN)
+    if( strcmp( "MBEDTLS_X509_MAX_FILE_PATH_LEN", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_X509_MAX_FILE_PATH_LEN );
+        return( 0 );
+    }
+#endif /* MBEDTLS_X509_MAX_FILE_PATH_LEN */
+
+#if defined(MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES)
+    if( strcmp( "MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES );
+        return( 0 );
+    }
+#endif /* MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES */
+
+#if defined(MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_KEY_EXCHANGE)
+    if( strcmp( "MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_KEY_EXCHANGE", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_KEY_EXCHANGE );
+        return( 0 );
+    }
+#endif /* MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_KEY_EXCHANGE */
+
+#if defined(MBEDTLS_PLATFORM_ZEROIZE_ALT)
+    if( strcmp( "MBEDTLS_PLATFORM_ZEROIZE_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_ZEROIZE_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_ZEROIZE_ALT */
+
+#if defined(MBEDTLS_PLATFORM_GMTIME_R_ALT)
+    if( strcmp( "MBEDTLS_PLATFORM_GMTIME_R_ALT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PLATFORM_GMTIME_R_ALT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PLATFORM_GMTIME_R_ALT */
+
+    /* If the symbol is not found, return an error */
+    return( 1 );
+}
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif /* _MSC_VER */
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index e2f8a8e..f7e2459 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -342,6 +342,10 @@
     "                        options: ssl3, tls1, tls1_1, tls1_2, dtls1, dtls1_2\n" \
     "\n"                                                    \
     "    force_ciphersuite=<name>    default: all enabled\n"\
+    "    query_config=<name>         return 0 if the specified\n"       \
+    "                                configuration macro is defined and 1\n"  \
+    "                                otherwise. The expansion of the macro\n" \
+    "                                is printed if it is defined\n"     \
     " acceptable ciphersuite names:\n"
 
 #define ALPN_LIST_SIZE  10
@@ -417,6 +421,8 @@
     int etm;                    /* negotiate encrypt then mac?              */
 } opt;
 
+int query_config( const char *config );
+
 static void my_debug( void *ctx, int level,
                       const char *file, int line,
                       const char *str )
@@ -472,6 +478,8 @@
 }
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
+static unsigned char peer_crt_info[1024];
+
 /*
  * Enabled if debug_level > 1 in code below
  */
@@ -481,8 +489,14 @@
     char buf[1024];
     ((void) data);
 
-    mbedtls_printf( "\nVerify requested for (Depth %d):\n", depth );
     mbedtls_x509_crt_info( buf, sizeof( buf ) - 1, "", crt );
+    if( depth == 0 )
+        memcpy( peer_crt_info, buf, sizeof( buf ) );
+
+    if( opt.debug_level == 0 )
+        return( 0 );
+
+    mbedtls_printf( "\nVerify requested for (Depth %d):\n", depth );
     mbedtls_printf( "%s", buf );
 
     if ( ( *flags ) == 0 )
@@ -1059,6 +1073,10 @@
             if( opt.dhmlen < 0 )
                 goto usage;
         }
+        else if( strcmp( p, "query_config" ) == 0 )
+        {
+            return query_config( q );
+        }
         else
             goto usage;
     }
@@ -1493,8 +1511,8 @@
         mbedtls_ssl_conf_sig_hashes( &conf, ssl_sig_hashes_for_test );
     }
 
-    if( opt.debug_level > 0 )
-        mbedtls_ssl_conf_verify( &conf, my_verify, NULL );
+    mbedtls_ssl_conf_verify( &conf, my_verify, NULL );
+    memset( peer_crt_info, 0, sizeof( peer_crt_info ) );
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
     if( opt.auth_mode != DFL_AUTH_MODE )
@@ -1823,13 +1841,8 @@
     else
         mbedtls_printf( " ok\n" );
 
-    if( mbedtls_ssl_get_peer_cert( &ssl ) != NULL )
-    {
-        mbedtls_printf( "  . Peer certificate information    ...\n" );
-        mbedtls_x509_crt_info( (char *) buf, sizeof( buf ) - 1, "      ",
-                       mbedtls_ssl_get_peer_cert( &ssl ) );
-        mbedtls_printf( "%s\n", buf );
-    }
+    mbedtls_printf( "  . Peer certificate information    ...\n" );
+    mbedtls_printf( "%s\n", peer_crt_info );
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
 #if defined(MBEDTLS_SSL_RENEGOTIATION)
@@ -2134,6 +2147,10 @@
         mbedtls_printf( "  . Restarting connection from same port..." );
         fflush( stdout );
 
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+        memset( peer_crt_info, 0, sizeof( peer_crt_info ) );
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
         if( ( ret = mbedtls_ssl_session_reset( &ssl ) ) != 0 )
         {
             mbedtls_printf( " failed\n  ! mbedtls_ssl_session_reset returned -0x%x\n\n",
@@ -2205,6 +2222,10 @@
 
         mbedtls_printf( "  . Reconnecting with saved session..." );
 
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+        memset( peer_crt_info, 0, sizeof( peer_crt_info ) );
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
         if( ( ret = mbedtls_ssl_session_reset( &ssl ) ) != 0 )
         {
             mbedtls_printf( " failed\n  ! mbedtls_ssl_session_reset returned -0x%x\n\n",
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 5bce958..7858db3 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -446,6 +446,10 @@
     "                                in order from ssl3 to tls1_2\n"    \
     "                                default: all enabled\n"            \
     "    force_ciphersuite=<name>    default: all enabled\n"            \
+    "    query_config=<name>         return 0 if the specified\n"       \
+    "                                configuration macro is defined and 1\n"  \
+    "                                otherwise. The expansion of the macro\n" \
+    "                                is printed if it is defined\n"     \
     " acceptable ciphersuite names:\n"
 
 
@@ -543,6 +547,8 @@
     int badmac_limit;           /* Limit of records with bad MAC            */
 } opt;
 
+int query_config( const char *config );
+
 static void my_debug( void *ctx, int level,
                       const char *file, int line,
                       const char *str )
@@ -1871,6 +1877,10 @@
         {
             opt.sni = q;
         }
+        else if( strcmp( p, "query_config" ) == 0 )
+        {
+            return query_config( q );
+        }
         else
             goto usage;
     }
diff --git a/programs/test/CMakeLists.txt b/programs/test/CMakeLists.txt
index 9ca0cb2..65ff249 100644
--- a/programs/test/CMakeLists.txt
+++ b/programs/test/CMakeLists.txt
@@ -30,6 +30,10 @@
 add_executable(zeroize zeroize.c)
 target_link_libraries(zeroize ${libs})
 
-install(TARGETS selftest benchmark ssl_cert_test udp_proxy
+add_executable(query_compile_time_config query_compile_time_config.c)
+target_sources(query_compile_time_config PUBLIC ../ssl/query_config.c)
+target_link_libraries(query_compile_time_config ${libs})
+
+install(TARGETS selftest benchmark ssl_cert_test udp_proxy query_compile_time_config
         DESTINATION "bin"
         PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
diff --git a/programs/test/query_compile_time_config.c b/programs/test/query_compile_time_config.c
new file mode 100644
index 0000000..17becf2
--- /dev/null
+++ b/programs/test/query_compile_time_config.c
@@ -0,0 +1,56 @@
+/*
+ *  Query the Mbed TLS compile time configuration
+ *
+ *  Copyright (C) 2018, Arm Limited, All Rights Reserved
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  This file is part of Mbed TLS (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#define mbedtls_printf       printf
+#define MBEDTLS_EXIT_FAILURE EXIT_FAILURE
+#endif
+
+#define USAGE                                                                \
+    "usage: %s <MBEDTLS_CONFIG>\n\n"                                         \
+    "This program takes one command line argument which corresponds to\n"    \
+    "the string representation of a Mbed TLS compile time configuration.\n"  \
+    "The value 0 will be returned if this configuration is defined in the\n" \
+    "Mbed TLS build and the macro expansion of that configuration will be\n" \
+    "printed (if any). Otherwise, 1 will be returned.\n"
+
+int query_config( const char *config );
+
+int main( int argc, char *argv[] )
+{
+    if ( argc != 2 )
+    {
+        mbedtls_printf( USAGE, argv[0] );
+        return( MBEDTLS_EXIT_FAILURE );
+    }
+
+    return( query_config( argv[1] ) );
+}
diff --git a/programs/x509/cert_app.c b/programs/x509/cert_app.c
index 626c4d1..38fbd51 100644
--- a/programs/x509/cert_app.c
+++ b/programs/x509/cert_app.c
@@ -467,9 +467,12 @@
         /*
          * 5. Print the certificate
          */
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+        mbedtls_printf( "  . Peer certificate information    ... skipped\n" );
+#else
         mbedtls_printf( "  . Peer certificate information    ...\n" );
         ret = mbedtls_x509_crt_info( (char *) buf, sizeof( buf ) - 1, "      ",
-                             ssl.session->peer_cert );
+                                     mbedtls_ssl_get_peer_cert( &ssl ) );
         if( ret == -1 )
         {
             mbedtls_printf( " failed\n  !  mbedtls_x509_crt_info returned %d\n\n", ret );
@@ -477,6 +480,7 @@
         }
 
         mbedtls_printf( "%s\n", buf );
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 
         mbedtls_ssl_close_notify( &ssl );
 
diff --git a/programs/x509/cert_req.c b/programs/x509/cert_req.c
index 027050c..d25ad4c 100644
--- a/programs/x509/cert_req.c
+++ b/programs/x509/cert_req.c
@@ -65,7 +65,9 @@
 #define DFL_OUTPUT_FILENAME     "cert.req"
 #define DFL_SUBJECT_NAME        "CN=Cert,O=mbed TLS,C=UK"
 #define DFL_KEY_USAGE           0
+#define DFL_FORCE_KEY_USAGE     0
 #define DFL_NS_CERT_TYPE        0
+#define DFL_FORCE_NS_CERT_TYPE  0
 #define DFL_MD_ALG              MBEDTLS_MD_SHA256
 
 #define USAGE \
@@ -85,6 +87,8 @@
     "                          key_agreement\n"         \
     "                          key_cert_sign\n"  \
     "                          crl_sign\n"              \
+    "    force_key_usage=0/1  default: off\n"           \
+    "                          Add KeyUsage even if it is empty\n"  \
     "    ns_cert_type=%%s     default: (empty)\n"       \
     "                        Comma-separated-list of values:\n"     \
     "                          ssl_client\n"            \
@@ -94,6 +98,8 @@
     "                          ssl_ca\n"                \
     "                          email_ca\n"              \
     "                          object_signing_ca\n"     \
+    "    force_ns_cert_type=0/1 default: off\n"         \
+    "                          Add NsCertType even if it is empty\n"    \
     "    md=%%s               default: SHA256\n"       \
     "                          possible values:\n"     \
     "                          MD4, MD5, SHA1\n"       \
@@ -123,7 +129,9 @@
     const char *output_file;    /* where to store the constructed key file  */
     const char *subject_name;   /* subject name for certificate request */
     unsigned char key_usage;    /* key usage flags                      */
+    int force_key_usage;        /* Force adding the KeyUsage extension  */
     unsigned char ns_cert_type; /* NS cert type                         */
+    int force_ns_cert_type;     /* Force adding NsCertType extension    */
     mbedtls_md_type_t md_alg;   /* Hash algorithm used for signature.   */
 } opt;
 
@@ -190,7 +198,9 @@
     opt.output_file         = DFL_OUTPUT_FILENAME;
     opt.subject_name        = DFL_SUBJECT_NAME;
     opt.key_usage           = DFL_KEY_USAGE;
+    opt.force_key_usage     = DFL_FORCE_KEY_USAGE;
     opt.ns_cert_type        = DFL_NS_CERT_TYPE;
+    opt.force_ns_cert_type  = DFL_FORCE_NS_CERT_TYPE;
     opt.md_alg              = DFL_MD_ALG;
 
     for( i = 1; i < argc; i++ )
@@ -292,6 +302,15 @@
                 q = r;
             }
         }
+        else if( strcmp( p, "force_key_usage" ) == 0 )
+        {
+            switch( atoi( q ) )
+            {
+                case 0: opt.force_key_usage = 0; break;
+                case 1: opt.force_key_usage = 1; break;
+                default: goto usage;
+            }
+        }
         else if( strcmp( p, "ns_cert_type" ) == 0 )
         {
             while( q != NULL )
@@ -319,16 +338,25 @@
                 q = r;
             }
         }
+        else if( strcmp( p, "force_ns_cert_type" ) == 0 )
+        {
+            switch( atoi( q ) )
+            {
+                case 0: opt.force_ns_cert_type = 0; break;
+                case 1: opt.force_ns_cert_type = 1; break;
+                default: goto usage;
+            }
+        }
         else
             goto usage;
     }
 
     mbedtls_x509write_csr_set_md_alg( &req, opt.md_alg );
 
-    if( opt.key_usage )
+    if( opt.key_usage || opt.force_key_usage == 1 )
         mbedtls_x509write_csr_set_key_usage( &req, opt.key_usage );
 
-    if( opt.ns_cert_type )
+    if( opt.ns_cert_type || opt.force_ns_cert_type == 1 )
         mbedtls_x509write_csr_set_ns_cert_type( &req, opt.ns_cert_type );
 
     /*
diff --git a/scripts/bump_version.sh b/scripts/bump_version.sh
index fc8b800..c39a86a 100755
--- a/scripts/bump_version.sh
+++ b/scripts/bump_version.sh
@@ -132,6 +132,9 @@
 [ $VERBOSE ] && echo "Re-generating library/error.c"
 scripts/generate_errors.pl
 
+[ $VERBOSE ] && echo "Re-generating programs/ssl/query_config.c"
+scripts/generate_query_config.pl
+
 [ $VERBOSE ] && echo "Re-generating library/version_features.c"
 scripts/generate_features.pl
 
diff --git a/scripts/config.pl b/scripts/config.pl
index 18e1dc8..6300362 100755
--- a/scripts/config.pl
+++ b/scripts/config.pl
@@ -30,6 +30,7 @@
 #   MBEDTLS_NO_PLATFORM_ENTROPY
 #   MBEDTLS_PSA_CRYPTO_C
 #   MBEDTLS_REMOVE_ARC4_CIPHERSUITES
+#   MBEDTLS_REMOVE_3DES_CIPHERSUITES
 #   MBEDTLS_SSL_HW_RECORD_ACCEL
 #   MBEDTLS_RSA_NO_CRT
 #   MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3
@@ -40,10 +41,9 @@
 #   MBEDTLS_USE_PSA_CRYPTO
 #       - experimental, and more an alternative implementation than a feature
 #   MBEDTLS_PSA_CRYPTO_STORAGE_C
-#   MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C
-#   MBEDTLS_PSA_CRYPTO_STORAGE_ITS_C
+#   MBEDTLS_PSA_ITS_FILE_C
 #   MBEDTLS_PSA_CRYPTO_SPM
-#   MBEDTLS_PSA_HAS_ITS_IO
+#   MBEDTLS_PSA_INJECT_ENTROPY
 #   and any symbol beginning _ALT
 #
 
@@ -98,6 +98,7 @@
 MBEDTLS_PSA_CRYPTO_C
 MBEDTLS_RSA_NO_CRT
 MBEDTLS_REMOVE_ARC4_CIPHERSUITES
+MBEDTLS_REMOVE_3DES_CIPHERSUITES
 MBEDTLS_SSL_HW_RECORD_ACCEL
 MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3
 MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
@@ -107,10 +108,9 @@
 MBEDTLS_NO_64BIT_MULTIPLICATION
 MBEDTLS_USE_PSA_CRYPTO
 MBEDTLS_PSA_CRYPTO_STORAGE_C
-MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C
-MBEDTLS_PSA_CRYPTO_STORAGE_ITS_C
+MBEDTLS_PSA_ITS_FILE_C
 MBEDTLS_PSA_CRYPTO_SPM
-MBEDTLS_PSA_HAS_ITS_IO
+MBEDTLS_PSA_INJECT_ENTROPY
 _ALT\s*$
 );
 
diff --git a/scripts/data_files/query_config.fmt b/scripts/data_files/query_config.fmt
new file mode 100644
index 0000000..064da4c
--- /dev/null
+++ b/scripts/data_files/query_config.fmt
@@ -0,0 +1,139 @@
+/*
+ *  Query Mbed TLS compile time configurations from config.h
+ *
+ *  Copyright (C) 2018, Arm Limited, All Rights Reserved
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  This file is part of Mbed TLS (https://tls.mbed.org)
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#if defined(MBEDTLS_PLATFORM_C)
+#include "mbedtls/platform.h"
+#else
+#include <stdio.h>
+#define mbedtls_printf printf
+#endif /* MBEDTLS_PLATFORM_C */
+
+/*
+ * Include all the headers with public APIs in case they define a macro to its
+ * default value when that configuration is not set in the config.h.
+ */
+#include "mbedtls/aes.h"
+#include "mbedtls/aesni.h"
+#include "mbedtls/arc4.h"
+#include "mbedtls/aria.h"
+#include "mbedtls/asn1.h"
+#include "mbedtls/asn1write.h"
+#include "mbedtls/base64.h"
+#include "mbedtls/bignum.h"
+#include "mbedtls/blowfish.h"
+#include "mbedtls/camellia.h"
+#include "mbedtls/ccm.h"
+#include "mbedtls/certs.h"
+#include "mbedtls/chacha20.h"
+#include "mbedtls/chachapoly.h"
+#include "mbedtls/cipher.h"
+#include "mbedtls/cmac.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/debug.h"
+#include "mbedtls/des.h"
+#include "mbedtls/dhm.h"
+#include "mbedtls/ecdh.h"
+#include "mbedtls/ecdsa.h"
+#include "mbedtls/ecjpake.h"
+#include "mbedtls/ecp.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/entropy_poll.h"
+#include "mbedtls/error.h"
+#include "mbedtls/gcm.h"
+#include "mbedtls/havege.h"
+#include "mbedtls/hkdf.h"
+#include "mbedtls/hmac_drbg.h"
+#include "mbedtls/md.h"
+#include "mbedtls/md2.h"
+#include "mbedtls/md4.h"
+#include "mbedtls/md5.h"
+#include "mbedtls/memory_buffer_alloc.h"
+#include "mbedtls/net_sockets.h"
+#include "mbedtls/nist_kw.h"
+#include "mbedtls/oid.h"
+#include "mbedtls/padlock.h"
+#include "mbedtls/pem.h"
+#include "mbedtls/pk.h"
+#include "mbedtls/pkcs11.h"
+#include "mbedtls/pkcs12.h"
+#include "mbedtls/pkcs5.h"
+#include "mbedtls/platform_time.h"
+#include "mbedtls/platform_util.h"
+#include "mbedtls/poly1305.h"
+#include "mbedtls/ripemd160.h"
+#include "mbedtls/rsa.h"
+#include "mbedtls/sha1.h"
+#include "mbedtls/sha256.h"
+#include "mbedtls/sha512.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/ssl_cache.h"
+#include "mbedtls/ssl_ciphersuites.h"
+#include "mbedtls/ssl_cookie.h"
+#include "mbedtls/ssl_internal.h"
+#include "mbedtls/ssl_ticket.h"
+#include "mbedtls/threading.h"
+#include "mbedtls/timing.h"
+#include "mbedtls/version.h"
+#include "mbedtls/x509.h"
+#include "mbedtls/x509_crl.h"
+#include "mbedtls/x509_crt.h"
+#include "mbedtls/x509_csr.h"
+#include "mbedtls/xtea.h"
+
+#include <string.h>
+
+/*
+ * Helper macros to convert a macro or its expansion into a string
+ * WARNING: This does not work for expanding function-like macros. However,
+ * Mbed TLS does not currently have configuration options used in this fashion.
+ */
+#define MACRO_EXPANSION_TO_STR(macro)   MACRO_NAME_TO_STR(macro)
+#define MACRO_NAME_TO_STR(macro)                                        \
+    mbedtls_printf( "%s", strlen( #macro "" ) > 0 ? #macro "\n" : "" )
+
+#if defined(_MSC_VER)
+/*
+ * Visual Studio throws the warning 4003 because many Mbed TLS feature macros
+ * are defined empty. This means that from the preprocessor's point of view
+ * the macro MBEDTLS_EXPANSION_TO_STR is being invoked without arguments as
+ * some macros expand to nothing. We suppress that specific warning to get a
+ * clean build and to ensure that tests treating warnings as errors do not
+ * fail.
+ */
+#pragma warning(push)
+#pragma warning(disable:4003)
+#endif /* _MSC_VER */
+
+int query_config( const char *config )
+{
+CHECK_CONFIG    /* If the symbol is not found, return an error */
+    return( 1 );
+}
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif /* _MSC_VER */
diff --git a/scripts/data_files/vs2010-app-template.vcxproj b/scripts/data_files/vs2010-app-template.vcxproj
index de18f9d8..fac9812 100644
--- a/scripts/data_files/vs2010-app-template.vcxproj
+++ b/scripts/data_files/vs2010-app-template.vcxproj
Binary files differ
diff --git a/scripts/generate_query_config.pl b/scripts/generate_query_config.pl
new file mode 100755
index 0000000..f15e03a
--- /dev/null
+++ b/scripts/generate_query_config.pl
@@ -0,0 +1,75 @@
+#! /usr/bin/env perl
+
+# Generate query_config.c
+#
+# The file query_config.c contains a C function that can be used to check if
+# a configuration macro is defined and to retrieve its expansion in string
+# form (if any). This facilitates querying the compile time configuration of
+# the library, for example, for testing.
+#
+# The query_config.c is generated from the current configuration at
+# include/mbedtls/config.h. The idea is that the config.h contains ALL the
+# compile time configurations available in Mbed TLS (commented or uncommented).
+# This script extracts the configuration macros from the config.h and this
+# information is used to automatically generate the body of the query_config()
+# function by using the template in scripts/data_files/query_config.fmt.
+#
+# Usage: ./scripts/generate_query_config.pl without arguments
+
+use strict;
+
+my $config_file = "./include/mbedtls/config.h";
+
+my $query_config_format_file = "./scripts/data_files/query_config.fmt";
+my $query_config_file = "./programs/ssl/query_config.c";
+
+# Excluded macros from the generated query_config.c. For example, macros that
+# have commas or function-like macros cannot be transformed into strings easily
+# using the preprocessor, so they should be excluded or the preprocessor will
+# throw errors.
+my @excluded = qw(
+MBEDTLS_SSL_CIPHERSUITES
+MBEDTLS_PARAM_FAILED
+);
+my $excluded_re = join '|', @excluded;
+
+open(CONFIG_FILE, "$config_file") or die "Opening config file '$config_file': $!";
+
+# This variable will contain the string to replace in the CHECK_CONFIG of the
+# format file
+my $config_check = "";
+
+while (my $line = <CONFIG_FILE>) {
+    if ($line =~ /^(\/\/)?\s*#\s*define\s+(MBEDTLS_\w+).*/) {
+        my $name = $2;
+
+        # Skip over the macro that prevents multiple inclusion
+        next if "MBEDTLS_CONFIG_H" eq $name;
+
+        # Skip over the macro if it is in the ecluded list
+        next if $name =~ /$excluded_re/;
+
+        $config_check .= "#if defined($name)\n";
+        $config_check .= "    if( strcmp( \"$name\", config ) == 0 )\n";
+        $config_check .= "    {\n";
+        $config_check .= "        MACRO_EXPANSION_TO_STR( $name );\n";
+        $config_check .= "        return( 0 );\n";
+        $config_check .= "    }\n";
+        $config_check .= "#endif /* $name */\n";
+        $config_check .= "\n";
+    }
+}
+
+# Read the full format file into a string
+local $/;
+open(FORMAT_FILE, "$query_config_format_file") or die "Opening query config format file '$query_config_format_file': $!";
+my $query_config_format = <FORMAT_FILE>;
+close(FORMAT_FILE);
+
+# Replace the body of the query_config() function with the code we just wrote
+$query_config_format =~ s/CHECK_CONFIG/$config_check/g;
+
+# Rewrite the query_config.c file
+open(QUERY_CONFIG_FILE, ">$query_config_file") or die "Opening destination file '$query_config_file': $!";
+print QUERY_CONFIG_FILE $query_config_format;
+close(QUERY_CONFIG_FILE);
diff --git a/scripts/generate_visualc_files.pl b/scripts/generate_visualc_files.pl
index 811c71f..9913976 100755
--- a/scripts/generate_visualc_files.pl
+++ b/scripts/generate_visualc_files.pl
@@ -93,8 +93,14 @@
     $path =~ s!/!\\!g;
     (my $appname = $path) =~ s/.*\\//;
 
+    my $srcs = "\n    <ClCompile Include=\"..\\..\\programs\\$path.c\" \/>\r";
+    if( $appname eq "ssl_client2" or $appname eq "ssl_server2" or
+        $appname eq "query_compile_time_config" ) {
+        $srcs .= "\n    <ClCompile Include=\"..\\..\\programs\\ssl\\query_config.c\" \/>\r";
+    }
+
     my $content = $template;
-    $content =~ s/<PATHNAME>/$path/g;
+    $content =~ s/<SOURCES>/$srcs/g;
     $content =~ s/<APPNAME>/$appname/g;
     $content =~ s/<GUID>/$guid/g;
 
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index eae1f57..06b8997 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -20,6 +20,13 @@
 # on non-POSIX platforms.
 add_definitions("-D_POSIX_C_SOURCE=200809L")
 
+# Test suites caught by SKIP_TEST_SUITES are built but not executed.
+# "foo" as a skip pattern skips "test_suite_foo" and "test_suite_foo.bar"
+# but not "test_suite_foobar".
+string(REGEX REPLACE "[ ,;]" "|" SKIP_TEST_SUITES_REGEX "${SKIP_TEST_SUITES}")
+string(REPLACE "." "\\." SKIP_TEST_SUITES_REGEX "${SKIP_TEST_SUITES_REGEX}")
+set(SKIP_TEST_SUITES_REGEX "^(${SKIP_TEST_SUITES_REGEX})(\$|\\.)")
+
 function(add_test_suite suite_name)
     if(ARGV1)
         set(data_name ${ARGV1})
@@ -36,7 +43,11 @@
     include_directories(${CMAKE_CURRENT_SOURCE_DIR})
     add_executable(test_suite_${data_name} test_suite_${data_name}.c)
     target_link_libraries(test_suite_${data_name} ${libs})
-    add_test(${data_name}-suite test_suite_${data_name} --verbose)
+    if(${data_name} MATCHES ${SKIP_TEST_SUITES_REGEX})
+        message(STATUS "The test suite ${data_name} will not be executed.")
+    else()
+        add_test(${data_name}-suite test_suite_${data_name} --verbose)
+    endif()
 endfunction(add_test_suite)
 
 if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG)
@@ -49,75 +60,80 @@
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX-")
 endif(MSVC)
 
-add_test_suite(aes aes.ecb)
-add_test_suite(aes aes.cbc)
-add_test_suite(aes aes.cfb)
-add_test_suite(aes aes.rest)
-add_test_suite(aes aes.xts)
-add_test_suite(arc4)
-add_test_suite(aria)
-add_test_suite(asn1write)
-add_test_suite(base64)
-add_test_suite(blowfish)
-add_test_suite(camellia)
-add_test_suite(ccm)
-add_test_suite(chacha20)
-add_test_suite(chachapoly)
-add_test_suite(cipher cipher.aes)
-add_test_suite(cipher cipher.arc4)
-add_test_suite(cipher cipher.blowfish)
-add_test_suite(cipher cipher.camellia)
-add_test_suite(cipher cipher.ccm)
-add_test_suite(cipher cipher.chacha20)
-add_test_suite(cipher cipher.chachapoly)
-add_test_suite(cipher cipher.des)
-add_test_suite(cipher cipher.gcm)
-add_test_suite(cipher cipher.misc)
-add_test_suite(cipher cipher.null)
-add_test_suite(cipher cipher.padding)
-add_test_suite(cmac)
-add_test_suite(ctr_drbg)
+if(NOT USE_CRYPTO_SUBMODULE)
+    add_test_suite(aes aes.ecb)
+    add_test_suite(aes aes.cbc)
+    add_test_suite(aes aes.cfb)
+    add_test_suite(aes aes.ofb)
+    add_test_suite(aes aes.rest)
+    add_test_suite(aes aes.xts)
+    add_test_suite(arc4)
+    add_test_suite(aria)
+    add_test_suite(asn1write)
+    add_test_suite(base64)
+    add_test_suite(blowfish)
+    add_test_suite(camellia)
+    add_test_suite(ccm)
+    add_test_suite(chacha20)
+    add_test_suite(chachapoly)
+    add_test_suite(cipher cipher.aes)
+    add_test_suite(cipher cipher.arc4)
+    add_test_suite(cipher cipher.blowfish)
+    add_test_suite(cipher cipher.camellia)
+    add_test_suite(cipher cipher.ccm)
+    add_test_suite(cipher cipher.chacha20)
+    add_test_suite(cipher cipher.chachapoly)
+    add_test_suite(cipher cipher.des)
+    add_test_suite(cipher cipher.gcm)
+    add_test_suite(cipher cipher.misc)
+    add_test_suite(cipher cipher.null)
+    add_test_suite(cipher cipher.padding)
+    add_test_suite(cipher cipher.nist_kw)
+    add_test_suite(cmac)
+    add_test_suite(ctr_drbg)
+    add_test_suite(des)
+    add_test_suite(dhm)
+    add_test_suite(ecdh)
+    add_test_suite(ecdsa)
+    add_test_suite(ecjpake)
+    add_test_suite(ecp)
+    add_test_suite(entropy)
+    add_test_suite(error)
+    add_test_suite(gcm gcm.aes128_en)
+    add_test_suite(gcm gcm.aes192_en)
+    add_test_suite(gcm gcm.aes256_en)
+    add_test_suite(gcm gcm.aes128_de)
+    add_test_suite(gcm gcm.aes192_de)
+    add_test_suite(gcm gcm.aes256_de)
+    add_test_suite(gcm gcm.camellia)
+    add_test_suite(gcm gcm.misc)
+    add_test_suite(hkdf)
+    add_test_suite(hmac_drbg hmac_drbg.misc)
+    add_test_suite(hmac_drbg hmac_drbg.no_reseed)
+    add_test_suite(hmac_drbg hmac_drbg.nopr)
+    add_test_suite(hmac_drbg hmac_drbg.pr)
+    add_test_suite(md)
+    add_test_suite(mdx)
+    add_test_suite(memory_buffer_alloc)
+    add_test_suite(mpi)
+    add_test_suite(nist_kw)
+    add_test_suite(oid)
+    add_test_suite(pem)
+    add_test_suite(pkcs1_v15)
+    add_test_suite(pkcs1_v21)
+    add_test_suite(pkcs5)
+    add_test_suite(pk)
+    add_test_suite(pkparse)
+    add_test_suite(pkwrite)
+    add_test_suite(poly1305)
+    add_test_suite(shax)
+    add_test_suite(timing)
+    add_test_suite(rsa)
+    add_test_suite(xtea)
+endif()
 add_test_suite(debug)
-add_test_suite(des)
-add_test_suite(dhm)
-add_test_suite(ecdh)
-add_test_suite(ecdsa)
-add_test_suite(ecjpake)
-add_test_suite(ecp)
-add_test_suite(entropy)
-add_test_suite(error)
-add_test_suite(gcm gcm.aes128_en)
-add_test_suite(gcm gcm.aes192_en)
-add_test_suite(gcm gcm.aes256_en)
-add_test_suite(gcm gcm.aes128_de)
-add_test_suite(gcm gcm.aes192_de)
-add_test_suite(gcm gcm.aes256_de)
-add_test_suite(gcm gcm.camellia)
-add_test_suite(gcm gcm.misc)
-add_test_suite(hkdf)
-add_test_suite(hmac_drbg hmac_drbg.misc)
-add_test_suite(hmac_drbg hmac_drbg.no_reseed)
-add_test_suite(hmac_drbg hmac_drbg.nopr)
-add_test_suite(hmac_drbg hmac_drbg.pr)
-add_test_suite(md)
-add_test_suite(mdx)
-add_test_suite(memory_buffer_alloc)
-add_test_suite(mpi)
-add_test_suite(nist_kw)
-add_test_suite(pem)
-add_test_suite(pkcs1_v15)
-add_test_suite(pkcs1_v21)
-add_test_suite(pkcs5)
-add_test_suite(pk)
-add_test_suite(pkparse)
-add_test_suite(pkwrite)
-add_test_suite(poly1305)
-add_test_suite(shax)
 add_test_suite(ssl)
-add_test_suite(timing)
-add_test_suite(rsa)
 add_test_suite(version)
-add_test_suite(xtea)
 add_test_suite(x509parse)
 add_test_suite(x509write)
 
diff --git a/tests/Makefile b/tests/Makefile
index 78670c3..f5cc409 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -66,6 +66,53 @@
 # constructed by stripping path 'suites/' and extension .data.
 APPS = $(basename $(subst suites/,,$(wildcard suites/test_suite_*.data)))
 
+ifdef USE_CRYPTO_SUBMODULE
+APPS := $(filter-out \
+		test_suite_aes.% \
+		test_suite_arc4 \
+		test_suite_aria \
+		test_suite_asn1write \
+		test_suite_base64 \
+		test_suite_blowfish \
+		test_suite_camellia \
+		test_suite_ccm \
+		test_suite_chacha20 \
+		test_suite_chachapoly \
+		test_suite_cipher.% \
+		test_suite_cmac \
+		test_suite_ctr_drbg \
+		test_suite_des \
+		test_suite_dhm \
+		test_suite_ecdh \
+		test_suite_ecdsa \
+		test_suite_ecjpake \
+		test_suite_ecp \
+		test_suite_entropy \
+		test_suite_error \
+		test_suite_gcm.% \
+		test_suite_hkdf \
+		test_suite_hmac_drbg.% \
+		test_suite_md \
+		test_suite_mdx \
+		test_suite_memory_buffer_alloc \
+		test_suite_mpi \
+		test_suite_nist_kw \
+		test_suite_oid \
+		test_suite_pem \
+		test_suite_pk \
+		test_suite_pkcs1_v15 \
+		test_suite_pkcs1_v21 \
+		test_suite_pkcs5 \
+		test_suite_pkparse \
+		test_suite_pkwrite \
+		test_suite_poly1305 \
+		test_suite_rsa \
+		test_suite_shax \
+		test_suite_timing \
+		test_suite_xtea \
+		,$(APPS))
+endif
+
 # Construct executable name by adding OS specific suffix $(EXEXT).
 BINARIES := $(addsuffix $(EXEXT),$(APPS))
 
@@ -121,8 +168,9 @@
 endif
 endif
 
+# Test suites caught by SKIP_TEST_SUITES are built but not executed.
 check: $(BINARIES)
-	perl scripts/run-test-suites.pl
+	perl scripts/run-test-suites.pl --skip=$(SKIP_TEST_SUITES)
 
 test: check
 
diff --git a/tests/compat.sh b/tests/compat.sh
index 1814528..0eae1ea 100755
--- a/tests/compat.sh
+++ b/tests/compat.sh
@@ -62,7 +62,8 @@
 #   avoid plain DES but keep 3DES-EDE-CBC (mbedTLS), DES-CBC3 (OpenSSL)
 # - ARIA: not in default config.h + requires OpenSSL >= 1.1.1
 # - ChachaPoly: requires OpenSSL >= 1.1.0
-EXCLUDE='NULL\|DES-CBC-\|RC4\|ARCFOUR\|ARIA\|CHACHA20-POLY1305'
+# - 3DES: not in default config
+EXCLUDE='NULL\|DES\|RC4\|ARCFOUR\|ARIA\|CHACHA20-POLY1305'
 VERBOSE=""
 MEMCHECK=0
 PEERS="OpenSSL$PEER_GNUTLS mbedTLS"
diff --git a/tests/data_files/Makefile b/tests/data_files/Makefile
index 2ed32e6..aa9fc36 100644
--- a/tests/data_files/Makefile
+++ b/tests/data_files/Makefile
@@ -45,7 +45,9 @@
 
 test-ca.crt: $(test_ca_key_file_rsa) test-ca.req.sha256
 	$(MBEDTLS_CERT_WRITE) is_ca=1 serial=3 request_file=test-ca.req.sha256 selfsign=1 issuer_name="C=NL,O=PolarSSL,CN=PolarSSL Test CA" issuer_key=$(test_ca_key_file_rsa) issuer_pwd=$(test_ca_pwd_rsa) not_before=20110212144400 not_after=20210212144400 md=SHA1 version=3 output_file=$@
-all_final += test-ca.crt
+test-ca.der: test-ca.crt
+	$(OPENSSL) x509 -inform PEM -in $< -outform DER -out $@
+all_final += test-ca.crt test-ca.der
 
 test-ca-sha1.crt: $(test_ca_key_file_rsa) test-ca.req.sha256
 	$(MBEDTLS_CERT_WRITE) is_ca=1 serial=3 request_file=test-ca.req.sha256 selfsign=1 issuer_name="C=NL,O=PolarSSL,CN=PolarSSL Test CA" issuer_key=$(test_ca_key_file_rsa) issuer_pwd=$(test_ca_pwd_rsa) not_before=20110212144400 not_after=20210212144400 md=SHA1 version=3 output_file=$@
@@ -783,6 +785,14 @@
 	$(MBEDTLS_CERT_REQ) output_file=$@ filename=$< key_usage=digital_signature,non_repudiation,key_encipherment ns_cert_type=ssl_server subject_name="C=NL,O=PolarSSL,CN=PolarSSL Server 1" md=SHA1
 all_final += server1.req.ku-ct
 
+server1.req.key_usage_empty: server1.key
+	$(MBEDTLS_CERT_REQ) output_file=$@ filename=$< subject_name="C=NL,O=PolarSSL,CN=PolarSSL Server 1" md=SHA1 force_key_usage=1
+all_final += server1.req.key_usage_empty
+
+server1.req.cert_type_empty: server1.key
+	$(MBEDTLS_CERT_REQ) output_file=$@ filename=$< subject_name="C=NL,O=PolarSSL,CN=PolarSSL Server 1" md=SHA1 force_ns_cert_type=1
+all_final += server1.req.cert_type_empty
+
 # server2*
 
 server2.req.sha256: server2.key
@@ -873,7 +883,9 @@
 
 server2.crt: server2.req.sha256
 	$(MBEDTLS_CERT_WRITE) request_file=server2.req.sha256 serial=2 issuer_crt=$(test_ca_crt) issuer_key=$(test_ca_key_file_rsa) issuer_pwd=$(test_ca_pwd_rsa) not_before=20110212144406 not_after=20210212144406 md=SHA1 version=3 output_file=$@
-all_final += server2.crt
+server2.der: server2.crt
+	$(OPENSSL) x509 -inform PEM -in $< -outform DER -out $@
+all_final += server2.crt server2.der
 
 server2-sha256.crt: server2.req.sha256
 	$(MBEDTLS_CERT_WRITE) request_file=server2.req.sha256 serial=2 issuer_crt=$(test_ca_crt) issuer_key=$(test_ca_key_file_rsa) issuer_pwd=$(test_ca_pwd_rsa) not_before=20110212144406 not_after=20210212144406 md=SHA256 version=3 output_file=$@
diff --git a/tests/data_files/server1.cert_type.crt b/tests/data_files/server1.cert_type.crt
index cf384cb..fb59ab8 100644
--- a/tests/data_files/server1.cert_type.crt
+++ b/tests/data_files/server1.cert_type.crt
@@ -11,10 +11,10 @@
 bp7OvViJ4lNZnm5akmXiiD8MlBmj3eXonZUT7Snbq3AS3FrKaxerUoJUsQIDAQAB
 o2AwXjAJBgNVHRMEAjAAMB0GA1UdDgQWBBQfdNY/KcF0dEU7BRIsPai9Q1kCpjAf
 BgNVHSMEGDAWgBS0WuSls97SUva51aaVD+s+vMf9/zARBglghkgBhvhCAQEEBAMC
-AEAwDQYJKoZIhvcNAQEFBQADggEBAEQOk5Ejgu/GsxvMo+RknXcta5Qr6MiNo1EM
-G5Xrf++aaf4Mi38p5ZxWDxQDyBmutSnuJgzO+Dxe5w/RNojFa4ri4g5Zk8zwfIcQ
-8jR6a9DJtxarxDj/UqEzaiBa5MpxsbQqbmou7X7YW9LHDzmCgzbaabyWCuGYxvmh
-lDbcISST73G+vJEeExcBHyom/GV9TNcFAGa66YV/FtABg2tiy9znmUeMnZeYkC9S
-05m6UstAU6pMdwiTpjZjovsTlAcmC76XmE/GpREhRvtGCKTb2pUi3agqsrapABmF
-EGZT9cpwkrl3cxh+jxAMEuhJLdEScDWHVsiNS5y9yxitWC4NqR4=
+BkAwDQYJKoZIhvcNAQEFBQADggEBAK1WXZYd6k7/zE2NcszT6rxNaSixPZrDYzRt
+Iz5rpH33IHkCdR956/ExCcDMqGNVtKtBdr8kw3+jzyPQhwyHVPNv4C/cgt0C89Pf
+qZLQGuEPVp1X4tzEY2Kno9c1tllLVzJdvz1mRhSb9z5CWQKNMT+8MMl3k+0NZ4LT
+NEx4gTZxYEsAGEuO/Yij9ctxp4RdSP585FXgiMC00ieMe/aJxlOIgpIhuWdu0KPP
+G5guYd4hQ9ZrGVOGdjv2cZbh4DuQOsCwU9in/e1RKFV6eMmyOdvLJ4jkTauwkGJG
+lCclZZQwzGawOiMl2OYPUia5bkaEsdE/0QW/lf36lco8CNjpUfY=
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server1.cert_type_noauthid.crt b/tests/data_files/server1.cert_type_noauthid.crt
index 7545e0b..0082b14 100644
--- a/tests/data_files/server1.cert_type_noauthid.crt
+++ b/tests/data_files/server1.cert_type_noauthid.crt
@@ -10,11 +10,11 @@
 lZvc/kFeF6babFtpzAK6FCwWJJxK3M3Q91Jnc/EtoCP9fvQxyi1wyokLBNsupk9w
 bp7OvViJ4lNZnm5akmXiiD8MlBmj3eXonZUT7Snbq3AS3FrKaxerUoJUsQIDAQAB
 oz8wPTAJBgNVHRMEAjAAMB0GA1UdDgQWBBQfdNY/KcF0dEU7BRIsPai9Q1kCpjAR
-BglghkgBhvhCAQEEBAMCAEAwDQYJKoZIhvcNAQEFBQADggEBAJc3yZUS9X3/lb63
-Nlt8rtXC45wbWZUoOK8N55IzEJC7FrttAStq24kq9QV0qiox8m1WLA+6xVaeZaXu
-h2z3WlUlyCNaKqHEpuSYu/XQ0td6j3jCMj3VDSZGHnKgliQ9fkkt+waPVCAZldwj
-rHsZibl2Dqzb3KttKqD1VyEVOUJ+saXRDJLFdK1M9nwdWMfOg/XE0WbqfVzw9COs
-08dJ6KL7SOvXtiOVQLNv7XN/2j+wF6+IoLDdLCDByj5VtK2q2vyVk5tpDJI1S696
-dP8Zi7VbBTS9OlVC+Gw3CntDKZA8e215MNG6iBuEM2mgi4i0umo7mN8FoA1zusnE
-8mCO55Q=
+BglghkgBhvhCAQEEBAMCBkAwDQYJKoZIhvcNAQEFBQADggEBAGl6bYCGKvDCvfSU
+PTyaiFPNGXV98AnIG0Hu4EJjs1owBU/Yf8UdFbWJtOymR80SbzmeQ6rEIoY1oXDA
+o9Y8yRgW8t25Wmq/0DCu/5P0/L6asstLTxLG4qajClVwqDLEqZNixmq8QorAOtK1
+JngFA+A5jzc70Ikl9+Hbx/2SEMrCpo0QLSco7KDK7XpNOHbkRz2AqSm0se4jDMP1
+Cwd2UtcpctIZEbECZo6S9WrVMqIhRF1Y5FeauBA2ORvGIHohaYJ9VzYWYXIp7N8d
+QXGv+M7ffpZiERcRr8lxtboPnTXKlv1mLCEX7g+KuiJQUm4OGfTCd5VHzWM7O5Id
+b+IvZD0=
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server1.der b/tests/data_files/server1.der
new file mode 100644
index 0000000..fcf45cd
--- /dev/null
+++ b/tests/data_files/server1.der
Binary files differ
diff --git a/tests/data_files/server1.key_usage.crt b/tests/data_files/server1.key_usage.crt
index 3a678ff..b5a2532 100644
--- a/tests/data_files/server1.key_usage.crt
+++ b/tests/data_files/server1.key_usage.crt
@@ -10,11 +10,11 @@
 lZvc/kFeF6babFtpzAK6FCwWJJxK3M3Q91Jnc/EtoCP9fvQxyi1wyokLBNsupk9w
 bp7OvViJ4lNZnm5akmXiiD8MlBmj3eXonZUT7Snbq3AS3FrKaxerUoJUsQIDAQAB
 o10wWzAJBgNVHRMEAjAAMB0GA1UdDgQWBBQfdNY/KcF0dEU7BRIsPai9Q1kCpjAf
-BgNVHSMEGDAWgBS0WuSls97SUva51aaVD+s+vMf9/zAOBgNVHQ8BAf8EBAMCAeAw
-DQYJKoZIhvcNAQEFBQADggEBAE4sz3ghfpolZ0rH6Q3CWIYQ1Q+aGBwQiCCBsApP
-8qZd880Kt+BiEdSsaU16S8CIMdOcHGQGB7dXK9wdTWkIqaW9I7fRPgDNDIhJoYDD
-67h1P+cEQeXT9900H173nYlM1vL9zLcnmmqEO7j8jXSpsR5mcCMPkR52RqxweLJw
-LGPeSlA+DF0WbezJc28FUgXAl8Kxm3Od40exMeicHtfgCnIykH1NEW3gXpc91nFT
-RoNRdEAIGHMX5Dd5QDlt2vlaKNXFtcx2xUXXIi71YNQybH3p6KXayPMFQzrBwoXJ
-YHevmjUaw7UH31fULa1dtd/dWmp8cCaKB4vBr0DBJPiMJMw=
+BgNVHSMEGDAWgBS0WuSls97SUva51aaVD+s+vMf9/zAOBgNVHQ8BAf8EBAMCBeAw
+DQYJKoZIhvcNAQEFBQADggEBAE6xegEHvwuQ8I4YCLX7oXmDJiDb7m2nMin+um0v
+TMqHAE3B9GvdWGUgMIEMf76ee7OMDzxfzM2vyNGemB0rn1djEv+knJBSdMQKD9X8
+tkT8cPqMHlRMYYbFFkkZEOeqeihZXQdUORao9ZSXrokYwv+Fr+PAmiUJEmkZHbA1
+Gqp6tPfGxJ2ah50Og9oAPwyND6kvE2o++Dth2evjljPCPM2Gw5kjQGw3V9CAUyUo
+KtLrtZdOeRHRCWCf3UQ/tYkG70tY/+grftrHqKB2E4qkmDiCPS9sEpa7jOGT6e4k
+jGVeZFNZZ10mD2Svr3xl/60++c7yLxrquujo8NOTCVcshfs=
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server1.key_usage_noauthid.crt b/tests/data_files/server1.key_usage_noauthid.crt
index 4a72ac1..c82a979 100644
--- a/tests/data_files/server1.key_usage_noauthid.crt
+++ b/tests/data_files/server1.key_usage_noauthid.crt
@@ -10,11 +10,11 @@
 lZvc/kFeF6babFtpzAK6FCwWJJxK3M3Q91Jnc/EtoCP9fvQxyi1wyokLBNsupk9w
 bp7OvViJ4lNZnm5akmXiiD8MlBmj3eXonZUT7Snbq3AS3FrKaxerUoJUsQIDAQAB
 ozwwOjAJBgNVHRMEAjAAMB0GA1UdDgQWBBQfdNY/KcF0dEU7BRIsPai9Q1kCpjAO
-BgNVHQ8BAf8EBAMCAeAwDQYJKoZIhvcNAQEFBQADggEBALqfFzzWOViKBXoFhtcc
-Ulzg1ShK20z3zeD6TL5Ss2+kMIGhvvvUMtcATIFa9LxZ//a0as1CACphxmrsqaju
-LDvnXjWLB+e7pJPQ+4XixKmA3QoQI6sduH03/4eRp/Er/+zXD7+uapz+GimiExJt
-mjW1Oz5n2Q7L9vQabqz0n9+8rM/chsfgipQSKmV0rXe/K1N4yuggh62r8kn9UaUR
-TKm6HaMIFBrZNwMy8TAc3gSq5rqbN8/ONiCBpW/LvwTnd7fFSl7yeetAbj08gpu2
-dkfYp/DK9Hs1KQFCi0u1pr9JIqFxNy6tUTO90ydq6QXj4E5yZhmitLPk5wPCozN+
-rIc=
+BgNVHQ8BAf8EBAMCBeAwDQYJKoZIhvcNAQEFBQADggEBAKuveVlnjgJIkiH6HqZk
++oGpLPxpcoMEMskzyFxTfjP4L2Mj798qydBbobyVJdH5p/sIpcHsI0xajM/dcZKS
+7b28KVwxOk+87DtwCikFT+jzWPe8fzowqsNAaKtvtDQnLYh8u2tDT1vhABwgTVAy
+aHCzs+nm3o36NPSN9K+wmI+r1KFnhjtyOQ++7M8wRRT5jrC+1tYicjsnVMu07yB5
+04C99Fa3MToilg66Jos95U3gBF5GbSfDXYtd3/etNMkUiG8FEZJlkhKbTO+4E03a
+X6+z2VojrAroYyO/F5ZlaC3/CsMQ8Zcate64nH/Lu/U78XAo8iKz5DLLOPBqodER
+z4A=
 -----END CERTIFICATE-----
diff --git a/tests/data_files/server1.req.cert_type b/tests/data_files/server1.req.cert_type
index b9b9f06..39ff3fd 100644
--- a/tests/data_files/server1.req.cert_type
+++ b/tests/data_files/server1.req.cert_type
@@ -7,11 +7,11 @@
 W+cTl4W1I5LZ1CQG1QkliXUH3aYajz8JGb6tZSxk65Wb3P5BXhem2mxbacwCuhQs
 FiScStzN0PdSZ3PxLaAj/X70McotcMqJCwTbLqZPcG6ezr1YieJTWZ5uWpJl4og/
 DJQZo93l6J2VE+0p26twEtxaymsXq1KCVLECAwEAAaAkMCIGCSqGSIb3DQEJDjEV
-MBMwEQYJYIZIAYb4QgEBBAQDAgBAMA0GCSqGSIb3DQEBBQUAA4IBAQCMX3H6BiGP
-VRvLu8UHIhsj9WgrGDRogOMVHOrQm+0fnGyxZa2UwftSZf2qLBZ+DmJStHabXibw
-QuWA9BMVFDih5yGMhdzQC8iQQCjfYOS0sfhy7p76q89rVO0E9KAtvFH2ApbaDAck
-m1WdQvYey2rYnT1ucHGdn017Iu1CaY8qnmh7Fhuov++69eGGG4MjRVT/7Ywufjo5
-Fn+JsMhj4IonP/jwKIUBskK15MkTQhKpyl5rQK/8v+7bWlsuqhiNPSYg6rgIrjmN
-QxxzqP5NLPdlS4ksN6zcuwdq21l+li8zakjbeUvyqZb7E6vTHJaNBOp7Y7jv25gG
-5/PjwquYbKFr
+MBMwEQYJYIZIAYb4QgEBBAQDAgZAMA0GCSqGSIb3DQEBBQUAA4IBAQBErZcEaEEO
+hLbRVuB3+N5by0mogdJsatJFSgW2/VztLvQBYu0O+VmTbZwCAWejA8U+cr6uPlyf
+b4lDqj3W+XykeK9bSzoSr1yNO2VAcE74Y0ZrSz2yXMfT5R9IyKqQZspaKD8MOmYH
+BqUH9o/phnGcaEG5xeSfhM1O/YNZuGnlLDQBGwT5puHOaLfjECvs8eZLopIWEBlD
+QkRlhYqZBwhGZ8D/TxqG4teFtnBX5FG7UoSSVuneBrkREQM7ElhtD9jCWjfMnqm1
+59G84OycClwaKU7/Dm6zeMGDyFoMksBud7lyDHMhxvwSbzb1JR5v8iBsmVY2dhHt
+Ot3Fx2be0gIr
 -----END CERTIFICATE REQUEST-----
diff --git a/tests/data_files/server1.req.cert_type_empty b/tests/data_files/server1.req.cert_type_empty
new file mode 100644
index 0000000..70fd111
--- /dev/null
+++ b/tests/data_files/server1.req.cert_type_empty
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICpDCCAYwCAQAwPDELMAkGA1UEBhMCTkwxETAPBgNVBAoMCFBvbGFyU1NMMRow
+GAYDVQQDDBFQb2xhclNTTCBTZXJ2ZXIgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAKkCHz1AatVVU4v9Nu6CZS4VYV6Jv7joRZDb7ogWUtPxQ1BHlhJZ
+ZIdr/SvgRvlzvt3PkuGRW+1moG+JKXlFgNCDatVBQ3dfOXwJBEeCsFc5cO2j7BUZ
+HqgzCEfBBUKp/UzDtN/dBh9NEFFAZ3MTD0D4bYElXwqxU8YwfhU5rPla7n+SnqYF
+W+cTl4W1I5LZ1CQG1QkliXUH3aYajz8JGb6tZSxk65Wb3P5BXhem2mxbacwCuhQs
+FiScStzN0PdSZ3PxLaAj/X70McotcMqJCwTbLqZPcG6ezr1YieJTWZ5uWpJl4og/
+DJQZo93l6J2VE+0p26twEtxaymsXq1KCVLECAwEAAaAjMCEGCSqGSIb3DQEJDjEU
+MBIwEAYJYIZIAYb4QgEBBAMDAQAwDQYJKoZIhvcNAQEFBQADggEBACU0LLDBIMgG
+B7gyNANHv42RovhQdzmUulqJPHNHx3v9G17F00bEykJb/r3awW6l5fhY/6oPydsY
+hnWEM6VVCUkJ6Zqm2/wE49uaNTbFd9JU4OywRBfjHHSTOGnYFg+BYSfwaIkSCkx2
+kVhyklFm7My5wkyDPpFSU2tTfgsgaQMyTm93a2kxM7qJ/X3gFDG8o7R0vyojFVSI
+mwsF9QsC6N9cygdFx23zCB0KsJ9KfmBqaTsdbKh8BsocYm5FJCw4WS/CBrCWBj+z
+N7yEJj4SR5F+P7sFc5I0HANov5wQe8E3+WxxQt8jcqIje6DlaaGja44cXOzvFQyx
+Hg/6H5EtBQc=
+-----END CERTIFICATE REQUEST-----
diff --git a/tests/data_files/server1.req.key_usage b/tests/data_files/server1.req.key_usage
index 4c20eed..30e4812 100644
--- a/tests/data_files/server1.req.key_usage
+++ b/tests/data_files/server1.req.key_usage
@@ -7,11 +7,11 @@
 W+cTl4W1I5LZ1CQG1QkliXUH3aYajz8JGb6tZSxk65Wb3P5BXhem2mxbacwCuhQs
 FiScStzN0PdSZ3PxLaAj/X70McotcMqJCwTbLqZPcG6ezr1YieJTWZ5uWpJl4og/
 DJQZo93l6J2VE+0p26twEtxaymsXq1KCVLECAwEAAaAeMBwGCSqGSIb3DQEJDjEP
-MA0wCwYDVR0PBAQDAgHgMA0GCSqGSIb3DQEBBQUAA4IBAQAIDkjGHokLINOSKAij
-DuBWyW72udNBwSmRAFYDyNoybWX+KJLFckyReF1S0YRHXWOljwxERF6htUEqIJDI
-vIzlXyV0YqHNmWEFpyRxyIllQ7X4NWnVm3zHYORx2utdy3EyNsNb4Rb/JNh6Qpqr
-27DB+frWaBYk27RPTdZz/ItZIicX8iHrAHL0aC6raQYvZfM1ybYehAh7Qx3asHKI
-XDcrbV50Kzrd0SgC4P6Z6/5C5uUL9AfcKnB2oj5VP2TM0BA6q+XRQFkJ3TO1UTLB
-lCKb9B1cIpVsT0YsOg/qptUh90zgd0x7FDa084ccwUJG73VXtHC6eioE4fbfrm5L
-9BNK
+MA0wCwYDVR0PBAQDAgXgMA0GCSqGSIb3DQEBBQUAA4IBAQBsJ3v1Ar2X28GJsRSJ
+WRQwFQwIbR/D0cHrwTf0ZfZttClytuc18JZlwkH3EG/rNkWaFp6MKIZoRMOBuSPc
+MNvvKIo4nPaeouDPruymx0gNenlyRL3D4OZpBO/BmQIQjbUKWFbzEnEqvwvMDUnG
+8w7UjPSFcxj2HzENr62HLPKKnVpL3nDXWK1a2A77KF9aMxyoWQ6FXb2xPD9cJjdo
+c1jwskQbgosQzKKwwp5yxq0zRD3EAGw4A78mgHMfgFprq9e9azaB0JeyFG2Vn0t0
+L+vfiDEVQ3eJXSCen1kEVyHRju8g53UcSgd+JicWFboFj2/mJBuyW6yM++RGA9B5
+Zd62
 -----END CERTIFICATE REQUEST-----
diff --git a/tests/data_files/server1.req.key_usage_empty b/tests/data_files/server1.req.key_usage_empty
new file mode 100644
index 0000000..47e56bf
--- /dev/null
+++ b/tests/data_files/server1.req.key_usage_empty
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICnjCCAYYCAQAwPDELMAkGA1UEBhMCTkwxETAPBgNVBAoMCFBvbGFyU1NMMRow
+GAYDVQQDDBFQb2xhclNTTCBTZXJ2ZXIgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAKkCHz1AatVVU4v9Nu6CZS4VYV6Jv7joRZDb7ogWUtPxQ1BHlhJZ
+ZIdr/SvgRvlzvt3PkuGRW+1moG+JKXlFgNCDatVBQ3dfOXwJBEeCsFc5cO2j7BUZ
+HqgzCEfBBUKp/UzDtN/dBh9NEFFAZ3MTD0D4bYElXwqxU8YwfhU5rPla7n+SnqYF
+W+cTl4W1I5LZ1CQG1QkliXUH3aYajz8JGb6tZSxk65Wb3P5BXhem2mxbacwCuhQs
+FiScStzN0PdSZ3PxLaAj/X70McotcMqJCwTbLqZPcG6ezr1YieJTWZ5uWpJl4og/
+DJQZo93l6J2VE+0p26twEtxaymsXq1KCVLECAwEAAaAdMBsGCSqGSIb3DQEJDjEO
+MAwwCgYDVR0PBAMDAQAwDQYJKoZIhvcNAQEFBQADggEBAAqQ/EU/3oMt7YW4vWgm
+0Q7F4v7DrFEoVMWfBzNWhMNIijzoaWKY8jwseZMzu8aCNQlJnM7c9FJF+OCgS7L5
+0ctwzjfCOi5I5cKgqv8WpuMZWHXNtB7YtjUWIZVri/RazCncZEwJGCKQjmQYrGJm
+Qmu2+D+DWY+nEW47ZfDH9jOJtatnREjSNsKzc44L9zUaEy3bi+m455XGH+ABmeb7
+Iqmguh10xUyY6rEOFEuqvFyFr5g1eb53Rr5CQxGfw1j+2bbSh+rVb6Ehf9LAijyu
+Ygqa91hGab/CjykS6HMrD91ouWtt2Rt3zCKo4Xxe8dlAszKB4W83M9OgDVVpiCfC
+t3A=
+-----END CERTIFICATE REQUEST-----
diff --git a/tests/data_files/server1.req.ku-ct b/tests/data_files/server1.req.ku-ct
index 98666d2..ebd01f5 100644
--- a/tests/data_files/server1.req.ku-ct
+++ b/tests/data_files/server1.req.ku-ct
@@ -7,11 +7,11 @@
 W+cTl4W1I5LZ1CQG1QkliXUH3aYajz8JGb6tZSxk65Wb3P5BXhem2mxbacwCuhQs
 FiScStzN0PdSZ3PxLaAj/X70McotcMqJCwTbLqZPcG6ezr1YieJTWZ5uWpJl4og/
 DJQZo93l6J2VE+0p26twEtxaymsXq1KCVLECAwEAAaAxMC8GCSqGSIb3DQEJDjEi
-MCAwCwYDVR0PBAQDAgHgMBEGCWCGSAGG+EIBAQQEAwIAQDANBgkqhkiG9w0BAQUF
-AAOCAQEAhDH3BQWViy67+9sdlrTvv0cIJ1IbogaM221MUasNIbfLi+KKfw50mzTa
-V/BCXPT+EzmOptBl+F2iZVQyr2c0nWbBZBHnykS3f0fgifm6yWVEYwJqxUC5+uxK
-bZztsHocTuqODpqYILycYkFXCcY8ZFHmz9XZorpUVTpZULW33EmLee5/BYI7whkA
-bVoSNB5tAb8kGZQffDnGkHiRfu8dbbEnkPYqm/cerN+4yCh1v1CGFh2lMn4d5p0L
-o9GvMsPM8pxdffZWZI9T0JnlHwtAJDA5G/MFYJdHzLzcHpvDA99MdNO4DMAiUyWb
-PCDL5e7mJ0lnBp8RppLBR7GEkznIQQ==
+MCAwCwYDVR0PBAQDAgXgMBEGCWCGSAGG+EIBAQQEAwIGQDANBgkqhkiG9w0BAQUF
+AAOCAQEAWUMyIXHi4BbIxOeCD/Vtu9LGV8ENMV7dwYVEQcwrt1AHahtYgUtkoGcP
+lOPqg1lbg22bu8dLPoY4HAzxCOAGs27otWL5LlE9M5QPH1RedEycmOuYrMl6K988
+hfDBJ+OkgCShcM91+udrc0gpDEI7N01A+fmukQ6EiaQjIf7HME/EKQqhEuEQMXHC
+GBvdNuEF5BfV3aAYuT+xfdXDU2ZWwXXWAHGmVh3ntnhtEG6SnXSnBATU2wa4tpBd
+KLbEbcsiy2uj0OLJlvG6LqsNggtkD58GCGpLpaVxdW80yw+f/krwLpeyocE1KGcT
+7eX+9yhLe9NIZojvevw+53dNE7BUfw==
 -----END CERTIFICATE REQUEST-----
diff --git a/tests/data_files/server2.der b/tests/data_files/server2.der
new file mode 100644
index 0000000..ec03190
--- /dev/null
+++ b/tests/data_files/server2.der
Binary files differ
diff --git a/tests/data_files/server5.req.ku.sha1 b/tests/data_files/server5.req.ku.sha1
index 39fc346..3281c94 100644
--- a/tests/data_files/server5.req.ku.sha1
+++ b/tests/data_files/server5.req.ku.sha1
@@ -1,8 +1,8 @@
 -----BEGIN CERTIFICATE REQUEST-----
-MIIBFzCBvAIBADA8MQswCQYDVQQGEwJOTDERMA8GA1UECgwIUG9sYXJTU0wxGjAY
+MIIBFjCBvAIBADA8MQswCQYDVQQGEwJOTDERMA8GA1UECgwIUG9sYXJTU0wxGjAY
 BgNVBAMMEVBvbGFyU1NMIFNlcnZlciAxMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD
 QgAEN8xW2XYJHlpyPsdZLf8gbu58+QaRdNCtFLX3aCJZYpJO5QDYIxH/6i/SNF1d
 Fr2KiMJrdw1VzYoqDvoByLTt/6AeMBwGCSqGSIb3DQEJDjEPMA0wCwYDVR0PBAQD
-AgHAMAsGByqGSM49BAEFAANJADBGAiEA5MGFTJkpOtCV7bAx+N+t4gP3JDM9RH3W
-mIXzSpcBwvACIQDf7f9ytclwouV1DQTFSUKxExIm48H60hk3lh19i3bGOw==
+AgbAMAsGByqGSM49BAEFAANIADBFAiEAnIKF+xKk0iEuN4MHd4FZWNvrznLQgkeg
+2n8ejjreTzcCIAH34z2TycuMpWQRhpV+YT988pBWR67LAg7REyZnjSAB
 -----END CERTIFICATE REQUEST-----
diff --git a/tests/data_files/test-ca.der b/tests/data_files/test-ca.der
new file mode 100644
index 0000000..039fb9e
--- /dev/null
+++ b/tests/data_files/test-ca.der
Binary files differ
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index fd9d664..d8374cc 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -303,7 +303,7 @@
 }
 
 check_headers_in_cpp () {
-    ls include/mbedtls >headers.txt
+    ls include/mbedtls | grep "\.h$" >headers.txt
     <programs/test/cpp_dummy_build.cpp sed -n 's/"$//; s!^#include "mbedtls/!!p' |
     sort |
     diff headers.txt -
@@ -406,6 +406,9 @@
     if [ ! -f "./tests/seedfile" ]; then
         dd if=/dev/urandom of=./tests/seedfile bs=32 count=1
     fi
+    if [ ! -f "./crypto/tests/seedfile" ]; then
+        dd if=/dev/urandom of=./crypto/tests/seedfile bs=32 count=1
+    fi
 }
 
 pre_setup_keep_going () {
@@ -675,6 +678,23 @@
     if_build_succeeded tests/compat.sh -t RSA
 }
 
+component_test_new_ecdh_context () {
+    msg "build: new ECDH context (ASan build)" # ~ 6 min
+    scripts/config.pl unset MBEDTLS_ECDH_LEGACY_CONTEXT
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
+
+    msg "test: new ECDH context - main suites (inc. selftests) (ASan build)" # ~ 50s
+    make test
+
+    msg "test: new ECDH context - ECDH-related part of ssl-opt.sh (ASan build)" # ~ 5s
+    if_build_succeeded tests/ssl-opt.sh -f ECDH
+
+    msg "test: new ECDH context - compat.sh with some ECDH ciphersuites (ASan build)" # ~ 3 min
+    # Exclude some symmetric ciphers that are redundant here to gain time.
+    if_build_succeeded tests/compat.sh -f ECDH -V NO -e 'ARCFOUR\|ARIA\|CAMELLIA\|CHACHA\|DES\|RC4'
+}
+
 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
@@ -730,8 +750,8 @@
     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, 3DES & 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 '^$' -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'
@@ -852,6 +872,7 @@
     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 unset MBEDTLS_ECP_RESTARTABLE  # restartable ECC not supported through PSA
     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 .
@@ -967,6 +988,22 @@
     if_build_succeeded tests/ssl-opt.sh -f "Max fragment length"
 }
 
+component_test_asan_remove_peer_certificate () {
+    msg "build: default config with MBEDTLS_SSL_KEEP_PEER_CERTIFICATE disabled (ASan build)"
+    scripts/config.pl unset MBEDTLS_SSL_KEEP_PEER_CERTIFICATE
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
+
+    msg "test: !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE"
+    make test
+
+    msg "test: ssl-opt.sh, !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE"
+    if_build_succeeded tests/ssl-opt.sh
+
+    msg "test: compat.sh, !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE"
+    if_build_succeeded tests/compat.sh
+}
+
 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
@@ -1083,6 +1120,16 @@
     esac
 }
 
+component_test_min_mpi_window_size () {
+    msg "build: Default + MBEDTLS_MPI_WINDOW_SIZE=1 (ASan build)" # ~ 10s
+    scripts/config.pl set MBEDTLS_MPI_WINDOW_SIZE 1
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
+
+    msg "test: MBEDTLS_MPI_WINDOW_SIZE=1 - main suites (inc. selftests) (ASan build)" # ~ 10s
+    make test
+}
+
 component_test_have_int32 () {
     msg "build: gcc, force 32-bit bignum limbs"
     scripts/config.pl unset MBEDTLS_HAVE_ASM
diff --git a/tests/scripts/basic-build-test.sh b/tests/scripts/basic-build-test.sh
index 28fc687..ab95e22 100755
--- a/tests/scripts/basic-build-test.sh
+++ b/tests/scripts/basic-build-test.sh
@@ -91,7 +91,7 @@
 OPENSSL_CMD="$OPENSSL_LEGACY"                                       \
     GNUTLS_CLI="$GNUTLS_LEGACY_CLI"                                 \
     GNUTLS_SERV="$GNUTLS_LEGACY_SERV"                               \
-    sh compat.sh -e '3DES\|DES-CBC3' -f 'NULL\|DES\|RC4\|ARCFOUR' | \
+    sh compat.sh -e '^$' -f 'NULL\|DES\|RC4\|ARCFOUR' |             \
     tee -a compat-test-$TEST_OUTPUT
 OPENSSL_CMD="$OPENSSL_NEXT"                     \
     sh compat.sh -e '^$' -f 'ARIA\|CHACHA' |    \
diff --git a/tests/scripts/check-generated-files.sh b/tests/scripts/check-generated-files.sh
index 4976bac..065ea33 100755
--- a/tests/scripts/check-generated-files.sh
+++ b/tests/scripts/check-generated-files.sh
@@ -65,5 +65,6 @@
 }
 
 check scripts/generate_errors.pl library/error.c
+check scripts/generate_query_config.pl programs/ssl/query_config.c
 check scripts/generate_features.pl library/version_features.c
 check scripts/generate_visualc_files.pl visualc/VS2010
diff --git a/tests/scripts/run-test-suites.pl b/tests/scripts/run-test-suites.pl
index 058a203..329ed14 100755
--- a/tests/scripts/run-test-suites.pl
+++ b/tests/scripts/run-test-suites.pl
@@ -4,19 +4,24 @@
 #
 # This file is part of mbed TLS (https://tls.mbed.org)
 #
-# Copyright (c) 2015-2016, ARM Limited, All Rights Reserved
-#
-# Purpose
-#
-# Executes all the available test suites, and provides a basic summary of the
-# results.
-#
-# Usage: run-test-suites.pl [-v]
-#
-# Options :
-#   -v|--verbose    - Provide a pass/fail/skip breakdown per test suite and
-#                     in total
-#
+# Copyright (c) 2015-2018, ARM Limited, All Rights Reserved
+
+=head1 SYNOPSIS
+
+Execute all the test suites and print a summary of the results.
+
+ run-test-suites.pl [[-v|--verbose] [VERBOSITY]] [--skip=SUITE[...]]
+
+Options:
+
+  -v|--verbose        Print detailed failure information.
+  -v 2|--verbose=2    Print detailed failure information and summary messages.
+  -v 3|--verbose=3    Print detailed information about every test case.
+  --skip=SUITE[,SUITE...]
+                      Skip the specified SUITE(s). This option can be used
+                      multiple times.
+
+=cut
 
 use warnings;
 use strict;
@@ -24,10 +29,15 @@
 use utf8;
 use open qw(:std utf8);
 
-use Getopt::Long;
+use Getopt::Long qw(:config auto_help gnu_compat);
+use Pod::Usage;
 
 my $verbose = 0;
-GetOptions( "verbose|v:1" => \$verbose );
+my @skip_patterns = ();
+GetOptions(
+           'skip=s' => \@skip_patterns,
+           'verbose|v:1' => \$verbose,
+          ) or die;
 
 # All test suites = executable files, excluding source files, debug
 # and profiling information, etc. We can't just grep {! /\./} because
@@ -36,6 +46,17 @@
 @suites = grep { !/\.c$/ && !/\.data$/ && -f } @suites;
 die "$0: no test suite found\n" unless @suites;
 
+# "foo" as a skip pattern skips "test_suite_foo" and "test_suite_foo.bar"
+# but not "test_suite_foobar".
+my $skip_re =
+    ( '\Atest_suite_(' .
+      join('|', map {
+          s/[ ,;]/|/g; # allow any of " ,;|" as separators
+          s/\./\./g; # "." in the input means ".", not "any character"
+          $_
+      } @skip_patterns) .
+      ')(\z|\.)' );
+
 # in case test suites are linked dynamically
 $ENV{'LD_LIBRARY_PATH'} = '../library:../crypto/library';
 $ENV{'DYLD_LIBRARY_PATH'} = '../library:../crypto/library';
@@ -45,6 +66,7 @@
 my ($failed_suites, $total_tests_run, $failed, $suite_cases_passed,
     $suite_cases_failed, $suite_cases_skipped, $total_cases_passed,
     $total_cases_failed, $total_cases_skipped );
+my $suites_skipped = 0;
 
 sub pad_print_center {
     my( $width, $padchar, $string ) = @_;
@@ -55,6 +77,12 @@
 for my $suite (@suites)
 {
     print "$suite ", "." x ( 72 - length($suite) - 2 - 4 ), " ";
+    if( $suite =~ /$skip_re/o ) {
+        print "SKIP\n";
+        ++$suites_skipped;
+        next;
+    }
+
     my $command = "$prefix$suite";
     if( $verbose ) {
         $command .= ' -v';
@@ -101,7 +129,10 @@
 
 print "-" x 72, "\n";
 print $failed_suites ? "FAILED" : "PASSED";
-printf " (%d suites, %d tests run)\n", scalar @suites, $total_tests_run;
+printf( " (%d suites, %d tests run%s)\n",
+        scalar(@suites) - $suites_skipped,
+        $total_tests_run,
+        $suites_skipped ? ", $suites_skipped suites skipped" : "" );
 
 if( $verbose > 1 ) {
     print "  test cases passed :", $total_cases_passed, "\n";
@@ -111,8 +142,11 @@
             "\n";
     print " of available tests :",
             ( $total_cases_passed + $total_cases_failed + $total_cases_skipped ),
-            "\n"
+            "\n";
+    if( $suites_skipped != 0 ) {
+        print "Note: $suites_skipped suites were skipped.\n";
     }
+}
 
 exit( $failed_suites ? 1 : 0 );
 
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 646ddd6..d952f33 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -165,22 +165,34 @@
 }
 
 get_config_value_or_default() {
-    NAME="$1"
-    DEF_VAL=$( grep ".*#define.*${NAME}" ../include/mbedtls/config.h |
-               sed 's/^.* \([0-9]*\)$/\1/' )
-    ../scripts/config.pl get $NAME || echo "$DEF_VAL"
+    # This function uses the query_config command line option to query the
+    # required Mbed TLS compile time configuration from the ssl_server2
+    # program. The command will always return a success value if the
+    # configuration is defined and the value will be printed to stdout.
+    #
+    # Note that if the configuration is not defined or is defined to nothing,
+    # the output of this function will be an empty string.
+    ${P_SRV} "query_config=${1}"
 }
 
 requires_config_value_at_least() {
-    VAL=$( get_config_value_or_default "$1" )
-    if [ "$VAL" -lt "$2" ]; then
+    VAL="$( get_config_value_or_default "$1" )"
+    if [ -z "$VAL" ]; then
+        # Should never happen
+        echo "Mbed TLS configuration $1 is not defined"
+        exit 1
+    elif [ "$VAL" -lt "$2" ]; then
        SKIP_NEXT="YES"
     fi
 }
 
 requires_config_value_at_most() {
     VAL=$( get_config_value_or_default "$1" )
-    if [ "$VAL" -gt "$2" ]; then
+    if [ -z "$VAL" ]; then
+        # Should never happen
+        echo "Mbed TLS configuration $1 is not defined"
+        exit 1
+    elif [ "$VAL" -gt "$2" ]; then
        SKIP_NEXT="YES"
     fi
 }
@@ -769,6 +781,30 @@
                 -C "Failed to setup PSA-based cipher context"\
                 -S "Failed to setup PSA-based cipher context"\
                 -s "Protocol is TLSv1.2" \
+                -c "Perform PSA-based ECDH computation."\
+                -c "Perform PSA-based computation of digest of ServerKeyExchange" \
+                -S "error" \
+                -C "error"
+}
+
+run_test_psa_force_curve() {
+    requires_config_enabled MBEDTLS_USE_PSA_CRYPTO
+    run_test    "PSA - ECDH with $1" \
+                "$P_SRV debug_level=4 force_version=tls1_2" \
+                "$P_CLI debug_level=4 force_version=tls1_2 force_ciphersuite=TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256 curves=$1" \
+                0 \
+                -c "Successfully setup PSA-based decryption cipher context" \
+                -c "Successfully setup PSA-based encryption cipher context" \
+                -c "PSA calc verify" \
+                -c "calc PSA finished" \
+                -s "Successfully setup PSA-based decryption cipher context" \
+                -s "Successfully setup PSA-based encryption cipher context" \
+                -s "PSA calc verify" \
+                -s "calc PSA finished" \
+                -C "Failed to setup PSA-based cipher context"\
+                -S "Failed to setup PSA-based cipher context"\
+                -s "Protocol is TLSv1.2" \
+                -c "Perform PSA-based ECDH computation."\
                 -c "Perform PSA-based computation of digest of ServerKeyExchange" \
                 -S "error" \
                 -C "error"
@@ -932,6 +968,29 @@
 run_test_psa TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256
 run_test_psa TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384
 
+requires_config_enabled MBEDTLS_ECP_DP_SECP521R1_ENABLED
+run_test_psa_force_curve "secp521r1"
+requires_config_enabled MBEDTLS_ECP_DP_BP512R1_ENABLED
+run_test_psa_force_curve "brainpoolP512r1"
+requires_config_enabled MBEDTLS_ECP_DP_SECP384R1_ENABLED
+run_test_psa_force_curve "secp384r1"
+requires_config_enabled MBEDTLS_ECP_DP_BP384R1_ENABLED
+run_test_psa_force_curve "brainpoolP384r1"
+requires_config_enabled MBEDTLS_ECP_DP_SECP256R1_ENABLED
+run_test_psa_force_curve "secp256r1"
+requires_config_enabled MBEDTLS_ECP_DP_SECP256K1_ENABLED
+run_test_psa_force_curve "secp256k1"
+requires_config_enabled MBEDTLS_ECP_DP_BP256R1_ENABLED
+run_test_psa_force_curve "brainpoolP256r1"
+requires_config_enabled MBEDTLS_ECP_DP_SECP224R1_ENABLED
+run_test_psa_force_curve "secp224r1"
+requires_config_enabled MBEDTLS_ECP_DP_SECP224K1_ENABLED
+run_test_psa_force_curve "secp224k1"
+requires_config_enabled MBEDTLS_ECP_DP_SECP192R1_ENABLED
+run_test_psa_force_curve "secp192r1"
+requires_config_enabled MBEDTLS_ECP_DP_SECP192K1_ENABLED
+run_test_psa_force_curve "secp192k1"
+
 # Test current time in ServerHello
 requires_config_enabled MBEDTLS_HAVE_TIME
 run_test    "ServerHello contains gmt_unix_time" \
@@ -4282,26 +4341,37 @@
 # Tests for ciphersuites per version
 
 requires_config_enabled MBEDTLS_SSL_PROTO_SSL3
+requires_config_enabled MBEDTLS_CAMELLIA_C
+requires_config_enabled MBEDTLS_AES_C
 run_test    "Per-version suites: SSL3" \
-            "$P_SRV min_version=ssl3 version_suites=TLS-RSA-WITH-3DES-EDE-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \
+            "$P_SRV min_version=ssl3 version_suites=TLS-RSA-WITH-CAMELLIA-128-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \
             "$P_CLI force_version=ssl3" \
             0 \
-            -c "Ciphersuite is TLS-RSA-WITH-3DES-EDE-CBC-SHA"
+            -c "Ciphersuite is TLS-RSA-WITH-CAMELLIA-128-CBC-SHA"
 
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1
+requires_config_enabled MBEDTLS_CAMELLIA_C
+requires_config_enabled MBEDTLS_AES_C
 run_test    "Per-version suites: TLS 1.0" \
-            "$P_SRV arc4=1 version_suites=TLS-RSA-WITH-3DES-EDE-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \
+            "$P_SRV version_suites=TLS-RSA-WITH-CAMELLIA-128-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \
             "$P_CLI force_version=tls1 arc4=1" \
             0 \
             -c "Ciphersuite is TLS-RSA-WITH-AES-256-CBC-SHA"
 
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_1
+requires_config_enabled MBEDTLS_CAMELLIA_C
+requires_config_enabled MBEDTLS_AES_C
 run_test    "Per-version suites: TLS 1.1" \
-            "$P_SRV version_suites=TLS-RSA-WITH-3DES-EDE-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \
+            "$P_SRV version_suites=TLS-RSA-WITH-CAMELLIA-128-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \
             "$P_CLI force_version=tls1_1" \
             0 \
             -c "Ciphersuite is TLS-RSA-WITH-AES-128-CBC-SHA"
 
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+requires_config_enabled MBEDTLS_CAMELLIA_C
+requires_config_enabled MBEDTLS_AES_C
 run_test    "Per-version suites: TLS 1.2" \
-            "$P_SRV version_suites=TLS-RSA-WITH-3DES-EDE-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \
+            "$P_SRV version_suites=TLS-RSA-WITH-CAMELLIA-128-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \
             "$P_CLI force_version=tls1_2" \
             0 \
             -c "Ciphersuite is TLS-RSA-WITH-AES-128-GCM-SHA256"
@@ -4310,7 +4380,7 @@
 
 requires_gnutls
 run_test    "ClientHello without extensions, SHA-1 allowed" \
-            "$P_SRV debug_level=3" \
+            "$P_SRV debug_level=3 key_file=data_files/server2.key crt_file=data_files/server2.crt" \
             "$G_CLI --priority=NORMAL:%NO_EXTENSIONS:%DISABLE_SAFE_RENEGOTIATION localhost" \
             0 \
             -s "dumping 'client hello extensions' (0 bytes)"
@@ -7002,13 +7072,7 @@
             -c "fragmenting handshake message" \
             -C "error"
 
-## The two tests below are disabled due to a bug in GnuTLS client that causes
-## handshake failures when the NewSessionTicket message is lost, see
-## https://gitlab.com/gnutls/gnutls/issues/543
-## We can re-enable them when a fixed version fo GnuTLS is available
-## and installed in our CI system.
-skip_next_test
-requires_gnutls
+requires_gnutls_next
 requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 requires_config_enabled MBEDTLS_RSA_C
 requires_config_enabled MBEDTLS_ECDSA_C
@@ -7020,12 +7084,11 @@
              crt_file=data_files/server7_int-ca.crt \
              key_file=data_files/server7.key \
              hs_timeout=250-60000 mtu=512 force_version=dtls1_2" \
-           "$G_CLI -u --insecure 127.0.0.1" \
+           "$G_NEXT_CLI -u --insecure 127.0.0.1" \
             0 \
             -s "fragmenting handshake message"
 
-skip_next_test
-requires_gnutls
+requires_gnutls_next
 requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 requires_config_enabled MBEDTLS_RSA_C
 requires_config_enabled MBEDTLS_ECDSA_C
@@ -7037,7 +7100,7 @@
              crt_file=data_files/server7_int-ca.crt \
              key_file=data_files/server7.key \
              hs_timeout=250-60000 mtu=512 force_version=dtls1" \
-           "$G_CLI -u --insecure 127.0.0.1" \
+           "$G_NEXT_CLI -u --insecure 127.0.0.1" \
             0 \
             -s "fragmenting handshake message"
 
@@ -7607,29 +7670,23 @@
             -s "Extra-header:" \
             -c "Extra-header:"
 
-# The next two test are disabled because they tend to trigger a bug in the
-# version of GnuTLS that's currently installed on our CI. The bug occurs when
-# different fragments of the same handshake message are received out-of-order
-# by GnuTLS and results in a timeout. It's been fixed in GnuTLS 3.5.2.
-skip_next_test
-requires_gnutls
+requires_gnutls_next
 client_needs_more_time 8
 not_with_valgrind # risk of non-mbedtls peer timing out
 run_test    "DTLS proxy: 3d, gnutls server, fragmentation" \
             -p "$P_PXY drop=5 delay=5 duplicate=5" \
-            "$G_SRV -u --mtu 512" \
+            "$G_NEXT_SRV -u --mtu 512" \
             "$P_CLI dgram_packing=0 dtls=1 hs_timeout=500-60000" \
             0 \
             -s "Extra-header:" \
             -c "Extra-header:"
 
-skip_next_test
-requires_gnutls
+requires_gnutls_next
 client_needs_more_time 8
 not_with_valgrind # risk of non-mbedtls peer timing out
 run_test    "DTLS proxy: 3d, gnutls server, fragmentation, nbio" \
             -p "$P_PXY drop=5 delay=5 duplicate=5" \
-            "$G_SRV -u --mtu 512" \
+            "$G_NEXT_SRV -u --mtu 512" \
             "$P_CLI dgram_packing=0 dtls=1 hs_timeout=500-60000 nbio=2" \
             0 \
             -s "Extra-header:" \
diff --git a/tests/suites/test_suite_asn1write.data b/tests/suites/test_suite_asn1write.data
index c2a78b1..9982d03 100644
--- a/tests/suites/test_suite_asn1write.data
+++ b/tests/suites/test_suite_asn1write.data
@@ -90,3 +90,75 @@
 
 ASN.1 Write / Read Length #12 (Len = 16909060, buffer too small)
 mbedtls_asn1_write_len:16909060:"8401020304":4:MBEDTLS_ERR_ASN1_BUF_TOO_SMALL
+
+ASN.1 Write Named Bitstring / Unused bits #0
+test_asn1_write_bitstrings:"FF":8:"030200FF":4:1
+
+ASN.1 Write Named Bitstring / Unused bits #1
+test_asn1_write_bitstrings:"FE":8:"030201FE":4:1
+
+ASN.1 Write Named Bitstring / Unused bits #2
+test_asn1_write_bitstrings:"FC":7:"030202FC":4:1
+
+ASN.1 Write Named Bitstring / Unused bits #3
+test_asn1_write_bitstrings:"F8":8:"030203F8":4:1
+
+ASN.1 Write Named Bitstring / Unused bits #4
+test_asn1_write_bitstrings:"F0":6:"030204F0":4:1
+
+ASN.1 Write Named Bitstring / Unused bits #5
+test_asn1_write_bitstrings:"E0":6:"030205E0":4:1
+
+ASN.1 Write Named Bitstring / Unused bits #6
+test_asn1_write_bitstrings:"C0":8:"030206C0":4:1
+
+ASN.1 Write Named Bitstring / Unused bits #7
+test_asn1_write_bitstrings:"80":8:"03020780":4:1
+
+ASN.1 Write Named Bitstring / Empty bitstring
+test_asn1_write_bitstrings:"00":7:"030100":3:1
+
+ASN.1 Write Named Bitstring / Empty bitstring (bits = 16)
+test_asn1_write_bitstrings:"0000":16:"030100":3:1
+
+ASN.1 Write Named Bitstring / Empty bitstring (bits = 24)
+test_asn1_write_bitstrings:"FFFFFF":0:"030100":3:1
+
+ASN.1 Write Named Bitstring / 15 trailing bits all unset
+test_asn1_write_bitstrings:"F88000":24:"030307F880":5:1
+
+ASN.1 Write Named Bitstring / 15 trailing bits all set
+test_asn1_write_bitstrings:"F8FFFF":9:"030307F880":5:1
+
+ASN.1 Write Bitstring / Unused bits #0
+test_asn1_write_bitstrings:"FF":8:"030200FF":4:0
+
+ASN.1 Write Bitstring / Unused bits #1
+test_asn1_write_bitstrings:"FF":7:"030201FE":4:0
+
+ASN.1 Write Bitstring / Unused bits #2
+test_asn1_write_bitstrings:"FF":6:"030202FC":4:0
+
+ASN.1 Write Bitstring / Unused bits #3
+test_asn1_write_bitstrings:"FF":5:"030203F8":4:0
+
+ASN.1 Write Bitstring / Unused bits #4
+test_asn1_write_bitstrings:"FF":4:"030204F0":4:0
+
+ASN.1 Write Bitstring / Unused bits #5
+test_asn1_write_bitstrings:"FF":3:"030205E0":4:0
+
+ASN.1 Write Bitstring / Unused bits #6
+test_asn1_write_bitstrings:"FF":2:"030206C0":4:0
+
+ASN.1 Write Bitstring / Unused bits #7
+test_asn1_write_bitstrings:"FF":1:"03020780":4:0
+
+ASN.1 Write Bitstring / 1 trailing bit (bits 15)
+test_asn1_write_bitstrings:"0003":15:"0303010002":5:0
+
+ASN.1 Write Bitstring / 0 bits
+test_asn1_write_bitstrings:"":0:"030100":3:0
+
+ASN.1 Write Bitstring / long string all bits unset except trailing bits
+test_asn1_write_bitstrings:"000000000007":45:"030703000000000000":9:0
diff --git a/tests/suites/test_suite_asn1write.function b/tests/suites/test_suite_asn1write.function
index 57a9741..e45583c 100644
--- a/tests/suites/test_suite_asn1write.function
+++ b/tests/suites/test_suite_asn1write.function
@@ -128,3 +128,47 @@
     }
 }
 /* END_CASE */
+
+/* BEGIN_CASE */
+void test_asn1_write_bitstrings( data_t *bitstring, int bits,
+                                 data_t *expected_asn1, int result,
+                                 int is_named )
+{
+    int ret;
+    size_t i;
+    unsigned char buf[150];
+    unsigned char *p;
+
+    memset( buf, GUARD_VAL, sizeof( buf ) );
+
+    p = buf + GUARD_LEN + expected_asn1->len;
+
+    if ( is_named == 0 )
+    {
+        ret = mbedtls_asn1_write_bitstring( &p,
+                                            buf,
+                                            (unsigned char *)bitstring->x,
+                                            (size_t) bits );
+    }
+    else
+    {
+        ret = mbedtls_asn1_write_named_bitstring( &p,
+                                                  buf,
+                                                  (unsigned char *)bitstring->x,
+                                                  (size_t) bits );
+    }
+    TEST_ASSERT( ret == result );
+
+    /* Check for buffer overwrite on both sides */
+    for( i = 0; i < GUARD_LEN; i++ )
+    {
+        TEST_ASSERT( buf[i] == GUARD_VAL );
+        TEST_ASSERT( buf[GUARD_LEN + expected_asn1->len + i] == GUARD_VAL );
+    }
+
+    if ( result >= 0 )
+    {
+        TEST_ASSERT( memcmp( p, expected_asn1->x, expected_asn1->len ) == 0 );
+    }
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_cipher.function b/tests/suites/test_suite_cipher.function
index a7d3a6e..9a0637e 100644
--- a/tests/suites/test_suite_cipher.function
+++ b/tests/suites/test_suite_cipher.function
@@ -1011,6 +1011,9 @@
     TEST_ASSERT( memcmp( output, clear->x, clear->len ) == 0 );
 
     /* then encrypt the clear->x and make sure we get the same ciphertext and tag->x */
+    TEST_ASSERT( 0 == mbedtls_cipher_setkey( &ctx, key->x, 8 * key->len,
+                                             MBEDTLS_ENCRYPT ) );
+
     memset( output, 0xFF, sizeof( output ) );
     outlen = 0;
 
@@ -1023,7 +1026,7 @@
                                output_tag, tag->len );
     TEST_ASSERT( ret == 0 );
 
-    TEST_ASSERT( outlen == clear->len );
+    TEST_ASSERT( outlen == cipher->len );
     TEST_ASSERT( memcmp( output, cipher->x, cipher->len ) == 0 );
     TEST_ASSERT( memcmp( output_tag, tag->x, tag->len ) == 0 );
 
diff --git a/tests/suites/test_suite_cipher.nist_kw.data b/tests/suites/test_suite_cipher.nist_kw.data
new file mode 100644
index 0000000..59ef931
--- /dev/null
+++ b/tests/suites/test_suite_cipher.nist_kw.data
@@ -0,0 +1,271 @@
+KW AES-128 wrap rfc 3394
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KW:"000102030405060708090A0B0C0D0E0F":"":"":"1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5":"":"":"00112233445566778899AABBCCDDEEFF":0
+
+KW AES-192 wrap rfc 3394
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_192_KW:"000102030405060708090A0B0C0D0E0F1011121314151617":"":"":"96778B25AE6CA435F92B5B97C050AED2468AB8A17AD84E5D":"":"":"00112233445566778899AABBCCDDEEFF":0
+
+KW AES-256 wrap rfc 3394
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_256_KW:"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F":"":"":"A8F9BC1612C68B3FF6E6F4FBE30E71E4769C8B80A32CB8958CD5D17D6B254DA1":"":"":"00112233445566778899AABBCCDDEEFF0001020304050607":0
+
+KW AES-256 wrap rfc 3394
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_256_KW:"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F":"":"":"64E8C3F9CE0F5BA263E9777905818A2A93C8191E7D6E8AE7":"":"":"00112233445566778899AABBCCDDEEFF":0
+
+KWP AES-192 RFC 5649
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_192_KWP:"5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8"::"":"":"138bdeaa9b8fa7fc61f97742e72248ee5ae6ae5360d1ae6a5f54f373fa543b6a":"":"":"c37b7e6492584340bed12207808941155068f738":0
+
+KWP AES-192 RFC 5649
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_192_KWP:"5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8"::"":"":"138bdeaa9b8fa7fc61f97742e72248ee5ae6ae5360d1ae6a5f54f373fa543b6a":"":"":"c37b7e6492584340bed12207808941155068f738":0
+
+KWP AES-128 1 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"A9D2D4394815D53F2799ABD7E51D2C8B":"":"":"00":0
+
+KWP AES-128 2 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"36D0CA197F638BF478D022C7E543B699":"":"":"0001":0
+
+KWP AES-128 3 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"DAB4EE2853E1C44C5E553E644143902B":"":"":"000102":0
+
+KWP AES-128 4 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"446C037F831092B147C372616357BF7D":"":"":"00010203":0
+
+KWP AES-128 5 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"9ED0AF6457B82E0DDADBD2240A303D74":"":"":"0001020304":0
+
+KWP AES-128 6 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"D863A8CE0DF301A564945259B4F74E7D":"":"":"000102030405":0
+
+KWP AES-128 7 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"E8387E5456242B0C30BE77FC1FF0C1FD":"":"":"00010203040506":0
+
+KWP AES-128 8 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"01FF4C430CDF3D2D815B0972B23D7C35":"":"":"0001020304050607":0
+
+KWP AES-128 9 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"C06E2163E0CC845B348E012AC9413DEEE40C8C3B030A3681":"":"":"000102030405060708":0
+
+KWP AES-128 10 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"3DFD2F643C38B07E121C77C2CA0EF82DA742B0989B6D848E":"":"":"00010203040506070809":0
+
+KWP AES-128 11 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"AFAEF390634E21E754FD09F55A4EDD918A1D23ECA9B76F2B":"":"":"000102030405060708090A":0
+
+KWP AES-128 12 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"A42D14C830F64F0A73570BFA7FDF8DDDD5E3AD3065A09FB0":"":"":"000102030405060708090A0B":0
+
+KWP AES-128 13 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"83F23527625FC643942279D090C1B61D10FC978B54D778CD":"":"":"000102030405060708090A0B0C":0
+
+KWP AES-128 14 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"E073C30E0DAC595F9FD28A0CB9E53945B26D1E1DE4E66D04":"":"":"000102030405060708090A0B0C0D":0
+
+KWP AES-128 15 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"64E3C2F7E0F7CB297C6B8C4CAF665F9F0A3F7082D2522635":"":"":"000102030405060708090A0B0C0D0E":0
+
+KWP AES-128 16 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"8F5982C7D265A0A40FC81D2326429A0A65BCD1368F0E16CB":"":"":"000102030405060708090A0B0C0D0E0F":0
+
+KWP AES-128 17 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"E29EC6664BCBA00986DD9845F8C4B26472BFDDF98522E537B5D23D5D2A8D02C5":"":"":"000102030405060708090A0B0C0D0E0F10":0
+
+KWP AES-128 18 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"9451ABCA0B9756A183F8C9ADA834E1AD2400B693C33624E59F26C35AC1586E2B":"":"":"000102030405060708090A0B0C0D0E0F1011":0
+
+KWP AES-128 19 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"F03CB49A65FD3EF8FC83C52F029A3D73667D5B84DB429C38436619ED8320D12E":"":"":"000102030405060708090A0B0C0D0E0F101112":0
+
+KWP AES-128 20 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"759524B855037849812D62979A18F24D3E672C2663DEA9204BA5A639FB7DB292":"":"":"000102030405060708090A0B0C0D0E0F10111213":0
+
+KWP AES-128 21 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"F352B8228FBFA0769C2E3858D7451FA603E9B751CFE780ED0F93C850C7870259":"":"":"000102030405060708090A0B0C0D0E0F1011121314":0
+
+KWP AES-128 22 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"3491F4C8D916A1BC3824D1478EC746BE8C837415017ED52A1ABC30FB14DDE825":"":"":"000102030405060708090A0B0C0D0E0F101112131415":0
+
+KWP AES-128 23 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"0E6E35C5B9D706C2FF2C4C6CFCF254849879D6C1CB577E0A73BB12CBC7AC9740":"":"":"000102030405060708090A0B0C0D0E0F10111213141516":0
+
+KWP AES-128 24 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"E7DB580663B113B57489E1107F2DCAF7CF80629E7CE1839E1ED044ECD0299E79":"":"":"000102030405060708090A0B0C0D0E0F1011121314151617":0
+
+KWP AES-128 25 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"883500DB91747BAD8C5E122ED2338F3BCB6B43064F5DA9D1303E165815EC8CC4C5BFD31AEAE1B6A3":"":"":"000102030405060708090A0B0C0D0E0F101112131415161718":0
+
+KWP AES-128 26 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"24099AAAD4F19BF614ECC35DA9E3646F73AAFAA9C46975D4B56D72A332AF7EC4850B8294D94B7E1A":"":"":"000102030405060708090A0B0C0D0E0F10111213141516171819":0
+
+KWP AES-128 27 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"C24F8CCE3425AC9638145A0DAC28B59368583FF3A7AAD85FBE1AEAAB5D23C0B128A1F9BC575B785A":"":"":"000102030405060708090A0B0C0D0E0F101112131415161718191A":0
+
+KWP AES-128 28 byte input
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"00000000000000000000000000000000"::"":"":"EFD0BC7612331A98F2D68F86E606717197BF57E35114234C675D40E9462ACF00DE7860C0F38677F7":"":"":"000102030405060708090A0B0C0D0E0F101112131415161718191A1B":0
+
+KW AES-128 wrap CAVS 17.4 COUNT 0 PLEN 16
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KW:"7575da3a93607cc2bfd8cec7aadfd9a6":"":"":"031f6bd7e61e643df68594816f64caa3f56fabea2548f5fb":"":"":"42136d3c384a3eeac95a066fd28fed3f":0
+
+KW AES-128 wrap CAVS 17.4 COUNT 0 PLEN 16
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KW:"7575da3a93607cc2bfd8cec7aadfd9a7":"":"":"031f6bd7e61e643df68594816f64cbb3f56fabea2548f5fb":"":"FAIL":"":0
+
+KW AES-128 wrap CAVS 17.4 COUNT 0 PLEN 32
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KW:"e5d058e7f1c22c016c4e1cc9b26b9f8f":"":"":"60b9f8ac797c56e01e9b5f84d65816a980777869f67991a0e6dc19b8cd75c9b54db4a38456bbd6f3":"":"":"7f604e9b8d39d3c91e193fe6f196c1e3da6211a7c9a33b8873b64b138d1803e4":0
+
+KW AES-128 wrap CAVS 17.4 COUNT 0 PLEN 24
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KW:"67ae4270bcdd31e8326b7e7f94c80276":"":"":"96cec0e3272a21faa550a857957aa38ce3c1cf06f0dd9f5b5c5c422cef6c69a1":"":"":"57e748b62fbc37ba25e904ee973d01b136cf7c1d0c8c5c87":0
+
+KW AES-192 wrap CAVS 17.4 COUNT 0 PLEN 16
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_192_KW:"a6a3f6d509811859238fc569b5664605f7a73c475a691a8f":"":"":"57d7a4b4e85ffdcb7788b9b666cb63303dd2c5d0f11b1bbb":"":"":"8484e414b091f8a9f72cfd13087ddec1":0
+
+KW AES-192 wrap CAVS 17.4 COUNT 0 PLEN 32
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_192_KW:"3686e50dd602f84024570f545bbf618362bef80d45472436":"":"":"c7d5a1a5dfeb7327acbb94767d74cc2afc622ffd01f854d7d3e2b6f75ca7e8f441a0c0bad3d26ee2":"":"":"d780d69b45483b682d311ccaaadcfa3a1cecf1f05dbe2ebc71e6d3fa979f3de8":0
+
+KW AES-192 wrap CAVS 17.4 COUNT 0 PLEN 24
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_192_KW:"0a833412e7aa1384ff26866dc9c551bf60413c17e847d317":"":"":"3a7efd629305bf1d61360ed6ff8ec7d059e8af3e5104c29729adb55d1bb94f7e":"":"":"f734760cc0fa3bbfb271277d4f29a48ddecda733d610fa42":0
+
+KW AES-256 wrap CAVS 17.4 COUNT 0 PLEN 16
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_256_KW:"f59782f1dceb0544a8da06b34969b9212b55ce6dcbdd0975a33f4b3f88b538da":"":"":"2e63946ea3c090902fa1558375fdb2907742ac74e39403fc":"":"":"73d33060b5f9f2eb5785c0703ddfa704":0
+
+KW AES-256 wrap CAVS 17.4 COUNT 0 PLEN 32
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_256_KW:"8b54e6bc3d20e823d96343dc776c0db10c51708ceecc9a38a14beb4ca5b8b221":"":"":"b13eeb7619fab818f1519266516ceb82abc0e699a7153cf26edcb8aeb879f4c011da906841fc5956":"":"":"d6192635c620dee3054e0963396b260af5c6f02695a5205f159541b4bc584bac":0
+
+KW AES-256 wrap CAVS 17.4 COUNT 0 PLEN 24
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_256_KW:"112ad41b4856c7254a9848d30fdd78335b039a48a8962c4d1cb78eabd5dad788":"":"":"ba8a259a471b787dd5d540ec25d43d87200fdadc6d1f05d916584fa9f6cbf512":"":"":"1b20bf1990b065d798e1b32264ad50a8747492ba09a04dd1":0
+
+KWP AES-128 wrap CAVS 17.4 COUNT 0 PLEN 1
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"6decf10a1caf8e3b80c7a4be8c9c84e8":"":"":"01a7d657fc4a5b216f261cca4d052c2b":"":"":"49":0
+
+KWP AES-128 wrap CAVS 17.4 COUNT 0 PLEN 8
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"a8e06da625a65b25cf5030826830b661":"":"":"b6f967616dd8d772e9fea295a456dba7":"":"":"43acff293120dd5d":0
+
+KWP AES-128 wrap CAVS 17.4 COUNT 0 PLEN 9
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"7865e20f3c21659ab4690b629cdf3cc4":"":"":"41eca956d4aa047eb5cf4efe659661e74db6f8c564e23500":"":"":"bd6843d420378dc896":0
+
+KWP AES-128 wrap CAVS 17.4 COUNT 0 PLEN 31
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"be96dc195ec034d616486ed70e97fe83":"":"":"974769b3a7b4d5d32985f87fddf9990631e5610fbfb278387b58b1f48e05c77d2fb7575c5169eb0e":"":"":"85b5437b6335ebba7635903a4493d12a77d9357a9e0dbc013456d85f1d3201":0
+
+KWP AES-192 wrap CAVS 17.4 COUNT 0 PLEN 1
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_192_KWP:"9ca11078baebc1597a68ce2fe3fc79a201626575252b8860":"":"":"866bc0ae30e290bb20a0dab31a6e7165":"":"":"76":0
+
+KWP AES-192 wrap CAVS 17.4 COUNT 0 PLEN 8
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_192_KWP:"c5029804d28341ca267c9e73afc5f963b14bb604708b43f2":"":"":"15b98046b2a3a49b9c0831c476fc34fb":"":"":"e6eb18a3e969ab5c":0
+
+KWP AES-192 wrap CAVS 17.4 COUNT 0 PLEN 9
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_192_KWP:"9464f1af6aabad076661328bcfd15777da16a288a2660009":"":"":"d9b257b400d808a0b0386af3be9154fc7f2fb2d7edc06201":"":"":"431527c3a644c106bb":0
+
+KWP AES-192 wrap CAVS 17.4 COUNT 0 PLEN 31
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_192_KWP:"a354ccd6dd97cf40bed840f8137e0cf2e91c00e592104765":"":"":"f018e7c8d6dcdbd20606502b2667439d9049a9a2d5c960af8e9251466d6ff8923fb82432b299f1a4":"":"":"22ccc034c5345550f5bc0114f2951f0fe439ec3ecd8ac1fea8889dd12bfb8e":0
+
+KWP AES-256 wrap CAVS 17.4 COUNT 0 PLEN 1
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_256_KWP:"95da2700ca6fd9a52554ee2a8df1386f5b94a1a60ed8a4aef60a8d61ab5f225a":"":"":"06ba7ae6f3248cfdcf267507fa001bc4":"":"":"d1":0
+
+KWP AES-256 wrap CAVS 17.4 COUNT 0 PLEN 8
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_256_KWP:"3517f0efa7f0c4d74f91af83ece5e7503bcc5ab82907a6e4b7ed34d87b69ab1d":"":"":"0b06a9b635d50cda9d4210cb3a71f990":"":"":"897e0456b289ad31":0
+
+KWP AES-256 wrap CAVS 17.4 COUNT 0 PLEN 9
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_256_KWP:"70da43aac823c6dd37d1109f5b18feb4503c973288989745e2cc1cc21d9570c6":"":"":"d67b5b2ad15c645450e23b5e7b6d682f8ae20e716d470db7":"":"":"edf17d966ed896aee3":0
+
+KWP AES-256 wrap CAVS 17.4 COUNT 0 PLEN 31
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_256_KWP:"e9bb7f44c7baafbf392ab912589a2f8db53268106eafb74689bb1833136e6113":"":"":"15b9f06fbc765e5e3d55d6b824616f21921d2a6918ee7bf1406b524274e170b4a78333ca5ee92af5":"":"":"ffe952604834bff899e63658f34246815c91597eb40a21729e0a8a959b61f2":0
+KW AES-128 wrap CAVS 17.4 FAIL COUNT 1 CLEN 48
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KW:"5d4899ee66beff1bda1fc717a1ad4c50":"":"":"bb7fd0bce778bd775e4e88d904d26a7134364c53a6c493a0":"":"FAIL":"":0
+
+KW AES-128 wrap CAVS 17.4 FAIL COUNT 1 CLEN 80
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KW:"84bc6ce7ee4fd9db512536669d0686da":"":"":"c383db930ffd02c0073ac2cc79ec289e6866bdcc6a135a3b776aa42f14ee04f9cca06ed6c0b22901":"":"FAIL":"":0
+
+KW AES-128 wrap CAVS 17.4 FAIL COUNT 3 CLEN 64
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KW:"266b009e911bb55f9aa0661539a6fdd5":"":"":"db9c94e7236ec56982d7ddeb9427c24580bc1fb96db98ab19340e03670045b7a":"":"FAIL":"":0
+
+KW AES-192 wrap CAVS 17.4 FAIL COUNT 3 CLEN 48
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_192_KW:"9200a0f688d86c0b6bfd9abeff66341684a373fe3f9a3057":"":"":"5c685c8596e374710fe327bafc45cd09190215fdcc03d010":"":"FAIL":"":0
+
+KW AES-192 wrap CAVS 17.4 FAIL COUNT 1 CLEN 80
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_192_KW:"95c9e644559919cace6f93f545dbfe48b130808ed66d0964":"":"":"7b8d1307e992221f6ffdcc7909d972d5f02e92187139cfd77f79345cb998bbdbabedb3ac00a6cdc4":"":"FAIL":"":0
+
+KW AES-192 wrap CAVS 17.4 FAIL COUNT 2 CLEN 64
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_192_KW:"e218e9643d5db01b412fcaefafe5eb237d03acfad0a3abaa":"":"":"5eee8fbf6a8ab6ba371f4581982ec61839bf28c0eb913d1f417a284dccd72580":"":"FAIL":"":0
+
+KW AES-256 wrap CAVS 17.4 FAIL COUNT 4 CLEN 48
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_256_KW:"08c936b25b567a0aa679c29f201bf8b190327df0c2563e39cee061f149f4d91b":"":"":"e227eb8ae9d239ccd8928adec39c28810ca9b3dc1f366444":"":"FAIL":"":0
+
+KW AES-256 wrap CAVS 17.4 FAIL COUNT 3 CLEN 80
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_256_KW:"605b22935f1eee56ba884bc7a869febc159ac306b66fb9767a7cc6ab7068dffa":"":"":"6607f5a64c8f9fd96dc6f9f735b06a193762cdbacfc367e410926c1bfe6dd715490adbad5b9697a6":"":"FAIL":"":0
+
+KW AES-256 wrap CAVS 17.4 FAIL COUNT 3 CLEN 64
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_256_KW:"81c93da5baa5157bf700fd38d7d67662670778b690cfbca9fe11e06268b35605":"":"":"875e1ca385586f83d1e23e44ca201006df04e1854e41b933fd607a7383ae1a39":"":"FAIL":"":0
+
+KWP AES-128 wrap CAVS 17.4 FAIL COUNT 1 CLEN 32
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_128_KWP:"30be7ff51227f0eef786cb7be2482510":"":"":"7f61a0a8b2fe7803f2947d233ec3a255":"":"FAIL":"":0
+
+KWP AES-192 wrap CAVS 17.4 FAIL COUNT 3 CLEN 32
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_192_KWP:"21fb6600c1d34a74adee67612672593a86cf235421735350":"":"":"56b45c49c3e379b18d9c38b6423db133":"":"FAIL":"":0
+
+KWP AES-256 wrap CAVS 17.4 FAIL COUNT 4 CLEN 32
+depends_on:MBEDTLS_AES_C:MBEDTLS_NIST_KW_C
+auth_crypt_tv:MBEDTLS_CIPHER_AES_256_KWP:"c32cb3e1e41a4b9f4de79989957866f5dd48dba38c22a6ebb80e14c84bdd9534":"":"":"c29b05c2619a58ecc1d239e7a34273cd":"":"FAIL":"":0
+
diff --git a/tests/suites/test_suite_ecdh.data b/tests/suites/test_suite_ecdh.data
index fe24ed4..fb4a232 100644
--- a/tests/suites/test_suite_ecdh.data
+++ b/tests/suites/test_suite_ecdh.data
@@ -79,3 +79,31 @@
 ECDH exchange legacy context
 depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
 ecdh_exchange_legacy:MBEDTLS_ECP_DP_SECP192R1
+
+ECDH calc_secret: ours first, SECP256R1 (RFC 5903)
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecdh_exchange_calc_secret:MBEDTLS_ECP_DP_SECP256R1:"c6ef9c5d78ae012a011164acb397ce2088685d8f06bf9be0b283ab46476bee53":"04dad0b65394221cf9b051e1feca5787d098dfe637fc90b9ef945d0c37725811805271a0461cdb8252d61f1c456fa3e59ab1f45b33accf5f58389e0577b8990bb3":0:"d6840f6b42f6edafd13116e0e12565202fef8e9ece7dce03812464d04b9442de"
+
+ECDH calc_secret: theirs first, SECP256R1 (RFC 5903)
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+ecdh_exchange_calc_secret:MBEDTLS_ECP_DP_SECP256R1:"c6ef9c5d78ae012a011164acb397ce2088685d8f06bf9be0b283ab46476bee53":"04dad0b65394221cf9b051e1feca5787d098dfe637fc90b9ef945d0c37725811805271a0461cdb8252d61f1c456fa3e59ab1f45b33accf5f58389e0577b8990bb3":1:"d6840f6b42f6edafd13116e0e12565202fef8e9ece7dce03812464d04b9442de"
+
+ecdh calc_secret: ours first (Alice), curve25519 (rfc 7748)
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecdh_exchange_calc_secret:MBEDTLS_ECP_DP_CURVE25519:"77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a":"de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f":0:"4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"
+
+ecdh calc_secret: theirs first (Alice), curve25519 (rfc 7748)
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecdh_exchange_calc_secret:MBEDTLS_ECP_DP_CURVE25519:"77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a":"de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f":1:"4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"
+
+ecdh calc_secret: ours first (Bob), curve25519 (rfc 7748)
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecdh_exchange_calc_secret:MBEDTLS_ECP_DP_CURVE25519:"5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb":"8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a":0:"4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"
+
+ECDH get_params with mismatched groups: our BP256R1, their SECP256R1
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_BP256R1_ENABLED
+ecdh_exchange_get_params_fail:MBEDTLS_ECP_DP_BP256R1:"1234567812345678123456781234567812345678123456781234567812345678":MBEDTLS_ECP_DP_SECP256R1:"04dad0b65394221cf9b051e1feca5787d098dfe637fc90b9ef945d0c37725811805271a0461cdb8252d61f1c456fa3e59ab1f45b33accf5f58389e0577b8990bb3":0:MBEDTLS_ERR_ECP_BAD_INPUT_DATA
+
+ECDH get_params with mismatched groups: their SECP256R1, our BP256R1
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_BP256R1_ENABLED
+ecdh_exchange_get_params_fail:MBEDTLS_ECP_DP_BP256R1:"1234567812345678123456781234567812345678123456781234567812345678":MBEDTLS_ECP_DP_SECP256R1:"04dad0b65394221cf9b051e1feca5787d098dfe637fc90b9ef945d0c37725811805271a0461cdb8252d61f1c456fa3e59ab1f45b33accf5f58389e0577b8990bb3":1:MBEDTLS_ERR_ECP_BAD_INPUT_DATA
diff --git a/tests/suites/test_suite_ecdh.function b/tests/suites/test_suite_ecdh.function
index 7db0ed1..d6bed7f 100644
--- a/tests/suites/test_suite_ecdh.function
+++ b/tests/suites/test_suite_ecdh.function
@@ -1,5 +1,40 @@
 /* BEGIN_HEADER */
 #include "mbedtls/ecdh.h"
+
+static int load_public_key( int grp_id, data_t *point,
+                            mbedtls_ecp_keypair *ecp )
+{
+    int ok = 0;
+    TEST_ASSERT( mbedtls_ecp_group_load( &ecp->grp, grp_id ) == 0 );
+    TEST_ASSERT( mbedtls_ecp_point_read_binary( &ecp->grp,
+                                                &ecp->Q,
+                                                point->x,
+                                                point->len ) == 0 );
+    TEST_ASSERT( mbedtls_ecp_check_pubkey( &ecp->grp,
+                                           &ecp->Q ) == 0 );
+    ok = 1;
+exit:
+    return( ok );
+}
+
+static int load_private_key( int grp_id, data_t *private_key,
+                             mbedtls_ecp_keypair *ecp,
+                             rnd_pseudo_info *rnd_info )
+{
+    int ok = 0;
+    TEST_ASSERT( mbedtls_ecp_read_key( grp_id, ecp,
+                                       private_key->x,
+                                       private_key->len ) == 0 );
+    TEST_ASSERT( mbedtls_ecp_check_privkey( &ecp->grp, &ecp->d ) == 0 );
+    /* Calculate the public key from the private key. */
+    TEST_ASSERT( mbedtls_ecp_mul( &ecp->grp, &ecp->Q, &ecp->d,
+                                  &ecp->grp.G,
+                                  &rnd_pseudo_rand, rnd_info ) == 0 );
+    ok = 1;
+exit:
+    return( ok );
+}
+
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
@@ -464,3 +499,107 @@
     mbedtls_ecdh_free( &cli );
 }
 /* END_CASE */
+
+/* BEGIN_CASE */
+void ecdh_exchange_calc_secret( int grp_id,
+                                data_t *our_private_key,
+                                data_t *their_point,
+                                int ours_first,
+                                data_t *expected )
+{
+    rnd_pseudo_info rnd_info;
+    mbedtls_ecp_keypair our_key;
+    mbedtls_ecp_keypair their_key;
+    mbedtls_ecdh_context ecdh;
+    unsigned char shared_secret[MBEDTLS_ECP_MAX_BYTES];
+    size_t shared_secret_length = 0;
+
+    memset( &rnd_info, 0x00, sizeof( rnd_pseudo_info ) );
+    mbedtls_ecdh_init( &ecdh );
+    mbedtls_ecp_keypair_init( &our_key );
+    mbedtls_ecp_keypair_init( &their_key );
+
+    if( ! load_private_key( grp_id, our_private_key, &our_key, &rnd_info ) )
+        goto exit;
+    if( ! load_public_key( grp_id, their_point, &their_key ) )
+        goto exit;
+
+    /* Import the keys to the ECDH calculation. */
+    if( ours_first )
+    {
+        TEST_ASSERT( mbedtls_ecdh_get_params(
+                         &ecdh, &our_key, MBEDTLS_ECDH_OURS ) == 0 );
+        TEST_ASSERT( mbedtls_ecdh_get_params(
+                         &ecdh, &their_key, MBEDTLS_ECDH_THEIRS ) == 0 );
+    }
+    else
+    {
+        TEST_ASSERT( mbedtls_ecdh_get_params(
+                         &ecdh, &their_key, MBEDTLS_ECDH_THEIRS ) == 0 );
+        TEST_ASSERT( mbedtls_ecdh_get_params(
+                         &ecdh, &our_key, MBEDTLS_ECDH_OURS ) == 0 );
+    }
+
+    /* Perform the ECDH calculation. */
+    TEST_ASSERT( mbedtls_ecdh_calc_secret(
+                     &ecdh,
+                     &shared_secret_length,
+                     shared_secret, sizeof( shared_secret ),
+                     &rnd_pseudo_rand, &rnd_info ) == 0 );
+    TEST_ASSERT( shared_secret_length == expected->len );
+    TEST_ASSERT( memcmp( expected->x, shared_secret,
+                         shared_secret_length ) == 0 );
+
+exit:
+    mbedtls_ecdh_free( &ecdh );
+    mbedtls_ecp_keypair_free( &our_key );
+    mbedtls_ecp_keypair_free( &their_key );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void ecdh_exchange_get_params_fail( int our_grp_id,
+                                    data_t *our_private_key,
+                                    int their_grp_id,
+                                    data_t *their_point,
+                                    int ours_first,
+                                    int expected_ret )
+{
+    rnd_pseudo_info rnd_info;
+    mbedtls_ecp_keypair our_key;
+    mbedtls_ecp_keypair their_key;
+    mbedtls_ecdh_context ecdh;
+
+    memset( &rnd_info, 0x00, sizeof( rnd_pseudo_info ) );
+    mbedtls_ecdh_init( &ecdh );
+    mbedtls_ecp_keypair_init( &our_key );
+    mbedtls_ecp_keypair_init( &their_key );
+
+    if( ! load_private_key( our_grp_id, our_private_key, &our_key, &rnd_info ) )
+        goto exit;
+    if( ! load_public_key( their_grp_id, their_point, &their_key ) )
+        goto exit;
+
+    if( ours_first )
+    {
+        TEST_ASSERT( mbedtls_ecdh_get_params(
+                         &ecdh, &our_key, MBEDTLS_ECDH_OURS ) == 0 );
+        TEST_ASSERT( mbedtls_ecdh_get_params(
+                         &ecdh, &their_key, MBEDTLS_ECDH_THEIRS ) ==
+                     expected_ret );
+    }
+    else
+    {
+        TEST_ASSERT( mbedtls_ecdh_get_params(
+                         &ecdh, &their_key, MBEDTLS_ECDH_THEIRS ) == 0 );
+        TEST_ASSERT( mbedtls_ecdh_get_params(
+                         &ecdh, &our_key, MBEDTLS_ECDH_OURS ) ==
+                     expected_ret );
+    }
+
+exit:
+    mbedtls_ecdh_free( &ecdh );
+    mbedtls_ecp_keypair_free( &our_key );
+    mbedtls_ecp_keypair_free( &their_key );
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_ecp.data b/tests/suites/test_suite_ecp.data
index 30d5ec6..8653366 100644
--- a/tests/suites/test_suite_ecp.data
+++ b/tests/suites/test_suite_ecp.data
@@ -88,6 +88,14 @@
 depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
 ecp_write_binary:MBEDTLS_ECP_DP_SECP192R1:"48d8082a3a1e3112bc03a8ef2f6d40d0a77a6f8e00cc9933":"93112b28345b7d1d7799611e49bea9d8290cb2d7afe1f9f3":"01":MBEDTLS_ECP_PF_COMPRESSED:"0348d8082a3a1e3112bc03a8ef2f6d40d0a77a6f8e00cc9933":25:0
 
+ECP write binary #10 (Montgomery, buffer just fits)
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_write_binary:MBEDTLS_ECP_DP_CURVE25519:"11223344556677889900aabbccddeeff11223344556677889900aabbccddeeff":"0":"1":MBEDTLS_ECP_PF_COMPRESSED:"ffeeddccbbaa00998877665544332211ffeeddccbbaa00998877665544332211":32:0
+
+ECP write binary #11 (Montgomery, buffer too small)
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_write_binary:MBEDTLS_ECP_DP_CURVE25519:"11223344556677889900aabbccddeeff11223344556677889900aabbccddeeff":"0":"1":MBEDTLS_ECP_PF_COMPRESSED:"ffeeddccbbaa00998877665544332211ffeeddccbbaa00998877665544332211":31:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL
+
 ECP read binary #1 (zero, invalid ilen)
 depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
 ecp_read_binary:MBEDTLS_ECP_DP_SECP192R1:"0000":"01":"01":"00":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
@@ -112,6 +120,30 @@
 depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
 ecp_read_binary:MBEDTLS_ECP_DP_SECP192R1:"0448d8082a3a1e3112bc03a8ef2f6d40d0a77a6f8e00cc99336ceed4d7cba482e288669ee1b6415626d6f34d28501e060c":"48d8082a3a1e3112bc03a8ef2f6d40d0a77a6f8e00cc9933":"6ceed4d7cba482e288669ee1b6415626d6f34d28501e060c":"01":0
 
+ECP read binary #7 (Curve25519, OK)
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_read_binary:MBEDTLS_ECP_DP_CURVE25519:"8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a":"6a4e9baa8ea9a4ebf41a38260d3abf0d5af73eb4dc7d8b7454a7308909f02085":"0":"1":0
+
+ECP read binary #8 (Curve25519, masked first bit)
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_read_binary:MBEDTLS_ECP_DP_CURVE25519:"8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4efa":"7a4e9baa8ea9a4ebf41a38260d3abf0d5af73eb4dc7d8b7454a7308909f02085":"0":"1":0
+
+ECP read binary #9 (Curve25519, too short)
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_read_binary:MBEDTLS_ECP_DP_CURVE25519:"20f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a":"6a4e9baa8ea9a4ebf41a38260d3abf0d5af73eb4dc7d8b7454a7308909f020":"0":"1":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
+
+ECP read binary #10 (Curve25519, non-canonical)
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_read_binary:MBEDTLS_ECP_DP_CURVE25519:"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f":"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff":"0":"1":0
+
+ECP read binary #11 (Curve25519, masked non-canonical)
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_read_binary:MBEDTLS_ECP_DP_CURVE25519:"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff":"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff":"0":"1":0
+
+ECP read binary #12 (Curve25519, too long)
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+ecp_read_binary:MBEDTLS_ECP_DP_CURVE25519:"8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a00":"6a4e9baa8ea9a4ebf41a38260d3abf0d5af73eb4dc7d8b7454a7308909f02085":"0":"1":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
+
 ECP tls read point #1 (zero, invalid length byte)
 depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
 mbedtls_ecp_tls_read_point:MBEDTLS_ECP_DP_SECP192R1:"0200":"01":"01":"00":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
@@ -244,6 +276,68 @@
 depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
 mbedtls_ecp_gen_key:MBEDTLS_ECP_DP_SECP192R1
 
+ECP read key #1 (short weierstrass, too small)
+depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
+mbedtls_ecp_read_key:MBEDTLS_ECP_DP_SECP192R1:"00":MBEDTLS_ERR_ECP_INVALID_KEY
+
+ECP read key #2 (short weierstrass, smallest)
+depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
+mbedtls_ecp_read_key:MBEDTLS_ECP_DP_SECP192R1:"01":0
+
+ECP read key #3 (short weierstrass, biggest)
+depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
+mbedtls_ecp_read_key:MBEDTLS_ECP_DP_SECP192R1:"FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22830":0
+
+ECP read key #4 (short weierstrass, too big)
+depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
+mbedtls_ecp_read_key:MBEDTLS_ECP_DP_SECP192R1:"FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831":MBEDTLS_ERR_ECP_INVALID_KEY
+
+ECP read key #5 (Curve25519, most significant bit set)
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"000000000000000000000000000000000000000000000000000000000000000C":0
+
+ECP read key #6 (Curve25519, second most significant bit unset)
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3":0
+
+ECP read key #7 (Curve25519, msb OK)
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"0000000000000000000000000000000000000000000000000000000000000004":0
+
+ECP read key #8 (Curve25519, bit 0 set)
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"1000000000000000000000000000000000000000000000000000000000000000":0
+
+ECP read key #9 (Curve25519, bit 1 set)
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"2000000000000000000000000000000000000000000000000000000000000004":0
+
+ECP read key #10 (Curve25519, bit 2 set)
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"4000000000000000000000000000000000000000000000000000000000000004":0
+
+ECP read key #11 (Curve25519, OK)
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7":0
+
+ECP read key #12 (Curve25519, too long)
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"00000000000000000000000000000000000000000000000000000000000000000C":MBEDTLS_ERR_ECP_INVALID_KEY
+
+ECP read key #13 (Curve25519, not long enough)
+depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED
+mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3":MBEDTLS_ERR_ECP_INVALID_KEY
+
+ECP read key #14 (Curve448, not supported)
+mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE448:"FCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE
+
+ECP read key #15 (Curve25519, not supported)
+depends_on:!MBEDTLS_ECP_DP_CURVE25519_ENABLED
+mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE
+
+ECP read key #15 (invalid curve)
+mbedtls_ecp_read_key:INT_MAX:"8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE
+
 ECP mod p192 small (more than 192 bits, less limbs than 2 * 192 bits)
 depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED
 ecp_fast_mod:MBEDTLS_ECP_DP_SECP192R1:"0100000000000103010000000000010201000000000001010100000000000100"
diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function
index 606ddd2..7eeea28 100644
--- a/tests/suites/test_suite_ecp.function
+++ b/tests/suites/test_suite_ecp.function
@@ -43,7 +43,9 @@
     unsigned char buf[42] = { 0 };
     const unsigned char *null_buf = NULL;
     mbedtls_ecp_group_id valid_group = MBEDTLS_ECP_DP_SECP192R1;
+#if defined(MBEDTLS_ECP_RESTARTABLE)
     mbedtls_ecp_restart_ctx restart_ctx;
+#endif /* MBEDTLS_ECP_RESTARTABLE */
 
     TEST_INVALID_PARAM( mbedtls_ecp_point_init( NULL ) );
     TEST_INVALID_PARAM( mbedtls_ecp_keypair_init( NULL ) );
@@ -760,8 +762,18 @@
     if( ret == 0 )
     {
         TEST_ASSERT( mbedtls_mpi_cmp_mpi( &P.X, &X ) == 0 );
-        TEST_ASSERT( mbedtls_mpi_cmp_mpi( &P.Y, &Y ) == 0 );
-        TEST_ASSERT( mbedtls_mpi_cmp_mpi( &P.Z, &Z ) == 0 );
+        if( mbedtls_ecp_get_type( &grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY )
+        {
+            TEST_ASSERT( mbedtls_mpi_cmp_int( &Y, 0 ) == 0 );
+            TEST_ASSERT( P.Y.p == NULL );
+            TEST_ASSERT( mbedtls_mpi_cmp_int( &Z, 1 ) == 0 );
+            TEST_ASSERT( mbedtls_mpi_cmp_int( &P.Z, 1 ) == 0 );
+        }
+        else
+        {
+            TEST_ASSERT( mbedtls_mpi_cmp_mpi( &P.Y, &Y ) == 0 );
+            TEST_ASSERT( mbedtls_mpi_cmp_mpi( &P.Z, &Z ) == 0 );
+        }
     }
 
 exit:
@@ -1006,6 +1018,28 @@
 }
 /* END_CASE */
 
+/* BEGIN_CASE */
+void mbedtls_ecp_read_key( int grp_id, data_t* in_key, int expected )
+{
+    int ret = 0;
+    mbedtls_ecp_keypair key;
+
+    mbedtls_ecp_keypair_init( &key );
+
+    ret = mbedtls_ecp_read_key( grp_id, &key, in_key->x, in_key->len );
+    TEST_ASSERT( ret == expected );
+
+    if( expected == 0 )
+    {
+        ret = mbedtls_ecp_check_privkey( &key.grp, &key.d );
+        TEST_ASSERT( ret == 0 );
+    }
+
+exit:
+    mbedtls_ecp_keypair_free( &key );
+}
+/* END_CASE */
+
 /* BEGIN_CASE depends_on:MBEDTLS_SELF_TEST */
 void ecp_selftest(  )
 {
diff --git a/tests/suites/test_suite_hkdf.function b/tests/suites/test_suite_hkdf.function
index c85a51a..3e87207 100644
--- a/tests/suites/test_suite_hkdf.function
+++ b/tests/suites/test_suite_hkdf.function
@@ -14,12 +14,16 @@
 {
     int ret;
     size_t ikm_len, salt_len, info_len, okm_len;
-    unsigned char ikm[1024] = { '\0' };
-    unsigned char salt[1024] = { '\0' };
-    unsigned char info[1024] = { '\0' };
-    unsigned char expected_okm[1024] = { '\0' };
-    unsigned char okm[1024] = { '\0' };
-    unsigned char okm_string[1000] = { '\0' };
+    unsigned char ikm[128] = { '\0' };
+    unsigned char salt[128] = { '\0' };
+    unsigned char info[128] = { '\0' };
+    unsigned char expected_okm[128] = { '\0' };
+    unsigned char okm[128] = { '\0' };
+    /*
+     * okm_hex is the string representation of okm,
+     * so its size is twice the size of okm, and an extra null-termination.
+     */
+    unsigned char okm_hex[257] = { '\0' };
 
     const mbedtls_md_info_t *md = mbedtls_md_info_from_type( md_alg );
     TEST_ASSERT( md != NULL );
@@ -34,8 +38,8 @@
     TEST_ASSERT( ret == 0 );
 
     // Run hexify on it so that it looks nicer if the assertion fails
-    hexify( okm_string, okm, okm_len );
-    TEST_ASSERT( !strcmp( (char *)okm_string, hex_okm_string ) );
+    hexify( okm_hex, okm, okm_len );
+    TEST_ASSERT( !strcmp( (char *)okm_hex, hex_okm_string ) );
 }
 /* END_CASE */
 
diff --git a/tests/suites/test_suite_mpi.data b/tests/suites/test_suite_mpi.data
index 8b5f97d..3eebcff 100644
--- a/tests/suites/test_suite_mpi.data
+++ b/tests/suites/test_suite_mpi.data
@@ -25,6 +25,9 @@
 Base test mpi_read_write_string #3 (Negative decimal)
 mpi_read_write_string:16:"-23":16:"-23":100:0:0
 
+Base test mpi_read_write_string #4 (Buffer just fits)
+mpi_read_write_string:16:"-4":4:"-10":4:0:0
+
 Test mpi_read_write_string #1 (Invalid character)
 mpi_read_write_string:10:"a28":0:"":100:MBEDTLS_ERR_MPI_INVALID_CHARACTER:0
 
@@ -58,6 +61,9 @@
 Base test mbedtls_mpi_read_binary #1
 mbedtls_mpi_read_binary:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":10:"56125680981752282334141896320372489490613963693556392520816017892111350604111697682705498319512049040516698827829292076808006940873974979584527073481012636016353913462376755556720019831187364993587901952757307830896531678727717924"
 
+Base test mbedtls_mpi_read_binary_le #1
+mbedtls_mpi_read_binary_le:"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":10:"219946662473865722255717126709915431768051735954189829340600976826409773245337023925691629251672268961177825243440202069039100741562168093042339401187848509859789949044607421190014088260008793380554914226244485299326152319899746569"
+
 Base test mbedtls_mpi_write_binary #1
 mbedtls_mpi_write_binary:10:"56125680981752282334141896320372489490613963693556392520816017892111350604111697682705498319512049040516698827829292076808006940873974979584527073481012636016353913462376755556720019831187364993587901952757307830896531678727717924":"0941379d00fed1491fe15df284dfde4a142f68aa8d412023195cee66883e6290ffe703f4ea5963bf212713cee46b107c09182b5edcd955adac418bf4918e2889af48e1099d513830cec85c26ac1e158b52620e33ba8692f893efbb2f958b4424":200:0
 
@@ -67,6 +73,15 @@
 Test mbedtls_mpi_write_binary #2 (Buffer too small)
 mbedtls_mpi_write_binary:16:"123123123123123123123123123":"23123123123123123123123123":13:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL
 
+Base test mbedtls_mpi_write_binary_le #1
+mbedtls_mpi_write_binary_le:10:"56125680981752282334141896320372489490613963693556392520816017892111350604111697682705498319512049040516698827829292076808006940873974979584527073481012636016353913462376755556720019831187364993587901952757307830896531678727717924":"24448b952fbbef93f89286ba330e62528b151eac265cc8ce3038519d09e148af89288e91f48b41acad55d9dc5e2b18097c106be4ce132721bf6359eaf403e7ff90623e8866ee5c192320418daa682f144adedf84f25de11f49d1fe009d374109":200:0
+
+Test mbedtls_mpi_write_binary_le #1 (Buffer just fits)
+mbedtls_mpi_write_binary_le:16:"123123123123123123123123123":"2331122331122331122331122301":14:0
+
+Test mbedtls_mpi_write_binary_le #2 (Buffer too small)
+mbedtls_mpi_write_binary_le:16:"123123123123123123123123123":"23311223311223311223311223":13:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL
+
 Base test mbedtls_mpi_read_file #1
 mbedtls_mpi_read_file:10:"data_files/mpi_10":"01f55332c3a48b910f9942f6c914e58bef37a47ee45cb164a5b6b8d1006bf59a059c21449939ebebfdf517d2e1dbac88010d7b1f141e997bd6801ddaec9d05910f4f2de2b2c4d714e2c14a72fc7f17aa428d59c531627f09":0
 
diff --git a/tests/suites/test_suite_mpi.function b/tests/suites/test_suite_mpi.function
index d1fa5a4..eaae196 100644
--- a/tests/suites/test_suite_mpi.function
+++ b/tests/suites/test_suite_mpi.function
@@ -294,6 +294,8 @@
 
     mbedtls_mpi_init( &X );
 
+    memset( str, '!', sizeof( str ) );
+
     TEST_ASSERT( mbedtls_mpi_read_string( &X, radix_X, input_X ) == result_read );
     if( result_read == 0 )
     {
@@ -301,6 +303,7 @@
         if( result_write == 0 )
         {
             TEST_ASSERT( strcasecmp( str, input_A ) == 0 );
+            TEST_ASSERT( str[len] == '!' );
         }
     }
 
@@ -313,14 +316,33 @@
 void mbedtls_mpi_read_binary( data_t * buf, int radix_A, char * input_A )
 {
     mbedtls_mpi X;
-    unsigned char str[1000];
+    char str[1000];
     size_t len;
 
     mbedtls_mpi_init( &X );
 
 
     TEST_ASSERT( mbedtls_mpi_read_binary( &X, buf->x, buf->len ) == 0 );
-    TEST_ASSERT( mbedtls_mpi_write_string( &X, radix_A, (char *) str, sizeof( str ), &len ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_write_string( &X, radix_A, str, sizeof( str ), &len ) == 0 );
+    TEST_ASSERT( strcmp( (char *) str, input_A ) == 0 );
+
+exit:
+    mbedtls_mpi_free( &X );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void mbedtls_mpi_read_binary_le( data_t * buf, int radix_A, char * input_A )
+{
+    mbedtls_mpi X;
+    char str[1000];
+    size_t len;
+
+    mbedtls_mpi_init( &X );
+
+
+    TEST_ASSERT( mbedtls_mpi_read_binary_le( &X, buf->x, buf->len ) == 0 );
+    TEST_ASSERT( mbedtls_mpi_write_string( &X, radix_A, str, sizeof( str ), &len ) == 0 );
     TEST_ASSERT( strcmp( (char *) str, input_A ) == 0 );
 
 exit:
@@ -359,6 +381,37 @@
 }
 /* END_CASE */
 
+/* BEGIN_CASE */
+void mbedtls_mpi_write_binary_le( int radix_X, char * input_X,
+                                  data_t * input_A, int output_size,
+                                  int result )
+{
+    mbedtls_mpi X;
+    unsigned char buf[1000];
+    size_t buflen;
+
+    memset( buf, 0x00, 1000 );
+
+    mbedtls_mpi_init( &X );
+
+    TEST_ASSERT( mbedtls_mpi_read_string( &X, radix_X, input_X ) == 0 );
+
+    buflen = mbedtls_mpi_size( &X );
+    if( buflen > (size_t) output_size )
+        buflen = (size_t) output_size;
+
+    TEST_ASSERT( mbedtls_mpi_write_binary_le( &X, buf, buflen ) == result );
+    if( result == 0)
+    {
+
+        TEST_ASSERT( hexcmp( buf, input_A->x, buflen, input_A->len ) == 0 );
+    }
+
+exit:
+    mbedtls_mpi_free( &X );
+}
+/* END_CASE */
+
 /* BEGIN_CASE depends_on:MBEDTLS_FS_IO */
 void mbedtls_mpi_read_file( int radix_X, char * input_file,
                             data_t * input_A, int result )
diff --git a/tests/suites/test_suite_oid.data b/tests/suites/test_suite_oid.data
new file mode 100644
index 0000000..759a010
--- /dev/null
+++ b/tests/suites/test_suite_oid.data
@@ -0,0 +1,8 @@
+OID get Any Policy certificate policy
+oid_get_certificate_policies:"551D2000":"Any Policy"
+
+OID get certificate policy invalid oid
+oid_get_certificate_policies:"5533445566":""
+
+OID get certificate policy wrong oid - id-ce-authorityKeyIdentifier
+oid_get_certificate_policies:"551D23":""
diff --git a/tests/suites/test_suite_oid.function b/tests/suites/test_suite_oid.function
new file mode 100644
index 0000000..e95e48d
--- /dev/null
+++ b/tests/suites/test_suite_oid.function
@@ -0,0 +1,34 @@
+/* BEGIN_HEADER */
+#include "mbedtls/oid.h"
+#include "mbedtls/asn1.h"
+#include "mbedtls/asn1write.h"
+#include "string.h"
+/* END_HEADER */
+
+/* BEGIN_DEPENDENCIES
+ * depends_on:MBEDTLS_OID_C
+ * END_DEPENDENCIES
+ */
+
+/* BEGIN_CASE depends_on:MBEDTLS_ASN1_WRITE_C*/
+void oid_get_certificate_policies( data_t * oid, char * result_str )
+{
+    mbedtls_asn1_buf asn1_buf = { 0, 0, NULL };
+    int ret;
+    const char *desc;
+
+    asn1_buf.tag = MBEDTLS_ASN1_OID;
+    asn1_buf.p = oid->x;
+    asn1_buf.len = oid->len;
+
+    ret = mbedtls_oid_get_certificate_policies( &asn1_buf, &desc );
+    if( strlen( result_str ) == 0 )
+    {
+        TEST_ASSERT( ret == MBEDTLS_ERR_OID_NOT_FOUND );
+    }
+    else
+    {
+        TEST_ASSERT( strcmp( ( char* )desc, result_str ) == 0 );
+    }
+}
+/* END_CASE */
diff --git a/tests/suites/test_suite_pkcs1_v15.data b/tests/suites/test_suite_pkcs1_v15.data
index a4d6eb5..b4cf09a 100644
--- a/tests/suites/test_suite_pkcs1_v15.data
+++ b/tests/suites/test_suite_pkcs1_v15.data
@@ -1,3 +1,9 @@
+RSAES-V15 Encryption input=NULL with length=0
+pkcs1_rsaes_v15_encrypt:1024:16:"bbf82f090682ce9c2338ac2b9da871f7368d07eed41043a440d6b6f07454f51fb8dfbaaf035c02ab61ea48ceeb6fcd4876ed520d60e1ec4619719d8a5b8b807fafb8e0a3dfc737723ee6b4b7d93a2584ee6a649d060953748834b2454598394ee0aab12d7b61a51f527a9a41f6c1687fe2537298ca2a8f5946f8e5fd091dbdcb":16:"11":MBEDTLS_MD_NONE:"":"aafd12f659cae63489b479e5076ddec2f06cb58f67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb3267c6697351ff4aec29cdbaabf2fbe34676cac0":"42c6fce63a3b858ba89fe83004cac3651d1497c15090bf0086b9a4b9ff3bd451502838a413095aefe231832ba10bb467ae3f95c889cd8e9a6e32b4df633b2170d07a2168c086745f0017cf1d9facff2eee55af2fcb03730209173b2a0bbfb2d4c34d7ea93b3b0cb84a8a7b6371670e14482e6dcedbdd9efe66d906e0238586fe":0
+
+RSAES-V15 Decryption empty output with NULL buffer
+pkcs1_rsaes_v15_decrypt:1024:16:"eecfae81b1b9b3c908810b10a1b5600199eb9f44aef4fda493b81a9e3d84f632124ef0236e5d1e3b7e28fae7aa040a2d5b252176459d1f397541ba2a58fb6599":16:"c97fb1f027f453f6341233eaaad1d9353f6c42d08866b1d05a0f2035028b9d869840b41666b42e92ea0da3b43204b5cfce3352524d0416a5a441e700af461503":16:"bbf82f090682ce9c2338ac2b9da871f7368d07eed41043a440d6b6f07454f51fb8dfbaaf035c02ab61ea48ceeb6fcd4876ed520d60e1ec4619719d8a5b8b807fafb8e0a3dfc737723ee6b4b7d93a2584ee6a649d060953748834b2454598394ee0aab12d7b61a51f527a9a41f6c1687fe2537298ca2a8f5946f8e5fd091dbdcb":16:"11":MBEDTLS_MD_NONE:"":"aafd12f659cae63489b479e5076ddec2f06cb58f":"42c6fce63a3b858ba89fe83004cac3651d1497c15090bf0086b9a4b9ff3bd451502838a413095aefe231832ba10bb467ae3f95c889cd8e9a6e32b4df633b2170d07a2168c086745f0017cf1d9facff2eee55af2fcb03730209173b2a0bbfb2d4c34d7ea93b3b0cb84a8a7b6371670e14482e6dcedbdd9efe66d906e0238586fe":0
+
 RSAES-V15 Encryption Test Vector Int
 pkcs1_rsaes_v15_encrypt:1024:16:"bbf82f090682ce9c2338ac2b9da871f7368d07eed41043a440d6b6f07454f51fb8dfbaaf035c02ab61ea48ceeb6fcd4876ed520d60e1ec4619719d8a5b8b807fafb8e0a3dfc737723ee6b4b7d93a2584ee6a649d060953748834b2454598394ee0aab12d7b61a51f527a9a41f6c1687fe2537298ca2a8f5946f8e5fd091dbdcb":16:"11":MBEDTLS_MD_SHA1:"d436e99569fd32a7c8a05bbc90d32c49":"aafd12f659cae63489b479e5076ddec2f06cb58f67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb32":"6c5ebca6116b1e91316613fbb5e93197270a849122d549122d05815e2626f80d20f7f3f038c98295203c0f7f6bb8c3568455c67dec82bca86be86eff43b56b7ba2d15375f9a42454c2a2c709953a6e4a977462e35fd21a9c2fb3c0ad2a370f7655267bf6f04814784982988e663b869fc8588475af860d499e5a6ffdfc2c6bfd":0
 
diff --git a/tests/suites/test_suite_pkcs1_v15.function b/tests/suites/test_suite_pkcs1_v15.function
index 0723623..3ef4e2c 100644
--- a/tests/suites/test_suite_pkcs1_v15.function
+++ b/tests/suites/test_suite_pkcs1_v15.function
@@ -32,11 +32,11 @@
     TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( ( mod + 7 ) / 8 ) );
     TEST_ASSERT( mbedtls_rsa_check_pubkey( &ctx ) == 0 );
 
-
+    if( message_str->len == 0 )
+        message_str->x = NULL;
     TEST_ASSERT( mbedtls_rsa_pkcs1_encrypt( &ctx, &rnd_buffer_rand, &info, MBEDTLS_RSA_PUBLIC, message_str->len, message_str->x, output ) == result );
     if( result == 0 )
     {
-
         TEST_ASSERT( hexcmp( output, result_hex_str->x, ctx.len, result_hex_str->len ) == 0 );
     }
 
@@ -78,12 +78,17 @@
     TEST_ASSERT( mbedtls_rsa_complete( &ctx ) == 0 );
     TEST_ASSERT( mbedtls_rsa_check_privkey( &ctx ) == 0 );
 
-
-    TEST_ASSERT( mbedtls_rsa_pkcs1_decrypt( &ctx, &rnd_pseudo_rand, &rnd_info, MBEDTLS_RSA_PRIVATE, &output_len, message_str->x, output, 1000 ) == result );
-    if( result == 0 )
+    if( result_hex_str->len == 0 )
     {
-
-        TEST_ASSERT( hexcmp( output, result_hex_str->x, output_len, result_hex_str->len) == 0 );
+        TEST_ASSERT( mbedtls_rsa_pkcs1_decrypt( &ctx, &rnd_pseudo_rand, &rnd_info, MBEDTLS_RSA_PRIVATE, &output_len, message_str->x, NULL, 0 ) == result );
+    }
+    else
+    {
+        TEST_ASSERT( mbedtls_rsa_pkcs1_decrypt( &ctx, &rnd_pseudo_rand, &rnd_info, MBEDTLS_RSA_PRIVATE, &output_len, message_str->x, output, 1000 ) == result );
+        if( result == 0 )
+        {
+            TEST_ASSERT( hexcmp( output, result_hex_str->x, output_len, result_hex_str->len) == 0 );
+        }
     }
 
 exit:
diff --git a/tests/suites/test_suite_pkcs1_v21.data b/tests/suites/test_suite_pkcs1_v21.data
index 291c305..012867c 100644
--- a/tests/suites/test_suite_pkcs1_v21.data
+++ b/tests/suites/test_suite_pkcs1_v21.data
@@ -187,6 +187,10 @@
 RSAES-OAEP Encryption Example 10_6
 pkcs1_rsaes_oaep_encrypt:2048:16:"ae45ed5601cec6b8cc05f803935c674ddbe0d75c4c09fd7951fc6b0caec313a8df39970c518bffba5ed68f3f0d7f22a4029d413f1ae07e4ebe9e4177ce23e7f5404b569e4ee1bdcf3c1fb03ef113802d4f855eb9b5134b5a7c8085adcae6fa2fa1417ec3763be171b0c62b760ede23c12ad92b980884c641f5a8fac26bdad4a03381a22fe1b754885094c82506d4019a535a286afeb271bb9ba592de18dcf600c2aeeae56e02f7cf79fc14cf3bdc7cd84febbbf950ca90304b2219a7aa063aefa2c3c1980e560cd64afe779585b6107657b957857efde6010988ab7de417fc88d8f384c4e6e72c3f943e0c31c0c4a5cc36f879d8a3ac9d7d59860eaada6b83bb":16:"010001":MBEDTLS_MD_SHA1:"eaf1a73a1b0c4609537de69cd9228bbcfb9a8ca8c6c3efaf056fe4a7f4634ed00b7c39ec6922d7b8ea2c04ebac":"9f47ddf42e97eea856a9bdbc714eb3ac22f6eb32":"2d207a73432a8fb4c03051b3f73b28a61764098dfa34c47a20995f8115aa6816679b557e82dbee584908c6e69782d7deb34dbd65af063d57fca76a5fd069492fd6068d9984d209350565a62e5c77f23038c12cb10c6634709b547c46f6b4a709bd85ca122d74465ef97762c29763e06dbc7a9e738c78bfca0102dc5e79d65b973f28240caab2e161a78b57d262457ed8195d53e3c7ae9da021883c6db7c24afdd2322eac972ad3c354c5fcef1e146c3a0290fb67adf007066e00428d2cec18ce58f9328698defef4b2eb5ec76918fde1c198cbb38b7afc67626a9aefec4322bfd90d2563481c9a221f78c8272c82d1b62ab914e1c69f6af6ef30ca5260db4a46":0
 
+RSAES-OAEP Encryption input=NULL with length=0
+depends_on:MBEDTLS_SHA1_C
+pkcs1_rsaes_oaep_encrypt:2048:16:"ae45ed5601cec6b8cc05f803935c674ddbe0d75c4c09fd7951fc6b0caec313a8df39970c518bffba5ed68f3f0d7f22a4029d413f1ae07e4ebe9e4177ce23e7f5404b569e4ee1bdcf3c1fb03ef113802d4f855eb9b5134b5a7c8085adcae6fa2fa1417ec3763be171b0c62b760ede23c12ad92b980884c641f5a8fac26bdad4a03381a22fe1b754885094c82506d4019a535a286afeb271bb9ba592de18dcf600c2aeeae56e02f7cf79fc14cf3bdc7cd84febbbf950ca90304b2219a7aa063aefa2c3c1980e560cd64afe779585b6107657b957857efde6010988ab7de417fc88d8f384c4e6e72c3f943e0c31c0c4a5cc36f879d8a3ac9d7d59860eaada6b83bb":16:"010001":MBEDTLS_MD_SHA1:"":"9f47ddf42e97eea856a9bdbc714eb3ac22f6eb32":"32b75304e631e94d4b02819642c7ffa66116af504cb3c4687420cc4b7f069fc6cc3b1a254611995ce2914a9e88152d38bbf87ccedcad9b9890341284e56e802a1b1f8f6bd3d5c991bd92eb8a8ea0a1d8bae141088ff8dceaebdb73515cf06ce33baa37c53093f1d1edc3502818cc70edcfddb41646374beb5b4f67f7f773e43778d4d31012e5a207c474e762ac3251ea6ede9018ad6e8e9ea65a3528a62b694eb9d8becff220a7c6c70d33eaafa52cf67a8090f67b6f9c43c6fe0b0f2375cbb9e611c0fcfef5312feb5e53d4a89d3d7e06c966e0c92ab9e5838239f390bcfd918d94c224df8e8ccb57ee364389908b6a0e550133f7565016804fbd6cb338314a":0
+
 RSAES-OAEP Decryption Test Vector Int
 pkcs1_rsaes_oaep_decrypt:1024:16:"eecfae81b1b9b3c908810b10a1b5600199eb9f44aef4fda493b81a9e3d84f632124ef0236e5d1e3b7e28fae7aa040a2d5b252176459d1f397541ba2a58fb6599":16:"c97fb1f027f453f6341233eaaad1d9353f6c42d08866b1d05a0f2035028b9d869840b41666b42e92ea0da3b43204b5cfce3352524d0416a5a441e700af461503":16:"bbf82f090682ce9c2338ac2b9da871f7368d07eed41043a440d6b6f07454f51fb8dfbaaf035c02ab61ea48ceeb6fcd4876ed520d60e1ec4619719d8a5b8b807fafb8e0a3dfc737723ee6b4b7d93a2584ee6a649d060953748834b2454598394ee0aab12d7b61a51f527a9a41f6c1687fe2537298ca2a8f5946f8e5fd091dbdcb":16:"11":MBEDTLS_MD_SHA1:"d436e99569fd32a7c8a05bbc90d32c49":"aafd12f659cae63489b479e5076ddec2f06cb58f":"1253e04dc0a5397bb44a7ab87e9bf2a039a33d1e996fc82a94ccd30074c95df763722017069e5268da5d1c0b4f872cf653c11df82314a67968dfeae28def04bb6d84b1c31d654a1970e5783bd6eb96a024c2ca2f4a90fe9f2ef5c9c140e5bb48da9536ad8700c84fc9130adea74e558d51a74ddf85d8b50de96838d6063e0955":0
 
@@ -370,6 +374,10 @@
 RSAES-OAEP Decryption Example 10_6
 pkcs1_rsaes_oaep_decrypt:2048:16:"ecf5aecd1e5515fffacbd75a2816c6ebf49018cdfb4638e185d66a7396b6f8090f8018c7fd95cc34b857dc17f0cc6516bb1346ab4d582cadad7b4103352387b70338d084047c9d9539b6496204b3dd6ea442499207bec01f964287ff6336c3984658336846f56e46861881c10233d2176bf15a5e96ddc780bc868aa77d3ce769":16:"bc46c464fc6ac4ca783b0eb08a3c841b772f7e9b2f28babd588ae885e1a0c61e4858a0fb25ac299990f35be85164c259ba1175cdd7192707135184992b6c29b746dd0d2cabe142835f7d148cc161524b4a09946d48b828473f1ce76b6cb6886c345c03e05f41d51b5c3a90a3f24073c7d74a4fe25d9cf21c75960f3fc3863183":16:"ae45ed5601cec6b8cc05f803935c674ddbe0d75c4c09fd7951fc6b0caec313a8df39970c518bffba5ed68f3f0d7f22a4029d413f1ae07e4ebe9e4177ce23e7f5404b569e4ee1bdcf3c1fb03ef113802d4f855eb9b5134b5a7c8085adcae6fa2fa1417ec3763be171b0c62b760ede23c12ad92b980884c641f5a8fac26bdad4a03381a22fe1b754885094c82506d4019a535a286afeb271bb9ba592de18dcf600c2aeeae56e02f7cf79fc14cf3bdc7cd84febbbf950ca90304b2219a7aa063aefa2c3c1980e560cd64afe779585b6107657b957857efde6010988ab7de417fc88d8f384c4e6e72c3f943e0c31c0c4a5cc36f879d8a3ac9d7d59860eaada6b83bb":16:"010001":MBEDTLS_MD_SHA1:"eaf1a73a1b0c4609537de69cd9228bbcfb9a8ca8c6c3efaf056fe4a7f4634ed00b7c39ec6922d7b8ea2c04ebac":"9f47ddf42e97eea856a9bdbc714eb3ac22f6eb32":"2d207a73432a8fb4c03051b3f73b28a61764098dfa34c47a20995f8115aa6816679b557e82dbee584908c6e69782d7deb34dbd65af063d57fca76a5fd069492fd6068d9984d209350565a62e5c77f23038c12cb10c6634709b547c46f6b4a709bd85ca122d74465ef97762c29763e06dbc7a9e738c78bfca0102dc5e79d65b973f28240caab2e161a78b57d262457ed8195d53e3c7ae9da021883c6db7c24afdd2322eac972ad3c354c5fcef1e146c3a0290fb67adf007066e00428d2cec18ce58f9328698defef4b2eb5ec76918fde1c198cbb38b7afc67626a9aefec4322bfd90d2563481c9a221f78c8272c82d1b62ab914e1c69f6af6ef30ca5260db4a46":0
 
+RSAES-OAEP Decryption empty output with NULL buffer
+depends_on:MBEDTLS_SHA1_C
+pkcs1_rsaes_oaep_decrypt:2048:16:"ecf5aecd1e5515fffacbd75a2816c6ebf49018cdfb4638e185d66a7396b6f8090f8018c7fd95cc34b857dc17f0cc6516bb1346ab4d582cadad7b4103352387b70338d084047c9d9539b6496204b3dd6ea442499207bec01f964287ff6336c3984658336846f56e46861881c10233d2176bf15a5e96ddc780bc868aa77d3ce769":16:"bc46c464fc6ac4ca783b0eb08a3c841b772f7e9b2f28babd588ae885e1a0c61e4858a0fb25ac299990f35be85164c259ba1175cdd7192707135184992b6c29b746dd0d2cabe142835f7d148cc161524b4a09946d48b828473f1ce76b6cb6886c345c03e05f41d51b5c3a90a3f24073c7d74a4fe25d9cf21c75960f3fc3863183":16:"ae45ed5601cec6b8cc05f803935c674ddbe0d75c4c09fd7951fc6b0caec313a8df39970c518bffba5ed68f3f0d7f22a4029d413f1ae07e4ebe9e4177ce23e7f5404b569e4ee1bdcf3c1fb03ef113802d4f855eb9b5134b5a7c8085adcae6fa2fa1417ec3763be171b0c62b760ede23c12ad92b980884c641f5a8fac26bdad4a03381a22fe1b754885094c82506d4019a535a286afeb271bb9ba592de18dcf600c2aeeae56e02f7cf79fc14cf3bdc7cd84febbbf950ca90304b2219a7aa063aefa2c3c1980e560cd64afe779585b6107657b957857efde6010988ab7de417fc88d8f384c4e6e72c3f943e0c31c0c4a5cc36f879d8a3ac9d7d59860eaada6b83bb":16:"010001":MBEDTLS_MD_SHA1:"":"9f47ddf42e97eea856a9bdbc714eb3ac22f6eb32":"32b75304e631e94d4b02819642c7ffa66116af504cb3c4687420cc4b7f069fc6cc3b1a254611995ce2914a9e88152d38bbf87ccedcad9b9890341284e56e802a1b1f8f6bd3d5c991bd92eb8a8ea0a1d8bae141088ff8dceaebdb73515cf06ce33baa37c53093f1d1edc3502818cc70edcfddb41646374beb5b4f67f7f773e43778d4d31012e5a207c474e762ac3251ea6ede9018ad6e8e9ea65a3528a62b694eb9d8becff220a7c6c70d33eaafa52cf67a8090f67b6f9c43c6fe0b0f2375cbb9e611c0fcfef5312feb5e53d4a89d3d7e06c966e0c92ab9e5838239f390bcfd918d94c224df8e8ccb57ee364389908b6a0e550133f7565016804fbd6cb338314a":0
+
 RSASSA-PSS Signing Test Vector Int
 pkcs1_rsassa_pss_sign:1024:16:"d17f655bf27c8b16d35462c905cc04a26f37e2a67fa9c0ce0dced472394a0df743fe7f929e378efdb368eddff453cf007af6d948e0ade757371f8a711e278f6b":16:"c6d92b6fee7414d1358ce1546fb62987530b90bd15e0f14963a5e2635adb69347ec0c01b2ab1763fd8ac1a592fb22757463a982425bb97a3a437c5bf86d03f2f":16:"a2ba40ee07e3b2bd2f02ce227f36a195024486e49c19cb41bbbdfbba98b22b0e577c2eeaffa20d883a76e65e394c69d4b3c05a1e8fadda27edb2a42bc000fe888b9b32c22d15add0cd76b3e7936e19955b220dd17d4ea904b1ec102b2e4de7751222aa99151024c7cb41cc5ea21d00eeb41f7c800834d2c6e06bce3bce7ea9a5":16:"010001":MBEDTLS_MD_SHA1:MBEDTLS_MD_SHA1:"859eef2fd78aca00308bdc471193bf55bf9d78db8f8a672b484634f3c9c26e6478ae10260fe0dd8c082e53a5293af2173cd50c6d5d354febf78b26021c25c02712e78cd4694c9f469777e451e7f8e9e04cd3739c6bbfedae487fb55644e9ca74ff77a53cb729802f6ed4a5ffa8ba159890fc":"e3b5d5d002c1bce50c2b65ef88a188d83bce7e61":"8daa627d3de7595d63056c7ec659e54406f10610128baae821c8b2a0f3936d54dc3bdce46689f6b7951bb18e840542769718d5715d210d85efbb596192032c42be4c29972c856275eb6d5a45f05f51876fc6743deddd28caec9bb30ea99e02c3488269604fe497f74ccd7c7fca1671897123cbd30def5d54a2b5536ad90a747e":0
 
diff --git a/tests/suites/test_suite_pkcs1_v21.function b/tests/suites/test_suite_pkcs1_v21.function
index 99be08a..180bc4a 100644
--- a/tests/suites/test_suite_pkcs1_v21.function
+++ b/tests/suites/test_suite_pkcs1_v21.function
@@ -32,11 +32,11 @@
     TEST_ASSERT( mbedtls_rsa_get_len( &ctx ) == (size_t) ( ( mod + 7 ) / 8 ) );
     TEST_ASSERT( mbedtls_rsa_check_pubkey( &ctx ) == 0 );
 
-
+    if( message_str->len == 0 )
+        message_str->x = NULL;
     TEST_ASSERT( mbedtls_rsa_pkcs1_encrypt( &ctx, &rnd_buffer_rand, &info, MBEDTLS_RSA_PUBLIC, message_str->len, message_str->x, output ) == result );
     if( result == 0 )
     {
-
         TEST_ASSERT( hexcmp( output, result_hex_str->x, ctx.len, result_hex_str->len ) == 0 );
     }
 
@@ -79,12 +79,17 @@
     TEST_ASSERT( mbedtls_rsa_complete( &ctx ) == 0 );
     TEST_ASSERT( mbedtls_rsa_check_privkey( &ctx ) == 0 );
 
-
-    TEST_ASSERT( mbedtls_rsa_pkcs1_decrypt( &ctx, &rnd_pseudo_rand, &rnd_info, MBEDTLS_RSA_PRIVATE, &output_len, message_str->x, output, 1000 ) == result );
-    if( result == 0 )
+    if( result_hex_str->len == 0 )
     {
-
-        TEST_ASSERT( hexcmp( output, result_hex_str->x, output_len, result_hex_str->len ) == 0 );
+        TEST_ASSERT( mbedtls_rsa_pkcs1_decrypt( &ctx, &rnd_pseudo_rand, &rnd_info, MBEDTLS_RSA_PRIVATE, &output_len, message_str->x, NULL, 0 ) == result );
+    }
+    else
+    {
+        TEST_ASSERT( mbedtls_rsa_pkcs1_decrypt( &ctx, &rnd_pseudo_rand, &rnd_info, MBEDTLS_RSA_PRIVATE, &output_len, message_str->x, output, 1000 ) == result );
+        if( result == 0 )
+        {
+            TEST_ASSERT( hexcmp( output, result_hex_str->x, output_len, result_hex_str->len ) == 0 );
+        }
     }
 
 exit:
diff --git a/tests/suites/test_suite_timing.data b/tests/suites/test_suite_timing.data
index 4dddcf7..2522da1 100644
--- a/tests/suites/test_suite_timing.data
+++ b/tests/suites/test_suite_timing.data
@@ -1,41 +1,17 @@
-Timing: basic timer operation
-timing_timer_simple:
-
-Timing: timer reset
-timing_timer_reset:
-
-Timing: two parallel timers, delay 0
-timing_two_timers:0:
-
-Timing: two parallel timers, delay 100
-timing_two_timers:100:
-
-Timing: two parallel timers, delay 1000
-timing_two_timers:1000:
-
-Timing: two parallel timers, delay 10000
-timing_two_timers:10000:
-
-Timing: delay 0ms, 0ms
-timing_delay:0:0:
-
-Timing: delay 0ms, 50ms
-timing_delay:0:50:
-
-Timing: delay 50ms, 50ms
-timing_delay:50:50:
-
-Timing: delay 50ms, 100ms
-timing_delay:50:100:
-
-Timing: delay 50ms, 200ms
-timing_delay:50:200:
-
-Timing: alarm in 0 second
-timing_alarm:0:
-
-Timing: alarm in 1 second
-timing_alarm:1:
-
 Timing: hardclock
 timing_hardclock:
+
+Timing: get timer
+timing_get_timer:
+
+Timing: set alarm with no delay
+timing_set_alarm:0:
+
+Timing: set alarm with 1s delay
+timing_set_alarm:1:
+
+Timing: delay 0ms
+timing_delay:0:
+
+Timing: delay 100ms
+timing_delay:100:
diff --git a/tests/suites/test_suite_timing.function b/tests/suites/test_suite_timing.function
index 1610155..74dc823 100644
--- a/tests/suites/test_suite_timing.function
+++ b/tests/suites/test_suite_timing.function
@@ -1,51 +1,14 @@
 /* BEGIN_HEADER */
 
-/* This test module exercises the timing module. One of the expected failure
-   modes is for timers to never expire, which could lead to an infinite loop.
-   The function timing_timer_simple is protected against this failure mode and
-   checks that timers do expire. Other functions will terminate if their
-   timers do expire. Therefore it is recommended to run timing_timer_simple
-   first and run other test functions only if that timing_timer_simple
-   succeeded. */
+/* This test module exercises the timing module. Since, depending on the
+ * underlying operating system, the timing routines are not always reliable,
+ * this suite only performs very basic sanity checks of the timing API.
+ */
 
 #include <limits.h>
 
 #include "mbedtls/timing.h"
 
-/* Wait this many milliseconds for a short timing test. This duration
-   should be large enough that, in practice, if you read the timer
-   value twice in a row, it won't have jumped by that much. */
-#define TIMING_SHORT_TEST_MS 100
-
-/* A loop that waits TIMING_SHORT_TEST_MS must not take more than this many
-   iterations. This value needs to be large enough to accommodate fast
-   platforms (e.g. at 4GHz and 10 cycles/iteration a CPU can run through 20
-   million iterations in 50ms). The only motivation to keep this value low is
-   to avoid having an infinite loop if the timer functions are not implemented
-   correctly. Ideally this value should be based on the processor speed but we
-   don't have this information! */
-#define TIMING_SHORT_TEST_ITERATIONS_MAX 1e8
-
-/* alarm(0) must fire in no longer than this amount of time. */
-#define TIMING_ALARM_0_DELAY_MS TIMING_SHORT_TEST_MS
-
-static int expected_delay_status( uint32_t int_ms, uint32_t fin_ms,
-                                  unsigned long actual_ms )
-{
-    return( fin_ms == 0 ? -1 :
-            actual_ms >= fin_ms ? 2 :
-            actual_ms >= int_ms ? 1 :
-            0 );
-}
-
-/* Some conditions in timing_timer_simple suggest that timers are unreliable.
-   Most other test cases rely on timers to terminate, and could loop
-   indefinitely if timers are too broken. So if timing_timer_simple detected a
-   timer that risks not terminating (going backwards, or not reaching the
-   desired count in the alloted clock cycles), set this flag to immediately
-   fail those other tests without running any timers. */
-static int timers_are_badly_broken = 0;
-
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
@@ -54,350 +17,58 @@
  */
 
 /* BEGIN_CASE */
-void timing_timer_simple( )
+void timing_hardclock( )
 {
-    struct mbedtls_timing_hr_time timer;
-    unsigned long millis = 0;
-    unsigned long new_millis = 0;
-    unsigned long iterations = 0;
-    /* Start the timer. */
-    (void) mbedtls_timing_get_timer( &timer, 1 );
-    /* Busy-wait loop for a few milliseconds. */
-    do
-    {
-        new_millis = mbedtls_timing_get_timer( &timer, 0 );
-        ++iterations;
-        /* Check that the timer didn't go backwards */
-        TEST_ASSERT( new_millis >= millis );
-        millis = new_millis;
-    }
-    while( millis < TIMING_SHORT_TEST_MS &&
-           iterations <= TIMING_SHORT_TEST_ITERATIONS_MAX );
-    /* The wait duration should have been large enough for at least a
-       few runs through the loop, even on the slowest realistic platform. */
-    TEST_ASSERT( iterations >= 2 );
-    /* The wait duration shouldn't have overflowed the iteration count. */
-    TEST_ASSERT( iterations < TIMING_SHORT_TEST_ITERATIONS_MAX );
-    return;
-
-exit:
-    if( iterations >= TIMING_SHORT_TEST_ITERATIONS_MAX ||
-        new_millis < millis )
-    {
-        /* The timer was very unreliable: it didn't increment and the loop ran
-           out, or it went backwards. Other tests that use timers might go
-           into an infinite loop, so we'll skip them. */
-        timers_are_badly_broken = 1;
-    }
-
-    /* No cleanup needed, but show some diagnostic iterations, because timing
-       problems can be hard to reproduce. */
-    mbedtls_fprintf( stdout, "  Finished with millis=%lu new_millis=%lu get(timer)<=%lu iterations=%lu\n",
-                     millis, new_millis, mbedtls_timing_get_timer( &timer, 0 ),
-                     iterations );
+    (void) mbedtls_timing_hardclock();
+    /* This goto is added to avoid warnings from the generated code. */
+    goto exit;
 }
 /* END_CASE */
 
 /* BEGIN_CASE */
-void timing_timer_reset( )
+void timing_get_timer( )
 {
-    struct mbedtls_timing_hr_time timer;
-    unsigned long millis = 0;
-    unsigned long iterations = 0;
-
-    /* Skip this test if it looks like timers don't work at all, to avoid an
-       infinite loop below. */
-    TEST_ASSERT( !timers_are_badly_broken );
-
-    /* Start the timer. Timers are always reset to 0. */
-    TEST_ASSERT( mbedtls_timing_get_timer( &timer, 1 ) == 0 );
-    /* Busy-wait loop for a few milliseconds */
-    do
-    {
-        ++iterations;
-        millis = mbedtls_timing_get_timer( &timer, 0 );
-    }
-    while( millis < TIMING_SHORT_TEST_MS );
-
-    /* Reset the timer and check that it has restarted. */
-    TEST_ASSERT( mbedtls_timing_get_timer( &timer, 1 ) == 0 );
-    /* Read the timer immediately after reset. It should be 0 or close
-       to it. */
-    TEST_ASSERT( mbedtls_timing_get_timer( &timer, 0 ) < TIMING_SHORT_TEST_MS );
-    return;
-
-exit:
-    /* No cleanup needed, but show some diagnostic information, because timing
-       problems can be hard to reproduce. */
-    if( !timers_are_badly_broken )
-        mbedtls_fprintf( stdout, "  Finished with millis=%lu get(timer)<=%lu iterations=%lu\n",
-                         millis, mbedtls_timing_get_timer( &timer, 0 ),
-                         iterations );
+    struct mbedtls_timing_hr_time time;
+    (void) mbedtls_timing_get_timer( &time, 1 );
+    (void) mbedtls_timing_get_timer( &time, 0 );
+    /* This goto is added to avoid warnings from the generated code. */
+    goto exit;
 }
 /* END_CASE */
 
 /* BEGIN_CASE */
-void timing_two_timers( int delta )
+void timing_set_alarm( int seconds )
 {
-    struct mbedtls_timing_hr_time timer1, timer2;
-    unsigned long millis1 = 0, millis2 = 0;
-
-    /* Skip this test if it looks like timers don't work at all, to avoid an
-       infinite loop below. */
-    TEST_ASSERT( !timers_are_badly_broken );
-
-    /* Start the first timer and wait for a short time. */
-    (void) mbedtls_timing_get_timer( &timer1, 1 );
-    do
+    if( seconds == 0 )
     {
-        millis1 = mbedtls_timing_get_timer( &timer1, 0 );
-    }
-    while( millis1 < TIMING_SHORT_TEST_MS );
-
-    /* Do a short busy-wait, so that the difference between timer1 and timer2
-       doesn't practically always end up being very close to a whole number of
-       milliseconds. */
-    while( delta > 0 )
-        --delta;
-
-    /* Start the second timer and compare it with the first. */
-    mbedtls_timing_get_timer( &timer2, 1 );
-    do
-    {
-        millis1 = mbedtls_timing_get_timer( &timer1, 0 );
-        millis2 = mbedtls_timing_get_timer( &timer2, 0 );
-        /* The first timer should always be ahead of the first. */
-        TEST_ASSERT( millis1 > millis2 );
-        /* The timers shouldn't drift apart, i.e. millis2-millis1 should stay
-           roughly constant, but this is hard to test reliably, especially in
-           a busy environment such as an overloaded continuous integration
-           system, so we don't test it it. */
-    }
-    while( millis2 < TIMING_SHORT_TEST_MS );
-
-    return;
-
-exit:
-    /* No cleanup needed, but show some diagnostic iterations, because timing
-       problems can be hard to reproduce. */
-    if( !timers_are_badly_broken )
-        mbedtls_fprintf( stdout, "  Finished with millis1=%lu get(timer1)<=%lu millis2=%lu get(timer2)<=%lu\n",
-                         millis1, mbedtls_timing_get_timer( &timer1, 0 ),
-                         millis2, mbedtls_timing_get_timer( &timer2, 0 ) );
-}
-/* END_CASE */
-
-/* BEGIN_CASE */
-void timing_alarm( int seconds )
-{
-    struct mbedtls_timing_hr_time timer;
-    unsigned long millis = 0;
-    /* We check that about the desired number of seconds has elapsed. Be
-       slightly liberal with the lower bound, so as to allow platforms where
-       the alarm (with second resolution) and the timer (with millisecond
-       resolution) are based on different clocks. Be very liberal with the
-       upper bound, because the platform might be busy. */
-    unsigned long millis_min = ( seconds > 0 ?
-                                 seconds * 900 :
-                                 0 );
-    unsigned long millis_max = ( seconds > 0 ?
-                                 seconds * 1100 + 400 :
-                                 TIMING_ALARM_0_DELAY_MS );
-    unsigned long iterations = 0;
-
-    /* Skip this test if it looks like timers don't work at all, to avoid an
-       infinite loop below. */
-    TEST_ASSERT( !timers_are_badly_broken );
-
-    /* Set an alarm and count how long it takes with a timer. */
-    (void) mbedtls_timing_get_timer( &timer, 1 );
-    mbedtls_set_alarm( seconds );
-
-    if( seconds > 0 )
-    {
-        /* We set the alarm for at least 1 second. It should not have fired
-           immediately, even on a slow and busy platform. */
-        TEST_ASSERT( !mbedtls_timing_alarmed );
-    }
-    /* A 0-second alarm should fire quickly, but we don't guarantee that it
-       fires immediately, so mbedtls_timing_alarmed may or may not be set at
-       this point. */
-
-    /* Busy-wait until the alarm rings */
-    do
-    {
-        ++iterations;
-        millis = mbedtls_timing_get_timer( &timer, 0 );
-    }
-    while( !mbedtls_timing_alarmed && millis <= millis_max );
-
-    TEST_ASSERT( mbedtls_timing_alarmed );
-    TEST_ASSERT( millis >= millis_min );
-    TEST_ASSERT( millis <= millis_max );
-
-    mbedtls_timing_alarmed = 0;
-    return;
-
-exit:
-    /* Show some diagnostic iterations, because timing
-       problems can be hard to reproduce. */
-    if( !timers_are_badly_broken )
-        mbedtls_fprintf( stdout, "  Finished with alarmed=%d millis=%lu get(timer)<=%lu iterations=%lu\n",
-                         mbedtls_timing_alarmed,
-                         millis, mbedtls_timing_get_timer( &timer, 0 ),
-                         iterations );
-    /* Cleanup */
-    mbedtls_timing_alarmed = 0;
-}
-/* END_CASE */
-
-/* BEGIN_CASE */
-void timing_delay( int int_ms, int fin_ms )
-{
-    /* This function assumes that if int_ms is nonzero then it is large
-       enough that we have time to read all timers at least once in an
-       interval of time lasting int_ms milliseconds, and likewise for (fin_ms
-       - int_ms). So don't call it with arguments that are too small. */
-
-    mbedtls_timing_delay_context delay;
-    struct mbedtls_timing_hr_time timer;
-    unsigned long delta = 0; /* delay started between timer=0 and timer=delta */
-    unsigned long before = 0, after = 0;
-    unsigned long iterations = 0;
-    int status = -2;
-    int saw_status_1 = 0;
-    int warn_inconclusive = 0;
-
-    assert( int_ms >= 0 );
-    assert( fin_ms >= 0 );
-
-    /* Skip this test if it looks like timers don't work at all, to avoid an
-       infinite loop below. */
-    TEST_ASSERT( !timers_are_badly_broken );
-
-    /* Start a reference timer. Program a delay, and verify that the status of
-       the delay is consistent with the time given by the reference timer. */
-    (void) mbedtls_timing_get_timer( &timer, 1 );
-    mbedtls_timing_set_delay( &delay, int_ms, fin_ms );
-    /* Set delta to an upper bound for the interval between the start of timer
-       and the start of delay. Reading timer after starting delay gives us an
-       upper bound for the interval, rounded to a 1ms precision. Since this
-       might have been rounded down, but we need an upper bound, we add 1. */
-    delta = mbedtls_timing_get_timer( &timer, 0 ) + 1;
-
-    status = mbedtls_timing_get_delay( &delay );
-    if( fin_ms == 0 )
-    {
-        /* Cancelled timer. Just check the correct status for this case. */
-        TEST_ASSERT( status == -1 );
-        return;
-    }
-
-    /* Initially, none of the delays must be passed yet if they're nonzero.
-       This could fail for very small values of int_ms and fin_ms, where "very
-       small" depends how fast and how busy the platform is. */
-    if( int_ms > 0 )
-    {
-        TEST_ASSERT( status == 0 );
+        mbedtls_set_alarm( seconds );
+        TEST_ASSERT( mbedtls_timing_alarmed == 1 );
     }
     else
     {
-        TEST_ASSERT( status == 1 );
+        mbedtls_set_alarm( seconds );
+        TEST_ASSERT( mbedtls_timing_alarmed == 0 ||
+                     mbedtls_timing_alarmed == 1 );
     }
-
-    do
-    {
-        unsigned long delay_min, delay_max;
-        int status_min, status_max;
-        ++iterations;
-        before = mbedtls_timing_get_timer( &timer, 0 );
-        status = mbedtls_timing_get_delay( &delay );
-        after = mbedtls_timing_get_timer( &timer, 0 );
-        /* At a time between before and after, the delay's status was status.
-           Check that this is consistent given that the delay was started
-           between times 0 and delta. */
-        delay_min = ( before > delta ? before - delta : 0 );
-        status_min = expected_delay_status( int_ms, fin_ms, delay_min );
-        delay_max = after;
-        status_max = expected_delay_status( int_ms, fin_ms, delay_max );
-        TEST_ASSERT( status >= status_min );
-        TEST_ASSERT( status <= status_max );
-        if( status == 1 )
-            saw_status_1 = 1;
-    }
-    while ( before <= fin_ms + delta && status != 2 );
-
-    /* Since we've waited at least fin_ms, the delay must have fully
-       expired. */
-    TEST_ASSERT( status == 2 );
-
-    /* If the second delay is more than the first, then there must have been a
-       point in time when the first delay was passed but not the second delay.
-       This could fail for very small values of (fin_ms - int_ms), where "very
-       small" depends how fast and how busy the platform is. In practice, this
-       is the test that's most likely to fail on a heavily loaded machine. */
-    if( fin_ms > int_ms )
-    {
-        warn_inconclusive = 1;
-        TEST_ASSERT( saw_status_1 );
-    }
-
-    return;
-
-exit:
-    /* No cleanup needed, but show some diagnostic iterations, because timing
-       problems can be hard to reproduce. */
-    if( !timers_are_badly_broken )
-        mbedtls_fprintf( stdout, "  Finished with delta=%lu before=%lu after=%lu status=%d iterations=%lu\n",
-                         delta, before, after, status, iterations );
-    if( warn_inconclusive )
-        mbedtls_fprintf( stdout, "  Inconclusive test, try running it on a less heavily loaded machine.\n" );
- }
+}
 /* END_CASE */
 
 /* BEGIN_CASE */
-void timing_hardclock( )
+void timing_delay( int fin_ms )
 {
-    /* We make very few guarantees about mbedtls_timing_hardclock: its rate is
-       platform-dependent, it can wrap around. So there isn't much we can
-       test. But we do at least test that it doesn't crash, stall or return
-       completely nonsensical values. */
-
-    struct mbedtls_timing_hr_time timer;
-    unsigned long hardclock0 = -1, hardclock1 = -1, delta1 = -1;
-
-    /* Skip this test if it looks like timers don't work at all, to avoid an
-       infinite loop below. */
-    TEST_ASSERT( !timers_are_badly_broken );
-
-    hardclock0 = mbedtls_timing_hardclock( );
-    /* Wait 2ms to ensure a nonzero delay. Since the timer interface has 1ms
-       resolution and unspecified precision, waiting 1ms might be a very small
-       delay that's rounded up. */
-    (void) mbedtls_timing_get_timer( &timer, 1 );
-    while( mbedtls_timing_get_timer( &timer, 0 ) < 2 )
-        /*busy-wait loop*/;
-    hardclock1 = mbedtls_timing_hardclock( );
-
-    /* Although the hardclock counter can wrap around, the difference
-       (hardclock1 - hardclock0) is taken modulo the type size, so it is
-       correct as long as the counter only wrapped around at most once. We
-       further require the difference to be nonzero (after a wait of more than
-       1ms, the counter must have changed), and not to be overly large (after
-       a wait of less than 3ms, plus time lost because other processes were
-       scheduled on the CPU). If the hardclock counter runs at 4GHz, then
-       1000000000 (which is 1/4 of the counter wraparound on a 32-bit machine)
-       allows 250ms. */
-    delta1 = hardclock1 - hardclock0;
-    TEST_ASSERT( delta1 > 0 );
-    TEST_ASSERT( delta1 < 1000000000 );
-    return;
-
-exit:
-    /* No cleanup needed, but show some diagnostic iterations, because timing
-       problems can be hard to reproduce. */
-    if( !timers_are_badly_broken )
-        mbedtls_fprintf( stdout, "  Finished with hardclock=%lu,%lu\n",
-                         hardclock0, hardclock1 );
+    mbedtls_timing_delay_context ctx;
+    int result;
+    if( fin_ms == 0 )
+    {
+        mbedtls_timing_set_delay( &ctx, 0, 0 );
+        result = mbedtls_timing_get_delay( &ctx );
+        TEST_ASSERT( result == -1 );
+    }
+    else
+    {
+        mbedtls_timing_set_delay( &ctx, fin_ms / 2, fin_ms );
+        result = mbedtls_timing_get_delay( &ctx );
+        TEST_ASSERT( result >= 0 && result <= 2 );
+    }
 }
 /* END_CASE */
diff --git a/tests/suites/test_suite_version.data b/tests/suites/test_suite_version.data
index 62bb782..a4575ab 100644
--- a/tests/suites/test_suite_version.data
+++ b/tests/suites/test_suite_version.data
@@ -1,8 +1,8 @@
 Check compiletime library version
-check_compiletime_version:"2.16.0"
+check_compiletime_version:"2.17.0"
 
 Check runtime library version
-check_runtime_version:"2.16.0"
+check_runtime_version:"2.17.0"
 
 Check for MBEDTLS_VERSION_C
 check_feature:"MBEDTLS_VERSION_C":0
diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data
index 6786c36..042d653 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -2,14 +2,26 @@
 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
 x509_cert_info:"data_files/server1.crt":"cert. version     \: 3\nserial number     \: 01\nissuer name       \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name      \: C=NL, O=PolarSSL, CN=PolarSSL Server 1\nissued  on        \: 2011-02-12 14\:44\:06\nexpires on        \: 2021-02-12 14\:44\:06\nsigned using      \: RSA with SHA1\nRSA key size      \: 2048 bits\nbasic constraints \: CA=false\n"
 
+X509 Certificate information #1 (DER)
+depends_on:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
+x509_cert_info:"data_files/server1.der":"cert. version     \: 3\nserial number     \: 01\nissuer name       \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name      \: C=NL, O=PolarSSL, CN=PolarSSL Server 1\nissued  on        \: 2011-02-12 14\:44\:06\nexpires on        \: 2021-02-12 14\:44\:06\nsigned using      \: RSA with SHA1\nRSA key size      \: 2048 bits\nbasic constraints \: CA=false\n"
+
 X509 Certificate information #2
 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
 x509_cert_info:"data_files/server2.crt":"cert. version     \: 3\nserial number     \: 02\nissuer name       \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name      \: C=NL, O=PolarSSL, CN=localhost\nissued  on        \: 2011-02-12 14\:44\:06\nexpires on        \: 2021-02-12 14\:44\:06\nsigned using      \: RSA with SHA1\nRSA key size      \: 2048 bits\nbasic constraints \: CA=false\n"
 
+X509 Certificate information #2 (DER)
+depends_on:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
+x509_cert_info:"data_files/server2.der":"cert. version     \: 3\nserial number     \: 02\nissuer name       \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name      \: C=NL, O=PolarSSL, CN=localhost\nissued  on        \: 2011-02-12 14\:44\:06\nexpires on        \: 2021-02-12 14\:44\:06\nsigned using      \: RSA with SHA1\nRSA key size      \: 2048 bits\nbasic constraints \: CA=false\n"
+
 X509 Certificate information #3
 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
 x509_cert_info:"data_files/test-ca.crt":"cert. version     \: 3\nserial number     \: 03\nissuer name       \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name      \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nissued  on        \: 2011-02-12 14\:44\:00\nexpires on        \: 2021-02-12 14\:44\:00\nsigned using      \: RSA with SHA1\nRSA key size      \: 2048 bits\nbasic constraints \: CA=true\n"
 
+X509 Certificate information #3 (DER)
+depends_on:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
+x509_cert_info:"data_files/test-ca.der":"cert. version     \: 3\nserial number     \: 03\nissuer name       \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name      \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nissued  on        \: 2011-02-12 14\:44\:00\nexpires on        \: 2021-02-12 14\:44\:00\nsigned using      \: RSA with SHA1\nRSA key size      \: 2048 bits\nbasic constraints \: CA=true\n"
+
 X509 Certificate information MD2 Digest
 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_MD2_C
 x509_cert_info:"data_files/cert_md2.crt":"cert. version     \: 3\nserial number     \: 09\nissuer name       \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name      \: C=NL, O=PolarSSL, CN=PolarSSL Cert MD2\nissued  on        \: 2009-07-12 10\:56\:59\nexpires on        \: 2011-07-12 10\:56\:59\nsigned using      \: RSA with MD2\nRSA key size      \: 2048 bits\nbasic constraints \: CA=false\n"
diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function
index 8914bd0..4a82608 100644
--- a/tests/suites/test_suite_x509parse.function
+++ b/tests/suites/test_suite_x509parse.function
@@ -513,8 +513,22 @@
     mbedtls_x509_crt_init( &crt );
     memset( output, 0, 2000 );
 
+    TEST_ASSERT( mbedtls_x509_crt_parse_der( &crt, buf->x, buf->len ) == ( result ) );
+    if( ( result ) == 0 )
+    {
+        res = mbedtls_x509_crt_info( (char *) output, 2000, "", &crt );
 
-    TEST_ASSERT( mbedtls_x509_crt_parse( &crt, buf->x, buf->len ) == ( result ) );
+        TEST_ASSERT( res != -1 );
+        TEST_ASSERT( res != -2 );
+
+        TEST_ASSERT( strcmp( (char *) output, result_str ) == 0 );
+    }
+
+    mbedtls_x509_crt_free( &crt );
+    mbedtls_x509_crt_init( &crt );
+    memset( output, 0, 2000 );
+
+    TEST_ASSERT( mbedtls_x509_crt_parse_der_nocopy( &crt, buf->x, buf->len ) == ( result ) );
     if( ( result ) == 0 )
     {
         res = mbedtls_x509_crt_info( (char *) output, 2000, "", &crt );
diff --git a/tests/suites/test_suite_x509write.data b/tests/suites/test_suite_x509write.data
index 4096425..54d7270 100644
--- a/tests/suites/test_suite_x509write.data
+++ b/tests/suites/test_suite_x509write.data
@@ -1,46 +1,54 @@
 Certificate Request check Server1 SHA1
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha1":MBEDTLS_MD_SHA1:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha1":MBEDTLS_MD_SHA1:0:0:0:0
 
 Certificate Request check Server1 SHA224
 depends_on:MBEDTLS_SHA256_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha224":MBEDTLS_MD_SHA224:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha224":MBEDTLS_MD_SHA224:0:0:0:0
 
 Certificate Request check Server1 SHA256
 depends_on:MBEDTLS_SHA256_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha256":MBEDTLS_MD_SHA256:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha256":MBEDTLS_MD_SHA256:0:0:0:0
 
 Certificate Request check Server1 SHA384
 depends_on:MBEDTLS_SHA512_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha384":MBEDTLS_MD_SHA384:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha384":MBEDTLS_MD_SHA384:0:0:0:0
 
 Certificate Request check Server1 SHA512
 depends_on:MBEDTLS_SHA512_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha512":MBEDTLS_MD_SHA512:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.sha512":MBEDTLS_MD_SHA512:0:0:0:0
 
 Certificate Request check Server1 MD4
 depends_on:MBEDTLS_MD4_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.md4":MBEDTLS_MD_MD4:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.md4":MBEDTLS_MD_MD4:0:0:0:0
 
 Certificate Request check Server1 MD5
 depends_on:MBEDTLS_MD5_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.md5":MBEDTLS_MD_MD5:0:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.md5":MBEDTLS_MD_MD5:0:0:0:0
 
 Certificate Request check Server1 key_usage
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.key_usage":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION | MBEDTLS_X509_KU_KEY_ENCIPHERMENT:0
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.key_usage":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION | MBEDTLS_X509_KU_KEY_ENCIPHERMENT:1:0:0
+
+Certificate Request check Server1 key_usage empty
+depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.key_usage_empty":MBEDTLS_MD_SHA1:0:1:0:0
 
 Certificate Request check Server1 ns_cert_type
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.cert_type":MBEDTLS_MD_SHA1:0:MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.cert_type":MBEDTLS_MD_SHA1:0:0:MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER:1
+
+Certificate Request check Server1 ns_cert_type empty
+depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.cert_type_empty":MBEDTLS_MD_SHA1:0:0:0:1
 
 Certificate Request check Server1 key_usage + ns_cert_type
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
-x509_csr_check:"data_files/server1.key":"data_files/server1.req.ku-ct":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION | MBEDTLS_X509_KU_KEY_ENCIPHERMENT:MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER
+x509_csr_check:"data_files/server1.key":"data_files/server1.req.ku-ct":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION | MBEDTLS_X509_KU_KEY_ENCIPHERMENT:1:MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER:1
 
 Certificate Request check Server5 ECDSA, key_usage
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_ECDSA_C:MBEDTLS_ECDSA_DETERMINISTIC:MBEDTLS_ECP_DP_SECP256R1_ENABLED
-x509_csr_check:"data_files/server5.key":"data_files/server5.req.ku.sha1":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION:0
+x509_csr_check:"data_files/server5.key":"data_files/server5.req.ku.sha1":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION:1:0:0
 
 Certificate Request check opaque Server5 ECDSA, key_usage
 depends_on:MBEDTLS_SHA256_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED
@@ -48,35 +56,35 @@
 
 Certificate write check Server1 SHA1
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C
-x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":MBEDTLS_MD_SHA1:0:0:1:-1:"data_files/server1.crt":0
+x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":MBEDTLS_MD_SHA1:0:0:0:0:1:-1:"data_files/server1.crt":0
 
 Certificate write check Server1 SHA1, key_usage
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C
-x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION | MBEDTLS_X509_KU_KEY_ENCIPHERMENT:0:1:-1:"data_files/server1.key_usage.crt":0
+x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION | MBEDTLS_X509_KU_KEY_ENCIPHERMENT:1:0:0:1:-1:"data_files/server1.key_usage.crt":0
 
 Certificate write check Server1 SHA1, ns_cert_type
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C
-x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":MBEDTLS_MD_SHA1:0:MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER:1:-1:"data_files/server1.cert_type.crt":0
+x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":MBEDTLS_MD_SHA1:0:0:MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER:1:1:-1:"data_files/server1.cert_type.crt":0
 
 Certificate write check Server1 SHA1, version 1
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C
-x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":MBEDTLS_MD_SHA1:0:0:1:MBEDTLS_X509_CRT_VERSION_1:"data_files/server1.v1.crt":0
+x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":MBEDTLS_MD_SHA1:0:0:0:0:1:MBEDTLS_X509_CRT_VERSION_1:"data_files/server1.v1.crt":0
 
 Certificate write check Server1 SHA1, RSA_ALT
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C
-x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":MBEDTLS_MD_SHA1:0:0:0:-1:"data_files/server1.noauthid.crt":1
+x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":MBEDTLS_MD_SHA1:0:0:0:0:0:-1:"data_files/server1.noauthid.crt":1
 
 Certificate write check Server1 SHA1, RSA_ALT, key_usage
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C
-x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION | MBEDTLS_X509_KU_KEY_ENCIPHERMENT:0:0:-1:"data_files/server1.key_usage_noauthid.crt":1
+x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION | MBEDTLS_X509_KU_KEY_ENCIPHERMENT:1:0:0:0:-1:"data_files/server1.key_usage_noauthid.crt":1
 
 Certificate write check Server1 SHA1, RSA_ALT, ns_cert_type
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C
-x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":MBEDTLS_MD_SHA1:0:MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER:0:-1:"data_files/server1.cert_type_noauthid.crt":1
+x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":MBEDTLS_MD_SHA1:0:0:MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER:1:0:-1:"data_files/server1.cert_type_noauthid.crt":1
 
 Certificate write check Server1 SHA1, RSA_ALT, version 1
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C
-x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":MBEDTLS_MD_SHA1:0:0:0:MBEDTLS_X509_CRT_VERSION_1:"data_files/server1.v1.crt":1
+x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":MBEDTLS_MD_SHA1:0:0:0:0:0:MBEDTLS_X509_CRT_VERSION_1:"data_files/server1.v1.crt":1
 
 X509 String to Names #1
 mbedtls_x509_string_to_names:"C=NL,O=Offspark\, Inc., OU=PolarSSL":"C=NL, O=Offspark, Inc., OU=PolarSSL":0
diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function
index 268b4bb..e15802f 100644
--- a/tests/suites/test_suite_x509write.function
+++ b/tests/suites/test_suite_x509write.function
@@ -70,7 +70,8 @@
 
 /* BEGIN_CASE depends_on:MBEDTLS_PEM_WRITE_C:MBEDTLS_X509_CSR_WRITE_C */
 void x509_csr_check( char * key_file, char * cert_req_check_file, int md_type,
-                     int key_usage, int cert_type )
+                     int key_usage, int set_key_usage, int cert_type,
+                     int set_cert_type )
 {
     mbedtls_pk_context key;
     mbedtls_x509write_csr req;
@@ -92,9 +93,9 @@
     mbedtls_x509write_csr_set_md_alg( &req, md_type );
     mbedtls_x509write_csr_set_key( &req, &key );
     TEST_ASSERT( mbedtls_x509write_csr_set_subject_name( &req, subject_name ) == 0 );
-    if( key_usage != 0 )
+    if( set_key_usage != 0 )
         TEST_ASSERT( mbedtls_x509write_csr_set_key_usage( &req, key_usage ) == 0 );
-    if( cert_type != 0 )
+    if( set_cert_type != 0 )
         TEST_ASSERT( mbedtls_x509write_csr_set_ns_cert_type( &req, cert_type ) == 0 );
 
     ret = mbedtls_x509write_csr_pem( &req, buf, sizeof( buf ),
@@ -180,7 +181,8 @@
                      char *subject_name, char *issuer_key_file,
                      char *issuer_pwd, char *issuer_name,
                      char *serial_str, char *not_before, char *not_after,
-                     int md_type, int key_usage, int cert_type, int auth_ident,
+                     int md_type, int key_usage, int set_key_usage,
+                     int cert_type, int set_cert_type, int auth_ident,
                      int ver, char *cert_check_file, int rsa_alt )
 {
     mbedtls_pk_context subject_key, issuer_key, issuer_key_alt;
@@ -248,9 +250,9 @@
         TEST_ASSERT( mbedtls_x509write_crt_set_subject_key_identifier( &crt ) == 0 );
         if( auth_ident )
             TEST_ASSERT( mbedtls_x509write_crt_set_authority_key_identifier( &crt ) == 0 );
-        if( key_usage != 0 )
+        if( set_key_usage != 0 )
             TEST_ASSERT( mbedtls_x509write_crt_set_key_usage( &crt, key_usage ) == 0 );
-        if( cert_type != 0 )
+        if( set_cert_type != 0 )
             TEST_ASSERT( mbedtls_x509write_crt_set_ns_cert_type( &crt, cert_type ) == 0 );
     }
 
diff --git a/visualc/VS2010/mbedTLS.sln b/visualc/VS2010/mbedTLS.sln
index 66b96c3..85429b8 100644
--- a/visualc/VS2010/mbedTLS.sln
+++ b/visualc/VS2010/mbedTLS.sln
@@ -208,6 +208,11 @@
 		{46CF2D25-6A36-4189-B59C-E4815388E554} = {46CF2D25-6A36-4189-B59C-E4815388E554}

 	EndProjectSection

 EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "query_compile_time_config", "query_compile_time_config.vcxproj", "{D6F58AF2-9D80-562A-E2B0-F743281522B9}"

+	ProjectSection(ProjectDependencies) = postProject

+		{46CF2D25-6A36-4189-B59C-E4815388E554} = {46CF2D25-6A36-4189-B59C-E4815388E554}

+	EndProjectSection

+EndProject

 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pem2der", "pem2der.vcxproj", "{D3C6FBD6-D78E-7180-8345-5E09B492DBEC}"

 	ProjectSection(ProjectDependencies) = postProject

 		{46CF2D25-6A36-4189-B59C-E4815388E554} = {46CF2D25-6A36-4189-B59C-E4815388E554}

@@ -587,6 +592,14 @@
 		{10C01E94-4926-063E-9F56-C84ED190D349}.Release|Win32.Build.0 = Release|Win32

 		{10C01E94-4926-063E-9F56-C84ED190D349}.Release|x64.ActiveCfg = Release|x64

 		{10C01E94-4926-063E-9F56-C84ED190D349}.Release|x64.Build.0 = Release|x64

+		{D6F58AF2-9D80-562A-E2B0-F743281522B9}.Debug|Win32.ActiveCfg = Debug|Win32

+		{D6F58AF2-9D80-562A-E2B0-F743281522B9}.Debug|Win32.Build.0 = Debug|Win32

+		{D6F58AF2-9D80-562A-E2B0-F743281522B9}.Debug|x64.ActiveCfg = Debug|x64

+		{D6F58AF2-9D80-562A-E2B0-F743281522B9}.Debug|x64.Build.0 = Debug|x64

+		{D6F58AF2-9D80-562A-E2B0-F743281522B9}.Release|Win32.ActiveCfg = Release|Win32

+		{D6F58AF2-9D80-562A-E2B0-F743281522B9}.Release|Win32.Build.0 = Release|Win32

+		{D6F58AF2-9D80-562A-E2B0-F743281522B9}.Release|x64.ActiveCfg = Release|x64

+		{D6F58AF2-9D80-562A-E2B0-F743281522B9}.Release|x64.Build.0 = Release|x64

 		{D3C6FBD6-D78E-7180-8345-5E09B492DBEC}.Debug|Win32.ActiveCfg = Debug|Win32

 		{D3C6FBD6-D78E-7180-8345-5E09B492DBEC}.Debug|Win32.Build.0 = Debug|Win32

 		{D3C6FBD6-D78E-7180-8345-5E09B492DBEC}.Debug|x64.ActiveCfg = Debug|x64

diff --git a/visualc/VS2010/query_compile_time_config.vcxproj b/visualc/VS2010/query_compile_time_config.vcxproj
new file mode 100644
index 0000000..83a29f0
--- /dev/null
+++ b/visualc/VS2010/query_compile_time_config.vcxproj
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="utf-8"?>

+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

+  <ItemGroup Label="ProjectConfigurations">

+    <ProjectConfiguration Include="Debug|Win32">

+      <Configuration>Debug</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Debug|x64">

+      <Configuration>Debug</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|Win32">

+      <Configuration>Release</Configuration>

+      <Platform>Win32</Platform>

+    </ProjectConfiguration>

+    <ProjectConfiguration Include="Release|x64">

+      <Configuration>Release</Configuration>

+      <Platform>x64</Platform>

+    </ProjectConfiguration>

+  </ItemGroup>

+  <ItemGroup>

+    <ClCompile Include="..\..\programs\test\query_compile_time_config.c" />

+    <ClCompile Include="..\..\programs\ssl\query_config.c" />

+  </ItemGroup>

+  <ItemGroup>

+    <ProjectReference Include="mbedTLS.vcxproj">
+      <Project>{46cf2d25-6a36-4189-b59c-e4815388e554}</Project>

+      <LinkLibraryDependencies>true</LinkLibraryDependencies>

+    </ProjectReference>

+  </ItemGroup>

+  <PropertyGroup Label="Globals">

+    <ProjectGuid>{D6F58AF2-9D80-562A-E2B0-F743281522B9}</ProjectGuid>

+    <Keyword>Win32Proj</Keyword>

+    <RootNamespace>query_compile_time_config</RootNamespace>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <UseDebugLibraries>true</UseDebugLibraries>

+    <CharacterSet>Unicode</CharacterSet>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <UseDebugLibraries>true</UseDebugLibraries>

+    <CharacterSet>Unicode</CharacterSet>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <UseDebugLibraries>false</UseDebugLibraries>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+    <CharacterSet>Unicode</CharacterSet>

+  </PropertyGroup>

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">

+    <ConfigurationType>Application</ConfigurationType>

+    <UseDebugLibraries>false</UseDebugLibraries>

+    <WholeProgramOptimization>true</WholeProgramOptimization>

+    <CharacterSet>Unicode</CharacterSet>

+    <PlatformToolset>Windows7.1SDK</PlatformToolset>

+  </PropertyGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />

+  <ImportGroup Label="ExtensionSettings">

+  </ImportGroup>

+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">

+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />

+  </ImportGroup>

+  <PropertyGroup Label="UserMacros" />

+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+    <IntDir>$(Configuration)\$(TargetName)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+    <IntDir>$(Configuration)\$(TargetName)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+    <IntDir>$(Configuration)\$(TargetName)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>false</LinkIncremental>
+    <IntDir>$(Configuration)\$(TargetName)\</IntDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">

+    <ClCompile>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <WarningLevel>Level3</WarningLevel>

+      <Optimization>Disabled</Optimization>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>

+    </ClCompile>

+    <Link>

+      <SubSystem>Console</SubSystem>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <ShowProgress>NotSet</ShowProgress>

+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>Debug</AdditionalLibraryDirectories>

+    </Link>

+    <ProjectReference>

+      <LinkLibraryDependencies>false</LinkLibraryDependencies>

+    </ProjectReference>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

+    <ClCompile>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <WarningLevel>Level3</WarningLevel>

+      <Optimization>Disabled</Optimization>

+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>

+    </ClCompile>

+    <Link>

+      <SubSystem>Console</SubSystem>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <ShowProgress>NotSet</ShowProgress>

+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>Debug</AdditionalLibraryDirectories>

+    </Link>

+    <ProjectReference>

+      <LinkLibraryDependencies>false</LinkLibraryDependencies>

+    </ProjectReference>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

+    <ClCompile>

+      <WarningLevel>Level3</WarningLevel>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <Optimization>MaxSpeed</Optimization>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>

+    </ClCompile>

+    <Link>

+      <SubSystem>Console</SubSystem>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <OptimizeReferences>true</OptimizeReferences>

+      <AdditionalLibraryDirectories>Release</AdditionalLibraryDirectories>

+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>

+  </ItemDefinitionGroup>

+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">

+    <ClCompile>

+      <WarningLevel>Level3</WarningLevel>

+      <PrecompiledHeader>

+      </PrecompiledHeader>

+      <Optimization>MaxSpeed</Optimization>

+      <FunctionLevelLinking>true</FunctionLevelLinking>

+      <IntrinsicFunctions>true</IntrinsicFunctions>

+      <PreprocessorDefinitions>WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>

+      <AdditionalIncludeDirectories>../../include</AdditionalIncludeDirectories>

+    </ClCompile>

+    <Link>

+      <SubSystem>Console</SubSystem>

+      <GenerateDebugInformation>true</GenerateDebugInformation>

+      <EnableCOMDATFolding>true</EnableCOMDATFolding>

+      <OptimizeReferences>true</OptimizeReferences>

+      <AdditionalLibraryDirectories>Release</AdditionalLibraryDirectories>

+      <AdditionalDependencies>%(AdditionalDependencies);</AdditionalDependencies>

+    </Link>

+  </ItemDefinitionGroup>

+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+  <ImportGroup Label="ExtensionTargets">

+  </ImportGroup>

+</Project>

diff --git a/visualc/VS2010/ssl_client2.vcxproj b/visualc/VS2010/ssl_client2.vcxproj
index 1d44fa7..a960fac 100644
--- a/visualc/VS2010/ssl_client2.vcxproj
+++ b/visualc/VS2010/ssl_client2.vcxproj
@@ -20,6 +20,7 @@
   </ItemGroup>

   <ItemGroup>

     <ClCompile Include="..\..\programs\ssl\ssl_client2.c" />

+    <ClCompile Include="..\..\programs\ssl\query_config.c" />

   </ItemGroup>

   <ItemGroup>

     <ProjectReference Include="mbedTLS.vcxproj">
diff --git a/visualc/VS2010/ssl_server2.vcxproj b/visualc/VS2010/ssl_server2.vcxproj
index d06e062..06a91cb 100644
--- a/visualc/VS2010/ssl_server2.vcxproj
+++ b/visualc/VS2010/ssl_server2.vcxproj
@@ -20,6 +20,7 @@
   </ItemGroup>

   <ItemGroup>

     <ClCompile Include="..\..\programs\ssl\ssl_server2.c" />

+    <ClCompile Include="..\..\programs\ssl\query_config.c" />

   </ItemGroup>

   <ItemGroup>

     <ProjectReference Include="mbedTLS.vcxproj">