Merge remote-tracking branch 'public/pr/1221' into mbedtls-2.1

* public/pr/1221:
  all.sh: add some documentation
  all.sh: new option --no-armcc
  all.sh: --keep-going mode
  all.sh: cleaned up usage output
  all.sh: indent
diff --git a/ChangeLog b/ChangeLog
index 0064f1e..c6031b4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -12,6 +12,13 @@
      was independently reported by Tim Nordell via e-mail and by Florin Petriuc
      and sjorsdewit on GitHub. Fix proposed by Florin Petriuc in #1022. Fixes #707.
 
+Features
+   * Allow comments in test data files.
+   * The selftest program can execute a subset of the tests based on command
+     line arguments.
+   * Improve the timing self-tests to be more robust when run on a
+     heavily-loaded machine.
+
 Bugfix
    * Fix ssl_parse_record_header() to silently discard invalid DTLS records
      as recommended in RFC 6347 Section 4.1.2.7.
@@ -50,15 +57,14 @@
    * Fix word size check in in pk.c to not depend on MBEDTLS_HAVE_INT64.
    * Fix crash when calling mbedtls_ssl_cache_free() twice. Found by
      MilenkoMitrovic, #1104
+   * Fix mbedtls_timing_alarm(0) on Unix.
+   * Fix use of uninitialized memory in mbedtls_timing_get_timer when reset=1.
 
 Changes
    * Extend cert_write example program by options to set the CRT version
      and the message digest. Further, allow enabling/disabling of authority
      identifier, subject identifier and basic constraints extensions.
 
-Features
-   * Allow comments in test data files.
-
 = mbed TLS 2.1.9 branch released 2017-08-10
 
 Security
diff --git a/include/mbedtls/timing.h b/include/mbedtls/timing.h
index ae7a713..bfb8579 100644
--- a/include/mbedtls/timing.h
+++ b/include/mbedtls/timing.h
@@ -1,7 +1,7 @@
 /**
  * \file timing.h
  *
- * \brief Portable interface to the CPU cycle counter
+ * \brief Portable interface to timeouts and to the CPU cycle counter
  *
  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
  *  SPDX-License-Identifier: Apache-2.0
@@ -65,6 +65,9 @@
  * \warning        This is only a best effort! Do not rely on this!
  *                 In particular, it is known to be unreliable on virtual
  *                 machines.
+ *
+ * \note           This value starts at an unspecified origin and
+ *                 may wrap around.
  */
 unsigned long mbedtls_timing_hardclock( void );
 
@@ -72,7 +75,18 @@
  * \brief          Return the elapsed time in milliseconds
  *
  * \param val      points to a timer structure
- * \param reset    if set to 1, the timer is restarted
+ * \param reset    If 0, query the elapsed time. Otherwise (re)start the timer.
+ *
+ * \return         Elapsed time since the previous reset in ms. When
+ *                 restarting, this is always 0.
+ *
+ * \note           To initialize a timer, call this function with reset=1.
+ *
+ *                 Determining the elapsed time and resetting the timer is not
+ *                 atomic on all platforms, so after the sequence
+ *                 `{ get_timer(1); ...; time1 = get_timer(1); ...; time2 =
+ *                 get_timer(0) }` the value time1+time2 is only approximately
+ *                 the delay since the first reset.
  */
 unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset );
 
@@ -80,6 +94,7 @@
  * \brief          Setup an alarm clock
  *
  * \param seconds  delay before the "mbedtls_timing_alarmed" flag is set
+ *                 (must be >=0)
  *
  * \warning        Only one alarm at a time  is supported. In a threaded
  *                 context, this means one for the whole process, not one per
@@ -91,11 +106,15 @@
  * \brief          Set a pair of delays to watch
  *                 (See \c mbedtls_timing_get_delay().)
  *
- * \param data     Pointer to timing data
+ * \param data     Pointer to timing data.
  *                 Must point to a valid \c mbedtls_timing_delay_context struct.
  * \param int_ms   First (intermediate) delay in milliseconds.
+ *                 The effect if int_ms > fin_ms is unspecified.
  * \param fin_ms   Second (final) delay in milliseconds.
  *                 Pass 0 to cancel the current delay.
+ *
+ * \note           To set a single delay, either use \c mbedtls_timing_set_timer
+ *                 directly or use this function with int_ms == fin_ms.
  */
 void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms );
 
@@ -106,7 +125,7 @@
  * \param data     Pointer to timing data
  *                 Must point to a valid \c mbedtls_timing_delay_context struct.
  *
- * \return         -1 if cancelled (fin_ms = 0)
+ * \return         -1 if cancelled (fin_ms = 0),
  *                  0 if none of the delays are passed,
  *                  1 if only the intermediate delay is passed,
  *                  2 if the final delay is passed.
diff --git a/library/timing.c b/library/timing.c
index 5d8b25b..de936e1 100644
--- a/library/timing.c
+++ b/library/timing.c
@@ -239,21 +239,23 @@
 
 unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset )
 {
-    unsigned long delta;
-    LARGE_INTEGER offset, hfreq;
     struct _hr_time *t = (struct _hr_time *) val;
 
-    QueryPerformanceCounter(  &offset );
-    QueryPerformanceFrequency( &hfreq );
-
-    delta = (unsigned long)( ( 1000 *
-        ( offset.QuadPart - t->start.QuadPart ) ) /
-           hfreq.QuadPart );
-
     if( reset )
+    {
         QueryPerformanceCounter( &t->start );
-
-    return( delta );
+        return( 0 );
+    }
+    else
+    {
+        unsigned long delta;
+        LARGE_INTEGER now, hfreq;
+        QueryPerformanceCounter(  &now );
+        QueryPerformanceFrequency( &hfreq );
+        delta = (unsigned long)( ( now.QuadPart - t->start.QuadPart ) * 1000ul
+                                 / hfreq.QuadPart );
+        return( delta );
+    }
 }
 
 /* It's OK to use a global because alarm() is supposed to be global anyway */
@@ -280,23 +282,22 @@
 
 unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset )
 {
-    unsigned long delta;
-    struct timeval offset;
     struct _hr_time *t = (struct _hr_time *) val;
 
-    gettimeofday( &offset, NULL );
-
     if( reset )
     {
-        t->start.tv_sec  = offset.tv_sec;
-        t->start.tv_usec = offset.tv_usec;
+        gettimeofday( &t->start, NULL );
         return( 0 );
     }
-
-    delta = ( offset.tv_sec  - t->start.tv_sec  ) * 1000
-          + ( offset.tv_usec - t->start.tv_usec ) / 1000;
-
-    return( delta );
+    else
+    {
+        unsigned long delta;
+        struct timeval now;
+        gettimeofday( &now, NULL );
+        delta = ( now.tv_sec  - t->start.tv_sec  ) * 1000ul
+              + ( now.tv_usec - t->start.tv_usec ) / 1000;
+        return( delta );
+    }
 }
 
 static void sighandler( int signum )
@@ -310,6 +311,12 @@
     mbedtls_timing_alarmed = 0;
     signal( SIGALRM, sighandler );
     alarm( seconds );
+    if( seconds == 0 )
+    {
+        /* alarm(0) cancelled any previous pending alarm, but the
+           handler won't fire, so raise the flag straight away. */
+        mbedtls_timing_alarmed = 1;
+    }
 }
 
 #endif /* _WIN32 && !EFIX64 && !EFI32 */
@@ -373,13 +380,21 @@
     (void) j;
 }
 
-#define FAIL    do                      \
-{                                       \
-    if( verbose != 0 )                  \
-        mbedtls_printf( "failed\n" );   \
-                                        \
-    return( 1 );                        \
-} while( 0 )
+#define FAIL    do                                                      \
+    {                                                                   \
+        if( verbose != 0 )                                              \
+        {                                                               \
+            mbedtls_printf( "failed at line %d\n", __LINE__ );          \
+            mbedtls_printf( " cycles=%lu ratio=%lu millisecs=%lu secs=%lu hardfail=%d a=%lu b=%lu\n", \
+                            cycles, ratio, millisecs, secs, hardfail,   \
+                            (unsigned long) a, (unsigned long) b );     \
+            mbedtls_printf( " elapsed(hires)=%lu elapsed(ctx)=%lu status(ctx)=%d\n", \
+                            mbedtls_timing_get_timer( &hires, 0 ),      \
+                            mbedtls_timing_get_timer( &ctx.timer, 0 ),  \
+                            mbedtls_timing_get_delay( &ctx ) );         \
+        }                                                               \
+        return( 1 );                                                    \
+    } while( 0 )
 
 /*
  * Checkup routine
@@ -389,22 +404,21 @@
  */
 int mbedtls_timing_self_test( int verbose )
 {
-    unsigned long cycles, ratio;
-    unsigned long millisecs, secs;
-    int hardfail;
+    unsigned long cycles = 0, ratio = 0;
+    unsigned long millisecs = 0, secs = 0;
+    int hardfail = 0;
     struct mbedtls_timing_hr_time hires;
-    uint32_t a, b;
+    uint32_t a = 0, b = 0;
     mbedtls_timing_delay_context ctx;
 
     if( verbose != 0 )
         mbedtls_printf( "  TIMING tests note: will take some time!\n" );
 
-
     if( verbose != 0 )
         mbedtls_printf( "  TIMING test #1 (set_alarm / get_timer): " );
 
-    for( secs = 1; secs <= 3; secs++ )
     {
+        secs = 1;
         (void) mbedtls_timing_get_timer( &hires, 1 );
 
         mbedtls_set_alarm( (int) secs );
@@ -416,12 +430,7 @@
         /* For some reason on Windows it looks like alarm has an extra delay
          * (maybe related to creating a new thread). Allow some room here. */
         if( millisecs < 800 * secs || millisecs > 1200 * secs + 300 )
-        {
-            if( verbose != 0 )
-                mbedtls_printf( "failed\n" );
-
-            return( 1 );
-        }
+            FAIL;
     }
 
     if( verbose != 0 )
@@ -430,28 +439,22 @@
     if( verbose != 0 )
         mbedtls_printf( "  TIMING test #2 (set/get_delay        ): " );
 
-    for( a = 200; a <= 400; a += 200 )
     {
-        for( b = 200; b <= 400; b += 200 )
-        {
-            mbedtls_timing_set_delay( &ctx, a, a + b );
+        a = 800;
+        b = 400;
+        mbedtls_timing_set_delay( &ctx, a, a + b );          /* T = 0 */
 
-            busy_msleep( a - a / 8 );
-            if( mbedtls_timing_get_delay( &ctx ) != 0 )
-                FAIL;
+        busy_msleep( a - a / 4 );                      /* T = a - a/4 */
+        if( mbedtls_timing_get_delay( &ctx ) != 0 )
+            FAIL;
 
-            busy_msleep( a / 4 );
-            if( mbedtls_timing_get_delay( &ctx ) != 1 )
-                FAIL;
+        busy_msleep( a / 4 + b / 4 );                  /* T = a + b/4 */
+        if( mbedtls_timing_get_delay( &ctx ) != 1 )
+            FAIL;
 
-            busy_msleep( b - a / 8 - b / 8 );
-            if( mbedtls_timing_get_delay( &ctx ) != 1 )
-                FAIL;
-
-            busy_msleep( b / 4 );
-            if( mbedtls_timing_get_delay( &ctx ) != 2 )
-                FAIL;
-        }
+        busy_msleep( b );                          /* T = a + b + b/4 */
+        if( mbedtls_timing_get_delay( &ctx ) != 2 )
+            FAIL;
     }
 
     mbedtls_timing_set_delay( &ctx, 0, 0 );
@@ -470,7 +473,6 @@
      * On a 4Ghz 32-bit machine the cycle counter wraps about once per second;
      * since the whole test is about 10ms, it shouldn't happen twice in a row.
      */
-    hardfail = 0;
 
 hard_test:
     if( hardfail > 1 )
diff --git a/programs/test/selftest.c b/programs/test/selftest.c
index 82e9581..846d34d 100644
--- a/programs/test/selftest.c
+++ b/programs/test/selftest.c
@@ -51,6 +51,7 @@
 #include "mbedtls/ecp.h"
 #include "mbedtls/timing.h"
 
+#include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -96,10 +97,123 @@
             test_snprintf( 5, "123",         3 ) != 0 );
 }
 
+#if defined(MBEDTLS_SELF_TEST)
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
+int mbedtls_memory_buffer_alloc_free_and_self_test( int verbose )
+{
+    if( verbose != 0 )
+    {
+#if defined(MBEDTLS_MEMORY_DEBUG)
+        mbedtls_memory_buffer_alloc_status( );
+#endif
+    }
+    mbedtls_memory_buffer_alloc_free( );
+    return( mbedtls_memory_buffer_alloc_self_test( verbose ) );
+}
+#endif
+
+typedef struct
+{
+    const char *name;
+    int ( *function )( int );
+} selftest_t;
+
+const selftest_t selftests[] =
+{
+#if defined(MBEDTLS_MD2_C)
+    {"md2", mbedtls_md2_self_test},
+#endif
+#if defined(MBEDTLS_MD4_C)
+    {"md4", mbedtls_md4_self_test},
+#endif
+#if defined(MBEDTLS_MD5_C)
+    {"md5", mbedtls_md5_self_test},
+#endif
+#if defined(MBEDTLS_RIPEMD160_C)
+    {"ripemd160", mbedtls_ripemd160_self_test},
+#endif
+#if defined(MBEDTLS_SHA1_C)
+    {"sha1", mbedtls_sha1_self_test},
+#endif
+#if defined(MBEDTLS_SHA256_C)
+    {"sha256", mbedtls_sha256_self_test},
+#endif
+#if defined(MBEDTLS_SHA512_C)
+    {"sha512", mbedtls_sha512_self_test},
+#endif
+#if defined(MBEDTLS_ARC4_C)
+    {"arc4", mbedtls_arc4_self_test},
+#endif
+#if defined(MBEDTLS_DES_C)
+    {"des", mbedtls_des_self_test},
+#endif
+#if defined(MBEDTLS_AES_C)
+    {"aes", mbedtls_aes_self_test},
+#endif
+#if defined(MBEDTLS_GCM_C) && defined(MBEDTLS_AES_C)
+    {"gcm", mbedtls_gcm_self_test},
+#endif
+#if defined(MBEDTLS_CCM_C) && defined(MBEDTLS_AES_C)
+    {"ccm", mbedtls_ccm_self_test},
+#endif
+#if defined(MBEDTLS_BASE64_C)
+    {"base64", mbedtls_base64_self_test},
+#endif
+#if defined(MBEDTLS_BIGNUM_C)
+    {"mpi", mbedtls_mpi_self_test},
+#endif
+#if defined(MBEDTLS_RSA_C)
+    {"rsa", mbedtls_rsa_self_test},
+#endif
+#if defined(MBEDTLS_X509_USE_C)
+    {"x509", mbedtls_x509_self_test},
+#endif
+#if defined(MBEDTLS_XTEA_C)
+    {"xtea", mbedtls_xtea_self_test},
+#endif
+#if defined(MBEDTLS_CAMELLIA_C)
+    {"camellia", mbedtls_camellia_self_test},
+#endif
+#if defined(MBEDTLS_CTR_DRBG_C)
+    {"ctr_drbg", mbedtls_ctr_drbg_self_test},
+#endif
+#if defined(MBEDTLS_HMAC_DRBG_C)
+    {"hmac_drbg", mbedtls_hmac_drbg_self_test},
+#endif
+#if defined(MBEDTLS_ECP_C)
+    {"ecp", mbedtls_ecp_self_test},
+#endif
+#if defined(MBEDTLS_DHM_C)
+    {"dhm", mbedtls_dhm_self_test},
+#endif
+#if defined(MBEDTLS_ENTROPY_C)
+    {"entropy", mbedtls_entropy_self_test},
+#endif
+#if defined(MBEDTLS_PKCS5_C)
+    {"pkcs5", mbedtls_pkcs5_self_test},
+#endif
+/* Slower test after the faster ones */
+#if defined(MBEDTLS_TIMING_C)
+    {"timing", mbedtls_timing_self_test},
+#endif
+/* Heap test comes last */
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
+    {"memory_buffer_alloc", mbedtls_memory_buffer_alloc_free_and_self_test},
+#endif
+    {NULL, NULL}
+};
+#endif /* MBEDTLS_SELF_TEST */
+
 int main( int argc, char *argv[] )
 {
-    int ret = 0, v;
-#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
+#if defined(MBEDTLS_SELF_TEST)
+    const selftest_t *test;
+#endif /* MBEDTLS_SELF_TEST */
+    char **argp;
+    int v = 1; /* v=1 for verbose mode */
+    int exclude_mode = 0;
+    int suites_tested = 0, suites_failed = 0;
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) && defined(MBEDTLS_SELF_TEST)
     unsigned char buf[1000000];
 #endif
     void *pointer;
@@ -113,7 +227,7 @@
     if( pointer != NULL )
     {
         mbedtls_printf( "all-bits-zero is not a NULL pointer\n" );
-        return( 1 );
+        return( EXIT_FAILURE );
     }
 
     /*
@@ -122,176 +236,112 @@
     if( run_test_snprintf() != 0 )
     {
         mbedtls_printf( "the snprintf implementation is broken\n" );
-        return( 0 );
+        return( EXIT_FAILURE );
     }
 
-    if( argc == 2 && strcmp( argv[1], "-quiet" ) == 0 )
-        v = 0;
-    else
+    for( argp = argv + ( argc >= 1 ? 1 : argc ); *argp != NULL; ++argp )
     {
-        v = 1;
-        mbedtls_printf( "\n" );
+        if( strcmp( *argp, "--quiet" ) == 0 ||
+            strcmp( *argp, "-quiet" ) == 0 ||
+            strcmp( *argp, "-q" ) == 0 )
+        {
+            v = 0;
+        }
+        else if( strcmp( *argp, "--exclude" ) == 0 ||
+                 strcmp( *argp, "-x" ) == 0 )
+        {
+            exclude_mode = 1;
+        }
+        else
+            break;
     }
 
+    if( v != 0 )
+        mbedtls_printf( "\n" );
+
 #if defined(MBEDTLS_SELF_TEST)
 
 #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
     mbedtls_memory_buffer_alloc_init( buf, sizeof(buf) );
 #endif
 
-#if defined(MBEDTLS_MD2_C)
-    if( ( ret = mbedtls_md2_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_MD4_C)
-    if( ( ret = mbedtls_md4_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_MD5_C)
-    if( ( ret = mbedtls_md5_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_RIPEMD160_C)
-    if( ( ret = mbedtls_ripemd160_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_SHA1_C)
-    if( ( ret = mbedtls_sha1_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_SHA256_C)
-    if( ( ret = mbedtls_sha256_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_SHA512_C)
-    if( ( ret = mbedtls_sha512_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_ARC4_C)
-    if( ( ret = mbedtls_arc4_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_DES_C)
-    if( ( ret = mbedtls_des_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_AES_C)
-    if( ( ret = mbedtls_aes_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_GCM_C) && defined(MBEDTLS_AES_C)
-    if( ( ret = mbedtls_gcm_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_CCM_C) && defined(MBEDTLS_AES_C)
-    if( ( ret = mbedtls_ccm_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_BASE64_C)
-    if( ( ret = mbedtls_base64_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_BIGNUM_C)
-    if( ( ret = mbedtls_mpi_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_RSA_C)
-    if( ( ret = mbedtls_rsa_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_X509_USE_C)
-    if( ( ret = mbedtls_x509_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_XTEA_C)
-    if( ( ret = mbedtls_xtea_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_CAMELLIA_C)
-    if( ( ret = mbedtls_camellia_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_CTR_DRBG_C)
-    if( ( ret = mbedtls_ctr_drbg_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_HMAC_DRBG_C)
-    if( ( ret = mbedtls_hmac_drbg_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_ECP_C)
-    if( ( ret = mbedtls_ecp_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_DHM_C)
-    if( ( ret = mbedtls_dhm_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_ENTROPY_C)
-    if( ( ret = mbedtls_entropy_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-#if defined(MBEDTLS_PKCS5_C)
-    if( ( ret = mbedtls_pkcs5_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-/* Slow tests last */
-
-#if defined(MBEDTLS_TIMING_C)
-    if( ( ret = mbedtls_timing_self_test( v ) ) != 0 )
-        return( ret );
-#endif
+    if( *argp != NULL && exclude_mode == 0 )
+    {
+        /* Run the specified tests */
+        for( ; *argp != NULL; argp++ )
+        {
+            for( test = selftests; test->name != NULL; test++ )
+            {
+                if( !strcmp( *argp, test->name ) )
+                {
+                    if( test->function( v )  != 0 )
+                    {
+                        suites_failed++;
+                    }
+                    suites_tested++;
+                    break;
+                }
+            }
+            if( test->name == NULL )
+            {
+                mbedtls_printf( "  Test suite %s not available -> failed\n\n", *argp );
+                suites_failed++;
+            }
+        }
+    }
+    else
+    {
+        /* Run all the tests except excluded ones */
+        for( test = selftests; test->name != NULL; test++ )
+        {
+            if( exclude_mode )
+            {
+                char **excluded;
+                for( excluded = argp; *excluded != NULL; ++excluded )
+                {
+                    if( !strcmp( *excluded, test->name ) )
+                        break;
+                }
+                if( *excluded )
+                {
+                    if( v )
+                        mbedtls_printf( "  Skip: %s\n", test->name );
+                    continue;
+                }
+            }
+            if( test->function( v )  != 0 )
+            {
+                suites_failed++;
+            }
+            suites_tested++;
+        }
+    }
 
 #else
+    (void) exclude_mode;
     mbedtls_printf( " MBEDTLS_SELF_TEST not defined.\n" );
 #endif
 
     if( v != 0 )
     {
-#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) && defined(MBEDTLS_MEMORY_DEBUG)
-        mbedtls_memory_buffer_alloc_status();
-#endif
-    }
+        mbedtls_printf( "  Executed %d test suites\n\n", suites_tested );
 
-#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
-    mbedtls_memory_buffer_alloc_free();
-
-    if( ( ret = mbedtls_memory_buffer_alloc_self_test( v ) ) != 0 )
-        return( ret );
-#endif
-
-    if( v != 0 )
-    {
-        mbedtls_printf( "  [ All tests passed ]\n\n" );
+        if( suites_failed > 0)
+        {
+            mbedtls_printf( "  [ %d tests FAILED ]\n\n", suites_failed );
+        }
+        else
+        {
+            mbedtls_printf( "  [ All tests passed ]\n\n" );
+        }
 #if defined(_WIN32)
         mbedtls_printf( "  Press Enter to exit this program.\n" );
         fflush( stdout ); getchar();
 #endif
     }
 
-    return( ret );
+    if( suites_failed > 0)
+        return( EXIT_FAILURE );
+
+    return( EXIT_SUCCESS );
 }
diff --git a/scripts/config.pl b/scripts/config.pl
index d8d6a20..1464813 100755
--- a/scripts/config.pl
+++ b/scripts/config.pl
@@ -1,13 +1,51 @@
 #!/usr/bin/perl
-
-# Tune the configuration file
+#
+# This file is part of mbed TLS (https://tls.mbed.org)
+#
+# Copyright (c) 2014-2016, ARM Limited, All Rights Reserved
+#
+# Purpose
+#
+# Comments and uncomments #define lines in the given header file and optionally
+# sets their value or can get the value. This is to provide scripting control of
+# what preprocessor symbols, and therefore what build time configuration flags
+# are set in the 'config.h' file.
+#
+# Usage: config.pl [-f <file> | --file <file>] [-o | --force]
+#                   [set <symbol> <value> | unset <symbol> | get <symbol> |
+#                       full | realfull]
+#
+# Full usage description provided below.
+#
+# Things that shouldn't be enabled with "full".
+#
+#   MBEDTLS_TEST_NULL_ENTROPY
+#   MBEDTLS_DEPRECATED_REMOVED
+#   MBEDTLS_HAVE_SSE2
+#   MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
+#   MBEDTLS_ECP_DP_M221_ENABLED
+#   MBEDTLS_ECP_DP_M383_ENABLED
+#   MBEDTLS_ECP_DP_M511_ENABLED
+#   MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
+#   MBEDTLS_NO_PLATFORM_ENTROPY
+#   MBEDTLS_REMOVE_ARC4_CIPHERSUITES
+#   MBEDTLS_SSL_HW_RECORD_ACCEL
+#   MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3
+#   MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
+#       - this could be enabled if the respective tests were adapted
+#   MBEDTLS_ZLIB_SUPPORT
+#   MBEDTLS_PKCS11_C
+#   and any symbol beginning _ALT
+#
 
 use warnings;
 use strict;
 
 my $config_file = "include/mbedtls/config.h";
 my $usage = <<EOU;
-$0 [-f <file>] [set <symbol> <value> | unset <symbol> | full | realfull]
+$0 [-f <file> | --file <file>] [-o | --force]
+                   [set <symbol> <value> | unset <symbol> | get <symbol> |
+                        full | realfull | baremetal]
 
 Commands
     set <symbol> [<value>]  - Uncomments or adds a #define for the <symbol> to
@@ -17,25 +55,27 @@
                               is returned.
     unset <symbol>          - Comments out the #define for the given symbol if
                               present in the configuration file.
+    get <symbol>            - Finds the #define for the given symbol, returning
+                              an exitcode of 0 if the symbol is found, and 1 if
+                              not. The value of the symbol is output if one is
+                              specified in the configuration file.
     full                    - Uncomments all #define's in the configuration file
                               excluding some reserved symbols, until the
                               'Module configuration options' section
     realfull                - Uncomments all #define's with no exclusions
+    baremetal               - Sets full configuration suitable for baremetal build.
 
 Options
-    -f <filename>           - The file or file path for the configuration file
+    -f | --file <filename>  - The file or file path for the configuration file
                               to edit. When omitted, the following default is
                               used:
                                 $config_file
-EOU
-# for our eyes only:
-# $0 [-f <file>] full|realfull
+    -o | --force            - If the symbol isn't present in the configuration
+                              file when setting its value, a #define is
+                              appended to the end of the file.
 
-# Things that shouldn't be enabled with "full".
-# Notes:
-# - MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 and
-#   MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION could be enabled if the
-#   respective tests were adapted
+EOU
+
 my @excluded = qw(
 MBEDTLS_DEPRECATED_REMOVED
 MBEDTLS_HAVE_SSE2
@@ -54,49 +94,107 @@
 _ALT\s*$
 );
 
+# Things that should be disabled in "baremetal"
+my @excluded_baremetal = qw(
+MBEDTLS_NET_C
+MBEDTLS_TIMING_C
+MBEDTLS_FS_IO
+MBEDTLS_ENTROPY_NV_SEED
+MBEDTLS_HAVE_TIME
+MBEDTLS_HAVE_TIME_DATE
+MBEDTLS_DEPRECATED_WARNING
+MBEDTLS_HAVEGE_C
+MBEDTLS_THREADING_C
+MBEDTLS_THREADING_PTHREAD
+MBEDTLS_MEMORY_BACKTRACE
+MBEDTLS_MEMORY_BUFFER_ALLOC_C
+MBEDTLS_PLATFORM_TIME_ALT
+MBEDTLS_PLATFORM_FPRINTF_ALT
+);
+
 # Things that should be enabled in "full" even if they match @excluded
 my @non_excluded = qw(
 PLATFORM_[A-Z0-9]+_ALT
 );
 
-# get -f option
-if (@ARGV >= 2 && $ARGV[0] eq "-f") {
-    shift; # -f
-    $config_file = shift;
+# Things that should be enabled in "baremetal"
+my @non_excluded_baremetal = qw(
+MBEDTLS_NO_PLATFORM_ENTROPY
+);
 
-    -f $config_file or die "No such file: $config_file\n";
-} else {
-    if (! -f $config_file)  {
-        chdir '..' or die;
-        -f $config_file
-            or die "Without -f, must be run from root or scripts\n"
+# Process the command line arguments
+
+my $force_option = 0;
+
+my ($arg, $name, $value, $action);
+
+while ($arg = shift) {
+
+    # Check if the argument is an option
+    if ($arg eq "-f" || $arg eq "--file") {
+        $config_file = shift;
+
+        -f $config_file or die "No such file: $config_file\n";
+
+    }
+    elsif ($arg eq "-o" || $arg eq "--force") {
+        $force_option = 1;
+
+    }
+    else
+    {
+        # ...else assume it's a command
+        $action = $arg;
+
+        if ($action eq "full" || $action eq "realfull" || $action eq "baremetal" ) {
+            # No additional parameters
+            die $usage if @ARGV;
+
+        }
+        elsif ($action eq "unset" || $action eq "get") {
+            die $usage unless @ARGV;
+            $name = shift;
+
+        }
+        elsif ($action eq "set") {
+            die $usage unless @ARGV;
+            $name = shift;
+            $value = shift if @ARGV;
+
+        }
+        else {
+            die "Command '$action' not recognised.\n\n".$usage;
+        }
     }
 }
 
-# get action
-die $usage unless @ARGV;
-my $action = shift;
+# If no command was specified, exit...
+if ( not defined($action) ){ die $usage; }
 
-my ($name, $value);
-if ($action eq "full" || $action eq "realfull") {
-    # nothing to do
-} elsif ($action eq "unset") {
-    die $usage unless @ARGV;
-    $name = shift;
-} elsif ($action eq "set") {
-    die $usage unless @ARGV;
-    $name = shift;
-    $value = shift if @ARGV;
-} else {
-    die $usage;
+# Check the config file is present
+if (! -f $config_file)  {
+
+    chdir '..' or die;
+
+    # Confirm this is the project root directory and try again
+    if ( !(-d 'scripts' && -d 'include' && -d 'library' && -f $config_file) ) {
+        die "If no file specified, must be run from the project root or scripts directory.\n";
+    }
 }
-die $usage if @ARGV;
+
+
+# Now read the file and process the contents
 
 open my $config_read, '<', $config_file or die "read $config_file: $!\n";
 my @config_lines = <$config_read>;
 close $config_read;
 
-my ($exclude_re, $no_exclude_re);
+# Add required baremetal symbols to the list that is included.
+if ( $action eq "baremetal" ) {
+    @non_excluded = ( @non_excluded, @non_excluded_baremetal );
+}
+
+my ($exclude_re, $no_exclude_re, $exclude_baremetal_re);
 if ($action eq "realfull") {
     $exclude_re = qr/^$/;
     $no_exclude_re = qr/./;
@@ -104,22 +202,30 @@
     $exclude_re = join '|', @excluded;
     $no_exclude_re = join '|', @non_excluded;
 }
+if ( $action eq "baremetal" ) {
+    $exclude_baremetal_re = join '|', @excluded_baremetal;
+}
 
-open my $config_write, '>', $config_file or die "write $config_file: $!\n";
+my $config_write = undef;
+if ($action ne "get") {
+    open $config_write, '>', $config_file or die "write $config_file: $!\n";
+}
 
 my $done;
 for my $line (@config_lines) {
-    if ($action eq "full" || $action eq "realfull") {
+    if ($action eq "full" || $action eq "realfull" || $action eq "baremetal" ) {
         if ($line =~ /name SECTION: Module configuration options/) {
             $done = 1;
         }
 
         if (!$done && $line =~ m!^//\s?#define! &&
-                ( $line !~ /$exclude_re/ || $line =~ /$no_exclude_re/ ) ) {
+                ( $line !~ /$exclude_re/ || $line =~ /$no_exclude_re/ ) &&
+                ( $action ne "baremetal" || ( $line !~ /$exclude_baremetal_re/ ) ) ) {
             $line =~ s!^//\s?!!;
         }
         if (!$done && $line =~ m!^\s?#define! &&
-                ! ( $line !~ /$exclude_re/ || $line =~ /$no_exclude_re/ ) ) {
+                ! ( ( $line !~ /$exclude_re/ || $line =~ /$no_exclude_re/ ) &&
+                    ( $action ne "baremetal" || ( $line !~ /$exclude_baremetal_re/ ) ) ) ) {
             $line =~ s!^!//!;
         }
     } elsif ($action eq "unset") {
@@ -134,14 +240,53 @@
             $line .= "\n";
             $done = 1;
         }
+    } elsif (!$done && $action eq "get") {
+        if ($line =~ /^\s*#define\s*$name(?:\s+(.*?))\s*(?:$|\/\*|\/\/)/) {
+            $value = $1;
+            $done = 1;
+        }
     }
 
-    print $config_write $line;
+    if (defined $config_write) {
+        print $config_write $line or die "write $config_file: $!\n";
+    }
 }
 
-close $config_write;
+# Did the set command work?
+if ($action eq "set" && $force_option && !$done) {
 
-die "configuration section not found" if ($action eq "full" && !$done);
-die "$name not found" if ($action ne "full" && !$done);
+    # If the force option was set, append the symbol to the end of the file
+    my $line = "#define $name";
+    $line .= " $value" if defined $value && $value ne "";
+    $line .= "\n";
+    $done = 1;
+
+    print $config_write $line or die "write $config_file: $!\n";
+}
+
+if (defined $config_write) {
+    close $config_write or die "close $config_file: $!\n";
+}
+
+if ($action eq "get") {
+    if ($done) {
+        if ($value ne '') {
+            print "$value\n";
+        }
+        exit 0;
+    } else {
+        # If the symbol was not found, return an error
+        exit 1;
+    }
+}
+
+if ($action eq "full" && !$done) {
+    die "Configuration section was not found in $config_file\n";
+
+}
+
+if ($action ne "full" && $action ne "unset" && !$done) {
+    die "A #define for the symbol $name was not found in $config_file\n";
+}
 
 __END__
diff --git a/tests/compat.sh b/tests/compat.sh
index 6d79520..8f864ad 100755
--- a/tests/compat.sh
+++ b/tests/compat.sh
@@ -857,6 +857,33 @@
     fi
 }
 
+# Wait for process $2 to be listening on port $1
+if type lsof >/dev/null 2>/dev/null; then
+    wait_server_start() {
+        START_TIME=$(date +%s)
+        if is_dtls "$MODE"; then
+            proto=UDP
+        else
+            proto=TCP
+        fi
+        while ! lsof -a -n -b -i "$proto:$1" -p "$2" >/dev/null 2>/dev/null; do
+              if [ $(( $(date +%s) - $START_TIME )) -gt $DOG_DELAY ]; then
+                  echo "SERVERSTART TIMEOUT"
+                  echo "SERVERSTART TIMEOUT" >> $SRV_OUT
+                  break
+              fi
+              # Linux and *BSD support decimal arguments to sleep. On other
+              # OSes this may be a tight loop.
+              sleep 0.1 2>/dev/null || true
+        done
+    }
+else
+    wait_server_start() {
+        sleep 1
+    }
+fi
+
+
 # start_server <name>
 # also saves name and command
 start_server() {
@@ -886,7 +913,7 @@
     while :; do echo bla; sleep 1; done | $SERVER_CMD >> $SRV_OUT 2>&1 &
     PROCESS_ID=$!
 
-    sleep 1
+    wait_server_start "$PORT" "$PROCESS_ID"
 }
 
 # terminate the running server
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 9e87f71..9dc75e1 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -232,40 +232,32 @@
     fi
 }
 
-# wait for server to start: two versions depending on lsof availability
-wait_server_start() {
-    if which lsof >/dev/null 2>&1; then
-        START_TIME=$( date +%s )
-        DONE=0
-
-        # make a tight loop, server usually takes less than 1 sec to start
+# Wait for process $2 to be listening on port $1
+if type lsof >/dev/null 2>/dev/null; then
+    wait_server_start() {
+        START_TIME=$(date +%s)
         if [ "$DTLS" -eq 1 ]; then
-            while [ $DONE -eq 0 ]; do
-                if lsof -nbi UDP:"$SRV_PORT" 2>/dev/null | grep UDP >/dev/null
-                then
-                    DONE=1
-                elif [ $(( $( date +%s ) - $START_TIME )) -gt $DOG_DELAY ]; then
-                    echo "SERVERSTART TIMEOUT"
-                    echo "SERVERSTART TIMEOUT" >> $SRV_OUT
-                    DONE=1
-                fi
-            done
+            proto=UDP
         else
-            while [ $DONE -eq 0 ]; do
-                if lsof -nbi TCP:"$SRV_PORT" 2>/dev/null | grep LISTEN >/dev/null
-                then
-                    DONE=1
-                elif [ $(( $( date +%s ) - $START_TIME )) -gt $DOG_DELAY ]; then
-                    echo "SERVERSTART TIMEOUT"
-                    echo "SERVERSTART TIMEOUT" >> $SRV_OUT
-                    DONE=1
-                fi
-            done
+            proto=TCP
         fi
-    else
+        # Make a tight loop, server normally takes less than 1s to start.
+        while ! lsof -a -n -b -i "$proto:$1" -p "$2" >/dev/null 2>/dev/null; do
+              if [ $(( $(date +%s) - $START_TIME )) -gt $DOG_DELAY ]; then
+                  echo "SERVERSTART TIMEOUT"
+                  echo "SERVERSTART TIMEOUT" >> $SRV_OUT
+                  break
+              fi
+              # Linux and *BSD support decimal arguments to sleep. On other
+              # OSes this may be a tight loop.
+              sleep 0.1 2>/dev/null || true
+        done
+    }
+else
+    wait_server_start() {
         sleep "$START_DELAY"
-    fi
-}
+    }
+fi
 
 # wait for client to terminate and set CLI_EXIT
 # must be called right after starting the client
@@ -373,7 +365,7 @@
         echo "$SRV_CMD" > $SRV_OUT
         provide_input | $SRV_CMD >> $SRV_OUT 2>&1 &
         SRV_PID=$!
-        wait_server_start
+        wait_server_start "$SRV_PORT" "$SRV_PID"
 
         echo "$CLI_CMD" > $CLI_OUT
         eval "$CLI_CMD" >> $CLI_OUT 2>&1 &