Merge remote-tracking branch 'tls/development' into development

Additional work done as part of merge:
    - Run ./tests/scripts/check-generated-files.sh and check in the
      resulting changes to programs/ssl/query_config.c
diff --git a/ChangeLog b/ChangeLog
index 606f8f0..2500919 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,16 @@
 
 = mbed TLS 2.x.x branch released xxxx-xx-xx
 
+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.
+
+API Changes
+   * Add a new X.509 API call `mbedtls_x509_parse_der_nocopy()`.
+     See the Features section for more information.
+
 Bugfix
    * Fix a compilation issue with mbedtls_ecp_restart_ctx not being defined
      when MBEDTLS_ECP_ALT is defined. Reported by jwhui. Fixes #2242.
@@ -19,8 +29,12 @@
      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.
 
 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 +49,10 @@
      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
 
 = mbed TLS 2.16.0 branch released 2018-12-21
 
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index 3d47899..ea05938 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -114,14 +114,15 @@
 #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_ECDSA_DETERMINISTIC) && !defined(MBEDTLS_HMAC_DRBG_C)
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_internal.h b/include/mbedtls/ssl_internal.h
index 3159cd3..be7f41b 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)
diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h
index 3dd5922..72c3901 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. */
 
@@ -220,16 +222,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/library/ssl_cli.c b/library/ssl_cli.c
index 06bcc73..87fa1e0 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)
@@ -2510,6 +2572,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)
@@ -2938,7 +3018,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 +3032,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 +3052,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 +3065,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 +3190,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 +3203,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 +3222,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 +3266,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 +3300,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 +3318,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 +3355,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 +3399,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 +3409,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 +3439,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;
 
@@ -3541,6 +3745,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_tls.c b/library/ssl_tls.c
index a0d2617..4c23f0e 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -5724,6 +5724,23 @@
     return( ret );
 }
 
+#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C)
+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 ) );
+}
+#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
@@ -5814,43 +5831,40 @@
         return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
     }
 
+    /* Make &ssl->in_msg[i] point to the beginning of the CRT chain. */
+    i += 3;
+
     /* 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 );
+        ssl->session_negotiate->peer_cert = NULL;
     }
 
-    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 );
-
-    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,72 +5872,101 @@
         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 );
         }
 
+        /* Check if we're handling the first CRT in the chain. */
+        if( ssl->session_negotiate->peer_cert == NULL )
+        {
+            /* 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. */
+#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 )
+            {
+                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 );
+                }
+
+                /* Move CRT chain structure to new session instance. */
+                ssl->session_negotiate->peer_cert = ssl->session->peer_cert;
+                ssl->session->peer_cert = NULL;
+
+                /* Delete all remaining CRTs from the original CRT chain. */
+                mbedtls_x509_crt_free(
+                    ssl->session_negotiate->peer_cert->next );
+                mbedtls_free( ssl->session_negotiate->peer_cert->next );
+                ssl->session_negotiate->peer_cert->next = NULL;
+
+                i += n;
+                continue;
+            }
+#endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */
+
+            /* Outside of client-side renegotiation, create a fresh X.509 CRT
+             * instance to parse the end-CRT into. */
+
+            ssl->session_negotiate->peer_cert =
+                mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) );
+            if( ssl->session_negotiate->peer_cert == 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 );
+
+            /* Intentional fall through */
+        }
+
+        /* Parse the next certificate in the chain. */
         ret = mbedtls_x509_crt_parse_der( ssl->session_negotiate->peer_cert,
-                                  ssl->in_msg + i, n );
+                                          ssl->in_msg + i, n );
         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 */
-
     return( 0 );
 }
 
@@ -9367,6 +9410,11 @@
     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 ) );
 }
diff --git a/library/x509_crt.c b/library/x509_crt.c
index 1f853ba..e3f169f 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  {
@@ -1091,8 +1094,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 +1129,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 +1143,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;
@@ -2699,7 +2720,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/programs/.gitignore b/programs/.gitignore
index 453ae0d..d19162d 100644
--- a/programs/.gitignore
+++ b/programs/.gitignore
@@ -53,6 +53,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 51548c3..1df2cb1 100644
--- a/programs/Makefile
+++ b/programs/Makefile
@@ -72,6 +72,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)		\
@@ -234,17 +235,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"
@@ -286,6 +287,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/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..828d75d
--- /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_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_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_PSA_HAS_ITS_IO)
+    if( strcmp( "MBEDTLS_PSA_HAS_ITS_IO", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PSA_HAS_ITS_IO );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PSA_HAS_ITS_IO */
+
+#if defined(MBEDTLS_PSA_CRYPTO_KEY_FILE_ID_ENCODES_OWNER)
+    if( strcmp( "MBEDTLS_PSA_CRYPTO_KEY_FILE_ID_ENCODES_OWNER", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PSA_CRYPTO_KEY_FILE_ID_ENCODES_OWNER );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PSA_CRYPTO_KEY_FILE_ID_ENCODES_OWNER */
+
+#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_HAS_ITS_IO)
+    if( strcmp( "MBEDTLS_PSA_HAS_ITS_IO", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PSA_HAS_ITS_IO );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PSA_HAS_ITS_IO */
+
+#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_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_CRYPTO_STORAGE_FILE_C)
+    if( strcmp( "MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_FILE_C */
+
+#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_ITS_C)
+    if( strcmp( "MBEDTLS_PSA_CRYPTO_STORAGE_ITS_C", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_PSA_CRYPTO_STORAGE_ITS_C );
+        return( 0 );
+    }
+#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_ITS_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..c2a8d42 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 )
@@ -1059,6 +1065,10 @@
             if( opt.dhmlen < 0 )
                 goto usage;
         }
+        else if( strcmp( p, "query_config" ) == 0 )
+        {
+            return query_config( q );
+        }
         else
             goto usage;
     }
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/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/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 d8825ee..68a1bd4 100755
--- a/scripts/generate_visualc_files.pl
+++ b/scripts/generate_visualc_files.pl
@@ -95,8 +95,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/data_files/Makefile b/tests/data_files/Makefile
index 2ed32e6..ff89476 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=$@
@@ -873,7 +875,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.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/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/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 844e4bc..9b5623a 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -298,7 +298,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 -
@@ -785,6 +785,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 CMAKE_BUILD_TYPE:String=Asan .
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/ssl-opt.sh b/tests/ssl-opt.sh
index 646ddd6..ff05f64 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" \
diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function
index 606ddd2..0b2e029 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 ) );
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_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/visualc/VS2010/mbedTLS.sln b/visualc/VS2010/mbedTLS.sln
index 32c86c0..8961f9d 100644
--- a/visualc/VS2010/mbedTLS.sln
+++ b/visualc/VS2010/mbedTLS.sln
@@ -223,6 +223,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}

@@ -626,6 +631,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">