Merge pull request #605 from ARMmbed/x509_ondemand_remove_unneeded_fields

[Baremetal] Allow removal of unneeded fields in X.509 CRT structures
diff --git a/ChangeLog b/ChangeLog
index 3e85f3f..0c579a8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -20,6 +20,7 @@
      irwir.
    * Enable Suite B with subset of ECP curves. Make sure the code compiles even
      if some curves are not defined. Fixes #1591 reported by dbedev.
+   * Fix misuse of signed arithmetic in the HAVEGE module. #2598
 
 Changes
    * Make it easier to define MBEDTLS_PARAM_FAILED as assert (which config.h
diff --git a/configs/baremetal.h b/configs/baremetal.h
index ce503aa..9929d56 100644
--- a/configs/baremetal.h
+++ b/configs/baremetal.h
@@ -57,9 +57,17 @@
 #define MBEDTLS_ECP_MAX_BITS   256
 #define MBEDTLS_MPI_MAX_SIZE    32 // 256 bits is 32 bytes
 
+#define MBEDTLS_SSL_CONF_SINGLE_EC
+#define MBEDTLS_SSL_CONF_SINGLE_EC_GRP_ID MBEDTLS_ECP_DP_SECP256R1
+#define MBEDTLS_SSL_CONF_SINGLE_EC_TLS_ID 23
+#define MBEDTLS_SSL_CONF_SINGLE_SIG_HASH
+#define MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_MD_ID MBEDTLS_MD_SHA256
+#define MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_TLS_ID MBEDTLS_SSL_HASH_SHA256
+
 /* Key exchanges */
 #define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
 #define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
+#define MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE MBEDTLS_SUITE_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
 
 /* Digests - just SHA-256 */
 #define MBEDTLS_MD_C
@@ -93,6 +101,16 @@
 #define MBEDTLS_SSL_CONF_AUTHMODE MBEDTLS_SSL_VERIFY_REQUIRED
 #define MBEDTLS_SSL_CONF_BADMAC_LIMIT 0
 #define MBEDTLS_SSL_CONF_ANTI_REPLAY MBEDTLS_SSL_ANTI_REPLAY_ENABLED
+#define MBEDTLS_SSL_CONF_GET_TIMER mbedtls_timing_get_delay
+#define MBEDTLS_SSL_CONF_SET_TIMER mbedtls_timing_set_delay
+#define MBEDTLS_SSL_CONF_RECV mbedtls_net_recv
+#define MBEDTLS_SSL_CONF_SEND mbedtls_net_send
+#define MBEDTLS_SSL_CONF_RECV_TIMEOUT mbedtls_net_recv_timeout
+#define MBEDTLS_SSL_CONF_RNG mbedtls_hmac_drbg_random
+#define MBEDTLS_SSL_CONF_MIN_MINOR_VER MBEDTLS_SSL_MINOR_VERSION_3
+#define MBEDTLS_SSL_CONF_MAX_MINOR_VER MBEDTLS_SSL_MINOR_VERSION_3
+#define MBEDTLS_SSL_CONF_MIN_MAJOR_VER MBEDTLS_SSL_MAJOR_VERSION_3
+#define MBEDTLS_SSL_CONF_MAX_MAJOR_VER MBEDTLS_SSL_MAJOR_VERSION_3
 #define MBEDTLS_SSL_CONF_EXTENDED_MASTER_SECRET \
     MBEDTLS_SSL_EXTENDED_MS_ENABLED
 #define MBEDTLS_SSL_CONF_ENFORCE_EXTENDED_MASTER_SECRET \
diff --git a/configs/baremetal_test.h b/configs/baremetal_test.h
index 82c0ed1..1b87474 100644
--- a/configs/baremetal_test.h
+++ b/configs/baremetal_test.h
@@ -51,6 +51,8 @@
 
 /* ssl_client2 and ssl_server2 use CTR-DRBG so far. */
 #define MBEDTLS_CTR_DRBG_C
+#undef MBEDTLS_SSL_CONF_RNG
+#define MBEDTLS_SSL_CONF_RNG mbedtls_ctr_drbg_random
 
 /* The ticket implementation hardcodes AES-GCM */
 #define MBEDTLS_GCM_C
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index 43f8896..29e61db 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -87,6 +87,18 @@
 #error "MBEDTLS_CMAC_C defined, but not all prerequisites"
 #endif
 
+#if defined(MBEDTLS_SSL_CONF_SINGLE_EC) &&           \
+    ( !defined(MBEDTLS_SSL_CONF_SINGLE_EC_TLS_ID) || \
+      !defined(MBEDTLS_SSL_CONF_SINGLE_EC_GRP_ID) )
+#error "MBEDTLS_SSL_CONF_SINGLE_EC defined, but not all prerequesites"
+#endif
+
+#if defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH) &&           \
+    ( !defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_MD_ID) || \
+      !defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_TLS_ID) )
+#error "MBEDTLS_SSL_CONF_SINGLE_SIG_HASH defined, but not all prerequesites"
+#endif
+
 #if defined(MBEDTLS_USE_TINYCRYPT) && defined(MBEDTLS_NO_64BIT_MULTIPLICATION)
 #error "MBEDTLS_USE_TINYCRYPT defined, but it cannot be defined with MBEDTLS_NO_64BIT_MULTIPLICATION"
 #endif
@@ -614,6 +626,18 @@
 #error "MBEDTLS_SSL_DTLS_ANTI_REPLAY  defined, but not all prerequisites"
 #endif
 
+#if defined(MBEDTLS_SSL_CONF_MIN_MINOR_VER) || \
+    defined(MBEDTLS_SSL_CONF_MAX_MINOR_VER) || \
+    defined(MBEDTLS_SSL_CONF_MIN_MAJOR_VER) || \
+    defined(MBEDTLS_SSL_CONF_MAX_MAJOR_VER)
+#if !( defined(MBEDTLS_SSL_CONF_MIN_MINOR_VER) &&        \
+       defined(MBEDTLS_SSL_CONF_MAX_MINOR_VER) &&        \
+       defined(MBEDTLS_SSL_CONF_MIN_MAJOR_VER) &&        \
+       defined(MBEDTLS_SSL_CONF_MAX_MAJOR_VER) )
+#error "MBEDTLS_SSL_CONF_MIN_MINOR_VER, MBEDTLS_SSL_CONF_MAX_MINOR_VER, MBEDTLS_SSL_CONF_MIN_MAJOR_VER, MBEDTLS_SSL_CONF_MAX_MAJOR_VER must be defined simultaneously"
+#endif
+#endif
+
 #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) &&                              \
     ( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) )
 #error "MBEDTLS_SSL_DTLS_CONNECTION_ID  defined, but not all prerequisites"
@@ -668,7 +692,26 @@
       !defined(MBEDTLS_SSL_CONF_ENFORCE_EXTENDED_MASTER_SECRET) ) || \
     ( !defined(MBEDTLS_SSL_CONF_EXTENDED_MASTER_SECRET) &&           \
       defined(MBEDTLS_SSL_CONF_ENFORCE_EXTENDED_MASTER_SECRET) )
-#define "MBEDTLS_SSL_CONF_EXTENDED_MASTER_SECRET and MBEDTLS_SSL_CONF_ENFORCE_EXTENDED_MASTER_SECRET must be defined together."
+#error "MBEDTLS_SSL_CONF_EXTENDED_MASTER_SECRET and MBEDTLS_SSL_CONF_ENFORCE_EXTENDED_MASTER_SECRET must be defined together."
+#endif
+
+#if ( defined(MBEDTLS_SSL_CONF_SEND) &&                 \
+      !( defined(MBEDTLS_SSL_CONF_RECV) &&              \
+         defined(MBEDTLS_SSL_CONF_RECV_TIMEOUT) ) ) ||  \
+    ( defined(MBEDTLS_SSL_CONF_RECV) &&                 \
+      !( defined(MBEDTLS_SSL_CONF_SEND) &&              \
+         defined(MBEDTLS_SSL_CONF_RECV_TIMEOUT) ) ) ||  \
+    ( defined(MBEDTLS_SSL_CONF_RECV_TIMEOUT) &&         \
+      !( defined(MBEDTLS_SSL_CONF_SEND) &&              \
+         defined(MBEDTLS_SSL_CONF_RECV) ) )
+#error "MBEDTLS_SSL_CONF_SEND/RECV/RECV_TIMEOUT must be defined simultaneously"
+#endif
+
+#if ( defined(MBEDTLS_SSL_CONF_GET_TIMER) &&            \
+      !defined(MBEDTLS_SSL_CONF_SET_TIMER) ) || \
+    ( !defined(MBEDTLS_SSL_CONF_GET_TIMER) &&           \
+      defined(MBEDTLS_SSL_CONF_SET_TIMER) )
+#error "MBEDTLS_SSL_CONF_GET_TIMER and MBEDTLS_SSL_CONF_SET_TIMER must be defined together."
 #endif
 
 #if defined(MBEDTLS_SSL_TICKET_C) && !defined(MBEDTLS_CIPHER_C)
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index 39b1cb1..6436411 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -3624,11 +3624,118 @@
 //#define MBEDTLS_SSL_CONF_CID_LEN 0
 //#define MBEDTLS_SSL_CONF_IGNORE_UNEXPECTED_CID MBEDTLS_SSL_UNEXPECTED_CID_IGNORE
 
+/* The timer callbacks to use by the SSL module.
+ * If defined,
+ * - MBEDTLS_SSL_CONF_SET_TIMER must evaluate to the name of an externally
+ *   defined function with signature
+ *      void f_set_timer( void* , uint32_t, uint32_t ),
+ * * MBEDTLS_SSL_CONF_SEND must evaluate to the name of an externally
+ *   defined function with signature
+ *      int f_get_timer( void* ).
+ */
+//#define MBEDTLS_SSL_CONF_GET_TIMER mbedtls_timing_get_delay
+//#define MBEDTLS_SSL_CONF_SET_TIMER mbedtls_timing_set_delay
+
+/* The send and receive callbacks to use by the SSL module.
+ * If defined,
+ * - MBEDTLS_SSL_CONF_RECV must evaluate to the name of an externally
+ *   defined function with signature
+ *      int f_recv( void*, unsigned char *, size_t ),
+ * * MBEDTLS_SSL_CONF_SEND must evaluate to the name of an externally
+ *   defined function with signature
+ *      int f_send( void*, const unsigned char *, size_t ),
+ * * MBEDTLS_SSL_CONF_RECV_TIMEOUT must evaluate to the name of an
+ *   externally defined function with signature
+ *      int f_recv_timeout( void*, const unsigned char *, size_t, uint32_t ).
+ */
+//#define MBEDTLS_SSL_CONF_RECV mbedtls_net_recv
+//#define MBEDTLS_SSL_CONF_SEND mbedtls_net_send
+//#define MBEDTLS_SSL_CONF_RECV_TIMEOUT mbedtls_net_recv_timeout
+
+/* The PRNG to use by the SSL module. If defined, this must
+ * evaluate to the name on externally defined function with signature
+ * int f_rng(void *, unsigned char *, size_t),
+ * e.g. mbedtls_ctr_drbg_random or mbedtls_hmac_drbg_random.
+ */
+//#define MBEDTLS_SSL_CONF_RNG mbedtls_ctr_drbg_random
+
+/* TLS version */
+//#define MBEDTLS_SSL_CONF_MIN_MINOR_VER MBEDTLS_SSL_MINOR_VERSION_3
+//#define MBEDTLS_SSL_CONF_MAX_MINOR_VER MBEDTLS_SSL_MINOR_VERSION_3
+//#define MBEDTLS_SSL_CONF_MIN_MAJOR_VER MBEDTLS_SSL_MAJOR_VERSION_3
+//#define MBEDTLS_SSL_CONF_MAX_MAJOR_VER MBEDTLS_SSL_MAJOR_VERSION_3
+
 /* ExtendedMasterSecret extension
  * The following two options must be set/unset simultaneously. */
 //#define MBEDTLS_SSL_CONF_EXTENDED_MASTER_SECRET MBEDTLS_SSL_EXTENDED_MS_ENABLED
 //#define MBEDTLS_SSL_CONF_ENFORCE_EXTENDED_MASTER_SECRET MBEDTLS_SSL_EXTENDED_MS_ENFORCE_DISABLED
 
+/* Set this to MBEDTLS_SUITE_{OFFICIAL_SUITE_NAME} to hardcode
+ * the choice of a fixed ciphersuite at compile-time.
+ *
+ * You need to make sure that the corresponding ciphersuite attributes
+ * are defined through macros in ssl_ciphersuites.h. See the definitions
+ * of MBEDTLS_SUITE_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_XXX for an example.
+ *
+ * If this option is set, the API mbedtls_ssl_conf_ciphersuites() is removed.
+ */
+//#define MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE MBEDTLS_SUITE_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
+
+/* Enable support of a single elliptic curve fixed
+ * at compile-time, at the benefit of code-size.
+ *
+ * On highly constrained systems with large control
+ * over the configuration of the connection endpoints,
+ * this option can be used to hardcode the choice of
+ * a single elliptic curve to be used for all elliptic
+ * curve operations during the handshake.
+ *
+ * If this is set, you must also define the following:
+ * - MBEDTLS_SSL_CONF_SINGLE_EC_GRP_ID
+ *   This must resolve to the Mbed TLS group ID for the elliptic
+ *   curve to use (e.g. MBEDTLS_ECP_DP_SECP256R1_ENABLED); see
+ *   ::mbedtls_ecp_group_id in mbedtls/ecp.h for a complete list
+ *   of curve identifiers.
+ * - MBEDTLS_SSL_CONF_SINGLE_EC_TLS_ID
+ *   This must resolve to the identifier for the elliptic curve
+ *   to use according to the IANA NamedCurve registry:
+ *     https://tools.ietf.org/html/rfc4492#section-5.1
+ *
+ * If defined, this option overwrites the effect of the
+ * runtime configuration API mbedtls_ssl_conf_curves().
+ */
+//#define MBEDTLS_SSL_CONF_SINGLE_EC
+//#define MBEDTLS_SSL_CONF_SINGLE_EC_TLS_ID
+//#define MBEDTLS_SSL_CONF_SINGLE_EC_GRP_ID
+
+/* Enable support a single signature hash algorithm
+ * at compile-time, at the benefit of code-size.
+ *
+ * On highly constrained systems with large control
+ * over the configuration of the connection endpoints,
+ * this option can be used to hardcode the choice of
+ * hash algorithm to be used for signatures in the
+ * ServerKeyExchange and CertificateVerify messages.
+ *
+ * If this is set, you must also define the following:
+ * - MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_MD_ID
+ *   This must resolve to the Mbed TLS hash ID for the hash
+ *   algorithm to use (e.g. MBEDTLS_MD_SHA256). See
+ *   ::mbedtls_md_type_t in mbedtls/md.h for a complete
+ *   list of supported hash algorithm identifiers.
+ * - MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_TLS_ID
+ *   This must resolve to the TLS identifier for the hash
+ *   algorithm to use. See
+ *   https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+ *   for a list of the supported identifiers.
+ *
+ * If defined, this option overwrites the effect of the
+ * runtime configuration API mbedtls_ssl_conf_sig_hashes().
+ */
+//#define MBEDTLS_SSL_CONF_SINGLE_SIG_HASH
+//#define MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_MD_ID
+//#define MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_TLS_ID
+
 /* \} SECTION: Compile-time SSL configuration */
 
 /* Target and application specific configurations
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index ead0fa7..b3fd7c4 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -33,8 +33,6 @@
 #include "bignum.h"
 #include "ecp.h"
 
-#include "ssl_ciphersuites.h"
-
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
 #include "x509_crt.h"
 #include "x509_crl.h"
@@ -65,6 +63,18 @@
 #include "platform_time.h"
 #endif
 
+#if defined(MBEDTLS_SSL_CONF_MAX_MAJOR_VER) && \
+    defined(MBEDTLS_SSL_CONF_MIN_MAJOR_VER) && \
+    ( MBEDTLS_SSL_CONF_MAX_MAJOR_VER == MBEDTLS_SSL_CONF_MIN_MAJOR_VER )
+#define MBEDTLS_SSL_CONF_FIXED_MAJOR_VER MBEDTLS_SSL_CONF_MIN_MAJOR_VER
+#endif
+
+#if defined(MBEDTLS_SSL_CONF_MAX_MINOR_VER) && \
+    defined(MBEDTLS_SSL_CONF_MIN_MINOR_VER) && \
+    ( MBEDTLS_SSL_CONF_MAX_MINOR_VER == MBEDTLS_SSL_CONF_MIN_MINOR_VER )
+#define MBEDTLS_SSL_CONF_FIXED_MINOR_VER MBEDTLS_SSL_CONF_MIN_MINOR_VER
+#endif
+
 /*
  * SSL Error codes
  */
@@ -356,6 +366,7 @@
 #define MBEDTLS_SSL_ALERT_MSG_UNRECOGNIZED_NAME    112  /* 0x70 */
 #define MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY 115  /* 0x73 */
 #define MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL 120 /* 0x78 */
+#define MBEDTLS_SSL_ALERT_MSG_NONE                 255  /* internal */
 
 #define MBEDTLS_SSL_HS_HELLO_REQUEST            0
 #define MBEDTLS_SSL_HS_CLIENT_HELLO             1
@@ -402,6 +413,84 @@
 #define MBEDTLS_TLS_EXT_RENEGOTIATION_INFO      0xFF01
 
 /*
+ * Helper macros indicating whether certain classes
+ * of key exchanges are enabled in the configuration.
+ */
+
+/* Key exchanges using a certificate */
+#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)           || \
+    defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)       || \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED)     || \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)   || \
+    defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED)       || \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED)      || \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)
+#define MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED
+#endif
+
+/* Key exchanges allowing client certificate requests */
+#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)           ||       \
+    defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)       ||       \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED)      ||       \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED)     ||       \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)    ||       \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
+#define MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED
+#endif
+
+/* Key exchanges involving server signature in ServerKeyExchange */
+#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)       || \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED)     || \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
+#define MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED
+#endif
+
+/* Key exchanges using ECDH */
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED)      || \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)
+#define MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED
+#endif
+
+/* Key exchanges that don't involve ephemeral keys */
+#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)           || \
+    defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)           || \
+    defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED)       || \
+    defined(MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED)
+#define MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED
+#endif
+
+/* Key exchanges that involve ephemeral keys */
+#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)       || \
+    defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED)       || \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED)     || \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED)     || \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)   || \
+    defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+#define MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED
+#endif
+
+/* Key exchanges using a PSK */
+#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)           || \
+    defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED)       || \
+    defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED)       || \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED)
+#define MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
+#endif
+
+/* Key exchanges using DHE */
+#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)       || \
+    defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED)
+#define MBEDTLS_KEY_EXCHANGE__SOME__DHE_ENABLED
+#endif
+
+/* Key exchanges using ECDHE */
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED)     || \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)   || \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED)
+#define MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED
+#endif
+
+/*
  * Size defines
  */
 #if !defined(MBEDTLS_PSK_MAX_LEN)
@@ -847,7 +936,9 @@
 #if defined(MBEDTLS_HAVE_TIME)
     mbedtls_time_t start;       /*!< starting time      */
 #endif
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
     int ciphersuite;            /*!< chosen ciphersuite */
+#endif /* MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
     int compression;            /*!< chosen compression */
     size_t id_len;              /*!< session id length  */
     unsigned char id[32];       /*!< session identifier */
@@ -896,14 +987,20 @@
      * Pointers
      */
 
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
     const int *ciphersuite_list[4]; /*!< allowed ciphersuites per version   */
+#endif /* MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
 
+#if defined(MBEDTLS_DEBUG_C)
     /** Callback for printing debug output                                  */
     void (*f_dbg)(void *, int, const char *, int, const char *);
     void *p_dbg;                    /*!< context for the debug function     */
+#endif /* MBEDTLS_DEBUG_C */
 
+#if !defined(MBEDTLS_SSL_CONF_RNG)
     /** Callback for getting (pseudo-)random numbers                        */
     int  (*f_rng)(void *, unsigned char *, size_t);
+#endif /* !MBEDTLS_SSL_CONF_RNG */
     void *p_rng;                    /*!< context for the RNG function       */
 
 #if defined(MBEDTLS_SSL_SRV_C) && !defined(MBEDTLS_SSL_NO_SESSION_CACHE)
@@ -982,11 +1079,15 @@
 #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
 
 #if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED)
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH)
     const int *sig_hashes;          /*!< allowed signature hashes           */
+#endif /* !MBEDTLS_SSL_CONF_SINGLE_SIG_HASH */
 #endif
 
 #if defined(MBEDTLS_ECP_C)
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_EC)
     const mbedtls_ecp_group_id *curve_list; /*!< allowed curves             */
+#endif /* MBEDTLS_SSL_CONF_SINGLE_EC */
 #endif
 
 #if defined(MBEDTLS_DHM_C)
@@ -1048,10 +1149,18 @@
     unsigned int dhm_min_bitlen;    /*!< min. bit length of the DHM prime   */
 #endif
 
+#if !defined(MBEDTLS_SSL_CONF_MAX_MAJOR_VER)
     unsigned char max_major_ver;    /*!< max. major version used            */
+#endif /* !MBEDTLS_SSL_CONF_MAX_MAJOR_VER */
+#if !defined(MBEDTLS_SSL_CONF_MAX_MINOR_VER)
     unsigned char max_minor_ver;    /*!< max. minor version used            */
+#endif /* !MBEDTLS_SSL_CONF_MAX_MINOR_VER */
+#if !defined(MBEDTLS_SSL_CONF_MIN_MAJOR_VER)
     unsigned char min_major_ver;    /*!< min. major version used            */
+#endif /* !MBEDTLS_SSL_CONF_MIN_MAJOR_VER */
+#if !defined(MBEDTLS_SSL_CONF_MIN_MINOR_VER)
     unsigned char min_minor_ver;    /*!< min. minor version used            */
+#endif /* !MBEDTLS_SSL_CONF_MIN_MINOR_VER */
 
     /*
      * Flags (bitfields)
@@ -1126,6 +1235,9 @@
 {
     const mbedtls_ssl_config *conf; /*!< configuration information          */
 
+    unsigned char pending_fatal_alert_msg; /*!< Type of a fatal alert
+                                            *   pending to be delivered.    */
+
     /*
      * Miscellaneous
      */
@@ -1137,16 +1249,26 @@
                                   renego_max_records is < 0           */
 #endif /* MBEDTLS_SSL_RENEGOTIATION */
 
+#if !defined(MBEDTLS_SSL_CONF_FIXED_MAJOR_VER)
     int major_ver;              /*!< equal to  MBEDTLS_SSL_MAJOR_VERSION_3    */
+#endif /* !MBEDTLS_SSL_CONF_FIXED_MAJOR_VER */
+#if !defined(MBEDTLS_SSL_CONF_FIXED_MINOR_VER)
     int minor_ver;              /*!< either 0 (SSL3) or 1 (TLS1.0)    */
+#endif /* !MBEDTLS_SSL_CONF_FIXED_MINOR_VER */
 
 #if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT)
     unsigned badmac_seen;       /*!< records with a bad MAC received    */
 #endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */
 
+#if !defined(MBEDTLS_SSL_CONF_SEND)
     mbedtls_ssl_send_t *f_send; /*!< Callback for network send */
+#endif /* !MBEDTLS_SSL_CONF_SEND */
+#if !defined(MBEDTLS_SSL_CONF_RECV)
     mbedtls_ssl_recv_t *f_recv; /*!< Callback for network receive */
+#endif /* !MBEDTLS_SSL_CONF_RECV */
+#if !defined(MBEDTLS_SSL_CONF_RECV_TIMEOUT)
     mbedtls_ssl_recv_timeout_t *f_recv_timeout;
+#endif /* !MBEDTLS_SSL_CONF_RECV_TIMEOUT */
                                 /*!< Callback for network receive with timeout */
 
     void *p_bio;                /*!< context for I/O operations   */
@@ -1175,8 +1297,12 @@
      */
     void *p_timer;              /*!< context for the timer callbacks */
 
+#if !defined(MBEDTLS_SSL_CONF_SET_TIMER)
     mbedtls_ssl_set_timer_t *f_set_timer;       /*!< set timer callback */
+#endif /* !MBEDTLS_SSL_CONF_SET_TIMER */
+#if !defined(MBEDTLS_SSL_CONF_GET_TIMER)
     mbedtls_ssl_get_timer_t *f_get_timer;       /*!< get timer callback */
+#endif /* !MBEDTLS_SSL_CONF_GET_TIMER */
 
     /*
      * Record layer (incoming data)
@@ -1462,9 +1588,13 @@
                      void *p_vrfy );
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
+#if !defined(MBEDTLS_SSL_CONF_RNG)
 /**
  * \brief          Set the random number generator callback
  *
+ * \note           On constrained systems, the RNG can also be configured at
+ *                 compile-time via the option MBEDTLS_SSL_CONF_RNG.
+ *
  * \param conf     SSL configuration
  * \param f_rng    RNG function
  * \param p_rng    RNG parameter
@@ -1472,7 +1602,18 @@
 void mbedtls_ssl_conf_rng( mbedtls_ssl_config *conf,
                   int (*f_rng)(void *, unsigned char *, size_t),
                   void *p_rng );
+#else /* !MBEDTLS_SSL_CONF_RNG */
+/**
+ * \brief          Set the random number generator callback context.
+ *
+ * \param conf     SSL configuration
+ * \param p_rng    RNG parameter
+ */
+void mbedtls_ssl_conf_rng_ctx( mbedtls_ssl_config *conf,
+                               void *p_rng );
+#endif /* MBEDTLS_SSL_CONF_RNG */
 
+#if defined(MBEDTLS_DEBUG_C)
 /**
  * \brief          Set the debug callback
  *
@@ -1490,7 +1631,11 @@
 void mbedtls_ssl_conf_dbg( mbedtls_ssl_config *conf,
                   void (*f_dbg)(void *, int, const char *, int, const char *),
                   void  *p_dbg );
+#endif /* MBEDTLS_DEBUG_C */
 
+#if !defined(MBEDTLS_SSL_CONF_RECV) && \
+    !defined(MBEDTLS_SSL_CONF_SEND) && \
+    !defined(MBEDTLS_SSL_CONF_RECV_TIMEOUT)
 /**
  * \brief          Set the underlying BIO callbacks for write, read and
  *                 read-with-timeout.
@@ -1516,6 +1661,11 @@
  *                 \c mbedtls_ssl_recv_t and \c mbedtls_ssl_recv_timeout_t for
  *                 the conventions those callbacks must follow.
  *
+ * \note           On constrained systems, the pointers \p f_send, \p f_recv,
+ *                 and \p f_recv_timeout can also be configured at compile-time
+ *                 via the macros MBEDTLS_SSL_CONF_RECV, MBEDTLS_SSL_CONF_SEND
+ *                 and MBEDTLS_SSL_CONF_RECV_TIMEOUT.
+ *
  * \note           On some platforms, net_sockets.c provides
  *                 \c mbedtls_net_send(), \c mbedtls_net_recv() and
  *                 \c mbedtls_net_recv_timeout() that are suitable to be used
@@ -1526,6 +1676,22 @@
                           mbedtls_ssl_send_t *f_send,
                           mbedtls_ssl_recv_t *f_recv,
                           mbedtls_ssl_recv_timeout_t *f_recv_timeout );
+#else /* !( MBEDTLS_SSL_CONF_RECV &&
+            MBEDTLS_SSL_CONF_SEND &&
+            MBEDTLS_SSL_CONF_RECV_TIMEOUT ) */
+/**
+ * \brief          Set the context to be passed to the underlying BIO callbacks
+ *                 for write, read and read-with-timeout.
+ *
+ * \param ssl      The SSL context to configure.
+ * \param p_bio    The parameter (context) to be used for the BIO callbacks.
+ *
+ */
+void mbedtls_ssl_set_bio_ctx( mbedtls_ssl_context *ssl,
+                              void *p_bio );
+#endif /* MBEDTLS_SSL_CONF_RECV &&
+          MBEDTLS_SSL_CONF_SEND &&
+          MBEDTLS_SSL_CONF_RECV_TIMEOUT */
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
 
@@ -1732,30 +1898,50 @@
 void mbedtls_ssl_conf_read_timeout( mbedtls_ssl_config *conf, uint32_t timeout );
 #endif /* !MBEDTLS_SSL_CONF_READ_TIMEOUT */
 
+#if !defined(MBEDTLS_SSL_CONF_SET_TIMER) && \
+    !defined(MBEDTLS_SSL_CONF_GET_TIMER)
 /**
- * \brief          Set the timer callbacks (Mandatory for DTLS.)
+ * \brief         Set the timer callbacks (Mandatory for DTLS.)
  *
- * \param ssl      SSL context
- * \param p_timer  parameter (context) shared by timer callbacks
+ * \param ssl     SSL context
+ * \param p_timer parameter (context) shared by timer callbacks
  * \param f_set_timer   set timer callback
  * \param f_get_timer   get timer callback. Must return:
  *
- * \note           See the documentation of \c mbedtls_ssl_set_timer_t and
- *                 \c mbedtls_ssl_get_timer_t for the conventions this pair of
- *                 callbacks must follow.
+ * \note          See the documentation of \c mbedtls_ssl_set_timer_t and
+ *                \c mbedtls_ssl_get_timer_t for the conventions this pair of
+ *                callbacks must follow.
  *
- * \note           On some platforms, timing.c provides
- *                 \c mbedtls_timing_set_delay() and
- *                 \c mbedtls_timing_get_delay() that are suitable for using
- *                 here, except if using an event-driven style.
+ * \note          On some platforms, timing.c provides
+ *                \c mbedtls_timing_set_delay() and
+ *                \c mbedtls_timing_get_delay() that are suitable for using
+ *                here, except if using an event-driven style.
  *
- * \note           See also the "DTLS tutorial" article in our knowledge base.
- *                 https://tls.mbed.org/kb/how-to/dtls-tutorial
+ * \note          On constrained systems, the timer callbacks \p f_set_timer
+ *                and \p f_get_timer may also be configured at compile-time
+ *                via MBEDTLS_SSL_CONF_GET_TIMER and MBEDTLS_SSL_CONF_SET_TIMER.
+ *
+ * \note          See also the "DTLS tutorial" article in our knowledge base.
+ *                https://tls.mbed.org/kb/how-to/dtls-tutorial
  */
 void mbedtls_ssl_set_timer_cb( mbedtls_ssl_context *ssl,
                                void *p_timer,
                                mbedtls_ssl_set_timer_t *f_set_timer,
                                mbedtls_ssl_get_timer_t *f_get_timer );
+#else /* !( MBEDTLS_SSL_CONF_SET_TIMER &&
+            MBEDTLS_SSL_CONF_GET_TIMER ) */
+/**
+ * \brief          Set the context to be passed to the timer callbacks
+ *                 (Mandatory for DTLS.)
+ *
+ * \param ssl      The SSL context to configure.
+ * \param p_timer  The context to be passed to the timer callbacks.
+ *
+ */
+void mbedtls_ssl_set_timer_cb_ctx( mbedtls_ssl_context *ssl,
+                                   void *p_timer );
+#endif /* MBEDTLS_SSL_CONF_SET_TIMER &&
+          MBEDTLS_SSL_CONF_GET_TIMER */
 
 /**
  * \brief           Callback type: generate and write session ticket
@@ -2320,6 +2506,7 @@
  */
 const mbedtls_ssl_session *mbedtls_ssl_get_session_pointer( const mbedtls_ssl_context *ssl );
 
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
 /**
  * \brief               Set the list of allowed ciphersuites and the preference
  *                      order. First in the list has the highest preference.
@@ -2332,11 +2519,43 @@
  *                      over the preference of the client unless
  *                      MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE is defined!
  *
+ * \note                On constrained systems, support for a single ciphersuite
+ *                      (in all versions) can be fixed at compile-time through
+ *                      the configuration option MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE.
+ *
  * \param conf          SSL configuration
  * \param ciphersuites  0-terminated list of allowed ciphersuites
  */
 void mbedtls_ssl_conf_ciphersuites( mbedtls_ssl_config *conf,
-                                   const int *ciphersuites );
+                                    const int *ciphersuites );
+
+/**
+ * \brief               Set the list of allowed ciphersuites and the
+ *                      preference order for a specific version of the protocol.
+ *                      (Only useful on the server side)
+ *
+ *                      The ciphersuites array is not copied, and must remain
+ *                      valid for the lifetime of the ssl_config.
+ *
+ * \param conf          SSL configuration
+ * \param ciphersuites  0-terminated list of allowed ciphersuites
+ * \param major         Major version number (only MBEDTLS_SSL_MAJOR_VERSION_3
+ *                      supported)
+ * \param minor         Minor version number (MBEDTLS_SSL_MINOR_VERSION_0,
+ *                      MBEDTLS_SSL_MINOR_VERSION_1 and MBEDTLS_SSL_MINOR_VERSION_2,
+ *                      MBEDTLS_SSL_MINOR_VERSION_3 supported)
+ *
+ * \note                With DTLS, use MBEDTLS_SSL_MINOR_VERSION_2 for DTLS 1.0
+ *                      and MBEDTLS_SSL_MINOR_VERSION_3 for DTLS 1.2
+ *
+ * \note                On constrained systems, support for a single ciphersuite
+ *                      (in all versions) can be fixed at compile-time through
+ *                      the configuration option MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE.
+ */
+void mbedtls_ssl_conf_ciphersuites_for_version( mbedtls_ssl_config *conf,
+                                       const int *ciphersuites,
+                                       int major, int minor );
+#endif /* !MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
 
 #define MBEDTLS_SSL_UNEXPECTED_CID_IGNORE 0
 #define MBEDTLS_SSL_UNEXPECTED_CID_FAIL   1
@@ -2385,29 +2604,6 @@
           !MBEDTLS_SSL_CONF_CID_LEN &&
           !MBEDTLS_SSL_CONF_IGNORE_UNEXPECTED_CID */
 
-/**
- * \brief               Set the list of allowed ciphersuites and the
- *                      preference order for a specific version of the protocol.
- *                      (Only useful on the server side)
- *
- *                      The ciphersuites array is not copied, and must remain
- *                      valid for the lifetime of the ssl_config.
- *
- * \param conf          SSL configuration
- * \param ciphersuites  0-terminated list of allowed ciphersuites
- * \param major         Major version number (only MBEDTLS_SSL_MAJOR_VERSION_3
- *                      supported)
- * \param minor         Minor version number (MBEDTLS_SSL_MINOR_VERSION_0,
- *                      MBEDTLS_SSL_MINOR_VERSION_1 and MBEDTLS_SSL_MINOR_VERSION_2,
- *                      MBEDTLS_SSL_MINOR_VERSION_3 supported)
- *
- * \note                With DTLS, use MBEDTLS_SSL_MINOR_VERSION_2 for DTLS 1.0
- *                      and MBEDTLS_SSL_MINOR_VERSION_3 for DTLS 1.2
- */
-void mbedtls_ssl_conf_ciphersuites_for_version( mbedtls_ssl_config *conf,
-                                       const int *ciphersuites,
-                                       int major, int minor );
-
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
 /**
  * \brief          Set the X.509 security profile used for verification
@@ -2621,6 +2817,7 @@
 #endif /* MBEDTLS_DHM_C && MBEDTLS_SSL_CLI_C */
 
 #if defined(MBEDTLS_ECP_C)
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_EC)
 /**
  * \brief          Set the allowed curves in order of preference.
  *                 (Default: all defined curves.)
@@ -2644,12 +2841,17 @@
  * \note           This list should be ordered by decreasing preference
  *                 (preferred curve first).
  *
+ * \note           On highly constrained systems, the support for a single
+ *                 fixed elliptic curve can be configured at compile time
+ *                 through the option MBEDTLS_SSL_CONF_SINGLE_EC.
+ *
  * \param conf     SSL configuration
  * \param curves   Ordered list of allowed curves,
  *                 terminated by MBEDTLS_ECP_DP_NONE.
  */
 void mbedtls_ssl_conf_curves( mbedtls_ssl_config *conf,
                               const mbedtls_ecp_group_id *curves );
+#endif /* !MBEDTLS_SSL_CONF_SINGLE_EC */
 #endif /* MBEDTLS_ECP_C */
 
 #if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED)
@@ -2667,6 +2869,10 @@
  * \note           This list should be ordered by decreasing preference
  *                 (preferred hash first).
  *
+ * \note           On highly constrained systems, the support for a single
+ *                 fixed signature hash algorithm can be configured at compile
+ *                 time through the option MBEDTLS_SSL_CONF_SINGLE_SIG_HASH.
+ *
  * \param conf     SSL configuration
  * \param hashes   Ordered list of allowed signature hashes,
  *                 terminated by \c MBEDTLS_MD_NONE.
@@ -2821,6 +3027,8 @@
 const char *mbedtls_ssl_get_alpn_protocol( const mbedtls_ssl_context *ssl );
 #endif /* MBEDTLS_SSL_ALPN */
 
+#if !defined(MBEDTLS_SSL_CONF_MAX_MINOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MAX_MAJOR_VER)
 /**
  * \brief          Set the maximum supported version sent from the client side
  *                 and/or accepted at the server side
@@ -2831,6 +3039,11 @@
  * \note           With DTLS, use MBEDTLS_SSL_MINOR_VERSION_2 for DTLS 1.0 and
  *                 MBEDTLS_SSL_MINOR_VERSION_3 for DTLS 1.2
  *
+ * \note           On constrained systems, the maximum major/minor version can
+ *                 also be configured at compile-time by setting
+ *                 MBEDTLS_SSL_CONF_MAX_MAJOR_VER and
+ *                 MBEDTLS_SSL_CONF_MAX_MINOR_VER.
+ *
  * \param conf     SSL configuration
  * \param major    Major version number (only MBEDTLS_SSL_MAJOR_VERSION_3 supported)
  * \param minor    Minor version number (MBEDTLS_SSL_MINOR_VERSION_0,
@@ -2838,7 +3051,11 @@
  *                 MBEDTLS_SSL_MINOR_VERSION_3 supported)
  */
 void mbedtls_ssl_conf_max_version( mbedtls_ssl_config *conf, int major, int minor );
+#endif /* MBEDTLS_SSL_CONF_MAX_MINOR_VER ||
+          MBEDTLS_SSL_CONF_MAX_MAJOR_VER */
 
+#if !defined(MBEDTLS_SSL_CONF_MIN_MINOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MIN_MAJOR_VER)
 /**
  * \brief          Set the minimum accepted SSL/TLS protocol version
  *                 (Default: TLS 1.0)
@@ -2851,6 +3068,11 @@
  * \note           With DTLS, use MBEDTLS_SSL_MINOR_VERSION_2 for DTLS 1.0 and
  *                 MBEDTLS_SSL_MINOR_VERSION_3 for DTLS 1.2
  *
+ * \note           On constrained systems, the minimum major/minor version can
+ *                 also be configured at compile-time by setting
+ *                 MBEDTLS_SSL_CONF_MIN_MAJOR_VER and
+ *                 MBEDTLS_SSL_CONF_MIN_MINOR_VER.
+ *
  * \param conf     SSL configuration
  * \param major    Major version number (only MBEDTLS_SSL_MAJOR_VERSION_3 supported)
  * \param minor    Minor version number (MBEDTLS_SSL_MINOR_VERSION_0,
@@ -2858,6 +3080,8 @@
  *                 MBEDTLS_SSL_MINOR_VERSION_3 supported)
  */
 void mbedtls_ssl_conf_min_version( mbedtls_ssl_config *conf, int major, int minor );
+#endif /* MBEDTLS_SSL_CONF_MIN_MINOR_VER ||
+          MBEDTLS_SSL_CONF_MIN_MAJOR_VER */
 
 #if defined(MBEDTLS_SSL_FALLBACK_SCSV) && defined(MBEDTLS_SSL_CLI_C)
 /**
@@ -3845,6 +4069,8 @@
  */
 void mbedtls_ssl_session_free( mbedtls_ssl_session *session );
 
+#include "ssl_ciphersuites.h"
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/mbedtls/ssl_ciphersuites.h b/include/mbedtls/ssl_ciphersuites.h
index 7126783..925f280 100644
--- a/include/mbedtls/ssl_ciphersuites.h
+++ b/include/mbedtls/ssl_ciphersuites.h
@@ -33,6 +33,8 @@
 #include "pk.h"
 #include "cipher.h"
 #include "md.h"
+#include "ssl.h"
+#include <string.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -304,79 +306,6 @@
     MBEDTLS_KEY_EXCHANGE_ECJPAKE,
 } mbedtls_key_exchange_type_t;
 
-/* Key exchanges using a certificate */
-#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)           || \
-    defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)       || \
-    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED)     || \
-    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)   || \
-    defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED)       || \
-    defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED)      || \
-    defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)
-#define MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED
-#endif
-
-/* Key exchanges allowing client certificate requests */
-#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)           ||       \
-    defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)       ||       \
-    defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED)      ||       \
-    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED)     ||       \
-    defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)    ||       \
-    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
-#define MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED
-#endif
-
-/* Key exchanges involving server signature in ServerKeyExchange */
-#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)       || \
-    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED)     || \
-    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
-#define MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED
-#endif
-
-/* Key exchanges using ECDH */
-#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED)      || \
-    defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)
-#define MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED
-#endif
-
-/* Key exchanges that don't involve ephemeral keys */
-#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)           || \
-    defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)           || \
-    defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED)       || \
-    defined(MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED)
-#define MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED
-#endif
-
-/* Key exchanges that involve ephemeral keys */
-#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)       || \
-    defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED)       || \
-    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED)     || \
-    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED)     || \
-    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)   || \
-    defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
-#define MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED
-#endif
-
-/* Key exchanges using a PSK */
-#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)           || \
-    defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED)       || \
-    defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED)       || \
-    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED)
-#define MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
-#endif
-
-/* Key exchanges using DHE */
-#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)       || \
-    defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED)
-#define MBEDTLS_KEY_EXCHANGE__SOME__DHE_ENABLED
-#endif
-
-/* Key exchanges using ECDHE */
-#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED)     || \
-    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)   || \
-    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED)
-#define MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED
-#endif
-
 typedef struct mbedtls_ssl_ciphersuite_t mbedtls_ssl_ciphersuite_t;
 
 #define MBEDTLS_CIPHERSUITE_WEAK       0x01    /**< Weak ciphersuite flag  */
@@ -384,6 +313,61 @@
                                                      eg for CCM_8 */
 #define MBEDTLS_CIPHERSUITE_NODTLS     0x04    /**< Can't be used with DTLS */
 
+/*
+ * Ciphersuite macro definitions
+ *
+ * This is highly incomplete and only contains those ciphersuites for
+ * which we need to be able to build the library with support for that
+ * ciphersuite only (currently MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
+ * as an example).
+ */
+
+#define MBEDTLS_SUITE_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_ID              MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
+#define MBEDTLS_SUITE_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_NAME            "TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8"
+#define MBEDTLS_SUITE_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_CIPHER          MBEDTLS_CIPHER_AES_128_CCM
+#define MBEDTLS_SUITE_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_MAC             MBEDTLS_MD_SHA256
+#define MBEDTLS_SUITE_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_KEY_EXCHANGE    MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA
+#define MBEDTLS_SUITE_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_MIN_MAJOR_VER   MBEDTLS_SSL_MAJOR_VERSION_3
+#define MBEDTLS_SUITE_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_MIN_MINOR_VER   MBEDTLS_SSL_MINOR_VERSION_3
+#define MBEDTLS_SUITE_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_MAX_MAJOR_VER   MBEDTLS_SSL_MAJOR_VERSION_3
+#define MBEDTLS_SUITE_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_MAX_MINOR_VER   MBEDTLS_SSL_MINOR_VERSION_3
+#define MBEDTLS_SUITE_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_FLAGS           MBEDTLS_CIPHERSUITE_SHORT_TAG
+
+/* This is just to make check-names.sh happy -- don't uncomment. */
+//#define MBEDTLS_SUITE_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
+
+/*
+ * Helper macros to extract fields from ciphersuites.
+ */
+
+#define MBEDTLS_SSL_SUITE_ID_T(            SUITE ) SUITE ## _ID
+#define MBEDTLS_SSL_SUITE_NAME_T(          SUITE ) SUITE ## _NAME
+#define MBEDTLS_SSL_SUITE_CIPHER_T(        SUITE ) SUITE ## _CIPHER
+#define MBEDTLS_SSL_SUITE_MAC_T(           SUITE ) SUITE ## _MAC
+#define MBEDTLS_SSL_SUITE_KEY_EXCHANGE_T(  SUITE ) SUITE ## _KEY_EXCHANGE
+#define MBEDTLS_SSL_SUITE_MIN_MAJOR_VER_T( SUITE ) SUITE ## _MIN_MAJOR_VER
+#define MBEDTLS_SSL_SUITE_MIN_MINOR_VER_T( SUITE ) SUITE ## _MIN_MINOR_VER
+#define MBEDTLS_SSL_SUITE_MAX_MAJOR_VER_T( SUITE ) SUITE ## _MAX_MAJOR_VER
+#define MBEDTLS_SSL_SUITE_MAX_MINOR_VER_T( SUITE ) SUITE ## _MAX_MINOR_VER
+#define MBEDTLS_SSL_SUITE_FLAGS_T(         SUITE ) SUITE ## _FLAGS
+
+/* Wrapper around MBEDTLS_SSL_SUITE_XXX_T() which makes sure that
+ * the argument is macro-expanded before concatenated with the
+ * field name. This allows to call these macros as
+ *    MBEDTLS_SSL_SUITE_XXX( MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE ),
+ * where MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE expands to MBEDTLS_SSL_SUITE_XXX. */
+#define MBEDTLS_SSL_SUITE_ID(            SUITE ) MBEDTLS_SSL_SUITE_ID_T(            SUITE )
+#define MBEDTLS_SSL_SUITE_NAME(          SUITE ) MBEDTLS_SSL_SUITE_NAME_T(          SUITE )
+#define MBEDTLS_SSL_SUITE_CIPHER(        SUITE ) MBEDTLS_SSL_SUITE_CIPHER_T(        SUITE )
+#define MBEDTLS_SSL_SUITE_MAC(           SUITE ) MBEDTLS_SSL_SUITE_MAC_T(           SUITE )
+#define MBEDTLS_SSL_SUITE_KEY_EXCHANGE(  SUITE ) MBEDTLS_SSL_SUITE_KEY_EXCHANGE_T(  SUITE )
+#define MBEDTLS_SSL_SUITE_MIN_MAJOR_VER( SUITE ) MBEDTLS_SSL_SUITE_MIN_MAJOR_VER_T( SUITE )
+#define MBEDTLS_SSL_SUITE_MIN_MINOR_VER( SUITE ) MBEDTLS_SSL_SUITE_MIN_MINOR_VER_T( SUITE )
+#define MBEDTLS_SSL_SUITE_MAX_MAJOR_VER( SUITE ) MBEDTLS_SSL_SUITE_MAX_MAJOR_VER_T( SUITE )
+#define MBEDTLS_SSL_SUITE_MAX_MINOR_VER( SUITE ) MBEDTLS_SSL_SUITE_MAX_MINOR_VER_T( SUITE )
+#define MBEDTLS_SSL_SUITE_FLAGS(         SUITE ) MBEDTLS_SSL_SUITE_FLAGS_T(         SUITE )
+
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
 /**
  * \brief   This structure is used for storing ciphersuite information
  */
@@ -404,23 +388,376 @@
     unsigned char flags;
 };
 
+typedef mbedtls_ssl_ciphersuite_t const * mbedtls_ssl_ciphersuite_handle_t;
+#define MBEDTLS_SSL_CIPHERSUITE_INVALID_HANDLE ( (mbedtls_ssl_ciphersuite_handle_t) NULL )
+
+/**
+ * \brief   This macro builds an instance of ::mbedtls_ssl_ciphersuite_t
+ *          from an \c MBEDTLS_SUITE_XXX identifier.
+ */
+#define MBEDTLS_SSL_SUITE_INFO( SUITE )           \
+    { MBEDTLS_SSL_SUITE_ID( SUITE ),              \
+      MBEDTLS_SSL_SUITE_NAME( SUITE ),            \
+      MBEDTLS_SSL_SUITE_CIPHER( SUITE ),          \
+      MBEDTLS_SSL_SUITE_MAC( SUITE ),             \
+      MBEDTLS_SSL_SUITE_KEY_EXCHANGE(  SUITE ),   \
+      MBEDTLS_SSL_SUITE_MIN_MAJOR_VER( SUITE ),   \
+      MBEDTLS_SSL_SUITE_MIN_MINOR_VER( SUITE ),   \
+      MBEDTLS_SSL_SUITE_MAX_MAJOR_VER( SUITE ),   \
+      MBEDTLS_SSL_SUITE_MAX_MINOR_VER( SUITE ),   \
+      MBEDTLS_SSL_SUITE_FLAGS( SUITE ) }
+
+#else /* !MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
+
+typedef unsigned char mbedtls_ssl_ciphersuite_handle_t;
+#define MBEDTLS_SSL_CIPHERSUITE_INVALID_HANDLE      ( (mbedtls_ssl_ciphersuite_handle_t) 0 )
+#define MBEDTLS_SSL_CIPHERSUITE_UNIQUE_VALID_HANDLE ( (mbedtls_ssl_ciphersuite_handle_t) 1 )
+
+#endif /* MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
+
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
+static inline int mbedtls_ssl_session_get_ciphersuite(
+    mbedtls_ssl_session const * session )
+{
+    return( session->ciphersuite );
+}
+#else /* !MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
+static inline int mbedtls_ssl_session_get_ciphersuite(
+    mbedtls_ssl_session const * session )
+{
+    ((void) session);
+    return( MBEDTLS_SSL_SUITE_ID( MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE ) );
+}
+#endif /* MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
+
+/*
+ * Getter functions for the extraction of ciphersuite attributes
+ * from a ciphersuite handle.
+ *
+ * Warning: These functions have the validity of the handle as a precondition!
+ * Their behaviour is undefined when MBEDTLS_SSL_CIPHERSUITE_INVALID_HANDLE
+ * is passed.
+ */
+
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
+/*
+ * Implementation of getter functions when the ciphersuite handle
+ * is a pointer to the ciphersuite information structure.
+ *
+ * The precondition that the handle is valid means that
+ * we don't need to check that info != NULL.
+ */
+static inline int mbedtls_ssl_suite_get_id(
+    mbedtls_ssl_ciphersuite_handle_t const info )
+{
+    return( info->id );
+}
+static inline const char* mbedtls_ssl_suite_get_name(
+    mbedtls_ssl_ciphersuite_handle_t const info )
+{
+    return( info->name );
+}
+static inline mbedtls_cipher_type_t mbedtls_ssl_suite_get_cipher(
+    mbedtls_ssl_ciphersuite_handle_t const info )
+{
+    return( info->cipher );
+}
+static inline mbedtls_md_type_t mbedtls_ssl_suite_get_mac(
+    mbedtls_ssl_ciphersuite_handle_t const info )
+{
+    return( info->mac );
+}
+static inline mbedtls_key_exchange_type_t mbedtls_ssl_suite_get_key_exchange(
+    mbedtls_ssl_ciphersuite_handle_t const info )
+{
+    return( info->key_exchange );
+}
+static inline int mbedtls_ssl_suite_get_min_major_ver(
+    mbedtls_ssl_ciphersuite_handle_t const info )
+{
+    return( info->min_major_ver );
+}
+static inline int mbedtls_ssl_suite_get_min_minor_ver(
+    mbedtls_ssl_ciphersuite_handle_t const info )
+{
+    return( info->min_minor_ver );
+}
+static inline int mbedtls_ssl_suite_get_max_major_ver(
+    mbedtls_ssl_ciphersuite_handle_t const info )
+{
+    return( info->max_major_ver );
+}
+static inline int mbedtls_ssl_suite_get_max_minor_ver(
+    mbedtls_ssl_ciphersuite_handle_t const info )
+{
+    return( info->max_minor_ver );
+}
+static inline unsigned char mbedtls_ssl_suite_get_flags(
+    mbedtls_ssl_ciphersuite_handle_t const info )
+{
+    return( info->flags );
+}
+#else /* !MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
+/*
+ * Implementations of getter functions in the case of only a single possible
+ * ciphersuite. In this case, the handle is logically a boolean (either the
+ * invalid handle or the unique valid handle representing the single enabled
+ * ciphersuite), and the precondition that the handle is valid means that we
+ * can statically return the hardcoded attribute of the enabled ciphersuite.
+ */
+static inline int mbedtls_ssl_suite_get_id(
+    mbedtls_ssl_ciphersuite_handle_t const info )
+{
+    ((void) info);
+    return( MBEDTLS_SSL_SUITE_ID( MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE ) );
+}
+static inline const char* mbedtls_ssl_suite_get_name(
+    mbedtls_ssl_ciphersuite_handle_t const info )
+{
+    ((void) info);
+    return( MBEDTLS_SSL_SUITE_NAME( MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE ) );
+}
+static inline mbedtls_cipher_type_t mbedtls_ssl_suite_get_cipher(
+    mbedtls_ssl_ciphersuite_handle_t const info )
+{
+    ((void) info);
+    return( MBEDTLS_SSL_SUITE_CIPHER( MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE ) );
+}
+static inline mbedtls_md_type_t mbedtls_ssl_suite_get_mac(
+    mbedtls_ssl_ciphersuite_handle_t const info )
+{
+    ((void) info);
+    return( MBEDTLS_SSL_SUITE_MAC( MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE ) );
+}
+static inline mbedtls_key_exchange_type_t mbedtls_ssl_suite_get_key_exchange(
+    mbedtls_ssl_ciphersuite_handle_t const info )
+{
+    ((void) info);
+    return( MBEDTLS_SSL_SUITE_KEY_EXCHANGE( MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE ) );
+}
+static inline int mbedtls_ssl_suite_get_min_major_ver(
+    mbedtls_ssl_ciphersuite_handle_t const info )
+{
+    ((void) info);
+    return( MBEDTLS_SSL_SUITE_MIN_MAJOR_VER( MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE ) );
+}
+static inline int mbedtls_ssl_suite_get_min_minor_ver(
+    mbedtls_ssl_ciphersuite_handle_t const info )
+{
+    ((void) info);
+    return( MBEDTLS_SSL_SUITE_MIN_MINOR_VER( MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE ) );
+}
+static inline int mbedtls_ssl_suite_get_max_major_ver(
+    mbedtls_ssl_ciphersuite_handle_t const info )
+{
+    ((void) info);
+    return( MBEDTLS_SSL_SUITE_MAX_MAJOR_VER( MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE ) );
+}
+static inline int mbedtls_ssl_suite_get_max_minor_ver(
+    mbedtls_ssl_ciphersuite_handle_t const info )
+{
+    ((void) info);
+    return( MBEDTLS_SSL_SUITE_MAX_MINOR_VER( MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE ) );
+}
+static inline unsigned char mbedtls_ssl_suite_get_flags(
+    mbedtls_ssl_ciphersuite_handle_t const info )
+{
+    ((void) info);
+    return( MBEDTLS_SSL_SUITE_FLAGS( MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE ) );
+}
+#endif /* MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
+
 const int *mbedtls_ssl_list_ciphersuites( void );
 
-const mbedtls_ssl_ciphersuite_t *mbedtls_ssl_ciphersuite_from_string( const char *ciphersuite_name );
-const mbedtls_ssl_ciphersuite_t *mbedtls_ssl_ciphersuite_from_id( int ciphersuite_id );
+/*
+ * Various small helper functions for ciphersuites.
+ *
+ * Like the getter functions, they assume that the provided ciphersuite
+ * handle is valid, and hence can be optimized in case there's only one
+ * ciphersuite enabled.
+ *
+ * To avoid code-duplication between inline and non-inline implementations
+ * of this, we define internal static inline versions of all functions first,
+ * and define wrappers around these either here or in ssl_ciphersuites.c,
+ * depending on whether MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE is defined.
+ */
 
 #if defined(MBEDTLS_PK_C)
-mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_pk_alg( const mbedtls_ssl_ciphersuite_t *info );
-mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_alg( const mbedtls_ssl_ciphersuite_t *info );
-#endif
-
-int mbedtls_ssl_ciphersuite_uses_ec( const mbedtls_ssl_ciphersuite_t *info );
-int mbedtls_ssl_ciphersuite_uses_psk( const mbedtls_ssl_ciphersuite_t *info );
-
-#if defined(MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED)
-static inline int mbedtls_ssl_ciphersuite_has_pfs( const mbedtls_ssl_ciphersuite_t *info )
+static inline mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_pk_alg_internal(
+    mbedtls_ssl_ciphersuite_handle_t info )
 {
-    switch( info->key_exchange )
+    switch( mbedtls_ssl_suite_get_key_exchange( info ) )
+    {
+        case MBEDTLS_KEY_EXCHANGE_RSA:
+        case MBEDTLS_KEY_EXCHANGE_DHE_RSA:
+        case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA:
+        case MBEDTLS_KEY_EXCHANGE_RSA_PSK:
+            return( MBEDTLS_PK_RSA );
+
+        case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA:
+            return( MBEDTLS_PK_ECDSA );
+
+        case MBEDTLS_KEY_EXCHANGE_ECDH_RSA:
+        case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA:
+            return( MBEDTLS_PK_ECKEY );
+
+        default:
+            return( MBEDTLS_PK_NONE );
+    }
+}
+
+static inline mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_alg_internal(
+    mbedtls_ssl_ciphersuite_handle_t info )
+{
+    switch( mbedtls_ssl_suite_get_key_exchange( info ) )
+    {
+        case MBEDTLS_KEY_EXCHANGE_RSA:
+        case MBEDTLS_KEY_EXCHANGE_DHE_RSA:
+        case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA:
+            return( MBEDTLS_PK_RSA );
+
+        case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA:
+            return( MBEDTLS_PK_ECDSA );
+
+        default:
+            return( MBEDTLS_PK_NONE );
+    }
+}
+
+#endif /* MBEDTLS_PK_C */
+
+#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \
+    defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+static inline int mbedtls_ssl_ciphersuite_uses_ec_internal(
+    mbedtls_ssl_ciphersuite_handle_t info )
+{
+    switch( mbedtls_ssl_suite_get_key_exchange( info ) )
+    {
+        case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA:
+        case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA:
+        case MBEDTLS_KEY_EXCHANGE_ECDHE_PSK:
+        case MBEDTLS_KEY_EXCHANGE_ECDH_RSA:
+        case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA:
+        case MBEDTLS_KEY_EXCHANGE_ECJPAKE:
+            return( 1 );
+
+        default:
+            return( 0 );
+    }
+}
+#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C || MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
+
+#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
+static inline int mbedtls_ssl_ciphersuite_uses_psk_internal(
+    mbedtls_ssl_ciphersuite_handle_t info )
+{
+    switch( mbedtls_ssl_suite_get_key_exchange( info ) )
+    {
+        case MBEDTLS_KEY_EXCHANGE_PSK:
+        case MBEDTLS_KEY_EXCHANGE_RSA_PSK:
+        case MBEDTLS_KEY_EXCHANGE_DHE_PSK:
+        case MBEDTLS_KEY_EXCHANGE_ECDHE_PSK:
+            return( 1 );
+
+        default:
+            return( 0 );
+    }
+}
+#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */
+
+/*
+ * Wrappers around internal helper functions to be used by the rest of
+ * the library, either defined static inline here or in ssl_ciphersuites.c.
+ */
+
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
+
+mbedtls_ssl_ciphersuite_handle_t mbedtls_ssl_ciphersuite_from_string(
+    const char *ciphersuite_name );
+mbedtls_ssl_ciphersuite_handle_t mbedtls_ssl_ciphersuite_from_id(
+    int ciphersuite_id );
+
+#if defined(MBEDTLS_PK_C)
+mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_pk_alg(
+    mbedtls_ssl_ciphersuite_handle_t info );
+mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_alg(
+    mbedtls_ssl_ciphersuite_handle_t info );
+#endif /* MBEDTLS_PK_C */
+
+#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \
+    defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+int mbedtls_ssl_ciphersuite_uses_ec( mbedtls_ssl_ciphersuite_handle_t info );
+#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C ||
+          MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED*/
+
+#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
+int mbedtls_ssl_ciphersuite_uses_psk( mbedtls_ssl_ciphersuite_handle_t info );
+#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */
+
+#else /* !MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
+
+#if defined(MBEDTLS_PK_C)
+static inline mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_pk_alg(
+    mbedtls_ssl_ciphersuite_handle_t info )
+{
+    return( mbedtls_ssl_get_ciphersuite_sig_pk_alg_internal( info ) );
+}
+
+static inline mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_alg(
+    mbedtls_ssl_ciphersuite_handle_t info )
+{
+    return( mbedtls_ssl_get_ciphersuite_sig_alg_internal( info ) );
+}
+#endif /* MBEDTLS_PK_C */
+
+#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \
+    defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+static inline int mbedtls_ssl_ciphersuite_uses_ec(
+    mbedtls_ssl_ciphersuite_handle_t info )
+{
+    return( mbedtls_ssl_ciphersuite_uses_ec_internal( info ) );
+}
+#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C ||
+          MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED*/
+
+#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
+static inline int mbedtls_ssl_ciphersuite_uses_psk(
+    mbedtls_ssl_ciphersuite_handle_t info )
+{
+    return( mbedtls_ssl_ciphersuite_uses_psk_internal( info ) );
+}
+#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */
+
+static inline mbedtls_ssl_ciphersuite_handle_t mbedtls_ssl_ciphersuite_from_id(
+    int ciphersuite )
+{
+    static const int single_suite_id =
+        MBEDTLS_SSL_SUITE_ID( MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE );
+
+    if( ciphersuite == single_suite_id )
+        return( MBEDTLS_SSL_CIPHERSUITE_UNIQUE_VALID_HANDLE );
+
+    return( MBEDTLS_SSL_CIPHERSUITE_INVALID_HANDLE );
+}
+
+static inline mbedtls_ssl_ciphersuite_handle_t mbedtls_ssl_ciphersuite_from_string(
+                                                const char *ciphersuite_name )
+{
+    static const char * const single_suite_name =
+        MBEDTLS_SSL_SUITE_NAME( MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE );
+
+    if( strcmp( ciphersuite_name, single_suite_name ) == 0 )
+        return( MBEDTLS_SSL_CIPHERSUITE_UNIQUE_VALID_HANDLE );
+
+    return( MBEDTLS_SSL_CIPHERSUITE_INVALID_HANDLE );
+}
+
+#endif /* MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
+
+static inline int mbedtls_ssl_ciphersuite_has_pfs(
+    mbedtls_ssl_ciphersuite_handle_t info )
+{
+    switch( mbedtls_ssl_suite_get_key_exchange( info ) )
     {
         case MBEDTLS_KEY_EXCHANGE_DHE_RSA:
         case MBEDTLS_KEY_EXCHANGE_DHE_PSK:
@@ -434,12 +771,11 @@
             return( 0 );
     }
 }
-#endif /* MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED */
 
-#if defined(MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED)
-static inline int mbedtls_ssl_ciphersuite_no_pfs( const mbedtls_ssl_ciphersuite_t *info )
+static inline int mbedtls_ssl_ciphersuite_no_pfs(
+    mbedtls_ssl_ciphersuite_handle_t info )
 {
-    switch( info->key_exchange )
+    switch( mbedtls_ssl_suite_get_key_exchange( info ) )
     {
         case MBEDTLS_KEY_EXCHANGE_ECDH_RSA:
         case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA:
@@ -452,12 +788,12 @@
             return( 0 );
     }
 }
-#endif /* MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED */
 
-#if defined(MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED)
-static inline int mbedtls_ssl_ciphersuite_uses_ecdh( const mbedtls_ssl_ciphersuite_t *info )
+
+static inline int mbedtls_ssl_ciphersuite_uses_ecdh(
+    mbedtls_ssl_ciphersuite_handle_t info )
 {
-    switch( info->key_exchange )
+    switch( mbedtls_ssl_suite_get_key_exchange( info ) )
     {
         case MBEDTLS_KEY_EXCHANGE_ECDH_RSA:
         case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA:
@@ -467,11 +803,11 @@
             return( 0 );
     }
 }
-#endif /* MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED */
 
-static inline int mbedtls_ssl_ciphersuite_cert_req_allowed( const mbedtls_ssl_ciphersuite_t *info )
+static inline int mbedtls_ssl_ciphersuite_cert_req_allowed(
+    mbedtls_ssl_ciphersuite_handle_t info )
 {
-    switch( info->key_exchange )
+    switch( mbedtls_ssl_suite_get_key_exchange( info ) )
     {
         case MBEDTLS_KEY_EXCHANGE_RSA:
         case MBEDTLS_KEY_EXCHANGE_DHE_RSA:
@@ -486,9 +822,10 @@
     }
 }
 
-static inline int mbedtls_ssl_ciphersuite_uses_srv_cert( const mbedtls_ssl_ciphersuite_t *info )
+static inline int mbedtls_ssl_ciphersuite_uses_srv_cert(
+    mbedtls_ssl_ciphersuite_handle_t info )
 {
-    switch( info->key_exchange )
+    switch( mbedtls_ssl_suite_get_key_exchange( info ) )
     {
         case MBEDTLS_KEY_EXCHANGE_RSA:
         case MBEDTLS_KEY_EXCHANGE_RSA_PSK:
@@ -504,10 +841,10 @@
     }
 }
 
-#if defined(MBEDTLS_KEY_EXCHANGE__SOME__DHE_ENABLED)
-static inline int mbedtls_ssl_ciphersuite_uses_dhe( const mbedtls_ssl_ciphersuite_t *info )
+static inline int mbedtls_ssl_ciphersuite_uses_dhe(
+    mbedtls_ssl_ciphersuite_handle_t info )
 {
-    switch( info->key_exchange )
+    switch( mbedtls_ssl_suite_get_key_exchange( info ) )
     {
         case MBEDTLS_KEY_EXCHANGE_DHE_RSA:
         case MBEDTLS_KEY_EXCHANGE_DHE_PSK:
@@ -517,12 +854,11 @@
             return( 0 );
     }
 }
-#endif /* MBEDTLS_KEY_EXCHANGE__SOME__DHE_ENABLED) */
 
-#if defined(MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED)
-static inline int mbedtls_ssl_ciphersuite_uses_ecdhe( const mbedtls_ssl_ciphersuite_t *info )
+static inline int mbedtls_ssl_ciphersuite_uses_ecdhe(
+    mbedtls_ssl_ciphersuite_handle_t info )
 {
-    switch( info->key_exchange )
+    switch( mbedtls_ssl_suite_get_key_exchange( info ) )
     {
         case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA:
         case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA:
@@ -533,12 +869,11 @@
             return( 0 );
     }
 }
-#endif /* MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED) */
 
-#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED)
-static inline int mbedtls_ssl_ciphersuite_uses_server_signature( const mbedtls_ssl_ciphersuite_t *info )
+static inline int mbedtls_ssl_ciphersuite_uses_server_signature(
+    mbedtls_ssl_ciphersuite_handle_t info )
 {
-    switch( info->key_exchange )
+    switch( mbedtls_ssl_suite_get_key_exchange( info ) )
     {
         case MBEDTLS_KEY_EXCHANGE_DHE_RSA:
         case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA:
@@ -549,7 +884,6 @@
             return( 0 );
     }
 }
-#endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */
 
 #ifdef __cplusplus
 }
diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h
index 74c9f1a..d3b426b 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -383,7 +383,7 @@
 #endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
 #if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \
     defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
-    const mbedtls_ecp_curve_info **curves;      /*!<  Supported elliptic curves */
+    uint16_t curve_tls_id;                      /*!< TLS ID of EC for ECDHE. */
 #endif
 #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
     unsigned char *psk;                 /*!<  PSK from the callback         */
@@ -501,7 +501,9 @@
                     const unsigned char *, size_t,
                     unsigned char *, size_t);
 
-    mbedtls_ssl_ciphersuite_t const *ciphersuite_info;
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info;
+#endif /* !MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
 
     size_t pmslen;                      /*!<  premaster length        */
 
@@ -512,8 +514,14 @@
 #if !defined(MBEDTLS_SSL_NO_SESSION_RESUMPTION)
     int resume;                         /*!<  session resume indicator*/
 #endif /* !MBEDTLS_SSL_NO_SESSION_RESUMPTION */
+
+#if defined(MBEDTLS_SSL_SRV_C) &&                        \
+    ( defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) ||       \
+      defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED ) )
     int max_major_ver;                  /*!< max. major version client*/
     int max_minor_ver;                  /*!< max. minor version client*/
+#endif /* MBEDTLS_SSL_SRV_C && ( MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED ||
+                                 MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED ) */
     int cli_exts;                       /*!< client extension presence*/
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
@@ -556,6 +564,21 @@
 }
 #endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */
 
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
+static inline mbedtls_ssl_ciphersuite_handle_t mbedtls_ssl_handshake_get_ciphersuite(
+    mbedtls_ssl_handshake_params const *handshake )
+{
+    return( handshake->ciphersuite_info );
+}
+#else /* !MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
+static inline mbedtls_ssl_ciphersuite_handle_t mbedtls_ssl_handshake_get_ciphersuite(
+    mbedtls_ssl_handshake_params const *handshake )
+{
+    ((void) handshake);
+    return( MBEDTLS_SSL_CIPHERSUITE_UNIQUE_VALID_HANDLE );
+}
+#endif /* MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
+
 typedef struct mbedtls_ssl_hs_buffer mbedtls_ssl_hs_buffer;
 
 /*
@@ -686,7 +709,10 @@
 
     mbedtls_cipher_context_t cipher_ctx_enc;    /*!<  encryption context      */
     mbedtls_cipher_context_t cipher_ctx_dec;    /*!<  decryption context      */
+
+#if !defined(MBEDTLS_SSL_CONF_FIXED_MINOR_VER)
     int minor_ver;
+#endif
 
 #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
     uint8_t in_cid_len;
@@ -704,6 +730,16 @@
 #endif
 };
 
+static inline int mbedtls_ssl_transform_get_minor_ver( mbedtls_ssl_transform const *transform )
+{
+#if !defined(MBEDTLS_SSL_CONF_FIXED_MINOR_VER)
+    return( transform->minor_ver );
+#else
+    ((void) transform);
+    return( MBEDTLS_SSL_CONF_FIXED_MINOR_VER );
+#endif
+}
+
 /*
  * Internal representation of record frames
  *
@@ -918,7 +954,7 @@
 int mbedtls_ssl_write_finished( mbedtls_ssl_context *ssl );
 
 void mbedtls_ssl_optimize_checksum( mbedtls_ssl_context *ssl,
-                            const mbedtls_ssl_ciphersuite_t *ciphersuite_info );
+                            mbedtls_ssl_ciphersuite_handle_t ciphersuite_info );
 
 #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
 int mbedtls_ssl_psk_derive_premaster( mbedtls_ssl_context *ssl, mbedtls_key_exchange_type_t key_ex );
@@ -943,6 +979,26 @@
                                 mbedtls_md_type_t md );
 #endif
 
+static inline int mbedtls_ssl_get_minor_ver( mbedtls_ssl_context const *ssl )
+{
+#if !defined(MBEDTLS_SSL_CONF_FIXED_MINOR_VER)
+    return( ssl->minor_ver );
+#else /* !MBEDTLS_SSL_CONF_FIXED_MINOR_VER */
+    ((void) ssl);
+    return( MBEDTLS_SSL_CONF_FIXED_MINOR_VER );
+#endif /* MBEDTLS_SSL_CONF_FIXED_MINOR_VER */
+}
+
+static inline int mbedtls_ssl_get_major_ver( mbedtls_ssl_context const *ssl )
+{
+#if !defined(MBEDTLS_SSL_CONF_FIXED_MAJOR_VER)
+    return( ssl->major_ver );
+#else /* !MBEDTLS_SSL_CONF_FIXED_MAJOR_VER */
+    ((void) ssl);
+    return( MBEDTLS_SSL_CONF_FIXED_MAJOR_VER );
+#endif /* MBEDTLS_SSL_CONF_FIXED_MAJOR_VER */
+}
+
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
 static inline mbedtls_pk_context *mbedtls_ssl_own_key( mbedtls_ssl_context *ssl )
 {
@@ -978,16 +1034,11 @@
  * Return 0 if everything is OK, -1 if not.
  */
 int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert,
-                          const mbedtls_ssl_ciphersuite_t *ciphersuite,
+                          mbedtls_ssl_ciphersuite_handle_t ciphersuite,
                           int cert_endpoint,
                           uint32_t *flags );
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
-void mbedtls_ssl_write_version( int major, int minor, int transport,
-                        unsigned char ver[2] );
-void mbedtls_ssl_read_version( int *major, int *minor, int transport,
-                       const unsigned char ver[2] );
-
 static inline size_t mbedtls_ssl_in_hdr_len( const mbedtls_ssl_context *ssl )
 {
     return( (size_t) ( ssl->in_iv - ssl->in_hdr ) );
@@ -1067,6 +1118,69 @@
 #endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \
           MBEDTLS_SSL_PROTO_TLS1_2 */
 
+/*
+ * Convert version numbers to/from wire format
+ * and, for DTLS, to/from TLS equivalent.
+ *
+ * For TLS this is the identity.
+ * For DTLS, use 1's complement (v -> 255 - v, and then map as follows:
+ * 1.0 <-> 3.2      (DTLS 1.0 is based on TLS 1.1)
+ * 1.x <-> 3.x+1    for x != 0 (DTLS 1.2 based on TLS 1.2)
+ */
+static inline void mbedtls_ssl_write_version( int major, int minor,
+                                              int transport,
+                                              unsigned char ver[2] )
+{
+#if !defined(MBEDTLS_SSL_TRANSPORT__BOTH)
+    ((void) transport);
+#endif
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( transport ) )
+    {
+        if( minor == MBEDTLS_SSL_MINOR_VERSION_2 )
+            --minor; /* DTLS 1.0 stored as TLS 1.1 internally */
+
+        ver[0] = (unsigned char)( 255 - ( major - 2 ) );
+        ver[1] = (unsigned char)( 255 - ( minor - 1 ) );
+    }
+    MBEDTLS_SSL_TRANSPORT_ELSE
+#endif
+#if defined(MBEDTLS_SSL_PROTO_TLS)
+    {
+        ver[0] = (unsigned char) major;
+        ver[1] = (unsigned char) minor;
+    }
+#endif
+}
+
+static inline void mbedtls_ssl_read_version( int *major, int *minor,
+                                             int transport,
+                                             const unsigned char ver[2] )
+{
+#if !defined(MBEDTLS_SSL_TRANSPORT__BOTH)
+    ((void) transport);
+#endif
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( transport ) )
+    {
+        *major = 255 - ver[0] + 2;
+        *minor = 255 - ver[1] + 1;
+
+        if( *minor == MBEDTLS_SSL_MINOR_VERSION_1 )
+            ++*minor; /* DTLS 1.0 stored as TLS 1.1 internally */
+    }
+    MBEDTLS_SSL_TRANSPORT_ELSE
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+#if defined(MBEDTLS_SSL_PROTO_TLS)
+    {
+        *major = ver[0];
+        *minor = ver[1];
+    }
+#endif /* MBEDTLS_SSL_PROTO_TLS */
+}
+
 #ifdef __cplusplus
 }
 #endif
@@ -1289,6 +1403,167 @@
 #endif /* MBEDTLS_SSL_CONF_ANTI_REPLAY */
 #endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */
 
+#if !defined(MBEDTLS_SSL_CONF_SET_TIMER)
+static inline mbedtls_ssl_set_timer_t* mbedtls_ssl_get_set_timer(
+    mbedtls_ssl_context const *ssl )
+{
+    return( ssl->f_set_timer );
+}
+#else /* !MBEDTLS_SSL_CONF_SET_TIMER */
+
+#define mbedtls_ssl_conf_set_timer_func MBEDTLS_SSL_CONF_SET_TIMER
+extern void mbedtls_ssl_conf_set_timer_func( void*, uint32_t, uint32_t );
+
+static inline mbedtls_ssl_set_timer_t* mbedtls_ssl_get_set_timer(
+    mbedtls_ssl_context const *ssl )
+{
+    ((void) ssl);
+    return ((mbedtls_ssl_set_timer_t*) mbedtls_ssl_conf_set_timer_func);
+}
+#endif /* MBEDTLS_SSL_CONF_SET_TIMER */
+
+#if !defined(MBEDTLS_SSL_CONF_GET_TIMER)
+static inline mbedtls_ssl_get_timer_t* mbedtls_ssl_get_get_timer(
+    mbedtls_ssl_context const *ssl )
+{
+    return( ssl->f_get_timer );
+}
+#else /* !MBEDTLS_SSL_CONF_GET_TIMER */
+
+#define mbedtls_ssl_conf_get_timer_func MBEDTLS_SSL_CONF_GET_TIMER
+extern int mbedtls_ssl_conf_get_timer_func( void* );
+
+static inline mbedtls_ssl_get_timer_t* mbedtls_ssl_get_get_timer(
+    mbedtls_ssl_context const *ssl )
+{
+    ((void) ssl);
+    return ((mbedtls_ssl_get_timer_t*) mbedtls_ssl_conf_get_timer_func);
+}
+#endif /* MBEDTLS_SSL_CONF_GET_TIMER */
+
+#if !defined(MBEDTLS_SSL_CONF_RECV)
+static inline mbedtls_ssl_recv_t* mbedtls_ssl_get_recv(
+    mbedtls_ssl_context const *ssl )
+{
+    return( ssl->f_recv );
+}
+#else /* !MBEDTLS_SSL_CONF_RECV */
+
+#define mbedtls_ssl_conf_recv_func MBEDTLS_SSL_CONF_RECV
+extern int mbedtls_ssl_conf_recv_func( void*, unsigned char*, size_t );
+
+static inline mbedtls_ssl_recv_t* mbedtls_ssl_get_recv(
+    mbedtls_ssl_context const *ssl )
+{
+    ((void) ssl);
+    return ((mbedtls_ssl_recv_t*) mbedtls_ssl_conf_recv_func);
+}
+#endif /* MBEDTLS_SSL_CONF_RECV */
+
+#if !defined(MBEDTLS_SSL_CONF_SEND)
+static inline mbedtls_ssl_send_t* mbedtls_ssl_get_send(
+    mbedtls_ssl_context const *ssl )
+{
+    return( ssl->f_send );
+}
+#else /* !MBEDTLS_SSL_CONF_SEND */
+
+#define mbedtls_ssl_conf_send_func MBEDTLS_SSL_CONF_SEND
+extern int mbedtls_ssl_conf_send_func( void*, unsigned char const*, size_t );
+
+static inline mbedtls_ssl_send_t* mbedtls_ssl_get_send(
+    mbedtls_ssl_context const *ssl )
+{
+    ((void) ssl);
+    return ((mbedtls_ssl_send_t*) mbedtls_ssl_conf_send_func);
+}
+#endif /* MBEDTLS_SSL_CONF_SEND */
+
+#if !defined(MBEDTLS_SSL_CONF_RECV_TIMEOUT)
+static inline mbedtls_ssl_recv_timeout_t* mbedtls_ssl_get_recv_timeout(
+    mbedtls_ssl_context const *ssl )
+{
+    return( ssl->f_recv_timeout );
+}
+#else /* !MBEDTLS_SSL_CONF_RECV_TIMEOUT */
+
+#define mbedtls_ssl_conf_recv_timeout_func MBEDTLS_SSL_CONF_RECV_TIMEOUT
+extern int mbedtls_ssl_conf_recv_timeout_func(
+    void*, unsigned char*, size_t, uint32_t );
+
+static inline mbedtls_ssl_recv_timeout_t* mbedtls_ssl_get_recv_timeout(
+    mbedtls_ssl_context const *ssl )
+{
+    ((void) ssl);
+    return ((mbedtls_ssl_recv_timeout_t*) mbedtls_ssl_conf_recv_timeout_func);
+}
+#endif /* MBEDTLS_SSL_CONF_RECV_TIMEOUT */
+
+typedef int mbedtls_frng_t( void*, unsigned char*, size_t );
+
+#if !defined(MBEDTLS_SSL_CONF_RNG)
+static inline mbedtls_frng_t* mbedtls_ssl_conf_get_frng(
+    mbedtls_ssl_config const *conf )
+{
+    return( conf->f_rng );
+}
+#else /* !MBEDTLS_SSL_CONF_RNG */
+
+#define mbedtls_ssl_conf_rng_func MBEDTLS_SSL_CONF_RNG
+extern int mbedtls_ssl_conf_rng_func( void*, unsigned char*, size_t );
+
+static inline mbedtls_frng_t* mbedtls_ssl_conf_get_frng(
+    mbedtls_ssl_config const *conf )
+{
+    ((void) conf);
+    return ((mbedtls_frng_t*) mbedtls_ssl_conf_rng_func);
+}
+#endif /* MBEDTLS_SSL_CONF_RNG */
+
+static inline int mbedtls_ssl_conf_get_max_major_ver(
+    mbedtls_ssl_config const *conf )
+{
+#if !defined(MBEDTLS_SSL_CONF_MAX_MAJOR_VER)
+    return( conf->max_major_ver );
+#else
+    ((void) conf);
+    return( MBEDTLS_SSL_CONF_MAX_MAJOR_VER );
+#endif /* MBEDTLS_SSL_CONF_MAX_MAJOR_VER */
+}
+
+static inline int mbedtls_ssl_conf_get_min_major_ver(
+    mbedtls_ssl_config const *conf )
+{
+#if !defined(MBEDTLS_SSL_CONF_MIN_MAJOR_VER)
+    return( conf->min_major_ver );
+#else /* !MBEDTLS_SSL_CONF_MIN_MAJOR_VER */
+    ((void) conf);
+    return( MBEDTLS_SSL_CONF_MIN_MAJOR_VER );
+#endif /* MBEDTLS_SSL_CONF_MIN_MAJOR_VER */
+}
+
+static inline int mbedtls_ssl_conf_get_max_minor_ver(
+    mbedtls_ssl_config const *conf )
+{
+#if !defined(MBEDTLS_SSL_CONF_MAX_MINOR_VER)
+    return( conf->max_minor_ver );
+#else /* !MBEDTLS_SSL_CONF_MAX_MINOR_VER */
+    ((void) conf);
+    return( MBEDTLS_SSL_CONF_MAX_MINOR_VER );
+#endif /* MBEDTLS_SSL_CONF_MAX_MINOR_VER */
+}
+
+static inline int mbedtls_ssl_conf_get_min_minor_ver(
+    mbedtls_ssl_config const *conf )
+{
+#if !defined(MBEDTLS_SSL_CONF_MIN_MINOR_VER)
+    return( conf->min_minor_ver );
+#else /* !MBEDTLS_SSL_CONF_MIN_MINOR_VER */
+    ((void) conf);
+    return( MBEDTLS_SSL_CONF_MIN_MINOR_VER );
+#endif /* MBEDTLS_SSL_CONF_MIN_MINOR_VER */
+}
+
 #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
 static inline unsigned int mbedtls_ssl_conf_get_ems(
     mbedtls_ssl_config const *conf )
@@ -1313,4 +1588,164 @@
 }
 #endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */
 
+/*
+ * Macros for the traversal of the list of all enabled ciphersuites.
+ * This is implemented as a plain loop in case we have a runtime
+ * configurable list of ciphersuites, and as a simple variable
+ * instantiation in case a single ciphersuite is enabled at
+ * compile-time.
+ */
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
+
+#define MBEDTLS_SSL_BEGIN_FOR_EACH_CIPHERSUITE( ssl, ver, info ) \
+    {                                                            \
+        int const *__id_ptr;                                     \
+        for( __id_ptr=(ssl)->conf->ciphersuite_list[ (ver) ];    \
+             *__id_ptr != 0; __id_ptr++ )                        \
+        {                                                        \
+           const int __id = *__id_ptr;                           \
+           mbedtls_ssl_ciphersuite_handle_t info;                \
+           info = mbedtls_ssl_ciphersuite_from_id( __id );       \
+           if( info == MBEDTLS_SSL_CIPHERSUITE_INVALID_HANDLE )  \
+               continue;
+
+#define MBEDTLS_SSL_END_FOR_EACH_CIPHERSUITE  \
+        }                                     \
+    }
+
+#else /* !MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
+
+#define MBEDTLS_SSL_BEGIN_FOR_EACH_CIPHERSUITE( ssl, ver, info )             \
+    do {                                                                     \
+        const mbedtls_ssl_ciphersuite_handle_t info =                        \
+            MBEDTLS_SSL_CIPHERSUITE_UNIQUE_VALID_HANDLE;
+
+#define MBEDTLS_SSL_END_FOR_EACH_CIPHERSUITE    \
+    } while( 0 );
+
+#endif /* MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
+
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_EC)
+
+#define MBEDTLS_SSL_BEGIN_FOR_EACH_SUPPORTED_EC_TLS_ID( TLS_ID_VAR )     \
+    {                                                                    \
+        mbedtls_ecp_group_id const *_gid;                                \
+        mbedtls_ecp_curve_info const *_info;                             \
+        for( _gid = ssl->conf->curve_list;                               \
+             *_gid != MBEDTLS_ECP_DP_NONE; _gid++ )                      \
+        {                                                                \
+            uint16_t TLS_ID_VAR;                                         \
+            _info = mbedtls_ecp_curve_info_from_grp_id( *_gid )   ;      \
+            if( _info == NULL )                                          \
+                continue;                                                \
+            TLS_ID_VAR = _info->tls_id;
+
+#define MBEDTLS_SSL_END_FOR_EACH_SUPPORTED_EC_TLS_ID                    \
+        }                                                               \
+    }
+
+#define MBEDTLS_SSL_BEGIN_FOR_EACH_SUPPORTED_EC_GRP_ID( EC_ID_VAR )     \
+    {                                                                   \
+        mbedtls_ecp_group_id const *_gid;                               \
+        for( _gid = ssl->conf->curve_list;                              \
+             *_gid != MBEDTLS_ECP_DP_NONE; _gid++ )                     \
+        {                                                               \
+            mbedtls_ecp_group_id EC_ID_VAR = *_gid;                     \
+
+#define MBEDTLS_SSL_END_FOR_EACH_SUPPORTED_EC_GRP_ID                    \
+        }                                                               \
+    }
+
+#else /* !MBEDTLS_SSL_CONF_SINGLE_EC */
+
+#define MBEDTLS_SSL_BEGIN_FOR_EACH_SUPPORTED_EC_TLS_ID( TLS_ID_VAR )    \
+    {                                                                   \
+        uint16_t TLS_ID_VAR = MBEDTLS_SSL_CONF_SINGLE_EC_TLS_ID;        \
+        ((void) ssl);
+
+#define MBEDTLS_SSL_END_FOR_EACH_SUPPORTED_EC_TLS_ID                    \
+    }
+
+#define MBEDTLS_SSL_BEGIN_FOR_EACH_SUPPORTED_EC_GRP_ID( EC_ID_VAR )         \
+    {                                                                       \
+        mbedtls_ecp_group_id EC_ID_VAR = MBEDTLS_SSL_CONF_SINGLE_EC_GRP_ID; \
+        ((void) ssl);
+
+#define MBEDTLS_SSL_END_FOR_EACH_SUPPORTED_EC_GRP_ID                    \
+    }
+
+#endif /* MBEDTLS_SSL_CONF_SINGLE_EC */
+
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH)
+
+#define MBEDTLS_SSL_BEGIN_FOR_EACH_SIG_HASH( MD_VAR )    \
+    {                                                                   \
+        int const *__md;                                                \
+        for( __md = ssl->conf->sig_hashes;                              \
+             *__md != MBEDTLS_MD_NONE; __md++ )                         \
+        {                                                               \
+            mbedtls_md_type_t MD_VAR = (mbedtls_md_type_t) *__md;       \
+
+ #define MBEDTLS_SSL_END_FOR_EACH_SIG_HASH                              \
+        }                                                               \
+    }
+
+#define MBEDTLS_SSL_BEGIN_FOR_EACH_SIG_HASH_TLS( HASH_VAR )             \
+    {                                                                   \
+        int const *__md;                                                \
+        for( __md = ssl->conf->sig_hashes;                              \
+             *__md != MBEDTLS_MD_NONE; __md++ )                         \
+        {                                                               \
+            unsigned char HASH_VAR;                                     \
+            HASH_VAR = mbedtls_ssl_hash_from_md_alg( *__md );
+
+#define MBEDTLS_SSL_END_FOR_EACH_SIG_HASH_TLS                           \
+        }                                                               \
+    }
+
+#else /* !MBEDTLS_SSL_CONF_SINGLE_SIG_HASH */
+
+#define MBEDTLS_SSL_BEGIN_FOR_EACH_SIG_HASH( MD_VAR )                   \
+    {                                                                   \
+        mbedtls_md_type_t MD_VAR = MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_MD_ID; \
+        ((void) ssl);
+
+#define MBEDTLS_SSL_END_FOR_EACH_SIG_HASH                               \
+    }
+
+#define MBEDTLS_SSL_BEGIN_FOR_EACH_SIG_HASH_TLS( HASH_VAR )                \
+    {                                                                      \
+        unsigned char HASH_VAR = MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_TLS_ID;  \
+        ((void) ssl);
+
+
+#define MBEDTLS_SSL_END_FOR_EACH_SIG_HASH_TLS                           \
+    }
+
+#endif /* MBEDTLS_SSL_CONF_SINGLE_SIG_HASH */
+
+#if defined(__GNUC__) || defined(__arm__)
+#define MBEDTLS_ALWAYS_INLINE __attribute__((always_inline))
+#else
+#define MBEDTLS_ALWAYS_INLINE
+#endif
+
+/* This internal function can be used to pend a fatal alert for
+ * later delivery.
+ *
+ * The check for pending alerts must be done by calling
+ * the function ssl_send_pending_fatal_alert() in ssl_tls.c.
+ * Currently, it happens only during the handshake loop and after
+ * calling ssl_get_next_record() in the record processing stack.
+ *
+ * This function must not be called multiple times without
+ * sending the pending fatal alerts in between.
+ */
+MBEDTLS_ALWAYS_INLINE static inline void mbedtls_ssl_pend_fatal_alert(
+    mbedtls_ssl_context *ssl,
+    unsigned char message )
+{
+    ssl->pending_fatal_alert_msg = message;
+}
+
 #endif /* ssl_internal.h */
diff --git a/library/ecdsa.c b/library/ecdsa.c
index dc19384..58e1a5f 100644
--- a/library/ecdsa.c
+++ b/library/ecdsa.c
@@ -172,11 +172,11 @@
 }
 #endif /* MBEDTLS_ECDSA_DETERMINISTIC */
 
-#define ECDSA_RS_ECP    &rs_ctx->ecp
+#define ECDSA_RS_ECP    ( rs_ctx == NULL ? NULL : &rs_ctx->ecp )
 
 /* Utility macro for checking and updating ops budget */
 #define ECDSA_BUDGET( ops )   \
-    MBEDTLS_MPI_CHK( mbedtls_ecp_check_budget( grp, &rs_ctx->ecp, ops ) );
+    MBEDTLS_MPI_CHK( mbedtls_ecp_check_budget( grp, ECDSA_RS_ECP, ops ) );
 
 /* Call this when entering a function that needs its own sub-context */
 #define ECDSA_RS_ENTER( SUB )   do {                                 \
diff --git a/library/havege.c b/library/havege.c
index 54f897c..c139e1d 100644
--- a/library/havege.c
+++ b/library/havege.c
@@ -38,8 +38,19 @@
 #include "mbedtls/timing.h"
 #include "mbedtls/platform_util.h"
 
+#include <limits.h>
 #include <string.h>
 
+/* If int isn't capable of storing 2^32 distinct values, the code of this
+ * module may cause a processor trap or a miscalculation. If int is more
+ * than 32 bits, the code may not calculate the intended values. */
+#if INT_MIN + 1 != -0x7fffffff
+#error "The HAVEGE module requires int to be exactly 32 bits, with INT_MIN = -2^31."
+#endif
+#if UINT_MAX != 0xffffffff
+#error "The HAVEGE module requires unsigned to be exactly 32 bits."
+#endif
+
 /* ------------------------------------------------------------------------
  * On average, one iteration accesses two 8-word blocks in the havege WALK
  * table, and generates 16 words in the RES array.
@@ -54,7 +65,7 @@
  * ------------------------------------------------------------------------
  */
 
-#define SWAP(X,Y) { int *T = (X); (X) = (Y); (Y) = T; }
+#define SWAP(X,Y) { unsigned *T = (X); (X) = (Y); (Y) = T; }
 
 #define TST1_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1;
 #define TST2_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1;
@@ -77,7 +88,7 @@
     PTX = (PT1 >> 18) & 7;                              \
     PT1 &= 0x1FFF;                                      \
     PT2 &= 0x1FFF;                                      \
-    CLK = (int) mbedtls_timing_hardclock();                            \
+    CLK = (unsigned) mbedtls_timing_hardclock();        \
                                                         \
     i = 0;                                              \
     A = &WALK[PT1    ]; RES[i++] ^= *A;                 \
@@ -100,7 +111,7 @@
                                                         \
     IN = (*A >> (5)) ^ (*A << (27)) ^ CLK;              \
     *A = (*B >> (6)) ^ (*B << (26)) ^ CLK;              \
-    *B = IN; CLK = (int) mbedtls_timing_hardclock();                   \
+    *B = IN; CLK = (unsigned) mbedtls_timing_hardclock(); \
     *C = (*C >> (7)) ^ (*C << (25)) ^ CLK;              \
     *D = (*D >> (8)) ^ (*D << (24)) ^ CLK;              \
                                                         \
@@ -151,19 +162,20 @@
     PT1 ^= (PT2 ^ 0x10) & 0x10;                         \
                                                         \
     for( n++, i = 0; i < 16; i++ )                      \
-        hs->pool[n % MBEDTLS_HAVEGE_COLLECT_SIZE] ^= RES[i];
+        POOL[n % MBEDTLS_HAVEGE_COLLECT_SIZE] ^= RES[i];
 
 /*
  * Entropy gathering function
  */
 static void havege_fill( mbedtls_havege_state *hs )
 {
-    int i, n = 0;
-    int  U1,  U2, *A, *B, *C, *D;
-    int PT1, PT2, *WALK, RES[16];
-    int PTX, PTY, CLK, PTEST, IN;
+    unsigned i, n = 0;
+    unsigned  U1,  U2, *A, *B, *C, *D;
+    unsigned PT1, PT2, *WALK, *POOL, RES[16];
+    unsigned PTX, PTY, CLK, PTEST, IN;
 
-    WALK = hs->WALK;
+    WALK = (unsigned *) hs->WALK;
+    POOL = (unsigned *) hs->pool;
     PT1  = hs->PT1;
     PT2  = hs->PT2;
 
diff --git a/library/ssl_cache.c b/library/ssl_cache.c
index 62a0a29..bcc2f59 100644
--- a/library/ssl_cache.c
+++ b/library/ssl_cache.c
@@ -84,10 +84,13 @@
             continue;
 #endif
 
-        if( session->ciphersuite != entry->session.ciphersuite ||
+        if( mbedtls_ssl_session_get_ciphersuite( session ) !=
+            mbedtls_ssl_session_get_ciphersuite( &entry->session ) ||
             session->compression != entry->session.compression ||
             session->id_len != entry->session.id_len )
+        {
             continue;
+        }
 
         if( memcmp( session->id, entry->session.id,
                     entry->session.id_len ) != 0 )
diff --git a/library/ssl_ciphersuites.c b/library/ssl_ciphersuites.c
index 518f7dd..ad66007 100644
--- a/library/ssl_ciphersuites.c
+++ b/library/ssl_ciphersuites.c
@@ -54,6 +54,7 @@
  */
 static const int ciphersuite_preference[] =
 {
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
 #if defined(MBEDTLS_SSL_CIPHERSUITES)
     MBEDTLS_SSL_CIPHERSUITES,
 #else
@@ -311,9 +312,13 @@
     MBEDTLS_TLS_PSK_WITH_NULL_SHA,
 
 #endif /* MBEDTLS_SSL_CIPHERSUITES */
+#else /* !MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
+    MBEDTLS_SSL_SUITE_ID( MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE ),
+#endif /* MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
     0
 };
 
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
 static const mbedtls_ssl_ciphersuite_t ciphersuite_definitions[] =
 {
 #if defined(MBEDTLS_CHACHAPOLY_C) && \
@@ -449,11 +454,7 @@
       MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3,
       MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3,
       0 },
-    { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, "TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8",
-      MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA,
-      MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3,
-      MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3,
-      MBEDTLS_CIPHERSUITE_SHORT_TAG },
+    MBEDTLS_SSL_SUITE_INFO( MBEDTLS_SUITE_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 ),
 #endif /* MBEDTLS_CCM_C */
 #endif /* MBEDTLS_AES_C */
 
@@ -2170,8 +2171,9 @@
       MBEDTLS_CIPHER_NONE, MBEDTLS_MD_NONE, MBEDTLS_KEY_EXCHANGE_NONE,
       0, 0, 0, 0, 0 }
 };
+#endif /* !MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
 
-#if defined(MBEDTLS_SSL_CIPHERSUITES)
+#if defined(MBEDTLS_SSL_CIPHERSUITES) || defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
 const int *mbedtls_ssl_list_ciphersuites( void )
 {
     return( ciphersuite_preference );
@@ -2182,18 +2184,19 @@
 static int supported_ciphersuites[MAX_CIPHERSUITES];
 static int supported_init = 0;
 
-static int ciphersuite_is_removed( const mbedtls_ssl_ciphersuite_t *cs_info )
+static int ciphersuite_is_removed( mbedtls_ssl_ciphersuite_handle_t cs_info )
 {
-    (void)cs_info;
+    if( cs_info == MBEDTLS_SSL_CIPHERSUITE_INVALID_HANDLE )
+        return( 1 );
 
 #if defined(MBEDTLS_REMOVE_ARC4_CIPHERSUITES)
-    if( cs_info->cipher == MBEDTLS_CIPHER_ARC4_128 )
+    if( mbedtls_ssl_suite_get_cipher( cs_info ) == MBEDTLS_CIPHER_ARC4_128 )
         return( 1 );
 #endif /* MBEDTLS_REMOVE_ARC4_CIPHERSUITES */
 
 #if defined(MBEDTLS_REMOVE_3DES_CIPHERSUITES)
-    if( cs_info->cipher == MBEDTLS_CIPHER_DES_EDE3_ECB ||
-        cs_info->cipher == MBEDTLS_CIPHER_DES_EDE3_CBC )
+    if( mbedtls_ssl_suite_get_cipher( cs_info ) == MBEDTLS_CIPHER_DES_EDE3_ECB ||
+        mbedtls_ssl_suite_get_cipher( cs_info ) == MBEDTLS_CIPHER_DES_EDE3_CBC )
     {
         return( 1 );
     }
@@ -2217,12 +2220,10 @@
              *p != 0 && q < supported_ciphersuites + MAX_CIPHERSUITES - 1;
              p++ )
         {
-            const mbedtls_ssl_ciphersuite_t *cs_info;
-            if( ( cs_info = mbedtls_ssl_ciphersuite_from_id( *p ) ) != NULL &&
-                !ciphersuite_is_removed( cs_info ) )
-            {
+            mbedtls_ssl_ciphersuite_handle_t cs_info;
+            cs_info = mbedtls_ssl_ciphersuite_from_id( *p );
+            if( !ciphersuite_is_removed( cs_info ) )
                 *(q++) = *p;
-            }
         }
         *q = 0;
 
@@ -2231,12 +2232,13 @@
 
     return( supported_ciphersuites );
 }
-#endif /* MBEDTLS_SSL_CIPHERSUITES */
+#endif /* !( MBEDTLS_SSL_CIPHERSUITES || MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE ) */
 
-const mbedtls_ssl_ciphersuite_t *mbedtls_ssl_ciphersuite_from_string(
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
+mbedtls_ssl_ciphersuite_handle_t mbedtls_ssl_ciphersuite_from_string(
                                                 const char *ciphersuite_name )
 {
-    const mbedtls_ssl_ciphersuite_t *cur = ciphersuite_definitions;
+    mbedtls_ssl_ciphersuite_handle_t cur = ciphersuite_definitions;
 
     if( NULL == ciphersuite_name )
         return( NULL );
@@ -2252,9 +2254,9 @@
     return( NULL );
 }
 
-const mbedtls_ssl_ciphersuite_t *mbedtls_ssl_ciphersuite_from_id( int ciphersuite )
+mbedtls_ssl_ciphersuite_handle_t mbedtls_ssl_ciphersuite_from_id( int ciphersuite )
 {
-    const mbedtls_ssl_ciphersuite_t *cur = ciphersuite_definitions;
+    mbedtls_ssl_ciphersuite_handle_t cur = ciphersuite_definitions;
 
     while( cur->id != 0 )
     {
@@ -2269,7 +2271,7 @@
 
 const char *mbedtls_ssl_get_ciphersuite_name( const int ciphersuite_id )
 {
-    const mbedtls_ssl_ciphersuite_t *cur;
+    mbedtls_ssl_ciphersuite_handle_t cur;
 
     cur = mbedtls_ssl_ciphersuite_from_id( ciphersuite_id );
 
@@ -2281,7 +2283,7 @@
 
 int mbedtls_ssl_get_ciphersuite_id( const char *ciphersuite_name )
 {
-    const mbedtls_ssl_ciphersuite_t *cur;
+    mbedtls_ssl_ciphersuite_handle_t cur;
 
     cur = mbedtls_ssl_ciphersuite_from_string( ciphersuite_name );
 
@@ -2292,82 +2294,62 @@
 }
 
 #if defined(MBEDTLS_PK_C)
-mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_pk_alg( const mbedtls_ssl_ciphersuite_t *info )
+mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_pk_alg(
+    mbedtls_ssl_ciphersuite_handle_t info )
 {
-    switch( info->key_exchange )
-    {
-        case MBEDTLS_KEY_EXCHANGE_RSA:
-        case MBEDTLS_KEY_EXCHANGE_DHE_RSA:
-        case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA:
-        case MBEDTLS_KEY_EXCHANGE_RSA_PSK:
-            return( MBEDTLS_PK_RSA );
-
-        case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA:
-            return( MBEDTLS_PK_ECDSA );
-
-        case MBEDTLS_KEY_EXCHANGE_ECDH_RSA:
-        case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA:
-            return( MBEDTLS_PK_ECKEY );
-
-        default:
-            return( MBEDTLS_PK_NONE );
-    }
+    return( mbedtls_ssl_get_ciphersuite_sig_pk_alg_internal( info ) );
 }
 
-mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_alg( const mbedtls_ssl_ciphersuite_t *info )
+mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_alg(
+    mbedtls_ssl_ciphersuite_handle_t info )
 {
-    switch( info->key_exchange )
-    {
-        case MBEDTLS_KEY_EXCHANGE_RSA:
-        case MBEDTLS_KEY_EXCHANGE_DHE_RSA:
-        case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA:
-            return( MBEDTLS_PK_RSA );
-
-        case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA:
-            return( MBEDTLS_PK_ECDSA );
-
-        default:
-            return( MBEDTLS_PK_NONE );
-    }
+    return( mbedtls_ssl_get_ciphersuite_sig_alg_internal( info ) );
 }
-
 #endif /* MBEDTLS_PK_C */
 
 #if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \
     defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
-int mbedtls_ssl_ciphersuite_uses_ec( const mbedtls_ssl_ciphersuite_t *info )
+int mbedtls_ssl_ciphersuite_uses_ec(
+    mbedtls_ssl_ciphersuite_handle_t info )
 {
-    switch( info->key_exchange )
-    {
-        case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA:
-        case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA:
-        case MBEDTLS_KEY_EXCHANGE_ECDHE_PSK:
-        case MBEDTLS_KEY_EXCHANGE_ECDH_RSA:
-        case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA:
-        case MBEDTLS_KEY_EXCHANGE_ECJPAKE:
-            return( 1 );
-
-        default:
-            return( 0 );
-    }
+    return( mbedtls_ssl_ciphersuite_uses_ec_internal( info ) );
 }
-#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C || MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED*/
+#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C ||
+          MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
 
 #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
-int mbedtls_ssl_ciphersuite_uses_psk( const mbedtls_ssl_ciphersuite_t *info )
+int mbedtls_ssl_ciphersuite_uses_psk(
+    mbedtls_ssl_ciphersuite_handle_t info )
 {
-    switch( info->key_exchange )
-    {
-        case MBEDTLS_KEY_EXCHANGE_PSK:
-        case MBEDTLS_KEY_EXCHANGE_RSA_PSK:
-        case MBEDTLS_KEY_EXCHANGE_DHE_PSK:
-        case MBEDTLS_KEY_EXCHANGE_ECDHE_PSK:
-            return( 1 );
-
-        default:
-            return( 0 );
-    }
+    return( mbedtls_ssl_ciphersuite_uses_psk_internal( info ) );
 }
 #endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */
 
+#else /* !MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
+
+const char *mbedtls_ssl_get_ciphersuite_name(
+    const int ciphersuite_id )
+{
+    static const int single_suite_id =
+        MBEDTLS_SSL_SUITE_ID( MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE );
+
+    if( ciphersuite_id == single_suite_id )
+        return( MBEDTLS_SSL_SUITE_NAME( MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE ) );
+
+    return( "unknown" );
+}
+
+int mbedtls_ssl_get_ciphersuite_id( const char *ciphersuite_name )
+{
+    static const char * const single_suite_name =
+        MBEDTLS_SSL_SUITE_NAME( MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE );
+
+    if( strcmp( ciphersuite_name, single_suite_name ) == 0 )
+        return( MBEDTLS_SSL_SUITE_ID( MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE ) );
+
+    return( 0 );
+}
+
+#endif /* MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
+
 #endif /* MBEDTLS_SSL_TLS_C */
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index 2749389..003aa10 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -173,27 +173,29 @@
     unsigned char *p = buf;
     const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN;
     size_t sig_alg_len = 0;
-    const int *md;
 #if defined(MBEDTLS_RSA_C) || defined(MBEDTLS_ECDSA_C)
     unsigned char *sig_alg_list = buf + 6;
 #endif
 
     *olen = 0;
 
-    if( ssl->conf->max_minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 )
+    if( mbedtls_ssl_conf_get_max_minor_ver( ssl->conf ) !=
+        MBEDTLS_SSL_MINOR_VERSION_3 )
+    {
         return;
+    }
 
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding signature_algorithms extension" ) );
 
-    for( md = ssl->conf->sig_hashes; *md != MBEDTLS_MD_NONE; md++ )
-    {
+    MBEDTLS_SSL_BEGIN_FOR_EACH_SIG_HASH_TLS( hash )
+    ((void) hash);
 #if defined(MBEDTLS_ECDSA_C)
-        sig_alg_len += 2;
+    sig_alg_len += 2;
 #endif
 #if defined(MBEDTLS_RSA_C)
-        sig_alg_len += 2;
+    sig_alg_len += 2;
 #endif
-    }
+    MBEDTLS_SSL_END_FOR_EACH_SIG_HASH_TLS
 
     if( end < p || (size_t)( end - p ) < sig_alg_len + 6 )
     {
@@ -206,17 +208,16 @@
      */
     sig_alg_len = 0;
 
-    for( md = ssl->conf->sig_hashes; *md != MBEDTLS_MD_NONE; md++ )
-    {
+    MBEDTLS_SSL_BEGIN_FOR_EACH_SIG_HASH_TLS( hash )
 #if defined(MBEDTLS_ECDSA_C)
-        sig_alg_list[sig_alg_len++] = mbedtls_ssl_hash_from_md_alg( *md );
-        sig_alg_list[sig_alg_len++] = MBEDTLS_SSL_SIG_ECDSA;
+    sig_alg_list[sig_alg_len++] = hash;
+    sig_alg_list[sig_alg_len++] = MBEDTLS_SSL_SIG_ECDSA;
 #endif
 #if defined(MBEDTLS_RSA_C)
-        sig_alg_list[sig_alg_len++] = mbedtls_ssl_hash_from_md_alg( *md );
-        sig_alg_list[sig_alg_len++] = MBEDTLS_SSL_SIG_RSA;
+    sig_alg_list[sig_alg_len++] = hash;
+    sig_alg_list[sig_alg_len++] = MBEDTLS_SSL_SIG_RSA;
 #endif
-    }
+    MBEDTLS_SSL_END_FOR_EACH_SIG_HASH_TLS
 
     /*
      * enum {
@@ -251,42 +252,34 @@
 
 #if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \
     defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
+static size_t ssl_get_ec_curve_list_length( mbedtls_ssl_context *ssl )
+{
+    size_t ec_list_len = 0;
+
+    MBEDTLS_SSL_BEGIN_FOR_EACH_SUPPORTED_EC_TLS_ID( tls_id )
+    ((void) tls_id);
+    ec_list_len++;
+    MBEDTLS_SSL_END_FOR_EACH_SUPPORTED_EC_TLS_ID
+
+    return( ec_list_len );
+}
+
 static void ssl_write_supported_elliptic_curves_ext( mbedtls_ssl_context *ssl,
                                                      unsigned char *buf,
                                                      size_t *olen )
 {
     unsigned char *p = buf;
     const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN;
-    unsigned char *elliptic_curve_list = p + 6;
     size_t elliptic_curve_len = 0;
-    const mbedtls_ecp_curve_info *info;
-#if defined(MBEDTLS_ECP_C)
-    const mbedtls_ecp_group_id *grp_id;
-#else
-    ((void) ssl);
-#endif
 
     *olen = 0;
 
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding supported_elliptic_curves extension" ) );
 
-#if defined(MBEDTLS_ECP_C)
-    for( grp_id = ssl->conf->curve_list; *grp_id != MBEDTLS_ECP_DP_NONE; grp_id++ )
-#else
-    for( info = mbedtls_ecp_curve_list(); info->grp_id != MBEDTLS_ECP_DP_NONE; info++ )
-#endif
-    {
-#if defined(MBEDTLS_ECP_C)
-        info = mbedtls_ecp_curve_info_from_grp_id( *grp_id );
-#endif
-        if( info == NULL )
-        {
-            MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid curve in ssl configuration" ) );
-            return;
-        }
-
-        elliptic_curve_len += 2;
-    }
+    /* Each elliptic curve is encoded in 2 bytes. */
+    elliptic_curve_len = 2 * ssl_get_ec_curve_list_length( ssl );
+    if( elliptic_curve_len == 0 )
+        return;
 
     if( end < p || (size_t)( end - p ) < 6 + elliptic_curve_len )
     {
@@ -294,24 +287,6 @@
         return;
     }
 
-    elliptic_curve_len = 0;
-
-#if defined(MBEDTLS_ECP_C)
-    for( grp_id = ssl->conf->curve_list; *grp_id != MBEDTLS_ECP_DP_NONE; grp_id++ )
-#else
-    for( info = mbedtls_ecp_curve_list(); info->grp_id != MBEDTLS_ECP_DP_NONE; info++ )
-#endif
-    {
-#if defined(MBEDTLS_ECP_C)
-        info = mbedtls_ecp_curve_info_from_grp_id( *grp_id );
-#endif
-        elliptic_curve_list[elliptic_curve_len++] = info->tls_id >> 8;
-        elliptic_curve_list[elliptic_curve_len++] = info->tls_id & 0xFF;
-    }
-
-    if( elliptic_curve_len == 0 )
-        return;
-
     *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_ELLIPTIC_CURVES >> 8 ) & 0xFF );
     *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_ELLIPTIC_CURVES      ) & 0xFF );
 
@@ -321,6 +296,11 @@
     *p++ = (unsigned char)( ( ( elliptic_curve_len     ) >> 8 ) & 0xFF );
     *p++ = (unsigned char)( ( ( elliptic_curve_len     )      ) & 0xFF );
 
+    MBEDTLS_SSL_BEGIN_FOR_EACH_SUPPORTED_EC_TLS_ID( tls_id )
+    *p++ = tls_id >> 8;
+    *p++ = tls_id & 0xFF;
+    MBEDTLS_SSL_END_FOR_EACH_SUPPORTED_EC_TLS_ID
+
     *olen = 6 + elliptic_curve_len;
 }
 
@@ -394,7 +374,8 @@
 
         ret = mbedtls_ecjpake_write_round_one( &ssl->handshake->ecjpake_ctx,
                                         p + 2, end - p - 2, &kkpp_len,
-                                        ssl->conf->f_rng, ssl->conf->p_rng );
+                                        mbedtls_ssl_conf_get_frng( ssl->conf ),
+                                        ssl->conf->p_rng );
         if( ret != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1 , "mbedtls_ecjpake_write_round_one", ret );
@@ -557,7 +538,8 @@
     *olen = 0;
 
     if( ssl->conf->encrypt_then_mac == MBEDTLS_SSL_ETM_DISABLED ||
-        ssl->conf->max_minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 )
+        mbedtls_ssl_conf_get_max_minor_ver( ssl->conf ) ==
+          MBEDTLS_SSL_MINOR_VERSION_0 )
     {
         return;
     }
@@ -592,7 +574,8 @@
 
     if( mbedtls_ssl_conf_get_ems( ssl->conf ) ==
           MBEDTLS_SSL_EXTENDED_MS_DISABLED ||
-        ssl->conf->max_minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 )
+        mbedtls_ssl_conf_get_max_minor_ver( ssl->conf ) ==
+          MBEDTLS_SSL_MINOR_VERSION_0 )
     {
         return;
     }
@@ -751,14 +734,20 @@
 
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, current time: %lu", t ) );
 #else
-    if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, p, 4 ) ) != 0 )
+    if( ( ret = mbedtls_ssl_conf_get_frng( ssl->conf )
+          ( ssl->conf->p_rng, p, 4 ) ) != 0 )
+    {
         return( ret );
+    }
 
     p += 4;
 #endif /* MBEDTLS_HAVE_TIME */
 
-    if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, p, 28 ) ) != 0 )
+    if( ( ret = mbedtls_ssl_conf_get_frng( ssl->conf )
+          ( ssl->conf->p_rng, p, 28 ) ) != 0 )
+    {
         return( ret );
+    }
 
     return( 0 );
 }
@@ -773,34 +762,44 @@
  *
  * \return          0 if valid, else 1
  */
-static int ssl_validate_ciphersuite( const mbedtls_ssl_ciphersuite_t * suite_info,
+static int ssl_validate_ciphersuite( mbedtls_ssl_ciphersuite_handle_t suite_info,
                                      const mbedtls_ssl_context * ssl,
                                      int min_minor_ver, int max_minor_ver )
 {
     (void) ssl;
-    if( suite_info == NULL )
+    if( suite_info == MBEDTLS_SSL_CIPHERSUITE_INVALID_HANDLE )
         return( 1 );
 
-    if( suite_info->min_minor_ver > max_minor_ver ||
-            suite_info->max_minor_ver < min_minor_ver )
+    if( mbedtls_ssl_suite_get_min_minor_ver( suite_info ) > max_minor_ver ||
+        mbedtls_ssl_suite_get_max_minor_ver( suite_info ) < min_minor_ver )
+    {
         return( 1 );
+    }
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
     if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
-            ( suite_info->flags & MBEDTLS_CIPHERSUITE_NODTLS ) )
+        ( mbedtls_ssl_suite_get_flags( suite_info ) &
+          MBEDTLS_CIPHERSUITE_NODTLS ) != 0 )
+    {
         return( 1 );
+    }
 #endif
 
 #if defined(MBEDTLS_ARC4_C)
     if( ssl->conf->arc4_disabled == MBEDTLS_SSL_ARC4_DISABLED &&
-            suite_info->cipher == MBEDTLS_CIPHER_ARC4_128 )
+        mbedtls_ssl_suite_get_cipher( suite_info ) == MBEDTLS_CIPHER_ARC4_128 )
+    {
         return( 1 );
+    }
 #endif
 
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
-    if( suite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE &&
-            mbedtls_ecjpake_check( &ssl->handshake->ecjpake_ctx ) != 0 )
+    if( mbedtls_ssl_suite_get_key_exchange( suite_info ) ==
+          MBEDTLS_KEY_EXCHANGE_ECJPAKE &&
+        mbedtls_ecjpake_check( &ssl->handshake->ecjpake_ctx ) != 0 )
+    {
         return( 1 );
+    }
 #endif
 
     return( 0 );
@@ -813,8 +812,6 @@
     unsigned char *buf;
     unsigned char *p, *q;
     unsigned char offer_compress;
-    const int *ciphersuites;
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
 #if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \
     defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
     int uses_ec = 0;
@@ -822,7 +819,7 @@
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write client hello" ) );
 
-    if( ssl->conf->f_rng == NULL )
+    if( mbedtls_ssl_conf_get_frng( ssl->conf ) == NULL )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "no RNG provided") );
         return( MBEDTLS_ERR_SSL_NO_RNG );
@@ -830,11 +827,15 @@
 
     if( mbedtls_ssl_get_renego_status( ssl ) == MBEDTLS_SSL_INITIAL_HANDSHAKE )
     {
-        ssl->major_ver = ssl->conf->min_major_ver;
-        ssl->minor_ver = ssl->conf->min_minor_ver;
+#if !defined(MBEDTLS_SSL_CONF_FIXED_MAJOR_VER)
+        ssl->major_ver = mbedtls_ssl_conf_get_min_major_ver( ssl->conf );
+#endif /* !MBEDTLS_SSL_CONF_FIXED_MAJOR_VER */
+#if !defined(MBEDTLS_SSL_CONF_FIXED_MINOR_VER)
+        ssl->minor_ver = mbedtls_ssl_conf_get_min_minor_ver( ssl->conf );
+#endif /* !MBEDTLS_SSL_CONF_FIXED_MINOR_VER */
     }
 
-    if( ssl->conf->max_major_ver == 0 )
+    if( mbedtls_ssl_conf_get_max_major_ver( ssl->conf ) == 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "configured max major version is invalid, "
                             "consider using mbedtls_ssl_config_defaults()" ) );
@@ -851,8 +852,9 @@
     buf = ssl->out_msg;
     p = buf + 4;
 
-    mbedtls_ssl_write_version( ssl->conf->max_major_ver, ssl->conf->max_minor_ver,
-                       ssl->conf->transport, p );
+    mbedtls_ssl_write_version( mbedtls_ssl_conf_get_max_major_ver( ssl->conf ),
+                               mbedtls_ssl_conf_get_max_minor_ver( ssl->conf ),
+                               ssl->conf->transport, p );
     p += 2;
 
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, max version: [%d:%d]",
@@ -908,7 +910,8 @@
         ssl->session_negotiate->ticket != NULL &&
         ssl->session_negotiate->ticket_len != 0 )
     {
-        ret = ssl->conf->f_rng( ssl->conf->p_rng, ssl->session_negotiate->id, 32 );
+        ret = mbedtls_ssl_conf_get_frng( ssl->conf )
+            ( ssl->conf->p_rng, ssl->session_negotiate->id, 32 );
 
         if( ret != 0 )
             return( ret );
@@ -953,24 +956,25 @@
     /*
      * Ciphersuite list
      */
-    ciphersuites = ssl->conf->ciphersuite_list[ssl->minor_ver];
 
     /* Skip writing ciphersuite length for now */
     n = 0;
     q = p;
     p += 2;
 
-    for( i = 0; ciphersuites[i] != 0; i++ )
+    MBEDTLS_SSL_BEGIN_FOR_EACH_CIPHERSUITE( ssl,
+                                            mbedtls_ssl_get_minor_ver( ssl ),
+                                            ciphersuite_info )
     {
-        ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( ciphersuites[i] );
-
         if( ssl_validate_ciphersuite( ciphersuite_info, ssl,
-                                      ssl->conf->min_minor_ver,
-                                      ssl->conf->max_minor_ver ) != 0 )
+                       mbedtls_ssl_conf_get_min_minor_ver( ssl->conf ),
+                       mbedtls_ssl_conf_get_max_minor_ver( ssl->conf ) ) != 0 )
+        {
             continue;
+        }
 
         MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, add ciphersuite: %04x",
-                                    ciphersuites[i] ) );
+                              mbedtls_ssl_suite_get_id( ciphersuite_info ) ) );
 
 #if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \
     defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
@@ -978,9 +982,12 @@
 #endif
 
         n++;
-        *p++ = (unsigned char)( ciphersuites[i] >> 8 );
-        *p++ = (unsigned char)( ciphersuites[i]      );
+        *p++ = (unsigned char)(
+            mbedtls_ssl_suite_get_id( ciphersuite_info ) >> 8 );
+        *p++ = (unsigned char)(
+            mbedtls_ssl_suite_get_id( ciphersuite_info )      );
     }
+    MBEDTLS_SSL_END_FOR_EACH_CIPHERSUITE
 
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, got %d ciphersuites (excluding SCSVs)", n ) );
 
@@ -1178,8 +1185,8 @@
                           ssl->peer_verify_data, ssl->verify_data_len ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching renegotiation info" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                   MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
             return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
         }
     }
@@ -1189,8 +1196,8 @@
         if( len != 1 || buf[0] != 0x00 )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-zero length renegotiation info" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                   MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
             return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
         }
 
@@ -1214,8 +1221,8 @@
         buf[0] != ssl->conf->mfl_code )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching max fragment length extension" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1232,8 +1239,8 @@
         len != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching truncated HMAC extension" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1258,16 +1265,16 @@
         ssl->negotiate_cid == MBEDTLS_SSL_CID_DISABLED )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "CID extension unexpected" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                     MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
     if( len == 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "CID extension invalid" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                     MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1277,16 +1284,16 @@
     if( peer_cid_len > MBEDTLS_SSL_CID_OUT_LEN_MAX )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "CID extension invalid" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                     MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
     if( len != peer_cid_len )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "CID extension invalid" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                     MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1307,12 +1314,12 @@
                                          size_t len )
 {
     if( ssl->conf->encrypt_then_mac == MBEDTLS_SSL_ETM_DISABLED ||
-        ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ||
+        mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_0 ||
         len != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching encrypt-then-MAC extension" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1331,12 +1338,12 @@
 {
     if( mbedtls_ssl_conf_get_ems( ssl->conf ) ==
           MBEDTLS_SSL_EXTENDED_MS_DISABLED ||
-        ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ||
+        mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_0 ||
         len != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching extended master secret extension" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1354,8 +1361,8 @@
         len != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching session ticket extension" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1379,8 +1386,8 @@
     if( len == 0 || (size_t)( buf[0] + 1 ) != len )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
     list_size = buf[0];
@@ -1406,8 +1413,8 @@
     }
 
     MBEDTLS_SSL_DEBUG_MSG( 1, ( "no point format in common" ) );
-    mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                    MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+    mbedtls_ssl_pend_fatal_alert( ssl,
+                                  MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
     return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
 }
 #endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C ||
@@ -1420,8 +1427,9 @@
 {
     int ret;
 
-    if( ssl->handshake->ciphersuite_info->key_exchange !=
-        MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    if( mbedtls_ssl_suite_get_key_exchange(
+            mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake ) )
+        != MBEDTLS_KEY_EXCHANGE_ECJPAKE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 3, ( "skip ecjpake kkpp extension" ) );
         return( 0 );
@@ -1436,8 +1444,8 @@
                                                 buf, len ) ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_read_round_one", ret );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( ret );
     }
 
@@ -1456,8 +1464,8 @@
     if( ssl->conf->alpn_list == NULL )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching ALPN extension" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1474,24 +1482,24 @@
     /* Min length is 2 (list_len) + 1 (name_len) + 1 (name) */
     if( len < 4 )
     {
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
     list_len = ( buf[0] << 8 ) | buf[1];
     if( list_len != len - 2 )
     {
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
     name_len = buf[2];
     if( name_len != list_len - 1 )
     {
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1507,8 +1515,8 @@
     }
 
     MBEDTLS_SSL_DEBUG_MSG( 1, ( "ALPN extension: no matching protocol" ) );
-    mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                    MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+    mbedtls_ssl_pend_fatal_alert( ssl,
+                                  MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
     return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
 }
 #endif /* MBEDTLS_SSL_ALPN */
@@ -1541,13 +1549,13 @@
      */
     if( major_ver < MBEDTLS_SSL_MAJOR_VERSION_3 ||
         minor_ver < MBEDTLS_SSL_MINOR_VERSION_2 ||
-        major_ver > ssl->conf->max_major_ver  ||
-        minor_ver > ssl->conf->max_minor_ver  )
+        major_ver > mbedtls_ssl_conf_get_max_major_ver( ssl->conf )  ||
+        minor_ver > mbedtls_ssl_conf_get_max_minor_ver( ssl->conf )  )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server version" ) );
 
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                     MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION );
 
         return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION );
     }
@@ -1559,8 +1567,8 @@
     {
         MBEDTLS_SSL_DEBUG_MSG( 1,
             ( "cookie length does not match incoming message size" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                    MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1605,7 +1613,9 @@
     int extended_ms_seen = 0;
 #endif
     int handshake_failure = 0;
-    const mbedtls_ssl_ciphersuite_t *suite_info;
+
+    /* The ciphersuite chosen by the server. */
+    mbedtls_ssl_ciphersuite_handle_t server_suite_info;
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse server hello" ) );
 
@@ -1641,8 +1651,8 @@
 #endif /* MBEDTLS_SSL_RENEGOTIATION */
 
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                        MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
         return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
     }
 
@@ -1669,8 +1679,8 @@
         buf[0] != MBEDTLS_SSL_HS_SERVER_HELLO )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1687,25 +1697,40 @@
      */
     buf += mbedtls_ssl_hs_hdr_len( ssl );
 
-    MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, version", buf + 0, 2 );
-    mbedtls_ssl_read_version( &ssl->major_ver, &ssl->minor_ver,
-                      ssl->conf->transport, buf + 0 );
-
-    if( ssl->major_ver < ssl->conf->min_major_ver ||
-        ssl->minor_ver < ssl->conf->min_minor_ver ||
-        ssl->major_ver > ssl->conf->max_major_ver ||
-        ssl->minor_ver > ssl->conf->max_minor_ver )
     {
-        MBEDTLS_SSL_DEBUG_MSG( 1, ( "server version out of bounds - "
-                            " min: [%d:%d], server: [%d:%d], max: [%d:%d]",
-                            ssl->conf->min_major_ver, ssl->conf->min_minor_ver,
-                            ssl->major_ver, ssl->minor_ver,
-                            ssl->conf->max_major_ver, ssl->conf->max_minor_ver ) );
+        int major_ver, minor_ver;
 
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                     MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION );
+        MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, version", buf + 0, 2 );
+        mbedtls_ssl_read_version( &major_ver, &minor_ver,
+                                  ssl->conf->transport,
+                                  buf + 0 );
 
-        return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION );
+        if( major_ver < mbedtls_ssl_conf_get_min_major_ver( ssl->conf ) ||
+            minor_ver < mbedtls_ssl_conf_get_min_minor_ver( ssl->conf ) ||
+            major_ver > mbedtls_ssl_conf_get_max_major_ver( ssl->conf ) ||
+            minor_ver > mbedtls_ssl_conf_get_max_minor_ver( ssl->conf ) )
+        {
+            MBEDTLS_SSL_DEBUG_MSG( 1, ( "server version out of bounds - "
+                         " min: [%d:%d], server: [%d:%d], max: [%d:%d]",
+                         mbedtls_ssl_conf_get_min_major_ver( ssl->conf ),
+                         mbedtls_ssl_conf_get_min_minor_ver( ssl->conf ),
+                         major_ver, minor_ver,
+                         mbedtls_ssl_conf_get_max_major_ver( ssl->conf ),
+                         mbedtls_ssl_conf_get_max_minor_ver( ssl->conf ) ) );
+
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                 MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION );
+
+            return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION );
+        }
+
+#if !defined(MBEDTLS_SSL_CONF_FIXED_MINOR_VER)
+        ssl->minor_ver = minor_ver;
+#endif /* !MBEDTLS_SSL_CONF_FIXED_MINOR_VER */
+
+#if !defined(MBEDTLS_SSL_CONF_FIXED_MAJOR_VER)
+        ssl->major_ver = major_ver;
+#endif /* !MBEDTLS_SSL_CONF_FIXED_MAJOR_VER */
     }
 
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, current time: %lu",
@@ -1723,8 +1748,8 @@
     if( n > 32 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1737,8 +1762,8 @@
             ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) + 40 + n + ext_len )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
         }
     }
@@ -1749,8 +1774,8 @@
     else
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1773,24 +1798,26 @@
 #endif/* MBEDTLS_ZLIB_SUPPORT */
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "server hello, bad compression: %d", comp ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
         return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
     }
 
     /*
      * Initialize update checksum functions
      */
-    ssl->handshake->ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( i );
-    if( ssl->handshake->ciphersuite_info == NULL )
+    server_suite_info = mbedtls_ssl_ciphersuite_from_id( i );
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
+    ssl->handshake->ciphersuite_info = server_suite_info;
+#endif
+    if( server_suite_info == MBEDTLS_SSL_CIPHERSUITE_INVALID_HANDLE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "ciphersuite info for %04x not found", i ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
     }
-
-    mbedtls_ssl_optimize_checksum( ssl, ssl->handshake->ciphersuite_info );
+    mbedtls_ssl_optimize_checksum( ssl, server_suite_info );
 
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, session id len.: %d", n ) );
     MBEDTLS_SSL_DEBUG_BUF( 3,   "server hello, session id", buf + 35, n );
@@ -1809,7 +1836,7 @@
 #if !defined(MBEDTLS_SSL_NO_SESSION_RESUMPTION)
     if( n == 0 ||
         mbedtls_ssl_get_renego_status( ssl ) != MBEDTLS_SSL_INITIAL_HANDSHAKE ||
-        ssl->session_negotiate->ciphersuite != i ||
+        mbedtls_ssl_session_get_ciphersuite( ssl->session_negotiate ) != i ||
         ssl->session_negotiate->compression != comp ||
         ssl->session_negotiate->id_len != n ||
         memcmp( ssl->session_negotiate->id, buf + 35, n ) != 0 )
@@ -1826,8 +1853,8 @@
         if( ( ret = mbedtls_ssl_derive_keys( ssl ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_derive_keys", ret );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                  MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
             return( ret );
         }
     }
@@ -1838,7 +1865,9 @@
 #if defined(MBEDTLS_HAVE_TIME)
         ssl->session_negotiate->start = mbedtls_time( NULL );
 #endif
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
         ssl->session_negotiate->ciphersuite = i;
+#endif /* MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
         ssl->session_negotiate->compression = comp;
         ssl->session_negotiate->id_len = n;
         memcpy( ssl->session_negotiate->id, buf + 35, n );
@@ -1853,38 +1882,40 @@
     /*
      * Perform cipher suite validation in same way as in ssl_write_client_hello.
      */
-    i = 0;
-    while( 1 )
+    MBEDTLS_SSL_BEGIN_FOR_EACH_CIPHERSUITE( ssl,
+                                            mbedtls_ssl_get_minor_ver( ssl ),
+                                            ciphersuite_info )
     {
-        if( ssl->conf->ciphersuite_list[ssl->minor_ver][i] == 0 )
+        if( ssl_validate_ciphersuite( ciphersuite_info, ssl,
+                    mbedtls_ssl_conf_get_min_minor_ver( ssl->conf ),
+                    mbedtls_ssl_conf_get_max_minor_ver( ssl->conf ) ) != 0 )
         {
-            MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello 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_HELLO );
+            continue;
         }
 
-        if( ssl->conf->ciphersuite_list[ssl->minor_ver][i++] ==
-            ssl->session_negotiate->ciphersuite )
-        {
-            break;
-        }
-    }
+        if( ciphersuite_info != server_suite_info )
+            continue;
 
-    suite_info = mbedtls_ssl_ciphersuite_from_id( ssl->session_negotiate->ciphersuite );
-    if( ssl_validate_ciphersuite( suite_info, ssl, ssl->minor_ver, ssl->minor_ver ) != 0 )
-    {
-        MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello 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_HELLO );
+        goto server_picked_valid_suite;
     }
+    MBEDTLS_SSL_END_FOR_EACH_CIPHERSUITE
 
-    MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %s", suite_info->name ) );
+    /* If we reach this code-path, the server's chosen ciphersuite
+     * wasn't among those advertised by us. */
+    MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
+    mbedtls_ssl_pend_fatal_alert( ssl,
+                                  MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+    return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
+
+server_picked_valid_suite:
+
+    MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %s",
+                                mbedtls_ssl_suite_get_name( server_suite_info ) ) );
 
 #if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
-    if( suite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA &&
-        ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
+    if( mbedtls_ssl_suite_get_key_exchange( server_suite_info ) ==
+          MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA &&
+        mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_3 )
     {
         ssl->handshake->ecrs_enabled = 1;
     }
@@ -1897,15 +1928,16 @@
       )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
     ssl->session_negotiate->compression = comp;
 
     ext = buf + 40 + n;
 
-    MBEDTLS_SSL_DEBUG_MSG( 2, ( "server hello, total extension length: %d", ext_len ) );
+    MBEDTLS_SSL_DEBUG_MSG( 2, ( "server hello, total extension length: %d",
+                                ext_len ) );
 
     while( ext_len )
     {
@@ -1917,8 +1949,8 @@
         if( ext_size + 4 > ext_len )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
         }
 
@@ -2129,8 +2161,8 @@
 
     if( handshake_failure == 1 )
     {
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -2313,7 +2345,7 @@
                                     size_t pms_offset )
 {
     int ret;
-    size_t len_bytes = ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ? 0 : 2;
+    size_t len_bytes = mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_0 ? 0 : 2;
     unsigned char *p = ssl->handshake->premaster + pms_offset;
     mbedtls_pk_context *peer_pk = NULL;
 
@@ -2330,10 +2362,12 @@
      *      opaque random[46];
      *  } PreMasterSecret;
      */
-    mbedtls_ssl_write_version( ssl->conf->max_major_ver, ssl->conf->max_minor_ver,
-                       ssl->conf->transport, p );
+    mbedtls_ssl_write_version( mbedtls_ssl_conf_get_max_major_ver( ssl->conf ),
+                               mbedtls_ssl_conf_get_max_minor_ver( ssl->conf ),
+                               ssl->conf->transport, p );
 
-    if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, p + 2, 46 ) ) != 0 )
+    if( ( ret = mbedtls_ssl_conf_get_frng( ssl->conf )
+          ( ssl->conf->p_rng, p + 2, 46 ) ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, "f_rng", ret );
         return( ret );
@@ -2382,7 +2416,8 @@
                             p, ssl->handshake->pmslen,
                             ssl->out_msg + offset + len_bytes, olen,
                             MBEDTLS_SSL_OUT_CONTENT_LEN - offset - len_bytes,
-                            ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
+                            mbedtls_ssl_conf_get_frng( ssl->conf ),
+                            ssl->conf->p_rng ) ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_rsa_pkcs1_encrypt", ret );
         goto cleanup;
@@ -2427,7 +2462,7 @@
     *pk_alg = MBEDTLS_PK_NONE;
 
     /* Only in TLS 1.2 */
-    if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 )
+    if( mbedtls_ssl_get_minor_ver( ssl ) != MBEDTLS_SSL_MINOR_VERSION_3 )
     {
         return( 0 );
     }
@@ -2545,14 +2580,15 @@
 static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl )
 {
     int ret;
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
-        ssl->handshake->ciphersuite_info;
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info =
+        mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake );
     unsigned char *p = NULL, *end = NULL;
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse server key exchange" ) );
 
 #if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA )
+    if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) ==
+        MBEDTLS_KEY_EXCHANGE_RSA )
     {
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse server key exchange" ) );
         ssl->state++;
@@ -2564,14 +2600,16 @@
 
 #if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \
     defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_RSA ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA )
+    if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) ==
+        MBEDTLS_KEY_EXCHANGE_ECDH_RSA ||
+        mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) ==
+        MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA )
     {
         if( ( ret = ssl_get_ecdh_params_from_cert( ssl ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "ssl_get_ecdh_params_from_cert", ret );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                    MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
             return( ret );
         }
 
@@ -2601,8 +2639,8 @@
     if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE )
     {
         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_UNEXPECTED_MESSAGE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                               MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
         return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
     }
 
@@ -2612,8 +2650,10 @@
      */
     if( ssl->in_msg[0] != MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE )
     {
-        if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-            ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK )
+        if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+            == MBEDTLS_KEY_EXCHANGE_PSK ||
+            mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+            == MBEDTLS_KEY_EXCHANGE_RSA_PSK )
         {
             /* Current message is probably either
              * CertificateRequest or ServerHelloDone */
@@ -2623,8 +2663,8 @@
 
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "server key exchange message must "
                                     "not be skipped" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                               MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
 
         return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
     }
@@ -2640,16 +2680,20 @@
     MBEDTLS_SSL_DEBUG_BUF( 3,   "server key exchange", p, end - p );
 
 #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK )
+    if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_PSK                             ||
+        mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_RSA_PSK                         ||
+        mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_DHE_PSK                         ||
+        mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK )
     {
         if( ssl_parse_server_psk_hint( 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 );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                               MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
             return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
         }
     } /* FALLTROUGH */
@@ -2657,22 +2701,28 @@
 
 #if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) ||                       \
     defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED)
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK )
+    if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_PSK                              ||
+        mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_RSA_PSK )
+    {
         ; /* nothing more to do */
+    }
     else
 #endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED ||
           MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */
 #if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) ||                       \
     defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED)
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_RSA ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK )
+    if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_DHE_RSA ||
+        mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_DHE_PSK )
     {
         if( ssl_parse_server_dh_params( 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 );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                   MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
             return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
         }
     }
@@ -2682,15 +2732,18 @@
 #if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) ||                     \
     defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_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_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA )
+    if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA                         ||
+        mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK                         ||
+        mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA )
     {
         if( ssl_parse_server_ecdh_params( 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 );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                   MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
             return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
         }
     }
@@ -2699,15 +2752,16 @@
           MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED ||
           MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
     {
         ret = mbedtls_ecjpake_read_round_two( &ssl->handshake->ecjpake_ctx,
                                               p, end - p );
         if( ret != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_read_round_two", ret );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                   MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
             return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
         }
     }
@@ -2735,22 +2789,22 @@
          * Handle the digitally-signed structure
          */
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
-        if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
+        if( mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_3 )
         {
             if( ssl_parse_signature_algorithm( ssl, &p, end,
                                                &md_alg, &pk_alg ) != 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 );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                                    MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
                 return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
             }
 
             if( pk_alg != mbedtls_ssl_get_ciphersuite_sig_pk_alg( ciphersuite_info ) )
             {
                 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 );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                                     MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
                 return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
             }
         }
@@ -2758,7 +2812,7 @@
 #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
 #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \
     defined(MBEDTLS_SSL_PROTO_TLS1_1)
-        if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 )
+        if( mbedtls_ssl_get_minor_ver( ssl ) < MBEDTLS_SSL_MINOR_VERSION_3 )
         {
             pk_alg = mbedtls_ssl_get_ciphersuite_sig_pk_alg( ciphersuite_info );
 
@@ -2780,8 +2834,8 @@
         if( p > end - 2 )
         {
             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_DECODE_ERROR );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
         }
         sig_len = ( p[0] << 8 ) | p[1];
@@ -2790,8 +2844,8 @@
         if( p != end - sig_len )
         {
             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_DECODE_ERROR );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
         }
 
@@ -2858,8 +2912,8 @@
         if( !mbedtls_pk_can_do( peer_pk, pk_alg ) )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
 #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
             mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert );
 #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
@@ -2877,8 +2931,10 @@
 #if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
             if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS )
 #endif
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                                MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR );
+            {
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                                     MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR );
+            }
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret );
 #if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
             if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
@@ -2912,8 +2968,8 @@
 #if ! defined(MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED)
 static int ssl_parse_certificate_request( mbedtls_ssl_context *ssl )
 {
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
-        ssl->handshake->ciphersuite_info;
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info =
+        mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake );
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate request" ) );
 
@@ -2934,8 +2990,8 @@
     unsigned char *buf;
     size_t n = 0;
     size_t cert_type_len = 0, dn_len = 0;
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
-        ssl->handshake->ciphersuite_info;
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info =
+        mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake );
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate request" ) );
 
@@ -2955,8 +3011,8 @@
     if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                              MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
         return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
     }
 
@@ -3003,8 +3059,8 @@
     if( ssl->in_hslen <= mbedtls_ssl_hs_hdr_len( ssl ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                               MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST );
     }
     cert_type_len = buf[mbedtls_ssl_hs_hdr_len( ssl )];
@@ -3023,14 +3079,14 @@
     if( ssl->in_hslen <= mbedtls_ssl_hs_hdr_len( ssl ) + 2 + n )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST );
     }
 
     /* supported_signature_algorithms */
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
-    if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
+    if( mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_3 )
     {
         size_t sig_alg_len = ( ( buf[mbedtls_ssl_hs_hdr_len( ssl ) + 1 + n] <<  8 )
                              | ( buf[mbedtls_ssl_hs_hdr_len( ssl ) + 2 + n]       ) );
@@ -3054,8 +3110,8 @@
         if( ssl->in_hslen <= mbedtls_ssl_hs_hdr_len( ssl ) + 3 + n + sig_alg_len )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST );
         }
 
@@ -3080,8 +3136,8 @@
     if( ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) + 3 + n )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST );
     }
 
@@ -3114,8 +3170,8 @@
         ssl->in_msg[0] != MBEDTLS_SSL_HS_SERVER_HELLO_DONE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello done message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE );
     }
 
@@ -3135,13 +3191,13 @@
 {
     int ret;
     size_t i, n;
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
-        ssl->handshake->ciphersuite_info;
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info =
+        mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake );
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write client key exchange" ) );
 
 #if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_RSA )
+    if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) == MBEDTLS_KEY_EXCHANGE_DHE_RSA )
     {
         /*
          * DHM key exchange -- send G^X mod P
@@ -3155,7 +3211,8 @@
         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 );
+                                mbedtls_ssl_conf_get_frng( ssl->conf ),
+                                ssl->conf->p_rng );
         if( ret != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_make_public", ret );
@@ -3169,7 +3226,8 @@
                                       ssl->handshake->premaster,
                                       MBEDTLS_PREMASTER_SIZE,
                                      &ssl->handshake->pmslen,
-                                      ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
+                                      mbedtls_ssl_conf_get_frng( ssl->conf ),
+                                      ssl->conf->p_rng ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_calc_secret", ret );
             return( ret );
@@ -3183,10 +3241,14 @@
     defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) ||                   \
     defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) ||                      \
     defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_RSA ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA )
+    if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA                       ||
+        mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA                     ||
+        mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_ECDH_RSA                        ||
+        mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA )
     {
         /*
          * ECDH key exchange -- send client public value
@@ -3206,7 +3268,8 @@
         ret = mbedtls_ecdh_make_public( &ssl->handshake->ecdh_ctx,
                                 &n,
                                 &ssl->out_msg[i], 1000,
-                                ssl->conf->f_rng, ssl->conf->p_rng );
+                                mbedtls_ssl_conf_get_frng( ssl->conf ),
+                                ssl->conf->p_rng );
         if( ret != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_public", ret );
@@ -3235,7 +3298,8 @@
                                       &ssl->handshake->pmslen,
                                        ssl->handshake->premaster,
                                        MBEDTLS_MPI_MAX_SIZE,
-                                       ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
+                                       mbedtls_ssl_conf_get_frng( ssl->conf ),
+                                       ssl->conf->p_rng ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_calc_secret", ret );
 #if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
@@ -3282,14 +3346,16 @@
         i += ssl->conf->psk_identity_len;
 
 #if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
-        if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK )
+        if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+            == MBEDTLS_KEY_EXCHANGE_PSK )
         {
             n = 0;
         }
         else
 #endif
 #if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED)
-        if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK )
+        if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+            == MBEDTLS_KEY_EXCHANGE_RSA_PSK )
         {
             if( ( ret = ssl_write_encrypted_pms( ssl, i, &n, 2 ) ) != 0 )
                 return( ret );
@@ -3297,7 +3363,8 @@
         else
 #endif
 #if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED)
-        if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK )
+        if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+            == MBEDTLS_KEY_EXCHANGE_DHE_PSK )
         {
             /*
              * ClientDiffieHellmanPublic public (DHM send G^X mod P)
@@ -3317,7 +3384,8 @@
             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 );
+                    mbedtls_ssl_conf_get_frng( ssl->conf ),
+                    ssl->conf->p_rng );
             if( ret != 0 )
             {
                 MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_make_public", ret );
@@ -3327,14 +3395,16 @@
         else
 #endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */
 #if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED)
-        if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK )
+        if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+            == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK )
         {
             /*
              * ClientECDiffieHellmanPublic public;
              */
             ret = mbedtls_ecdh_make_public( &ssl->handshake->ecdh_ctx, &n,
                     &ssl->out_msg[i], MBEDTLS_SSL_OUT_CONTENT_LEN - i,
-                    ssl->conf->f_rng, ssl->conf->p_rng );
+                    mbedtls_ssl_conf_get_frng( ssl->conf ),
+                    ssl->conf->p_rng );
             if( ret != 0 )
             {
                 MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_public", ret );
@@ -3352,7 +3422,7 @@
         }
 
         if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl,
-                        ciphersuite_info->key_exchange ) ) != 0 )
+               mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_psk_derive_premaster", ret );
             return( ret );
@@ -3361,7 +3431,8 @@
     else
 #endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */
 #if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA )
+    if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) ==
+        MBEDTLS_KEY_EXCHANGE_RSA )
     {
         i = 4;
         if( ( ret = ssl_write_encrypted_pms( ssl, i, &n, 0 ) ) != 0 )
@@ -3370,13 +3441,15 @@
     else
 #endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) ==
+        MBEDTLS_KEY_EXCHANGE_ECJPAKE )
     {
         i = 4;
 
         ret = mbedtls_ecjpake_write_round_two( &ssl->handshake->ecjpake_ctx,
                 ssl->out_msg + i, MBEDTLS_SSL_OUT_CONTENT_LEN - i, &n,
-                ssl->conf->f_rng, ssl->conf->p_rng );
+                mbedtls_ssl_conf_get_frng( ssl->conf ),
+                ssl->conf->p_rng );
         if( ret != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_write_round_two", ret );
@@ -3385,7 +3458,8 @@
 
         ret = mbedtls_ecjpake_derive_secret( &ssl->handshake->ecjpake_ctx,
                 ssl->handshake->premaster, 32, &ssl->handshake->pmslen,
-                ssl->conf->f_rng, ssl->conf->p_rng );
+                mbedtls_ssl_conf_get_frng( ssl->conf ),
+                ssl->conf->p_rng );
         if( ret != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_derive_secret", ret );
@@ -3420,8 +3494,8 @@
 #if !defined(MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED)
 static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl )
 {
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
-        ssl->handshake->ciphersuite_info;
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info =
+        mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake );
     int ret;
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate verify" ) );
@@ -3446,8 +3520,8 @@
 static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
-        ssl->handshake->ciphersuite_info;
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info =
+        mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake );
     size_t n = 0, offset = 0;
     unsigned char hash[48];
     unsigned char *hash_start = hash;
@@ -3505,7 +3579,7 @@
 
 #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \
     defined(MBEDTLS_SSL_PROTO_TLS1_1)
-    if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 )
+    if( mbedtls_ssl_get_minor_ver( ssl ) != MBEDTLS_SSL_MINOR_VERSION_3 )
     {
         /*
          * digitally-signed struct {
@@ -3535,7 +3609,7 @@
 #endif /* MBEDTLS_SSL_PROTO_SSL3 || MBEDTLS_SSL_PROTO_TLS1 || \
           MBEDTLS_SSL_PROTO_TLS1_1 */
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
-    if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
+    if( mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_3 )
     {
         /*
          * digitally-signed struct {
@@ -3552,7 +3626,9 @@
          * Reason: Otherwise we should have running hashes for SHA512 and SHA224
          *         in order to satisfy 'weird' needs from the server side.
          */
-        if( ssl->handshake->ciphersuite_info->mac == MBEDTLS_MD_SHA384 )
+        if( mbedtls_ssl_suite_get_mac(
+                mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake ) )
+            == MBEDTLS_MD_SHA384 )
         {
             md_alg = MBEDTLS_MD_SHA384;
             ssl->out_msg[4] = MBEDTLS_SSL_HASH_SHA384;
@@ -3583,7 +3659,8 @@
     if( ( ret = mbedtls_pk_sign_restartable( mbedtls_ssl_own_key( ssl ),
                          md_alg, hash_start, hashlen,
                          ssl->out_msg + 6 + offset, &n,
-                         ssl->conf->f_rng, ssl->conf->p_rng, rs_ctx ) ) != 0 )
+                         mbedtls_ssl_conf_get_frng( ssl->conf ),
+                         ssl->conf->p_rng, rs_ctx ) ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_sign", ret );
 #if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
@@ -3634,8 +3711,8 @@
     if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                         MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
         return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
     }
 
@@ -3653,8 +3730,8 @@
         ssl->in_hslen < 6 + mbedtls_ssl_hs_hdr_len( ssl ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET );
     }
 
@@ -3668,8 +3745,8 @@
     if( ticket_len + 6 + mbedtls_ssl_hs_hdr_len( ssl ) != ssl->in_hslen )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET );
     }
 
@@ -3704,8 +3781,8 @@
     if( ( ticket = mbedtls_calloc( 1, ticket_len ) ) == NULL )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "ticket alloc failed" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
         return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
     }
 
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index 66f25ea..573f327 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -94,16 +94,16 @@
     if( len < 2 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                       MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
     servername_list_size = ( ( buf[0] << 8 ) | ( buf[1] ) );
     if( servername_list_size + 2 != len )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -114,8 +114,8 @@
         if( hostname_len + 3 > servername_list_size )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
         }
 
@@ -126,7 +126,7 @@
             if( ret != 0 )
             {
                 MBEDTLS_SSL_DEBUG_RET( 1, "ssl_sni_wrapper", ret );
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                mbedtls_ssl_pend_fatal_alert( ssl,
                         MBEDTLS_SSL_ALERT_MSG_UNRECOGNIZED_NAME );
                 return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
             }
@@ -140,8 +140,8 @@
     if( servername_list_size != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -163,8 +163,8 @@
                           ssl->verify_data_len ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching renegotiation info" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                  MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
             return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
         }
     }
@@ -174,8 +174,8 @@
         if( len != 1 || buf[0] != 0x0 )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-zero length renegotiation info" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                  MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
             return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
         }
 
@@ -214,8 +214,8 @@
 
     if ( len < 2 ) {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                       MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
     sig_alg_list_size = ( ( buf[0] << 8 ) | ( buf[1] ) );
@@ -223,8 +223,8 @@
         sig_alg_list_size % 2 != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -279,17 +279,16 @@
 #if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \
     defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
 static int ssl_parse_supported_elliptic_curves( mbedtls_ssl_context *ssl,
-                                                const unsigned char *buf,
-                                                size_t len )
+                        const unsigned char *buf, size_t len,
+                        unsigned char const **list_start, size_t *list_len )
 {
-    size_t list_size, our_size;
+    size_t list_size;
     const unsigned char *p;
-    const mbedtls_ecp_curve_info *curve_info, **curves;
 
     if ( len < 2 ) {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                       MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
     list_size = ( ( buf[0] << 8 ) | ( buf[1] ) );
@@ -297,45 +296,28 @@
         list_size % 2 != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
-    /* Should never happen unless client duplicates the extension */
-    if( ssl->handshake->curves != NULL )
-    {
-        MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
-        return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
-    }
-
-    /* Don't allow our peer to make us allocate too much memory,
-     * and leave room for a final 0 */
-    our_size = list_size / 2 + 1;
-    if( our_size > MBEDTLS_ECP_DP_MAX )
-        our_size = MBEDTLS_ECP_DP_MAX;
-
-    if( ( curves = mbedtls_calloc( our_size, sizeof( *curves ) ) ) == NULL )
-    {
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
-        return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
-    }
-
-    ssl->handshake->curves = curves;
-
     p = buf + 2;
-    while( list_size > 0 && our_size > 1 )
-    {
-        curve_info = mbedtls_ecp_curve_info_from_tls_id( ( p[0] << 8 ) | p[1] );
 
-        if( curve_info != NULL )
+    /* Remember list for later. */
+    *list_start = p;
+    *list_len = list_size / 2;
+
+    while( list_size > 0 )
+    {
+        uint16_t const peer_tls_id = ( p[0] << 8 ) | p[1];
+
+        MBEDTLS_SSL_BEGIN_FOR_EACH_SUPPORTED_EC_TLS_ID( own_tls_id )
+        if( own_tls_id == peer_tls_id &&
+            ssl->handshake->curve_tls_id == 0 )
         {
-            *curves++ = curve_info;
-            our_size--;
+            ssl->handshake->curve_tls_id = own_tls_id;
         }
+        MBEDTLS_SSL_END_FOR_EACH_SUPPORTED_EC_TLS_ID
 
         list_size -= 2;
         p += 2;
@@ -354,8 +336,8 @@
     if( len == 0 || (size_t)( buf[0] + 1 ) != len )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
     list_size = buf[0];
@@ -402,8 +384,8 @@
                                                 buf, len ) ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_read_round_one", ret );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
         return( ret );
     }
 
@@ -422,8 +404,8 @@
     if( len != 1 || buf[0] >= MBEDTLS_SSL_MAX_FRAG_LEN_INVALID )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -444,8 +426,8 @@
     if( MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -461,8 +443,8 @@
     if( len < 1 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -472,8 +454,8 @@
     if( len != peer_cid_len )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -489,8 +471,8 @@
     if( peer_cid_len > MBEDTLS_SSL_CID_OUT_LEN_MAX )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -513,8 +495,8 @@
     if( len != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -535,7 +517,7 @@
     if( len != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+        mbedtls_ssl_pend_fatal_alert( ssl,
                                         MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
@@ -543,7 +525,7 @@
     ((void) buf);
 
     if( ssl->conf->encrypt_then_mac == MBEDTLS_SSL_ETM_ENABLED &&
-        ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_0 )
+        mbedtls_ssl_get_minor_ver( ssl ) != MBEDTLS_SSL_MINOR_VERSION_0 )
     {
         ssl->session_negotiate->encrypt_then_mac = MBEDTLS_SSL_ETM_ENABLED;
     }
@@ -560,8 +542,8 @@
     if( len != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -668,16 +650,16 @@
     /* Min length is 2 (list_len) + 1 (name_len) + 1 (name) */
     if( len < 4 )
     {
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
     list_len = ( buf[0] << 8 ) | buf[1];
     if( list_len != len - 2 )
     {
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -693,16 +675,16 @@
         /* Current identifier must fit in list */
         if( cur_len > (size_t)( end - theirs ) )
         {
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
         }
 
         /* Empty strings MUST NOT be included */
         if( cur_len == 0 )
         {
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
             return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
         }
     }
@@ -727,8 +709,8 @@
     }
 
     /* If we get there, no match was found */
-    mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                            MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL );
+    mbedtls_ssl_pend_fatal_alert( ssl,
+                                  MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL );
     return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
 }
 #endif /* MBEDTLS_SSL_ALPN */
@@ -743,16 +725,28 @@
  */
 #if defined(MBEDTLS_ECDSA_C)
 static int ssl_check_key_curve( mbedtls_pk_context *pk,
-                                const mbedtls_ecp_curve_info **curves )
+                                unsigned char const *acceptable_ec_tls_ids,
+                                size_t ec_tls_ids_len )
 {
-    const mbedtls_ecp_curve_info **crv = curves;
+    mbedtls_ecp_curve_info const *info;
     mbedtls_ecp_group_id grp_id = mbedtls_pk_ec( *pk )->grp.id;
 
-    while( *crv != NULL )
+    info = mbedtls_ecp_curve_info_from_grp_id( grp_id );
+    if( info == NULL )
+        return( -1 );
+
+    if( acceptable_ec_tls_ids == NULL )
+        return( -1 );
+
+    while( ec_tls_ids_len-- != 0 )
     {
-        if( (*crv)->grp_id == grp_id )
+        uint16_t const cur_tls_id =
+            ( acceptable_ec_tls_ids[0] << 8 ) | acceptable_ec_tls_ids[1];
+
+        if( cur_tls_id == info->tls_id )
             return( 0 );
-        crv++;
+
+        acceptable_ec_tls_ids += 2;
     }
 
     return( -1 );
@@ -764,7 +758,9 @@
  * return 0 on success and -1 on failure.
  */
 static int ssl_pick_cert( mbedtls_ssl_context *ssl,
-                          const mbedtls_ssl_ciphersuite_t * ciphersuite_info )
+                          mbedtls_ssl_ciphersuite_handle_t ciphersuite_info,
+                          unsigned char const *acceptable_ec_tls_ids,
+                          size_t ec_tls_ids_len )
 {
     mbedtls_ssl_key_cert *cur, *list, *fallback = NULL;
     mbedtls_pk_type_t pk_alg =
@@ -829,11 +825,16 @@
 
 #if defined(MBEDTLS_ECDSA_C)
         if( pk_alg == MBEDTLS_PK_ECDSA &&
-            ssl_check_key_curve( pk, ssl->handshake->curves ) != 0 )
+            ssl_check_key_curve( pk,
+                                 acceptable_ec_tls_ids,
+                                 ec_tls_ids_len ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: elliptic curve" ) );
             match = 0;
         }
+#else
+        ((void) acceptable_ec_tls_ids);
+        ((void) ec_tls_ids_len);
 #endif
 
 #if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
@@ -866,7 +867,7 @@
          * present them a SHA-higher cert rather than failing if it's the only
          * one we got that satisfies the other conditions.
          */
-        if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 )
+        if( mbedtls_ssl_get_minor_ver( ssl ) < MBEDTLS_SSL_MINOR_VERSION_3 )
         {
             mbedtls_md_type_t sig_md;
             {
@@ -920,27 +921,23 @@
  * Check if a given ciphersuite is suitable for use with our config/keys/etc
  * Sets ciphersuite_info only if the suite matches.
  */
-static int ssl_ciphersuite_match( mbedtls_ssl_context *ssl, int suite_id,
-                                  const mbedtls_ssl_ciphersuite_t **ciphersuite_info )
+static int ssl_ciphersuite_is_match( mbedtls_ssl_context *ssl,
+                            mbedtls_ssl_ciphersuite_handle_t suite_info,
+                            unsigned char const *acceptable_ec_tls_ids,
+                            size_t ec_tls_ids_len )
 {
-    const mbedtls_ssl_ciphersuite_t *suite_info;
-
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \
     defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED)
     mbedtls_pk_type_t sig_type;
 #endif
 
-    suite_info = mbedtls_ssl_ciphersuite_from_id( suite_id );
-    if( suite_info == NULL )
-    {
-        MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
-        return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
-    }
+    MBEDTLS_SSL_DEBUG_MSG( 3, ( "trying ciphersuite: %s",
+                                mbedtls_ssl_suite_get_name( suite_info ) ) );
 
-    MBEDTLS_SSL_DEBUG_MSG( 3, ( "trying ciphersuite: %s", suite_info->name ) );
-
-    if( suite_info->min_minor_ver > ssl->minor_ver ||
-        suite_info->max_minor_ver < ssl->minor_ver )
+    if( mbedtls_ssl_suite_get_min_minor_ver( suite_info )
+          > mbedtls_ssl_get_minor_ver( ssl ) ||
+        mbedtls_ssl_suite_get_max_minor_ver( suite_info )
+          < mbedtls_ssl_get_minor_ver( ssl ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: version" ) );
         return( 0 );
@@ -948,13 +945,16 @@
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
     if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) &&
-        ( suite_info->flags & MBEDTLS_CIPHERSUITE_NODTLS ) )
+        ( mbedtls_ssl_suite_get_flags( suite_info ) &
+          MBEDTLS_CIPHERSUITE_NODTLS ) )
+    {
         return( 0 );
+    }
 #endif
 
 #if defined(MBEDTLS_ARC4_C)
     if( ssl->conf->arc4_disabled == MBEDTLS_SSL_ARC4_DISABLED &&
-            suite_info->cipher == MBEDTLS_CIPHER_ARC4_128 )
+        mbedtls_ssl_suite_get_cipher( suite_info ) == MBEDTLS_CIPHER_ARC4_128 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: rc4" ) );
         return( 0 );
@@ -962,7 +962,8 @@
 #endif
 
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
-    if( suite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE &&
+    if( mbedtls_ssl_suite_get_key_exchange( suite_info ) ==
+        MBEDTLS_KEY_EXCHANGE_ECJPAKE &&
         ( ssl->handshake->cli_exts & MBEDTLS_TLS_EXT_ECJPAKE_KKPP_OK ) == 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: ecjpake "
@@ -971,11 +972,9 @@
     }
 #endif
 
-
 #if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C)
     if( mbedtls_ssl_ciphersuite_uses_ec( suite_info ) &&
-        ( ssl->handshake->curves == NULL ||
-          ssl->handshake->curves[0] == NULL ) )
+        ssl->handshake->curve_tls_id == 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: "
                             "no common elliptic curve" ) );
@@ -1000,7 +999,7 @@
     defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED)
     /* If the ciphersuite requires signing, check whether
      * a suitable hash algorithm is present. */
-    if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
+    if( mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_3 )
     {
         sig_type = mbedtls_ssl_get_ciphersuite_sig_alg( suite_info );
         if( sig_type != MBEDTLS_PK_NONE &&
@@ -1023,16 +1022,20 @@
      * - try the next ciphersuite if we don't
      * This must be done last since we modify the key_cert list.
      */
-    if( ssl_pick_cert( ssl, suite_info ) != 0 )
+    if( ssl_pick_cert( ssl, suite_info,
+                       acceptable_ec_tls_ids,
+                       ec_tls_ids_len ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: "
                             "no suitable certificate" ) );
         return( 0 );
     }
+#else
+    ((void) acceptable_ec_tls_ids);
+    ((void) ec_tls_ids_len);
 #endif
 
-    *ciphersuite_info = suite_info;
-    return( 0 );
+    return( 1 );
 }
 
 #if defined(MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO)
@@ -1043,8 +1046,9 @@
     size_t n;
     unsigned int ciph_len, sess_len, chal_len;
     unsigned char *buf, *p;
-    const int *ciphersuites;
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info;
+#endif
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse client hello v2" ) );
 
@@ -1052,8 +1056,8 @@
     if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "client hello v2 illegal for renegotiation" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 #endif /* MBEDTLS_SSL_RENEGOTIATION */
@@ -1095,23 +1099,30 @@
     }
 
     ssl->major_ver = MBEDTLS_SSL_MAJOR_VERSION_3;
-    ssl->minor_ver = ( buf[4] <= ssl->conf->max_minor_ver )
-                     ? buf[4]  : ssl->conf->max_minor_ver;
+    ssl->minor_ver =
+        ( buf[4] <= mbedtls_ssl_conf_get_max_minor_ver( ssl->conf ) )
+        ? buf[4]  : mbedtls_ssl_conf_get_max_minor_ver( ssl->conf );
 
-    if( ssl->minor_ver < ssl->conf->min_minor_ver )
+    if( mbedtls_ssl_get_minor_ver( ssl ) < mbedtls_ssl_conf_get_min_minor_ver( ssl->conf ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "client only supports ssl smaller than minimum"
                             " [%d:%d] < [%d:%d]",
-                            ssl->major_ver, ssl->minor_ver,
-                            ssl->conf->min_major_ver, ssl->conf->min_minor_ver ) );
+                            mbedtls_ssl_get_major_ver( ssl ),
+                            mbedtls_ssl_get_minor_ver( ssl ),
+                            mbedtls_ssl_conf_get_min_major_ver( ssl->conf ),
+                            mbedtls_ssl_conf_get_min_minor_ver( ssl->conf ) ) );
 
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                     MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION );
         return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION );
     }
 
+#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) ||        \
+    defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED)
     ssl->handshake->max_major_ver = buf[3];
     ssl->handshake->max_minor_ver = buf[4];
+#endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED ||
+          MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */
 
     if( ( ret = mbedtls_ssl_fetch_input( ssl, 2 + n ) ) != 0 )
     {
@@ -1199,8 +1210,8 @@
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "received RENEGOTIATION SCSV "
                                     "during renegotiation" ) );
 
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                                MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                             MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
                 return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
             }
 #endif /* MBEDTLS_SSL_RENEGOTIATION */
@@ -1218,12 +1229,13 @@
         {
             MBEDTLS_SSL_DEBUG_MSG( 3, ( "received FALLBACK_SCSV" ) );
 
-            if( ssl->minor_ver < ssl->conf->max_minor_ver )
+            if( mbedtls_ssl_get_minor_ver( ssl ) <
+                mbedtls_ssl_conf_get_max_minor_ver( ssl->conf ) )
             {
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "inapropriate fallback" ) );
 
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                         MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK );
 
                 return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
             }
@@ -1234,30 +1246,50 @@
 #endif /* MBEDTLS_SSL_FALLBACK_SCSV */
 
     got_common_suite = 0;
-    ciphersuites = ssl->conf->ciphersuite_list[ssl->minor_ver];
-    ciphersuite_info = NULL;
 #if defined(MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE)
     for( j = 0, p = buf + 6; j < ciph_len; j += 3, p += 3 )
-        for( i = 0; ciphersuites[i] != 0; i++ )
-#else
-    for( i = 0; ciphersuites[i] != 0; i++ )
-        for( j = 0, p = buf + 6; j < ciph_len; j += 3, p += 3 )
-#endif
+    {
+        MBEDTLS_SSL_BEGIN_FOR_EACH_CIPHERSUITE( ssl,                              \
+                                                mbedtls_ssl_get_minor_ver( ssl ), \
+                                                cur_info )
         {
+#else
+    MBEDTLS_SSL_BEGIN_FOR_EACH_CIPHERSUITE( ssl,                              \
+                                            mbedtls_ssl_get_minor_ver( ssl ), \
+                                            cur_info )
+    {
+        for( j = 0, p = buf + 6; j < ciph_len; j += 3, p += 3 )
+        {
+#endif
+            const int ciphersuite_id =
+                mbedtls_ssl_suite_get_id( cur_info );
+
             if( p[0] != 0 ||
-                p[1] != ( ( ciphersuites[i] >> 8 ) & 0xFF ) ||
-                p[2] != ( ( ciphersuites[i]      ) & 0xFF ) )
+                p[1] != ( ( ciphersuite_id >> 8 ) & 0xFF ) ||
+                p[2] != ( ( ciphersuite_id      ) & 0xFF ) )
+            {
                 continue;
+            }
 
             got_common_suite = 1;
 
-            if( ( ret = ssl_ciphersuite_match( ssl, ciphersuites[i],
-                                               &ciphersuite_info ) ) != 0 )
-                return( ret );
-
-            if( ciphersuite_info != NULL )
+            if( ssl_ciphersuite_is_match( ssl, cur_info, NULL, 0 ) )
+            {
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
+                ciphersuite_info = cur_info;
+#endif
                 goto have_ciphersuite_v2;
+            }
+
+#if defined(MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE)
         }
+        MBEDTLS_SSL_END_FOR_EACH_CIPHERSUITE
+    }
+#else
+        }
+    }
+    MBEDTLS_SSL_END_FOR_EACH_CIPHERSUITE
+#endif
 
     if( got_common_suite )
     {
@@ -1272,10 +1304,16 @@
     }
 
 have_ciphersuite_v2:
-    MBEDTLS_SSL_DEBUG_MSG( 2, ( "selected ciphersuite: %s", ciphersuite_info->name ) );
 
-    ssl->session_negotiate->ciphersuite = ciphersuites[i];
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
+    ssl->session_negotiate->ciphersuite =
+        mbedtls_ssl_suite_get_id( ciphersuite_info );
     ssl->handshake->ciphersuite_info = ciphersuite_info;
+#endif
+
+    MBEDTLS_SSL_DEBUG_MSG( 2, ( "selected ciphersuite: %s",
+        mbedtls_ssl_get_ciphersuite_name(
+            mbedtls_ssl_session_get_ciphersuite( ssl->session_negotiate ) ) ) );
 
     /*
      * SSLv2 Client Hello relevant renegotiation security checks
@@ -1285,8 +1323,8 @@
           MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "legacy renegotiation, breaking off handshake" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -1319,10 +1357,15 @@
     int extended_ms_seen = 0;
 #endif
     int handshake_failure = 0;
-    const int *ciphersuites;
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
+
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info;
+#endif
     int major, minor;
 
+    unsigned char const *acceptable_ec_tls_ids = NULL;
+    size_t ec_tls_ids_len = 0;
+
     /* If there is no signature-algorithm extension present,
      * we need to fall back to the default values for allowed
      * signature-hash pairs. */
@@ -1588,31 +1631,47 @@
      */
     MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, version", buf, 2 );
 
-    mbedtls_ssl_read_version( &ssl->major_ver, &ssl->minor_ver,
-                      ssl->conf->transport, buf );
-
-    ssl->handshake->max_major_ver = ssl->major_ver;
-    ssl->handshake->max_minor_ver = ssl->minor_ver;
-
-    if( ssl->major_ver < ssl->conf->min_major_ver ||
-        ssl->minor_ver < ssl->conf->min_minor_ver )
     {
-        MBEDTLS_SSL_DEBUG_MSG( 1, ( "client only supports ssl smaller than minimum"
+        int minor_ver, major_ver;
+        mbedtls_ssl_read_version( &major_ver, &minor_ver,
+                                  ssl->conf->transport,
+                                  buf );
+
+#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) ||        \
+    defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED)
+        ssl->handshake->max_major_ver = major_ver;
+        ssl->handshake->max_minor_ver = minor_ver;
+#endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED ||
+          MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */
+
+        if( major_ver < mbedtls_ssl_conf_get_min_major_ver( ssl->conf ) ||
+            minor_ver < mbedtls_ssl_conf_get_min_minor_ver( ssl->conf ) )
+        {
+            MBEDTLS_SSL_DEBUG_MSG( 1, ( "client only supports ssl smaller than minimum"
                             " [%d:%d] < [%d:%d]",
-                            ssl->major_ver, ssl->minor_ver,
-                            ssl->conf->min_major_ver, ssl->conf->min_minor_ver ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                     MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION );
-        return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION );
-    }
+                            major_ver, minor_ver,
+                            mbedtls_ssl_conf_get_min_major_ver( ssl->conf ),
+                            mbedtls_ssl_conf_get_min_minor_ver( ssl->conf ) ) );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                  MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION );
+            return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION );
+        }
 
-    if( ssl->major_ver > ssl->conf->max_major_ver )
-    {
-        ssl->major_ver = ssl->conf->max_major_ver;
-        ssl->minor_ver = ssl->conf->max_minor_ver;
+        if( major_ver > mbedtls_ssl_conf_get_max_major_ver( ssl->conf ) )
+        {
+            major_ver = mbedtls_ssl_conf_get_max_major_ver( ssl->conf );
+            minor_ver = mbedtls_ssl_conf_get_max_minor_ver( ssl->conf );
+        }
+        else if( minor_ver > mbedtls_ssl_conf_get_max_minor_ver( ssl->conf ) )
+            minor_ver = mbedtls_ssl_conf_get_max_minor_ver( ssl->conf );
+
+#if !defined(MBEDTLS_SSL_CONF_FIXED_MAJOR_VER)
+        ssl->major_ver = major_ver;
+#endif /* MBEDTLS_SSL_CONF_FIXED_MAJOR_VER */
+#if !defined(MBEDTLS_SSL_CONF_FIXED_MINOR_VER)
+        ssl->minor_ver = minor_ver;
+#endif /* MBEDTLS_SSL_CONF_FIXED_MINOR_VER */
     }
-    else if( ssl->minor_ver > ssl->conf->max_minor_ver )
-        ssl->minor_ver = ssl->conf->max_minor_ver;
 
     /*
      * Save client random (inc. Unix time)
@@ -1630,8 +1689,8 @@
         sess_len + 34 + 2 > msg_len ) /* 2 for cipherlist length field */
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -1655,8 +1714,8 @@
         if( cookie_offset + 1 + cookie_len + 2 > msg_len )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                               MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION );
             return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
         }
 
@@ -1715,8 +1774,8 @@
         ( ciph_len % 2 ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -1735,8 +1794,8 @@
         comp_len + comp_offset + 1 > msg_len )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -1763,7 +1822,8 @@
 
     /* Do not parse the extensions if the protocol is SSLv3 */
 #if defined(MBEDTLS_SSL_PROTO_SSL3)
-    if( ( ssl->major_ver != 3 ) || ( ssl->minor_ver != 0 ) )
+    if( ( mbedtls_ssl_get_major_ver( ssl ) != 3 ) ||
+        ( mbedtls_ssl_get_minor_ver( ssl ) != 0 ) )
     {
 #endif
         /*
@@ -1775,8 +1835,8 @@
             if( msg_len < ext_offset + 2 )
             {
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                                MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
                 return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
             }
 
@@ -1787,8 +1847,8 @@
                 msg_len != ext_offset + 2 + ext_len )
             {
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                                MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                                         MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
                 return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
             }
         }
@@ -1804,8 +1864,8 @@
             unsigned int ext_size;
             if ( ext_len < 4 ) {
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                               MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                                         MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
                 return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
             }
             ext_id   = ( ( ext[0] <<  8 ) | ( ext[1] ) );
@@ -1814,8 +1874,8 @@
             if( ext_size + 4 > ext_len )
             {
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                                MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
                 return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
             }
             switch( ext_id )
@@ -1862,7 +1922,10 @@
             case MBEDTLS_TLS_EXT_SUPPORTED_ELLIPTIC_CURVES:
                 MBEDTLS_SSL_DEBUG_MSG( 3, ( "found supported elliptic curves extension" ) );
 
-                ret = ssl_parse_supported_elliptic_curves( ssl, ext + 4, ext_size );
+                ret = ssl_parse_supported_elliptic_curves( ssl, ext + 4,
+                                                      ext_size,
+                                                      &acceptable_ec_tls_ids,
+                                                      &ec_tls_ids_len );
                 if( ret != 0 )
                     return( ret );
                 break;
@@ -1970,8 +2033,8 @@
             if( ext_len > 0 && ext_len < 4 )
             {
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                                MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                                         MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
                 return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
             }
         }
@@ -1987,12 +2050,13 @@
         {
             MBEDTLS_SSL_DEBUG_MSG( 2, ( "received FALLBACK_SCSV" ) );
 
-            if( ssl->minor_ver < ssl->conf->max_minor_ver )
+            if( mbedtls_ssl_get_minor_ver( ssl ) <
+                mbedtls_ssl_conf_get_max_minor_ver( ssl->conf ) )
             {
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "inapropriate fallback" ) );
 
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                              MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK );
 
                 return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
             }
@@ -2035,8 +2099,8 @@
             {
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "received RENEGOTIATION SCSV "
                                             "during renegotiation" ) );
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                                MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                                    MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
                 return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
             }
 #endif
@@ -2105,8 +2169,8 @@
 
     if( handshake_failure == 1 )
     {
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                            MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -2116,51 +2180,78 @@
      * and certificate from the SNI callback triggered by the SNI extension.)
      */
     got_common_suite = 0;
-    ciphersuites = ssl->conf->ciphersuite_list[ssl->minor_ver];
-    ciphersuite_info = NULL;
 #if defined(MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE)
     for( j = 0, p = buf + ciph_offset + 2; j < ciph_len; j += 2, p += 2 )
-        for( i = 0; ciphersuites[i] != 0; i++ )
-#else
-    for( i = 0; ciphersuites[i] != 0; i++ )
-        for( j = 0, p = buf + ciph_offset + 2; j < ciph_len; j += 2, p += 2 )
-#endif
+    {
+        MBEDTLS_SSL_BEGIN_FOR_EACH_CIPHERSUITE( ssl,                              \
+                                                mbedtls_ssl_get_minor_ver( ssl ), \
+                                                cur_info )
         {
-            if( p[0] != ( ( ciphersuites[i] >> 8 ) & 0xFF ) ||
-                p[1] != ( ( ciphersuites[i]      ) & 0xFF ) )
+#else
+    MBEDTLS_SSL_BEGIN_FOR_EACH_CIPHERSUITE( ssl,                              \
+                                            mbedtls_ssl_get_minor_ver( ssl ), \
+                                            cur_info )
+    {
+        for( j = 0, p = buf + ciph_offset + 2; j < ciph_len; j += 2, p += 2 )
+        {
+#endif
+            const int ciphersuite_id =
+                mbedtls_ssl_suite_get_id( cur_info );
+
+            if( p[0] != ( ( ciphersuite_id >> 8 ) & 0xFF ) ||
+                p[1] != ( ( ciphersuite_id      ) & 0xFF ) )
+            {
                 continue;
+            }
 
             got_common_suite = 1;
 
-            if( ( ret = ssl_ciphersuite_match( ssl, ciphersuites[i],
-                                               &ciphersuite_info ) ) != 0 )
-                return( ret );
-
-            if( ciphersuite_info != NULL )
+            if( ssl_ciphersuite_is_match( ssl, cur_info,
+                                          acceptable_ec_tls_ids,
+                                          ec_tls_ids_len ) != 0 )
+            {
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
+                ciphersuite_info = cur_info;
+#endif /* MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
                 goto have_ciphersuite;
+            }
+#if defined(MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE)
         }
+        MBEDTLS_SSL_END_FOR_EACH_CIPHERSUITE
+    }
+#else
+        }
+    }
+    MBEDTLS_SSL_END_FOR_EACH_CIPHERSUITE
+#endif
 
     if( got_common_suite )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "got ciphersuites in common, "
                             "but none of them usable" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                          MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE );
     }
     else
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                           MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN );
     }
 
 have_ciphersuite:
-    MBEDTLS_SSL_DEBUG_MSG( 2, ( "selected ciphersuite: %s", ciphersuite_info->name ) );
 
-    ssl->session_negotiate->ciphersuite = ciphersuites[i];
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
+    ssl->session_negotiate->ciphersuite =
+        mbedtls_ssl_suite_get_id( ciphersuite_info );
     ssl->handshake->ciphersuite_info = ciphersuite_info;
+#endif /* MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
+
+    MBEDTLS_SSL_DEBUG_MSG( 2, ( "selected ciphersuite: %s",
+        mbedtls_ssl_get_ciphersuite_name(
+            mbedtls_ssl_session_get_ciphersuite( ssl->session_negotiate ) ) ) );
 
     ssl->state++;
 
@@ -2173,9 +2264,10 @@
 #if defined(MBEDTLS_DEBUG_C)                         && \
     defined(MBEDTLS_SSL_PROTO_TLS1_2)                && \
     defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED)
-    if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
+    if( mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_3 )
     {
-        mbedtls_pk_type_t sig_alg = mbedtls_ssl_get_ciphersuite_sig_alg( ciphersuite_info );
+        mbedtls_pk_type_t sig_alg = mbedtls_ssl_get_ciphersuite_sig_alg(
+                mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake ) );
         if( sig_alg != MBEDTLS_PK_NONE )
         {
             mbedtls_md_type_t md_alg = mbedtls_ssl_sig_hash_set_find( &ssl->handshake->hash_algs,
@@ -2275,11 +2367,12 @@
                                             size_t *olen )
 {
     unsigned char *p = buf;
-    const mbedtls_ssl_ciphersuite_t *suite = NULL;
+    mbedtls_ssl_ciphersuite_handle_t suite =
+        MBEDTLS_SSL_CIPHERSUITE_INVALID_HANDLE;
     const mbedtls_cipher_info_t *cipher = NULL;
 
     if( ssl->session_negotiate->encrypt_then_mac == MBEDTLS_SSL_ETM_DISABLED ||
-        ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 )
+        mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_0 )
     {
         *olen = 0;
         return;
@@ -2291,9 +2384,17 @@
      * with Associated Data (AEAD) ciphersuite, it MUST NOT send an
      * encrypt-then-MAC response extension back to the client."
      */
-    if( ( suite = mbedtls_ssl_ciphersuite_from_id(
-                    ssl->session_negotiate->ciphersuite ) ) == NULL ||
-        ( cipher = mbedtls_cipher_info_from_type( suite->cipher ) ) == NULL ||
+    suite = mbedtls_ssl_ciphersuite_from_id(
+        mbedtls_ssl_session_get_ciphersuite( ssl->session_negotiate ) );
+    if( suite == MBEDTLS_SSL_CIPHERSUITE_INVALID_HANDLE )
+    {
+        *olen = 0;
+        return;
+    }
+
+    cipher = mbedtls_cipher_info_from_type(
+        mbedtls_ssl_suite_get_cipher( suite ) );
+    if( cipher == NULL ||
         cipher->mode != MBEDTLS_MODE_CBC )
     {
         *olen = 0;
@@ -2321,7 +2422,7 @@
 
     if( mbedtls_ssl_hs_get_extended_ms( ssl->handshake )
           == MBEDTLS_SSL_EXTENDED_MS_DISABLED ||
-        ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 )
+        mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_0 )
     {
         *olen = 0;
         return;
@@ -2476,9 +2577,12 @@
     *olen = 0;
 
     /* Skip costly computation if not needed */
-    if( ssl->handshake->ciphersuite_info->key_exchange !=
+    if( mbedtls_ssl_suite_get_key_exchange(
+            mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake ) ) !=
         MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    {
         return;
+    }
 
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, ecjpake kkpp extension" ) );
 
@@ -2493,7 +2597,8 @@
 
     ret = mbedtls_ecjpake_write_round_one( &ssl->handshake->ecjpake_ctx,
                                         p + 2, end - p - 2, &kkpp_len,
-                                        ssl->conf->f_rng, ssl->conf->p_rng );
+                                        mbedtls_ssl_conf_get_frng( ssl->conf ),
+                                        ssl->conf->p_rng );
     if( ret != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1 , "mbedtls_ecjpake_write_round_one", ret );
@@ -2561,8 +2666,9 @@
 
     /* The RFC is not clear on this point, but sending the actual negotiated
      * version looks like the most interoperable thing to do. */
-    mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver,
-                       ssl->conf->transport, p );
+    mbedtls_ssl_write_version( mbedtls_ssl_get_major_ver( ssl ),
+                               mbedtls_ssl_get_minor_ver( ssl ),
+                               ssl->conf->transport, p );
     MBEDTLS_SSL_DEBUG_BUF( 3, "server version", p, 2 );
     p += 2;
 
@@ -2621,6 +2727,7 @@
     mbedtls_time_t t;
 #endif
     int ret;
+    int ciphersuite;
     size_t olen, ext_len = 0, n;
     unsigned char *buf, *p;
 
@@ -2637,7 +2744,7 @@
     }
 #endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */
 
-    if( ssl->conf->f_rng == NULL )
+    if( mbedtls_ssl_conf_get_frng( ssl->conf ) == NULL )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "no RNG provided") );
         return( MBEDTLS_ERR_SSL_NO_RNG );
@@ -2653,8 +2760,9 @@
     buf = ssl->out_msg;
     p = buf + 4;
 
-    mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver,
-                       ssl->conf->transport, p );
+    mbedtls_ssl_write_version( mbedtls_ssl_get_major_ver( ssl ),
+                               mbedtls_ssl_get_minor_ver( ssl ),
+                               ssl->conf->transport, p );
     p += 2;
 
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen version: [%d:%d]",
@@ -2669,14 +2777,20 @@
 
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, current time: %lu", t ) );
 #else
-    if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, p, 4 ) ) != 0 )
+    if( ( ret = mbedtls_ssl_conf_get_frng( ssl->conf )
+          ( ssl->conf->p_rng, p, 4 ) ) != 0 )
+    {
         return( ret );
+    }
 
     p += 4;
 #endif /* MBEDTLS_HAVE_TIME */
 
-    if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, p, 28 ) ) != 0 )
+    if( ( ret = mbedtls_ssl_conf_get_frng( ssl->conf )
+          ( ssl->conf->p_rng, p, 28 ) ) != 0 )
+    {
         return( ret );
+    }
 
     p += 28;
 
@@ -2739,9 +2853,11 @@
 #endif /* MBEDTLS_SSL_SESSION_TICKETS */
         {
             ssl->session_negotiate->id_len = n = 32;
-            if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, ssl->session_negotiate->id,
-                                    n ) ) != 0 )
+            if( ( ret = mbedtls_ssl_conf_get_frng( ssl->conf )
+                  ( ssl->conf->p_rng, ssl->session_negotiate->id, n ) ) != 0 )
+            {
                 return( ret );
+            }
         }
     }
 
@@ -2762,18 +2878,19 @@
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "%s session has been resumed",
             mbedtls_ssl_handshake_get_resume( ssl->handshake ) ? "a" : "no" ) );
 
-    *p++ = (unsigned char)( ssl->session_negotiate->ciphersuite >> 8 );
-    *p++ = (unsigned char)( ssl->session_negotiate->ciphersuite      );
+    ciphersuite = mbedtls_ssl_session_get_ciphersuite( ssl->session_negotiate );
+    *p++ = (unsigned char)( ciphersuite >> 8 );
+    *p++ = (unsigned char)( ciphersuite      );
     *p++ = (unsigned char)( ssl->session_negotiate->compression      );
 
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %s",
-           mbedtls_ssl_get_ciphersuite_name( ssl->session_negotiate->ciphersuite ) ) );
+           mbedtls_ssl_get_ciphersuite_name( ciphersuite ) ) );
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, compress alg.: 0x%02X",
                    ssl->session_negotiate->compression ) );
 
     /* Do not write the extensions if the protocol is SSLv3 */
 #if defined(MBEDTLS_SSL_PROTO_SSL3)
-    if( ( ssl->major_ver != 3 ) || ( ssl->minor_ver != 0 ) )
+    if( ( mbedtls_ssl_get_major_ver( ssl ) != 3 ) || ( mbedtls_ssl_get_minor_ver( ssl ) != 0 ) )
     {
 #endif
 
@@ -2816,7 +2933,8 @@
 #if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \
     defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
     if ( mbedtls_ssl_ciphersuite_uses_ec(
-         mbedtls_ssl_ciphersuite_from_id( ssl->session_negotiate->ciphersuite ) ) )
+           mbedtls_ssl_ciphersuite_from_id(
+             mbedtls_ssl_session_get_ciphersuite( ssl->session_negotiate ) ) ) )
     {
         ssl_write_supported_point_formats_ext( ssl, p + 2 + ext_len, &olen );
         ext_len += olen;
@@ -2860,8 +2978,8 @@
 #if !defined(MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED)
 static int ssl_write_certificate_request( mbedtls_ssl_context *ssl )
 {
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
-        ssl->handshake->ciphersuite_info;
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info =
+        mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake );
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate request" ) );
 
@@ -2879,8 +2997,8 @@
 static int ssl_write_certificate_request( mbedtls_ssl_context *ssl )
 {
     int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
-        ssl->handshake->ciphersuite_info;
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info =
+        mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake );
     size_t dn_size, total_dn_size; /* excluding length bytes */
     size_t ct_len, sa_len; /* including length bytes */
     unsigned char *buf, *p;
@@ -2954,20 +3072,21 @@
      *     enum { (255) } HashAlgorithm;
      *     enum { (255) } SignatureAlgorithm;
      */
-    if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
+    if( mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_3 )
     {
-        const int *cur;
-
         /*
          * Supported signature algorithms
          */
-        for( cur = ssl->conf->sig_hashes; *cur != MBEDTLS_MD_NONE; cur++ )
+        MBEDTLS_SSL_BEGIN_FOR_EACH_SIG_HASH_TLS( hash )
+        if( 0
+#if defined(MBEDTLS_SHA512_C)
+            || hash == MBEDTLS_SSL_HASH_SHA384
+#endif
+#if defined(MBEDTLS_SHA256_C)
+            || hash == MBEDTLS_SSL_HASH_SHA256
+#endif
+            )
         {
-            unsigned char hash = mbedtls_ssl_hash_from_md_alg( *cur );
-
-            if( MBEDTLS_SSL_HASH_NONE == hash || mbedtls_ssl_set_calc_verify_md( ssl, hash ) )
-                continue;
-
 #if defined(MBEDTLS_RSA_C)
             p[2 + sa_len++] = hash;
             p[2 + sa_len++] = MBEDTLS_SSL_SIG_RSA;
@@ -2977,6 +3096,7 @@
             p[2 + sa_len++] = MBEDTLS_SSL_SIG_ECDSA;
 #endif
         }
+        MBEDTLS_SSL_END_FOR_EACH_SIG_HASH_TLS
 
         p[0] = (unsigned char)( sa_len >> 8 );
         p[1] = (unsigned char)( sa_len      );
@@ -3110,8 +3230,8 @@
 static int ssl_prepare_server_key_exchange( mbedtls_ssl_context *ssl,
                                             size_t *signature_len )
 {
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
-        ssl->handshake->ciphersuite_info;
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info =
+        mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake );
 
 #if defined(MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED)
 #if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED)
@@ -3136,7 +3256,8 @@
      * - ECJPAKE key exchanges
      */
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
     {
         int ret;
         size_t len = 0;
@@ -3145,7 +3266,8 @@
             &ssl->handshake->ecjpake_ctx,
             ssl->out_msg + ssl->out_msglen,
             MBEDTLS_SSL_OUT_CONTENT_LEN - ssl->out_msglen, &len,
-            ssl->conf->f_rng, ssl->conf->p_rng );
+            mbedtls_ssl_conf_get_frng( ssl->conf ),
+            ssl->conf->p_rng );
         if( ret != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_write_round_two", ret );
@@ -3163,8 +3285,8 @@
      **/
 #if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED)   || \
     defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED)
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK )
+    if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) == MBEDTLS_KEY_EXCHANGE_DHE_PSK ||
+        mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK )
     {
         ssl->out_msg[ssl->out_msglen++] = 0x00;
         ssl->out_msg[ssl->out_msglen++] = 0x00;
@@ -3208,7 +3330,8 @@
                   &ssl->handshake->dhm_ctx,
                   (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ),
                   ssl->out_msg + ssl->out_msglen, &len,
-                  ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
+                  mbedtls_ssl_conf_get_frng( ssl->conf ),
+                  ssl->conf->p_rng ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_make_params", ret );
             return( ret );
@@ -3241,28 +3364,20 @@
          *     ECPoint      public;
          * } ServerECDHParams;
          */
-        const mbedtls_ecp_curve_info **curve = NULL;
-        const mbedtls_ecp_group_id *gid;
+        const mbedtls_ecp_curve_info *curve =
+            mbedtls_ecp_curve_info_from_tls_id( ssl->handshake->curve_tls_id );
         int ret;
         size_t len = 0;
 
-        /* Match our preference list against the offered curves */
-        for( gid = ssl->conf->curve_list; *gid != MBEDTLS_ECP_DP_NONE; gid++ )
-            for( curve = ssl->handshake->curves; *curve != NULL; curve++ )
-                if( (*curve)->grp_id == *gid )
-                    goto curve_matching_done;
-
-curve_matching_done:
-        if( curve == NULL || *curve == NULL )
+        if( curve == NULL )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "no matching curve for ECDHE" ) );
             return( MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN );
         }
-
-        MBEDTLS_SSL_DEBUG_MSG( 2, ( "ECDHE curve: %s", (*curve)->name ) );
+        MBEDTLS_SSL_DEBUG_MSG( 2, ( "ECDHE curve: %s", curve->name ) );
 
         if( ( ret = mbedtls_ecdh_setup( &ssl->handshake->ecdh_ctx,
-                                        (*curve)->grp_id ) ) != 0 )
+                                        curve->grp_id ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecp_group_load", ret );
             return( ret );
@@ -3272,7 +3387,8 @@
                   &ssl->handshake->ecdh_ctx, &len,
                   ssl->out_msg + ssl->out_msglen,
                   MBEDTLS_SSL_OUT_CONTENT_LEN - ssl->out_msglen,
-                  ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
+                  mbedtls_ssl_conf_get_frng( ssl->conf ),
+                  ssl->conf->p_rng ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_params", ret );
             return( ret );
@@ -3317,7 +3433,7 @@
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
         mbedtls_pk_type_t sig_alg =
             mbedtls_ssl_get_ciphersuite_sig_pk_alg( ciphersuite_info );
-        if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
+        if( mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_3 )
         {
             /* A: For TLS 1.2, obey signature-hash-algorithm extension
              *    (RFC 5246, Sec. 7.4.1.4.1). */
@@ -3335,7 +3451,8 @@
 #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
 #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \
     defined(MBEDTLS_SSL_PROTO_TLS1_1)
-        if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA )
+        if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+            == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA )
         {
             /* B: Default hash SHA1 */
             md_alg = MBEDTLS_MD_SHA1;
@@ -3392,7 +3509,7 @@
          * 2.3: Compute and add the signature
          */
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
-        if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
+        if( mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_3 )
         {
             /*
              * For TLS 1.2, we need to specify signature and hash algorithm
@@ -3456,7 +3573,7 @@
                                      md_alg, hash, hashlen,
                                      ssl->out_msg + ssl->out_msglen + 2,
                                      signature_len,
-                                     ssl->conf->f_rng,
+                                     mbedtls_ssl_conf_get_frng( ssl->conf ),
                                      ssl->conf->p_rng ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_sign", ret );
@@ -3477,8 +3594,8 @@
     int ret;
     size_t signature_len = 0;
 #if defined(MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED)
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
-                            ssl->handshake->ciphersuite_info;
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info =
+        mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake );
 #endif /* MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED */
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) );
@@ -3696,7 +3813,7 @@
 #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
     defined(MBEDTLS_SSL_PROTO_TLS1_2)
 #if defined(MBEDTLS_SSL_PROTO_SSL3)
-    if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_0 )
+     if( mbedtls_ssl_get_minor_ver( ssl ) != MBEDTLS_SSL_MINOR_VERSION_0 )
 #endif /* MBEDTLS_SSL_PROTO_SSL3 */
     {
         if( len < 2 )
@@ -3753,7 +3870,8 @@
 
     ret = mbedtls_pk_decrypt( private_key, p, len,
                               peer_pms, peer_pmslen, peer_pmssize,
-                              ssl->conf->f_rng, ssl->conf->p_rng );
+                              mbedtls_ssl_conf_get_frng( ssl->conf ),
+                              ssl->conf->p_rng );
     return( ret );
 }
 
@@ -3822,7 +3940,8 @@
      * successful. In particular, always generate the fake premaster secret,
      * regardless of whether it will ultimately influence the output or not.
      */
-    ret = ssl->conf->f_rng( ssl->conf->p_rng, fake_pms, sizeof( fake_pms ) );
+    ret = mbedtls_ssl_conf_get_frng( ssl->conf )
+        ( ssl->conf->p_rng, fake_pms, sizeof( fake_pms ) );
     if( ret != 0 )
     {
         /* It's ok to abort on an RNG failure, since this does not reveal
@@ -3905,8 +4024,8 @@
     if( ret == MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY )
     {
         MBEDTLS_SSL_DEBUG_BUF( 3, "Unknown PSK identity", *p, n );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                 MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY );
         return( MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY );
     }
 
@@ -3919,18 +4038,17 @@
 static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl )
 {
     int ret;
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info =
+        mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake );
     unsigned char *p, *end;
 
-    ciphersuite_info = ssl->handshake->ciphersuite_info;
-
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse client key exchange" ) );
 
 #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) && \
     ( defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) || \
       defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) )
-    if( ( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ||
-          ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA ) &&
+    if( ( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) == MBEDTLS_KEY_EXCHANGE_RSA_PSK ||
+          mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) == MBEDTLS_KEY_EXCHANGE_RSA ) &&
         ( ssl->handshake->async_in_progress != 0 ) )
     {
         /* We've already read a record and there is an asynchronous
@@ -3962,7 +4080,8 @@
     }
 
 #if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED)
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_RSA )
+    if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_DHE_RSA )
     {
         if( ( ret = ssl_parse_client_dh_public( ssl, &p, end ) ) != 0 )
         {
@@ -3980,7 +4099,8 @@
                                       ssl->handshake->premaster,
                                       MBEDTLS_PREMASTER_SIZE,
                                      &ssl->handshake->pmslen,
-                                      ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
+                                      mbedtls_ssl_conf_get_frng( ssl->conf ),
+                                      ssl->conf->p_rng ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_calc_secret", ret );
             return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS );
@@ -3994,10 +4114,14 @@
     defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) ||                   \
     defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) ||                      \
     defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_RSA ||
-        ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA )
+    if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA                       ||
+        mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA                     ||
+        mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_ECDH_RSA                        ||
+        mbedtls_ssl_suite_get_key_exchange( ciphersuite_info )
+        == MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA )
     {
         if( ( ret = mbedtls_ecdh_read_public( &ssl->handshake->ecdh_ctx,
                                       p, end - p) ) != 0 )
@@ -4013,7 +4137,8 @@
                                       &ssl->handshake->pmslen,
                                        ssl->handshake->premaster,
                                        MBEDTLS_MPI_MAX_SIZE,
-                                       ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
+                                       mbedtls_ssl_conf_get_frng( ssl->conf ),
+                                       ssl->conf->p_rng ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_calc_secret", ret );
             return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS );
@@ -4028,7 +4153,8 @@
           MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED ||
           MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */
 #if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK )
+    if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) ==
+        MBEDTLS_KEY_EXCHANGE_PSK )
     {
         if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 )
         {
@@ -4043,7 +4169,7 @@
         }
 
         if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl,
-                        ciphersuite_info->key_exchange ) ) != 0 )
+               mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_psk_derive_premaster", ret );
             return( ret );
@@ -4052,7 +4178,8 @@
     else
 #endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */
 #if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED)
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK )
+    if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) ==
+        MBEDTLS_KEY_EXCHANGE_RSA_PSK )
     {
 #if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
         if ( ssl->handshake->async_in_progress != 0 )
@@ -4080,7 +4207,7 @@
         }
 
         if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl,
-                        ciphersuite_info->key_exchange ) ) != 0 )
+               mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_psk_derive_premaster", ret );
             return( ret );
@@ -4089,7 +4216,8 @@
     else
 #endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */
 #if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED)
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK )
+    if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) ==
+        MBEDTLS_KEY_EXCHANGE_DHE_PSK )
     {
         if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 )
         {
@@ -4109,7 +4237,7 @@
         }
 
         if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl,
-                        ciphersuite_info->key_exchange ) ) != 0 )
+               mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_psk_derive_premaster", ret );
             return( ret );
@@ -4118,7 +4246,8 @@
     else
 #endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */
 #if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED)
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK )
+    if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) ==
+        MBEDTLS_KEY_EXCHANGE_ECDHE_PSK )
     {
         if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 )
         {
@@ -4137,7 +4266,7 @@
                                 MBEDTLS_DEBUG_ECDH_QP );
 
         if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl,
-                        ciphersuite_info->key_exchange ) ) != 0 )
+               mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_psk_derive_premaster", ret );
             return( ret );
@@ -4146,7 +4275,8 @@
     else
 #endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */
 #if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA )
+    if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) ==
+        MBEDTLS_KEY_EXCHANGE_RSA )
     {
         if( ( ret = ssl_parse_encrypted_pms( ssl, p, end, 0 ) ) != 0 )
         {
@@ -4157,7 +4287,8 @@
     else
 #endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */
 #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
-    if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE )
+    if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) ==
+        MBEDTLS_KEY_EXCHANGE_ECJPAKE )
     {
         ret = mbedtls_ecjpake_read_round_two( &ssl->handshake->ecjpake_ctx,
                                               p, end - p );
@@ -4169,7 +4300,8 @@
 
         ret = mbedtls_ecjpake_derive_secret( &ssl->handshake->ecjpake_ctx,
                 ssl->handshake->premaster, 32, &ssl->handshake->pmslen,
-                ssl->conf->f_rng, ssl->conf->p_rng );
+                mbedtls_ssl_conf_get_frng( ssl->conf ),
+                ssl->conf->p_rng );
         if( ret != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_derive_secret", ret );
@@ -4199,8 +4331,8 @@
 #if !defined(MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED)
 static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl )
 {
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
-        ssl->handshake->ciphersuite_info;
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info =
+        mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake );
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) );
 
@@ -4226,8 +4358,8 @@
     mbedtls_pk_type_t pk_alg;
 #endif
     mbedtls_md_type_t md_alg;
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
-        ssl->handshake->ciphersuite_info;
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info =
+        mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake );
     mbedtls_pk_context *peer_pk = NULL;
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) );
@@ -4301,7 +4433,7 @@
      */
 #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \
     defined(MBEDTLS_SSL_PROTO_TLS1_1)
-    if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 )
+    if( mbedtls_ssl_get_minor_ver( ssl ) != MBEDTLS_SSL_MINOR_VERSION_3 )
     {
         md_alg = MBEDTLS_MD_NONE;
         hashlen = 36;
@@ -4318,7 +4450,7 @@
 #endif /* MBEDTLS_SSL_PROTO_SSL3 || MBEDTLS_SSL_PROTO_TLS1 ||
           MBEDTLS_SSL_PROTO_TLS1_1 */
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
-    if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
+    if( mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_3 )
     {
         if( i + 2 > ssl->in_hslen )
         {
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 91b944c..0b86e36 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -75,17 +75,30 @@
 #endif
 }
 
+static void ssl_send_pending_fatal_alert( mbedtls_ssl_context *ssl )
+{
+    if( ssl->pending_fatal_alert_msg == MBEDTLS_SSL_ALERT_MSG_NONE )
+        return;
+
+    mbedtls_ssl_send_alert_message( ssl,
+                                    MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                                    ssl->pending_fatal_alert_msg );
+    ssl->pending_fatal_alert_msg = MBEDTLS_SSL_ALERT_MSG_NONE;
+}
+
 /*
  * Start a timer.
  * Passing millisecs = 0 cancels a running timer.
  */
 static void ssl_set_timer( mbedtls_ssl_context *ssl, uint32_t millisecs )
 {
-    if( ssl->f_set_timer == NULL )
+    if( mbedtls_ssl_get_set_timer( ssl ) == NULL )
         return;
 
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "set_timer to %d ms", (int) millisecs ) );
-    ssl->f_set_timer( ssl->p_timer, millisecs / 4, millisecs );
+    mbedtls_ssl_get_set_timer( ssl )( ssl->p_timer,
+                                           millisecs / 4,
+                                           millisecs );
 }
 
 /*
@@ -93,10 +106,10 @@
  */
 static int ssl_check_timer( mbedtls_ssl_context *ssl )
 {
-    if( ssl->f_get_timer == NULL )
+    if( mbedtls_ssl_get_get_timer( ssl ) == NULL )
         return( 0 );
 
-    if( ssl->f_get_timer( ssl->p_timer ) == 2 )
+    if( mbedtls_ssl_get_get_timer( ssl )( ssl->p_timer ) == 2 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 3, ( "timer expired" ) );
         return( -1 );
@@ -799,7 +812,7 @@
     size_t mac_key_len;
     size_t iv_copy_len;
     unsigned keylen;
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info;
     const mbedtls_cipher_info_t *cipher_info;
     const mbedtls_md_info_t *md_info;
 
@@ -815,32 +828,39 @@
     defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
     transform->encrypt_then_mac = encrypt_then_mac;
 #endif
+
+#if !defined(MBEDTLS_SSL_CONF_FIXED_MINOR_VER)
     transform->minor_ver = minor_ver;
+#else
+    ((void) minor_ver);
+#endif /* !MBEDTLS_SSL_CONF_FIXED_MINOR_VER */
 
     /*
      * Get various info structures
      */
     ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( ciphersuite );
-    if( ciphersuite_info == NULL )
+    if( ciphersuite_info == MBEDTLS_SSL_CIPHERSUITE_INVALID_HANDLE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "ciphersuite info for %d not found",
                                     ciphersuite ) );
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
     }
 
-    cipher_info = mbedtls_cipher_info_from_type( ciphersuite_info->cipher );
+    cipher_info = mbedtls_cipher_info_from_type(
+        mbedtls_ssl_suite_get_cipher( ciphersuite_info ) );
     if( cipher_info == NULL )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "cipher info for %d not found",
-                                    ciphersuite_info->cipher ) );
+                       mbedtls_ssl_suite_get_cipher( ciphersuite_info ) ) );
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
     }
 
-    md_info = mbedtls_md_info_from_type( ciphersuite_info->mac );
+    md_info = mbedtls_md_info_from_type(
+        mbedtls_ssl_suite_get_mac( ciphersuite_info ) );
     if( md_info == NULL )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "mbedtls_md info for %d not found",
-                            ciphersuite_info->mac ) );
+                       mbedtls_ssl_suite_get_mac( ciphersuite_info ) ) );
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
     }
 
@@ -897,8 +917,8 @@
 
         transform->maclen = 0;
         mac_key_len = 0;
-        transform->taglen =
-            ciphersuite_info->flags & MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16;
+        transform->taglen = mbedtls_ssl_suite_get_flags( ciphersuite_info ) &
+            MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16;
 
         /* All modes haves 96-bit IVs;
          * GCM and CCM has 4 implicit and 8 explicit bytes
@@ -1336,15 +1356,15 @@
 int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl )
 {
     int ret;
-    const mbedtls_ssl_ciphersuite_t * const ciphersuite_info =
-        ssl->handshake->ciphersuite_info;
+    mbedtls_ssl_ciphersuite_handle_t const ciphersuite_info =
+        mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake );
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> derive keys" ) );
 
     /* Set PRF, calc_verify and calc_finished function pointers */
     ret = ssl_set_handshake_prfs( ssl->handshake,
-                                  ssl->minor_ver,
-                                  ciphersuite_info->mac );
+                            mbedtls_ssl_get_minor_ver( ssl ),
+                            mbedtls_ssl_suite_get_mac( ciphersuite_info ) );
     if( ret != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, "ssl_set_handshake_prfs", ret );
@@ -1374,24 +1394,24 @@
 
     /* Populate transform structure */
     ret = ssl_populate_transform( ssl->transform_negotiate,
-                                  ssl->session_negotiate->ciphersuite,
-                                  ssl->session_negotiate->master,
+                  mbedtls_ssl_session_get_ciphersuite( ssl->session_negotiate ),
+                  ssl->session_negotiate->master,
 #if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
 #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
-                                  ssl->session_negotiate->encrypt_then_mac,
+                  ssl->session_negotiate->encrypt_then_mac,
 #endif
 #if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
-                                  ssl->session_negotiate->trunc_hmac,
+                  ssl->session_negotiate->trunc_hmac,
 #endif
 #endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */
 #if defined(MBEDTLS_ZLIB_SUPPORT)
-                                  ssl->session_negotiate->compression,
+                  ssl->session_negotiate->compression,
 #endif
-                                  ssl->handshake->tls_prf,
-                                  ssl->handshake->randbytes,
-                                  ssl->minor_ver,
-                                  mbedtls_ssl_conf_get_endpoint( ssl->conf ),
-                                  ssl );
+                  ssl->handshake->tls_prf,
+                  ssl->handshake->randbytes,
+                  mbedtls_ssl_get_minor_ver( ssl ),
+                  mbedtls_ssl_conf_get_endpoint( ssl->conf ),
+                  ssl );
     if( ret != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, "ssl_populate_transform", ret );
@@ -1623,7 +1643,8 @@
         /* Write length only when we know the actual value */
         if( ( ret = mbedtls_dhm_calc_secret( &ssl->handshake->dhm_ctx,
                                       p + 2, end - ( p + 2 ), &len,
-                                      ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
+                                      mbedtls_ssl_conf_get_frng( ssl->conf ),
+                                      ssl->conf->p_rng ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_calc_secret", ret );
             return( ret );
@@ -1644,7 +1665,8 @@
 
         if( ( ret = mbedtls_ecdh_calc_secret( &ssl->handshake->ecdh_ctx, &zlen,
                                        p + 2, end - ( p + 2 ),
-                                       ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
+                                       mbedtls_ssl_conf_get_frng( ssl->conf ),
+                                       ssl->conf->p_rng ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_calc_secret", ret );
             return( ret );
@@ -1988,7 +2010,8 @@
         }
 
 #if defined(MBEDTLS_SSL_PROTO_SSL3)
-        if( transform->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 )
+        if( mbedtls_ssl_transform_get_minor_ver( transform ) ==
+            MBEDTLS_SSL_MINOR_VERSION_0 )
         {
             unsigned char mac[SSL_MAC_MAX_BYTES];
             ssl_mac( &transform->md_ctx_enc, transform->mac_enc,
@@ -1999,7 +2022,8 @@
 #endif
 #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
         defined(MBEDTLS_SSL_PROTO_TLS1_2)
-        if( transform->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 )
+        if( mbedtls_ssl_transform_get_minor_ver( transform ) >=
+            MBEDTLS_SSL_MINOR_VERSION_1 )
         {
             unsigned char mac[MBEDTLS_SSL_MAC_ADD];
 
@@ -2178,7 +2202,8 @@
          * Prepend per-record IV for block cipher in TLS v1.1 and up as per
          * Method 1 (6.2.3.2. in RFC4346 and RFC5246)
          */
-        if( transform->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 )
+        if( mbedtls_ssl_transform_get_minor_ver( transform ) >=
+            MBEDTLS_SSL_MINOR_VERSION_2 )
         {
             if( f_rng == NULL )
             {
@@ -2227,7 +2252,8 @@
         }
 
 #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1)
-        if( transform->minor_ver < MBEDTLS_SSL_MINOR_VERSION_2 )
+        if( mbedtls_ssl_transform_get_minor_ver( transform ) <
+            MBEDTLS_SSL_MINOR_VERSION_2 )
         {
             /*
              * Save IV in SSL3 and TLS1
@@ -2476,7 +2502,8 @@
          * Check immediate ciphertext sanity
          */
 #if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2)
-        if( transform->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 )
+        if( mbedtls_ssl_transform_get_minor_ver( transform ) >=
+            MBEDTLS_SSL_MINOR_VERSION_2 )
         {
             /* The ciphertext is prefixed with the CBC IV. */
             minlen += transform->ivlen;
@@ -2567,7 +2594,8 @@
         /*
          * Initialize for prepended IV for block cipher in TLS v1.1 and up
          */
-        if( transform->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 )
+        if( mbedtls_ssl_transform_get_minor_ver( transform ) >=
+            MBEDTLS_SSL_MINOR_VERSION_2 )
         {
             /* This is safe because data_len >= minlen + maclen + 1 initially,
              * and at this point we have at most subtracted maclen (note that
@@ -2595,7 +2623,8 @@
         }
 
 #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1)
-        if( transform->minor_ver < MBEDTLS_SSL_MINOR_VERSION_2 )
+        if( mbedtls_ssl_transform_get_minor_ver( transform ) <
+            MBEDTLS_SSL_MINOR_VERSION_2 )
         {
             /*
              * Save IV in SSL3 and TLS1
@@ -2637,7 +2666,8 @@
          * we have data_len >= padlen here. */
 
 #if defined(MBEDTLS_SSL_PROTO_SSL3)
-        if( transform->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 )
+        if( mbedtls_ssl_transform_get_minor_ver( transform ) ==
+            MBEDTLS_SSL_MINOR_VERSION_0 )
         {
             if( padlen > transform->ivlen )
             {
@@ -2653,7 +2683,8 @@
 #endif /* MBEDTLS_SSL_PROTO_SSL3 */
 #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
     defined(MBEDTLS_SSL_PROTO_TLS1_2)
-        if( transform->minor_ver > MBEDTLS_SSL_MINOR_VERSION_0 )
+        if( mbedtls_ssl_transform_get_minor_ver( transform ) >
+            MBEDTLS_SSL_MINOR_VERSION_0 )
         {
             /* The padding check involves a series of up to 256
              * consecutive memory reads at the end of the record
@@ -2739,7 +2770,8 @@
         ssl_extract_add_data_from_record( add_data, &add_data_len, rec );
 
 #if defined(MBEDTLS_SSL_PROTO_SSL3)
-        if( transform->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 )
+        if( mbedtls_ssl_transform_get_minor_ver( transform ) ==
+            MBEDTLS_SSL_MINOR_VERSION_0 )
         {
             ssl_mac( &transform->md_ctx_dec,
                      transform->mac_dec,
@@ -2751,7 +2783,8 @@
 #endif /* MBEDTLS_SSL_PROTO_SSL3 */
 #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
         defined(MBEDTLS_SSL_PROTO_TLS1_2)
-        if( transform->minor_ver > MBEDTLS_SSL_MINOR_VERSION_0 )
+        if( mbedtls_ssl_transform_get_minor_ver( transform ) >
+            MBEDTLS_SSL_MINOR_VERSION_0 )
         {
             /*
              * Process MAC and always update for padlen afterwards to make
@@ -3062,7 +3095,8 @@
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> fetch input" ) );
 
-    if( ssl->f_recv == NULL && ssl->f_recv_timeout == NULL )
+    if( mbedtls_ssl_get_recv( ssl ) == NULL &&
+        mbedtls_ssl_get_recv_timeout( ssl ) == NULL )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "Bad usage of mbedtls_ssl_set_bio() "
                             "or mbedtls_ssl_set_bio()" ) );
@@ -3081,7 +3115,8 @@
         uint32_t timeout;
 
         /* Just to be sure */
-        if( ssl->f_set_timer == NULL || ssl->f_get_timer == NULL )
+        if( mbedtls_ssl_get_set_timer( ssl ) == NULL ||
+            mbedtls_ssl_get_get_timer( ssl ) == NULL )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "You must use "
                         "mbedtls_ssl_set_timer_cb() for DTLS" ) );
@@ -3164,11 +3199,16 @@
 
             MBEDTLS_SSL_DEBUG_MSG( 3, ( "f_recv_timeout: %u ms", timeout ) );
 
-            if( ssl->f_recv_timeout != NULL )
-                ret = ssl->f_recv_timeout( ssl->p_bio, ssl->in_hdr, len,
-                                                                    timeout );
+            if( mbedtls_ssl_get_recv_timeout( ssl ) != NULL )
+            {
+                ret = mbedtls_ssl_get_recv_timeout( ssl )
+                    ( ssl->p_bio, ssl->in_hdr, len, timeout );
+            }
             else
-                ret = ssl->f_recv( ssl->p_bio, ssl->in_hdr, len );
+            {
+                ret = mbedtls_ssl_get_recv( ssl )
+                    ( ssl->p_bio, ssl->in_hdr, len );
+            }
 
             MBEDTLS_SSL_DEBUG_RET( 2, "ssl->f_recv(_timeout)", ret );
 
@@ -3233,15 +3273,15 @@
                 ret = MBEDTLS_ERR_SSL_TIMEOUT;
             else
             {
-                if( ssl->f_recv_timeout != NULL )
+                if( mbedtls_ssl_get_recv_timeout( ssl ) != NULL )
                 {
-                    ret = ssl->f_recv_timeout( ssl->p_bio,
-                             ssl->in_hdr + ssl->in_left, len,
-                             mbedtls_ssl_conf_get_read_timeout( ssl->conf ) );
+                    ret = mbedtls_ssl_get_recv_timeout( ssl )( ssl->p_bio,
+                       ssl->in_hdr + ssl->in_left, len,
+                       mbedtls_ssl_conf_get_read_timeout( ssl->conf ) );
                 }
                 else
                 {
-                    ret = ssl->f_recv( ssl->p_bio,
+                    ret = mbedtls_ssl_get_recv( ssl )( ssl->p_bio,
                                        ssl->in_hdr + ssl->in_left, len );
                 }
             }
@@ -3284,7 +3324,7 @@
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> flush output" ) );
 
-    if( ssl->f_send == NULL )
+    if( mbedtls_ssl_get_send( ssl ) == NULL )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "Bad usage of mbedtls_ssl_set_bio() "
                             "or mbedtls_ssl_set_bio()" ) );
@@ -3304,7 +3344,7 @@
                        mbedtls_ssl_out_hdr_len( ssl ) + ssl->out_msglen, ssl->out_left ) );
 
         buf = ssl->out_hdr - ssl->out_left;
-        ret = ssl->f_send( ssl->p_bio, buf, ssl->out_left );
+        ret = mbedtls_ssl_get_send( ssl )( ssl->p_bio, buf, ssl->out_left );
 
         MBEDTLS_SSL_DEBUG_RET( 2, "ssl->f_send", ret );
 
@@ -3723,7 +3763,7 @@
     {
         /* In SSLv3, the client might send a NoCertificate alert. */
 #if defined(MBEDTLS_SSL_PROTO_SSL3) && defined(MBEDTLS_SSL_CLI_C)
-        if( ! ( ssl->minor_ver      == MBEDTLS_SSL_MINOR_VERSION_0 &&
+        if( ! ( mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_0 &&
                 ssl->out_msgtype    == MBEDTLS_SSL_MSG_ALERT       &&
                 mbedtls_ssl_conf_get_endpoint( ssl->conf ) ==
                   MBEDTLS_SSL_IS_CLIENT ) )
@@ -3913,8 +3953,9 @@
         /* Skip writing the record content type to after the encryption,
          * as it may change when using the CID extension. */
 
-        mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver,
-                           ssl->conf->transport, ssl->out_hdr + 1 );
+        mbedtls_ssl_write_version( mbedtls_ssl_get_major_ver( ssl ),
+                                   mbedtls_ssl_get_minor_ver( ssl ),
+                                   ssl->conf->transport, ssl->out_hdr + 1 );
 
         memcpy( ssl->out_ctr, ssl->cur_out_ctr, 8 );
         ssl->out_len[0] = (unsigned char)( len >> 8 );
@@ -3931,7 +3972,8 @@
             rec.data_offset = ssl->out_msg - rec.buf;
 
             memcpy( &rec.ctr[0], ssl->out_ctr, 8 );
-            mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver,
+            mbedtls_ssl_write_version( mbedtls_ssl_get_major_ver( ssl ),
+                                       mbedtls_ssl_get_minor_ver( ssl ),
                                        ssl->conf->transport, rec.ver );
             rec.type = ssl->out_msgtype;
 
@@ -3941,7 +3983,8 @@
 #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
 
             if( ( ret = mbedtls_ssl_encrypt_buf( ssl, ssl->transform_out, &rec,
-                                         ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 )
+                                         mbedtls_ssl_conf_get_frng( ssl->conf ),
+                                         ssl->conf->p_rng ) ) != 0 )
             {
                 MBEDTLS_SSL_DEBUG_RET( 1, "ssl_encrypt_buf", ret );
                 return( ret );
@@ -4578,7 +4621,7 @@
         /* Don't check write errors as we can't do anything here.
          * If the error is permanent we'll catch it later,
          * if it's not, then hopefully it'll work next time. */
-        (void) ssl->f_send( ssl->p_bio, ssl->out_buf, len );
+        (void) mbedtls_ssl_get_send( ssl )( ssl->p_bio, ssl->out_buf, len );
 
         return( MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED );
     }
@@ -4676,8 +4719,8 @@
          * Section 4.1.2.7, that is, send alert only with TLS */
         if( MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) )
         {
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                    MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
         }
 #endif /* MBEDTLS_SSL_PROTO_TLS */
 
@@ -4685,13 +4728,13 @@
     }
 
     /* Check version */
-    if( major_ver != ssl->major_ver )
+    if( major_ver != mbedtls_ssl_get_major_ver( ssl ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "major version mismatch" ) );
         return( MBEDTLS_ERR_SSL_INVALID_RECORD );
     }
 
-    if( minor_ver > ssl->conf->max_minor_ver )
+    if( minor_ver > mbedtls_ssl_conf_get_max_minor_ver( ssl->conf ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "minor version mismatch" ) );
         return( MBEDTLS_ERR_SSL_INVALID_RECORD );
@@ -4816,7 +4859,7 @@
         }
 
 #if defined(MBEDTLS_SSL_PROTO_SSL3)
-        if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 &&
+        if( mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_0 &&
             ssl->in_msglen > ssl->transform_in->minlen + MBEDTLS_SSL_IN_CONTENT_LEN )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) );
@@ -4828,7 +4871,7 @@
         /*
          * TLS encrypted messages can have up to 256 bytes of padding
          */
-        if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 &&
+        if( mbedtls_ssl_get_minor_ver( ssl ) >= MBEDTLS_SSL_MINOR_VERSION_1 &&
             ssl->in_msglen > ssl->transform_in->minlen +
                              MBEDTLS_SSL_IN_CONTENT_LEN + 256 )
         {
@@ -4882,7 +4925,8 @@
 #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
 
         memcpy( &rec.ctr[0], ssl->in_ctr, 8 );
-        mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver,
+        mbedtls_ssl_write_version( mbedtls_ssl_get_major_ver( ssl ),
+                                   mbedtls_ssl_get_minor_ver( ssl ),
                                    ssl->conf->transport, rec.ver );
         rec.type = ssl->in_msgtype;
         if( ( ret = mbedtls_ssl_decrypt_buf( ssl, ssl->transform_in,
@@ -4948,7 +4992,7 @@
         else if( ssl->in_msglen == 0 )
         {
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
-            if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3
+            if( mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_3
                 && ssl->in_msgtype != MBEDTLS_SSL_MSG_APPLICATION_DATA )
             {
                 /* TLS v1.2 explicitly disallows zero-length messages which are not application data */
@@ -5072,6 +5116,7 @@
                     if( ret != 0 )
                     {
                         MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_get_next_record" ), ret );
+                        ssl_send_pending_fatal_alert( ssl );
                         return( ret );
                     }
                 }
@@ -5800,8 +5845,7 @@
 #if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES)
                     if( ret == MBEDTLS_ERR_SSL_INVALID_MAC )
                     {
-                        mbedtls_ssl_send_alert_message( ssl,
-                                MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                        mbedtls_ssl_pend_fatal_alert( ssl,
                                 MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC );
                     }
 #endif
@@ -5837,8 +5881,7 @@
 #if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES)
             if( ret == MBEDTLS_ERR_SSL_INVALID_MAC )
             {
-                mbedtls_ssl_send_alert_message( ssl,
-                        MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                mbedtls_ssl_pend_fatal_alert( ssl,
                         MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC );
             }
 #endif
@@ -5941,7 +5984,7 @@
 #endif
 
 #if defined(MBEDTLS_SSL_PROTO_SSL3) && defined(MBEDTLS_SSL_SRV_C)
-        if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 &&
+        if( mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_0 &&
             mbedtls_ssl_conf_get_endpoint( ssl->conf ) ==
               MBEDTLS_SSL_IS_SERVER &&
             ssl->in_msg[0] == MBEDTLS_SSL_ALERT_LEVEL_WARNING &&
@@ -6000,8 +6043,8 @@
 }
 
 int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl,
-                            unsigned char level,
-                            unsigned char message )
+                                    unsigned char level,
+                                    unsigned char message )
 {
     int ret;
 
@@ -6058,7 +6101,8 @@
 /* No certificate support -> dummy functions */
 int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl )
 {
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->handshake->ciphersuite_info;
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info =
+        mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake );
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate" ) );
 
@@ -6075,7 +6119,8 @@
 
 int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl )
 {
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->handshake->ciphersuite_info;
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info =
+        mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake );
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) );
 
@@ -6098,7 +6143,8 @@
     int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
     size_t i, n;
     const mbedtls_x509_crt *crt;
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->handshake->ciphersuite_info;
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info =
+        mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake );
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate" ) );
 
@@ -6126,7 +6172,7 @@
          * (otherwise an empty Certificate message will be sent).
          */
         if( mbedtls_ssl_own_cert( ssl )  == NULL &&
-            ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 )
+            mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_0 )
         {
             ssl->out_msglen  = 2;
             ssl->out_msgtype = MBEDTLS_SSL_MSG_ALERT;
@@ -6272,8 +6318,8 @@
     if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                            MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
         return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
     }
 
@@ -6281,8 +6327,8 @@
         ssl->in_hslen < mbedtls_ssl_hs_hdr_len( ssl ) + 3 + 3 )
     {
         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_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
     }
 
@@ -6297,8 +6343,8 @@
         ssl->in_hslen != n + 3 + mbedtls_ssl_hs_hdr_len( ssl ) )
     {
         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_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
     }
 
@@ -6311,9 +6357,8 @@
         /* 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_pend_fatal_alert( ssl,
+                                          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
@@ -6321,9 +6366,8 @@
         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_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
         }
 
@@ -6335,9 +6379,8 @@
         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_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
         }
 
@@ -6358,9 +6401,8 @@
                                               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 );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                                       MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED );
                 return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
             }
 
@@ -6396,7 +6438,7 @@
             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_pend_fatal_alert( ssl,  alert );
                 MBEDTLS_SSL_DEBUG_RET( 1, " mbedtls_x509_crt_parse_der", ret );
                 return( ret );
         }
@@ -6418,7 +6460,7 @@
     /*
      * Check if the client sent an empty certificate
      */
-    if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 )
+    if( mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_0 )
     {
         if( ssl->in_msglen  == 2                        &&
             ssl->in_msgtype == MBEDTLS_SSL_MSG_ALERT            &&
@@ -6462,8 +6504,8 @@
 static int ssl_parse_certificate_coordinate( mbedtls_ssl_context *ssl,
                                              int authmode )
 {
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
-        ssl->handshake->ciphersuite_info;
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info =
+        mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake );
 
     if( !mbedtls_ssl_ciphersuite_uses_srv_cert( ciphersuite_info ) )
         return( SSL_CERTIFICATE_SKIP );
@@ -6471,8 +6513,11 @@
 #if defined(MBEDTLS_SSL_SRV_C)
     if( mbedtls_ssl_conf_get_endpoint( ssl->conf ) == MBEDTLS_SSL_IS_SERVER )
     {
-        if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK )
+        if( mbedtls_ssl_suite_get_key_exchange( ciphersuite_info ) ==
+            MBEDTLS_KEY_EXCHANGE_RSA_PSK )
+        {
             return( SSL_CERTIFICATE_SKIP );
+        }
 
         if( authmode == MBEDTLS_SSL_VERIFY_NONE )
         {
@@ -6494,8 +6539,8 @@
                                          void *rs_ctx )
 {
     int verify_ret;
-    const mbedtls_ssl_ciphersuite_t *ciphersuite_info =
-        ssl->handshake->ciphersuite_info;
+    mbedtls_ssl_ciphersuite_handle_t ciphersuite_info =
+        mbedtls_ssl_handshake_get_ciphersuite( ssl->handshake );
     mbedtls_x509_crt *ca_chain;
     mbedtls_x509_crl *ca_crl;
 
@@ -6627,8 +6672,7 @@
             alert = MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA;
         else
             alert = MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN;
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        alert );
+        mbedtls_ssl_pend_fatal_alert( ssl, alert );
     }
 
 #if defined(MBEDTLS_DEBUG_C)
@@ -6660,9 +6704,8 @@
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed",
                                     sizeof( MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN ) ) );
-        mbedtls_ssl_send_alert_message( ssl,
-                                        MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
 
         return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
     }
@@ -6765,9 +6808,8 @@
     {
         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 );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
 
         ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
         goto exit;
@@ -6898,8 +6940,8 @@
     if( ssl->in_msgtype != MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad change cipher spec message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                             MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
         return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
     }
 
@@ -6946,8 +6988,8 @@
         if( ( ret = mbedtls_ssl_hw_record_activate( ssl, MBEDTLS_SSL_CHANNEL_INBOUND ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_activate", ret );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                  MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
             return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
         }
     }
@@ -6961,24 +7003,24 @@
 }
 
 void mbedtls_ssl_optimize_checksum( mbedtls_ssl_context *ssl,
-                            const mbedtls_ssl_ciphersuite_t *ciphersuite_info )
+                            mbedtls_ssl_ciphersuite_handle_t ciphersuite_info )
 {
     ((void) ciphersuite_info);
 
 #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \
     defined(MBEDTLS_SSL_PROTO_TLS1_1)
-    if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 )
+    if( mbedtls_ssl_get_minor_ver( ssl ) < MBEDTLS_SSL_MINOR_VERSION_3 )
         ssl->handshake->update_checksum = ssl_update_checksum_md5sha1;
     else
 #endif
 #if defined(MBEDTLS_SSL_PROTO_TLS1_2)
 #if defined(MBEDTLS_SHA512_C)
-    if( ciphersuite_info->mac == MBEDTLS_MD_SHA384 )
+    if( mbedtls_ssl_suite_get_mac( ciphersuite_info ) == MBEDTLS_MD_SHA384 )
         ssl->handshake->update_checksum = ssl_update_checksum_sha384;
     else
 #endif
 #if defined(MBEDTLS_SHA256_C)
-    if( ciphersuite_info->mac != MBEDTLS_MD_SHA384 )
+    if( mbedtls_ssl_suite_get_mac( ciphersuite_info ) != MBEDTLS_MD_SHA384 )
         ssl->handshake->update_checksum = ssl_update_checksum_sha256;
     else
 #endif
@@ -7400,7 +7442,7 @@
      * ciphersuite does this (and this is unlikely to change as activity has
      * moved to TLS 1.3 now) so we can keep the hardcoded 12 here.
      */
-    hash_len = ( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) ? 36 : 12;
+    hash_len = ( mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_0 ) ? 36 : 12;
 
 #if defined(MBEDTLS_SSL_RENEGOTIATION)
     ssl->verify_data_len = hash_len;
@@ -7540,14 +7582,14 @@
     if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                               MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
         return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
     }
 
     /* There is currently no ciphersuite using another length with TLS 1.2 */
 #if defined(MBEDTLS_SSL_PROTO_SSL3)
-    if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 )
+    if( mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_0 )
         hash_len = 36;
     else
 #endif
@@ -7557,8 +7599,8 @@
         ssl->in_hslen  != mbedtls_ssl_hs_hdr_len( ssl ) + hash_len )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_FINISHED );
     }
 
@@ -7566,8 +7608,8 @@
                       buf, hash_len ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_FINISHED );
     }
 
@@ -7738,8 +7780,6 @@
             ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_PREPARING;
         else
             ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_WAITING;
-
-        ssl_set_timer( ssl, 0 );
     }
 #endif
 
@@ -7815,7 +7855,7 @@
 
     /* Adjust out_msg to make space for explicit IV, if used. */
     if( transform != NULL &&
-        ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 )
+        mbedtls_ssl_get_minor_ver( ssl ) >= MBEDTLS_SSL_MINOR_VERSION_2 )
     {
         ssl->out_msg = ssl->out_iv + transform->ivlen - transform->fixed_ivlen;
     }
@@ -7946,6 +7986,8 @@
     if( ( ret = ssl_handshake_init( ssl ) ) != 0 )
         goto error;
 
+    ssl->pending_fatal_alert_msg = MBEDTLS_SSL_ALERT_MSG_NONE;
+
     return( 0 );
 
 error:
@@ -8185,6 +8227,7 @@
 }
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
+#if !defined(MBEDTLS_SSL_CONF_RNG)
 void mbedtls_ssl_conf_rng( mbedtls_ssl_config *conf,
                   int (*f_rng)(void *, unsigned char *, size_t),
                   void *p_rng )
@@ -8192,7 +8235,15 @@
     conf->f_rng      = f_rng;
     conf->p_rng      = p_rng;
 }
+#else
+void mbedtls_ssl_conf_rng_ctx( mbedtls_ssl_config *conf,
+                               void *p_rng )
+{
+    conf->p_rng      = p_rng;
+}
+#endif
 
+#if defined(MBEDTLS_DEBUG_C)
 void mbedtls_ssl_conf_dbg( mbedtls_ssl_config *conf,
                   void (*f_dbg)(void *, int, const char *, int, const char *),
                   void  *p_dbg )
@@ -8200,18 +8251,29 @@
     conf->f_dbg      = f_dbg;
     conf->p_dbg      = p_dbg;
 }
+#endif /* MBEDTLS_DEBUG_C */
 
+#if !defined(MBEDTLS_SSL_CONF_RECV) && \
+    !defined(MBEDTLS_SSL_CONF_SEND) && \
+    !defined(MBEDTLS_SSL_CONF_RECV_TIMEOUT)
 void mbedtls_ssl_set_bio( mbedtls_ssl_context *ssl,
         void *p_bio,
         mbedtls_ssl_send_t *f_send,
         mbedtls_ssl_recv_t *f_recv,
         mbedtls_ssl_recv_timeout_t *f_recv_timeout )
 {
-    ssl->p_bio          = p_bio;
-    ssl->f_send         = f_send;
-    ssl->f_recv         = f_recv;
+    ssl->p_bio = p_bio;
+    ssl->f_send = f_send;
+    ssl->f_recv = f_recv;
     ssl->f_recv_timeout = f_recv_timeout;
 }
+#else
+void mbedtls_ssl_set_bio_ctx( mbedtls_ssl_context *ssl,
+                              void *p_bio )
+{
+    ssl->p_bio = p_bio;
+}
+#endif
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
 void mbedtls_ssl_set_mtu( mbedtls_ssl_context *ssl, uint16_t mtu )
@@ -8227,6 +8289,8 @@
 }
 #endif /* MBEDTLS_SSL_CONF_READ_TIMEOUT */
 
+#if !defined(MBEDTLS_SSL_CONF_SET_TIMER) && \
+    !defined(MBEDTLS_SSL_CONF_GET_TIMER)
 void mbedtls_ssl_set_timer_cb( mbedtls_ssl_context *ssl,
                                void *p_timer,
                                mbedtls_ssl_set_timer_t *f_set_timer,
@@ -8235,10 +8299,18 @@
     ssl->p_timer        = p_timer;
     ssl->f_set_timer    = f_set_timer;
     ssl->f_get_timer    = f_get_timer;
-
     /* Make sure we start with no timer running */
     ssl_set_timer( ssl, 0 );
 }
+#else
+void mbedtls_ssl_set_timer_cb_ctx( mbedtls_ssl_context *ssl,
+                               void *p_timer )
+{
+    ssl->p_timer        = p_timer;
+    /* Make sure we start with no timer running */
+    ssl_set_timer( ssl, 0 );
+}
+#endif
 
 #if defined(MBEDTLS_SSL_SRV_C) && !defined(MBEDTLS_SSL_NO_SESSION_CACHE)
 void mbedtls_ssl_conf_session_cache( mbedtls_ssl_config *conf,
@@ -8275,6 +8347,7 @@
 }
 #endif /* MBEDTLS_SSL_CLI_C && !MBEDTLS_SSL_NO_SESSION_RESUMPTION */
 
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
 void mbedtls_ssl_conf_ciphersuites( mbedtls_ssl_config *conf,
                                    const int *ciphersuites )
 {
@@ -8296,6 +8369,7 @@
 
     conf->ciphersuite_list[minor] = ciphersuites;
 }
+#endif /* MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
 void mbedtls_ssl_conf_cert_profile( mbedtls_ssl_config *conf,
@@ -8559,11 +8633,17 @@
 void mbedtls_ssl_conf_sig_hashes( mbedtls_ssl_config *conf,
                                   const int *hashes )
 {
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH)
     conf->sig_hashes = hashes;
+#else
+    ((void) conf);
+    ((void) hashes);
+#endif /* MBEDTLS_SSL_CONF_SINGLE_SIG_HASH */
 }
 #endif /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */
 
 #if defined(MBEDTLS_ECP_C)
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_EC)
 /*
  * Set the allowed elliptic curves
  */
@@ -8572,6 +8652,7 @@
 {
     conf->curve_list = curve_list;
 }
+#endif /* MBEDTLS_SSL_CONF_SINGLE_EC */
 #endif /* MBEDTLS_ECP_C */
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
@@ -8663,17 +8744,27 @@
 }
 #endif /* MBEDTLS_SSL_ALPN */
 
-void mbedtls_ssl_conf_max_version( mbedtls_ssl_config *conf, int major, int minor )
+#if !defined(MBEDTLS_SSL_CONF_MAX_MINOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MAX_MAJOR_VER)
+void mbedtls_ssl_conf_max_version( mbedtls_ssl_config *conf,
+                                   int major, int minor )
 {
     conf->max_major_ver = major;
     conf->max_minor_ver = minor;
 }
+#endif /* MBEDTLS_SSL_CONF_MAX_MINOR_VER ||
+          MBEDTLS_SSL_CONF_MAX_MAJOR_VER */
 
-void mbedtls_ssl_conf_min_version( mbedtls_ssl_config *conf, int major, int minor )
+#if !defined(MBEDTLS_SSL_CONF_MIN_MINOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MIN_MAJOR_VER)
+void mbedtls_ssl_conf_min_version( mbedtls_ssl_config *conf,
+                                   int major, int minor )
 {
     conf->min_major_ver = major;
     conf->min_minor_ver = minor;
 }
+#endif /* MBEDTLS_SSL_CONF_MIN_MINOR_VER ||
+          MBEDTLS_SSL_CONF_MIN_MAJOR_VER */
 
 #if defined(MBEDTLS_SSL_FALLBACK_SCSV) && defined(MBEDTLS_SSL_CLI_C)
 void mbedtls_ssl_conf_fallback( mbedtls_ssl_config *conf, char fallback )
@@ -8918,10 +9009,13 @@
 
 const char *mbedtls_ssl_get_ciphersuite( const mbedtls_ssl_context *ssl )
 {
+    int suite;
+
     if( ssl == NULL || ssl->session == NULL )
         return( NULL );
 
-    return mbedtls_ssl_get_ciphersuite_name( ssl->session->ciphersuite );
+    suite = mbedtls_ssl_session_get_ciphersuite( ssl->session );
+    return( mbedtls_ssl_get_ciphersuite_name( suite ) );
 }
 
 const char *mbedtls_ssl_get_version( const mbedtls_ssl_context *ssl )
@@ -8929,7 +9023,7 @@
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
     if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( ssl->conf->transport ) )
     {
-        switch( ssl->minor_ver )
+        switch( mbedtls_ssl_get_minor_ver( ssl ) )
         {
             case MBEDTLS_SSL_MINOR_VERSION_2:
                 return( "DTLSv1.0" );
@@ -8945,7 +9039,7 @@
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
 #if defined(MBEDTLS_SSL_PROTO_TLS)
     {
-        switch( ssl->minor_ver )
+        switch( mbedtls_ssl_get_minor_ver( ssl ) )
         {
             case MBEDTLS_SSL_MINOR_VERSION_0:
                 return( "SSLv3.0" );
@@ -9007,7 +9101,7 @@
             /* For TLS 1.1 or higher, an explicit IV is added
              * after the record header. */
 #if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2)
-            if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 )
+            if( mbedtls_ssl_get_minor_ver( ssl ) >= MBEDTLS_SSL_MINOR_VERSION_2 )
                 transform_expansion += block_size;
 #endif /* MBEDTLS_SSL_PROTO_TLS1_1 || MBEDTLS_SSL_PROTO_TLS1_2 */
 
@@ -9343,8 +9437,10 @@
 
     if( used <= buf_len )
     {
-        *p++ = (unsigned char)( ( session->ciphersuite >> 8 ) & 0xFF );
-        *p++ = (unsigned char)( ( session->ciphersuite      ) & 0xFF );
+        const int ciphersuite =
+            mbedtls_ssl_session_get_ciphersuite( session );
+        *p++ = (unsigned char)( ( ciphersuite >> 8 ) & 0xFF );
+        *p++ = (unsigned char)( ( ciphersuite      ) & 0xFF );
 
         *p++ = (unsigned char)( session->compression & 0xFF );
 
@@ -9482,6 +9578,7 @@
 {
     const unsigned char *p = buf;
     const unsigned char * const end = buf + len;
+    int ciphersuite;
 #if defined(MBEDTLS_HAVE_TIME)
     uint64_t start;
 #endif
@@ -9528,12 +9625,23 @@
     /*
      * Basic mandatory fields
      */
+
     if( 2 + 1 + 1 + 32 + 48 + 4 > (size_t)( end - p ) )
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
 
-    session->ciphersuite = ( p[0] << 8 ) | p[1];
+    ciphersuite = ( p[0] << 8 ) | p[1];
     p += 2;
 
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
+    session->ciphersuite = ciphersuite;
+#else
+    if( ciphersuite !=
+        MBEDTLS_SSL_SUITE_ID( MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE ) )
+    {
+        return( MBEDTLS_ERR_SSL_VERSION_MISMATCH );
+    }
+#endif
+
     session->compression = *p++;
 
     session->id_len = *p++;
@@ -9732,6 +9840,7 @@
         ret = mbedtls_ssl_handshake_server_step( ssl );
 #endif
 
+    ssl_send_pending_fatal_alert( ssl );
     return( ret );
 }
 
@@ -9990,8 +10099,8 @@
     while( ssl->in_offt == NULL )
     {
         /* Start timer if not already running */
-        if( ssl->f_get_timer != NULL &&
-            ssl->f_get_timer( ssl->p_timer ) == -1 )
+        if( mbedtls_ssl_get_get_timer( ssl ) != NULL &&
+            mbedtls_ssl_get_get_timer( ssl )( ssl->p_timer ) == -1 )
         {
             ssl_set_timer( ssl,
                            mbedtls_ssl_conf_get_read_timeout( ssl->conf ) );
@@ -10117,7 +10226,7 @@
                 MBEDTLS_SSL_DEBUG_MSG( 3, ( "refusing renegotiation, sending alert" ) );
 
 #if defined(MBEDTLS_SSL_PROTO_SSL3)
-                if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 )
+                if( mbedtls_ssl_get_minor_ver( ssl ) == MBEDTLS_SSL_MINOR_VERSION_0 )
                 {
                     /* SSLv3 does not have a "no_renegotiation" warning, so
                        we send a fatal alert and abort the connection. */
@@ -10129,14 +10238,13 @@
 #endif /* MBEDTLS_SSL_PROTO_SSL3 */
 #if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
     defined(MBEDTLS_SSL_PROTO_TLS1_2)
-                if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 )
+                if( mbedtls_ssl_get_minor_ver( ssl ) >= MBEDTLS_SSL_MINOR_VERSION_1 )
                 {
-                    if( ( ret = mbedtls_ssl_send_alert_message( ssl,
-                                    MBEDTLS_SSL_ALERT_LEVEL_WARNING,
-                                    MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION ) ) != 0 )
-                    {
+                    ret = mbedtls_ssl_send_alert_message( ssl,
+                                             MBEDTLS_SSL_ALERT_LEVEL_WARNING,
+                                             MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION );
+                    if( ret != 0 )
                         return( ret );
-                    }
                 }
                 else
 #endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 ||
@@ -10338,7 +10446,7 @@
     if( ssl->conf->cbc_record_splitting ==
             MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED ||
         len <= 1 ||
-        ssl->minor_ver > MBEDTLS_SSL_MINOR_VERSION_1 ||
+        mbedtls_ssl_get_minor_ver( ssl ) > MBEDTLS_SSL_MINOR_VERSION_1 ||
         mbedtls_cipher_get_cipher_mode( &ssl->transform_out->cipher_ctx_enc )
                                 != MBEDTLS_MODE_CBC )
     {
@@ -10546,12 +10654,6 @@
 #endif
 #endif
 
-#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \
-    defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED)
-    /* explicit void pointer cast for buggy MS compiler */
-    mbedtls_free( (void *) handshake->curves );
-#endif
-
 #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
     if( handshake->psk != NULL )
     {
@@ -10745,6 +10847,7 @@
 }
 
 #if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED)
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH)
 static int ssl_preset_default_hashes[] = {
 #if defined(MBEDTLS_SHA512_C)
     MBEDTLS_MD_SHA512,
@@ -10760,22 +10863,27 @@
     MBEDTLS_MD_NONE
 };
 #endif
+#endif
 
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
 static int ssl_preset_suiteb_ciphersuites[] = {
     MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
     MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
     0
 };
+#endif /* !MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
 
 #if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED)
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH)
 static int ssl_preset_suiteb_hashes[] = {
     MBEDTLS_MD_SHA256,
     MBEDTLS_MD_SHA384,
     MBEDTLS_MD_NONE
 };
 #endif
+#endif
 
-#if defined(MBEDTLS_ECP_C)
+#if defined(MBEDTLS_ECP_C) && !defined(MBEDTLS_SSL_CONF_SINGLE_EC)
 static mbedtls_ecp_group_id ssl_preset_suiteb_curves[] = {
 #if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED)
     MBEDTLS_ECP_DP_SECP256R1,
@@ -10896,67 +11004,94 @@
          * NSA Suite B
          */
         case MBEDTLS_SSL_PRESET_SUITEB:
+#if !defined(MBEDTLS_SSL_CONF_MIN_MAJOR_VER)
             conf->min_major_ver = MBEDTLS_SSL_MAJOR_VERSION_3;
+#endif /* !MBEDTLS_SSL_CONF_MIN_MAJOR_VER */
+#if !defined(MBEDTLS_SSL_CONF_MIN_MINOR_VER)
             conf->min_minor_ver = MBEDTLS_SSL_MINOR_VERSION_3; /* TLS 1.2 */
+#endif /* !MBEDTLS_SSL_CONF_MIN_MINOR_VER */
+#if !defined(MBEDTLS_SSL_CONF_MAX_MAJOR_VER)
             conf->max_major_ver = MBEDTLS_SSL_MAX_MAJOR_VERSION;
+#endif /* !MBEDTLS_SSL_CONF_MAX_MAJOR_VER */
+#if !defined(MBEDTLS_SSL_CONF_MAX_MINOR_VER)
             conf->max_minor_ver = MBEDTLS_SSL_MAX_MINOR_VERSION;
+#endif /* !MBEDTLS_SSL_CONF_MAX_MINOR_VER */
 
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
             conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_0] =
             conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_1] =
             conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_2] =
             conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_3] =
                                    ssl_preset_suiteb_ciphersuites;
+#endif /* MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
             conf->cert_profile = &mbedtls_x509_crt_profile_suiteb;
 #endif
 
 #if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED)
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH)
             conf->sig_hashes = ssl_preset_suiteb_hashes;
 #endif
+#endif
 
 #if defined(MBEDTLS_ECP_C)
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_EC)
             conf->curve_list = ssl_preset_suiteb_curves;
 #endif
+#endif
             break;
 
         /*
          * Default
          */
         default:
+#if !defined(MBEDTLS_SSL_CONF_MIN_MAJOR_VER)
             conf->min_major_ver = ( MBEDTLS_SSL_MIN_MAJOR_VERSION >
                                     MBEDTLS_SSL_MIN_VALID_MAJOR_VERSION ) ?
                                     MBEDTLS_SSL_MIN_MAJOR_VERSION :
                                     MBEDTLS_SSL_MIN_VALID_MAJOR_VERSION;
+#endif /* !MBEDTLS_SSL_CONF_MIN_MAJOR_VER */
+#if !defined(MBEDTLS_SSL_CONF_MIN_MINOR_VER)
             conf->min_minor_ver = ( MBEDTLS_SSL_MIN_MINOR_VERSION >
                                     MBEDTLS_SSL_MIN_VALID_MINOR_VERSION ) ?
                                     MBEDTLS_SSL_MIN_MINOR_VERSION :
                                     MBEDTLS_SSL_MIN_VALID_MINOR_VERSION;
-            conf->max_major_ver = MBEDTLS_SSL_MAX_MAJOR_VERSION;
-            conf->max_minor_ver = MBEDTLS_SSL_MAX_MINOR_VERSION;
-
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
             if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( transport ) )
                 conf->min_minor_ver = MBEDTLS_SSL_MINOR_VERSION_2;
 #endif
+#endif /* !MBEDTLS_SSL_CONF_MIN_MINOR_VER */
+#if !defined(MBEDTLS_SSL_CONF_MAX_MAJOR_VER)
+            conf->max_major_ver = MBEDTLS_SSL_MAX_MAJOR_VERSION;
+#endif /* !MBEDTLS_SSL_CONF_MAX_MAJOR_VER */
+#if !defined(MBEDTLS_SSL_CONF_MAX_MINOR_VER)
+            conf->max_minor_ver = MBEDTLS_SSL_MAX_MINOR_VERSION;
+#endif /* !MBEDTLS_SSL_CONF_MAX_MINOR_VER */
 
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
             conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_0] =
             conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_1] =
             conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_2] =
             conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_3] =
                                    mbedtls_ssl_list_ciphersuites();
+#endif /* MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
             conf->cert_profile = &mbedtls_x509_crt_profile_default;
 #endif
 
 #if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED)
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH)
             conf->sig_hashes = ssl_preset_default_hashes;
 #endif
+#endif
 
 #if defined(MBEDTLS_ECP_C)
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_EC)
             conf->curve_list = mbedtls_ecp_grp_id_list();
 #endif
+#endif
 
 #if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_CLI_C)
             conf->dhm_min_bitlen = 1024;
@@ -11172,14 +11307,10 @@
  */
 int mbedtls_ssl_check_curve( const mbedtls_ssl_context *ssl, mbedtls_ecp_group_id grp_id )
 {
-    const mbedtls_ecp_group_id *gid;
-
-    if( ssl->conf->curve_list == NULL )
-        return( -1 );
-
-    for( gid = ssl->conf->curve_list; *gid != MBEDTLS_ECP_DP_NONE; gid++ )
-        if( *gid == grp_id )
-            return( 0 );
+    MBEDTLS_SSL_BEGIN_FOR_EACH_SUPPORTED_EC_GRP_ID( own_ec_id )
+    if( own_ec_id == grp_id )
+        return( 0 );
+    MBEDTLS_SSL_END_FOR_EACH_SUPPORTED_EC_GRP_ID
 
     return( -1 );
 }
@@ -11193,14 +11324,10 @@
 int mbedtls_ssl_check_sig_hash( const mbedtls_ssl_context *ssl,
                                 mbedtls_md_type_t md )
 {
-    const int *cur;
-
-    if( ssl->conf->sig_hashes == NULL )
-        return( -1 );
-
-    for( cur = ssl->conf->sig_hashes; *cur != MBEDTLS_MD_NONE; cur++ )
-        if( *cur == (int) md )
-            return( 0 );
+    MBEDTLS_SSL_BEGIN_FOR_EACH_SIG_HASH( md_alg )
+    if( md_alg == md )
+        return( 0 );
+    MBEDTLS_SSL_END_FOR_EACH_SIG_HASH
 
     return( -1 );
 }
@@ -11208,7 +11335,7 @@
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
 int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert,
-                          const mbedtls_ssl_ciphersuite_t *ciphersuite,
+                          mbedtls_ssl_ciphersuite_handle_t ciphersuite,
                           int cert_endpoint,
                           uint32_t *flags )
 {
@@ -11232,7 +11359,7 @@
     if( cert_endpoint == MBEDTLS_SSL_IS_SERVER )
     {
         /* Server part of the key exchange */
-        switch( ciphersuite->key_exchange )
+        switch( mbedtls_ssl_suite_get_key_exchange( ciphersuite ) )
         {
             case MBEDTLS_KEY_EXCHANGE_RSA:
             case MBEDTLS_KEY_EXCHANGE_RSA_PSK:
@@ -11297,86 +11424,11 @@
 }
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
-/*
- * Convert version numbers to/from wire format
- * and, for DTLS, to/from TLS equivalent.
- *
- * For TLS this is the identity.
- * For DTLS, use 1's complement (v -> 255 - v, and then map as follows:
- * 1.0 <-> 3.2      (DTLS 1.0 is based on TLS 1.1)
- * 1.x <-> 3.x+1    for x != 0 (DTLS 1.2 based on TLS 1.2)
- */
-void mbedtls_ssl_write_version( int major, int minor, int transport,
-                        unsigned char ver[2] )
-{
-#if !defined(MBEDTLS_SSL_TRANSPORT__BOTH)
-    ((void) transport);
-#endif
-
-#if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( transport ) )
-    {
-        if( minor == MBEDTLS_SSL_MINOR_VERSION_2 )
-            --minor; /* DTLS 1.0 stored as TLS 1.1 internally */
-
-        ver[0] = (unsigned char)( 255 - ( major - 2 ) );
-        ver[1] = (unsigned char)( 255 - ( minor - 1 ) );
-    }
-    MBEDTLS_SSL_TRANSPORT_ELSE
-#endif
-#if defined(MBEDTLS_SSL_PROTO_TLS)
-    {
-        ver[0] = (unsigned char) major;
-        ver[1] = (unsigned char) minor;
-    }
-#endif
-}
-
-void mbedtls_ssl_read_version( int *major, int *minor, int transport,
-                       const unsigned char ver[2] )
-{
-#if !defined(MBEDTLS_SSL_TRANSPORT__BOTH)
-    ((void) transport);
-#endif
-
-#if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( MBEDTLS_SSL_TRANSPORT_IS_DTLS( transport ) )
-    {
-        *major = 255 - ver[0] + 2;
-        *minor = 255 - ver[1] + 1;
-
-        if( *minor == MBEDTLS_SSL_MINOR_VERSION_1 )
-            ++*minor; /* DTLS 1.0 stored as TLS 1.1 internally */
-    }
-    MBEDTLS_SSL_TRANSPORT_ELSE
-#endif /* MBEDTLS_SSL_PROTO_DTLS */
-#if defined(MBEDTLS_SSL_PROTO_TLS)
-    {
-        *major = ver[0];
-        *minor = ver[1];
-    }
-#endif /* MBEDTLS_SSL_PROTO_TLS */
-}
-
+#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
 int mbedtls_ssl_set_calc_verify_md( mbedtls_ssl_context *ssl, int md )
 {
-#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
-    if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 )
-        return MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH;
-
     switch( md )
     {
-#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1)
-#if defined(MBEDTLS_MD5_C)
-        case MBEDTLS_SSL_HASH_MD5:
-            return MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH;
-#endif
-#if defined(MBEDTLS_SHA1_C)
-        case MBEDTLS_SSL_HASH_SHA1:
-            ssl->handshake->calc_verify = ssl_calc_verify_tls;
-            break;
-#endif
-#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 */
 #if defined(MBEDTLS_SHA512_C)
         case MBEDTLS_SSL_HASH_SHA384:
             ssl->handshake->calc_verify = ssl_calc_verify_tls_sha384;
@@ -11387,18 +11439,14 @@
             ssl->handshake->calc_verify = ssl_calc_verify_tls_sha256;
             break;
 #endif
+
         default:
-            return MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH;
+            return( MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH );
     }
 
-    return 0;
-#else /* !MBEDTLS_SSL_PROTO_TLS1_2 */
-    (void) ssl;
-    (void) md;
-
-    return MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH;
-#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
+    return( 0 );
 }
+#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
 
 #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \
     defined(MBEDTLS_SSL_PROTO_TLS1_1)
@@ -11477,8 +11525,8 @@
     mbedtls_sha1_free( &mbedtls_sha1 );
 
     if( ret != 0 )
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
 
     return( ret );
 
@@ -11537,8 +11585,8 @@
     mbedtls_md_free( &ctx );
 
     if( ret != 0 )
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
 
     return( ret );
 }
diff --git a/programs/ssl/dtls_client.c b/programs/ssl/dtls_client.c
index cb2851b..5bd5cbe 100644
--- a/programs/ssl/dtls_client.c
+++ b/programs/ssl/dtls_client.c
@@ -83,6 +83,7 @@
 #define DEBUG_LEVEL 0
 
 
+#if defined(MBEDTLS_DEBUG_C)
 static void my_debug( void *ctx, int level,
                       const char *file, int line,
                       const char *str )
@@ -92,6 +93,7 @@
     mbedtls_fprintf( (FILE *) ctx, "%s:%04d: %s", file, line, str );
     fflush(  (FILE *) ctx  );
 }
+#endif /* MBEDTLS_DEBUG_C */
 
 int main( int argc, char *argv[] )
 {
@@ -191,7 +193,9 @@
     mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_OPTIONAL );
     mbedtls_ssl_conf_ca_chain( &conf, &cacert, NULL );
     mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
+#if defined(MBEDTLS_DEBUG_C)
     mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
+#endif
 
     if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
     {
@@ -205,11 +209,23 @@
         goto exit;
     }
 
-    mbedtls_ssl_set_bio( &ssl, &server_fd,
-                         mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout );
+#if !defined(MBEDTLS_SSL_CONF_RECV) && \
+    !defined(MBEDTLS_SSL_CONF_SEND) && \
+    !defined(MBEDTLS_SSL_CONF_RECV_TIMEOUT)
+    mbedtls_ssl_set_bio( &ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL );
+#else
+     mbedtls_ssl_set_bio_ctx( &ssl, &server_fd );
+#endif
 
+#if defined(MBEDTLS_TIMING_C)
+#if !defined(MBEDTLS_SSL_CONF_SET_TIMER) && \
+    !defined(MBEDTLS_SSL_CONF_GET_TIMER)
     mbedtls_ssl_set_timer_cb( &ssl, &timer, mbedtls_timing_set_delay,
                                             mbedtls_timing_get_delay );
+#else
+    mbedtls_ssl_set_timer_cb_ctx( &ssl, &timer );
+#endif
+#endif
 
     mbedtls_printf( " ok\n" );
 
diff --git a/programs/ssl/dtls_server.c b/programs/ssl/dtls_server.c
index 7d19d69..f2dcd2f 100644
--- a/programs/ssl/dtls_server.c
+++ b/programs/ssl/dtls_server.c
@@ -92,6 +92,7 @@
 #define DEBUG_LEVEL 0
 
 
+#if defined(MBEDTLS_DEBUG_C)
 static void my_debug( void *ctx, int level,
                       const char *file, int line,
                       const char *str )
@@ -101,6 +102,7 @@
     mbedtls_fprintf( (FILE *) ctx, "%s:%04d: %s", file, line, str );
     fflush(  (FILE *) ctx  );
 }
+#endif /* MBEDTLS_DEBUG_C */
 
 int main( void )
 {
@@ -223,7 +225,9 @@
     }
 
     mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
+#if defined(MBEDTLS_DEBUG_C)
     mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
+#endif
 
 #if defined(MBEDTLS_SSL_CACHE_C) && !defined(MBEDTLS_SSL_NO_SESSION_CACHE)
     mbedtls_ssl_conf_session_cache( &conf, &cache,
@@ -254,8 +258,14 @@
         goto exit;
     }
 
-    mbedtls_ssl_set_timer_cb( &ssl, &timer, mbedtls_timing_set_delay,
-                                            mbedtls_timing_get_delay );
+#if !defined(MBEDTLS_SSL_CONF_SET_TIMER) && \
+    !defined(MBEDTLS_SSL_CONF_GET_TIMER)
+    mbedtls_ssl_set_timer_cb( &ssl, &timer,
+                              mbedtls_timing_set_delay,
+                              mbedtls_timing_get_delay );
+#else
+    mbedtls_ssl_set_timer_cb_ctx( &ssl, &timer );
+#endif
 
     printf( " ok\n" );
 
diff --git a/programs/ssl/mini_client.c b/programs/ssl/mini_client.c
index 4b8140e..4231c0c 100644
--- a/programs/ssl/mini_client.c
+++ b/programs/ssl/mini_client.c
@@ -209,7 +209,11 @@
         goto exit;
     }
 
+#if !defined(MBEDTLS_SSL_CONF_RNG)
     mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
+#else
+    mbedtls_ssl_conf_rng_ctx( &conf, &ctr_drbg );
+#endif
 
 #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
     mbedtls_ssl_conf_psk( &conf, psk, sizeof( psk ),
@@ -265,7 +269,13 @@
         goto exit;
     }
 
+#if !defined(MBEDTLS_SSL_CONF_RECV) && \
+    !defined(MBEDTLS_SSL_CONF_SEND) && \
+    !defined(MBEDTLS_SSL_CONF_RECV_TIMEOUT)
     mbedtls_ssl_set_bio( &ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL );
+#else
+     mbedtls_ssl_set_bio_ctx( &ssl, &server_fd );
+#endif
 
     if( mbedtls_ssl_handshake( &ssl ) != 0 )
     {
diff --git a/programs/ssl/query_config.c b/programs/ssl/query_config.c
index 4502831..0f7251d 100644
--- a/programs/ssl/query_config.c
+++ b/programs/ssl/query_config.c
@@ -2722,6 +2722,86 @@
     }
 #endif /* MBEDTLS_SSL_CONF_IGNORE_UNEXPECTED_CID */
 
+#if defined(MBEDTLS_SSL_CONF_GET_TIMER)
+    if( strcmp( "MBEDTLS_SSL_CONF_GET_TIMER", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CONF_GET_TIMER );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CONF_GET_TIMER */
+
+#if defined(MBEDTLS_SSL_CONF_SET_TIMER)
+    if( strcmp( "MBEDTLS_SSL_CONF_SET_TIMER", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CONF_SET_TIMER );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CONF_SET_TIMER */
+
+#if defined(MBEDTLS_SSL_CONF_RECV)
+    if( strcmp( "MBEDTLS_SSL_CONF_RECV", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CONF_RECV );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CONF_RECV */
+
+#if defined(MBEDTLS_SSL_CONF_SEND)
+    if( strcmp( "MBEDTLS_SSL_CONF_SEND", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CONF_SEND );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CONF_SEND */
+
+#if defined(MBEDTLS_SSL_CONF_RECV_TIMEOUT)
+    if( strcmp( "MBEDTLS_SSL_CONF_RECV_TIMEOUT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CONF_RECV_TIMEOUT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CONF_RECV_TIMEOUT */
+
+#if defined(MBEDTLS_SSL_CONF_RNG)
+    if( strcmp( "MBEDTLS_SSL_CONF_RNG", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CONF_RNG );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CONF_RNG */
+
+#if defined(MBEDTLS_SSL_CONF_MIN_MINOR_VER)
+    if( strcmp( "MBEDTLS_SSL_CONF_MIN_MINOR_VER", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CONF_MIN_MINOR_VER );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CONF_MIN_MINOR_VER */
+
+#if defined(MBEDTLS_SSL_CONF_MAX_MINOR_VER)
+    if( strcmp( "MBEDTLS_SSL_CONF_MAX_MINOR_VER", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CONF_MAX_MINOR_VER );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CONF_MAX_MINOR_VER */
+
+#if defined(MBEDTLS_SSL_CONF_MIN_MAJOR_VER)
+    if( strcmp( "MBEDTLS_SSL_CONF_MIN_MAJOR_VER", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CONF_MIN_MAJOR_VER );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CONF_MIN_MAJOR_VER */
+
+#if defined(MBEDTLS_SSL_CONF_MAX_MAJOR_VER)
+    if( strcmp( "MBEDTLS_SSL_CONF_MAX_MAJOR_VER", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CONF_MAX_MAJOR_VER );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CONF_MAX_MAJOR_VER */
+
 #if defined(MBEDTLS_SSL_CONF_EXTENDED_MASTER_SECRET)
     if( strcmp( "MBEDTLS_SSL_CONF_EXTENDED_MASTER_SECRET", config ) == 0 )
     {
@@ -2738,6 +2818,62 @@
     }
 #endif /* MBEDTLS_SSL_CONF_ENFORCE_EXTENDED_MASTER_SECRET */
 
+#if defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
+    if( strcmp( "MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
+
+#if defined(MBEDTLS_SSL_CONF_SINGLE_EC)
+    if( strcmp( "MBEDTLS_SSL_CONF_SINGLE_EC", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CONF_SINGLE_EC );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CONF_SINGLE_EC */
+
+#if defined(MBEDTLS_SSL_CONF_SINGLE_EC_TLS_ID)
+    if( strcmp( "MBEDTLS_SSL_CONF_SINGLE_EC_TLS_ID", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CONF_SINGLE_EC_TLS_ID );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CONF_SINGLE_EC_TLS_ID */
+
+#if defined(MBEDTLS_SSL_CONF_SINGLE_EC_GRP_ID)
+    if( strcmp( "MBEDTLS_SSL_CONF_SINGLE_EC_GRP_ID", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CONF_SINGLE_EC_GRP_ID );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CONF_SINGLE_EC_GRP_ID */
+
+#if defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH)
+    if( strcmp( "MBEDTLS_SSL_CONF_SINGLE_SIG_HASH", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CONF_SINGLE_SIG_HASH );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CONF_SINGLE_SIG_HASH */
+
+#if defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_MD_ID)
+    if( strcmp( "MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_MD_ID", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_MD_ID );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_MD_ID */
+
+#if defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_TLS_ID)
+    if( strcmp( "MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_TLS_ID", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_TLS_ID );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_TLS_ID */
+
     /* If the symbol is not found, return an error */
     return( 1 );
 }
diff --git a/programs/ssl/ssl_client1.c b/programs/ssl/ssl_client1.c
index 28ecc21..2554946 100644
--- a/programs/ssl/ssl_client1.c
+++ b/programs/ssl/ssl_client1.c
@@ -73,6 +73,7 @@
 #define DEBUG_LEVEL 1
 
 
+#if defined(MBEDTLS_DEBUG_C)
 static void my_debug( void *ctx, int level,
                       const char *file, int line,
                       const char *str )
@@ -82,6 +83,7 @@
     mbedtls_fprintf( (FILE *) ctx, "%s:%04d: %s", file, line, str );
     fflush(  (FILE *) ctx  );
 }
+#endif /* MBEDTLS_DEBUG_C */
 
 int main( void )
 {
@@ -178,7 +180,9 @@
     mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_OPTIONAL );
     mbedtls_ssl_conf_ca_chain( &conf, &cacert, NULL );
     mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
+#if defined(MBEDTLS_DEBUG_C)
     mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
+#endif
 
     if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
     {
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 8d7ee0a..bb84207 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -56,6 +56,7 @@
 
 #include "mbedtls/net_sockets.h"
 #include "mbedtls/ssl.h"
+#include "mbedtls/ssl_ciphersuites.h"
 #include "mbedtls/entropy.h"
 #include "mbedtls/ctr_drbg.h"
 #include "mbedtls/certs.h"
@@ -214,7 +215,7 @@
 #define USAGE_ALPN ""
 #endif /* MBEDTLS_SSL_ALPN */
 
-#if defined(MBEDTLS_ECP_C)
+#if defined(MBEDTLS_ECP_C) && !defined(MBEDTLS_SSL_CONF_SINGLE_EC)
 #define USAGE_CURVES \
     "    curves=a,b,c,d      default: \"default\" (library default)\n"  \
     "                        example: \"secp521r1,brainpoolP512r1\"\n"  \
@@ -314,6 +315,20 @@
 #define USAGE_READ_TIMEOUT ""
 #endif
 
+#if !defined(MBEDTLS_SSL_CONF_MIN_MINOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MIN_MAJOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MAX_MINOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MAX_MAJOR_VER)
+#define USAGE_MAX_VERSION    "    max_version=%%s      default: (library default: tls1_2)\n"
+#define USAGE_MIN_VERSION    "    min_version=%%s      default: (library default: tls1)\n"
+#define USAGE_FORCE_VERSION    "    force_version=%%s    default: \"\" (none)\n"       \
+           "                        options: ssl3, tls1, tls1_1, tls1_2, dtls1, dtls1_2\n"
+#else
+#define USAGE_MAX_VERSION   ""
+#define USAGE_MIN_VERSION   ""
+#define USAGE_FORCE_VERSION ""
+#endif
+
 #define USAGE \
     "\n usage: ssl_client2 param=<>...\n"                   \
     "\n acceptable parameters:\n"                           \
@@ -367,10 +382,9 @@
     "\n"                                                    \
     "    arc4=%%d             default: (library default: 0)\n" \
     "    allow_sha1=%%d       default: 0\n"                             \
-    "    min_version=%%s      default: (library default: tls1)\n"       \
-    "    max_version=%%s      default: (library default: tls1_2)\n"     \
-    "    force_version=%%s    default: \"\" (none)\n"       \
-    "                        options: ssl3, tls1, tls1_1, tls1_2, dtls1, dtls1_2\n" \
+    USAGE_MIN_VERSION                                                   \
+    USAGE_MAX_VERSION                                                   \
+    USAGE_FORCE_VERSION                                                 \
     "\n"                                                    \
     "    force_ciphersuite=<name>    default: all enabled\n"\
     "    query_config=<name>         return 0 if the specified\n"       \
@@ -450,6 +464,7 @@
 
 int query_config( const char *config );
 
+#if defined(MBEDTLS_DEBUG_C)
 static void my_debug( void *ctx, int level,
                       const char *file, int line,
                       const char *str )
@@ -465,7 +480,12 @@
                      basename, line, level, str );
     fflush(  (FILE *) ctx  );
 }
+#endif /* MBEDTLS_DEBUG_C */
 
+
+#if !defined(MBEDTLS_SSL_CONF_RECV) && \
+    !defined(MBEDTLS_SSL_CONF_SEND) && \
+    !defined(MBEDTLS_SSL_CONF_RECV_TIMEOUT)
 /*
  * Test recv/send functions that make sure each try returns
  * WANT_READ/WANT_WRITE at least once before sucesseding
@@ -503,6 +523,9 @@
         first_try = 1; /* Next call will be a new operation */
     return( ret );
 }
+#endif /* MBEDTLS_SSL_CONF_RECV &&
+          MBEDTLS_SSL_CONF_SEND &&
+          MBEDTLS_SSL_CONF_RECV_TIMEOUT */
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
 static unsigned char peer_crt_info[1024];
@@ -546,6 +569,7 @@
     return( 0 );
 }
 
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_HASH)
 static int ssl_sig_hashes_for_test[] = {
 #if defined(MBEDTLS_SHA512_C)
     MBEDTLS_MD_SHA512,
@@ -561,6 +585,7 @@
 #endif
     MBEDTLS_MD_NONE
 };
+#endif /* !MBEDTLS_SSL_CONF_SINGLE_HASH */
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
 /*
@@ -754,7 +779,7 @@
 #if defined(MBEDTLS_SSL_ALPN)
     const char *alpn_list[ALPN_LIST_SIZE];
 #endif
-#if defined(MBEDTLS_ECP_C)
+#if defined(MBEDTLS_ECP_C) && !defined(MBEDTLS_SSL_CONF_SINGLE_EC)
     mbedtls_ecp_group_id curve_list[CURVE_LIST_SIZE];
     const mbedtls_ecp_curve_info *curve_cur;
 #endif
@@ -1092,8 +1117,10 @@
                 default: goto usage;
             }
         }
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_EC)
         else if( strcmp( p, "curves" ) == 0 )
             opt.curves = q;
+#endif /* !MBEDTLS_SSL_CONF_SINGLE_EC */
         else if( strcmp( p, "etm" ) == 0 )
         {
             switch( atoi( q ) )
@@ -1103,6 +1130,10 @@
                 default: goto usage;
             }
         }
+#if !defined(MBEDTLS_SSL_CONF_MIN_MINOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MIN_MAJOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MAX_MINOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MAX_MAJOR_VER)
         else if( strcmp( p, "min_version" ) == 0 )
         {
             if( strcmp( q, "ssl3" ) == 0 )
@@ -1133,24 +1164,6 @@
             else
                 goto usage;
         }
-        else if( strcmp( p, "arc4" ) == 0 )
-        {
-            switch( atoi( q ) )
-            {
-                case 0:     opt.arc4 = MBEDTLS_SSL_ARC4_DISABLED;   break;
-                case 1:     opt.arc4 = MBEDTLS_SSL_ARC4_ENABLED;    break;
-                default:    goto usage;
-            }
-        }
-        else if( strcmp( p, "allow_sha1" ) == 0 )
-        {
-            switch( atoi( q ) )
-            {
-                case 0:     opt.allow_sha1 = 0;   break;
-                case 1:     opt.allow_sha1 = 1;    break;
-                default:    goto usage;
-            }
-        }
         else if( strcmp( p, "force_version" ) == 0 )
         {
             if( strcmp( q, "ssl3" ) == 0 )
@@ -1188,6 +1201,25 @@
             else
                 goto usage;
         }
+#endif
+        else if( strcmp( p, "arc4" ) == 0 )
+        {
+            switch( atoi( q ) )
+            {
+                case 0:     opt.arc4 = MBEDTLS_SSL_ARC4_DISABLED;   break;
+                case 1:     opt.arc4 = MBEDTLS_SSL_ARC4_ENABLED;    break;
+                default:    goto usage;
+            }
+        }
+        else if( strcmp( p, "allow_sha1" ) == 0 )
+        {
+            switch( atoi( q ) )
+            {
+                case 0:     opt.allow_sha1 = 0;   break;
+                case 1:     opt.allow_sha1 = 1;    break;
+                default:    goto usage;
+            }
+        }
 #if !defined(MBEDTLS_SSL_CONF_AUTHMODE)
         else if( strcmp( p, "auth_mode" ) == 0 )
         {
@@ -1289,19 +1321,19 @@
 
     if( opt.force_ciphersuite[0] > 0 )
     {
-        const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
+        mbedtls_ssl_ciphersuite_handle_t ciphersuite_info;
         ciphersuite_info =
             mbedtls_ssl_ciphersuite_from_id( opt.force_ciphersuite[0] );
 
         if( opt.max_version != -1 &&
-            ciphersuite_info->min_minor_ver > opt.max_version )
+            mbedtls_ssl_suite_get_min_minor_ver( ciphersuite_info ) > opt.max_version )
         {
             mbedtls_printf( "forced ciphersuite not allowed with this protocol version\n" );
             ret = 2;
             goto usage;
         }
         if( opt.min_version != -1 &&
-            ciphersuite_info->max_minor_ver < opt.min_version )
+            mbedtls_ssl_suite_get_max_minor_ver( ciphersuite_info ) < opt.min_version )
         {
             mbedtls_printf( "forced ciphersuite not allowed with this protocol version\n" );
             ret = 2;
@@ -1311,13 +1343,13 @@
         /* If the server selects a version that's not supported by
          * this suite, then there will be no common ciphersuite... */
         if( opt.max_version == -1 ||
-            opt.max_version > ciphersuite_info->max_minor_ver )
+            opt.max_version > mbedtls_ssl_suite_get_max_minor_ver( ciphersuite_info ) )
         {
-            opt.max_version = ciphersuite_info->max_minor_ver;
+            opt.max_version = mbedtls_ssl_suite_get_max_minor_ver( ciphersuite_info );
         }
-        if( opt.min_version < ciphersuite_info->min_minor_ver )
+        if( opt.min_version < mbedtls_ssl_suite_get_min_minor_ver( ciphersuite_info ) )
         {
-            opt.min_version = ciphersuite_info->min_minor_ver;
+            opt.min_version = mbedtls_ssl_suite_get_min_minor_ver( ciphersuite_info );
             /* DTLS starts with TLS 1.1 */
             if( opt.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
                 opt.min_version < MBEDTLS_SSL_MINOR_VERSION_2 )
@@ -1325,7 +1357,7 @@
         }
 
         /* Enable RC4 if needed and not explicitly disabled */
-        if( ciphersuite_info->cipher == MBEDTLS_CIPHER_ARC4_128 )
+        if( mbedtls_ssl_suite_get_cipher( ciphersuite_info ) == MBEDTLS_CIPHER_ARC4_128 )
         {
             if( opt.arc4 == MBEDTLS_SSL_ARC4_DISABLED )
             {
@@ -1394,7 +1426,7 @@
     }
 #endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */
 
-#if defined(MBEDTLS_ECP_C)
+#if defined(MBEDTLS_ECP_C) && !defined(MBEDTLS_SSL_CONF_SINGLE_EC)
     if( opt.curves != NULL )
     {
         p = (char *) opt.curves;
@@ -1448,7 +1480,7 @@
             curve_list[i] = MBEDTLS_ECP_DP_NONE;
         }
     }
-#endif /* MBEDTLS_ECP_C */
+#endif /* MBEDTLS_ECP_C && !MBEDTLS_SSL_CONF_SINGLE_EC */
 
 #if defined(MBEDTLS_SSL_ALPN)
     if( opt.alpn_string != NULL )
@@ -1663,7 +1695,9 @@
     {
         crt_profile_for_test.allowed_mds |= MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 );
         mbedtls_ssl_conf_cert_profile( &conf, &crt_profile_for_test );
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_HASH)
         mbedtls_ssl_conf_sig_hashes( &conf, ssl_sig_hashes_for_test );
+#endif
     }
 
     mbedtls_ssl_conf_verify( &conf, my_verify, NULL );
@@ -1764,8 +1798,15 @@
         }
 #endif
 
+#if !defined(MBEDTLS_SSL_CONF_RNG)
     mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
+#else
+    mbedtls_ssl_conf_rng_ctx( &conf, &ctr_drbg );
+#endif
+
+#if defined(MBEDTLS_DEBUG_C)
     mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
+#endif
 
 #if !defined(MBEDTLS_SSL_CONF_READ_TIMEOUT)
     mbedtls_ssl_conf_read_timeout( &conf, opt.read_timeout );
@@ -1775,8 +1816,10 @@
     mbedtls_ssl_conf_session_tickets( &conf, opt.tickets );
 #endif
 
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
     if( opt.force_ciphersuite[0] != DFL_FORCE_CIPHER )
         mbedtls_ssl_conf_ciphersuites( &conf, opt.force_ciphersuite );
+#endif /* MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
 
 #if defined(MBEDTLS_ARC4_C)
     if( opt.arc4 != DFL_ARC4 )
@@ -1810,12 +1853,14 @@
 #endif
 
 #if defined(MBEDTLS_ECP_C)
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_EC)
     if( opt.curves != NULL &&
         strcmp( opt.curves, "default" ) != 0 )
     {
         mbedtls_ssl_conf_curves( &conf, curve_list );
     }
-#endif
+#endif /* !MBEDTLS_SSL_CONF_SINGLE_EC */
+#endif /* MBEDTLS_ECP_C */
 
 #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
     if( ( ret = mbedtls_ssl_conf_psk( &conf, psk, psk_len,
@@ -1828,6 +1873,10 @@
     }
 #endif
 
+#if !defined(MBEDTLS_SSL_CONF_MIN_MINOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MIN_MAJOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MAX_MINOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MAX_MAJOR_VER)
     if( opt.min_version != DFL_MIN_VERSION )
         mbedtls_ssl_conf_min_version( &conf, MBEDTLS_SSL_MAJOR_VERSION_3,
                                       opt.min_version );
@@ -1835,6 +1884,7 @@
     if( opt.max_version != DFL_MAX_VERSION )
         mbedtls_ssl_conf_max_version( &conf, MBEDTLS_SSL_MAJOR_VERSION_3,
                                       opt.max_version );
+#endif
 
 #if defined(MBEDTLS_SSL_FALLBACK_SCSV)
     if( opt.fallback != DFL_FALLBACK )
@@ -1871,12 +1921,18 @@
     }
 #endif
 
+#if !defined(MBEDTLS_SSL_CONF_RECV) && \
+    !defined(MBEDTLS_SSL_CONF_SEND) && \
+    !defined(MBEDTLS_SSL_CONF_RECV_TIMEOUT)
     if( opt.nbio == 2 )
         mbedtls_ssl_set_bio( &ssl, &server_fd, my_send, my_recv, NULL );
     else
         mbedtls_ssl_set_bio( &ssl, &server_fd,
                              mbedtls_net_send, mbedtls_net_recv,
                              opt.nbio == 0 ? mbedtls_net_recv_timeout : NULL );
+#else
+     mbedtls_ssl_set_bio_ctx( &ssl, &server_fd );
+#endif
 
 #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
     if( opt.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
@@ -1897,8 +1953,13 @@
 #endif
 
 #if defined(MBEDTLS_TIMING_C)
+#if !defined(MBEDTLS_SSL_CONF_SET_TIMER) && \
+    !defined(MBEDTLS_SSL_CONF_GET_TIMER)
     mbedtls_ssl_set_timer_cb( &ssl, &timer, mbedtls_timing_set_delay,
                                             mbedtls_timing_get_delay );
+#else
+    mbedtls_ssl_set_timer_cb_ctx( &ssl, &timer );
+#endif
 #endif
 
 #if defined(MBEDTLS_ECP_RESTARTABLE)
@@ -2489,9 +2550,16 @@
 
 #if defined(MBEDTLS_TIMING_C)
             if( opt.nbio != 0 && opt.read_timeout != 0 )
+            {
+#if !defined(MBEDTLS_SSL_CONF_SET_TIMER) && \
+    !defined(MBEDTLS_SSL_CONF_GET_TIMER)
                 mbedtls_ssl_set_timer_cb( &ssl, &timer,
                                           mbedtls_timing_set_delay,
                                           mbedtls_timing_get_delay );
+#else
+                mbedtls_ssl_set_timer_cb_ctx( &ssl, &timer );
+#endif
+            }
 #endif /* MBEDTLS_TIMING_C */
         }
 
diff --git a/programs/ssl/ssl_fork_server.c b/programs/ssl/ssl_fork_server.c
index b4a5414..c716ca9 100644
--- a/programs/ssl/ssl_fork_server.c
+++ b/programs/ssl/ssl_fork_server.c
@@ -90,6 +90,7 @@
 #define DEBUG_LEVEL 0
 
 
+#if defined(MBEDTLS_DEBUG_C)
 static void my_debug( void *ctx, int level,
                       const char *file, int line,
                       const char *str )
@@ -99,6 +100,7 @@
     mbedtls_fprintf( (FILE *) ctx, "%s:%04d: %s", file, line, str );
     fflush(  (FILE *) ctx  );
 }
+#endif /* MBEDTLS_DEBUG_C */
 
 int main( void )
 {
@@ -195,7 +197,9 @@
     }
 
     mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
+#if defined(MBEDTLS_DEBUG_C)
     mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
+#endif
 
     mbedtls_ssl_conf_ca_chain( &conf, srvcert.next, NULL );
     if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert, &pkey ) ) != 0 )
diff --git a/programs/ssl/ssl_mail_client.c b/programs/ssl/ssl_mail_client.c
index 5880468..11b682c 100644
--- a/programs/ssl/ssl_mail_client.c
+++ b/programs/ssl/ssl_mail_client.c
@@ -163,6 +163,7 @@
     int force_ciphersuite[2];   /* protocol/ciphersuite to use, or all      */
 } opt;
 
+#if defined(MBEDTLS_DEBUG_C)
 static void my_debug( void *ctx, int level,
                       const char *file, int line,
                       const char *str )
@@ -172,6 +173,7 @@
     mbedtls_fprintf( (FILE *) ctx, "%s:%04d: %s", file, line, str );
     fflush(  (FILE *) ctx  );
 }
+#endif /* MBEDTLS_DEBUG_C */
 
 static int do_handshake( mbedtls_ssl_context *ssl )
 {
@@ -619,10 +621,14 @@
     mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_OPTIONAL );
 
     mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
+#if defined(MBEDTLS_DEBUG_C)
     mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
+#endif
 
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
     if( opt.force_ciphersuite[0] != DFL_FORCE_CIPHER )
         mbedtls_ssl_conf_ciphersuites( &conf, opt.force_ciphersuite );
+#endif /* !MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
 
     mbedtls_ssl_conf_ca_chain( &conf, &cacert, NULL );
     if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &clicert, &pkey ) ) != 0 )
diff --git a/programs/ssl/ssl_pthread_server.c b/programs/ssl/ssl_pthread_server.c
index 11298a5..6ce4faa 100644
--- a/programs/ssl/ssl_pthread_server.c
+++ b/programs/ssl/ssl_pthread_server.c
@@ -433,7 +433,9 @@
     }
 
     mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
+#if defined(MBEDTLS_DEBUG_C)
     mbedtls_ssl_conf_dbg( &conf, my_mutexed_debug, stdout );
+#endif
 
     /* mbedtls_ssl_cache_get() and mbedtls_ssl_cache_set() are thread-safe if
      * MBEDTLS_THREADING_C is set.
diff --git a/programs/ssl/ssl_server.c b/programs/ssl/ssl_server.c
index f5fcfda..849c14d 100644
--- a/programs/ssl/ssl_server.c
+++ b/programs/ssl/ssl_server.c
@@ -85,6 +85,7 @@
 #define DEBUG_LEVEL 0
 
 
+#if defined(MBEDTLS_DEBUG_C)
 static void my_debug( void *ctx, int level,
                       const char *file, int line,
                       const char *str )
@@ -94,6 +95,7 @@
     mbedtls_fprintf( (FILE *) ctx, "%s:%04d: %s", file, line, str );
     fflush(  (FILE *) ctx  );
 }
+#endif /* MBEDTLS_DEBUG_C */
 
 int main( void )
 {
@@ -211,7 +213,9 @@
     }
 
     mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
+#if defined(MBEDTLS_DEBUG_C)
     mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
+#endif
 
 #if defined(MBEDTLS_SSL_CACHE_C) && !defined(MBEDTLS_SSL_NO_SESSION_CACHE)
     mbedtls_ssl_conf_session_cache( &conf, &cache,
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 5135ad4..42b9773 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -55,6 +55,7 @@
 
 #include "mbedtls/net_sockets.h"
 #include "mbedtls/ssl.h"
+#include "mbedtls/ssl_ciphersuites.h"
 #include "mbedtls/entropy.h"
 #include "mbedtls/ctr_drbg.h"
 #include "mbedtls/certs.h"
@@ -380,7 +381,7 @@
 #define USAGE_ECJPAKE ""
 #endif
 
-#if defined(MBEDTLS_ECP_C)
+#if defined(MBEDTLS_ECP_C) && !defined(MBEDTLS_SSL_CONF_SINGLE_EC)
 #define USAGE_CURVES \
     "    curves=a,b,c,d      default: \"default\" (library default)\n"  \
     "                        example: \"secp521r1,brainpoolP512r1\"\n"  \
@@ -430,6 +431,20 @@
 #define USAGE_CERT_REQ_CA_LIST ""
 #endif
 
+#if !defined(MBEDTLS_SSL_CONF_MIN_MINOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MIN_MAJOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MAX_MINOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MAX_MAJOR_VER)
+#define USAGE_MAX_VERSION    "    max_version=%%s      default: (library default: tls1_2)\n"
+#define USAGE_MIN_VERSION    "    min_version=%%s      default: (library default: tls1)\n"
+#define USAGE_FORCE_VERSION    "    force_version=%%s    default: \"\" (none)\n"       \
+           "                        options: ssl3, tls1, tls1_1, tls1_2, dtls1, dtls1_2\n"
+#else
+#define USAGE_MAX_VERSION   ""
+#define USAGE_MIN_VERSION   ""
+#define USAGE_FORCE_VERSION ""
+#endif
+
 #define USAGE \
     "\n usage: ssl_server2 param=<>...\n"                   \
     "\n acceptable parameters:\n"                           \
@@ -476,10 +491,9 @@
     "\n"                                                    \
     "    arc4=%%d             default: (library default: 0)\n" \
     "    allow_sha1=%%d       default: 0\n"                             \
-    "    min_version=%%s      default: (library default: tls1)\n"       \
-    "    max_version=%%s      default: (library default: tls1_2)\n"     \
-    "    force_version=%%s    default: \"\" (none)\n"       \
-    "                        options: ssl3, tls1, tls1_1, tls1_2, dtls1, dtls1_2\n" \
+    USAGE_MIN_VERSION                                                   \
+    USAGE_MAX_VERSION                                                   \
+    USAGE_FORCE_VERSION                                                 \
     "\n"                                                                \
     "    version_suites=a,b,c,d      per-version ciphersuites\n"        \
     "                                in order from ssl3 to tls1_2\n"    \
@@ -582,6 +596,7 @@
 
 int query_config( const char *config );
 
+#if defined(MBEDTLS_DEBUG_C)
 static void my_debug( void *ctx, int level,
                       const char *file, int line,
                       const char *str )
@@ -596,7 +611,12 @@
     mbedtls_fprintf( (FILE *) ctx, "%s:%04d: |%d| %s", basename, line, level, str );
     fflush(  (FILE *) ctx  );
 }
+#endif /* MBEDTLS_DEBUG_C */
 
+
+#if !defined(MBEDTLS_SSL_CONF_RECV) && \
+    !defined(MBEDTLS_SSL_CONF_SEND) && \
+    !defined(MBEDTLS_SSL_CONF_RECV_TIMEOUT)
 /*
  * Test recv/send functions that make sure each try returns
  * WANT_READ/WANT_WRITE at least once before sucesseding
@@ -634,6 +654,9 @@
         first_try = 1; /* Next call will be a new operation */
     return( ret );
 }
+#endif /* MBEDTLS_SSL_CONF_RECV &&
+          MBEDTLS_SSL_CONF_SEND &&
+          MBEDTLS_SSL_CONF_RECV_TIMEOUT */
 
 #if !defined(MBEDTLS_SSL_CONF_AUTHMODE)
 /*
@@ -977,7 +1000,8 @@
 }
 #endif
 
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
+    !defined(MBEDTLS_SSL_CONF_SINGLE_HASH)
 static int ssl_sig_hashes_for_test[] = {
 #if defined(MBEDTLS_SHA512_C)
     MBEDTLS_MD_SHA512,
@@ -993,7 +1017,7 @@
 #endif
     MBEDTLS_MD_NONE
 };
-#endif /* MBEDTLS_X509_CRT_PARSE_C */
+#endif /* MBEDTLS_X509_CRT_PARSE_C && !defined(MBEDTLS_SSL_CONF_SINGLE_HASH) */
 
 /** Return true if \p ret is a status code indicating that there is an
  * operation in progress on an SSL connection, and false if it indicates
@@ -1402,7 +1426,7 @@
 #if defined(SNI_OPTION)
     sni_entry *sni_info = NULL;
 #endif
-#if defined(MBEDTLS_ECP_C)
+#if defined(MBEDTLS_ECP_C) && !defined(MBEDTLS_SSL_CONF_SINGLE_EC)
     mbedtls_ecp_group_id curve_list[CURVE_LIST_SIZE];
     const mbedtls_ecp_curve_info * curve_cur;
 #endif
@@ -1684,8 +1708,10 @@
             }
             opt.force_ciphersuite[1] = 0;
         }
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_EC)
         else if( strcmp( p, "curves" ) == 0 )
             opt.curves = q;
+#endif /* !MBEDTLS_SSL_CONF_SINGLE_EC */
         else if( strcmp( p, "version_suites" ) == 0 )
             opt.version_suites = q;
         else if( strcmp( p, "renegotiation" ) == 0 )
@@ -1739,6 +1765,10 @@
             if( opt.exchanges < 0 )
                 goto usage;
         }
+#if !defined(MBEDTLS_SSL_CONF_MIN_MINOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MIN_MAJOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MAX_MINOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MAX_MAJOR_VER)
         else if( strcmp( p, "min_version" ) == 0 )
         {
             if( strcmp( q, "ssl3" ) == 0 )
@@ -1769,24 +1799,6 @@
             else
                 goto usage;
         }
-        else if( strcmp( p, "arc4" ) == 0 )
-        {
-            switch( atoi( q ) )
-            {
-                case 0:     opt.arc4 = MBEDTLS_SSL_ARC4_DISABLED;   break;
-                case 1:     opt.arc4 = MBEDTLS_SSL_ARC4_ENABLED;    break;
-                default:    goto usage;
-            }
-        }
-        else if( strcmp( p, "allow_sha1" ) == 0 )
-        {
-            switch( atoi( q ) )
-            {
-                case 0:     opt.allow_sha1 = 0;   break;
-                case 1:     opt.allow_sha1 = 1;    break;
-                default:    goto usage;
-            }
-        }
         else if( strcmp( p, "force_version" ) == 0 )
         {
             if( strcmp( q, "ssl3" ) == 0 )
@@ -1824,6 +1836,31 @@
             else
                 goto usage;
         }
+#endif
+        else if( strcmp( p, "arc4" ) == 0 )
+        {
+            switch( atoi( q ) )
+            {
+                case 0:     opt.arc4 = MBEDTLS_SSL_ARC4_DISABLED;   break;
+                case 1:     opt.arc4 = MBEDTLS_SSL_ARC4_ENABLED;    break;
+                default:    goto usage;
+            }
+        }
+        else if( strcmp( p, "allow_sha1" ) == 0 )
+        {
+            switch( atoi( q ) )
+            {
+                case 0:     opt.allow_sha1 = 0;   break;
+                case 1:     opt.allow_sha1 = 1;    break;
+                default:    goto usage;
+            }
+        }
+#if !defined(MBEDTLS_SSL_CONF_MIN_MINOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MIN_MAJOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MAX_MINOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MAX_MAJOR_VER)
+
+#endif
 #if !defined(MBEDTLS_SSL_CONF_AUTHMODE)
         else if( strcmp( p, "auth_mode" ) == 0 )
         {
@@ -2011,19 +2048,19 @@
 
     if( opt.force_ciphersuite[0] > 0 )
     {
-        const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
+        mbedtls_ssl_ciphersuite_handle_t ciphersuite_info;
         ciphersuite_info =
             mbedtls_ssl_ciphersuite_from_id( opt.force_ciphersuite[0] );
 
         if( opt.max_version != -1 &&
-            ciphersuite_info->min_minor_ver > opt.max_version )
+            mbedtls_ssl_suite_get_min_minor_ver( ciphersuite_info ) > opt.max_version )
         {
             mbedtls_printf( "forced ciphersuite not allowed with this protocol version\n" );
             ret = 2;
             goto usage;
         }
         if( opt.min_version != -1 &&
-            ciphersuite_info->max_minor_ver < opt.min_version )
+            mbedtls_ssl_suite_get_max_minor_ver( ciphersuite_info ) < opt.min_version )
         {
             mbedtls_printf( "forced ciphersuite not allowed with this protocol version\n" );
             ret = 2;
@@ -2033,13 +2070,13 @@
         /* If we select a version that's not supported by
          * this suite, then there will be no common ciphersuite... */
         if( opt.max_version == -1 ||
-            opt.max_version > ciphersuite_info->max_minor_ver )
+            opt.max_version > mbedtls_ssl_suite_get_max_minor_ver( ciphersuite_info ) )
         {
-            opt.max_version = ciphersuite_info->max_minor_ver;
+            opt.max_version = mbedtls_ssl_suite_get_max_minor_ver( ciphersuite_info );
         }
-        if( opt.min_version < ciphersuite_info->min_minor_ver )
+        if( opt.min_version < mbedtls_ssl_suite_get_min_minor_ver( ciphersuite_info ) )
         {
-            opt.min_version = ciphersuite_info->min_minor_ver;
+            opt.min_version = mbedtls_ssl_suite_get_min_minor_ver( ciphersuite_info );
             /* DTLS starts with TLS 1.1 */
             if( opt.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
                 opt.min_version < MBEDTLS_SSL_MINOR_VERSION_2 )
@@ -2047,7 +2084,7 @@
         }
 
         /* Enable RC4 if needed and not explicitly disabled */
-        if( ciphersuite_info->cipher == MBEDTLS_CIPHER_ARC4_128 )
+        if( mbedtls_ssl_suite_get_cipher( ciphersuite_info ) == MBEDTLS_CIPHER_ARC4_128 )
         {
             if( opt.arc4 == MBEDTLS_SSL_ARC4_DISABLED )
             {
@@ -2142,7 +2179,7 @@
     }
 #endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */
 
-#if defined(MBEDTLS_ECP_C)
+#if defined(MBEDTLS_ECP_C) && !defined(MBEDTLS_SSL_CONF_SINGLE_EC)
     if( opt.curves != NULL )
     {
         p = (char *) opt.curves;
@@ -2196,7 +2233,7 @@
             curve_list[i] = MBEDTLS_ECP_DP_NONE;
         }
     }
-#endif /* MBEDTLS_ECP_C */
+#endif /* MBEDTLS_ECP_C && !MBEDTLS_SSL_CONF_SINGLE_EC */
 
 #if defined(MBEDTLS_SSL_ALPN)
     if( opt.alpn_string != NULL )
@@ -2480,7 +2517,9 @@
     {
         crt_profile_for_test.allowed_mds |= MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 );
         mbedtls_ssl_conf_cert_profile( &conf, &crt_profile_for_test );
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_HASH)
         mbedtls_ssl_conf_sig_hashes( &conf, ssl_sig_hashes_for_test );
+#endif
     }
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
@@ -2570,8 +2609,15 @@
         }
 #endif
 
+#if !defined(MBEDTLS_SSL_CONF_RNG)
     mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
+#else
+    mbedtls_ssl_conf_rng_ctx( &conf, &ctr_drbg );
+#endif
+
+#if defined(MBEDTLS_DEBUG_C)
     mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
+#endif
 
 #if defined(MBEDTLS_SSL_CACHE_C)
     if( opt.cache_max != -1 )
@@ -2649,14 +2695,17 @@
     }
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
 
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
     if( opt.force_ciphersuite[0] != DFL_FORCE_CIPHER )
         mbedtls_ssl_conf_ciphersuites( &conf, opt.force_ciphersuite );
+#endif /* !MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
 
 #if defined(MBEDTLS_ARC4_C)
     if( opt.arc4 != DFL_ARC4 )
         mbedtls_ssl_conf_arc4_support( &conf, opt.arc4 );
 #endif
 
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
     if( opt.version_suites != NULL )
     {
         mbedtls_ssl_conf_ciphersuites_for_version( &conf, version_suites[0],
@@ -2672,6 +2721,7 @@
                                           MBEDTLS_SSL_MAJOR_VERSION_3,
                                           MBEDTLS_SSL_MINOR_VERSION_3 );
     }
+#endif /* !MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
 
 #if !defined(MBEDTLS_SSL_CONF_ALLOW_LEGACY_RENEGOTIATION)
     if( opt.allow_legacy != DFL_ALLOW_LEGACY )
@@ -2803,12 +2853,14 @@
 #endif
 
 #if defined(MBEDTLS_ECP_C)
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_EC)
     if( opt.curves != NULL &&
         strcmp( opt.curves, "default" ) != 0 )
     {
         mbedtls_ssl_conf_curves( &conf, curve_list );
     }
-#endif
+#endif /* !MBEDTLS_SSL_CONF_SINGLE_EC */
+#endif /* MBEDTLS_ECP_C */
 
 #if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
     if( strlen( opt.psk ) != 0 && strlen( opt.psk_identity ) != 0 )
@@ -2842,11 +2894,16 @@
     }
 #endif
 
+#if !defined(MBEDTLS_SSL_CONF_MIN_MINOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MIN_MAJOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MAX_MINOR_VER) || \
+    !defined(MBEDTLS_SSL_CONF_MAX_MAJOR_VER)
     if( opt.min_version != DFL_MIN_VERSION )
         mbedtls_ssl_conf_min_version( &conf, MBEDTLS_SSL_MAJOR_VERSION_3, opt.min_version );
 
     if( opt.max_version != DFL_MIN_VERSION )
         mbedtls_ssl_conf_max_version( &conf, MBEDTLS_SSL_MAJOR_VERSION_3, opt.max_version );
+#endif
 
     if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
     {
@@ -2854,11 +2911,18 @@
         goto exit;
     }
 
+#if !defined(MBEDTLS_SSL_CONF_RECV) && \
+    !defined(MBEDTLS_SSL_CONF_SEND) && \
+    !defined(MBEDTLS_SSL_CONF_RECV_TIMEOUT)
     if( opt.nbio == 2 )
         mbedtls_ssl_set_bio( &ssl, &client_fd, my_send, my_recv, NULL );
     else
-        mbedtls_ssl_set_bio( &ssl, &client_fd, mbedtls_net_send, mbedtls_net_recv,
+        mbedtls_ssl_set_bio( &ssl, &client_fd,
+                             mbedtls_net_send, mbedtls_net_recv,
                              opt.nbio == 0 ? mbedtls_net_recv_timeout : NULL );
+#else
+     mbedtls_ssl_set_bio_ctx( &ssl, &client_fd );
+#endif
 
 #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
     if( opt.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
@@ -2879,8 +2943,13 @@
 #endif
 
 #if defined(MBEDTLS_TIMING_C)
+#if !defined(MBEDTLS_SSL_CONF_SET_TIMER) && \
+    !defined(MBEDTLS_SSL_CONF_GET_TIMER)
     mbedtls_ssl_set_timer_cb( &ssl, &timer, mbedtls_timing_set_delay,
                                             mbedtls_timing_get_delay );
+#else
+    mbedtls_ssl_set_timer_cb_ctx( &ssl, &timer );
+#endif
 #endif
 
     mbedtls_printf( " ok\n" );
@@ -3496,9 +3565,16 @@
 
 #if defined(MBEDTLS_TIMING_C)
             if( opt.nbio != 0 && opt.read_timeout != 0 )
+            {
+#if !defined(MBEDTLS_SSL_CONF_SET_TIMER) && \
+    !defined(MBEDTLS_SSL_CONF_GET_TIMER)
                 mbedtls_ssl_set_timer_cb( &ssl, &timer,
                                           mbedtls_timing_set_delay,
                                           mbedtls_timing_get_delay );
+#else
+                mbedtls_ssl_set_timer_cb_ctx( &ssl, &timer );
+#endif
+            }
 #endif /* MBEDTLS_TIMING_C */
         }
 
diff --git a/programs/x509/cert_app.c b/programs/x509/cert_app.c
index 3fc093e..0656ce7 100644
--- a/programs/x509/cert_app.c
+++ b/programs/x509/cert_app.c
@@ -117,6 +117,7 @@
     int permissive;             /* permissive parsing                   */
 } opt;
 
+#if defined(MBEDTLS_DEBUG_C)
 static void my_debug( void *ctx, int level,
                       const char *file, int line,
                       const char *str )
@@ -126,6 +127,7 @@
     mbedtls_fprintf( (FILE *) ctx, "%s:%04d: %s", file, line, str );
     fflush(  (FILE *) ctx  );
 }
+#endif /* MBEDTLS_DEBUG_C */
 
 static int my_verify( void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags )
 {
@@ -423,7 +425,9 @@
             mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_NONE );
 
         mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
+#if defined(MBEDTLS_DEBUG_C)
         mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
+#endif
 
         if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
         {
diff --git a/scripts/abi_check.py b/scripts/abi_check.py
index 502c7ae..533aaea 100755
--- a/scripts/abi_check.py
+++ b/scripts/abi_check.py
@@ -59,9 +59,7 @@
 
     @staticmethod
     def check_repo_path():
-        current_dir = os.path.realpath('.')
-        root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
-        if current_dir != root_dir:
+        if not all(os.path.isdir(d) for d in ["include", "library", "tests"]):
             raise Exception("Must be run from Mbed TLS root")
 
     def _setup_logger(self):
@@ -108,6 +106,12 @@
             stderr=subprocess.STDOUT
         )
         self.log.debug(worktree_output.decode("utf-8"))
+        version.commit = subprocess.check_output(
+            [self.git_command, "rev-parse", worktree_rev],
+            cwd=git_worktree_path,
+            stderr=subprocess.STDOUT
+        ).decode("ascii").rstrip()
+        self.log.debug("Commit is {}".format(version.commit))
         return git_worktree_path
 
     def _update_git_submodules(self, git_worktree_path, version):
@@ -163,6 +167,13 @@
                     os.path.join(root, file)
                 )
 
+    @staticmethod
+    def _pretty_revision(version):
+        if version.revision == version.commit:
+            return version.revision
+        else:
+            return "{} ({})".format(version.revision, version.commit)
+
     def _get_abi_dumps_from_shared_libraries(self, version):
         """Generate the ABI dumps for the specified git revision.
         The shared libraries must have been built and the module paths
@@ -177,7 +188,7 @@
                 "abi-dumper",
                 module_path,
                 "-o", output_path,
-                "-lver", version.revision
+                "-lver", self._pretty_revision(version),
             ]
             abi_dump_output = subprocess.check_output(
                 abi_dump_command,
@@ -222,70 +233,84 @@
                 if not problems.getchildren():
                     report.remove(problems)
 
+    def _abi_compliance_command(self, mbed_module, output_path):
+        """Build the command to run to analyze the library mbed_module.
+        The report will be placed in output_path."""
+        abi_compliance_command = [
+            "abi-compliance-checker",
+            "-l", mbed_module,
+            "-old", self.old_version.abi_dumps[mbed_module],
+            "-new", self.new_version.abi_dumps[mbed_module],
+            "-strict",
+            "-report-path", output_path,
+        ]
+        if self.skip_file:
+            abi_compliance_command += ["-skip-symbols", self.skip_file,
+                                       "-skip-types", self.skip_file]
+        if self.brief:
+            abi_compliance_command += ["-report-format", "xml",
+                                       "-stdout"]
+        return abi_compliance_command
+
+    def _is_library_compatible(self, mbed_module, compatibility_report):
+        """Test if the library mbed_module has remained compatible.
+        Append a message regarding compatibility to compatibility_report."""
+        output_path = os.path.join(
+            self.report_dir, "{}-{}-{}.html".format(
+                mbed_module, self.old_version.revision,
+                self.new_version.revision
+            )
+        )
+        try:
+            subprocess.check_output(
+                self._abi_compliance_command(mbed_module, output_path),
+                stderr=subprocess.STDOUT
+            )
+        except subprocess.CalledProcessError as err:
+            if err.returncode != 1:
+                raise err
+            if self.brief:
+                self.log.info(
+                    "Compatibility issues found for {}".format(mbed_module)
+                )
+                report_root = ET.fromstring(err.output.decode("utf-8"))
+                self._remove_extra_detail_from_report(report_root)
+                self.log.info(ET.tostring(report_root).decode("utf-8"))
+            else:
+                self.can_remove_report_dir = False
+                compatibility_report.append(
+                    "Compatibility issues found for {}, "
+                    "for details see {}".format(mbed_module, output_path)
+                )
+            return False
+        compatibility_report.append(
+            "No compatibility issues for {}".format(mbed_module)
+        )
+        if not (self.keep_all_reports or self.brief):
+            os.remove(output_path)
+        return True
+
     def get_abi_compatibility_report(self):
         """Generate a report of the differences between the reference ABI
         and the new ABI. ABI dumps from self.old_version and self.new_version
         must be available."""
-        compatibility_report = ""
+        compatibility_report = ["Checking evolution from {} to {}".format(
+            self._pretty_revision(self.old_version),
+            self._pretty_revision(self.new_version)
+        )]
         compliance_return_code = 0
         shared_modules = list(set(self.old_version.modules.keys()) &
                               set(self.new_version.modules.keys()))
         for mbed_module in shared_modules:
-            output_path = os.path.join(
-                self.report_dir, "{}-{}-{}.html".format(
-                    mbed_module, self.old_version.revision,
-                    self.new_version.revision
-                )
-            )
-            abi_compliance_command = [
-                "abi-compliance-checker",
-                "-l", mbed_module,
-                "-old", self.old_version.abi_dumps[mbed_module],
-                "-new", self.new_version.abi_dumps[mbed_module],
-                "-strict",
-                "-report-path", output_path,
-            ]
-            if self.skip_file:
-                abi_compliance_command += ["-skip-symbols", self.skip_file,
-                                           "-skip-types", self.skip_file]
-            if self.brief:
-                abi_compliance_command += ["-report-format", "xml",
-                                           "-stdout"]
-            try:
-                subprocess.check_output(
-                    abi_compliance_command,
-                    stderr=subprocess.STDOUT
-                )
-            except subprocess.CalledProcessError as err:
-                if err.returncode == 1:
-                    compliance_return_code = 1
-                    if self.brief:
-                        self.log.info(
-                            "Compatibility issues found for {}".format(mbed_module)
-                        )
-                        report_root = ET.fromstring(err.output.decode("utf-8"))
-                        self._remove_extra_detail_from_report(report_root)
-                        self.log.info(ET.tostring(report_root).decode("utf-8"))
-                    else:
-                        self.can_remove_report_dir = False
-                        compatibility_report += (
-                            "Compatibility issues found for {}, "
-                            "for details see {}\n".format(mbed_module, output_path)
-                        )
-                else:
-                    raise err
-            else:
-                compatibility_report += (
-                    "No compatibility issues for {}\n".format(mbed_module)
-                )
-                if not (self.keep_all_reports or self.brief):
-                    os.remove(output_path)
+            if not self._is_library_compatible(mbed_module,
+                                               compatibility_report):
+                compliance_return_code = 1
         for version in [self.old_version, self.new_version]:
             for mbed_module, mbed_module_dump in version.abi_dumps.items():
                 os.remove(mbed_module_dump)
         if self.can_remove_report_dir:
             os.rmdir(self.report_dir)
-        self.log.info(compatibility_report)
+        self.log.info("\n".join(compatibility_report))
         return compliance_return_code
 
     def check_for_abi_changes(self):
@@ -357,7 +382,9 @@
         )
         parser.add_argument(
             "-s", "--skip-file", type=str,
-            help="path to file containing symbols and types to skip"
+            help=("path to file containing symbols and types to skip "
+                  "(typically \"-s identifiers\" after running "
+                  "\"tests/scripts/list-identifiers.sh --internal\")")
         )
         parser.add_argument(
             "-b", "--brief", action="store_true",
@@ -371,6 +398,7 @@
             version="old",
             repository=abi_args.old_repo,
             revision=abi_args.old_rev,
+            commit=None,
             crypto_repository=abi_args.old_crypto_repo,
             crypto_revision=abi_args.old_crypto_rev,
             abi_dumps={},
@@ -380,6 +408,7 @@
             version="new",
             repository=abi_args.new_repo,
             revision=abi_args.new_rev,
+            commit=None,
             crypto_repository=abi_args.new_crypto_repo,
             crypto_revision=abi_args.new_crypto_rev,
             abi_dumps={},
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index f626b55..a77fe13 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -759,6 +759,39 @@
     if_build_succeeded env OPENSSL_CMD="$OPENSSL_NEXT" tests/compat.sh -e '^$' -f 'ARIA\|CHACHA'
 }
 
+component_test_hardcoded_ciphersuite_cmake_clang() {
+    msg "build: cmake, full config + MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE, clang" # ~ 50s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE
+    scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C
+    scripts/config.pl set MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE MBEDTLS_SUITE_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
+    CC=clang cmake -D LINK_WITH_PTHREAD=1 -D CMAKE_BUILD_TYPE:String=ASanDbg -D ENABLE_TESTING=On .
+    make
+
+    msg "test: main suites (full config + MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)" # ~ 5s
+    make test
+
+    msg "test: ssl-opt.sh default (full config + MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)" # ~ 5s
+    if_build_succeeded tests/ssl-opt.sh -f '^Default$\|^Default, DTLS$'
+}
+
+component_test_hardcoded_timer_callback_cmake_clang() {
+    msg "build: cmake, full config + MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE, clang" # ~ 50s
+    scripts/config.pl full
+    scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE
+    scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C
+    scripts/config.pl set MBEDTLS_SSL_CONF_GET_TIMER mbedtls_timing_get_delay
+    scripts/config.pl set MBEDTLS_SSL_CONF_SET_TIMER mbedtls_timing_set_delay
+    CC=clang cmake -D LINK_WITH_PTHREAD=1 -D CMAKE_BUILD_TYPE:String=ASanDbg -D ENABLE_TESTING=On .
+    make
+
+    msg "test: main suites (full config + MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)" # ~ 5s
+    make test
+
+    msg "test: ssl-opt.sh default (full config + MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)" # ~ 5s
+    if_build_succeeded tests/ssl-opt.sh -f '^Default$\|^Default, DTLS$'
+}
+
 component_build_deprecated () {
     msg "build: make, full config + DEPRECATED_WARNING, gcc -O" # ~ 30s
     scripts/config.pl full
diff --git a/tests/scripts/check-files.py b/tests/scripts/check-files.py
index feea36c..1c2e6ea 100755
--- a/tests/scripts/check-files.py
+++ b/tests/scripts/check-files.py
@@ -1,14 +1,12 @@
 #!/usr/bin/env python3
+
+# This file is part of Mbed TLS (https://tls.mbed.org)
+# Copyright (c) 2018, Arm Limited, All Rights Reserved
+
 """
-This file is part of Mbed TLS (https://tls.mbed.org)
-
-Copyright (c) 2018, Arm Limited, All Rights Reserved
-
-Purpose
-
 This script checks the current state of the source code for minor issues,
 including incorrect file permissions, presence of tabs, non-Unix line endings,
-trailing whitespace, presence of UTF-8 BOM, and TODO comments.
+trailing whitespace, and presence of UTF-8 BOM.
 Note: requires python 3, must be run from Mbed TLS root.
 """
 
@@ -170,19 +168,6 @@
             return True
         return False
 
-class TodoIssueTracker(LineIssueTracker):
-    """Track lines containing ``TODO``."""
-
-    heading = "TODO present:"
-    files_exemptions = frozenset([
-        os.path.basename(__file__),
-        "benchmark.c",
-        "pull_request_template.md",
-    ])
-
-    def issue_with_line(self, line, _filepath):
-        return b"todo" in line.lower()
-
 
 class IntegrityChecker(object):
     """Sanity-check files under the current directory."""
@@ -211,7 +196,6 @@
             TrailingWhitespaceIssueTracker(),
             TabIssueTracker(),
             MergeArtifactIssueTracker(),
-            TodoIssueTracker(),
         ]
 
     @staticmethod
@@ -257,15 +241,7 @@
 
 
 def run_main():
-    parser = argparse.ArgumentParser(
-        description=(
-            "This script checks the current state of the source code for "
-            "minor issues, including incorrect file permissions, "
-            "presence of tabs, non-Unix line endings, trailing whitespace, "
-            "presence of UTF-8 BOM, and TODO comments. "
-            "Note: requires python 3, must be run from Mbed TLS root."
-        )
-    )
+    parser = argparse.ArgumentParser(description=__doc__)
     parser.add_argument(
         "-l", "--log_file", type=str, help="path to optional output log",
     )
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 5f9e2ec..56db054 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -164,6 +164,12 @@
     fi
 }
 
+requires_ciphersuite_enabled() {
+    if [ -z "$($P_CLI --help | grep "$1")" ]; then
+        SKIP_NEXT="YES"
+    fi
+}
+
 get_config_value_or_default() {
     # This function uses the query_config command line option to query the
     # required Mbed TLS compile time configuration from the ssl_server2
@@ -557,6 +563,84 @@
     fi
 }
 
+check_cmdline_min_minor_version_compat() {
+    __VAL="$( get_config_value_or_default "MBEDTLS_SSL_CONF_MIN_MINOR_VER" )"
+    if [ ! -z "$__VAL" ]; then
+        extract_cmdline_argument "min_version"
+        if   [ "$__ARG" = "ssl3" ]   && [ "$__VAL" != "0" ]; then
+            SKIP_NEXT="YES";
+        elif [ "$__ARG" = "tls1" ]   && [ "$__VAL" != "1" ]; then
+            SKIP_NEXT="YES"
+        elif [ "$__ARG" = "tls1_1" ] && [ "$__VAL" != "2" ]; then
+            SKIP_NEXT="YES"
+        elif [ "$__ARG" = "tls1_2" ] && [ "$__VAL" != "3" ]; then
+            SKIP_NEXT="YES"
+        fi
+    fi
+}
+
+check_cmdline_max_minor_version_compat() {
+    __VAL="$( get_config_value_or_default "MBEDTLS_SSL_CONF_MAX_MINOR_VER" )"
+    if [ ! -z "$__VAL" ]; then
+        extract_cmdline_argument "max_version"
+        if   [ "$__ARG" = "ssl3" ]   && [ "$__VAL" != "0" ]; then
+            SKIP_NEXT="YES";
+        elif [ "$__ARG" = "tls1" ]   && [ "$__VAL" != "1" ]; then
+            SKIP_NEXT="YES"
+        elif [ "$__ARG" = "tls1_1" ] && [ "$__VAL" != "2" ]; then
+            SKIP_NEXT="YES"
+        elif [ "$__ARG" = "tls1_2" ] && [ "$__VAL" != "3" ]; then
+            SKIP_NEXT="YES"
+        fi
+    fi
+}
+
+check_cmdline_force_version_compat() {
+    __VAL_MAX="$( get_config_value_or_default "MBEDTLS_SSL_CONF_MAX_MINOR_VER" )"
+    __VAL_MIN="$( get_config_value_or_default "MBEDTLS_SSL_CONF_MIN_MINOR_VER" )"
+    if [ ! -z "$__VAL_MIN" ]; then
+
+        # SSL cli/srv cmd line
+
+        extract_cmdline_argument "force_version"
+        if   [ "$__ARG" = "ssl3" ] && \
+                 ( [ "$__VAL_MIN" != "0" ] || [ "$__VAL_MAX" != "0" ] ); then
+            SKIP_NEXT="YES";
+        elif  [ "$__ARG" = "tls1" ] && \
+                 ( [ "$__VAL_MIN" != "1" ] || [ "$__VAL_MAX" != "1" ] ); then
+            SKIP_NEXT="YES"
+        elif ( [ "$__ARG" = "tls1_1" ] || [ "$__ARG" = "dtls1" ] ) && \
+                 ( [ "$__VAL_MIN" != "2" ] || [ "$__VAL_MAX" != "2" ] ); then
+            SKIP_NEXT="YES"
+        elif ( [ "$__ARG" = "tls1_2" ] || [ "$__ARG" = "dtls1_2" ] ) && \
+                  ( [ "$__VAL_MIN" != "3" ] || [ "$__VAL_MAX" != "3" ] ); then
+            echo "FORCE SKIP"
+            SKIP_NEXT="YES"
+        fi
+
+        # OpenSSL cmd line
+
+        if echo "$CMD" | grep -e "-tls1\($\|[^_]\)" > /dev/null; then
+            if [ "$__VAL_MIN" != "1" ] || [ "$__VAL_MAX" != "1" ]; then
+                SKIP_NEXT="YES"
+            fi
+        fi
+
+        if echo "$CMD" | grep -e "-\(dtls1\($\|[^_]\)\|tls1_1\)" > /dev/null; then
+            if [ "$__VAL_MIN" != "2" ] || [ "$__VAL_MAX" != "2" ]; then
+                SKIP_NEXT="YES"
+            fi
+        fi
+
+        if echo "$CMD" | grep -e "-\(dtls1_2\($\|[^_]\)\|tls1_2\)" > /dev/null; then
+            if [ "$__VAL_MIN" != "3" ] || [ "$__VAL_MAX" != "3" ]; then
+                SKIP_NEXT="YES"
+            fi
+        fi
+
+    fi
+}
+
 # Go through all options that can be hardcoded at compile-time and
 # detect whether the command line configures them in a conflicting
 # way. If so, skip the test. Otherwise, remove the corresponding
@@ -586,6 +670,11 @@
 
     # Legacy renegotiation
     check_cmdline_legacy_renego_compat
+
+    # Version configuration
+    check_cmdline_min_minor_version_compat
+    check_cmdline_max_minor_version_compat
+    check_cmdline_force_version_compat
 }
 
 # Usage: run_test name [-p proxy_cmd] srv_cmd cli_cmd cli_exit [option [...]]
@@ -952,11 +1041,25 @@
 
 # Basic test
 
+run_test    "Default" \
+            "$P_SRV debug_level=3" \
+            "$P_CLI" \
+            0
+
+run_test    "Default, DTLS" \
+            "$P_SRV dtls=1" \
+            "$P_CLI dtls=1" \
+            0
+
 # Checks that:
 # - things work with all ciphersuites active (used with config-full in all.sh)
 # - the expected (highest security) parameters are selected
 #   ("signature_algorithm ext: 6" means SHA-512 (highest common hash))
-run_test    "Default" \
+requires_ciphersuite_enabled "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256"
+requires_config_enabled MBEDTLS_SHA512_C
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+requires_config_enabled MBEDTLS_ECP_DP_SECP521R1_ENABLED
+run_test    "Default, choose highest security suite and hash" \
             "$P_SRV debug_level=3" \
             "$P_CLI" \
             0 \
@@ -967,12 +1070,18 @@
             -S "error" \
             -C "error"
 
-run_test    "Default, DTLS" \
-            "$P_SRV dtls=1" \
+requires_ciphersuite_enabled "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256"
+requires_config_enabled MBEDTLS_SHA512_C
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+requires_config_enabled MBEDTLS_ECP_DP_SECP521R1_ENABLED
+run_test    "Default, choose highest security suite and hash, DTLS" \
+            "$P_SRV debug_level=3 dtls=1" \
             "$P_CLI dtls=1" \
             0 \
             -s "Protocol is DTLSv1.2" \
-            -s "Ciphersuite is TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256"
+            -s "Ciphersuite is TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256" \
+            -s "client hello v3, signature_algorithm ext: 6" \
+            -s "ECDHE curve: secp521r1"
 
 # Test current time in ServerHello
 requires_config_enabled MBEDTLS_HAVE_TIME
@@ -3448,7 +3557,6 @@
              key_file=data_files/server6.key \
              force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384" \
             0 \
-            -c "Supported Signature Algorithm found: 4," \
             -c "Supported Signature Algorithm found: 5,"
 
 run_test    "Authentication: client SHA384, server required" \
@@ -3457,7 +3565,6 @@
              key_file=data_files/server6.key \
              force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256" \
             0 \
-            -c "Supported Signature Algorithm found: 4," \
             -c "Supported Signature Algorithm found: 5,"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_SSL3
diff --git a/tests/suites/helpers.function b/tests/suites/helpers.function
index a33cc03..ccd4d42 100644
--- a/tests/suites/helpers.function
+++ b/tests/suites/helpers.function
@@ -108,6 +108,21 @@
        }                                                    \
     } while( 0 )
 
+/**
+ * \brief   This macro tests the expression passed to it and skips the
+ *          running test if it doesn't evaluate to 'true'.
+ *
+ * \param   TEST    The test expression to be tested.
+ */
+#define TEST_ASSUME( TEST )                         \
+    do {                                            \
+        if( ! (TEST) )                              \
+        {                                           \
+            test_skip( #TEST, __LINE__, __FILE__ ); \
+            goto exit;                              \
+        }                                           \
+    } while( 0 )
+
 #if defined(MBEDTLS_CHECK_PARAMS) && !defined(MBEDTLS_PARAM_FAILED_ALT)
 /**
  * \brief   This macro tests the statement passed to it as a test step or
@@ -241,10 +256,17 @@
 /*----------------------------------------------------------------------------*/
 /* Global variables */
 
+typedef enum
+{
+    TEST_RESULT_SUCCESS = 0,
+    TEST_RESULT_FAILED,
+    TEST_RESULT_SKIPPED
+} test_result_t;
+
 static struct
 {
     paramfail_test_state_t paramfail_test_state;
-    int failed;
+    test_result_t result;
     const char *test;
     const char *filename;
     int line_no;
@@ -280,7 +302,15 @@
 
 void test_fail( const char *test, int line_no, const char* filename )
 {
-    test_info.failed = 1;
+    test_info.result = TEST_RESULT_FAILED;
+    test_info.test = test;
+    test_info.line_no = line_no;
+    test_info.filename = filename;
+}
+
+void test_skip( const char *test, int line_no, const char* filename )
+{
+    test_info.result = TEST_RESULT_SKIPPED;
     test_info.test = test;
     test_info.line_no = line_no;
     test_info.filename = filename;
@@ -319,7 +349,7 @@
         /* Record the location of the failure, but not as a failure yet, in case
          * it was part of the test */
         test_fail( failure_condition, line, file );
-        test_info.failed = 0;
+        test_info.result = TEST_RESULT_SUCCESS;
 
         longjmp( param_fail_jmp, 1 );
     }
diff --git a/tests/suites/host_test.function b/tests/suites/host_test.function
index fe6a2bc..0f98d23 100644
--- a/tests/suites/host_test.function
+++ b/tests/suites/host_test.function
@@ -498,7 +498,8 @@
 
             if( ( ret = get_line( file, buf, sizeof(buf) ) ) != 0 )
                 break;
-            mbedtls_fprintf( stdout, "%s%.66s", test_info.failed ? "\n" : "", buf );
+            mbedtls_fprintf( stdout, "%s%.66s",
+                    test_info.result == TEST_RESULT_FAILED ? "\n" : "", buf );
             mbedtls_fprintf( stdout, " " );
             for( i = strlen( buf ) + 1; i < 67; i++ )
                 mbedtls_fprintf( stdout, "." );
@@ -545,7 +546,7 @@
             // If there are no unmet dependencies execute the test
             if( unmet_dep_count == 0 )
             {
-                test_info.failed = 0;
+                test_info.result = TEST_RESULT_SUCCESS;
                 test_info.paramfail_test_state = PARAMFAIL_TESTSTATE_IDLE;
 
 #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
@@ -610,10 +611,15 @@
             }
             else if( ret == DISPATCH_TEST_SUCCESS )
             {
-                if( test_info.failed == 0 )
+                if( test_info.result == TEST_RESULT_SUCCESS )
                 {
                     mbedtls_fprintf( stdout, "PASS\n" );
                 }
+                else if( test_info.result == TEST_RESULT_SKIPPED )
+                {
+                    mbedtls_fprintf( stdout, "----\n" );
+                    total_skipped++;
+                }
                 else
                 {
                     total_errors++;
diff --git a/tests/suites/main_test.function b/tests/suites/main_test.function
index ca4783d..1f4180d 100644
--- a/tests/suites/main_test.function
+++ b/tests/suites/main_test.function
@@ -156,7 +156,7 @@
     else
     {
         /* Unexpected parameter validation error */
-        test_info.failed = 1;
+        test_info.result = TEST_RESULT_FAILED;
     }
 
     memset( param_fail_jmp, 0, sizeof(jmp_buf) );
diff --git a/tests/suites/test_suite_nist_kw.function b/tests/suites/test_suite_nist_kw.function
index f1acde9..9c34ea6 100644
--- a/tests/suites/test_suite_nist_kw.function
+++ b/tests/suites/test_suite_nist_kw.function
@@ -170,10 +170,6 @@
         TEST_ASSERT( ciphertext != NULL );
     }
 
-    memset( plaintext, 0, in_len );
-    memset( ciphertext, 0, output_len );
-
-
     TEST_ASSERT( mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES,
                                          key, 8 * sizeof( key ), 1 ) == 0 );
 
@@ -225,10 +221,6 @@
         TEST_ASSERT( ciphertext != NULL );
     }
 
-    memset( plaintext, 0, output_len );
-    memset( ciphertext, 0, in_len );
-
-
     TEST_ASSERT( mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES,
                                          key, 8 * sizeof( key ), 0 ) == 0 );
     unwrap_ret = mbedtls_nist_kw_unwrap( &ctx, mode, ciphertext, in_len,
diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function
index 8271b23..7d7845e 100644
--- a/tests/suites/test_suite_ssl.function
+++ b/tests/suites/test_suite_ssl.function
@@ -168,8 +168,12 @@
     ((void) etm);
 #endif
 
+#if !defined(MBEDTLS_SSL_CONF_FIXED_MINOR_VER)
     t_out->minor_ver = ver;
     t_in->minor_ver = ver;
+#else
+    ((void) ver);
+#endif
     t_out->ivlen = ivlen;
     t_in->ivlen = ivlen;
 
@@ -279,7 +283,9 @@
 #if defined(MBEDTLS_HAVE_TIME)
     session->start = mbedtls_time( NULL ) - 42;
 #endif
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
     session->ciphersuite = 0xabcd;
+#endif
     session->compression = 1;
     session->id_len = sizeof( session->id );
     memset( session->id, 66, session->id_len );
@@ -430,6 +436,11 @@
     mbedtls_ssl_init( &ssl );
     mbedtls_ssl_transform_init( &t0 );
     mbedtls_ssl_transform_init( &t1 );
+
+#if defined(MBEDTLS_SSL_CONF_FIXED_MINOR_VER)
+    TEST_ASSUME( ver == MBEDTLS_SSL_CONF_FIXED_MINOR_VER );
+#endif
+
     TEST_ASSERT( build_transforms( &t0, &t1, cipher_type, hash_id,
                                    etm, tag_mode, ver,
                                    (size_t) cid0_len,
@@ -571,6 +582,10 @@
                                    (size_t) cid0_len,
                                    (size_t) cid1_len ) == 0 );
 
+#if defined(MBEDTLS_SSL_CONF_FIXED_MINOR_VER)
+    TEST_ASSUME( ver == MBEDTLS_SSL_CONF_FIXED_MINOR_VER );
+#endif
+
     TEST_ASSERT( ( buf = mbedtls_calloc( 1, buflen ) ) != NULL );
 
     for( mode=1; mode <= 3; mode++ )
@@ -698,7 +713,9 @@
 #if defined(MBEDTLS_HAVE_TIME)
     TEST_ASSERT( original.start == restored.start );
 #endif
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
     TEST_ASSERT( original.ciphersuite == restored.ciphersuite );
+#endif
     TEST_ASSERT( original.compression == restored.compression );
     TEST_ASSERT( original.id_len == restored.id_len );
     TEST_ASSERT( memcmp( original.id,