Merge pull request #6201 from gilles-peskine-arm/tls13_only-renegotiation

Disable MBEDTLS_SSL_RENEGOTIATION in TLS-1.3-only builds
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index 2d2fae5..3065df5 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -712,41 +712,6 @@
 #if defined(MBEDTLS_SHA512_ALT) || defined(MBEDTLS_SHA512_PROCESS_ALT)
 #error "MBEDTLS_SHA512_*ALT can't be used with MBEDTLS_SHA512_USE_A64_CRYPTO_*"
 #endif
-/*
- * Best performance comes from most recent compilers, with intrinsics and -O3.
- * Must compile with -march=armv8.2-a+sha3, but we can't detect armv8.2-a, and
- * can't always detect __ARM_FEATURE_SHA512 (notably clang 7-12).
- *
- * GCC < 8 won't work at all (lacks the sha512 instructions)
- * GCC >= 8 uses intrinsics, sets __ARM_FEATURE_SHA512
- *
- * Clang < 7 won't work at all (lacks the sha512 instructions)
- * Clang 7-12 don't have intrinsics (but we work around that with inline
- *            assembler) or __ARM_FEATURE_SHA512
- * Clang == 13.0.0 same as clang 12 (only seen on macOS)
- * Clang >= 13.0.1 has __ARM_FEATURE_SHA512 and intrinsics
- */
-#if defined(__aarch64__) && !defined(__ARM_FEATURE_SHA512)
-   /* Test Clang first, as it defines __GNUC__ */
-#  if defined(__clang__)
-#    if __clang_major__ < 7
-#      error "A more recent Clang is required for MBEDTLS_SHA512_USE_A64_CRYPTO_*"
-#    elif __clang_major__ < 13 || \
-         (__clang_major__ == 13 && __clang_minor__ == 0 && __clang_patchlevel__ == 0)
-       /* We implement the intrinsics with inline assembler, so don't error */
-#    else
-#      error "Must use minimum -march=armv8.2-a+sha3 for MBEDTLS_SHA512_USE_A64_CRYPTO_*"
-#    endif
-#  elif defined(__GNUC__)
-#    if __GNUC__ < 8
-#      error "A more recent GCC is required for MBEDTLS_SHA512_USE_A64_CRYPTO_*"
-#    else
-#      error "Must use minimum -march=armv8.2-a+sha3 for MBEDTLS_SHA512_USE_A64_CRYPTO_*"
-#    endif
-#  else
-#    error "Only GCC and Clang supported for MBEDTLS_SHA512_USE_A64_CRYPTO_*"
-#  endif
-#endif
 
 #endif /* MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT || MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY */
 
@@ -767,9 +732,7 @@
 #if defined(MBEDTLS_SHA256_ALT) || defined(MBEDTLS_SHA256_PROCESS_ALT)
 #error "MBEDTLS_SHA256_*ALT can't be used with MBEDTLS_SHA256_USE_A64_CRYPTO_*"
 #endif
-#if defined(__aarch64__) && !defined(__ARM_FEATURE_CRYPTO)
-#error "Must use minimum -march=armv8-a+crypto for MBEDTLS_SHA256_USE_A64_CRYPTO_*"
-#endif
+
 #endif
 
 #if defined(MBEDTLS_SHA256_USE_A64_CRYPTO_ONLY) && \
diff --git a/include/mbedtls/mbedtls_config.h b/include/mbedtls/mbedtls_config.h
index 5aff9c5..1995e54 100644
--- a/include/mbedtls/mbedtls_config.h
+++ b/include/mbedtls/mbedtls_config.h
@@ -3115,9 +3115,6 @@
  * \note If MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT is defined when building
  * for a non-Aarch64 build it will be silently ignored.
  *
- * \note The code uses Neon intrinsics, so \c CFLAGS must be set to a minimum
- * of \c -march=armv8-a+crypto.
- *
  * \warning MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT cannot be defined at the
  * same time as MBEDTLS_SHA256_USE_A64_CRYPTO_ONLY.
  *
@@ -3140,9 +3137,6 @@
  * \note This allows builds with a smaller code size than with
  * MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT
  *
- * \note The code uses Neon intrinsics, so \c CFLAGS must be set to a minimum
- * of \c -march=armv8-a+crypto.
- *
  * \warning MBEDTLS_SHA256_USE_A64_CRYPTO_ONLY cannot be defined at the same
  * time as MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT.
  *
@@ -3197,9 +3191,7 @@
  * for a non-Aarch64 build it will be silently ignored.
  *
  * \note The code uses the SHA-512 Neon intrinsics, so requires GCC >= 8 or
- * Clang >= 7, and \c CFLAGS must be set to a minimum of
- * \c -march=armv8.2-a+sha3. An optimisation level of \c -O3 generates the
- * fastest code.
+ * Clang >= 7.
  *
  * \warning MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT cannot be defined at the
  * same time as MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY.
@@ -3224,9 +3216,7 @@
  * MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT
  *
  * \note The code uses the SHA-512 Neon intrinsics, so requires GCC >= 8 or
- * Clang >= 7, and \c CFLAGS must be set to a minimum of
- * \c -march=armv8.2-a+sha3. An optimisation level of \c -O3 generates the
- * fastest code.
+ * Clang >= 7.
  *
  * \warning MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY cannot be defined at the same
  * time as MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT.
diff --git a/library/sha256.c b/library/sha256.c
index cb09a71..23cd406 100644
--- a/library/sha256.c
+++ b/library/sha256.c
@@ -22,6 +22,23 @@
  *  http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
  */
 
+#if defined(__aarch64__) && !defined(__ARM_FEATURE_CRYPTO) && \
+    defined(__clang__) &&  __clang_major__ < 18 && __clang_major__ > 3
+/* TODO: Re-consider above after https://reviews.llvm.org/D131064 merged.
+ *
+ * The intrinsic declaration are guarded by predefined ACLE macros in clang:
+ * these are normally only enabled by the -march option on the command line.
+ * By defining the macros ourselves we gain access to those declarations without
+ * requiring -march on the command line.
+ *
+ * `arm_neon.h` could be included by any header file, so we put these defines
+ * at the top of this file, before any includes.
+ */
+#define __ARM_FEATURE_CRYPTO 1
+#define NEED_TARGET_OPTIONS
+#endif /* __aarch64__ && __clang__ &&
+          !__ARM_FEATURE_CRYPTO && __clang_major__ < 18 && __clang_major__ > 3 */
+
 #include "common.h"
 
 #if defined(MBEDTLS_SHA256_C) || defined(MBEDTLS_SHA224_C)
@@ -37,6 +54,30 @@
 #if defined(__aarch64__)
 #  if defined(MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT) || \
     defined(MBEDTLS_SHA256_USE_A64_CRYPTO_ONLY)
+/* *INDENT-OFF* */
+#    if !defined(__ARM_FEATURE_CRYPTO) || defined(NEED_TARGET_OPTIONS)
+#      if defined(__clang__)
+#        if __clang_major__ < 4
+#          error "A more recent Clang is required for MBEDTLS_SHA256_USE_A64_CRYPTO_*"
+#        endif
+#        pragma clang attribute push (__attribute__((target("crypto"))), apply_to=function)
+#        define MBEDTLS_POP_TARGET_PRAGMA
+#      elif defined(__GNUC__)
+         /* FIXME: GCC-5 annouce crypto extension, but some intrinsic are missed.
+          *        Known miss intrinsic can be workaround.
+          */
+#        if __GNUC__ < 6
+#          error "A more recent GCC is required for MBEDTLS_SHA256_USE_A64_CRYPTO_*"
+#        else
+#          pragma GCC push_options
+#          pragma GCC target ("arch=armv8-a+crypto")
+#          define MBEDTLS_POP_TARGET_PRAGMA
+#        endif
+#      else
+#        error "Only GCC and Clang supported for MBEDTLS_SHA256_USE_A64_CRYPTO_*"
+#      endif
+#    endif
+/* *INDENT-ON* */
 #    include <arm_neon.h>
 #  endif
 #  if defined(MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT)
@@ -353,8 +394,16 @@
             SHA256_BLOCK_SIZE) ? 0 : -1;
 }
 
-#endif /* MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT || MBEDTLS_SHA256_USE_A64_CRYPTO_ONLY */
+#if defined(MBEDTLS_POP_TARGET_PRAGMA)
+#if defined(__clang__)
+#pragma clang attribute pop
+#elif defined(__GNUC__)
+#pragma GCC pop_options
+#endif
+#undef MBEDTLS_POP_TARGET_PRAGMA
+#endif
 
+#endif /* MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT || MBEDTLS_SHA256_USE_A64_CRYPTO_ONLY */
 
 #if !defined(MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT)
 #define mbedtls_internal_sha256_process_many_c mbedtls_internal_sha256_process_many
diff --git a/library/sha512.c b/library/sha512.c
index efcbed4..bc92a8d 100644
--- a/library/sha512.c
+++ b/library/sha512.c
@@ -22,6 +22,26 @@
  *  http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
  */
 
+#if defined(__aarch64__) && !defined(__ARM_FEATURE_SHA512) && \
+    defined(__clang__) &&  __clang_major__ < 18 && \
+    __clang_major__ >= 13 && __clang_minor__ > 0 && __clang_patchlevel__ > 0
+/* TODO: Re-consider above after https://reviews.llvm.org/D131064 merged.
+ *
+ * The intrinsic declaration are guarded by predefined ACLE macros in clang:
+ * these are normally only enabled by the -march option on the command line.
+ * By defining the macros ourselves we gain access to those declarations without
+ * requiring -march on the command line.
+ *
+ * `arm_neon.h` could be included by any header file, so we put these defines
+ * at the top of this file, before any includes.
+ */
+#define __ARM_FEATURE_SHA512 1
+#define NEED_TARGET_OPTIONS
+#endif /* __aarch64__ && __clang__ &&
+          !__ARM_FEATURE_SHA512 && __clang_major__ < 18 &&
+          __clang_major__ >= 13 && __clang_minor__ > 0 &&
+          __clang_patchlevel__ > 0 */
+
 #include "common.h"
 
 #if defined(MBEDTLS_SHA512_C) || defined(MBEDTLS_SHA384_C)
@@ -43,6 +63,47 @@
 #if defined(__aarch64__)
 #  if defined(MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT) || \
     defined(MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY)
+/* *INDENT-OFF* */
+/*
+ * Best performance comes from most recent compilers, with intrinsics and -O3.
+ * Must compile with -march=armv8.2-a+sha3, but we can't detect armv8.2-a, and
+ * can't always detect __ARM_FEATURE_SHA512 (notably clang 7-12).
+ *
+ * GCC < 8 won't work at all (lacks the sha512 instructions)
+ * GCC >= 8 uses intrinsics, sets __ARM_FEATURE_SHA512
+ *
+ * Clang < 7 won't work at all (lacks the sha512 instructions)
+ * Clang 7-12 don't have intrinsics (but we work around that with inline
+ *            assembler) or __ARM_FEATURE_SHA512
+ * Clang == 13.0.0 same as clang 12 (only seen on macOS)
+ * Clang >= 13.0.1 has __ARM_FEATURE_SHA512 and intrinsics
+ */
+#    if !defined(__ARM_FEATURE_SHA512) || defined(NEED_TARGET_OPTIONS)
+       /* Test Clang first, as it defines __GNUC__ */
+#      if defined(__clang__)
+#        if __clang_major__ < 7
+#          error "A more recent Clang is required for MBEDTLS_SHA512_USE_A64_CRYPTO_*"
+#        elif __clang_major__ < 13 || \
+              (__clang_major__ == 13 && __clang_minor__ == 0 && \
+               __clang_patchlevel__ == 0)
+           /* We implement the intrinsics with inline assembler, so don't error */
+#        else
+#          pragma clang attribute push (__attribute__((target("sha3"))), apply_to=function)
+#          define MBEDTLS_POP_TARGET_PRAGMA
+#        endif
+#      elif defined(__GNUC__)
+#        if __GNUC__ < 8
+#          error "A more recent GCC is required for MBEDTLS_SHA512_USE_A64_CRYPTO_*"
+#        else
+#          pragma GCC push_options
+#          pragma GCC target ("arch=armv8.2-a+sha3")
+#          define MBEDTLS_POP_TARGET_PRAGMA
+#        endif
+#      else
+#        error "Only GCC and Clang supported for MBEDTLS_SHA512_USE_A64_CRYPTO_*"
+#      endif
+#    endif
+/* *INDENT-ON* */
 #    include <arm_neon.h>
 #  endif
 #  if defined(MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT)
@@ -516,6 +577,15 @@
             SHA512_BLOCK_SIZE) ? 0 : -1;
 }
 
+#if defined(MBEDTLS_POP_TARGET_PRAGMA)
+#if defined(__clang__)
+#pragma clang attribute pop
+#elif defined(__GNUC__)
+#pragma GCC pop_options
+#endif
+#undef MBEDTLS_POP_TARGET_PRAGMA
+#endif
+
 #endif /* MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT || MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY */
 
 
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 353ec69..61233f8 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -388,7 +388,7 @@
 
     msg "build: ARM Compiler 6 ($FLAGS)"
     ARM_TOOL_VARIANT="ult" CC="$ARMC6_CC" AR="$ARMC6_AR" CFLAGS="$FLAGS" \
-                    WARNING_CFLAGS='-xc -std=c99' make lib
+                    WARNING_CFLAGS='-Werror -xc -std=c99' make lib
 
     msg "size: ARM Compiler 6 ($FLAGS)"
     "$ARMC6_FROMELF" -z library/*.o
@@ -3479,6 +3479,15 @@
     scripts/config.py baremetal
     # armc[56] don't support SHA-512 intrinsics
     scripts/config.py unset MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT
+
+    # Stop armclang warning about feature detection for A64_CRYPTO.
+    # With this enabled, the library does build correctly under armclang,
+    # but in baremetal builds (as tested here), feature detection is
+    # unavailable, and the user is notified via a #warning. So enabling
+    # this feature would prevent us from building with -Werror on
+    # armclang. Tracked in #7198.
+    scripts/config.py unset MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT
+
     scripts/config.py set MBEDTLS_HAVE_ASM
 
     make CC="$ARMC5_CC" AR="$ARMC5_AR" WARNING_CFLAGS='--strict --c99' lib
diff --git a/tests/scripts/depends.py b/tests/scripts/depends.py
index 52ca412..581baad 100755
--- a/tests/scripts/depends.py
+++ b/tests/scripts/depends.py
@@ -23,7 +23,7 @@
 This script can be divided into several steps:
 
 First, include/mbedtls/mbedtls_config.h or a different config file passed
-in the arguments is parsed to extract any configuration options (collect_config_symbols).
+in the arguments is parsed to extract any configuration options (using config.py).
 
 Then, test domains (groups of jobs, tests) are built based on predefined data
 collected in the DomainData class. Here, each domain has five major traits:
@@ -65,6 +65,11 @@
 import subprocess
 import sys
 import traceback
+from typing import Union
+
+# Add the Mbed TLS Python library directory to the module search path
+import scripts_path # pylint: disable=unused-import
+import config
 
 class Colors: # pylint: disable=too-few-public-methods
     """Minimalistic support for colored output.
@@ -74,6 +79,7 @@
 stop switches the text color back to the default."""
     red = None
     green = None
+    cyan = None
     bold_red = None
     bold_green = None
     def __init__(self, options=None):
@@ -89,6 +95,7 @@
             normal = '\033[0m'
             self.red = ('\033[31m', normal)
             self.green = ('\033[32m', normal)
+            self.cyan = ('\033[36m', normal)
             self.bold_red = ('\033[1;31m', normal)
             self.bold_green = ('\033[1;32m', normal)
 NO_COLORS = Colors(None)
@@ -124,34 +131,38 @@
     else:
         shutil.copy(options.config_backup, options.config)
 
-def run_config_py(options, args):
-    """Run scripts/config.py with the specified arguments."""
-    cmd = ['scripts/config.py']
-    if options.config != 'include/mbedtls/mbedtls_config.h':
-        cmd += ['--file', options.config]
-    cmd += args
-    log_command(cmd)
-    subprocess.check_call(cmd)
+def option_exists(conf, option):
+    return option in conf.settings
 
-def set_reference_config(options):
+def set_config_option_value(conf, option, colors, value: Union[bool, str]):
+    """Set/unset a configuration option, optionally specifying a value.
+value can be either True/False (set/unset config option), or a string,
+which will make a symbol defined with a certain value."""
+    if not option_exists(conf, option):
+        log_line('Symbol {} was not found in {}'.format(option, conf.filename), color=colors.red)
+        return False
+
+    if value is False:
+        log_command(['config.py', 'unset', option])
+        conf.unset(option)
+    elif value is True:
+        log_command(['config.py', 'set', option])
+        conf.set(option)
+    else:
+        log_command(['config.py', 'set', option, value])
+        conf.set(option, value)
+    return True
+
+def set_reference_config(conf, options, colors):
     """Change the library configuration file (mbedtls_config.h) to the reference state.
 The reference state is the one from which the tested configurations are
 derived."""
     # Turn off options that are not relevant to the tests and slow them down.
-    run_config_py(options, ['full'])
-    run_config_py(options, ['unset', 'MBEDTLS_TEST_HOOKS'])
+    log_command(['config.py', 'full'])
+    conf.adapt(config.full_adapter)
+    set_config_option_value(conf, 'MBEDTLS_TEST_HOOKS', colors, False)
     if options.unset_use_psa:
-        run_config_py(options, ['unset', 'MBEDTLS_USE_PSA_CRYPTO'])
-
-def collect_config_symbols(options):
-    """Read the list of settings from mbedtls_config.h.
-Return them in a generator."""
-    with open(options.config, encoding="utf-8") as config_file:
-        rx = re.compile(r'\s*(?://\s*)?#define\s+(\w+)\s*(?:$|/[/*])')
-        for line in config_file:
-            m = re.match(rx, line)
-            if m:
-                yield m.group(1)
+        set_config_option_value(conf, 'MBEDTLS_USE_PSA_CRYPTO', colors, False)
 
 class Job:
     """A job builds the library in a specific configuration and runs some tests."""
@@ -179,19 +190,16 @@
         elif what is False:
             log_line(self.name + ' FAILED', color=colors.red)
         else:
-            log_line('starting ' + self.name)
+            log_line('starting ' + self.name, color=colors.cyan)
 
-    def configure(self, options):
+    def configure(self, conf, options, colors):
         '''Set library configuration options as required for the job.'''
-        set_reference_config(options)
+        set_reference_config(conf, options, colors)
         for key, value in sorted(self.config_settings.items()):
-            if value is True:
-                args = ['set', key]
-            elif value is False:
-                args = ['unset', key]
-            else:
-                args = ['set', key, value]
-            run_config_py(options, args)
+            ret = set_config_option_value(conf, key, colors, value)
+            if ret is False:
+                return False
+        return True
 
     def test(self, options):
         '''Run the job's build and test commands.
@@ -382,11 +390,11 @@
         return [symbol for symbol in self.all_config_symbols
                 if re.match(regexp, symbol)]
 
-    def __init__(self, options):
+    def __init__(self, options, conf):
         """Gather data about the library and establish a list of domains to test."""
         build_command = [options.make_command, 'CFLAGS=-Werror']
         build_and_test = [build_command, [options.make_command, 'test']]
-        self.all_config_symbols = set(collect_config_symbols(options))
+        self.all_config_symbols = set(conf.settings.keys())
         # Find hash modules by name.
         hash_symbols = self.config_symbols_matching(r'MBEDTLS_(MD|RIPEMD|SHA)[0-9]+_C\Z')
         # Find elliptic curve enabling macros by name.
@@ -442,16 +450,19 @@
         else:
             return [self.jobs[name]]
 
-def run(options, job, colors=NO_COLORS):
+def run(options, job, conf, colors=NO_COLORS):
     """Run the specified job (a Job instance)."""
     subprocess.check_call([options.make_command, 'clean'])
     job.announce(colors, None)
-    job.configure(options)
+    if not job.configure(conf, options, colors):
+        job.announce(colors, False)
+        return False
+    conf.write()
     success = job.test(options)
     job.announce(colors, success)
     return success
 
-def run_tests(options, domain_data):
+def run_tests(options, domain_data, conf):
     """Run the desired jobs.
 domain_data should be a DomainData instance that describes the available
 domains and jobs.
@@ -467,7 +478,7 @@
     backup_config(options)
     try:
         for job in jobs:
-            success = run(options, job, colors=colors)
+            success = run(options, job, conf, colors=colors)
             if not success:
                 if options.keep_going:
                     failures.append(job.name)
@@ -533,7 +544,9 @@
                             default=True)
         options = parser.parse_args()
         os.chdir(options.directory)
-        domain_data = DomainData(options)
+        conf = config.ConfigFile(options.config)
+        domain_data = DomainData(options, conf)
+
         if options.tasks is True:
             options.tasks = sorted(domain_data.domains.keys())
         if options.list:
@@ -542,7 +555,7 @@
                     print(domain_name)
             sys.exit(0)
         else:
-            sys.exit(0 if run_tests(options, domain_data) else 1)
+            sys.exit(0 if run_tests(options, domain_data, conf) else 1)
     except Exception: # pylint: disable=broad-except
         traceback.print_exc()
         sys.exit(3)