Merge branch 'mbedtls_ssl_get_key_exchange_md_ssl_tls-return_hashlen' into tls_async_server-2.9

Conflict resolution:
* ChangeLog: put the new entry from my branch in the proper place.
* include/mbedtls/error.h: counted high-level module error codes again.
* include/mbedtls/ssl.h: picked different numeric codes for the
  concurrently added errors; made the new error a full sentence per
  current standards.
* library/error.c: ran scripts/generate_errors.pl.
* library/ssl_srv.c:
    * ssl_prepare_server_key_exchange "DHE key exchanges": the conflict
      was due to style corrections in development
      (4cb1f4d49cff999d0c853bc696ad7eea68888c35) which I merged with
      my refactoring.
    * ssl_prepare_server_key_exchange "For key exchanges involving the
      server signing", first case, variable declarations: merged line
      by line:
        * dig_signed_len: added in async
        * signature_len: removed in async
        * hashlen: type changed to size_t in development
        * hash: size changed to MBEDTLS_MD_MAX_SIZE in async
        * ret: added in async
    * ssl_prepare_server_key_exchange "For key exchanges involving the
      server signing", first cae comment: the conflict was due to style
      corrections in development (4cb1f4d49cff999d0c853bc696ad7eea68888c35)
      which I merged with my comment changes made as part of refactoring
      the function.
    * ssl_prepare_server_key_exchange "Compute the hash to be signed" if
      `md_alg != MBEDTLS_MD_NONE`: conflict between
      ebd652fe2dfc2c82d774bfd334398279d9027492
      "ssl_write_server_key_exchange: calculate hashlen explicitly" and
      46f5a3e9b4d5db3cacfe2ba33480a27317c62d46 "Check return codes from
      MD in ssl code". I took the code from commit
      ca1d74290439ec9e2723a911657fd96aa320e219 made on top of development
      which makes mbedtls_ssl_get_key_exchange_md_ssl_tls return the
      hash length.
* programs/ssl/ssl_server2.c: multiple conflicts between the introduction
  of MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS and new auxiliary functions and
  definitions for async support, and the introduction of idle().
    * definitions before main: concurrent additions, kept both.
    * main, just after `handshake:`: in the loop around
      mbedtls_ssl_handshake(), merge the addition of support for
      MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS and SSL_ASYNC_INJECT_ERROR_CANCEL
      with the addition of the idle() call.
    * main, if `opt.transport == MBEDTLS_SSL_TRANSPORT_STREAM`: take the
      code from development and add a check for
      MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS.
    * main, loop around mbedtls_ssl_read() in the datagram case:
      take the code from development and add a check for
      MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS; revert to a do...while loop.
    * main, loop around mbedtls_ssl_write() in the datagram case:
      take the code from development and add a check for
      MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS; revert to a do...while loop.
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 2f3908d..02f9633 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -101,6 +101,7 @@
 #define DFL_SERVER_PORT         "4433"
 #define DFL_DEBUG_LEVEL         0
 #define DFL_NBIO                0
+#define DFL_EVENT               0
 #define DFL_READ_TIMEOUT        0
 #define DFL_CA_FILE             ""
 #define DFL_CA_PATH             ""
@@ -347,6 +348,8 @@
     "    debug_level=%%d      default: 0 (disabled)\n"      \
     "    nbio=%%d             default: 0 (blocking I/O)\n"  \
     "                        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"    \
     "\n"                                                    \
     USAGE_DTLS                                              \
@@ -416,6 +419,7 @@
     const char *server_port;    /* port on which the ssl service runs       */
     int debug_level;            /* level of debugging                       */
     int nbio;                   /* should I/O be blocking?                  */
+    int event;                  /* loop or event-driven IO? level or edge triggered? */
     uint32_t read_timeout;      /* timeout on mbedtls_ssl_read() in milliseconds    */
     const char *ca_file;        /* the file with the CA certificate(s)      */
     const char *ca_path;        /* the path with the CA certificate(s) reside */
@@ -1041,6 +1045,56 @@
 }
 #endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */
 
+/*
+ * Wait for an event from the underlying transport or the timer
+ * (Used in event-driven IO mode).
+ */
+#if !defined(MBEDTLS_TIMING_C)
+int idle( mbedtls_net_context *fd,
+          int idle_reason )
+#else
+int idle( mbedtls_net_context *fd,
+          mbedtls_timing_delay_context *timer,
+          int idle_reason )
+#endif
+{
+    int ret;
+    int poll_type = 0;
+
+    if( idle_reason == MBEDTLS_ERR_SSL_WANT_WRITE )
+        poll_type = MBEDTLS_NET_POLL_WRITE;
+    else if( idle_reason == MBEDTLS_ERR_SSL_WANT_READ )
+        poll_type = MBEDTLS_NET_POLL_READ;
+#if !defined(MBEDTLS_TIMING_C)
+    else
+        return( 0 );
+#endif
+
+    while( 1 )
+    {
+        /* Check if timer has expired */
+#if defined(MBEDTLS_TIMING_C)
+        if( timer != NULL &&
+            mbedtls_timing_get_delay( timer ) == 2 )
+        {
+            break;
+        }
+#endif /* MBEDTLS_TIMING_C */
+
+        /* Check if underlying transport became available */
+        if( poll_type != 0 )
+        {
+            ret = mbedtls_net_poll( fd, poll_type, 0 );
+            if( ret < 0 )
+                return( ret );
+            if( ret == poll_type )
+                break;
+        }
+    }
+
+    return( 0 );
+}
+
 int main( int argc, char *argv[] )
 {
     int ret = 0, len, written, frags, exchanges_left;
@@ -1176,6 +1230,7 @@
     opt.server_addr         = DFL_SERVER_ADDR;
     opt.server_port         = DFL_SERVER_PORT;
     opt.debug_level         = DFL_DEBUG_LEVEL;
+    opt.event               = DFL_EVENT;
     opt.nbio                = DFL_NBIO;
     opt.read_timeout        = DFL_READ_TIMEOUT;
     opt.ca_file             = DFL_CA_FILE;
@@ -1258,6 +1313,12 @@
             if( opt.nbio < 0 || opt.nbio > 2 )
                 goto usage;
         }
+        else if( strcmp( p, "event" ) == 0 )
+        {
+            opt.event = atoi( q );
+            if( opt.event < 0 || opt.event > 2 )
+                goto usage;
+        }
         else if( strcmp( p, "read_timeout" ) == 0 )
             opt.read_timeout = atoi( q );
         else if( strcmp( p, "ca_file" ) == 0 )
@@ -1318,16 +1379,23 @@
             opt.version_suites = q;
         else if( strcmp( p, "renegotiation" ) == 0 )
         {
-            opt.renegotiation = (atoi( q )) ? MBEDTLS_SSL_RENEGOTIATION_ENABLED :
-                                              MBEDTLS_SSL_RENEGOTIATION_DISABLED;
+            opt.renegotiation = (atoi( q )) ?
+                MBEDTLS_SSL_RENEGOTIATION_ENABLED :
+                MBEDTLS_SSL_RENEGOTIATION_DISABLED;
         }
         else if( strcmp( p, "allow_legacy" ) == 0 )
         {
             switch( atoi( q ) )
             {
-                case -1: opt.allow_legacy = MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE; break;
-                case 0:  opt.allow_legacy = MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION; break;
-                case 1:  opt.allow_legacy = MBEDTLS_SSL_LEGACY_ALLOW_RENEGOTIATION; break;
+                case -1:
+                    opt.allow_legacy = MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE;
+                    break;
+                case 0:
+                    opt.allow_legacy = MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION;
+                    break;
+                case 1:
+                    opt.allow_legacy = MBEDTLS_SSL_LEGACY_ALLOW_RENEGOTIATION;
+                    break;
                 default: goto usage;
             }
         }
@@ -1484,8 +1552,12 @@
         {
             switch( atoi( q ) )
             {
-                case 0: opt.extended_ms = MBEDTLS_SSL_EXTENDED_MS_DISABLED; break;
-                case 1: opt.extended_ms = MBEDTLS_SSL_EXTENDED_MS_ENABLED; break;
+                case 0:
+                    opt.extended_ms = MBEDTLS_SSL_EXTENDED_MS_DISABLED;
+                    break;
+                case 1:
+                    opt.extended_ms = MBEDTLS_SSL_EXTENDED_MS_ENABLED;
+                    break;
                 default: goto usage;
             }
         }
@@ -1558,6 +1630,15 @@
             goto usage;
     }
 
+    /* Event-driven IO is incompatible with the above custom
+     * receive and send functions, as the polling builds on
+     * refers to the underlying net_context. */
+    if( opt.event == 1 && opt.nbio != 1 )
+    {
+        mbedtls_printf( "Warning: event-driven IO mandates nbio=1 - overwrite\n" );
+        opt.nbio = 1;
+    }
+
 #if defined(MBEDTLS_DEBUG_C)
     mbedtls_debug_set_threshold( opt.debug_level );
 #endif
@@ -1565,19 +1646,20 @@
     if( opt.force_ciphersuite[0] > 0 )
     {
         const mbedtls_ssl_ciphersuite_t *ciphersuite_info;
-        ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( opt.force_ciphersuite[0] );
+        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_printf("forced ciphersuite not allowed with this protocol version\n");
+            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_printf("forced ciphersuite not allowed with this protocol version\n");
+            mbedtls_printf( "forced ciphersuite not allowed with this protocol version\n" );
             ret = 2;
             goto usage;
         }
@@ -1756,11 +1838,12 @@
     fflush( stdout );
 
     mbedtls_entropy_init( &entropy );
-    if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
-                               (const unsigned char *) pers,
-                               strlen( pers ) ) ) != 0 )
+    if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func,
+                                       &entropy, (const unsigned char *) pers,
+                                       strlen( pers ) ) ) != 0 )
     {
-        mbedtls_printf( " failed\n  ! mbedtls_ctr_drbg_seed returned -0x%x\n", -ret );
+        mbedtls_printf( " failed\n  ! mbedtls_ctr_drbg_seed returned -0x%x\n",
+                        -ret );
         goto exit;
     }
 
@@ -1857,7 +1940,7 @@
         if( ( ret = mbedtls_pk_parse_keyfile( &pkey2, opt.key_file2, "" ) ) != 0 )
         {
             mbedtls_printf( " failed\n  !  mbedtls_pk_parse_keyfile(2) returned -0x%x\n\n",
-                    -ret );
+                            -ret );
             goto exit;
         }
     }
@@ -1875,8 +1958,7 @@
         strcmp( opt.key_file2, "none" ) != 0 )
     {
 #if !defined(MBEDTLS_CERTS_C)
-        mbedtls_printf( "Not certificated or key provided, and \n"
-                "MBEDTLS_CERTS_C not defined!\n" );
+        mbedtls_printf( "Not certificated or key provided, and \nMBEDTLS_CERTS_C not defined!\n" );
         goto exit;
 #else
 #if defined(MBEDTLS_RSA_C)
@@ -1884,14 +1966,16 @@
                                     (const unsigned char *) mbedtls_test_srv_crt_rsa,
                                     mbedtls_test_srv_crt_rsa_len ) ) != 0 )
         {
-            mbedtls_printf( " failed\n  !  mbedtls_x509_crt_parse returned -0x%x\n\n", -ret );
+            mbedtls_printf( " failed\n  !  mbedtls_x509_crt_parse returned -0x%x\n\n",
+                            -ret );
             goto exit;
         }
         if( ( ret = mbedtls_pk_parse_key( &pkey,
                                   (const unsigned char *) mbedtls_test_srv_key_rsa,
                                   mbedtls_test_srv_key_rsa_len, NULL, 0 ) ) != 0 )
         {
-            mbedtls_printf( " failed\n  !  mbedtls_pk_parse_key returned -0x%x\n\n", -ret );
+            mbedtls_printf( " failed\n  !  mbedtls_pk_parse_key returned -0x%x\n\n",
+                            -ret );
             goto exit;
         }
         key_cert_init = 2;
@@ -1901,14 +1985,16 @@
                                     (const unsigned char *) mbedtls_test_srv_crt_ec,
                                     mbedtls_test_srv_crt_ec_len ) ) != 0 )
         {
-            mbedtls_printf( " failed\n  !  x509_crt_parse2 returned -0x%x\n\n", -ret );
+            mbedtls_printf( " failed\n  !  x509_crt_parse2 returned -0x%x\n\n",
+                            -ret );
             goto exit;
         }
         if( ( ret = mbedtls_pk_parse_key( &pkey2,
                                   (const unsigned char *) mbedtls_test_srv_key_ec,
                                   mbedtls_test_srv_key_ec_len, NULL, 0 ) ) != 0 )
         {
-            mbedtls_printf( " failed\n  !  pk_parse_key2 returned -0x%x\n\n", -ret );
+            mbedtls_printf( " failed\n  !  pk_parse_key2 returned -0x%x\n\n",
+                            -ret );
             goto exit;
         }
         key_cert_init2 = 2;
@@ -2303,8 +2389,10 @@
 #if !defined(_WIN32)
     if( received_sigterm )
     {
-        mbedtls_printf( " interrupted by SIGTERM\n" );
-        ret = 0;
+        mbedtls_printf( " interrupted by SIGTERM (not in net_accept())\n" );
+        if( ret == MBEDTLS_ERR_NET_INVALID_CONTEXT )
+            ret = 0;
+
         goto exit;
     }
 #endif
@@ -2340,8 +2428,10 @@
 #if !defined(_WIN32)
         if( received_sigterm )
         {
-            mbedtls_printf( " interrupted by signal\n" );
-            ret = 0;
+            mbedtls_printf( " interrupted by SIGTERM (in net_accept())\n" );
+            if( ret == MBEDTLS_ERR_NET_ACCEPT_FAILED )
+                ret = 0;
+
             goto exit;
         }
 #endif
@@ -2368,8 +2458,8 @@
         if( ( ret = mbedtls_ssl_set_client_transport_id( &ssl,
                         client_ip, cliip_len ) ) != 0 )
         {
-            mbedtls_printf( " failed\n  ! "
-                    "mbedtls_ssl_set_client_transport_id() returned -0x%x\n\n", -ret );
+            mbedtls_printf( " failed\n  ! mbedtls_ssl_set_client_transport_id() returned -0x%x\n\n",
+                            -ret );
             goto exit;
         }
     }
@@ -2397,9 +2487,8 @@
     mbedtls_printf( "  . Performing the SSL/TLS handshake..." );
     fflush( stdout );
 
-    do
+    while( ( ret = mbedtls_ssl_handshake( &ssl ) ) != 0 )
     {
-        ret = mbedtls_ssl_handshake( &ssl );
 #if defined(MBEDTLS_SSL_ASYNC_PRIVATE_C)
         if( ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS &&
             ssl_async_keys.inject_error == SSL_ASYNC_INJECT_ERROR_CANCEL )
@@ -2408,10 +2497,24 @@
             break;
         }
 #endif /* MBEDTLS_SSL_ASYNC_PRIVATE_C */
+
+        if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
+            ret != MBEDTLS_ERR_SSL_WANT_WRITE &&
+            ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS )
+            break;
+
+        /* For event-driven IO, wait for socket to become available */
+        if( opt.event == 1 /* level triggered IO */ )
+        {
+#if defined(MBEDTLS_TIMING_C)
+            ret = idle( &client_fd, &timer, ret );
+#else
+            ret = idle( &client_fd, ret );
+#endif
+            if( ret != 0 )
+                goto reset;
+        }
     }
-    while( ret == MBEDTLS_ERR_SSL_WANT_READ ||
-           ret == MBEDTLS_ERR_SSL_WANT_WRITE ||
-           ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS );
 
     if( ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED )
     {
@@ -2523,7 +2626,18 @@
             if( ret == MBEDTLS_ERR_SSL_WANT_READ ||
                 ret == MBEDTLS_ERR_SSL_WANT_WRITE ||
                 ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS )
+            {
+                if( opt.event == 1 /* level triggered IO */ )
+                {
+#if defined(MBEDTLS_TIMING_C)
+                    idle( &client_fd, &timer, ret );
+#else
+                    idle( &client_fd, ret );
+#endif
+                }
+
                 continue;
+            }
 
             if( ret <= 0 )
             {
@@ -2611,7 +2725,37 @@
         len = sizeof( buf ) - 1;
         memset( buf, 0, sizeof( buf ) );
 
-        do ret = mbedtls_ssl_read( &ssl, buf, len );
+        do
+        {
+            /* Without the call to `mbedtls_ssl_check_pending`, it might
+             * happen that the client sends application data in the same
+             * datagram as the Finished message concluding the handshake.
+             * In this case, the application data would be ready to be
+             * processed while the underlying transport wouldn't signal
+             * any further incoming data.
+             *
+             * See the test 'Event-driven I/O: session-id resume, UDP packing'
+             * in tests/ssl-opt.sh.
+             */
+
+            /* For event-driven IO, wait for socket to become available */
+            if( mbedtls_ssl_check_pending( &ssl ) == 0 &&
+                opt.event == 1 /* level triggered IO */ )
+            {
+#if defined(MBEDTLS_TIMING_C)
+                idle( &client_fd, &timer, MBEDTLS_ERR_SSL_WANT_READ );
+#else
+                idle( &client_fd, MBEDTLS_ERR_SSL_WANT_READ );
+#endif
+            }
+
+            ret = mbedtls_ssl_read( &ssl, buf, len );
+
+            /* Note that even if `mbedtls_ssl_check_pending` returns true,
+             * it can happen that the subsequent call to `mbedtls_ssl_read`
+             * returns `MBEDTLS_ERR_SSL_WANT_READ`, because the pending messages
+             * might be discarded (e.g. because they are retransmissions). */
+        }
         while( ret == MBEDTLS_ERR_SSL_WANT_READ ||
                ret == MBEDTLS_ERR_SSL_WANT_WRITE ||
                ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS );
@@ -2656,6 +2800,16 @@
                 mbedtls_printf( " failed\n  ! mbedtls_ssl_renegotiate returned %d\n\n", ret );
                 goto reset;
             }
+
+            /* For event-driven IO, wait for socket to become available */
+            if( opt.event == 1 /* level triggered IO */ )
+            {
+#if defined(MBEDTLS_TIMING_C)
+                idle( &client_fd, &timer, ret );
+#else
+                idle( &client_fd, ret );
+#endif
+            }
         }
 
         mbedtls_printf( " ok\n" );
@@ -2691,15 +2845,40 @@
                     mbedtls_printf( " failed\n  ! mbedtls_ssl_write returned %d\n\n", ret );
                     goto reset;
                 }
+
+                /* For event-driven IO, wait for socket to become available */
+                if( opt.event == 1 /* level triggered IO */ )
+                {
+#if defined(MBEDTLS_TIMING_C)
+                    idle( &client_fd, &timer, ret );
+#else
+                    idle( &client_fd, ret );
+#endif
+                }
             }
         }
     }
     else /* Not stream, so datagram */
     {
-        do ret = mbedtls_ssl_write( &ssl, buf, len );
-        while( ret == MBEDTLS_ERR_SSL_WANT_READ ||
-               ret == MBEDTLS_ERR_SSL_WANT_WRITE ||
-               ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS );
+        while( 1 )
+        {
+            ret = mbedtls_ssl_write( &ssl, buf, len );
+
+            if( ret != MBEDTLS_ERR_SSL_WANT_READ &&
+                ret != MBEDTLS_ERR_SSL_WANT_WRITE &&
+                ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS )
+                break;
+
+            /* For event-driven IO, wait for socket to become available */
+            if( opt.event == 1 /* level triggered IO */ )
+            {
+#if defined(MBEDTLS_TIMING_C)
+                idle( &client_fd, &timer, ret );
+#else
+                idle( &client_fd, ret );
+#endif
+            }
+        }
 
         if( ret < 0 )
         {