Allow configuration of read timeouts at compile-time

Introduces compile-time constants
- MBEDTLS_SSL_CONF_READ_TIMEOUT
- MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN
- MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX
which allow to configure the read timeouts and
minimum/maximum handshake timeout at compile time.

Impact on code-size:

|  | GCC 8.2.1 | ARMC5 5.06 | ARMC6 6.12 |
| --- | --- | --- | --- |
| `libmbedtls.a` before  | 23147 | 23781 | 26703 |
| `libmbedtls.a` after | 23131 | 23753 | 26673 |
| gain in Bytes | 16 | 28 | 30 |
diff --git a/configs/baremetal.h b/configs/baremetal.h
index c6ba057..37e2444 100644
--- a/configs/baremetal.h
+++ b/configs/baremetal.h
@@ -80,6 +80,9 @@
 #define MBEDTLS_SSL_DTLS_CONNECTION_ID
 
 /* Compile-time fixed parts of the SSL configuration */
+#define MBEDTLS_SSL_CONF_READ_TIMEOUT 0
+#define MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN 1000
+#define MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX 16000
 #define MBEDTLS_SSL_CONF_CID_LEN 0
 #define MBEDTLS_SSL_CONF_IGNORE_UNEXPECTED_CID MBEDTLS_SSL_UNEXPECTED_CID_IGNORE
 #define MBEDTLS_SSL_CONF_ALLOW_LEGACY_RENEGOTIATION \
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index a038121..4487bd7 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -638,6 +638,13 @@
 #error "MBEDTLS_SSL_CONF_CID_LEN and MBEDTLS_SSL_CONF_IGNORE_UNEXPECTED_CID must be defined simultaneously"
 #endif
 
+#if (  defined(MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN) &&       \
+      !defined(MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX) ) ||    \
+    ( !defined(MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN) &&       \
+       defined(MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX) )
+#error "MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN and MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX must be defined simultaneously"
+#endif
+
 #if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) &&                              \
     ( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) )
 #error "MBEDTLS_SSL_DTLS_BADMAC_LIMIT  defined, but not all prerequisites"
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index 5af2e79..e872840 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -3454,7 +3454,12 @@
 
 //#define MBEDTLS_SSL_CONF_AUTHMODE MBEDTLS_SSL_VERIFY_REQUIRED
 
+/* Timeout */
+//#define MBEDTLS_SSL_CONF_READ_TIMEOUT 0
+
 /* DTLS-specific settings */
+//#define MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MIN
+//#define MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MAX
 //#define MBEDTLS_SSL_CONF_ANTI_REPLAY MBEDTLS_SSL_ANTI_REPLAY_ENABLED
 //#define MBEDTLS_SSL_CONF_BADMAC_LIMIT 0
 //#define MBEDTLS_SSL_CONF_CID_LEN 0
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index e68eb1c..1d7c05d 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -1015,14 +1015,20 @@
      * Numerical settings (int then char)
      */
 
+#if !defined(MBEDTLS_SSL_CONF_READ_TIMEOUT)
     uint32_t read_timeout;          /*!< timeout for mbedtls_ssl_read (ms)  */
+#endif /* !MBEDTLS_SSL_CONF_READ_TIMEOUT */
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
+#if !defined(MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN)
     uint32_t hs_timeout_min;        /*!< initial value of the handshake
                                          retransmission timeout (ms)        */
+#endif /* !MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN */
+#if !defined(MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX)
     uint32_t hs_timeout_max;        /*!< maximum value of the handshake
                                          retransmission timeout (ms)        */
-#endif
+#endif /* !MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX */
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
 
 #if defined(MBEDTLS_SSL_RENEGOTIATION)
     int renego_max_records;         /*!< grace period for renegotiation     */
@@ -1692,6 +1698,7 @@
 void mbedtls_ssl_set_mtu( mbedtls_ssl_context *ssl, uint16_t mtu );
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
 
+#if !defined(MBEDTLS_SSL_CONF_READ_TIMEOUT)
 /**
  * \brief          Set the timeout period for mbedtls_ssl_read()
  *                 (Default: no timeout.)
@@ -1705,10 +1712,14 @@
  *                 With non-blocking I/O, this will only work if timer
  *                 callbacks were set with \c mbedtls_ssl_set_timer_cb().
  *
+ * \note           On constrained systems, this option can also be configured
+ *                 at compile-time via MBEDTLS_SSL_CONF_READ_TIMEOUT.
+ *
  * \note           With non-blocking I/O, you may also skip this function
  *                 altogether and handle timeouts at the application layer.
  */
 void mbedtls_ssl_conf_read_timeout( mbedtls_ssl_config *conf, uint32_t timeout );
+#endif /* !MBEDTLS_SSL_CONF_READ_TIMEOUT */
 
 /**
  * \brief          Set the timer callbacks (Mandatory for DTLS.)
diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h
index 57fe486..093c4ac 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -1085,6 +1085,53 @@
  * be fixed at compile time via one of MBEDTLS_SSL_SSL_CONF_XXX.
  */
 
+#if !defined(MBEDTLS_SSL_CONF_READ_TIMEOUT)
+static inline uint32_t mbedtls_ssl_conf_get_read_timeout(
+    mbedtls_ssl_config  const *conf )
+{
+    return( conf->read_timeout );
+}
+#else /* !MBEDTLS_SSL_CONF_READ_TIMEOUT */
+static inline uint32_t mbedtls_ssl_conf_get_read_timeout(
+    mbedtls_ssl_config  const *conf )
+{
+    ((void) conf);
+    return( MBEDTLS_SSL_CONF_READ_TIMEOUT );
+}
+#endif /* MBEDTLS_SSL_CONF_READ_TIMEOUT */
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+#if !defined(MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN)
+static inline uint32_t mbedtls_ssl_conf_get_hs_timeout_min(
+    mbedtls_ssl_config  const *conf )
+{
+    return( conf->hs_timeout_min );
+}
+#else /* !MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN */
+static inline uint32_t mbedtls_ssl_conf_get_hs_timeout_min(
+    mbedtls_ssl_config  const *conf )
+{
+    ((void) conf);
+    return( MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN );
+}
+#endif /* MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN */
+
+#if !defined(MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX)
+static inline uint32_t mbedtls_ssl_conf_get_hs_timeout_max(
+    mbedtls_ssl_config  const *conf )
+{
+    return( conf->hs_timeout_max );
+}
+#else /* !MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX */
+static inline uint32_t mbedtls_ssl_conf_get_hs_timeout_max(
+    mbedtls_ssl_config  const *conf )
+{
+    ((void) conf);
+    return( MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX );
+}
+#endif /* MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX */
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
 #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
 #if !defined(MBEDTLS_SSL_CONF_CID_LEN)
 static inline size_t mbedtls_ssl_conf_get_cid_len(
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 7729cbc..95cf554 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -318,8 +318,11 @@
 {
     uint32_t new_timeout;
 
-    if( ssl->handshake->retransmit_timeout >= ssl->conf->hs_timeout_max )
+    if( ssl->handshake->retransmit_timeout >=
+        mbedtls_ssl_conf_get_hs_timeout_max( ssl->conf ) )
+    {
         return( -1 );
+    }
 
     /* Implement the final paragraph of RFC 6347 section 4.1.1.1
      * in the following way: after the initial transmission and a first
@@ -327,7 +330,8 @@
      * This value is guaranteed to be deliverable (if not guaranteed to be
      * delivered) of any compliant IPv4 (and IPv6) network, and should work
      * on most non-IP stacks too. */
-    if( ssl->handshake->retransmit_timeout != ssl->conf->hs_timeout_min )
+    if( ssl->handshake->retransmit_timeout !=
+        mbedtls_ssl_conf_get_hs_timeout_min( ssl->conf ) )
     {
         ssl->handshake->mtu = 508;
         MBEDTLS_SSL_DEBUG_MSG( 2, ( "mtu autoreduction to %d bytes", ssl->handshake->mtu ) );
@@ -337,9 +341,9 @@
 
     /* Avoid arithmetic overflow and range overflow */
     if( new_timeout < ssl->handshake->retransmit_timeout ||
-        new_timeout > ssl->conf->hs_timeout_max )
+        new_timeout > mbedtls_ssl_conf_get_hs_timeout_max( ssl->conf ) )
     {
-        new_timeout = ssl->conf->hs_timeout_max;
+        new_timeout = mbedtls_ssl_conf_get_hs_timeout_max( ssl->conf );
     }
 
     ssl->handshake->retransmit_timeout = new_timeout;
@@ -351,7 +355,7 @@
 
 static void ssl_reset_retransmit_timeout( mbedtls_ssl_context *ssl )
 {
-    ssl->handshake->retransmit_timeout = ssl->conf->hs_timeout_min;
+    ssl->handshake->retransmit_timeout = mbedtls_ssl_conf_get_hs_timeout_min( ssl->conf );
     MBEDTLS_SSL_DEBUG_MSG( 3, ( "update timeout value to %d millisecs",
                         ssl->handshake->retransmit_timeout ) );
 }
@@ -3011,7 +3015,9 @@
      * timeout if we were using the usual handshake doubling scheme */
     if( ssl->conf->renego_max_records < 0 )
     {
-        uint32_t ratio = ssl->conf->hs_timeout_max / ssl->conf->hs_timeout_min + 1;
+        uint32_t ratio =
+            mbedtls_ssl_conf_get_hs_timeout_max( ssl->conf ) /
+            mbedtls_ssl_conf_get_hs_timeout_min( ssl->conf ) + 1;
         unsigned char doublings = 1;
 
         while( ratio != 0 )
@@ -3152,7 +3158,7 @@
             if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER )
                 timeout = ssl->handshake->retransmit_timeout;
             else
-                timeout = ssl->conf->read_timeout;
+                timeout = mbedtls_ssl_conf_get_read_timeout( ssl->conf );
 
             MBEDTLS_SSL_DEBUG_MSG( 3, ( "f_recv_timeout: %u ms", timeout ) );
 
@@ -3227,8 +3233,8 @@
                 if( ssl->f_recv_timeout != NULL )
                 {
                     ret = ssl->f_recv_timeout( ssl->p_bio,
-                                               ssl->in_hdr + ssl->in_left, len,
-                                               ssl->conf->read_timeout );
+                             ssl->in_hdr + ssl->in_left, len,
+                             mbedtls_ssl_conf_get_read_timeout( ssl->conf ) );
                 }
                 else
                 {
@@ -8103,13 +8109,27 @@
     ssl->disable_datagram_packing = !allow_packing;
 }
 
+#if !( defined(MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX) &&      \
+       defined(MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN) )
 void mbedtls_ssl_conf_handshake_timeout( mbedtls_ssl_config *conf,
                                          uint32_t min, uint32_t max )
 {
     conf->hs_timeout_min = min;
     conf->hs_timeout_max = max;
 }
-#endif
+#else /* !( MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN &&
+            MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX ) */
+void mbedtls_ssl_conf_handshake_timeout( mbedtls_ssl_config *conf,
+                                         uint32_t min, uint32_t max )
+{
+    ((void) conf);
+    ((void) min);
+    ((void) max);
+}
+#endif /* MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN &&
+          MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX */
+
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
 
 void mbedtls_ssl_conf_authmode( mbedtls_ssl_config *conf, int authmode )
 {
@@ -8166,10 +8186,12 @@
 }
 #endif
 
+#if !defined(MBEDTLS_SSL_CONF_READ_TIMEOUT)
 void mbedtls_ssl_conf_read_timeout( mbedtls_ssl_config *conf, uint32_t timeout )
 {
     conf->read_timeout   = timeout;
 }
+#endif /* MBEDTLS_SSL_CONF_READ_TIMEOUT */
 
 void mbedtls_ssl_set_timer_cb( mbedtls_ssl_context *ssl,
                                void *p_timer,
@@ -9932,7 +9954,8 @@
         if( ssl->f_get_timer != NULL &&
             ssl->f_get_timer( ssl->p_timer ) == -1 )
         {
-            ssl_set_timer( ssl, ssl->conf->read_timeout );
+            ssl_set_timer( ssl,
+                           mbedtls_ssl_conf_get_read_timeout( ssl->conf ) );
         }
 
         if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
@@ -10784,9 +10807,13 @@
 #endif
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
+#if !defined(MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN)
     conf->hs_timeout_min = MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MIN;
+#endif /* !MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN */
+#if !defined(MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX)
     conf->hs_timeout_max = MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MAX;
-#endif
+#endif /* !MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX */
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
 
 #if defined(MBEDTLS_SSL_RENEGOTIATION)
     conf->renego_max_records = MBEDTLS_SSL_RENEGO_MAX_RECORDS_DEFAULT;
diff --git a/programs/ssl/query_config.c b/programs/ssl/query_config.c
index 99217ba..e58ddc4 100644
--- a/programs/ssl/query_config.c
+++ b/programs/ssl/query_config.c
@@ -2594,6 +2594,30 @@
     }
 #endif /* MBEDTLS_SSL_CONF_AUTHMODE */
 
+#if defined(MBEDTLS_SSL_CONF_READ_TIMEOUT)
+    if( strcmp( "MBEDTLS_SSL_CONF_READ_TIMEOUT", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CONF_READ_TIMEOUT );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CONF_READ_TIMEOUT */
+
+#if defined(MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN)
+    if( strcmp( "MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CONF_HS_TIMEOUT_MIN */
+
+#if defined(MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX)
+    if( strcmp( "MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX );
+        return( 0 );
+    }
+#endif /* MBEDTLS_SSL_CONF_HS_TIMEOUT_MAX */
+
 #if defined(MBEDTLS_SSL_CONF_ANTI_REPLAY)
     if( strcmp( "MBEDTLS_SSL_CONF_ANTI_REPLAY", config ) == 0 )
     {
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 9e9a44b..391513b 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -307,6 +307,13 @@
 #define USAGE_ALLOW_LEGACY_RENEGO ""
 #endif
 
+#if !defined(MBEDTLS_SSL_CONF_READ_TIMEOUT)
+#define USAGE_READ_TIMEOUT                              \
+    "    read_timeout=%%d     default: 0 ms (no timeout)\n"
+#else
+#define USAGE_READ_TIMEOUT ""
+#endif
+
 #define USAGE \
     "\n usage: ssl_client2 param=<>...\n"                   \
     "\n acceptable parameters:\n"                           \
@@ -325,7 +332,7 @@
     "                        options: 1 (non-blocking), 2 (added delays)\n"   \
     "    event=%%d            default: 0 (loop)\n"                            \
     "                        options: 1 (level-triggered, implies nbio=1),\n" \
-    "    read_timeout=%%d     default: 0 ms (no timeout)\n"        \
+    USAGE_READ_TIMEOUT                                                  \
     "    max_resend=%%d       default: 0 (no resend on timeout)\n" \
     "\n"                                                    \
     USAGE_DTLS                                              \
@@ -921,8 +928,10 @@
             if( opt.event < 0 || opt.event > 2 )
                 goto usage;
         }
+#if !defined(MBEDTLS_SSL_CONF_READ_TIMEOUT)
         else if( strcmp( p, "read_timeout" ) == 0 )
             opt.read_timeout = atoi( q );
+#endif
         else if( strcmp( p, "max_resend" ) == 0 )
         {
             opt.max_resend = atoi( q );
@@ -1769,7 +1778,9 @@
     mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
     mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
 
+#if !defined(MBEDTLS_SSL_CONF_READ_TIMEOUT)
     mbedtls_ssl_conf_read_timeout( &conf, opt.read_timeout );
+#endif
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS)
     mbedtls_ssl_conf_session_tickets( &conf, opt.tickets );
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index a4624fc..707660f 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -415,6 +415,13 @@
 #define USAGE_ALLOW_LEGACY_RENEGO ""
 #endif
 
+#if !defined(MBEDTLS_SSL_CONF_READ_TIMEOUT)
+#define USAGE_READ_TIMEOUT                              \
+    "    read_timeout=%%d     default: 0 ms (no timeout)\n"
+#else
+#define USAGE_READ_TIMEOUT ""
+#endif
+
 #define USAGE \
     "\n usage: ssl_server2 param=<>...\n"                   \
     "\n acceptable parameters:\n"                           \
@@ -430,7 +437,7 @@
     "                        options: 1 (non-blocking), 2 (added delays)\n" \
     "    event=%%d            default: 0 (loop)\n"                            \
     "                        options: 1 (level-triggered, implies nbio=1),\n" \
-    "    read_timeout=%%d     default: 0 ms (no timeout)\n"    \
+    USAGE_READ_TIMEOUT                                                  \
     "\n"                                                    \
     USAGE_DTLS                                              \
     USAGE_COOKIES                                           \
@@ -1575,8 +1582,10 @@
             if( opt.event < 0 || opt.event > 2 )
                 goto usage;
         }
+#if !defined(MBEDTLS_SSL_CONF_READ_TIMEOUT)
         else if( strcmp( p, "read_timeout" ) == 0 )
             opt.read_timeout = atoi( q );
+#endif
         else if( strcmp( p, "buffer_size" ) == 0 )
         {
             opt.buffer_size = atoi( q );
@@ -2927,7 +2936,9 @@
         goto exit;
     }
 
+#if !defined(MBEDTLS_SSL_CONF_READ_TIMEOUT)
     mbedtls_ssl_conf_read_timeout( &conf, opt.read_timeout );
+#endif /* MBEDTLS_SSL_CONF_READ_TIMEOUT */
 
 #if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY)
     if( opt.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )