Merge pull request #8373 from sergio-nsk/sergio-nsk/8372/1

Backport 2.28: Fix compiling AESNI in Mbed-TLS with clang on Windows
diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt
index 18945e5..37480f2 100644
--- a/3rdparty/CMakeLists.txt
+++ b/3rdparty/CMakeLists.txt
@@ -4,11 +4,7 @@
 list (APPEND thirdparty_inc)
 list (APPEND thirdparty_def)
 
-execute_process(COMMAND ${MBEDTLS_PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../scripts/config.py -f ${CMAKE_CURRENT_SOURCE_DIR}/../include/mbedtls/config.h get MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED RESULT_VARIABLE result)
-
-if(${result} EQUAL 0)
-    add_subdirectory(everest)
-endif()
+add_subdirectory(everest)
 
 set(thirdparty_src ${thirdparty_src} PARENT_SCOPE)
 set(thirdparty_lib ${thirdparty_lib} PARENT_SCOPE)
diff --git a/ChangeLog.d/fix-cmake-3rdparty-custom-config.txt b/ChangeLog.d/fix-cmake-3rdparty-custom-config.txt
new file mode 100644
index 0000000..c52aa3d
--- /dev/null
+++ b/ChangeLog.d/fix-cmake-3rdparty-custom-config.txt
@@ -0,0 +1,3 @@
+Bugfix
+   * Fix the build with CMake when Everest is enabled through
+     a user configuration file or the compiler command line. Fixes #8165.
diff --git a/ChangeLog.d/fix-mingw32-build.txt b/ChangeLog.d/fix-mingw32-build.txt
new file mode 100644
index 0000000..feef0a2
--- /dev/null
+++ b/ChangeLog.d/fix-mingw32-build.txt
@@ -0,0 +1,4 @@
+Bugfix
+  * Fix an inconsistency between implementations and usages of `__cpuid`,
+    which mainly causes failures when building Windows target using
+    mingw or clang. Fixes #8334 & #8332.
diff --git a/ChangeLog.d/pkwrite-pem-use-heap.txt b/ChangeLog.d/pkwrite-pem-use-heap.txt
new file mode 100644
index 0000000..11db7b6
--- /dev/null
+++ b/ChangeLog.d/pkwrite-pem-use-heap.txt
@@ -0,0 +1,4 @@
+Changes
+   * Use heap memory to allocate DER encoded public/private key.
+     This reduces stack usage significantly for writing a public/private
+     key to a PEM string.
diff --git a/library/aes.c b/library/aes.c
index d2a3c89..683480a 100644
--- a/library/aes.c
+++ b/library/aes.c
@@ -334,7 +334,7 @@
 /*
  * Round constants
  */
-static const uint32_t RCON[10] =
+static const uint32_t round_constants[10] =
 {
     0x00000001, 0x00000002, 0x00000004, 0x00000008,
     0x00000010, 0x00000020, 0x00000040, 0x00000080,
@@ -381,7 +381,7 @@
 /*
  * Round constants
  */
-static uint32_t RCON[10];
+static uint32_t round_constants[10];
 
 /*
  * Tables generation code
@@ -411,7 +411,7 @@
      * calculate the round constants
      */
     for (i = 0, x = 1; i < 10; i++) {
-        RCON[i] = (uint32_t) x;
+        round_constants[i] = (uint32_t) x;
         x = MBEDTLS_BYTE_0(XTIME(x));
     }
 
@@ -637,7 +637,7 @@
         case 10:
 
             for (i = 0; i < 10; i++, RK += 4) {
-                RK[4]  = RK[0] ^ RCON[i] ^
+                RK[4]  = RK[0] ^ round_constants[i] ^
                          ((uint32_t) FSb[MBEDTLS_BYTE_1(RK[3])]) ^
                          ((uint32_t) FSb[MBEDTLS_BYTE_2(RK[3])] <<  8) ^
                          ((uint32_t) FSb[MBEDTLS_BYTE_3(RK[3])] << 16) ^
@@ -652,7 +652,7 @@
         case 12:
 
             for (i = 0; i < 8; i++, RK += 6) {
-                RK[6]  = RK[0] ^ RCON[i] ^
+                RK[6]  = RK[0] ^ round_constants[i] ^
                          ((uint32_t) FSb[MBEDTLS_BYTE_1(RK[5])]) ^
                          ((uint32_t) FSb[MBEDTLS_BYTE_2(RK[5])] <<  8) ^
                          ((uint32_t) FSb[MBEDTLS_BYTE_3(RK[5])] << 16) ^
@@ -669,7 +669,7 @@
         case 14:
 
             for (i = 0; i < 7; i++, RK += 8) {
-                RK[8]  = RK[0] ^ RCON[i] ^
+                RK[8]  = RK[0] ^ round_constants[i] ^
                          ((uint32_t) FSb[MBEDTLS_BYTE_1(RK[7])]) ^
                          ((uint32_t) FSb[MBEDTLS_BYTE_2(RK[7])] <<  8) ^
                          ((uint32_t) FSb[MBEDTLS_BYTE_3(RK[7])] << 16) ^
diff --git a/library/aesni.c b/library/aesni.c
index 8bc74f1..3f62a2e 100644
--- a/library/aesni.c
+++ b/library/aesni.c
@@ -39,10 +39,12 @@
 #if defined(MBEDTLS_AESNI_HAVE_CODE)
 
 #if MBEDTLS_AESNI_HAVE_CODE == 2
-#if !defined(_WIN32)
+#if defined(__GNUC__)
 #include <cpuid.h>
-#else
+#elif defined(_MSC_VER)
 #include <intrin.h>
+#else
+#error "`__cpuid` required by MBEDTLS_AESNI_C is not supported by the compiler"
 #endif
 #include <immintrin.h>
 #endif
diff --git a/library/pkcs12.c b/library/pkcs12.c
index 89fda10..76aad9e 100644
--- a/library/pkcs12.c
+++ b/library/pkcs12.c
@@ -256,21 +256,22 @@
     }
 
 #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
-    /* PKCS12 uses CBC with PKCS7 padding */
-
-    mbedtls_cipher_padding_t padding = MBEDTLS_PADDING_PKCS7;
+    {
+        /* PKCS12 uses CBC with PKCS7 padding */
+        mbedtls_cipher_padding_t padding = MBEDTLS_PADDING_PKCS7;
 #if !defined(MBEDTLS_CIPHER_PADDING_PKCS7)
-    /* For historical reasons, when decrypting, this function works when
-     * decrypting even when support for PKCS7 padding is disabled. In this
-     * case, it ignores the padding, and so will never report a
-     * password mismatch.
-     */
-    if (mode == MBEDTLS_PKCS12_PBE_DECRYPT) {
-        padding = MBEDTLS_PADDING_NONE;
-    }
+        /* For historical reasons, when decrypting, this function works when
+         * decrypting even when support for PKCS7 padding is disabled. In this
+         * case, it ignores the padding, and so will never report a
+         * password mismatch.
+         */
+        if (mode == MBEDTLS_PKCS12_PBE_DECRYPT) {
+            padding = MBEDTLS_PADDING_NONE;
+        }
 #endif
-    if ((ret = mbedtls_cipher_set_padding_mode(&cipher_ctx, padding)) != 0) {
-        goto exit;
+        if ((ret = mbedtls_cipher_set_padding_mode(&cipher_ctx, padding)) != 0) {
+            goto exit;
+        }
     }
 #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
 
diff --git a/library/pkcs5.c b/library/pkcs5.c
index ebf391a..4dc5fd7 100644
--- a/library/pkcs5.c
+++ b/library/pkcs5.c
@@ -251,23 +251,25 @@
     }
 
 #if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
-    /* PKCS5 uses CBC with PKCS7 padding (which is the same as
-     * "PKCS5 padding" except that it's typically only called PKCS5
-     * with 64-bit-block ciphers).
-     */
-    mbedtls_cipher_padding_t padding = MBEDTLS_PADDING_PKCS7;
+    {
+        /* PKCS5 uses CBC with PKCS7 padding (which is the same as
+         * "PKCS5 padding" except that it's typically only called PKCS5
+         * with 64-bit-block ciphers).
+         */
+        mbedtls_cipher_padding_t padding = MBEDTLS_PADDING_PKCS7;
 #if !defined(MBEDTLS_CIPHER_PADDING_PKCS7)
-    /* For historical reasons, when decrypting, this function works when
-     * decrypting even when support for PKCS7 padding is disabled. In this
-     * case, it ignores the padding, and so will never report a
-     * password mismatch.
-     */
-    if (mode == MBEDTLS_DECRYPT) {
-        padding = MBEDTLS_PADDING_NONE;
-    }
+        /* For historical reasons, when decrypting, this function works when
+         * decrypting even when support for PKCS7 padding is disabled. In this
+         * case, it ignores the padding, and so will never report a
+         * password mismatch.
+         */
+        if (mode == MBEDTLS_DECRYPT) {
+            padding = MBEDTLS_PADDING_NONE;
+        }
 #endif
-    if ((ret = mbedtls_cipher_set_padding_mode(&cipher_ctx, padding)) != 0) {
-        goto exit;
+        if ((ret = mbedtls_cipher_set_padding_mode(&cipher_ctx, padding)) != 0) {
+            goto exit;
+        }
     }
 #endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
     if ((ret = mbedtls_cipher_crypt(&cipher_ctx, iv, enc_scheme_params.len,
diff --git a/library/pkwrite.c b/library/pkwrite.c
index 88e6855..5e3fcc9 100644
--- a/library/pkwrite.c
+++ b/library/pkwrite.c
@@ -571,38 +571,49 @@
 int mbedtls_pk_write_pubkey_pem(mbedtls_pk_context *key, unsigned char *buf, size_t size)
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    unsigned char output_buf[PUB_DER_MAX_BYTES];
+    unsigned char *output_buf = NULL;
+    output_buf = mbedtls_calloc(1, PUB_DER_MAX_BYTES);
+    if (output_buf == NULL) {
+        return MBEDTLS_ERR_PK_ALLOC_FAILED;
+    }
     size_t olen = 0;
 
     PK_VALIDATE_RET(key != NULL);
     PK_VALIDATE_RET(buf != NULL || size == 0);
 
     if ((ret = mbedtls_pk_write_pubkey_der(key, output_buf,
-                                           sizeof(output_buf))) < 0) {
-        return ret;
+                                           PUB_DER_MAX_BYTES)) < 0) {
+        goto cleanup;
     }
 
     if ((ret = mbedtls_pem_write_buffer(PEM_BEGIN_PUBLIC_KEY, PEM_END_PUBLIC_KEY,
-                                        output_buf + sizeof(output_buf) - ret,
+                                        output_buf + PUB_DER_MAX_BYTES - ret,
                                         ret, buf, size, &olen)) != 0) {
-        return ret;
+        goto cleanup;
     }
 
-    return 0;
+    ret = 0;
+cleanup:
+    mbedtls_free(output_buf);
+    return ret;
 }
 
 int mbedtls_pk_write_key_pem(mbedtls_pk_context *key, unsigned char *buf, size_t size)
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    unsigned char output_buf[PRV_DER_MAX_BYTES];
+    unsigned char *output_buf = NULL;
+    output_buf = mbedtls_calloc(1, PRV_DER_MAX_BYTES);
+    if (output_buf == NULL) {
+        return MBEDTLS_ERR_PK_ALLOC_FAILED;
+    }
     const char *begin, *end;
     size_t olen = 0;
 
     PK_VALIDATE_RET(key != NULL);
     PK_VALIDATE_RET(buf != NULL || size == 0);
 
-    if ((ret = mbedtls_pk_write_key_der(key, output_buf, sizeof(output_buf))) < 0) {
-        return ret;
+    if ((ret = mbedtls_pk_write_key_der(key, output_buf, PRV_DER_MAX_BYTES)) < 0) {
+        goto cleanup;
     }
 
 #if defined(MBEDTLS_RSA_C)
@@ -617,15 +628,22 @@
         end = PEM_END_PRIVATE_KEY_EC;
     } else
 #endif
-    return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
-
-    if ((ret = mbedtls_pem_write_buffer(begin, end,
-                                        output_buf + sizeof(output_buf) - ret,
-                                        ret, buf, size, &olen)) != 0) {
-        return ret;
+    {
+        ret = MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
+        goto cleanup;
     }
 
-    return 0;
+    if ((ret = mbedtls_pem_write_buffer(begin, end,
+                                        output_buf + PRV_DER_MAX_BYTES - ret,
+                                        ret, buf, size, &olen)) != 0) {
+        goto cleanup;
+    }
+
+    ret = 0;
+cleanup:
+    mbedtls_platform_zeroize(output_buf, PRV_DER_MAX_BYTES);
+    mbedtls_free(output_buf);
+    return ret;
 }
 #endif /* MBEDTLS_PEM_WRITE_C */
 
diff --git a/programs/demo_common.sh b/programs/demo_common.sh
new file mode 100644
index 0000000..d8fcda5
--- /dev/null
+++ b/programs/demo_common.sh
@@ -0,0 +1,137 @@
+## Common shell functions used by demo scripts programs/*/*.sh.
+
+## How to write a demo script
+## ==========================
+##
+## Include this file near the top of each demo script:
+##   . "${0%/*}/../demo_common.sh"
+##
+## Start with a "msg" call that explains the purpose of the script.
+## Then call the "depends_on" function to ensure that all config
+## dependencies are met.
+##
+## As the last thing in the script, call the cleanup function.
+##
+## You can use the functions and variables described below.
+
+set -e -u
+
+## $root_dir is the root directory of the Mbed TLS source tree.
+root_dir="${0%/*}"
+# Find a nice path to the root directory, avoiding unnecessary "../".
+# The code supports demo scripts nested up to 4 levels deep.
+# The code works no matter where the demo script is relative to the current
+# directory, even if it is called with a relative path.
+n=4 # limit the search depth
+while ! [ -d "$root_dir/programs" ] || ! [ -d "$root_dir/library" ]; do
+  if [ $n -eq 0 ]; then
+    echo >&2 "This doesn't seem to be an Mbed TLS source tree."
+    exit 125
+  fi
+  n=$((n - 1))
+  case $root_dir in
+    .) root_dir="..";;
+    ..|?*/..) root_dir="$root_dir/..";;
+    ?*/*) root_dir="${root_dir%/*}";;
+    /*) root_dir="/";;
+    *) root_dir=".";;
+  esac
+done
+
+## $programs_dir is the directory containing the sample programs.
+# Assume an in-tree build.
+programs_dir="$root_dir/programs"
+
+## msg LINE...
+## msg <TEXT_ORIGIN
+## Display an informational message.
+msg () {
+  if [ $# -eq 0 ]; then
+    sed 's/^/# /'
+  else
+    for x in "$@"; do
+      echo "# $x"
+    done
+  fi
+}
+
+## run "Message" COMMAND ARGUMENT...
+## Display the message, then run COMMAND with the specified arguments.
+run () {
+    echo
+    echo "# $1"
+    shift
+    echo "+ $*"
+    "$@"
+}
+
+## Like '!', but stop on failure with 'set -e'
+not () {
+  if "$@"; then false; fi
+}
+
+## run_bad "Message" COMMAND ARGUMENT...
+## Like run, but the command is expected to fail.
+run_bad () {
+  echo
+  echo "$1 This must fail."
+  shift
+  echo "+ ! $*"
+  not "$@"
+}
+
+## config_has SYMBOL...
+## Succeeds if the library configuration has all SYMBOLs set.
+config_has () {
+  for x in "$@"; do
+    "$programs_dir/test/query_compile_time_config" "$x"
+  done
+}
+
+## depends_on SYMBOL...
+## Exit if the library configuration does not have all SYMBOLs set.
+depends_on () {
+  m=
+  for x in "$@"; do
+    if ! config_has "$x"; then
+      m="$m $x"
+    fi
+  done
+  if [ -n "$m" ]; then
+    cat >&2 <<EOF
+$0: this demo requires the following
+configuration options to be enabled at compile time:
+ $m
+EOF
+    # Exit with a success status so that this counts as a pass for run_demos.py.
+    exit
+  fi
+}
+
+## Add the names of files to clean up to this whitespace-separated variable.
+## The file names must not contain whitespace characters.
+files_to_clean=
+
+## Call this function at the end of each script.
+## It is called automatically if the script is killed by a signal.
+cleanup () {
+  rm -f -- $files_to_clean
+}
+
+
+
+################################################################
+## End of the public interfaces. Code beyond this point is not
+## meant to be called directly from a demo script.
+
+trap 'cleanup; trap - HUP; kill -HUP $$' HUP
+trap 'cleanup; trap - INT; kill -INT $$' INT
+trap 'cleanup; trap - TERM; kill -TERM $$' TERM
+
+if config_has MBEDTLS_ENTROPY_NV_SEED; then
+  # Create a seedfile that's sufficiently long in all library configurations.
+  # This is necessary for programs that use randomness.
+  # Assume that the name of the seedfile is the default name.
+  files_to_clean="$files_to_clean seedfile"
+  dd if=/dev/urandom of=seedfile ibs=64 obs=64 count=1
+fi
diff --git a/programs/psa/key_ladder_demo.sh b/programs/psa/key_ladder_demo.sh
index e21d1ab..bb4a24f 100755
--- a/programs/psa/key_ladder_demo.sh
+++ b/programs/psa/key_ladder_demo.sh
@@ -15,36 +15,17 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-set -e -u
+. "${0%/*}/../demo_common.sh"
 
-program_name="key_ladder_demo"
-program="${0%/*}/$program_name"
-files_to_clean=
+msg <<'EOF'
+This script demonstrates the use of the PSA cryptography interface to
+create a master key, derive a key from it and use that derived key to
+wrap some data using an AEAD algorithm.
+EOF
 
-if [ ! -e "$program" ]; then
-    # Look for programs in the current directory and the directories above it
-    for dir in "." ".." "../.."; do
-        program="$dir/programs/psa/$program_name"
-        if [ -e "$program" ]; then
-            break
-        fi
-    done
-    if [ ! -e "$program" ]; then
-        echo "Could not find $program_name executable"
+depends_on MBEDTLS_SHA256_C MBEDTLS_MD_C MBEDTLS_AES_C MBEDTLS_CCM_C MBEDTLS_PSA_CRYPTO_C MBEDTLS_FS_IO
 
-        echo "If building out-of-tree, this script must be run" \
-             "from the project build directory."
-        exit 1
-    fi
-fi
-
-run () {
-    echo
-    echo "# $1"
-    shift
-    echo "+ $*"
-    "$@"
-}
+program="${0%/*}"/key_ladder_demo
 
 if [ -e master.key ]; then
     echo "# Reusing the existing master.key file."
@@ -68,7 +49,7 @@
     cmp input.txt hello_world.txt
 
 files_to_clean="$files_to_clean hellow_orld.txt"
-! run "Derive a different key and attempt to unwrap the data. This must fail." \
+run_bad "Derive a different key and attempt to unwrap the data." \
   "$program" unwrap master=master.key input=hello_world.wrap output=hellow_orld.txt label=hellow label=orld
 
 files_to_clean="$files_to_clean hello.key"
@@ -79,5 +60,4 @@
     "$program" unwrap master=hello.key label=world \
                input=hello_world.wrap output=hello_world.txt
 
-# Cleanup
-rm -f $files_to_clean
+cleanup
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index ca74c00..f5223fb 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -438,7 +438,7 @@
     "                                otherwise. The expansion of the macro\n" \
     "                                is printed if it is defined\n"     \
     USAGE_SERIALIZATION                                     \
-    " acceptable ciphersuite names:\n"
+    "\n"
 
 #define ALPN_LIST_SIZE  10
 #define CURVE_LIST_SIZE 20
@@ -767,31 +767,6 @@
     mbedtls_test_enable_insecure_external_rng();
 #endif  /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
 
-    if (argc < 2) {
-usage:
-        if (ret == 0) {
-            ret = 1;
-        }
-
-        mbedtls_printf(USAGE1);
-        mbedtls_printf(USAGE2);
-        mbedtls_printf(USAGE3);
-        mbedtls_printf(USAGE4);
-
-        list = mbedtls_ssl_list_ciphersuites();
-        while (*list) {
-            mbedtls_printf(" %-42s", mbedtls_ssl_get_ciphersuite_name(*list));
-            list++;
-            if (!*list) {
-                break;
-            }
-            mbedtls_printf(" %s\n", mbedtls_ssl_get_ciphersuite_name(*list));
-            list++;
-        }
-        mbedtls_printf("\n");
-        goto exit;
-    }
-
     opt.server_name         = DFL_SERVER_NAME;
     opt.server_addr         = DFL_SERVER_ADDR;
     opt.server_port         = DFL_SERVER_PORT;
@@ -864,9 +839,54 @@
     opt.force_srtp_profile  = DFL_SRTP_FORCE_PROFILE;
     opt.mki                 = DFL_SRTP_MKI;
 
+    p = q = NULL;
+    if (argc < 1) {
+usage:
+        if (p != NULL && q != NULL) {
+            printf("unrecognized value for '%s': '%s'\n", p, q);
+        } else if (p != NULL && q == NULL) {
+            printf("unrecognized param: '%s'\n", p);
+        }
+
+        mbedtls_printf("usage: ssl_client2 [param=value] [...]\n");
+        mbedtls_printf("       ssl_client2 help[_theme]\n");
+        mbedtls_printf("'help' lists acceptable 'param' and 'value'\n");
+        mbedtls_printf("'help_ciphersuites' lists available ciphersuites\n");
+        mbedtls_printf("\n");
+
+        if (ret == 0) {
+            ret = 1;
+        }
+        goto exit;
+    }
+
     for (i = 1; i < argc; i++) {
         p = argv[i];
+
+        if (strcmp(p, "help") == 0) {
+            mbedtls_printf(USAGE1);
+            mbedtls_printf(USAGE2);
+            mbedtls_printf(USAGE3);
+            mbedtls_printf(USAGE4);
+
+            ret = 0;
+            goto exit;
+        }
+        if (strcmp(p, "help_ciphersuites") == 0) {
+            mbedtls_printf(" acceptable ciphersuite names:\n");
+            for (list = mbedtls_ssl_list_ciphersuites();
+                 *list != 0;
+                 list++) {
+                mbedtls_printf(" %s\n", mbedtls_ssl_get_ciphersuite_name(*list));
+            }
+
+            ret = 0;
+            goto exit;
+        }
+
         if ((q = strchr(p, '=')) == NULL) {
+            mbedtls_printf("param requires a value: '%s'\n", p);
+            p = NULL; // avoid "unrecnognized param" message
             goto usage;
         }
         *q++ = '\0';
@@ -1226,9 +1246,13 @@
         } else if (strcmp(p, "mki") == 0) {
             opt.mki = q;
         } else {
+            /* This signals that the problem is with p not q */
+            q = NULL;
             goto usage;
         }
     }
+    /* This signals that any further errors are not with a single option */
+    p = q = NULL;
 
     if (opt.nss_keylog != 0 && opt.eap_tls != 0) {
         mbedtls_printf("Error: eap_tls and nss_keylog options cannot be used together.\n");
diff --git a/programs/ssl/ssl_context_info.c b/programs/ssl/ssl_context_info.c
index ebdef4f..41b12e9 100644
--- a/programs/ssl/ssl_context_info.c
+++ b/programs/ssl/ssl_context_info.c
@@ -1,5 +1,5 @@
 /*
- *  MbedTLS SSL context deserializer from base64 code
+ *  Mbed TLS SSL context deserializer from base64 code
  *
  *  Copyright The Mbed TLS Contributors
  *  SPDX-License-Identifier: Apache-2.0
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index c3c5149..dcd5eca 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -535,7 +535,7 @@
     "                                otherwise. The expansion of the macro\n" \
     "                                is printed if it is defined\n"     \
     USAGE_SERIALIZATION                                     \
-    " acceptable ciphersuite names:\n"
+    "\n"
 
 #define ALPN_LIST_SIZE  10
 #define CURVE_LIST_SIZE 20
@@ -1449,31 +1449,6 @@
     signal(SIGINT, term_handler);
 #endif
 
-    if (argc < 2) {
-usage:
-        if (ret == 0) {
-            ret = 1;
-        }
-
-        mbedtls_printf(USAGE1);
-        mbedtls_printf(USAGE2);
-        mbedtls_printf(USAGE3);
-        mbedtls_printf(USAGE4);
-
-        list = mbedtls_ssl_list_ciphersuites();
-        while (*list) {
-            mbedtls_printf(" %-42s", mbedtls_ssl_get_ciphersuite_name(*list));
-            list++;
-            if (!*list) {
-                break;
-            }
-            mbedtls_printf(" %s\n", mbedtls_ssl_get_ciphersuite_name(*list));
-            list++;
-        }
-        mbedtls_printf("\n");
-        goto exit;
-    }
-
     opt.buffer_size         = DFL_IO_BUF_LEN;
     opt.server_addr         = DFL_SERVER_ADDR;
     opt.server_port         = DFL_SERVER_PORT;
@@ -1557,9 +1532,54 @@
     opt.force_srtp_profile  = DFL_SRTP_FORCE_PROFILE;
     opt.support_mki         = DFL_SRTP_SUPPORT_MKI;
 
+    p = q = NULL;
+    if (argc < 1) {
+usage:
+        if (p != NULL && q != NULL) {
+            printf("unrecognized value for '%s': '%s'\n", p, q);
+        } else if (p != NULL && q == NULL) {
+            printf("unrecognized param: '%s'\n", p);
+        }
+
+        mbedtls_printf("usage: ssl_client2 [param=value] [...]\n");
+        mbedtls_printf("       ssl_client2 help[_theme]\n");
+        mbedtls_printf("'help' lists acceptable 'param' and 'value'\n");
+        mbedtls_printf("'help_ciphersuites' lists available ciphersuites\n");
+        mbedtls_printf("\n");
+
+        if (ret == 0) {
+            ret = 1;
+        }
+        goto exit;
+    }
+
     for (i = 1; i < argc; i++) {
         p = argv[i];
+
+        if (strcmp(p, "help") == 0) {
+            mbedtls_printf(USAGE1);
+            mbedtls_printf(USAGE2);
+            mbedtls_printf(USAGE3);
+            mbedtls_printf(USAGE4);
+
+            ret = 0;
+            goto exit;
+        }
+        if (strcmp(p, "help_ciphersuites") == 0) {
+            mbedtls_printf(" acceptable ciphersuite names:\n");
+            for (list = mbedtls_ssl_list_ciphersuites();
+                 *list != 0;
+                 list++) {
+                mbedtls_printf(" %s\n", mbedtls_ssl_get_ciphersuite_name(*list));
+            }
+
+            ret = 0;
+            goto exit;
+        }
+
         if ((q = strchr(p, '=')) == NULL) {
+            mbedtls_printf("param requires a value: '%s'\n", p);
+            p = NULL; // avoid "unrecnognized param" message
             goto usage;
         }
         *q++ = '\0';
@@ -1949,9 +1969,13 @@
         } else if (strcmp(p, "support_mki") == 0) {
             opt.support_mki = atoi(q);
         } else {
+            /* This signals that the problem is with p not q */
+            q = NULL;
             goto usage;
         }
     }
+    /* This signals that any further erorrs are not with a single option */
+    p = q = NULL;
 
     if (opt.nss_keylog != 0 && opt.eap_tls != 0) {
         mbedtls_printf("Error: eap_tls and nss_keylog options cannot be used together.\n");
diff --git a/programs/test/benchmark.c b/programs/test/benchmark.c
index bbb7046..cf92e95 100644
--- a/programs/test/benchmark.c
+++ b/programs/test/benchmark.c
@@ -89,12 +89,12 @@
 #define HEADER_FORMAT   "  %-24s :  "
 #define TITLE_LEN       25
 
-#define OPTIONS                                                         \
-    "md4, md5, ripemd160, sha1, sha256, sha512,\n"                      \
-    "arc4, des3, des, camellia, blowfish, chacha20,\n"                  \
-    "aes_cbc, aes_gcm, aes_ccm, aes_xts, chachapoly,\n"                 \
-    "aes_cmac, des3_cmac, poly1305\n"                                   \
-    "havege, ctr_drbg, hmac_drbg\n"                                     \
+#define OPTIONS                                                               \
+    "md4, md5, ripemd160, sha1, sha256, sha512,\n"                            \
+    "arc4, des3, des, camellia, blowfish, chacha20,\n"                        \
+    "aes_cbc, aes_cfb128, aes_cfb8, aes_gcm, aes_ccm, aes_xts, chachapoly,\n" \
+    "aes_cmac, des3_cmac, poly1305\n"                                         \
+    "havege, ctr_drbg, hmac_drbg\n"                                           \
     "rsa, dhm, ecdsa, ecdh.\n"
 
 #if defined(MBEDTLS_ERROR_C)
@@ -280,7 +280,7 @@
 typedef struct {
     char md4, md5, ripemd160, sha1, sha256, sha512,
          arc4, des3, des,
-         aes_cbc, aes_gcm, aes_ccm, aes_xts, chachapoly,
+         aes_cbc, aes_cfb128, aes_cfb8, aes_gcm, aes_ccm, aes_xts, chachapoly,
          aes_cmac, des3_cmac,
          aria, camellia, blowfish, chacha20,
          poly1305,
@@ -336,6 +336,10 @@
                 todo.des = 1;
             } else if (strcmp(argv[i], "aes_cbc") == 0) {
                 todo.aes_cbc = 1;
+            } else if (strcmp(argv[i], "aes_cfb128") == 0) {
+                todo.aes_cfb128 = 1;
+            } else if (strcmp(argv[i], "aes_cfb8") == 0) {
+                todo.aes_cfb8 = 1;
             } else if (strcmp(argv[i], "aes_xts") == 0) {
                 todo.aes_xts = 1;
             } else if (strcmp(argv[i], "aes_gcm") == 0) {
@@ -432,6 +436,7 @@
 #if defined(MBEDTLS_ARC4_C)
     if (todo.arc4) {
         mbedtls_arc4_context arc4;
+
         mbedtls_arc4_init(&arc4);
         mbedtls_arc4_setup(&arc4, tmp, 32);
         TIME_AND_TSC("ARC4", mbedtls_arc4_crypt(&arc4, BUFSIZE, buf, buf));
@@ -443,6 +448,7 @@
 #if defined(MBEDTLS_CIPHER_MODE_CBC)
     if (todo.des3) {
         mbedtls_des3_context des3;
+
         mbedtls_des3_init(&des3);
         if (mbedtls_des3_set3key_enc(&des3, tmp) != 0) {
             mbedtls_exit(1);
@@ -454,6 +460,7 @@
 
     if (todo.des) {
         mbedtls_des_context des;
+
         mbedtls_des_init(&des);
         if (mbedtls_des_setkey_enc(&des, tmp) != 0) {
             mbedtls_exit(1);
@@ -486,6 +493,7 @@
     if (todo.aes_cbc) {
         int keysize;
         mbedtls_aes_context aes;
+
         mbedtls_aes_init(&aes);
         for (keysize = 128; keysize <= 256; keysize += 64) {
             mbedtls_snprintf(title, sizeof(title), "AES-CBC-%d", keysize);
@@ -500,6 +508,44 @@
         mbedtls_aes_free(&aes);
     }
 #endif
+#if defined(MBEDTLS_CIPHER_MODE_CFB)
+    if (todo.aes_cfb128) {
+        int keysize;
+        size_t iv_off = 0;
+        mbedtls_aes_context aes;
+
+        mbedtls_aes_init(&aes);
+        for (keysize = 128; keysize <= 256; keysize += 64) {
+            mbedtls_snprintf(title, sizeof(title), "AES-CFB128-%d", keysize);
+
+            memset(buf, 0, sizeof(buf));
+            memset(tmp, 0, sizeof(tmp));
+            CHECK_AND_CONTINUE(mbedtls_aes_setkey_enc(&aes, tmp, keysize));
+
+            TIME_AND_TSC(title,
+                         mbedtls_aes_crypt_cfb128(&aes, MBEDTLS_AES_ENCRYPT, BUFSIZE,
+                                                  &iv_off, tmp, buf, buf));
+        }
+        mbedtls_aes_free(&aes);
+    }
+    if (todo.aes_cfb8) {
+        int keysize;
+        mbedtls_aes_context aes;
+
+        mbedtls_aes_init(&aes);
+        for (keysize = 128; keysize <= 256; keysize += 64) {
+            mbedtls_snprintf(title, sizeof(title), "AES-CFB8-%d", keysize);
+
+            memset(buf, 0, sizeof(buf));
+            memset(tmp, 0, sizeof(tmp));
+            CHECK_AND_CONTINUE(mbedtls_aes_setkey_enc(&aes, tmp, keysize));
+
+            TIME_AND_TSC(title,
+                         mbedtls_aes_crypt_cfb8(&aes, MBEDTLS_AES_ENCRYPT, BUFSIZE, tmp, buf, buf));
+        }
+        mbedtls_aes_free(&aes);
+    }
+#endif
 #if defined(MBEDTLS_CIPHER_MODE_XTS)
     if (todo.aes_xts) {
         int keysize;
@@ -617,6 +663,7 @@
     if (todo.aria) {
         int keysize;
         mbedtls_aria_context aria;
+
         mbedtls_aria_init(&aria);
         for (keysize = 128; keysize <= 256; keysize += 64) {
             mbedtls_snprintf(title, sizeof(title), "ARIA-CBC-%d", keysize);
@@ -637,6 +684,7 @@
     if (todo.camellia) {
         int keysize;
         mbedtls_camellia_context camellia;
+
         mbedtls_camellia_init(&camellia);
         for (keysize = 128; keysize <= 256; keysize += 64) {
             mbedtls_snprintf(title, sizeof(title), "CAMELLIA-CBC-%d", keysize);
@@ -669,6 +717,7 @@
     if (todo.blowfish) {
         int keysize;
         mbedtls_blowfish_context blowfish;
+
         mbedtls_blowfish_init(&blowfish);
 
         for (keysize = 128; keysize <= 256; keysize += 64) {
@@ -690,6 +739,7 @@
 #if defined(MBEDTLS_HAVEGE_C)
     if (todo.havege) {
         mbedtls_havege_state hs;
+
         mbedtls_havege_init(&hs);
         TIME_AND_TSC("HAVEGE", mbedtls_havege_random(&hs, buf, BUFSIZE));
         mbedtls_havege_free(&hs);
@@ -774,6 +824,7 @@
     if (todo.rsa) {
         int keysize;
         mbedtls_rsa_context rsa;
+
         for (keysize = 2048; keysize <= 4096; keysize *= 2) {
             mbedtls_snprintf(title, sizeof(title), "RSA-%d", keysize);
 
@@ -815,6 +866,7 @@
 
         mbedtls_dhm_context dhm;
         size_t olen;
+
         for (i = 0; (size_t) i < sizeof(dhm_sizes) / sizeof(dhm_sizes[0]); i++) {
             mbedtls_dhm_init(&dhm);
 
@@ -928,6 +980,7 @@
 
         if (curve_list == (const mbedtls_ecp_curve_info *) &single_curve) {
             mbedtls_ecp_group grp;
+
             mbedtls_ecp_group_init(&grp);
             if (mbedtls_ecp_group_load(&grp, curve_list->grp_id) != 0) {
                 mbedtls_exit(1);
diff --git a/programs/test/dlopen_demo.sh b/programs/test/dlopen_demo.sh
index a6a9022..b162d7b 100755
--- a/programs/test/dlopen_demo.sh
+++ b/programs/test/dlopen_demo.sh
@@ -18,34 +18,21 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-set -e -u
+. "${0%/*}/../demo_common.sh"
 
-program_name="dlopen"
-program_dir="${0%/*}"
-program="$program_dir/$program_name"
+msg "Test the dynamic loading of libmbed*"
 
+program="$programs_dir/test/dlopen"
+library_dir="$root_dir/library"
+
+# Skip this test if we don't have a shared library build. Detect this
+# through the absence of the demo program.
 if [ ! -e "$program" ]; then
-    # Look for programs in the current directory and the directories above it
-    for dir in "." ".." "../.."; do
-        program_dir="$dir/programs/test"
-        program="$program_dir/$program_name"
-        if [ -e "$program" ]; then
-            break
-        fi
-    done
-    if [ ! -e "$program" ]; then
-        echo "Could not find $program_name program"
-
-        echo "Make sure that Mbed TLS is built as a shared library." \
-             "If building out-of-tree, this script must be run" \
-             "from the project build directory."
-        exit 1
-    fi
+    msg "$0: this demo requires a shared library build."
+    # Exit with a success status so that this counts as a pass for run_demos.py.
+    exit
 fi
 
-top_dir="$program_dir/../.."
-library_dir="$top_dir/library"
-
 # ELF-based Unix-like (Linux, *BSD, Solaris, ...)
 if [ -n "${LD_LIBRARY_PATH-}" ]; then
     LD_LIBRARY_PATH="$library_dir:$LD_LIBRARY_PATH"
@@ -62,6 +49,6 @@
 fi
 export DYLD_LIBRARY_PATH
 
-echo "Running dynamic loading test program: $program"
-echo "Loading libraries from: $library_dir"
+msg "Running dynamic loading test program: $program"
+msg "Loading libraries from: $library_dir"
 "$program"
diff --git a/scripts/assemble_changelog.py b/scripts/assemble_changelog.py
index d27cc47..d44678b 100755
--- a/scripts/assemble_changelog.py
+++ b/scripts/assemble_changelog.py
@@ -60,6 +60,11 @@
         message = ('Lost content from {}: "{}"'.format(filename, line))
         super().__init__(message)
 
+class FilePathError(Exception):
+    def __init__(self, filenames):
+        message = ('Changelog filenames do not end with .txt: {}'.format(", ".join(filenames)))
+        super().__init__(message)
+
 # The category names we use in the changelog.
 # If you edit this, update ChangeLog.d/README.md.
 STANDARD_CATEGORIES = (
@@ -445,8 +450,21 @@
     """List the entry files to merge, oldest first.
 
     "Oldest" is defined by `EntryFileSortKey`.
+
+    Also check for required .txt extension
     """
-    files_to_merge = glob.glob(os.path.join(options.dir, '*.txt'))
+    files_to_merge = glob.glob(os.path.join(options.dir, '*'))
+
+    # Ignore 00README.md
+    readme = os.path.join(options.dir, "00README.md")
+    if readme in files_to_merge:
+        files_to_merge.remove(readme)
+
+    # Identify files without the required .txt extension
+    bad_files = [x for x in files_to_merge if not x.endswith(".txt")]
+    if bad_files:
+        raise FilePathError(bad_files)
+
     files_to_merge.sort(key=EntryFileSortKey)
     return files_to_merge
 
@@ -454,6 +472,7 @@
     """Merge changelog entries into the changelog file.
 
     Read the changelog file from options.input.
+    Check that all entries have a .txt extension
     Read entries to merge from the directory options.dir.
     Write the new changelog to options.output.
     Remove the merged entries if options.keep_entries is false.
diff --git a/scripts/output_env.sh b/scripts/output_env.sh
index 5356132..63628e7 100755
--- a/scripts/output_env.sh
+++ b/scripts/output_env.sh
@@ -192,20 +192,6 @@
 print_version "$GNUTLS_SERV" "--version" "default" "head -n 1"
 echo
 
-if [ -n "${GNUTLS_LEGACY_CLI+set}" ]; then
-    print_version "$GNUTLS_LEGACY_CLI" "--version" "legacy" "head -n 1"
-else
-     echo " * gnutls-cli (legacy): Not configured."
-fi
-echo
-
-if [ -n "${GNUTLS_LEGACY_SERV+set}" ]; then
-    print_version "$GNUTLS_LEGACY_SERV" "--version" "legacy" "head -n 1"
-else
-    echo " * gnutls-serv (legacy): Not configured."
-fi
-echo
-
 echo " * Installed asan versions:"
 if type dpkg-query >/dev/null 2>/dev/null; then
     if ! dpkg-query -f '${Status} ${Package}: ${Version}\n' -W 'libasan*' |
diff --git a/tests/compat.sh b/tests/compat.sh
index ba8465b..de9dc40 100755
--- a/tests/compat.sh
+++ b/tests/compat.sh
@@ -110,6 +110,7 @@
 EXCLUDE='NULL\|DES\|RC4\|ARCFOUR\|ARIA\|CHACHA20-POLY1305'
 VERBOSE=""
 MEMCHECK=0
+PRESERVE_LOGS=0
 PEERS="OpenSSL$PEER_GNUTLS mbedTLS"
 
 # hidden option: skip DTLS with OpenSSL
@@ -131,6 +132,7 @@
     printf "     --list-test-case\tList all potential test cases (No Execution)\n"
     printf "     --outcome-file\tFile where test outcomes are written\n"
     printf "                   \t(default: \$MBEDTLS_TEST_OUTCOME_FILE, none if empty)\n"
+    printf "     --preserve-logs\tPreserve logs of successful tests as well\n"
 }
 
 # print_test_case <CLIENT> <SERVER> <STANDARD_CIPHER_SUITE>
@@ -198,6 +200,9 @@
             --outcome-file)
                 shift; MBEDTLS_TEST_OUTCOME_FILE=$1
                 ;;
+            --preserve-logs)
+                PRESERVE_LOGS=1
+                ;;
             -h|--help)
                 print_usage
                 exit 0
@@ -648,7 +653,16 @@
             ;;
 
         "RSA")
-            if [ `minor_ver "$MODE"` -gt 0 ]
+            # TLS-RSA-WITH-NULL-SHA256 is a (D)TLS 1.2-only cipher suite,
+            # like all SHA256 cipher suites. But Mbed TLS supports it with
+            # (D)TLS 1.0 and 1.1 as well. So do ancient versions of GnuTLS,
+            # but this was considered a bug which was fixed in GnuTLS 3.4.7.
+            # Check the GnuTLS support list to see what the protocol version
+            # requirement is for that cipher suite.
+            if [ `minor_ver "$MODE"` -ge 3 ] || {
+                   [ `minor_ver "$MODE"` -gt 0 ] &&
+                   $GNUTLS_CLI --list | grep -q '^TLS_RSA_NULL_SHA256.*0$'
+               }
             then
                 M_CIPHERS="$M_CIPHERS                           \
                     TLS-RSA-WITH-NULL-SHA256                    \
@@ -972,7 +986,7 @@
     fi
 
     M_SERVER_ARGS="server_port=$PORT server_addr=0.0.0.0 force_version=$MODE arc4=1"
-    O_SERVER_ARGS="-accept $PORT -cipher NULL,ALL -$O_MODE"
+    O_SERVER_ARGS="-accept $PORT -cipher ALL,COMPLEMENTOFALL -$O_MODE"
     G_SERVER_ARGS="-p $PORT --http $G_MODE"
     G_SERVER_PRIO="NORMAL:${G_PRIO_CCM}+ARCFOUR-128:+NULL:+MD5:+PSK:+DHE-PSK:+ECDHE-PSK:+SHA256:+SHA384:+RSA-PSK:-VERS-TLS-ALL:$G_PRIO_MODE"
 
@@ -1218,12 +1232,16 @@
     fi
 }
 
+save_logs() {
+    cp $SRV_OUT c-srv-${TESTS}.log
+    cp $CLI_OUT c-cli-${TESTS}.log
+}
+
 # display additional information if test case fails
 report_fail() {
     FAIL_PROMPT="outputs saved to c-srv-${TESTS}.log, c-cli-${TESTS}.log"
     record_outcome "FAIL" "$FAIL_PROMPT"
-    cp $SRV_OUT c-srv-${TESTS}.log
-    cp $CLI_OUT c-cli-${TESTS}.log
+    save_logs
     echo "  ! $FAIL_PROMPT"
 
     if [ "${LOG_FAILURE_ON_STDOUT:-0}" != 0 ]; then
@@ -1349,6 +1367,9 @@
     case $RESULT in
         "0")
             record_outcome "PASS"
+            if [ "$PRESERVE_LOGS" -gt 0 ]; then
+                save_logs
+            fi
             ;;
         "1")
             record_outcome "SKIP"
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index afb4a9d..d3e9cda 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -50,10 +50,14 @@
 #   * G++
 #   * arm-gcc and mingw-gcc
 #   * ArmCC 5 and ArmCC 6, unless invoked with --no-armcc
-#   * OpenSSL and GnuTLS command line tools, recent enough for the
-#     interoperability tests. If they don't support SSLv3 then a legacy
-#     version of these tools must be present as well (search for LEGACY
-#     below).
+#   * OpenSSL and GnuTLS command line tools, in suitable versions for the
+#     interoperability tests. The following are the official versions at the
+#     time of writing:
+#     * GNUTLS_{CLI,SERV} = 3.4.10
+#     * GNUTLS_NEXT_{CLI,SERV} = 3.7.2
+#     * OPENSSL_LEGACY = 1.0.1j
+#     * OPENSSL = 1.0.2g (without Debian/Ubuntu patches)
+#     * OPENSSL_NEXT = 1.1.1a
 # See the invocation of check_tools below for details.
 #
 # This script must be invoked from the toplevel directory of a git
@@ -168,8 +172,6 @@
     : ${OPENSSL_NEXT:="$OPENSSL"}
     : ${GNUTLS_CLI:="gnutls-cli"}
     : ${GNUTLS_SERV:="gnutls-serv"}
-    : ${GNUTLS_LEGACY_CLI:="$GNUTLS_CLI"}
-    : ${GNUTLS_LEGACY_SERV:="$GNUTLS_SERV"}
     : ${OUT_OF_SOURCE_DIR:=./mbedtls_out_of_source_build}
     : ${ARMC5_BIN_DIR:=/usr/bin}
     : ${ARMC6_BIN_DIR:=/usr/bin}
@@ -286,8 +288,6 @@
      --gcc-latest=<GCC_latest_path>             Latest version of GCC available
      --gnutls-cli=<GnuTLS_cli_path>             GnuTLS client executable to use for most tests.
      --gnutls-serv=<GnuTLS_serv_path>           GnuTLS server executable to use for most tests.
-     --gnutls-legacy-cli=<GnuTLS_cli_path>      GnuTLS client executable to use for legacy tests.
-     --gnutls-legacy-serv=<GnuTLS_serv_path>    GnuTLS server executable to use for legacy tests.
      --openssl=<OpenSSL_path>                   OpenSSL executable to use for most tests.
      --openssl-legacy=<OpenSSL_path>            OpenSSL executable to use for legacy tests e.g. SSLv3.
      --openssl-next=<OpenSSL_path>              OpenSSL executable to use for recent things like ARIA
@@ -435,8 +435,8 @@
             --gcc-earliest) shift; GCC_EARLIEST="$1";;
             --gcc-latest) shift; GCC_LATEST="$1";;
             --gnutls-cli) shift; GNUTLS_CLI="$1";;
-            --gnutls-legacy-cli) shift; GNUTLS_LEGACY_CLI="$1";;
-            --gnutls-legacy-serv) shift; GNUTLS_LEGACY_SERV="$1";;
+            --gnutls-legacy-cli) shift;; # ignored for backward compatibility
+            --gnutls-legacy-serv) shift;; # ignored for backward compatibility
             --gnutls-serv) shift; GNUTLS_SERV="$1";;
             --help|-h) usage; exit;;
             --keep-going|-k) KEEP_GOING=1;;
@@ -709,8 +709,6 @@
     echo "OPENSSL_NEXT: $OPENSSL_NEXT"
     echo "GNUTLS_CLI: $GNUTLS_CLI"
     echo "GNUTLS_SERV: $GNUTLS_SERV"
-    echo "GNUTLS_LEGACY_CLI: $GNUTLS_LEGACY_CLI"
-    echo "GNUTLS_LEGACY_SERV: $GNUTLS_LEGACY_SERV"
     echo "ARMC5_BIN_DIR: $ARMC5_BIN_DIR"
     echo "ARMC6_BIN_DIR: $ARMC6_BIN_DIR"
 }
@@ -736,11 +734,8 @@
             fi
             set "$@" OPENSSL="$OPENSSL" OPENSSL_LEGACY="$OPENSSL_LEGACY"
             set "$@" GNUTLS_CLI="$GNUTLS_CLI" GNUTLS_SERV="$GNUTLS_SERV"
-            set "$@" GNUTLS_LEGACY_CLI="$GNUTLS_LEGACY_CLI"
-            set "$@" GNUTLS_LEGACY_SERV="$GNUTLS_LEGACY_SERV"
             check_tools "$OPENSSL" "$OPENSSL_LEGACY" "$OPENSSL_NEXT" \
-                        "$GNUTLS_CLI" "$GNUTLS_SERV" \
-                        "$GNUTLS_LEGACY_CLI" "$GNUTLS_LEGACY_SERV"
+                        "$GNUTLS_CLI" "$GNUTLS_SERV"
             ;;
     esac
 
@@ -873,6 +868,9 @@
 
     msg "selftest: make, default config (out-of-box)" # ~10s
     programs/test/selftest
+
+    msg "program demos: make, default config (out-of-box)" # ~10s
+    tests/scripts/run_demos.py
 }
 
 component_test_default_cmake_gcc_asan () {
@@ -883,6 +881,9 @@
     msg "test: main suites (inc. selftests) (ASan build)" # ~ 50s
     make test
 
+    msg "program demos (ASan build)" # ~10s
+    tests/scripts/run_demos.py
+
     msg "test: selftest (ASan build)" # ~ 10s
     programs/test/selftest
 
@@ -1031,8 +1032,7 @@
     make test
 
     msg "build: SSLv3 - compat.sh (ASan build)" # ~ 6 min
-    tests/compat.sh -m 'tls1 tls1_1 tls12 dtls1 dtls12'
-    env OPENSSL="$OPENSSL_LEGACY" tests/compat.sh -m 'ssl3'
+    tests/compat.sh -m 'ssl3 tls1 tls1_1 tls12 dtls1 dtls12'
 
     msg "build: SSLv3 - ssl-opt.sh (ASan build)" # ~ 6 min
     tests/ssl-opt.sh
@@ -1584,14 +1584,20 @@
     msg "test: cpp_dummy_build (full config, clang)" # ~ 1s
     programs/test/cpp_dummy_build
 
+    msg "program demos (full config, clang)" # ~10s
+    tests/scripts/run_demos.py
+
     msg "test: psa_constant_names (full config, clang)" # ~ 1s
     tests/scripts/test_psa_constant_names.py
 
     msg "test: ssl-opt.sh default, ECJPAKE, SSL async (full config)" # ~ 1s
     tests/ssl-opt.sh -f 'Default\|ECJPAKE\|SSL async private'
 
-    msg "test: compat.sh RC4, DES, 3DES & NULL (full config)" # ~ 2 min
-    env OPENSSL="$OPENSSL_LEGACY" GNUTLS_CLI="$GNUTLS_LEGACY_CLI" GNUTLS_SERV="$GNUTLS_LEGACY_SERV" tests/compat.sh -e '^$' -f 'NULL\|DES\|RC4\|ARCFOUR'
+    msg "test: compat.sh RC4, 3DES & NULL (full config)" # ~ 2min
+    tests/compat.sh -e '^$' -f 'NULL\|3DES\|DES-CBC3\|RC4\|ARCFOUR'
+
+    msg "test: compat.sh single-DES (full config)" # ~ 30s
+    env OPENSSL="$OPENSSL_LEGACY" tests/compat.sh -e '3DES\|DES-CBC3' -f 'DES'
 
     msg "test: compat.sh ARIA + ChachaPoly"
     env OPENSSL="$OPENSSL_NEXT" tests/compat.sh -e '^$' -f 'ARIA\|CHACHA'
@@ -1701,6 +1707,9 @@
 
     msg "test: full config + MBEDTLS_TEST_DEPRECATED" # ~ 30s
     make test
+
+    msg "program demos: full config + MBEDTLS_TEST_DEPRECATED" # ~10s
+    tests/scripts/run_demos.py
 }
 
 # Check that the specified libraries exist and are empty.
@@ -1881,8 +1890,11 @@
     msg "test: compat.sh default (full minus MBEDTLS_USE_PSA_CRYPTO)"
     tests/compat.sh
 
-    msg "test: compat.sh RC4, DES & NULL (full minus MBEDTLS_USE_PSA_CRYPTO)"
-    env OPENSSL="$OPENSSL_LEGACY" GNUTLS_CLI="$GNUTLS_LEGACY_CLI" GNUTLS_SERV="$GNUTLS_LEGACY_SERV" tests/compat.sh -e '3DES\|DES-CBC3' -f 'NULL\|DES\|RC4\|ARCFOUR'
+    msg "test: compat.sh RC4, 3DES & NULL (full minus MBEDTLS_USE_PSA_CRYPTO)"
+    tests/compat.sh -e '^$' -f 'NULL\|3DES\|DES-CBC3\|RC4\|ARCFOUR'
+
+    msg "test: compat.sh single-DES (full minus MBEDTLS_USE_PSA_CRYPTO)"
+    env OPENSSL="$OPENSSL_LEGACY" tests/compat.sh -e '3DES\|DES-CBC3' -f 'DES'
 
     msg "test: compat.sh ARIA + ChachaPoly (full minus MBEDTLS_USE_PSA_CRYPTO)"
     env OPENSSL="$OPENSSL_NEXT" tests/compat.sh -e '^$' -f 'ARIA\|CHACHA'
@@ -3327,7 +3339,16 @@
     make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 SHARED=1 lib programs
     make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 SHARED=1 tests
     make WINDOWS_BUILD=1 clean
-}
+
+    msg "build: Windows cross build - mingw64, make (Library only, AESNI intrinsics)" # ~ 30s
+    make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra -maes -msse2 -mpclmul' WINDOWS_BUILD=1 lib
+    make WINDOWS_BUILD=1 clean
+
+    msg "build: Windows cross build - mingw64, make (Library only, default config without MBEDTLS_AESNI_C)" # ~ 30s
+    ./scripts/config.py unset MBEDTLS_AESNI_C
+    make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 lib
+    make WINDOWS_BUILD=1 clean
+ }
 support_build_mingw() {
     case $(i686-w64-mingw32-gcc -dumpversion 2>/dev/null) in
         [0-5]*|"") false;;
@@ -3344,6 +3365,9 @@
     msg "test: main suites (MSan)" # ~ 10s
     make test
 
+    msg "program demos (MSan)" # ~20s
+    tests/scripts/run_demos.py
+
     msg "test: ssl-opt.sh (MSan)" # ~ 1 min
     tests/ssl-opt.sh
 
diff --git a/tests/scripts/basic-build-test.sh b/tests/scripts/basic-build-test.sh
index 196ce45..970abfa 100755
--- a/tests/scripts/basic-build-test.sh
+++ b/tests/scripts/basic-build-test.sh
@@ -51,8 +51,6 @@
 : ${OPENSSL_LEGACY:="$OPENSSL"}
 : ${GNUTLS_CLI:="gnutls-cli"}
 : ${GNUTLS_SERV:="gnutls-serv"}
-: ${GNUTLS_LEGACY_CLI:="$GNUTLS_CLI"}
-: ${GNUTLS_LEGACY_SERV:="$GNUTLS_SERV"}
 
 # Used to make ssl-opt.sh deterministic.
 #
@@ -81,8 +79,6 @@
     OPENSSL_LEGACY="$OPENSSL_LEGACY"         \
     GNUTLS_CLI="$GNUTLS_CLI"                 \
     GNUTLS_SERV="$GNUTLS_SERV"               \
-    GNUTLS_LEGACY_CLI="$GNUTLS_LEGACY_CLI"   \
-    GNUTLS_LEGACY_SERV="$GNUTLS_LEGACY_SERV" \
     scripts/output_env.sh
 echo
 
@@ -120,17 +116,12 @@
 # Step 2c - Compatibility tests (keep going even if some tests fail)
 echo '################ compat.sh ################'
 {
-    echo '#### compat.sh: Default versions'
-    sh compat.sh -m 'tls1 tls1_1 tls12 dtls1 dtls12'
-    echo
-
-    echo '#### compat.sh: legacy (SSLv3)'
-    OPENSSL="$OPENSSL_LEGACY" sh compat.sh -m 'ssl3'
+    echo '#### compat.sh: Default ciphers'
+    sh compat.sh -m 'ssl3 tls1 tls1_1 tls12 dtls1 dtls12'
     echo
 
     echo '#### compat.sh: legacy (null, DES, RC4)'
     OPENSSL="$OPENSSL_LEGACY" \
-    GNUTLS_CLI="$GNUTLS_LEGACY_CLI" GNUTLS_SERV="$GNUTLS_LEGACY_SERV" \
     sh compat.sh -e '^$' -f 'NULL\|DES\|RC4\|ARCFOUR'
     echo
 
diff --git a/tests/scripts/check_files.py b/tests/scripts/check_files.py
index 352b55e..238a83f 100755
--- a/tests/scripts/check_files.py
+++ b/tests/scripts/check_files.py
@@ -162,24 +162,6 @@
     return ext in ('.bat', '.dsp', '.dsw', '.sln', '.vcxproj')
 
 
-class PermissionIssueTracker(FileIssueTracker):
-    """Track files with bad permissions.
-
-    Files that are not executable scripts must not be executable."""
-
-    heading = "Incorrect permissions:"
-
-    # .py files can be either full scripts or modules, so they may or may
-    # not be executable.
-    suffix_exemptions = frozenset({".py"})
-
-    def check_file_for_issue(self, filepath):
-        is_executable = os.access(filepath, os.X_OK)
-        should_be_executable = filepath.endswith((".sh", ".pl"))
-        if is_executable != should_be_executable:
-            self.files_with_issues[filepath] = None
-
-
 class ShebangIssueTracker(FileIssueTracker):
     """Track files with a bad, missing or extraneous shebang line.
 
@@ -386,7 +368,6 @@
         self.logger = None
         self.setup_logger(log_file)
         self.issues_to_check = [
-            PermissionIssueTracker(),
             ShebangIssueTracker(),
             EndOfFileNewlineIssueTracker(),
             Utf8BomIssueTracker(),
diff --git a/tests/scripts/check_names.py b/tests/scripts/check_names.py
index 8c08e5c..96a1d3c 100755
--- a/tests/scripts/check_names.py
+++ b/tests/scripts/check_names.py
@@ -930,7 +930,7 @@
             "This script confirms that the naming of all symbols and identifiers "
             "in Mbed TLS are consistent with the house style and are also "
             "self-consistent.\n\n"
-            "Expected to be run from the MbedTLS root directory.")
+            "Expected to be run from the Mbed TLS root directory.")
     )
     parser.add_argument(
         "-v", "--verbose",
diff --git a/tests/scripts/run_demos.py b/tests/scripts/run_demos.py
new file mode 100755
index 0000000..6a63d23
--- /dev/null
+++ b/tests/scripts/run_demos.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python3
+"""Run the Mbed TLS demo scripts.
+"""
+import argparse
+import glob
+import subprocess
+import sys
+
+def run_demo(demo, quiet=False):
+    """Run the specified demo script. Return True if it succeeds."""
+    args = {}
+    if quiet:
+        args['stdout'] = subprocess.DEVNULL
+        args['stderr'] = subprocess.DEVNULL
+    returncode = subprocess.call([demo], **args)
+    return returncode == 0
+
+def run_demos(demos, quiet=False):
+    """Run the specified demos and print summary information about failures.
+
+    Return True if all demos passed and False if a demo fails.
+    """
+    failures = []
+    for demo in demos:
+        if not quiet:
+            print('#### {} ####'.format(demo))
+        success = run_demo(demo, quiet=quiet)
+        if not success:
+            failures.append(demo)
+            if not quiet:
+                print('{}: FAIL'.format(demo))
+        if quiet:
+            print('{}: {}'.format(demo, 'PASS' if success else 'FAIL'))
+        else:
+            print('')
+    successes = len(demos) - len(failures)
+    print('{}/{} demos passed'.format(successes, len(demos)))
+    if failures and not quiet:
+        print('Failures:', *failures)
+    return not failures
+
+def run_all_demos(quiet=False):
+    """Run all the available demos.
+
+    Return True if all demos passed and False if a demo fails.
+    """
+    all_demos = glob.glob('programs/*/*_demo.sh')
+    if not all_demos:
+        # Keep the message on one line. pylint: disable=line-too-long
+        raise Exception('No demos found. run_demos needs to operate from the Mbed TLS toplevel directory.')
+    return run_demos(all_demos, quiet=quiet)
+
+def main():
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument('--quiet', '-q',
+                        action='store_true',
+                        help="suppress the output of demos")
+    options = parser.parse_args()
+    success = run_all_demos(quiet=options.quiet)
+    sys.exit(0 if success else 1)
+
+if __name__ == '__main__':
+    main()
diff --git a/tests/src/external_timing/timing_alt.h b/tests/src/external_timing/timing_alt.h
index 82e8c8b..d71ceb9 100644
--- a/tests/src/external_timing/timing_alt.h
+++ b/tests/src/external_timing/timing_alt.h
@@ -1,5 +1,5 @@
 /*
- * Copy of the internal MbedTLS timing implementation, to be used in tests.
+ * Copy of the internal Mbed TLS timing implementation, to be used in tests.
  */
 /*
  *  Copyright The Mbed TLS Contributors
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 3a27aac..4b6b695 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -81,14 +81,6 @@
 
 # alternative versions of OpenSSL and GnuTLS (no default path)
 
-if [ -n "${OPENSSL_LEGACY:-}" ]; then
-    O_LEGACY_SRV="$OPENSSL_LEGACY s_server -www -cert data_files/server5.crt -key data_files/server5.key"
-    O_LEGACY_CLI="echo 'GET / HTTP/1.0' | $OPENSSL_LEGACY s_client"
-else
-    O_LEGACY_SRV=false
-    O_LEGACY_CLI=false
-fi
-
 if [ -n "${OPENSSL_NEXT:-}" ]; then
     O_NEXT_SRV="$OPENSSL_NEXT s_server -www -cert data_files/server5.crt -key data_files/server5.key"
     O_NEXT_CLI="echo 'GET / HTTP/1.0' | $OPENSSL_NEXT s_client"
@@ -456,20 +448,6 @@
     fi
 }
 
-# skip next test if OpenSSL-legacy isn't available
-requires_openssl_legacy() {
-    if [ -z "${OPENSSL_LEGACY_AVAILABLE:-}" ]; then
-        if which "${OPENSSL_LEGACY:-}" >/dev/null 2>&1; then
-            OPENSSL_LEGACY_AVAILABLE="YES"
-        else
-            OPENSSL_LEGACY_AVAILABLE="NO"
-        fi
-    fi
-    if [ "$OPENSSL_LEGACY_AVAILABLE" = "NO" ]; then
-        SKIP_NEXT="YES"
-    fi
-}
-
 requires_openssl_next() {
     if [ -z "${OPENSSL_NEXT_AVAILABLE:-}" ]; then
         if which "${OPENSSL_NEXT:-}" >/dev/null 2>&1; then
@@ -1502,11 +1480,6 @@
 G_SRV="$G_SRV -p $SRV_PORT"
 G_CLI="$G_CLI -p +SRV_PORT"
 
-if [ -n "${OPENSSL_LEGACY:-}" ]; then
-    O_LEGACY_SRV="$O_LEGACY_SRV -accept $SRV_PORT -dhparam data_files/dhparams.pem"
-    O_LEGACY_CLI="$O_LEGACY_CLI -connect 127.0.0.1:+SRV_PORT"
-fi
-
 # Newer versions of OpenSSL have a syntax to enable all "ciphers", even
 # low-security ones. This covers not just cipher suites but also protocol
 # versions. It is necessary, for example, to use (D)TLS 1.0/1.1 on
diff --git a/tests/suites/host_test.function b/tests/suites/host_test.function
index 06f391f..d8ff49e 100644
--- a/tests/suites/host_test.function
+++ b/tests/suites/host_test.function
@@ -432,6 +432,50 @@
     fflush(outcome_file);
 }
 
+#if defined(__unix__) ||                                \
+    (defined(__APPLE__) && defined(__MACH__))
+#define MBEDTLS_HAVE_CHDIR
+#endif
+
+#if defined(MBEDTLS_HAVE_CHDIR)
+/** Try chdir to the directory containing argv0.
+ *
+ * Failures are silent.
+ */
+static void try_chdir_if_supported(const char *argv0)
+{
+    /* We might want to allow backslash as well, for Windows. But then we also
+     * need to consider chdir() vs _chdir(), and different conventions
+     * regarding paths in argv[0] (naively enabling this code with
+     * backslash support on Windows leads to chdir into the wrong directory
+     * on the CI). */
+    const char *slash = strrchr(argv0, '/');
+    if (slash == NULL) {
+        return;
+    }
+    size_t path_size = slash - argv0 + 1;
+    char *path = mbedtls_calloc(1, path_size);
+    if (path == NULL) {
+        return;
+    }
+    memcpy(path, argv0, path_size - 1);
+    path[path_size - 1] = 0;
+    int ret = chdir(path);
+    if (ret != 0) {
+        mbedtls_fprintf(stderr, "%s: note: chdir(\"%s\") failed.\n",
+                        __func__, path);
+    }
+    mbedtls_free(path);
+}
+#else /* MBEDTLS_HAVE_CHDIR */
+/* No chdir() or no support for parsing argv[0] on this platform. */
+static void try_chdir_if_supported(const char *argv0)
+{
+    (void) argv0;
+    return;
+}
+#endif /* MBEDTLS_HAVE_CHDIR */
+
 /**
  * \brief       Desktop implementation of execute_tests().
  *              Parses command line and executes tests from
diff --git a/tests/suites/main_test.function b/tests/suites/main_test.function
index 335ce84..a69442d 100644
--- a/tests/suites/main_test.function
+++ b/tests/suites/main_test.function
@@ -278,6 +278,21 @@
     mbedtls_test_hook_error_add = &mbedtls_test_err_add_check;
 #endif
 
+    /* Try changing to the directory containing the executable, if
+     * using the default data file. This allows running the executable
+     * from another directory (e.g. the project root) and still access
+     * the .datax file as well as data files used by test cases
+     * (typically from tests/data_files).
+     *
+     * Note that we do this before the platform setup (which may access
+     * files such as a random seed). We also do this before accessing
+     * test-specific files such as the outcome file, which is arguably
+     * not desirable and should be fixed later.
+     */
+    if (argc == 1) {
+        try_chdir_if_supported(argv[0]);
+    }
+
     int ret = mbedtls_test_platform_setup();
     if (ret != 0) {
         mbedtls_fprintf(stderr,