Merge tests for asn1write, XTEA and Entropy modules
diff --git a/include/polarssl/dhm.h b/include/polarssl/dhm.h
index 628cd62..c6c2d8f 100644
--- a/include/polarssl/dhm.h
+++ b/include/polarssl/dhm.h
@@ -43,6 +43,8 @@
 #define POLARSSL_ERR_DHM_FILE_IO_ERROR                     -0x3480  /**< Read/write of file failed. */
 
 /**
+ * RFC 2409 defines a number of standardized Diffie-Hellman groups
+ * that can be used.
  * RFC 3526 defines a number of standardized Diffie-Hellman groups
  * for IKE.
  * RFC 5114 defines a number of standardized Diffie-Hellman groups
@@ -51,11 +53,22 @@
  * Some are included here for convenience.
  *
  * Included are:
+ *  RFC 2409 6.2.  1024-bit MODP Group (Second Oakley Group)
  *  RFC 3526 3.    2048-bit MODP Group
  *  RFC 3526 4.    3072-bit MODP Group
  *  RFC 5114 2.1.  1024-bit MODP Group with 160-bit Prime Order Subgroup
  *  RFC 5114 2.2.  2048-bit MODP Group with 224-bit Prime Order Subgroup
  */
+#define POLARSSL_DHM_RFC2409_MODP_1024_P               \
+    "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
+    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
+    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
+    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
+    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" \
+    "FFFFFFFFFFFFFFFF"
+
+#define POLARSSL_DHM_RFC2409_MODP_1024_G          "02"
+
 #define POLARSSL_DHM_RFC3526_MODP_2048_P               \
     "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
     "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index 4cbd162..2e202de 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -1,5 +1,6 @@
 option(USE_STATIC_POLARSSL_LIBRARY "Build PolarSSL static library." ON)
 option(USE_SHARED_POLARSSL_LIBRARY "Build PolarSSL shared library." OFF)
+option(LINK_WITH_PTHREAD "Explicitly link PolarSSL library to pthread." OFF)
 
 set(src
      aes.c
@@ -102,6 +103,9 @@
 		target_link_libraries(${polarssl_static_target} ${ZLIB_LIBRARIES})
 	endif(ZLIB_FOUND)
 
+	if(LINK_WITH_PTHREAD)
+        target_link_libraries(${polarssl_static_target} pthread)
+	endif()
 
 	install(TARGETS ${polarssl_static_target}
 			DESTINATION ${LIB_INSTALL_DIR}
@@ -118,6 +122,10 @@
 		target_link_libraries(polarssl ${ZLIB_LIBRARIES})
 	endif(ZLIB_FOUND)
 
+	if(LINK_WITH_PTHREAD)
+        target_link_libraries(polarssl pthread)
+	endif()
+
 	install(TARGETS polarssl
 			DESTINATION ${LIB_INSTALL_DIR}
 			PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
diff --git a/library/aes.c b/library/aes.c
index ca5c906..c03cbbe 100644
--- a/library/aes.c
+++ b/library/aes.c
@@ -565,10 +565,6 @@
                 RK[15] = RK[7] ^ RK[14];
             }
             break;
-
-        default:
-
-            break;
     }
 
     return( 0 );
@@ -586,14 +582,6 @@
     uint32_t *SK;
     int ret;
 
-    switch( keysize )
-    {
-        case 128: ctx->nr = 10; break;
-        case 192: ctx->nr = 12; break;
-        case 256: ctx->nr = 14; break;
-        default : return( POLARSSL_ERR_AES_INVALID_KEY_LENGTH );
-    }
-
 #if defined(POLARSSL_PADLOCK_C) && defined(PADLOCK_ALIGN16)
     if( aes_padlock_ace == -1 )
         aes_padlock_ace = padlock_supports( PADLOCK_ACE );
@@ -604,10 +592,12 @@
 #endif
     ctx->rk = RK = ctx->buf;
 
-    ret = aes_setkey_enc( &cty, key, keysize );
-    if( ret != 0 )
+    /* Also checks keysize */
+    if( ( ret = aes_setkey_enc( &cty, key, keysize ) ) != 0 )
         return( ret );
 
+    ctx->nr = cty.nr;
+
 #if defined(POLARSSL_AESNI_C) && defined(POLARSSL_HAVE_X86_64)
     if( aesni_supports( POLARSSL_AESNI_AES ) )
     {
diff --git a/library/camellia.c b/library/camellia.c
index 524e6ff..306be61 100644
--- a/library/camellia.c
+++ b/library/camellia.c
@@ -435,20 +435,14 @@
     uint32_t *SK;
     int ret;
 
-    switch( keysize )
-    {
-        case 128: ctx->nr = 3; idx = 0; break;
-        case 192:
-        case 256: ctx->nr = 4; idx = 1; break;
-        default : return( POLARSSL_ERR_CAMELLIA_INVALID_KEY_LENGTH );
-    }
-
-    RK = ctx->rk;
-
-    ret = camellia_setkey_enc(&cty, key, keysize);
-    if( ret != 0 )
+    /* Also checks keysize */
+    if( ( ret = camellia_setkey_enc(&cty, key, keysize) ) )
         return( ret );
 
+    ctx->nr = cty.nr;
+    idx = ( ctx->nr == 4 );
+
+    RK = ctx->rk;
     SK = cty.rk + 24 * 2 + 8 * idx * 2;
 
     *RK++ = *SK++;
diff --git a/library/debug.c b/library/debug.c
index f2dd776..b747ddc 100644
--- a/library/debug.c
+++ b/library/debug.c
@@ -131,7 +131,7 @@
     if( debug_log_mode == POLARSSL_DEBUG_LOG_FULL )
         idx = snprintf( str, maxlen, "%s(%04d): ", file, line );
 
-    snprintf( str + idx, maxlen - idx, "dumping '%s' (%d bytes)\n",
+    snprintf( str + idx, maxlen - idx, "dumping '%s' (%u bytes)\n",
               text, (unsigned int) len );
 
     str[maxlen] = '\0';
diff --git a/library/des.c b/library/des.c
index 79c81bc..2f06af3 100644
--- a/library/des.c
+++ b/library/des.c
@@ -837,15 +837,12 @@
     int i, j, u, v;
     des_context ctx;
     des3_context ctx3;
-    unsigned char key[24];
     unsigned char buf[8];
 #if defined(POLARSSL_CIPHER_MODE_CBC)
     unsigned char prv[8];
     unsigned char iv[8];
 #endif
 
-    memset( key, 0, 24 );
-
     /*
      * ECB mode
      */
diff --git a/library/gcm.c b/library/gcm.c
index a892076..62fe185 100644
--- a/library/gcm.c
+++ b/library/gcm.c
@@ -195,7 +195,6 @@
                       unsigned char output[16] )
 {
     int i = 0;
-    unsigned char z[16];
     unsigned char lo, hi, rem;
     uint64_t zh, zl;
 
@@ -213,8 +212,6 @@
     }
 #endif /* POLARSSL_AESNI_C && POLARSSL_HAVE_X86_64 */
 
-    memset( z, 0x00, 16 );
-
     lo = x[15] & 0xf;
     hi = x[15] >> 4;
 
diff --git a/library/net.c b/library/net.c
index be30fbd..0866149 100644
--- a/library/net.c
+++ b/library/net.c
@@ -146,7 +146,7 @@
 
     if( wsa_init_done == 0 )
     {
-        if( WSAStartup( MAKEWORD(2,0), &wsaData ) == SOCKET_ERROR )
+        if( WSAStartup( MAKEWORD(2,0), &wsaData ) != 0 )
             return( POLARSSL_ERR_NET_SOCKET_FAILED );
 
         wsa_init_done = 1;
diff --git a/library/pem.c b/library/pem.c
index 2775ef9..3dd3b79 100644
--- a/library/pem.c
+++ b/library/pem.c
@@ -370,11 +370,8 @@
 
 void pem_free( pem_context *ctx )
 {
-    if( ctx->buf )
-        polarssl_free( ctx->buf );
-
-    if( ctx->info )
-        polarssl_free( ctx->info );
+    polarssl_free( ctx->buf );
+    polarssl_free( ctx->info );
 
     memset( ctx, 0, sizeof( pem_context ) );
 }
diff --git a/library/ssl_cache.c b/library/ssl_cache.c
index 9e49b9a..836b685 100644
--- a/library/ssl_cache.c
+++ b/library/ssl_cache.c
@@ -321,8 +321,7 @@
         ssl_session_free( &prv->session );
 
 #if defined(POLARSSL_X509_CRT_PARSE_C)
-        if( prv->peer_cert.p != NULL )
-            polarssl_free( prv->peer_cert.p );
+        polarssl_free( prv->peer_cert.p );
 #endif /* POLARSSL_X509_CRT_PARSE_C */
 
         polarssl_free( prv );
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index 5152895..53b3179 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -691,7 +691,7 @@
 static int ssl_parse_alpn_ext( ssl_context *ssl,
                                unsigned char *buf, size_t len )
 {
-    size_t list_len, cur_len;
+    size_t list_len, cur_len, ours_len;
     const unsigned char *theirs, *start, *end;
     const char **ours;
 
@@ -722,6 +722,7 @@
     end = buf + len;
     for( ours = ssl->alpn_list; *ours != NULL; ours++ )
     {
+        ours_len = strlen( *ours );
         for( theirs = start; theirs != end; theirs += cur_len )
         {
             /* If the list is well formed, we should get equality first */
@@ -734,7 +735,7 @@
             if( cur_len == 0 )
                 return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
 
-            if( cur_len == strlen( *ours ) &&
+            if( cur_len == ours_len &&
                 memcmp( theirs, *ours, cur_len ) == 0 )
             {
                 ssl->alpn_chosen = *ours;
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 8c29e21..2cd0cce 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -97,7 +97,7 @@
         x509_crt_init( dst->peer_cert );
 
         if( ( ret = x509_crt_parse( dst->peer_cert, src->peer_cert->raw.p,
-                                    src->peer_cert->raw.len ) != 0 ) )
+                                    src->peer_cert->raw.len ) ) != 0 )
         {
             polarssl_free( dst->peer_cert );
             dst->peer_cert = NULL;
@@ -1070,8 +1070,7 @@
 
         if( ssl->out_msglen != olen )
         {
-            SSL_DEBUG_MSG( 1, ( "total encrypted length incorrect %d %d",
-                                ssl->out_msglen, olen ) );
+            SSL_DEBUG_MSG( 1, ( "should never happen" ) );
             return( POLARSSL_ERR_SSL_INTERNAL_ERROR );
         }
     }
@@ -1146,8 +1145,7 @@
 
         if( olen != enc_msglen )
         {
-            SSL_DEBUG_MSG( 1, ( "total encrypted length incorrect %d %d",
-                                enc_msglen, olen ) );
+            SSL_DEBUG_MSG( 1, ( "should never happen" ) );
             return( POLARSSL_ERR_SSL_INTERNAL_ERROR );
         }
 
@@ -1225,8 +1223,7 @@
 
         if( enc_msglen != olen )
         {
-            SSL_DEBUG_MSG( 1, ( "total encrypted length incorrect %d %d",
-                                enc_msglen, olen ) );
+            SSL_DEBUG_MSG( 1, ( "should never happen" ) );
             return( POLARSSL_ERR_SSL_INTERNAL_ERROR );
         }
 
@@ -1308,7 +1305,7 @@
 
         if( ssl->in_msglen != olen )
         {
-            SSL_DEBUG_MSG( 1, ( "total encrypted length incorrect" ) );
+            SSL_DEBUG_MSG( 1, ( "should never happen" ) );
             return( POLARSSL_ERR_SSL_INTERNAL_ERROR );
         }
     }
@@ -1372,8 +1369,7 @@
 
         if( olen != dec_msglen )
         {
-            SSL_DEBUG_MSG( 1, ( "total decrypted length incorrect %d %d",
-                                dec_msglen, olen ) );
+            SSL_DEBUG_MSG( 1, ( "should never happen" ) );
             return( POLARSSL_ERR_SSL_INTERNAL_ERROR );
         }
     }
@@ -1448,7 +1444,7 @@
 
         if( dec_msglen != olen )
         {
-            SSL_DEBUG_MSG( 1, ( "total encrypted length incorrect" ) );
+            SSL_DEBUG_MSG( 1, ( "should never happen" ) );
             return( POLARSSL_ERR_SSL_INTERNAL_ERROR );
         }
 
diff --git a/library/timing.c b/library/timing.c
index 4b29d7e..fe741b9 100644
--- a/library/timing.c
+++ b/library/timing.c
@@ -337,6 +337,25 @@
 #endif
 
 /*
+ * Busy-waits for the given number of milliseconds.
+ * Used for testing hardclock.
+ */
+static void busy_msleep( unsigned long msec )
+{
+    struct hr_time hires;
+    unsigned long i = 0; /* for busy-waiting */
+    volatile unsigned long j; /* to prevent optimisation */
+
+    (void) get_timer( &hires, 1 );
+
+    while( get_timer( &hires, 0 ) < msec )
+        i++;
+
+    j = i;
+    (void) j;
+}
+
+/*
  * Checkup routine
  *
  * Warning: this is work in progress, some tests may not be reliable enough
@@ -350,7 +369,7 @@
     struct hr_time hires;
 
     if( verbose != 0)
-        polarssl_printf( "  TIMING tests warning: will take some time!\n" );
+        polarssl_printf( "  TIMING tests note: will take some time!\n" );
 
     if( verbose != 0 )
         polarssl_printf( "  TIMING test #1 (m_sleep   / get_timer): " );
@@ -401,7 +420,7 @@
         polarssl_printf( "passed\n" );
 
     if( verbose != 0 )
-        polarssl_printf( "  TIMING test #3 (hardclock / m_sleep  ): " );
+        polarssl_printf( "  TIMING test #3 (hardclock / get_timer): " );
 
     /*
      * Allow one failure for possible counter wrapping.
@@ -420,15 +439,17 @@
     }
 
     /* Get a reference ratio cycles/ms */
+    millisecs = 1;
     cycles = hardclock();
-    m_sleep( 1 );
+    busy_msleep( millisecs );
     cycles = hardclock() - cycles;
-    ratio = cycles / 1;
+    ratio = cycles / millisecs;
 
+    /* Check that the ratio is mostly constant */
     for( millisecs = 2; millisecs <= 4; millisecs++ )
     {
         cycles = hardclock();
-        m_sleep( millisecs );
+        busy_msleep( millisecs );
         cycles = hardclock() - cycles;
 
         /* Allow variation up to 20% */
@@ -443,9 +464,6 @@
     if( verbose != 0 )
         polarssl_printf( "passed\n" );
 
-    if( verbose != 0 )
-        polarssl_printf( "\n" );
-
 #if defined(POLARSSL_NET_C)
     if( verbose != 0 )
         polarssl_printf( "  TIMING test #4 (net_usleep/ get_timer): " );
@@ -471,6 +489,9 @@
         polarssl_printf( "passed\n" );
 #endif /* POLARSSL_NET_C */
 
+    if( verbose != 0 )
+        polarssl_printf( "\n" );
+
     return( 0 );
 }
 
diff --git a/library/x509_crt.c b/library/x509_crt.c
index 7946068..54e76db 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -1550,12 +1550,12 @@
 static int x509_wildcard_verify( const char *cn, x509_buf *name )
 {
     size_t i;
-    size_t cn_idx = 0;
+    size_t cn_idx = 0, cn_len = strlen( cn );
 
     if( name->len < 3 || name->p[0] != '*' || name->p[1] != '.' )
         return( 0 );
 
-    for( i = 0; i < strlen( cn ); ++i )
+    for( i = 0; i < cn_len; ++i )
     {
         if( cn[i] == '.' )
         {
@@ -1567,7 +1567,7 @@
     if( cn_idx == 0 )
         return( 0 );
 
-    if( strlen( cn ) - cn_idx == name->len - 1 &&
+    if( cn_len - cn_idx == name->len - 1 &&
         x509_name_cmp( name->p + 1, cn + cn_idx, name->len - 1 ) == 0 )
     {
         return( 1 );
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 06e4a16..8db6ddb 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -458,11 +458,9 @@
             opt.psk_identity = q;
         else if( strcmp( p, "force_ciphersuite" ) == 0 )
         {
-            opt.force_ciphersuite[0] = -1;
-
             opt.force_ciphersuite[0] = ssl_get_ciphersuite_id( q );
 
-            if( opt.force_ciphersuite[0] <= 0 )
+            if( opt.force_ciphersuite[0] == 0 )
             {
                 ret = 2;
                 goto usage;
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 2b6e426..9f53ad2 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -77,7 +77,9 @@
 #define DFL_KEY_FILE2           ""
 #define DFL_PSK                 ""
 #define DFL_PSK_IDENTITY        "Client_identity"
+#define DFL_PSK_LIST            NULL
 #define DFL_FORCE_CIPHER        0
+#define DFL_VERSION_SUITES      NULL
 #define DFL_RENEGOTIATION       SSL_RENEGOTIATION_DISABLED
 #define DFL_ALLOW_LEGACY        SSL_LEGACY_NO_RENEGOTIATION
 #define DFL_RENEGOTIATE         0
@@ -91,6 +93,7 @@
 #define DFL_CACHE_TIMEOUT       -1
 #define DFL_SNI                 NULL
 #define DFL_ALPN_STRING         NULL
+#define DFL_DHM_FILE            NULL
 
 #define LONG_RESPONSE "<p>01-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \
     "02-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n"  \
@@ -107,6 +110,16 @@
     "<h2>PolarSSL Test Server</h2>\r\n" \
     "<p>Successful connection using: %s</p>\r\n" // LONG_RESPONSE
 
+#define MAX_PSK_LEN     256
+
+/*
+ * Size of the basic I/O buffer. Able to hold our default response.
+ *
+ * You will need to adapt the ssl_get_bytes_avail() test in ssl-opt.sh
+ * if you change this value to something outside the range <= 100 or > 500
+ */
+#define IO_BUF_LEN      200
+
 /*
  * global options
  */
@@ -124,7 +137,9 @@
     const char *key_file2;      /* the file with the 2nd server key         */
     const char *psk;            /* the pre-shared key                       */
     const char *psk_identity;   /* the pre-shared key identity              */
+    char *psk_list;             /* list of PSK id/key pairs for callback    */
     int force_ciphersuite[2];   /* protocol/ciphersuite to use, or all      */
+    const char *version_suites; /* per-version ciphersuites                 */
     int renegotiation;          /* enable / disable renegotiation           */
     int allow_legacy;           /* allow legacy renegotiation               */
     int renegotiate;            /* attempt renegotiation?                   */
@@ -138,6 +153,7 @@
     int cache_timeout;          /* expiration delay of session cache entries */
     char *sni;                  /* string describing sni information        */
     const char *alpn_string;    /* ALPN supported protocols                 */
+    const char *dhm_file;       /* the file with the DH parameters          */
 } opt;
 
 static void my_debug( void *ctx, int level, const char *str )
@@ -200,7 +216,9 @@
     "                        default: see note after key_file2\n" \
     "    key_file2=%%s        default: see note below\n" \
     "                        note: if neither crt_file/key_file nor crt_file2/key_file2 are used,\n" \
-    "                              preloaded certificate(s) and key(s) are used if available\n"
+    "                              preloaded certificate(s) and key(s) are used if available\n" \
+    "    dhm_file=%%s        File containing Diffie-Hellman parameters\n" \
+    "                       default: preloaded parameters\n"
 #else
 #define USAGE_IO \
     "\n"                                                    \
@@ -286,9 +304,12 @@
     "    min_version=%%s      default: \"ssl3\"\n"          \
     "    max_version=%%s      default: \"tls1_2\"\n"        \
     "    force_version=%%s    default: \"\" (none)\n"       \
-    "                        options: ssl3, tls1, tls1_1, tls1_2\n" \
-    "\n"                                                    \
-    "    force_ciphersuite=<name>    default: all enabled\n"\
+    "                        options: ssl3, tls1, tls1_1, tls1_2\n"     \
+    "\n"                                                                \
+    "    version_suites=a,b,c,d      per-version ciphersuites\n"        \
+    "                                in order from ssl3 to tls1_2\n"    \
+    "                                default: all enabled\n"            \
+    "    force_ciphersuite=<name>    default: all enabled\n"            \
     " acceptable ciphersuite names:\n"
 
 #if !defined(POLARSSL_ENTROPY_C) ||  \
@@ -306,6 +327,16 @@
 }
 #else
 
+/*
+ * Used by sni_parse and psk_parse to handle coma-separated lists
+ */
+#define GET_ITEM( dst )         \
+    dst = p;                    \
+    while( *p != ',' )          \
+        if( ++p > end )         \
+            return( NULL );     \
+    *p++ = '\0';
+
 #if defined(POLARSSL_SNI)
 typedef struct _sni_entry sni_entry;
 
@@ -320,8 +351,8 @@
  * Parse a string of triplets name1,crt1,key1[,name2,crt2,key2[,...]]
  * into a usable sni_entry list.
  *
- * Note: this is not production quality: leaks memory if parsing fails,
- * and error reporting is poor.
+ * Modifies the input string! This is not production quality!
+ * (leaks memory if parsing fails, no error reporting, ...)
  */
 sni_entry *sni_parse( char *sni_string )
 {
@@ -343,44 +374,21 @@
 
         if( ( new->cert = polarssl_malloc( sizeof( x509_crt ) ) ) == NULL ||
             ( new->key = polarssl_malloc( sizeof( pk_context ) ) ) == NULL )
-        {
-            cur = NULL;
-            goto exit;
-        }
+            return( NULL );
 
         x509_crt_init( new->cert );
         pk_init( new->key );
 
-        new->name = p;
-        while( *p != ',' ) if( ++p > end ) { cur = NULL; goto exit; }
-        *p++ = '\0';
-
-        crt_file = p;
-        while( *p != ',' ) if( ++p > end ) { cur = NULL; goto exit; }
-        *p++ = '\0';
-
-        key_file = p;
-        while( *p != ',' ) if( ++p > end ) { cur = NULL; goto exit; }
-        *p++ = '\0';
+        GET_ITEM( new->name );
+        GET_ITEM( crt_file );
+        GET_ITEM( key_file );
 
         if( x509_crt_parse_file( new->cert, crt_file ) != 0 ||
             pk_parse_keyfile( new->key, key_file, "" ) != 0 )
-        {
-            cur = NULL;
-            goto exit;
-        }
+            return( NULL );
 
         new->next = cur;
         cur = new;
-        new = NULL;
-    }
-
-exit:
-    if( new != NULL )
-    {
-        x509_crt_free( new->cert);
-        pk_free( new->key );
-        polarssl_free( new );
     }
 
     return( cur );
@@ -429,15 +437,144 @@
 
 #endif /* POLARSSL_SNI */
 
+#if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED)
+
+#define HEX2NUM( c )                    \
+        if( c >= '0' && c <= '9' )      \
+            c -= '0';                   \
+        else if( c >= 'a' && c <= 'f' ) \
+            c -= 'a' - 10;              \
+        else if( c >= 'A' && c <= 'F' ) \
+            c -= 'A' - 10;              \
+        else                            \
+            return( -1 );
+
+/*
+ * Convert a hex string to bytes.
+ * Return 0 on success, -1 on error.
+ */
+int unhexify( unsigned char *output, const char *input, size_t *olen )
+{
+    unsigned char c;
+    size_t j;
+
+    *olen = strlen( input );
+    if( *olen % 2 != 0 || *olen / 2 > MAX_PSK_LEN )
+        return( -1 );
+    *olen /= 2;
+
+    for( j = 0; j < *olen * 2; j += 2 )
+    {
+        c = input[j];
+        HEX2NUM( c );
+        output[ j / 2 ] = c << 4;
+
+        c = input[j + 1];
+        HEX2NUM( c );
+        output[ j / 2 ] |= c;
+    }
+
+    return( 0 );
+}
+
+typedef struct _psk_entry psk_entry;
+
+struct _psk_entry
+{
+    const char *name;
+    size_t key_len;
+    unsigned char key[MAX_PSK_LEN];
+    psk_entry *next;
+};
+
+/*
+ * Parse a string of pairs name1,key1[,name2,key2[,...]]
+ * into a usable psk_entry list.
+ *
+ * Modifies the input string! This is not production quality!
+ * (leaks memory if parsing fails, no error reporting, ...)
+ */
+psk_entry *psk_parse( char *psk_string )
+{
+    psk_entry *cur = NULL, *new = NULL;
+    char *p = psk_string;
+    char *end = p;
+    char *key_hex;
+
+    while( *end != '\0' )
+        ++end;
+    *end = ',';
+
+    while( p <= end )
+    {
+        if( ( new = polarssl_malloc( sizeof( psk_entry ) ) ) == NULL )
+            return( NULL );
+
+        memset( new, 0, sizeof( psk_entry ) );
+
+        GET_ITEM( new->name );
+        GET_ITEM( key_hex );
+
+        if( unhexify( new->key, key_hex, &new->key_len ) != 0 )
+            return( NULL );
+
+        new->next = cur;
+        cur = new;
+    }
+
+    return( cur );
+}
+
+/*
+ * Free a list of psk_entry's
+ */
+void psk_free( psk_entry *head )
+{
+    psk_entry *next;
+
+    while( head != NULL )
+    {
+        next = head->next;
+        polarssl_free( head );
+        head = next;
+    }
+}
+
+/*
+ * PSK callback
+ */
+int psk_callback( void *p_info, ssl_context *ssl,
+                  const unsigned char *name, size_t name_len )
+{
+    psk_entry *cur = (psk_entry *) p_info;
+
+    while( cur != NULL )
+    {
+        if( name_len == strlen( cur->name ) &&
+            memcmp( name, cur->name, name_len ) == 0 )
+        {
+            return( ssl_set_psk( ssl, cur->key, cur->key_len,
+                                 name, name_len ) );
+        }
+
+        cur = cur->next;
+    }
+
+    return( -1 );
+}
+#endif /* POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED */
+
 int main( int argc, char *argv[] )
 {
     int ret = 0, len, written, frags;
     int listen_fd;
     int client_fd = -1;
-    unsigned char buf[SSL_MAX_CONTENT_LEN + 1];
+    int version_suites[4][2];
+    unsigned char buf[IO_BUF_LEN];
 #if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED)
-    unsigned char psk[256];
+    unsigned char psk[MAX_PSK_LEN];
     size_t psk_len = 0;
+    psk_entry *psk_info;
 #endif
     const char *pers = "ssl_server2";
 
@@ -452,6 +589,9 @@
     pk_context pkey2;
     int key_cert_init = 0, key_cert_init2 = 0;
 #endif
+#if defined(POLARSSL_DHM_C) && defined(POLARSSL_FS_IO)
+    dhm_context dhm;
+#endif
 #if defined(POLARSSL_SSL_CACHE_C)
     ssl_cache_context cache;
 #endif
@@ -485,6 +625,9 @@
     x509_crt_init( &srvcert2 );
     pk_init( &pkey2 );
 #endif
+#if defined(POLARSSL_DHM_C) && defined(POLARSSL_FS_IO)
+    memset( &dhm, 0, sizeof( dhm_context ) );
+#endif
 #if defined(POLARSSL_SSL_CACHE_C)
     ssl_cache_init( &cache );
 #endif
@@ -526,7 +669,9 @@
     opt.key_file2           = DFL_KEY_FILE2;
     opt.psk                 = DFL_PSK;
     opt.psk_identity        = DFL_PSK_IDENTITY;
+    opt.psk_list            = DFL_PSK_LIST;
     opt.force_ciphersuite[0]= DFL_FORCE_CIPHER;
+    opt.version_suites      = DFL_VERSION_SUITES;
     opt.renegotiation       = DFL_RENEGOTIATION;
     opt.allow_legacy        = DFL_ALLOW_LEGACY;
     opt.renegotiate         = DFL_RENEGOTIATE;
@@ -540,6 +685,7 @@
     opt.cache_timeout       = DFL_CACHE_TIMEOUT;
     opt.sni                 = DFL_SNI;
     opt.alpn_string         = DFL_ALPN_STRING;
+    opt.dhm_file            = DFL_DHM_FILE;
 
     for( i = 1; i < argc; i++ )
     {
@@ -580,23 +726,27 @@
             opt.crt_file2 = q;
         else if( strcmp( p, "key_file2" ) == 0 )
             opt.key_file2 = q;
+        else if( strcmp( p, "dhm_file" ) == 0 )
+            opt.dhm_file = q;
         else if( strcmp( p, "psk" ) == 0 )
             opt.psk = q;
         else if( strcmp( p, "psk_identity" ) == 0 )
             opt.psk_identity = q;
+        else if( strcmp( p, "psk_list" ) == 0 )
+            opt.psk_list = q;
         else if( strcmp( p, "force_ciphersuite" ) == 0 )
         {
-            opt.force_ciphersuite[0] = -1;
-
             opt.force_ciphersuite[0] = ssl_get_ciphersuite_id( q );
 
-            if( opt.force_ciphersuite[0] <= 0 )
+            if( opt.force_ciphersuite[0] == 0 )
             {
                 ret = 2;
                 goto usage;
             }
             opt.force_ciphersuite[1] = 0;
         }
+        else if( strcmp( p, "version_suites" ) == 0 )
+            opt.version_suites = q;
         else if( strcmp( p, "renegotiation" ) == 0 )
         {
             opt.renegotiation = (atoi( q )) ? SSL_RENEGOTIATION_ENABLED :
@@ -754,52 +904,63 @@
             opt.min_version = ciphersuite_info->min_minor_ver;
     }
 
-#if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED)
-    /*
-     * Unhexify the pre-shared key if any is given
-     */
-    if( strlen( opt.psk ) )
+    if( opt.version_suites != NULL )
     {
-        unsigned char c;
-        size_t j;
+        const char *name[4] = { 0 };
 
-        if( strlen( opt.psk ) % 2 != 0 )
+        /* Parse 4-element coma-separated list */
+        for( i = 0, p = (char *) opt.version_suites;
+             i < 4 && *p != '\0';
+             i++ )
         {
-            printf("pre-shared key not valid hex\n");
+            name[i] = p;
+
+            /* Terminate the current string and move on to next one */
+            while( *p != ',' && *p != '\0' )
+                p++;
+            if( *p == ',' )
+                *p++ = '\0';
+        }
+
+        if( i != 4 )
+        {
+            printf( "too few values for version_suites\n" );
+            ret = 1;
             goto exit;
         }
 
-        psk_len = strlen( opt.psk ) / 2;
+        memset( version_suites, 0, sizeof( version_suites ) );
 
-        for( j = 0; j < strlen( opt.psk ); j += 2 )
+        /* Get the suites identifiers from their name */
+        for( i = 0; i < 4; i++ )
         {
-            c = opt.psk[j];
-            if( c >= '0' && c <= '9' )
-                c -= '0';
-            else if( c >= 'a' && c <= 'f' )
-                c -= 'a' - 10;
-            else if( c >= 'A' && c <= 'F' )
-                c -= 'A' - 10;
-            else
-            {
-                printf("pre-shared key not valid hex\n");
-                goto exit;
-            }
-            psk[ j / 2 ] = c << 4;
+            version_suites[i][0] = ssl_get_ciphersuite_id( name[i] );
 
-            c = opt.psk[j + 1];
-            if( c >= '0' && c <= '9' )
-                c -= '0';
-            else if( c >= 'a' && c <= 'f' )
-                c -= 'a' - 10;
-            else if( c >= 'A' && c <= 'F' )
-                c -= 'A' - 10;
-            else
+            if( version_suites[i][0] == 0 )
             {
-                printf("pre-shared key not valid hex\n");
-                goto exit;
+                printf( "unknown ciphersuite: '%s'\n", name[i] );
+                ret = 2;
+                goto usage;
             }
-            psk[ j / 2 ] |= c;
+        }
+    }
+
+#if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED)
+    /*
+     * Unhexify the pre-shared key and parse the list if any given
+     */
+    if( unhexify( psk, opt.psk, &psk_len ) != 0 )
+    {
+        printf( "pre-shared key not valid hex\n" );
+        goto exit;
+    }
+
+    if( opt.psk_list != NULL )
+    {
+        if( ( psk_info = psk_parse( opt.psk_list ) ) == NULL )
+        {
+            printf( "psk_list invalid" );
+            goto exit;
         }
     }
 #endif /* POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED */
@@ -988,6 +1149,23 @@
     printf( " ok\n" );
 #endif /* POLARSSL_X509_CRT_PARSE_C */
 
+#if defined(POLARSSL_DHM_C) && defined(POLARSSL_FS_IO)
+    if( opt.dhm_file != NULL )
+    {
+        printf( "  . Loading DHM parameters..." );
+        fflush( stdout );
+
+        if( ( ret = dhm_parse_dhmfile( &dhm, opt.dhm_file ) ) != 0 )
+        {
+            printf( " failed\n  ! dhm_parse_dhmfile returned -0x%04X\n\n",
+                     -ret );
+            goto exit;
+        }
+
+        printf( " ok\n" );
+    }
+#endif
+
 #if defined(POLARSSL_SNI)
     if( opt.sni != NULL )
     {
@@ -1067,6 +1245,22 @@
     if( opt.force_ciphersuite[0] != DFL_FORCE_CIPHER )
         ssl_set_ciphersuites( &ssl, opt.force_ciphersuite );
 
+    if( opt.version_suites != NULL )
+    {
+        ssl_set_ciphersuites_for_version( &ssl, version_suites[0],
+                                          SSL_MAJOR_VERSION_3,
+                                          SSL_MINOR_VERSION_0 );
+        ssl_set_ciphersuites_for_version( &ssl, version_suites[1],
+                                          SSL_MAJOR_VERSION_3,
+                                          SSL_MINOR_VERSION_1 );
+        ssl_set_ciphersuites_for_version( &ssl, version_suites[2],
+                                          SSL_MAJOR_VERSION_3,
+                                          SSL_MINOR_VERSION_2 );
+        ssl_set_ciphersuites_for_version( &ssl, version_suites[3],
+                                          SSL_MAJOR_VERSION_3,
+                                          SSL_MINOR_VERSION_3 );
+    }
+
     ssl_set_renegotiation( &ssl, opt.renegotiation );
     ssl_legacy_renegotiation( &ssl, opt.allow_legacy );
 
@@ -1088,16 +1282,39 @@
 #endif
 
 #if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED)
-    ssl_set_psk( &ssl, psk, psk_len, (const unsigned char *) opt.psk_identity,
-                 strlen( opt.psk_identity ) );
+    if( strlen( opt.psk ) != 0 && strlen( opt.psk_identity ) != 0 )
+    {
+        ret = ssl_set_psk( &ssl, psk, psk_len,
+                           (const unsigned char *) opt.psk_identity,
+                           strlen( opt.psk_identity ) );
+        if( ret != 0 )
+        {
+            printf( "  failed\n  ssl_set_psk returned -0x%04X\n\n", - ret );
+            goto exit;
+        }
+    }
+
+    if( opt.psk_list != NULL )
+        ssl_set_psk_cb( &ssl, psk_callback, psk_info );
 #endif
 
 #if defined(POLARSSL_DHM_C)
     /*
      * Use different group than default DHM group
      */
-    ssl_set_dh_param( &ssl, POLARSSL_DHM_RFC5114_MODP_2048_P,
-                            POLARSSL_DHM_RFC5114_MODP_2048_G );
+#if defined(POLARSSL_FS_IO)
+    if( opt.dhm_file != NULL )
+        ret = ssl_set_dh_param_ctx( &ssl, &dhm );
+    else
+#endif
+        ret = ssl_set_dh_param( &ssl, POLARSSL_DHM_RFC5114_MODP_2048_P,
+                                      POLARSSL_DHM_RFC5114_MODP_2048_G );
+
+    if( ret != 0 )
+    {
+        printf( "  failed\n  ssl_set_dh_param returned -0x%04X\n\n", - ret );
+        goto exit;
+    }
 #endif
 
     if( opt.min_version != -1 )
@@ -1252,9 +1469,48 @@
             break;
         }
 
-        len = ret;
-        buf[len] = '\0';
-        printf( " %d bytes read\n\n%s\n", len, (char *) buf );
+        if( ssl_get_bytes_avail( &ssl ) == 0 )
+        {
+            len = ret;
+            buf[len] = '\0';
+            printf( " %d bytes read\n\n%s\n", len, (char *) buf );
+        }
+        else
+        {
+            int extra_len, ori_len;
+            unsigned char *larger_buf;
+
+            ori_len = ret;
+            extra_len = ssl_get_bytes_avail( &ssl );
+
+            larger_buf = polarssl_malloc( ori_len + extra_len + 1 );
+            if( larger_buf == NULL )
+            {
+                printf( "  ! memory allocation failed\n" );
+                ret = 1;
+                goto exit;
+            }
+
+            memset( larger_buf, 0, ori_len + extra_len );
+            memcpy( larger_buf, buf, ori_len );
+
+            /* This read should never fail and get the whole cached data */
+            ret = ssl_read( &ssl, larger_buf + ori_len, extra_len );
+            if( ret != extra_len ||
+                ssl_get_bytes_avail( &ssl ) != 0 )
+            {
+                printf( "  ! ssl_read failed on cached data\n" );
+                ret = 1;
+                goto exit;
+            }
+
+            larger_buf[ori_len + extra_len] = '\0';
+            printf( " %u bytes read (%u + %u)\n\n%s\n",
+                    ori_len + extra_len, ori_len, extra_len, (char *) buf );
+
+            polarssl_free( larger_buf );
+        }
+
 
         if( memcmp( buf, "SERVERQUIT", 10 ) == 0 )
         {
diff --git a/programs/test/selftest.c b/programs/test/selftest.c
index edb1331..0210a19 100644
--- a/programs/test/selftest.c
+++ b/programs/test/selftest.c
@@ -211,10 +211,7 @@
 #endif
 #endif
 
-/*
- * Not reliable enough yet
- */
-#if 0 && defined(POLARSSL_TIMING_C)
+#if defined(POLARSSL_TIMING_C)
     if( ( ret = timing_self_test( v ) ) != 0 )
         return( ret );
 #endif
diff --git a/programs/x509/cert_app.c b/programs/x509/cert_app.c
index 72618e6..e558da2 100644
--- a/programs/x509/cert_app.c
+++ b/programs/x509/cert_app.c
@@ -65,6 +65,7 @@
 #define DFL_MODE                MODE_NONE
 #define DFL_FILENAME            "cert.crt"
 #define DFL_CA_FILE             ""
+#define DFL_CRL_FILE            ""
 #define DFL_CA_PATH             ""
 #define DFL_SERVER_NAME         "localhost"
 #define DFL_SERVER_PORT         4433
@@ -79,6 +80,7 @@
     int mode;                   /* the mode to run the application in   */
     const char *filename;       /* filename of the certificate file     */
     const char *ca_file;        /* the file with the CA certificate(s)  */
+    const char *crl_file;       /* the file with the CRL to use         */
     const char *ca_path;        /* the path with the CA certificate(s) reside */
     const char *server_name;    /* hostname of the server (client only) */
     int server_port;            /* port on which the ssl service runs   */
@@ -134,6 +136,8 @@
 #define USAGE_IO \
     "    ca_file=%%s          The single file containing the top-level CA(s) you fully trust\n" \
     "                        default: \"\" (none)\n" \
+    "    crl_file=%%s         The single CRL file you want to use\n" \
+    "                        default: \"\" (none)\n" \
     "    ca_path=%%s          The path containing the top-level CA(s) you fully trust\n" \
     "                        default: \"\" (none) (overrides ca_file)\n"
 
@@ -158,6 +162,7 @@
     ssl_context ssl;
     x509_crt cacert;
     x509_crt clicert;
+    x509_crl cacrl;
     pk_context pkey;
     int i, j;
     int flags, verify = 0;
@@ -170,6 +175,7 @@
     server_fd = 0;
     x509_crt_init( &cacert );
     x509_crt_init( &clicert );
+    x509_crl_init( &cacrl );
     pk_init( &pkey );
 
     if( argc == 0 )
@@ -182,6 +188,7 @@
     opt.mode                = DFL_MODE;
     opt.filename            = DFL_FILENAME;
     opt.ca_file             = DFL_CA_FILE;
+    opt.crl_file            = DFL_CRL_FILE;
     opt.ca_path             = DFL_CA_PATH;
     opt.server_name         = DFL_SERVER_NAME;
     opt.server_port         = DFL_SERVER_PORT;
@@ -214,6 +221,8 @@
             opt.filename = q;
         else if( strcmp( p, "ca_file" ) == 0 )
             opt.ca_file = q;
+        else if( strcmp( p, "crl_file" ) == 0 )
+            opt.crl_file = q;
         else if( strcmp( p, "ca_path" ) == 0 )
             opt.ca_path = q;
         else if( strcmp( p, "server_name" ) == 0 )
@@ -265,6 +274,18 @@
 
     printf( " ok (%d skipped)\n", ret );
 
+    if( strlen( opt.crl_file ) )
+    {
+        ret = x509_crl_parse_file( &cacrl, opt.crl_file );
+        verify = 1;
+    }
+
+    if( ret < 0 )
+    {
+        printf( " failed\n  !  x509_crl_parse returned -0x%x\n\n", -ret );
+        goto exit;
+    }
+
     if( opt.mode == MODE_FILE )
     {
         x509_crt crt;
@@ -322,7 +343,7 @@
         {
             printf( "  . Verifying X.509 certificate..." );
 
-            if( ( ret = x509_crt_verify( &crt, &cacert, NULL, NULL, &flags,
+            if( ( ret = x509_crt_verify( &crt, &cacert, &cacrl, NULL, &flags,
                                          my_verify, NULL ) ) != 0 )
             {
                 printf( " failed\n" );
@@ -452,6 +473,7 @@
         net_close( server_fd );
     x509_crt_free( &cacert );
     x509_crt_free( &clicert );
+    x509_crl_free( &cacrl );
     pk_free( &pkey );
     entropy_free( &entropy );
 
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 44904fa..b8a125c 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -99,7 +99,7 @@
     file(TO_NATIVE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/data_files" target)
 
     if (NOT EXISTS ${link})
-        if (UNIX)
+        if (CMAKE_HOST_UNIX)
             set(command ln -s ${target} ${link})
         else()
             set(command cmd.exe /c mklink ${link} ${target})
diff --git a/tests/compat.sh b/tests/compat.sh
index 724311c..06243bd 100755
--- a/tests/compat.sh
+++ b/tests/compat.sh
@@ -645,14 +645,14 @@
             exit 1;
     esac
 
-    P_SERVER_ARGS="server_addr=0.0.0.0 force_version=$MODE"
-    O_SERVER_ARGS="-www -cipher NULL,ALL -$MODE"
-    G_SERVER_ARGS="-p 4433 --http"
+    P_SERVER_ARGS="server_port=$PORT server_addr=0.0.0.0 force_version=$MODE"
+    O_SERVER_ARGS="-accept $PORT -www -cipher NULL,ALL -$MODE"
+    G_SERVER_ARGS="-p $PORT --http"
     G_SERVER_PRIO="EXPORT:+NULL:+MD5:+PSK:+DHE-PSK:+ECDHE-PSK:+RSA-PSK:-VERS-TLS-ALL:$G_PRIO_MODE"
 
-    P_CLIENT_ARGS="force_version=$MODE"
-    O_CLIENT_ARGS="-$MODE"
-    G_CLIENT_ARGS="-p 4433 --debug 3"
+    P_CLIENT_ARGS="server_port=$PORT force_version=$MODE"
+    O_CLIENT_ARGS="-connect localhost:$PORT -$MODE"
+    G_CLIENT_ARGS="-p $PORT --debug 3"
     G_CLIENT_PRIO="NONE:$G_PRIO_MODE:+COMP-NULL:+CURVE-ALL:+SIGN-ALL"
 
     if [ "X$VERIFY" = "XYES" ];
@@ -757,8 +757,8 @@
     SERVER_NAME=$1
 
     log "$SERVER_CMD"
-    echo "$SERVER_CMD" > srv_out
-    $SERVER_CMD >> srv_out 2>&1 &
+    echo "$SERVER_CMD" > $SRV_OUT
+    $SERVER_CMD >> $SRV_OUT 2>&1 &
     PROCESS_ID=$!
 
     sleep 1
@@ -768,6 +768,10 @@
 stop_server() {
     case $SERVER_NAME in
         [Pp]olar*)
+            # start watchdog in case SERVERQUIT fails
+            ( sleep 20; echo "SERVERQUIT TIMEOUT"; kill $MAIN_PID ) &
+            WATCHDOG_PID=$!
+
             # we must force a PSK suite when in PSK mode (otherwise client
             # auth will fail), so try every entry in $P_CIPHERS in turn (in
             # case the first one is not implemented in this configuration)
@@ -779,27 +783,31 @@
                     break
                 fi
             done
+
+            wait $PROCESS_ID 2>/dev/null
+            kill $WATCHDOG_PID 2>/dev/null
+            wait $WATCHDOG_PID 2>/dev/null
             ;;
         *)
             kill $PROCESS_ID 2>/dev/null
+            wait $PROCESS_ID 2>/dev/null
     esac
 
-    wait $PROCESS_ID 2>/dev/null
 
     if [ "$MEMCHECK" -gt 0 ]; then
-        if is_polar "$SERVER_CMD" && has_mem_err srv_out; then
+        if is_polar "$SERVER_CMD" && has_mem_err $SRV_OUT; then
             echo "  ! Server had memory errors"
             let "srvmem++"
             return
         fi
     fi
 
-    rm -f srv_out
+    rm -f $SRV_OUT
 }
 
 # kill the running server (used when killed by signal)
 cleanup() {
-    rm -f srv_out cli_out
+    rm -f $SRV_OUT $CLI_OUT
     kill $PROCESS_ID
     exit 1
 }
@@ -820,14 +828,14 @@
         [Oo]pen*)
             CLIENT_CMD="$OPENSSL_CMD s_client $O_CLIENT_ARGS -cipher $2"
             log "$CLIENT_CMD"
-            echo "$CLIENT_CMD" > cli_out
-            ( echo -e 'GET HTTP/1.0'; echo; ) | $CLIENT_CMD >> cli_out 2>&1
+            echo "$CLIENT_CMD" > $CLI_OUT
+            ( echo -e 'GET HTTP/1.0'; echo; ) | $CLIENT_CMD >> $CLI_OUT 2>&1
             EXIT=$?
 
             if [ "$EXIT" == "0" ]; then
                 RESULT=0
             else
-                if grep 'Cipher is (NONE)' cli_out >/dev/null; then
+                if grep 'Cipher is (NONE)' $CLI_OUT >/dev/null; then
                     RESULT=1
                 else
                     RESULT=2
@@ -838,8 +846,8 @@
         [Gg]nu*)
             CLIENT_CMD="$GNUTLS_CLI $G_CLIENT_ARGS --priority $G_PRIO_MODE:$2 localhost"
             log "$CLIENT_CMD"
-            echo "$CLIENT_CMD" > cli_out
-            ( echo -e 'GET HTTP/1.0'; echo; ) | $CLIENT_CMD >> cli_out 2>&1
+            echo "$CLIENT_CMD" > $CLI_OUT
+            ( echo -e 'GET HTTP/1.0'; echo; ) | $CLIENT_CMD >> $CLI_OUT 2>&1
             EXIT=$?
 
             if [ "$EXIT" == "0" ]; then
@@ -848,8 +856,8 @@
                 RESULT=2
                 # interpret early failure, with a handshake_failure alert
                 # before the server hello, as "no ciphersuite in common"
-                if grep -F 'Received alert [40]: Handshake failed' cli_out; then
-                    if grep -i 'SERVER HELLO .* was received' cli_out; then :
+                if grep -F 'Received alert [40]: Handshake failed' $CLI_OUT; then
+                    if grep -i 'SERVER HELLO .* was received' $CLI_OUT; then :
                     else
                         RESULT=1
                     fi
@@ -863,8 +871,8 @@
                 CLIENT_CMD="valgrind --leak-check=full $CLIENT_CMD"
             fi
             log "$CLIENT_CMD"
-            echo "$CLIENT_CMD" > cli_out
-            $CLIENT_CMD >> cli_out 2>&1
+            echo "$CLIENT_CMD" > $CLI_OUT
+            $CLIENT_CMD >> $CLI_OUT 2>&1
             EXIT=$?
 
             case $EXIT in
@@ -874,7 +882,7 @@
             esac
 
             if [ "$MEMCHECK" -gt 0 ]; then
-                if is_polar "$CLIENT_CMD" && has_mem_err cli_out; then
+                if is_polar "$CLIENT_CMD" && has_mem_err $CLI_OUT; then
                     RESULT=2
                 fi
             fi
@@ -887,7 +895,7 @@
             ;;
     esac
 
-    echo "EXIT: $EXIT" >> cli_out
+    echo "EXIT: $EXIT" >> $CLI_OUT
 
     # report and count result
     case $RESULT in
@@ -900,14 +908,14 @@
             ;;
         "2")
             echo FAIL
-            cp srv_out c-srv-${tests}.log
-            cp cli_out c-cli-${tests}.log
+            cp $SRV_OUT c-srv-${tests}.log
+            cp $CLI_OUT c-cli-${tests}.log
             echo "  ! outputs saved to c-srv-${tests}.log, c-cli-${tests}.log"
             let "failed++"
             ;;
     esac
 
-    rm -f cli_out
+    rm -f $CLI_OUT
 }
 
 #
@@ -952,7 +960,17 @@
     esac
 done
 
-killall -q gnutls-serv openssl ssl_server ssl_server2
+# used by watchdog
+MAIN_PID="$$"
+
+# Pick a "unique" port in the range 10000-19999.
+PORT="0000$$"
+PORT="1$(echo $PORT | tail -c 4)"
+
+# Also pick a unique name for intermediate files
+SRV_OUT="srv_out.$$"
+CLI_OUT="cli_out.$$"
+
 trap cleanup INT TERM HUP
 
 for VERIFY in $VERIFIES; do
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 1e11d78..d01dc25 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -6,8 +6,8 @@
 # CMake configuration. After this script is run, the CMake cache is lost and
 # CMake is not initialised any more!
 #
-# Assumes gcc, clang (recent enough for using ASan) are available, as weel as
-# cmake. Also assumes valgrind is available if --memcheck is used.
+# Assumes gcc and clang (recent enough for using ASan) are available,
+# as well as cmake and valgrind.
 
 # Abort on errors (and uninitiliased variables)
 set -eu
@@ -54,54 +54,72 @@
     echo "******************************************************************"
 }
 
-# Step 1: various build types
+# The test ordering tries to optimize for the following criteria:
+# 1. Catch possible problems early, by running first test that run quickly
+#    and/or are more likely to fail than others.
+# 2. Minimize total running time, by avoiding useless rebuilds
+#
+# Indicative running times are given for reference.
 
-msg "Unix make, default compiler and flags"
-cleanup
-make
-
-msg "cmake, gcc with lots of warnings"
+msg "build: cmake, gcc with lots of warnings" # ~ 1 min
 cleanup
 CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Check .
 make
 
-msg "cmake, clang with lots of warnings"
+msg "test: main suites with valgrind" # ~ 2 min 10s
+make memcheck
+
+msg "build: with ASan" # ~ 1 min
+cleanup
+cmake -D CMAKE_BUILD_TYPE:String=ASan .
+make
+
+msg "test: ssl-opt.sh (ASan build)" # ~ 1 min 10s
+cd tests
+./ssl-opt.sh
+cd ..
+
+msg "test: main suites and selftest (ASan build)" # ~ 10s + 30s
+make test
+programs/test/selftest
+
+msg "test: ref-configs (ASan build)" # ~ 4 min 45 s
+tests/scripts/test-ref-configs.pl
+
+# Most issues are likely to be caught at this point
+
+msg "build: with ASan (rebuild after ref-configs)" # ~ 1 min
+make
+
+msg "test: compat.sh (ASan build)" # ~ 7 min 30s
+cd tests
+./compat.sh
+cd ..
+
+msg "build: cmake, clang with lots of warnings" # ~ 40s
 cleanup
 CC=clang cmake -D CMAKE_BUILD_TYPE:String=Check .
 make
 
-# Step 2: Full tests, with ASan
-
-msg "ASan build and full tests"
+msg "build: Unix make, -O2" # ~ 30s
 cleanup
-cmake -D CMAKE_BUILD_TYPE:String=ASan .
 make
-make test
-programs/test/selftest
-cd tests
-./compat.sh
-./ssl-opt.sh
-cd ..
-tests/scripts/test-ref-configs.pl
 
-# Step 3: using valgrind's memcheck
-
-msg "Release build, test suites with valgrind's memcheck"
-cleanup
-# optimized build to compensate a bit for valgrind slowdown
-cmake -D CMAKE_BUILD_TYPE:String=Release .
-make
-make memcheck
+# Optional parts that take a long time to run
 
 if [ "$MEMORY" -gt 0 ]; then
+    msg "test: ssl-opt --memcheck (-02 build)" # ~ 8 min
     cd tests
     ./ssl-opt.sh --memcheck
-    [ "$MEMORY" -gt 1 ] && ./compat.sh --memcheck
     cd ..
-    # no test-ref-configs: doesn't have a memcheck option (yet?)
-fi
 
-# Done
+    if [ "$MEMORY" -gt 1 ]; then
+        msg "test: compat --memcheck (-02 build)" # ~ 42 min
+        cd tests
+        ./compat.sh --memcheck
+        cd ..
+    fi
+fi
 
 echo "Done."
 cleanup
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index f4fbc01..5104712 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -89,8 +89,8 @@
     echo "FAIL"
     echo "  ! $1"
 
-    cp srv_out o-srv-${TESTS}.log
-    cp cli_out o-cli-${TESTS}.log
+    cp $SRV_OUT o-srv-${TESTS}.log
+    cp $CLI_OUT o-cli-${TESTS}.log
     echo "  ! outputs saved to o-srv-${TESTS}.log and o-cli-${TESTS}.log"
 
     FAILS=`echo $FAILS + 1 | bc`
@@ -112,6 +112,28 @@
     fi
 }
 
+# wait for server to be ready
+wait_srv_ready() {
+    if is_polar "$SRV_CMD"; then
+        READY_MSG="Waiting for a remote connection"
+    else
+        READY_MSG="ACCEPT"
+    fi
+
+    # If the server isn't ready after 10 secs, something probably went wrong
+    ( sleep 10; echo "SERVERSTART TIMEOUT"; kill $MAIN_PID ) &
+    WATCHDOG_PID=$!
+
+    while ! grep "$READY_MSG" $SRV_OUT >/dev/null; do
+        # don't use sleep, since the whole goal is to avoid wasting time,
+        # and 1 second is usually way more than the server needs to start
+        true
+    done
+
+    kill $WATCHDOG_PID
+    wait $WATCHDOG_PID
+}
+
 # Usage: run_test name srv_cmd cli_cmd cli_exit [option [...]]
 # Options:  -s pattern  pattern that must be present in server output
 #           -c pattern  pattern that must be present in client output
@@ -142,38 +164,46 @@
     fi
 
     # run the commands
-    echo "$SRV_CMD" > srv_out
-    $SRV_CMD >> srv_out 2>&1 &
+    echo "$SRV_CMD" > $SRV_OUT
+    $SRV_CMD >> $SRV_OUT 2>&1 &
     SRV_PID=$!
-    sleep 1
-    echo "$CLI_CMD" > cli_out
-    eval "$CLI_CMD" >> cli_out 2>&1
+    wait_srv_ready
+    echo "$CLI_CMD" > $CLI_OUT
+    eval "$CLI_CMD" >> $CLI_OUT 2>&1
     CLI_EXIT=$?
-    echo "EXIT: $CLI_EXIT" >> cli_out
+    echo "EXIT: $CLI_EXIT" >> $CLI_OUT
 
-    # psk is useful when server only has bad certs
     if is_polar "$SRV_CMD"; then
-        "$P_CLI" request_page=SERVERQUIT tickets=0 auth_mode=none psk=abc123 \
+        # start watchdog in case SERVERQUIT fails
+        ( sleep 10; echo "SERVERQUIT TIMEOUT"; kill $MAIN_PID ) &
+        WATCHDOG_PID=$!
+
+        # psk is useful when server only has bad certs
+        $P_CLI request_page=SERVERQUIT tickets=0 auth_mode=none psk=abc123 \
             crt_file=data_files/cli2.crt key_file=data_files/cli2.key \
             >/dev/null
+
+        wait $SRV_PID
+        kill $WATCHDOG_PID
+        wait $WATCHDOG_PID
     else
         kill $SRV_PID
+        wait $SRV_PID
     fi
-    wait $SRV_PID
 
     # check if the client and server went at least to the handshake stage
     # (useful to avoid tests with only negative assertions and non-zero
     # expected client exit to incorrectly succeed in case of catastrophic
     # failure)
     if is_polar "$SRV_CMD"; then
-        if grep "Performing the SSL/TLS handshake" srv_out >/dev/null; then :;
+        if grep "Performing the SSL/TLS handshake" $SRV_OUT >/dev/null; then :;
         else
             fail "server failed to start"
             return
         fi
     fi
     if is_polar "$CLI_CMD"; then
-        if grep "Performing the SSL/TLS handshake" cli_out >/dev/null; then :;
+        if grep "Performing the SSL/TLS handshake" $CLI_OUT >/dev/null; then :;
         else
             fail "client failed to start"
             return
@@ -199,28 +229,28 @@
     do
         case $1 in
             "-s")
-                if grep "$2" srv_out >/dev/null; then :; else
+                if grep "$2" $SRV_OUT >/dev/null; then :; else
                     fail "-s $2"
                     return
                 fi
                 ;;
 
             "-c")
-                if grep "$2" cli_out >/dev/null; then :; else
+                if grep "$2" $CLI_OUT >/dev/null; then :; else
                     fail "-c $2"
                     return
                 fi
                 ;;
 
             "-S")
-                if grep "$2" srv_out >/dev/null; then
+                if grep "$2" $SRV_OUT >/dev/null; then
                     fail "-S $2"
                     return
                 fi
                 ;;
 
             "-C")
-                if grep "$2" cli_out >/dev/null; then
+                if grep "$2" $CLI_OUT >/dev/null; then
                     fail "-C $2"
                     return
                 fi
@@ -235,11 +265,11 @@
 
     # check valgrind's results
     if [ "$MEMCHECK" -gt 0 ]; then
-        if is_polar "$SRV_CMD" && has_mem_err srv_out; then
+        if is_polar "$SRV_CMD" && has_mem_err $SRV_OUT; then
             fail "Server has memory errors"
             return
         fi
-        if is_polar "$CLI_CMD" && has_mem_err cli_out; then
+        if is_polar "$CLI_CMD" && has_mem_err $CLI_OUT; then
             fail "Client has memory errors"
             return
         fi
@@ -247,11 +277,11 @@
 
     # if we're here, everything is ok
     echo "PASS"
-    rm -f srv_out cli_out
+    rm -f $SRV_OUT $CLI_OUT
 }
 
 cleanup() {
-    rm -f cli_out srv_out sess
+    rm -f $CLI_OUT $SRV_OUT $SESSION
     kill $SRV_PID
     exit 1
 }
@@ -276,7 +306,24 @@
     exit 1
 fi
 
-killall -q openssl ssl_server ssl_server2
+# used by watchdog
+MAIN_PID="$$"
+
+# Pick a "unique" port in the range 10000-19999.
+PORT="0000$$"
+PORT="1$(echo $PORT | tail -c 4)"
+
+# fix commands to use this port
+P_SRV="$P_SRV server_port=$PORT"
+P_CLI="$P_CLI server_port=$PORT"
+O_SRV="$O_SRV -accept $PORT"
+O_CLI="$O_CLI -connect localhost:$PORT"
+
+# Also pick a unique name for intermediate files
+SRV_OUT="srv_out.$$"
+CLI_OUT="cli_out.$$"
+SESSION="session.$$"
+
 trap cleanup INT TERM HUP
 
 # Test for SSLv2 ClientHello
@@ -365,7 +412,9 @@
 
 run_test    "Session resume using tickets #5 (openssl client)" \
             "$P_SRV debug_level=4 tickets=1" \
-            "($O_CLI -sess_out sess; $O_CLI -sess_in sess; rm -f sess)" \
+            "( $O_CLI -sess_out $SESSION; \
+               $O_CLI -sess_in $SESSION; \
+               rm -f $SESSION )" \
             0 \
             -s "found session ticket extension" \
             -s "server hello, adding session ticket extension" \
@@ -450,7 +499,9 @@
 
 run_test    "Session resume using cache #8 (openssl client)" \
             "$P_SRV debug_level=4 tickets=0" \
-            "($O_CLI -sess_out sess; $O_CLI -sess_in sess; rm -f sess)" \
+            "( $O_CLI -sess_out $SESSION; \
+               $O_CLI -sess_in $SESSION; \
+               rm -f $SESSION )" \
             0 \
             -s "found session ticket extension" \
             -S "server hello, adding session ticket extension" \
@@ -1243,6 +1294,129 @@
             -s "bad certificate (usage extensions)" \
             -s "Processing of the Certificate handshake message failed"
 
+# Tests for DHM parameters loading
+
+run_test    "DHM parameters #0 (reference)" \
+            "$P_SRV" \
+            "$P_CLI force_ciphersuite=TLS-DHE-RSA-WITH-AES-128-CBC-SHA \
+                    debug_level=3" \
+            0 \
+            -c "value of 'DHM: P ' (2048 bits)" \
+            -c "value of 'DHM: G ' (2048 bits)"
+
+run_test    "DHM parameters #1 (other parameters)" \
+            "$P_SRV dhm_file=data_files/dhparams.pem" \
+            "$P_CLI force_ciphersuite=TLS-DHE-RSA-WITH-AES-128-CBC-SHA \
+                    debug_level=3" \
+            0 \
+            -c "value of 'DHM: P ' (1024 bits)" \
+            -c "value of 'DHM: G ' (2 bits)"
+
+# Tests for PSK callback
+
+run_test    "PSK callback #0a (psk, no callback)" \
+            "$P_SRV psk=abc123 psk_identity=foo" \
+            "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \
+            psk_identity=foo psk=abc123" \
+            0 \
+            -S "SSL - The server has no ciphersuites in common" \
+            -S "SSL - Unknown identity received" \
+            -S "SSL - Verification of the message MAC failed"
+
+run_test    "PSK callback #0b (no psk, no callback)" \
+            "$P_SRV" \
+            "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \
+            psk_identity=foo psk=abc123" \
+            1 \
+            -s "SSL - The server has no ciphersuites in common" \
+            -S "SSL - Unknown identity received" \
+            -S "SSL - Verification of the message MAC failed"
+
+run_test    "PSK callback #1 (callback overrides other settings)" \
+            "$P_SRV psk=abc123 psk_identity=foo psk_list=abc,dead,def,beef" \
+            "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \
+            psk_identity=foo psk=abc123" \
+            1 \
+            -S "SSL - The server has no ciphersuites in common" \
+            -s "SSL - Unknown identity received" \
+            -S "SSL - Verification of the message MAC failed"
+
+run_test    "PSK callback #2 (first id matches)" \
+            "$P_SRV psk_list=abc,dead,def,beef" \
+            "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \
+            psk_identity=abc psk=dead" \
+            0 \
+            -S "SSL - The server has no ciphersuites in common" \
+            -S "SSL - Unknown identity received" \
+            -S "SSL - Verification of the message MAC failed"
+
+run_test    "PSK callback #3 (second id matches)" \
+            "$P_SRV psk_list=abc,dead,def,beef" \
+            "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \
+            psk_identity=def psk=beef" \
+            0 \
+            -S "SSL - The server has no ciphersuites in common" \
+            -S "SSL - Unknown identity received" \
+            -S "SSL - Verification of the message MAC failed"
+
+run_test    "PSK callback #4 (no match)" \
+            "$P_SRV psk_list=abc,dead,def,beef" \
+            "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \
+            psk_identity=ghi psk=beef" \
+            1 \
+            -S "SSL - The server has no ciphersuites in common" \
+            -s "SSL - Unknown identity received" \
+            -S "SSL - Verification of the message MAC failed"
+
+run_test    "PSK callback #5 (wrong key)" \
+            "$P_SRV psk_list=abc,dead,def,beef" \
+            "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \
+            psk_identity=abc psk=beef" \
+            1 \
+            -S "SSL - The server has no ciphersuites in common" \
+            -S "SSL - Unknown identity received" \
+            -s "SSL - Verification of the message MAC failed"
+
+# Tests for ciphersuites per version
+
+run_test    "Per-version suites #1" \
+            "$P_SRV version_suites=TLS-RSA-WITH-3DES-EDE-CBC-SHA,TLS-RSA-WITH-RC4-128-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \
+            "$P_CLI force_version=ssl3" \
+            0 \
+            -c "Ciphersuite is TLS-RSA-WITH-3DES-EDE-CBC-SHA"
+
+run_test    "Per-version suites #2" \
+            "$P_SRV version_suites=TLS-RSA-WITH-3DES-EDE-CBC-SHA,TLS-RSA-WITH-RC4-128-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \
+            "$P_CLI force_version=tls1" \
+            0 \
+            -c "Ciphersuite is TLS-RSA-WITH-RC4-128-SHA"
+
+run_test    "Per-version suites #3" \
+            "$P_SRV version_suites=TLS-RSA-WITH-3DES-EDE-CBC-SHA,TLS-RSA-WITH-RC4-128-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \
+            "$P_CLI force_version=tls1_1" \
+            0 \
+            -c "Ciphersuite is TLS-RSA-WITH-AES-128-CBC-SHA"
+
+run_test    "Per-version suites #4" \
+            "$P_SRV version_suites=TLS-RSA-WITH-3DES-EDE-CBC-SHA,TLS-RSA-WITH-RC4-128-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \
+            "$P_CLI force_version=tls1_2" \
+            0 \
+            -c "Ciphersuite is TLS-RSA-WITH-AES-128-GCM-SHA256"
+
+# Tests for ssl_get_bytes_avail()
+
+run_test    "ssl_get_bytes_avail #1 (no extra data)" \
+            "$P_SRV" \
+            "$P_CLI request_size=100" \
+            0 \
+            -s "Read from client: 100 bytes read$"
+
+run_test    "ssl_get_bytes_avail #2 (extra data)" \
+            "$P_SRV" \
+            "$P_CLI request_size=500" \
+            0 \
+            -s "Read from client: 500 bytes read (.*+.*)"
+
 # Final report
 
 echo "------------------------------------------------------------------------"