Allow hardcoding single signature hash at compile-time

This commit introduces the option MBEDTLS_SSL_CONF_SINGLE_HASH
which can be used to register a single supported signature hash
algorithm at compile time. It replaces the runtime configuration
API mbedtls_ssl_conf_sig_hashes() which allows to register a _list_
of supported signature hash algorithms.

In contrast to other options used to hardcode configuration options,
MBEDTLS_SSL_CONF_SINGLE_HASH isn't a numeric option, but instead it's
only relevant if it's defined or not. To actually set the single
supported hash algorithm that should be supported, numeric options

MBEDTLS_SSL_CONF_SINGLE_HASH_TLS_ID
MBEDTLS_SSL_CONF_SINGLE_HASH_MD_ID

must both be defined and provide the TLS ID and the Mbed TLS internal
ID and the chosen hash algorithm, respectively.
diff --git a/configs/baremetal.h b/configs/baremetal.h
index a88f8ac..aadbd09 100644
--- a/configs/baremetal.h
+++ b/configs/baremetal.h
@@ -60,6 +60,9 @@
 #define MBEDTLS_SSL_CONF_SINGLE_EC
 #define MBEDTLS_SSL_CONF_SINGLE_EC_GRP_ID MBEDTLS_ECP_DP_SECP256R1
 #define MBEDTLS_SSL_CONF_SINGLE_EC_TLS_ID 23
+#define MBEDTLS_SSL_CONF_SINGLE_SIG_HASH
+#define MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_MD_ID MBEDTLS_MD_SHA256
+#define MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_TLS_ID MBEDTLS_SSL_HASH_SHA256
 
 /* Key exchanges */
 #define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index 93831b7..576349f 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -93,6 +93,12 @@
 #error "MBEDTLS_SSL_CONF_SINGLE_EC defined, but not all prerequesites"
 #endif
 
+#if defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH) &&           \
+    ( !defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_MD_ID) || \
+      !defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_TLS_ID) )
+#error "MBEDTLS_SSL_CONF_SINGLE_SIG_HASH defined, but not all prerequesites"
+#endif
+
 #if defined(MBEDTLS_USE_TINYCRYPT) && defined(MBEDTLS_NO_64BIT_MULTIPLICATION)
 #error "MBEDTLS_USE_TINYCRYPT defined, but it cannot be defined with MBEDTLS_NO_64BIT_MULTIPLICATION"
 #endif
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index 5b17238..65819ca 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -3685,6 +3685,34 @@
 //#define MBEDTLS_SSL_CONF_SINGLE_EC_TLS_ID
 //#define MBEDTLS_SSL_CONF_SINGLE_EC_GRP_ID
 
+/* Enable support a single signature hash algorithm
+ * at compile-time, at the benefit of code-size.
+ *
+ * On highly constrained systems which large control
+ * over the configuration of the connection endpoints,
+ * this option can be used to hardcode the choice of
+ * hash algorithm to be used for signatures in the
+ * ServerKeyExchange and CertificateVerify messages.
+ *
+ * If this is set, you must also define the following:
+ * - MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_MD_ID
+ *   This must resolve to the Mbed TLS hash ID for the hash
+ *   algorithm to use (e.g. MBEDTLS_MD_SHA256). See
+ *   ::mbedtls_md_type_t in mbedtls/md.h for a complete
+ *   list of supported hash algorithm identifiers.
+ * - MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_TLS_ID
+ *   This must resolve to the TLS identifier for the hash
+ *   algorithm to use. See
+ *   https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+ *   for a list of the supported identifiers.
+ *
+ * If defined, this option overwrites the effect of the
+ * runtime configuration API mbedtls_ssl_conf_sig_hashes().
+ */
+//#define MBEDTLS_SSL_CONF_SINGLE_SIG_HASH
+//#define MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_MD_ID
+//#define MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_TLS_ID
+
 /* \} SECTION: Compile-time SSL configuration */
 
 /* Target and application specific configurations
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 0f9ab0e..a41182c 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -1078,7 +1078,9 @@
 #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
 
 #if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED)
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH)
     const int *sig_hashes;          /*!< allowed signature hashes           */
+#endif /* !MBEDTLS_SSL_CONF_SINGLE_SIG_HASH */
 #endif
 
 #if defined(MBEDTLS_ECP_C)
@@ -2863,6 +2865,10 @@
  * \note           This list should be ordered by decreasing preference
  *                 (preferred hash first).
  *
+ * \note           On highly constrained systems, the support for a single
+ *                 fixed signature hash algorithm can be configured at compile
+ *                 time through the option MBEDTLS_SSL_CONF_SINGLE_SIG_HASH.
+ *
  * \param conf     SSL configuration
  * \param hashes   Ordered list of allowed signature hashes,
  *                 terminated by \c MBEDTLS_MD_NONE.
diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h
index 29729d4..b8875ab 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -1676,6 +1676,8 @@
 
 #endif /* MBEDTLS_SSL_CONF_SINGLE_EC */
 
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH)
+
 #define MBEDTLS_SSL_BEGIN_FOR_EACH_SIG_HASH( MD_VAR )    \
     {                                                                   \
         int const *__md;                                                \
@@ -1701,4 +1703,25 @@
         }                                                               \
     }
 
+#else /* !MBEDTLS_SSL_CONF_SINGLE_SIG_HASH */
+
+#define MBEDTLS_SSL_BEGIN_FOR_EACH_SIG_HASH( MD_VAR )                   \
+    {                                                                   \
+        mbedtls_md_type_t MD_VAR = MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_MD_ID; \
+        ((void) ssl);
+
+#define MBEDTLS_SSL_END_FOR_EACH_SIG_HASH                               \
+    }
+
+#define MBEDTLS_SSL_BEGIN_FOR_EACH_SIG_HASH_TLS( HASH_VAR )                \
+    {                                                                      \
+        unsigned char HASH_VAR = MBEDTLS_SSL_CONF_SINGLE_SIG_HASH_TLS_ID;  \
+        ((void) ssl);
+
+
+#define MBEDTLS_SSL_END_FOR_EACH_SIG_HASH_TLS                           \
+    }
+
+#endif /* MBEDTLS_SSL_CONF_SINGLE_SIG_HASH */
+
 #endif /* ssl_internal.h */
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 9359be6..78a15fe 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -8630,7 +8630,12 @@
 void mbedtls_ssl_conf_sig_hashes( mbedtls_ssl_config *conf,
                                   const int *hashes )
 {
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH)
     conf->sig_hashes = hashes;
+#else
+    ((void) conf);
+    ((void) hashes);
+#endif /* MBEDTLS_SSL_CONF_SINGLE_SIG_HASH */
 }
 #endif /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */
 
@@ -10839,6 +10844,7 @@
 }
 
 #if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED)
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH)
 static int ssl_preset_default_hashes[] = {
 #if defined(MBEDTLS_SHA512_C)
     MBEDTLS_MD_SHA512,
@@ -10854,6 +10860,7 @@
     MBEDTLS_MD_NONE
 };
 #endif
+#endif
 
 #if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
 static int ssl_preset_suiteb_ciphersuites[] = {
@@ -10864,12 +10871,14 @@
 #endif /* !MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE */
 
 #if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED)
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH)
 static int ssl_preset_suiteb_hashes[] = {
     MBEDTLS_MD_SHA256,
     MBEDTLS_MD_SHA384,
     MBEDTLS_MD_NONE
 };
 #endif
+#endif
 
 #if defined(MBEDTLS_ECP_C) && !defined(MBEDTLS_SSL_CONF_SINGLE_EC)
 static mbedtls_ecp_group_id ssl_preset_suiteb_curves[] = {
@@ -11018,8 +11027,10 @@
 #endif
 
 #if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED)
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH)
             conf->sig_hashes = ssl_preset_suiteb_hashes;
 #endif
+#endif
 
 #if defined(MBEDTLS_ECP_C)
 #if !defined(MBEDTLS_SSL_CONF_SINGLE_EC)
@@ -11068,8 +11079,10 @@
 #endif
 
 #if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED)
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_SIG_HASH)
             conf->sig_hashes = ssl_preset_default_hashes;
 #endif
+#endif
 
 #if defined(MBEDTLS_ECP_C)
 #if !defined(MBEDTLS_SSL_CONF_SINGLE_EC)
@@ -11308,9 +11321,6 @@
 int mbedtls_ssl_check_sig_hash( const mbedtls_ssl_context *ssl,
                                 mbedtls_md_type_t md )
 {
-    if( ssl->conf->sig_hashes == NULL )
-        return( -1 );
-
     MBEDTLS_SSL_BEGIN_FOR_EACH_SIG_HASH( md_alg )
     if( md_alg == md )
         return( 0 );
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 87454b2..bb84207 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -569,6 +569,7 @@
     return( 0 );
 }
 
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_HASH)
 static int ssl_sig_hashes_for_test[] = {
 #if defined(MBEDTLS_SHA512_C)
     MBEDTLS_MD_SHA512,
@@ -584,6 +585,7 @@
 #endif
     MBEDTLS_MD_NONE
 };
+#endif /* !MBEDTLS_SSL_CONF_SINGLE_HASH */
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
 /*
@@ -1693,7 +1695,9 @@
     {
         crt_profile_for_test.allowed_mds |= MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 );
         mbedtls_ssl_conf_cert_profile( &conf, &crt_profile_for_test );
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_HASH)
         mbedtls_ssl_conf_sig_hashes( &conf, ssl_sig_hashes_for_test );
+#endif
     }
 
     mbedtls_ssl_conf_verify( &conf, my_verify, NULL );
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 9cca9c4..42b9773 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -1000,7 +1000,8 @@
 }
 #endif
 
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_X509_CRT_PARSE_C) && \
+    !defined(MBEDTLS_SSL_CONF_SINGLE_HASH)
 static int ssl_sig_hashes_for_test[] = {
 #if defined(MBEDTLS_SHA512_C)
     MBEDTLS_MD_SHA512,
@@ -1016,7 +1017,7 @@
 #endif
     MBEDTLS_MD_NONE
 };
-#endif /* MBEDTLS_X509_CRT_PARSE_C */
+#endif /* MBEDTLS_X509_CRT_PARSE_C && !defined(MBEDTLS_SSL_CONF_SINGLE_HASH) */
 
 /** Return true if \p ret is a status code indicating that there is an
  * operation in progress on an SSL connection, and false if it indicates
@@ -2516,7 +2517,9 @@
     {
         crt_profile_for_test.allowed_mds |= MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 );
         mbedtls_ssl_conf_cert_profile( &conf, &crt_profile_for_test );
+#if !defined(MBEDTLS_SSL_CONF_SINGLE_HASH)
         mbedtls_ssl_conf_sig_hashes( &conf, ssl_sig_hashes_for_test );
+#endif
     }
 #endif /* MBEDTLS_X509_CRT_PARSE_C */