Merge pull request #4595 from gilles-peskine-arm/alt-dummy-headers-3.0

Lighten and test constraints on context types in alternative implementations
diff --git a/ChangeLog.d/issue4398.txt b/ChangeLog.d/issue4398.txt
new file mode 100644
index 0000000..b7f2413
--- /dev/null
+++ b/ChangeLog.d/issue4398.txt
@@ -0,0 +1,3 @@
+API changes
+    * Replace MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE by a runtime
+      configuration function mbedtls_ssl_conf_preference_order(). Fixes #4398.
diff --git a/docs/3.0-migration-guide.d/turn_SSL_SRV_RESPECT_CLIENT_PREFERENCE_config_opt_to_runtime_opt.md b/docs/3.0-migration-guide.d/turn_SSL_SRV_RESPECT_CLIENT_PREFERENCE_config_opt_to_runtime_opt.md
new file mode 100644
index 0000000..6a6554d
--- /dev/null
+++ b/docs/3.0-migration-guide.d/turn_SSL_SRV_RESPECT_CLIENT_PREFERENCE_config_opt_to_runtime_opt.md
@@ -0,0 +1,14 @@
+Turn MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE configuration option into a runtime option
+--
+
+This change affects users who were enabling MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE
+option in the `config.h`
+
+This option has been removed and a new function with similar functionality has
+been introduced into the SSL API.
+
+This new function `mbedtls_ssl_conf_preference_order()` can be used to
+change the preferred order of ciphersuites on the server to those used on the client,
+e.g.: `mbedtls_ssl_conf_preference_order(ssl_config, MBEDTLS_SSL_SRV_CIPHERSUITE_ORDER_CLIENT)`
+has the same effect as enabling the removed option. The default state is to use
+the server order of suites.
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index 57783f8..16f8f8b 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -1472,16 +1472,6 @@
 #define MBEDTLS_SSL_RENEGOTIATION
 
 /**
- * \def MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE
- *
- * Pick the ciphersuite according to the client's preferences rather than ours
- * in the SSL Server module (MBEDTLS_SSL_SRV_C).
- *
- * Uncomment this macro to respect client's ciphersuite order
- */
-//#define MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE
-
-/**
  * \def MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
  *
  * Enable support for RFC 6066 max_fragment_length extension in SSL.
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 8f21a9a..b2f5c67 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -201,6 +201,9 @@
 #define MBEDTLS_SSL_DTLS_SRTP_MKI_UNSUPPORTED    0
 #define MBEDTLS_SSL_DTLS_SRTP_MKI_SUPPORTED      1
 
+#define MBEDTLS_SSL_SRV_CIPHERSUITE_ORDER_CLIENT  1
+#define MBEDTLS_SSL_SRV_CIPHERSUITE_ORDER_SERVER  0
+
 /*
  * Default range for DTLS retransmission timer value, in milliseconds.
  * RFC 6347 4.2.4.1 says from 1 second to 60 seconds.
@@ -1186,6 +1189,9 @@
 #if defined(MBEDTLS_SSL_SRV_C)
     unsigned int MBEDTLS_PRIVATE(cert_req_ca_list) : 1;  /*!< enable sending CA list in
                                           Certificate Request messages?     */
+    unsigned int respect_cli_pref : 1;  /*!< pick the ciphersuite according to
+                                          the client's preferences rather
+                                          than ours                         */
 #endif
 #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
     unsigned int MBEDTLS_PRIVATE(ignore_unexpected_cid) : 1; /*!< Determines whether DTLS
@@ -2493,9 +2499,12 @@
  *                      The ciphersuites array is not copied, and must remain
  *                      valid for the lifetime of the ssl_config.
  *
- *                      Note: The server uses its own preferences
- *                      over the preference of the client unless
- *                      MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE is defined!
+ *                      Note: By default, the server chooses its preferred
+ *                      ciphersuite among those that the client supports. If
+ *                      mbedtls_ssl_conf_preference_order() is called to prefer
+ *                      the client's preferences, the server instead chooses
+ *                      the client's preferred ciphersuite among those that
+ *                      the server supports.
  *
  * \param conf          SSL configuration
  * \param ciphersuites  0-terminated list of allowed ciphersuites
@@ -3293,6 +3302,19 @@
 int mbedtls_ssl_conf_max_frag_len( mbedtls_ssl_config *conf, unsigned char mfl_code );
 #endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
 
+#if defined(MBEDTLS_SSL_SRV_C)
+/**
+ * \brief          Pick the ciphersuites order according to the second parameter
+ *                 in the SSL Server module (MBEDTLS_SSL_SRV_C).
+ *                 (Default, if never called: MBEDTLS_SSL_SRV_CIPHERSUITE_ORDER_SERVER)
+ *
+ * \param conf     SSL configuration
+ * \param order    Server or client (MBEDTLS_SSL_SRV_CIPHERSUITE_ORDER_SERVER
+ *                                or MBEDTLS_SSL_SRV_CIPHERSUITE_ORDER_CLIENT)
+ */
+void mbedtls_ssl_conf_preference_order( mbedtls_ssl_config *conf, int order );
+#endif /* MBEDTLS_SSL_SRV_C */
+
 #if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
 /**
  * \brief          Activate negotiation of truncated HMAC
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index d9ad607..29569d1 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -1873,27 +1873,43 @@
     got_common_suite = 0;
     ciphersuites = ssl->conf->ciphersuite_list;
     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++ )
+
+    if (ssl->conf->respect_cli_pref == MBEDTLS_SSL_SRV_CIPHERSUITE_ORDER_CLIENT)
+    {
         for( j = 0, p = buf + ciph_offset + 2; j < ciph_len; j += 2, p += 2 )
-#endif
-        {
-            if( p[0] != ( ( ciphersuites[i] >> 8 ) & 0xFF ) ||
-                p[1] != ( ( ciphersuites[i]      ) & 0xFF ) )
-                continue;
+            for( i = 0; ciphersuites[i] != 0; i++ )
+            {
+                if( p[0] != ( ( ciphersuites[i] >> 8 ) & 0xFF ) ||
+                    p[1] != ( ( ciphersuites[i]      ) & 0xFF ) )
+                    continue;
 
-            got_common_suite = 1;
+                got_common_suite = 1;
 
-            if( ( ret = ssl_ciphersuite_match( ssl, ciphersuites[i],
-                                               &ciphersuite_info ) ) != 0 )
-                return( ret );
+                if( ( ret = ssl_ciphersuite_match( ssl, ciphersuites[i],
+                                                   &ciphersuite_info ) ) != 0 )
+                    return( ret );
 
-            if( ciphersuite_info != NULL )
-                goto have_ciphersuite;
-        }
+                if( ciphersuite_info != NULL )
+                    goto have_ciphersuite;
+            }
+    } else {
+        for( i = 0; ciphersuites[i] != 0; i++ )
+            for( j = 0, p = buf + ciph_offset + 2; j < ciph_len; j += 2, p += 2 )
+            {
+                if( p[0] != ( ( ciphersuites[i] >> 8 ) & 0xFF ) ||
+                    p[1] != ( ( ciphersuites[i]      ) & 0xFF ) )
+                    continue;
+
+                got_common_suite = 1;
+
+                if( ( ret = ssl_ciphersuite_match( ssl, ciphersuites[i],
+                                                   &ciphersuite_info ) ) != 0 )
+                    return( ret );
+
+                if( ciphersuite_info != NULL )
+                    goto have_ciphersuite;
+            }
+    }
 
     if( got_common_suite )
     {
@@ -4417,4 +4433,10 @@
 
     return( ret );
 }
+
+void mbedtls_ssl_conf_preference_order( mbedtls_ssl_config *conf, int order )
+{
+    conf->respect_cli_pref = order;
+}
+
 #endif /* MBEDTLS_SSL_SRV_C */
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 560597d..1677ef8 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -6191,6 +6191,7 @@
 
 #if defined(MBEDTLS_SSL_SRV_C)
     conf->cert_req_ca_list = MBEDTLS_SSL_CERT_REQ_CA_LIST_ENABLED;
+    conf->respect_cli_pref = MBEDTLS_SSL_SRV_CIPHERSUITE_ORDER_SERVER;
 #endif
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)