Merge remote-tracking branch 'origin/pr/606' into baremetal
diff --git a/configs/baremetal.h b/configs/baremetal.h
index ee514b4..2e92e76 100644
--- a/configs/baremetal.h
+++ b/configs/baremetal.h
@@ -60,6 +60,7 @@
 /* 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
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index 91d2550..8290c51 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -3641,6 +3641,17 @@
 //#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
+
 /* \} SECTION: Compile-time SSL configuration */
 
 /* Target and application specific configurations
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index ad60e82..0a1d9d5 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"
@@ -402,6 +400,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 +923,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,7 +974,9 @@
      * Pointers
      */
 
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
     const int *ciphersuite_list[4]; /*!< allowed ciphersuites per version   */
+#endif /* MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
 
     /** Callback for printing debug output                                  */
     void (*f_dbg)(void *, int, const char *, int, const char *);
@@ -2390,6 +2470,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.
@@ -2402,11 +2483,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
@@ -2455,29 +2568,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
@@ -3915,6 +4005,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 151589f..8a51577 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -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        */
 
@@ -556,6 +558,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;
 
 /*
@@ -918,7 +935,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 );
@@ -978,7 +995,7 @@
  * 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 */
@@ -1430,4 +1447,41 @@
 }
 #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 */
+
 #endif /* ssl_internal.h */
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 a050adb..d45f3d3 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -780,34 +780,45 @@
  *
  * \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 );
@@ -820,8 +831,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;
@@ -961,24 +970,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,
+                                            ssl->minor_ver,
+                                            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 )
+        {
             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)
@@ -986,9 +996,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 ) );
 
@@ -1428,8 +1441,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 );
@@ -1613,7 +1627,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" ) );
 
@@ -1789,16 +1805,18 @@
     /*
      * 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 );
         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 );
@@ -1817,7 +1835,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 )
@@ -1846,7 +1864,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 );
@@ -1861,37 +1881,39 @@
     /*
      * Perform cipher suite validation in same way as in ssl_write_client_hello.
      */
-    i = 0;
-    while( 1 )
+    MBEDTLS_SSL_BEGIN_FOR_EACH_CIPHERSUITE( ssl,
+                                            ssl->minor_ver,
+                                            ciphersuite_info )
     {
-        if( ssl->conf->ciphersuite_list[ssl->minor_ver][i] == 0 )
+        if( ssl_validate_ciphersuite( ciphersuite_info, ssl,
+                                      ssl->conf->min_minor_ver,
+                                      ssl->conf->max_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 );
+            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_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                                    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 &&
+    if( mbedtls_ssl_suite_get_key_exchange( server_suite_info ) ==
+          MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA &&
         ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
     {
         ssl->handshake->ecrs_enabled = 1;
@@ -2555,14 +2577,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++;
@@ -2574,8 +2597,10 @@
 
 #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 )
         {
@@ -2622,8 +2647,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 */
@@ -2650,10 +2677,14 @@
     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 )
         {
@@ -2667,16 +2698,22 @@
 
 #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 )
         {
@@ -2692,9 +2729,12 @@
 #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 )
         {
@@ -2709,7 +2749,8 @@
           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 );
@@ -2922,8 +2963,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" ) );
 
@@ -2944,8 +2985,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" ) );
 
@@ -3145,13 +3186,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
@@ -3195,10 +3236,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
@@ -3296,14 +3341,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 );
@@ -3311,7 +3358,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)
@@ -3342,7 +3390,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 )
         {
             /*
              * ClientECDiffieHellmanPublic public;
@@ -3368,7 +3417,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 );
@@ -3377,7 +3426,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 )
@@ -3386,7 +3436,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 )
     {
         i = 4;
 
@@ -3438,8 +3489,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" ) );
@@ -3464,8 +3515,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;
@@ -3570,7 +3621,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;
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index 4fab4ed..e743eff 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -759,9 +759,8 @@
  * 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,
                           mbedtls_ecp_group_id const *acceptable_ec_grp_ids )
-
 {
     mbedtls_ssl_key_cert *cur, *list, *fallback = NULL;
     mbedtls_pk_type_t pk_alg =
@@ -919,28 +918,20 @@
  * 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,
-                           mbedtls_ecp_group_id const *acceptable_ec_grp_ids )
+static int ssl_ciphersuite_is_match( mbedtls_ssl_context *ssl,
+                            mbedtls_ssl_ciphersuite_handle_t suite_info,
+                            mbedtls_ecp_group_id const *acceptable_ec_grp_ids )
 {
-    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 ) > ssl->minor_ver ||
+        mbedtls_ssl_suite_get_max_minor_ver( suite_info ) < ssl->minor_ver )
     {
         MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: version" ) );
         return( 0 );
@@ -948,13 +939,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 +956,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 "
@@ -1031,8 +1026,7 @@
     ((void) acceptable_ec_grp_ids);
 #endif
 
-    *ciphersuite_info = suite_info;
-    return( 0 );
+    return( 1 );
 }
 
 #if defined(MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO)
@@ -1043,8 +1037,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" ) );
 
@@ -1234,33 +1229,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,                    \
+                                                ssl->minor_ver,         \
+                                                cur_info )
         {
+#else
+    MBEDTLS_SSL_BEGIN_FOR_EACH_CIPHERSUITE( ssl,                \
+                                            ssl->minor_ver,     \
+                                            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,
-                                               NULL ) ) )
+            if( ssl_ciphersuite_is_match( ssl, cur_info, NULL ) )
             {
-                return( ret );
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
+                ciphersuite_info = cur_info;
+#endif
+                goto have_ciphersuite_v2;
             }
 
-            if( ciphersuite_info != NULL )
-                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 )
     {
@@ -1275,10 +1287,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
@@ -1322,8 +1340,10 @@
     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;
 
 #if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \
@@ -2128,32 +2148,49 @@
      * 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,                    \
+                                                ssl->minor_ver,         \
+                                                cur_info )
         {
-            if( p[0] != ( ( ciphersuites[i] >> 8 ) & 0xFF ) ||
-                p[1] != ( ( ciphersuites[i]      ) & 0xFF ) )
+#else
+    MBEDTLS_SSL_BEGIN_FOR_EACH_CIPHERSUITE( ssl,                \
+                                            ssl->minor_ver,     \
+                                            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,
-                                               acceptable_ec_grp_ids ) ) != 0 )
+            if( ssl_ciphersuite_is_match( ssl, cur_info,
+                                          acceptable_ec_grp_ids) )
             {
-                return( ret );
-            }
-
-            if( ciphersuite_info != NULL )
+#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 )
     {
@@ -2172,10 +2209,16 @@
     }
 
 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++;
 
@@ -2190,7 +2233,8 @@
     defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED)
     if( ssl->minor_ver == 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,
@@ -2290,7 +2334,8 @@
                                             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 ||
@@ -2306,9 +2351,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;
@@ -2491,9 +2544,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" ) );
 
@@ -2637,6 +2693,7 @@
     mbedtls_time_t t;
 #endif
     int ret;
+    int ciphersuite;
     size_t olen, ext_len = 0, n;
     unsigned char *buf, *p;
 
@@ -2786,12 +2843,13 @@
     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 ) );
 
@@ -2840,7 +2898,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;
@@ -2884,8 +2943,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" ) );
 
@@ -2903,8 +2962,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;
@@ -3134,8 +3193,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)
@@ -3160,7 +3219,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;
@@ -3188,8 +3248,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;
@@ -3353,7 +3413,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;
@@ -3495,8 +3556,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" ) );
@@ -3939,18 +4000,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
@@ -3982,7 +4042,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 )
         {
@@ -4015,10 +4076,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 )
@@ -4050,7 +4115,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 )
         {
@@ -4065,7 +4131,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 );
@@ -4074,7 +4140,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 )
@@ -4102,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 );
@@ -4111,7 +4178,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 )
         {
@@ -4131,7 +4199,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 );
@@ -4140,7 +4208,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 )
         {
@@ -4159,7 +4228,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 );
@@ -4168,7 +4237,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 )
         {
@@ -4179,7 +4249,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 );
@@ -4222,8 +4293,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" ) );
 
@@ -4249,8 +4320,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" ) );
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 84c78c4..e63c688 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -801,7 +801,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;
 
@@ -823,26 +823,28 @@
      * 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 );
     }
 
@@ -899,8 +901,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
@@ -1338,15 +1340,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 );
+                            ssl->minor_ver,
+                            mbedtls_ssl_suite_get_mac( ciphersuite_info ) );
     if( ret != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, "ssl_set_handshake_prfs", ret );
@@ -1376,24 +1378,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,
+                  ssl->minor_ver,
+                  mbedtls_ssl_conf_get_endpoint( ssl->conf ),
+                  ssl );
     if( ret != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, "ssl_populate_transform", ret );
@@ -6070,7 +6072,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" ) );
 
@@ -6087,7 +6090,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" ) );
 
@@ -6110,7 +6114,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" ) );
 
@@ -6474,8 +6479,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 );
@@ -6483,8 +6488,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 )
         {
@@ -6506,8 +6514,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;
 
@@ -6973,7 +6981,7 @@
 }
 
 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);
 
@@ -6985,12 +6993,12 @@
 #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
@@ -8315,6 +8323,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 )
 {
@@ -8336,6 +8345,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,
@@ -8958,10 +8968,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 )
@@ -9383,8 +9396,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 );
 
@@ -9522,6 +9537,7 @@
 {
     const unsigned char *p = buf;
     const unsigned char * const end = buf + len;
+    int ciphersuite;
 #if defined(MBEDTLS_HAVE_TIME)
     uint64_t start;
 #endif
@@ -9568,12 +9584,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++;
@@ -10795,11 +10822,13 @@
 };
 #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)
 static int ssl_preset_suiteb_hashes[] = {
@@ -10935,11 +10964,13 @@
             conf->max_major_ver = MBEDTLS_SSL_MAX_MAJOR_VERSION;
             conf->max_minor_ver = MBEDTLS_SSL_MAX_MINOR_VERSION;
 
+#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;
@@ -10974,11 +11005,13 @@
                 conf->min_minor_ver = MBEDTLS_SSL_MINOR_VERSION_2;
 #endif
 
+#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;
@@ -11242,7 +11275,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 )
 {
@@ -11266,7 +11299,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:
diff --git a/programs/ssl/query_config.c b/programs/ssl/query_config.c
index cda71fd..574d4d7 100644
--- a/programs/ssl/query_config.c
+++ b/programs/ssl/query_config.c
@@ -2770,6 +2770,14 @@
     }
 #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 the symbol is not found, return an error */
     return( 1 );
 }
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index c63b445..d9cfa25 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"
@@ -1296,19 +1297,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;
@@ -1318,13 +1319,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 )
@@ -1332,7 +1333,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 )
             {
@@ -1787,8 +1788,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 )
diff --git a/programs/ssl/ssl_mail_client.c b/programs/ssl/ssl_mail_client.c
index 5880468..63a3a2d 100644
--- a/programs/ssl/ssl_mail_client.c
+++ b/programs/ssl/ssl_mail_client.c
@@ -621,8 +621,10 @@
     mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
     mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
 
+#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_server2.c b/programs/ssl/ssl_server2.c
index 876a7a0..deaee9a 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"
@@ -2018,19 +2019,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;
@@ -2040,13 +2041,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 )
@@ -2054,7 +2055,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 )
             {
@@ -2661,14 +2662,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],
@@ -2684,6 +2688,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 )
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index f626b55..8c53c67 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -759,6 +759,21 @@
     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 # too slow for tests
+    scripts/config.pl set MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE MBEDTLS_SUITE_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
+    CC=clang cmake -D CMAKE_BUILD_TYPE:String=Check -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/ssl-opt.sh b/tests/ssl-opt.sh
index 5f9e2ec..553ece4 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
@@ -952,11 +958,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 +987,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
diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function
index 8271b23..9707935 100644
--- a/tests/suites/test_suite_ssl.function
+++ b/tests/suites/test_suite_ssl.function
@@ -279,7 +279,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 );
@@ -698,7 +700,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,