| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 1 | #!/usr/bin/env python3 | 
|  | 2 |  | 
| Dave Rodgman | 4eb44e4 | 2023-11-03 12:15:12 +0000 | [diff] [blame] | 3 | # Copyright The Mbed TLS Contributors | 
| Dave Rodgman | 16799db | 2023-11-02 19:47:20 +0000 | [diff] [blame] | 4 | # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 5 |  | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 6 | """ | 
| Andrzej Kurek | 01af84a | 2022-10-09 05:29:44 -0400 | [diff] [blame] | 7 | Test Mbed TLS with a subset of algorithms. | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 8 |  | 
| Andrzej Kurek | 01af84a | 2022-10-09 05:29:44 -0400 | [diff] [blame] | 9 | This script can be divided into several steps: | 
|  | 10 |  | 
|  | 11 | First, include/mbedtls/mbedtls_config.h or a different config file passed | 
| Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 12 | in the arguments is parsed to extract any configuration options (using config.py). | 
| Andrzej Kurek | 01af84a | 2022-10-09 05:29:44 -0400 | [diff] [blame] | 13 |  | 
|  | 14 | Then, test domains (groups of jobs, tests) are built based on predefined data | 
|  | 15 | collected in the DomainData class. Here, each domain has five major traits: | 
| Andrzej Kurek | 629c412 | 2022-10-17 08:34:40 -0400 | [diff] [blame] | 16 | - domain name, can be used to run only specific tests via command-line; | 
| Andrzej Kurek | 01af84a | 2022-10-09 05:29:44 -0400 | [diff] [blame] | 17 | - configuration building method, described in detail below; | 
|  | 18 | - list of symbols passed to the configuration building method; | 
|  | 19 | - commands to be run on each job (only build, build and test, or any other custom); | 
|  | 20 | - optional list of symbols to be excluded from testing. | 
|  | 21 |  | 
|  | 22 | The configuration building method can be one of the three following: | 
|  | 23 |  | 
|  | 24 | - ComplementaryDomain - build a job for each passed symbol by disabling a single | 
|  | 25 | symbol and its reverse dependencies (defined in REVERSE_DEPENDENCIES); | 
|  | 26 |  | 
|  | 27 | - ExclusiveDomain - build a job where, for each passed symbol, only this particular | 
|  | 28 | one is defined and other symbols from the list are unset. For each job look for | 
|  | 29 | any non-standard symbols to set/unset in EXCLUSIVE_GROUPS. These are usually not | 
|  | 30 | direct dependencies, but rather non-trivial results of other configs missing. Then | 
|  | 31 | look for any unset symbols and handle their reverse dependencies. | 
|  | 32 | Examples of EXCLUSIVE_GROUPS usage: | 
| Andrzej Kurek | 01af84a | 2022-10-09 05:29:44 -0400 | [diff] [blame] | 33 | - MBEDTLS_SHA512_C job turns off all hashes except SHA512. MBEDTLS_SSL_COOKIE_C | 
|  | 34 | requires either SHA256 or SHA384 to work, so it also has to be disabled. | 
|  | 35 | This is not a dependency on SHA512_C, but a result of an exclusive domain | 
|  | 36 | config building method. Relevant field: | 
| Andrzej Kurek | 629c412 | 2022-10-17 08:34:40 -0400 | [diff] [blame] | 37 | 'MBEDTLS_SHA512_C': ['-MBEDTLS_SSL_COOKIE_C'], | 
| Andrzej Kurek | 01af84a | 2022-10-09 05:29:44 -0400 | [diff] [blame] | 38 |  | 
|  | 39 | - DualDomain - combination of the two above - both complementary and exclusive domain | 
|  | 40 | job generation code will be run. Currently only used for hashes. | 
|  | 41 |  | 
|  | 42 | Lastly, the collected jobs are executed and (optionally) tested, with | 
|  | 43 | error reporting and coloring as configured in options. Each test starts with | 
|  | 44 | a full config without a couple of slowing down or unnecessary options | 
|  | 45 | (see set_reference_config), then the specific job config is derived. | 
|  | 46 | """ | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 47 | import argparse | 
|  | 48 | import os | 
|  | 49 | import re | 
|  | 50 | import shutil | 
|  | 51 | import subprocess | 
|  | 52 | import sys | 
|  | 53 | import traceback | 
| Andrzej Kurek | 576803f | 2023-01-24 07:40:42 -0500 | [diff] [blame] | 54 | from typing import Union | 
|  | 55 |  | 
| Andrzej Kurek | 3b0215d | 2023-01-23 07:19:22 -0500 | [diff] [blame] | 56 | # Add the Mbed TLS Python library directory to the module search path | 
| Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 57 | import scripts_path # pylint: disable=unused-import | 
|  | 58 | import config | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 59 |  | 
| Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 60 | class Colors: # pylint: disable=too-few-public-methods | 
| Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 61 | """Minimalistic support for colored output. | 
|  | 62 | Each field of an object of this class is either None if colored output | 
|  | 63 | is not possible or not desired, or a pair of strings (start, stop) such | 
|  | 64 | that outputting start switches the text color to the desired color and | 
|  | 65 | stop switches the text color back to the default.""" | 
|  | 66 | red = None | 
|  | 67 | green = None | 
| Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 68 | cyan = None | 
| Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 69 | bold_red = None | 
|  | 70 | bold_green = None | 
|  | 71 | def __init__(self, options=None): | 
| Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 72 | """Initialize color profile according to passed options.""" | 
| Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 73 | if not options or options.color in ['no', 'never']: | 
|  | 74 | want_color = False | 
|  | 75 | elif options.color in ['yes', 'always']: | 
|  | 76 | want_color = True | 
|  | 77 | else: | 
|  | 78 | want_color = sys.stderr.isatty() | 
|  | 79 | if want_color: | 
|  | 80 | # Assume ANSI compatible terminal | 
|  | 81 | normal = '\033[0m' | 
|  | 82 | self.red = ('\033[31m', normal) | 
|  | 83 | self.green = ('\033[32m', normal) | 
| Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 84 | self.cyan = ('\033[36m', normal) | 
| Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 85 | self.bold_red = ('\033[1;31m', normal) | 
|  | 86 | self.bold_green = ('\033[1;32m', normal) | 
|  | 87 | NO_COLORS = Colors(None) | 
|  | 88 |  | 
|  | 89 | def log_line(text, prefix='depends.py:', suffix='', color=None): | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 90 | """Print a status message.""" | 
| Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 91 | if color is not None: | 
| Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 92 | prefix = color[0] + prefix | 
|  | 93 | suffix = suffix + color[1] | 
|  | 94 | sys.stderr.write(prefix + ' ' + text + suffix + '\n') | 
| Gilles Peskine | 46c8256 | 2019-01-29 18:42:55 +0100 | [diff] [blame] | 95 | sys.stderr.flush() | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 96 |  | 
| Gilles Peskine | 54aa5c6 | 2019-01-29 18:46:34 +0100 | [diff] [blame] | 97 | def log_command(cmd): | 
|  | 98 | """Print a trace of the specified command. | 
|  | 99 | cmd is a list of strings: a command name and its arguments.""" | 
|  | 100 | log_line(' '.join(cmd), prefix='+') | 
|  | 101 |  | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 102 | def backup_config(options): | 
| Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 103 | """Back up the library configuration file (mbedtls_config.h). | 
| Gilles Peskine | bf7537d | 2019-01-29 18:52:16 +0100 | [diff] [blame] | 104 | If the backup file already exists, it is presumed to be the desired backup, | 
|  | 105 | so don't make another backup.""" | 
|  | 106 | if os.path.exists(options.config_backup): | 
|  | 107 | options.own_backup = False | 
|  | 108 | else: | 
|  | 109 | options.own_backup = True | 
|  | 110 | shutil.copy(options.config, options.config_backup) | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 111 |  | 
| Gilles Peskine | bf7537d | 2019-01-29 18:52:16 +0100 | [diff] [blame] | 112 | def restore_config(options): | 
| Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 113 | """Restore the library configuration file (mbedtls_config.h). | 
| Gilles Peskine | bf7537d | 2019-01-29 18:52:16 +0100 | [diff] [blame] | 114 | Remove the backup file if it was saved earlier.""" | 
|  | 115 | if options.own_backup: | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 116 | shutil.move(options.config_backup, options.config) | 
|  | 117 | else: | 
|  | 118 | shutil.copy(options.config_backup, options.config) | 
| Gilles Peskine | bf7537d | 2019-01-29 18:52:16 +0100 | [diff] [blame] | 119 |  | 
| Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 120 | def option_exists(conf, option): | 
| Andrzej Kurek | 81cf5ad | 2023-02-06 10:48:43 +0100 | [diff] [blame] | 121 | return option in conf.settings | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 122 |  | 
| Andrzej Kurek | 576803f | 2023-01-24 07:40:42 -0500 | [diff] [blame] | 123 | def set_config_option_value(conf, option, colors, value: Union[bool, str]): | 
|  | 124 | """Set/unset a configuration option, optionally specifying a value. | 
|  | 125 | value can be either True/False (set/unset config option), or a string, | 
|  | 126 | which will make a symbol defined with a certain value.""" | 
| Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 127 | if not option_exists(conf, option): | 
|  | 128 | log_line('Symbol {} was not found in {}'.format(option, conf.filename), color=colors.red) | 
|  | 129 | return False | 
| Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 130 |  | 
| Andrzej Kurek | 3b0215d | 2023-01-23 07:19:22 -0500 | [diff] [blame] | 131 | if value is False: | 
|  | 132 | log_command(['config.py', 'unset', option]) | 
|  | 133 | conf.unset(option) | 
| Andrzej Kurek | 72082dc | 2023-02-06 10:49:46 +0100 | [diff] [blame] | 134 | elif value is True: | 
|  | 135 | log_command(['config.py', 'set', option]) | 
|  | 136 | conf.set(option) | 
| Andrzej Kurek | 3b0215d | 2023-01-23 07:19:22 -0500 | [diff] [blame] | 137 | else: | 
| Andrzej Kurek | 72082dc | 2023-02-06 10:49:46 +0100 | [diff] [blame] | 138 | log_command(['config.py', 'set', option, value]) | 
|  | 139 | conf.set(option, value) | 
| Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 140 | return True | 
|  | 141 |  | 
|  | 142 | def set_reference_config(conf, options, colors): | 
| Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 143 | """Change the library configuration file (mbedtls_config.h) to the reference state. | 
|  | 144 | The reference state is the one from which the tested configurations are | 
|  | 145 | derived.""" | 
| Andrzej Kurek | a0cb4fa | 2022-10-14 07:06:43 -0400 | [diff] [blame] | 146 | # Turn off options that are not relevant to the tests and slow them down. | 
| Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 147 | log_command(['config.py', 'full']) | 
|  | 148 | conf.adapt(config.full_adapter) | 
| Andrzej Kurek | 3b0215d | 2023-01-23 07:19:22 -0500 | [diff] [blame] | 149 | set_config_option_value(conf, 'MBEDTLS_TEST_HOOKS', colors, False) | 
| Gilles Peskine | 884b462 | 2023-07-20 20:11:51 +0200 | [diff] [blame] | 150 | set_config_option_value(conf, 'MBEDTLS_PSA_CRYPTO_CONFIG', colors, False) | 
| Andrzej Kurek | 2c7993c | 2022-10-24 10:41:20 -0400 | [diff] [blame] | 151 | if options.unset_use_psa: | 
| Andrzej Kurek | 3b0215d | 2023-01-23 07:19:22 -0500 | [diff] [blame] | 152 | set_config_option_value(conf, 'MBEDTLS_USE_PSA_CRYPTO', colors, False) | 
| Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 153 |  | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 154 | class Job: | 
|  | 155 | """A job builds the library in a specific configuration and runs some tests.""" | 
|  | 156 | def __init__(self, name, config_settings, commands): | 
|  | 157 | """Build a job object. | 
|  | 158 | The job uses the configuration described by config_settings. This is a | 
|  | 159 | dictionary where the keys are preprocessor symbols and the values are | 
|  | 160 | booleans or strings. A boolean indicates whether or not to #define the | 
|  | 161 | symbol. With a string, the symbol is #define'd to that value. | 
|  | 162 | After setting the configuration, the job runs the programs specified by | 
|  | 163 | commands. This is a list of lists of strings; each list of string is a | 
|  | 164 | command name and its arguments and is passed to subprocess.call with | 
|  | 165 | shell=False.""" | 
|  | 166 | self.name = name | 
|  | 167 | self.config_settings = config_settings | 
|  | 168 | self.commands = commands | 
|  | 169 |  | 
| Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 170 | def announce(self, colors, what): | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 171 | '''Announce the start or completion of a job. | 
|  | 172 | If what is None, announce the start of the job. | 
|  | 173 | If what is True, announce that the job has passed. | 
|  | 174 | If what is False, announce that the job has failed.''' | 
|  | 175 | if what is True: | 
| Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 176 | log_line(self.name + ' PASSED', color=colors.green) | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 177 | elif what is False: | 
| Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 178 | log_line(self.name + ' FAILED', color=colors.red) | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 179 | else: | 
| Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 180 | log_line('starting ' + self.name, color=colors.cyan) | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 181 |  | 
| Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 182 | def configure(self, conf, options, colors): | 
| Andrzej Kurek | a0cb4fa | 2022-10-14 07:06:43 -0400 | [diff] [blame] | 183 | '''Set library configuration options as required for the job.''' | 
| Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 184 | set_reference_config(conf, options, colors) | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 185 | for key, value in sorted(self.config_settings.items()): | 
| Andrzej Kurek | 3b0215d | 2023-01-23 07:19:22 -0500 | [diff] [blame] | 186 | ret = set_config_option_value(conf, key, colors, value) | 
| Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 187 | if ret is False: | 
|  | 188 | return False | 
|  | 189 | return True | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 190 |  | 
|  | 191 | def test(self, options): | 
|  | 192 | '''Run the job's build and test commands. | 
|  | 193 | Return True if all the commands succeed and False otherwise. | 
|  | 194 | If options.keep_going is false, stop as soon as one command fails. Otherwise | 
|  | 195 | run all the commands, except that if the first command fails, none of the | 
|  | 196 | other commands are run (typically, the first command is a build command | 
|  | 197 | and subsequent commands are tests that cannot run if the build failed).''' | 
|  | 198 | built = False | 
|  | 199 | success = True | 
|  | 200 | for command in self.commands: | 
| Gilles Peskine | 54aa5c6 | 2019-01-29 18:46:34 +0100 | [diff] [blame] | 201 | log_command(command) | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 202 | ret = subprocess.call(command) | 
|  | 203 | if ret != 0: | 
|  | 204 | if command[0] not in ['make', options.make_command]: | 
|  | 205 | log_line('*** [{}] Error {}'.format(' '.join(command), ret)) | 
|  | 206 | if not options.keep_going or not built: | 
|  | 207 | return False | 
|  | 208 | success = False | 
|  | 209 | built = True | 
|  | 210 | return success | 
|  | 211 |  | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 212 | # If the configuration option A requires B, make sure that | 
| Andrzej Kurek | 202932f | 2022-10-04 16:22:22 -0400 | [diff] [blame] | 213 | # B in REVERSE_DEPENDENCIES[A]. | 
| Gilles Peskine | 584c24a | 2019-01-29 19:30:40 +0100 | [diff] [blame] | 214 | # All the information here should be contained in check_config.h. This | 
|  | 215 | # file includes a copy because it changes rarely and it would be a pain | 
|  | 216 | # to extract automatically. | 
| Andrzej Kurek | 202932f | 2022-10-04 16:22:22 -0400 | [diff] [blame] | 217 | REVERSE_DEPENDENCIES = { | 
| Gilles Peskine | 34a1557 | 2019-01-29 23:12:28 +0100 | [diff] [blame] | 218 | 'MBEDTLS_AES_C': ['MBEDTLS_CTR_DRBG_C', | 
| Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 219 | 'MBEDTLS_NIST_KW_C'], | 
| Gilles Peskine | 34a1557 | 2019-01-29 23:12:28 +0100 | [diff] [blame] | 220 | 'MBEDTLS_CHACHA20_C': ['MBEDTLS_CHACHAPOLY_C'], | 
| Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 221 | 'MBEDTLS_ECDSA_C': ['MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED', | 
|  | 222 | 'MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED'], | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 223 | 'MBEDTLS_ECP_C': ['MBEDTLS_ECDSA_C', | 
|  | 224 | 'MBEDTLS_ECDH_C', | 
|  | 225 | 'MBEDTLS_ECJPAKE_C', | 
| Manuel Pégourié-Gonnard | ad45c4d | 2022-12-06 13:20:06 +0100 | [diff] [blame] | 226 | 'MBEDTLS_ECP_RESTARTABLE', | 
| Valerio Setti | 15e7044 | 2023-06-15 09:47:26 +0200 | [diff] [blame] | 227 | 'MBEDTLS_PK_PARSE_EC_EXTENDED', | 
|  | 228 | 'MBEDTLS_PK_PARSE_EC_COMPRESSED', | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 229 | 'MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED', | 
|  | 230 | 'MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED', | 
|  | 231 | 'MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED', | 
|  | 232 | 'MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED', | 
| Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 233 | 'MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED', | 
| Ronald Cron | d8d2ea5 | 2022-10-04 15:48:06 +0200 | [diff] [blame] | 234 | 'MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED', | 
|  | 235 | 'MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED', | 
|  | 236 | 'MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED'], | 
| Gilles Peskine | 584c24a | 2019-01-29 19:30:40 +0100 | [diff] [blame] | 237 | 'MBEDTLS_ECP_DP_SECP256R1_ENABLED': ['MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED'], | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 238 | 'MBEDTLS_PKCS1_V21': ['MBEDTLS_X509_RSASSA_PSS_SUPPORT'], | 
|  | 239 | 'MBEDTLS_PKCS1_V15': ['MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED', | 
|  | 240 | 'MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED', | 
|  | 241 | 'MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED', | 
|  | 242 | 'MBEDTLS_KEY_EXCHANGE_RSA_ENABLED'], | 
|  | 243 | 'MBEDTLS_RSA_C': ['MBEDTLS_X509_RSASSA_PSS_SUPPORT', | 
|  | 244 | 'MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED', | 
|  | 245 | 'MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED', | 
|  | 246 | 'MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED', | 
| Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 247 | 'MBEDTLS_KEY_EXCHANGE_RSA_ENABLED', | 
|  | 248 | 'MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED'], | 
| Gilles Peskine | 584c24a | 2019-01-29 19:30:40 +0100 | [diff] [blame] | 249 | 'MBEDTLS_SHA256_C': ['MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED', | 
| Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 250 | 'MBEDTLS_ENTROPY_FORCE_SHA256', | 
| Dave Rodgman | d680d4f | 2023-10-11 11:05:22 +0100 | [diff] [blame] | 251 | 'MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT', | 
|  | 252 | 'MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY', | 
| Andrzej Kurek | 22b959d | 2022-10-16 12:51:41 -0400 | [diff] [blame] | 253 | 'MBEDTLS_LMS_C', | 
|  | 254 | 'MBEDTLS_LMS_PRIVATE'], | 
| Valerio Setti | e7221a2 | 2022-12-16 11:53:45 +0100 | [diff] [blame] | 255 | 'MBEDTLS_SHA512_C': ['MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT', | 
| Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 256 | 'MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY'], | 
|  | 257 | 'MBEDTLS_SHA224_C': ['MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED', | 
|  | 258 | 'MBEDTLS_ENTROPY_FORCE_SHA256', | 
| Dave Rodgman | d680d4f | 2023-10-11 11:05:22 +0100 | [diff] [blame] | 259 | 'MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT', | 
|  | 260 | 'MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY'], | 
| Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 261 | 'MBEDTLS_X509_RSASSA_PSS_SUPPORT': [] | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 262 | } | 
|  | 263 |  | 
| Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 264 | # If an option is tested in an exclusive test, alter the following defines. | 
| Andrzej Kurek | 01af84a | 2022-10-09 05:29:44 -0400 | [diff] [blame] | 265 | # These are not necessarily dependencies, but just minimal required changes | 
| Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 266 | # if a given define is the only one enabled from an exclusive group. | 
| Andrzej Kurek | 202932f | 2022-10-04 16:22:22 -0400 | [diff] [blame] | 267 | EXCLUSIVE_GROUPS = { | 
| Andrzej Kurek | 65b2ac1 | 2022-10-14 08:09:16 -0400 | [diff] [blame] | 268 | 'MBEDTLS_SHA512_C': ['-MBEDTLS_SSL_COOKIE_C', | 
| Manuel Pégourié-Gonnard | 5a51d0d | 2023-03-22 13:04:08 +0100 | [diff] [blame] | 269 | '-MBEDTLS_SSL_TLS_C'], | 
| Andrzej Kurek | 65b2ac1 | 2022-10-14 08:09:16 -0400 | [diff] [blame] | 270 | 'MBEDTLS_ECP_DP_CURVE448_ENABLED': ['-MBEDTLS_ECDSA_C', | 
|  | 271 | '-MBEDTLS_ECDSA_DETERMINISTIC', | 
|  | 272 | '-MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED', | 
|  | 273 | '-MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED', | 
|  | 274 | '-MBEDTLS_ECJPAKE_C', | 
|  | 275 | '-MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED'], | 
|  | 276 | 'MBEDTLS_ECP_DP_CURVE25519_ENABLED': ['-MBEDTLS_ECDSA_C', | 
|  | 277 | '-MBEDTLS_ECDSA_DETERMINISTIC', | 
|  | 278 | '-MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED', | 
|  | 279 | '-MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED', | 
|  | 280 | '-MBEDTLS_ECJPAKE_C', | 
|  | 281 | '-MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED'], | 
|  | 282 | 'MBEDTLS_ARIA_C': ['-MBEDTLS_CMAC_C'], | 
|  | 283 | 'MBEDTLS_CAMELLIA_C': ['-MBEDTLS_CMAC_C'], | 
|  | 284 | 'MBEDTLS_CHACHA20_C': ['-MBEDTLS_CMAC_C', '-MBEDTLS_CCM_C', '-MBEDTLS_GCM_C'], | 
|  | 285 | 'MBEDTLS_DES_C': ['-MBEDTLS_CCM_C', | 
|  | 286 | '-MBEDTLS_GCM_C', | 
|  | 287 | '-MBEDTLS_SSL_TICKET_C', | 
|  | 288 | '-MBEDTLS_SSL_CONTEXT_SERIALIZATION'], | 
| Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 289 | } | 
|  | 290 | def handle_exclusive_groups(config_settings, symbol): | 
|  | 291 | """For every symbol tested in an exclusive group check if there are other | 
|  | 292 | defines to be altered. """ | 
| Andrzej Kurek | 202932f | 2022-10-04 16:22:22 -0400 | [diff] [blame] | 293 | for dep in EXCLUSIVE_GROUPS.get(symbol, []): | 
| Andrzej Kurek | 65b2ac1 | 2022-10-14 08:09:16 -0400 | [diff] [blame] | 294 | unset = dep.startswith('-') | 
|  | 295 | dep = dep[1:] | 
| Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 296 | config_settings[dep] = not unset | 
|  | 297 |  | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 298 | def turn_off_dependencies(config_settings): | 
|  | 299 | """For every option turned off config_settings, also turn off what depends on it. | 
|  | 300 | An option O is turned off if config_settings[O] is False.""" | 
|  | 301 | for key, value in sorted(config_settings.items()): | 
|  | 302 | if value is not False: | 
|  | 303 | continue | 
| Andrzej Kurek | 202932f | 2022-10-04 16:22:22 -0400 | [diff] [blame] | 304 | for dep in REVERSE_DEPENDENCIES.get(key, []): | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 305 | config_settings[dep] = False | 
|  | 306 |  | 
| Andrzej Kurek | 228b12c | 2022-10-06 18:52:44 -0400 | [diff] [blame] | 307 | class BaseDomain: # pylint: disable=too-few-public-methods, unused-argument | 
|  | 308 | """A base class for all domains.""" | 
|  | 309 | def __init__(self, symbols, commands, exclude): | 
|  | 310 | """Initialize the jobs container""" | 
|  | 311 | self.jobs = [] | 
|  | 312 |  | 
|  | 313 | class ExclusiveDomain(BaseDomain): # pylint: disable=too-few-public-methods | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 314 | """A domain consisting of a set of conceptually-equivalent settings. | 
|  | 315 | Establish a list of configuration symbols. For each symbol, run a test job | 
| Andrzej Kurek | fe46949 | 2022-10-06 16:57:38 -0400 | [diff] [blame] | 316 | with this symbol set and the others unset.""" | 
| Gilles Peskine | b1284cf | 2019-01-29 18:56:03 +0100 | [diff] [blame] | 317 | def __init__(self, symbols, commands, exclude=None): | 
|  | 318 | """Build a domain for the specified list of configuration symbols. | 
| Andrzej Kurek | fe46949 | 2022-10-06 16:57:38 -0400 | [diff] [blame] | 319 | The domain contains a set of jobs that enable one of the elements | 
|  | 320 | of symbols and disable the others. | 
| Gilles Peskine | b1284cf | 2019-01-29 18:56:03 +0100 | [diff] [blame] | 321 | Each job runs the specified commands. | 
|  | 322 | If exclude is a regular expression, skip generated jobs whose description | 
|  | 323 | would match this regular expression.""" | 
| Andrzej Kurek | 228b12c | 2022-10-06 18:52:44 -0400 | [diff] [blame] | 324 | super().__init__(symbols, commands, exclude) | 
| Andrzej Kurek | fe46949 | 2022-10-06 16:57:38 -0400 | [diff] [blame] | 325 | base_config_settings = {} | 
|  | 326 | for symbol in symbols: | 
|  | 327 | base_config_settings[symbol] = False | 
|  | 328 | for symbol in symbols: | 
|  | 329 | description = symbol | 
|  | 330 | if exclude and re.match(exclude, description): | 
|  | 331 | continue | 
|  | 332 | config_settings = base_config_settings.copy() | 
|  | 333 | config_settings[symbol] = True | 
|  | 334 | handle_exclusive_groups(config_settings, symbol) | 
|  | 335 | turn_off_dependencies(config_settings) | 
|  | 336 | job = Job(description, config_settings, commands) | 
|  | 337 | self.jobs.append(job) | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 338 |  | 
| Andrzej Kurek | 228b12c | 2022-10-06 18:52:44 -0400 | [diff] [blame] | 339 | class ComplementaryDomain(BaseDomain): # pylint: disable=too-few-public-methods | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 340 | """A domain consisting of a set of loosely-related settings. | 
|  | 341 | Establish a list of configuration symbols. For each symbol, run a test job | 
| Andrzej Kurek | a0cb4fa | 2022-10-14 07:06:43 -0400 | [diff] [blame] | 342 | with this symbol unset. | 
|  | 343 | If exclude is a regular expression, skip generated jobs whose description | 
|  | 344 | would match this regular expression.""" | 
| Andrzej Kurek | 228b12c | 2022-10-06 18:52:44 -0400 | [diff] [blame] | 345 | def __init__(self, symbols, commands, exclude=None): | 
| Gilles Peskine | b1284cf | 2019-01-29 18:56:03 +0100 | [diff] [blame] | 346 | """Build a domain for the specified list of configuration symbols. | 
|  | 347 | Each job in the domain disables one of the specified symbols. | 
|  | 348 | Each job runs the specified commands.""" | 
| Andrzej Kurek | 228b12c | 2022-10-06 18:52:44 -0400 | [diff] [blame] | 349 | super().__init__(symbols, commands, exclude) | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 350 | for symbol in symbols: | 
|  | 351 | description = '!' + symbol | 
| Andrzej Kurek | 228b12c | 2022-10-06 18:52:44 -0400 | [diff] [blame] | 352 | if exclude and re.match(exclude, description): | 
|  | 353 | continue | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 354 | config_settings = {symbol: False} | 
|  | 355 | turn_off_dependencies(config_settings) | 
|  | 356 | job = Job(description, config_settings, commands) | 
|  | 357 | self.jobs.append(job) | 
|  | 358 |  | 
| Andrzej Kurek | 228b12c | 2022-10-06 18:52:44 -0400 | [diff] [blame] | 359 | class DualDomain(ExclusiveDomain, ComplementaryDomain): # pylint: disable=too-few-public-methods | 
| Andrzej Kurek | a0cb4fa | 2022-10-14 07:06:43 -0400 | [diff] [blame] | 360 | """A domain that contains both the ExclusiveDomain and BaseDomain tests. | 
| Andrzej Kurek | f4b1867 | 2022-10-14 07:57:00 -0400 | [diff] [blame] | 361 | Both parent class __init__ calls are performed in any order and | 
| Andrzej Kurek | a0cb4fa | 2022-10-14 07:06:43 -0400 | [diff] [blame] | 362 | each call adds respective jobs. The job array initialization is done once in | 
|  | 363 | BaseDomain, before the parent __init__ calls.""" | 
| Andrzej Kurek | 228b12c | 2022-10-06 18:52:44 -0400 | [diff] [blame] | 364 |  | 
| Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 365 | class CipherInfo: # pylint: disable=too-few-public-methods | 
| Gilles Peskine | 34a1557 | 2019-01-29 23:12:28 +0100 | [diff] [blame] | 366 | """Collect data about cipher.h.""" | 
| Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 367 | def __init__(self): | 
| Gilles Peskine | 34a1557 | 2019-01-29 23:12:28 +0100 | [diff] [blame] | 368 | self.base_symbols = set() | 
| Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 369 | with open('include/mbedtls/cipher.h', encoding="utf-8") as fh: | 
| Gilles Peskine | 34a1557 | 2019-01-29 23:12:28 +0100 | [diff] [blame] | 370 | for line in fh: | 
|  | 371 | m = re.match(r' *MBEDTLS_CIPHER_ID_(\w+),', line) | 
|  | 372 | if m and m.group(1) not in ['NONE', 'NULL', '3DES']: | 
|  | 373 | self.base_symbols.add('MBEDTLS_' + m.group(1) + '_C') | 
|  | 374 |  | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 375 | class DomainData: | 
| Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 376 | """A container for domains and jobs, used to structurize testing.""" | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 377 | def config_symbols_matching(self, regexp): | 
| Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 378 | """List the mbedtls_config.h settings matching regexp.""" | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 379 | return [symbol for symbol in self.all_config_symbols | 
|  | 380 | if re.match(regexp, symbol)] | 
|  | 381 |  | 
| Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 382 | def __init__(self, options, conf): | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 383 | """Gather data about the library and establish a list of domains to test.""" | 
|  | 384 | build_command = [options.make_command, 'CFLAGS=-Werror'] | 
|  | 385 | build_and_test = [build_command, [options.make_command, 'test']] | 
| Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 386 | self.all_config_symbols = set(conf.settings.keys()) | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 387 | # Find hash modules by name. | 
|  | 388 | hash_symbols = self.config_symbols_matching(r'MBEDTLS_(MD|RIPEMD|SHA)[0-9]+_C\Z') | 
|  | 389 | # Find elliptic curve enabling macros by name. | 
|  | 390 | curve_symbols = self.config_symbols_matching(r'MBEDTLS_ECP_DP_\w+_ENABLED\Z') | 
|  | 391 | # Find key exchange enabling macros by name. | 
|  | 392 | key_exchange_symbols = self.config_symbols_matching(r'MBEDTLS_KEY_EXCHANGE_\w+_ENABLED\Z') | 
| Gilles Peskine | 34a1557 | 2019-01-29 23:12:28 +0100 | [diff] [blame] | 393 | # Find cipher IDs (block permutations and stream ciphers --- chaining | 
|  | 394 | # and padding modes are exercised separately) information by parsing | 
| Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 395 | # cipher.h, as the information is not readily available in mbedtls_config.h. | 
| Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 396 | cipher_info = CipherInfo() | 
| Gilles Peskine | 34a1557 | 2019-01-29 23:12:28 +0100 | [diff] [blame] | 397 | # Find block cipher chaining and padding mode enabling macros by name. | 
|  | 398 | cipher_chaining_symbols = self.config_symbols_matching(r'MBEDTLS_CIPHER_MODE_\w+\Z') | 
|  | 399 | cipher_padding_symbols = self.config_symbols_matching(r'MBEDTLS_CIPHER_PADDING_\w+\Z') | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 400 | self.domains = { | 
| Gilles Peskine | 34a1557 | 2019-01-29 23:12:28 +0100 | [diff] [blame] | 401 | # Cipher IDs, chaining modes and padding modes. Run the test suites. | 
|  | 402 | 'cipher_id': ExclusiveDomain(cipher_info.base_symbols, | 
|  | 403 | build_and_test), | 
|  | 404 | 'cipher_chaining': ExclusiveDomain(cipher_chaining_symbols, | 
|  | 405 | build_and_test), | 
|  | 406 | 'cipher_padding': ExclusiveDomain(cipher_padding_symbols, | 
|  | 407 | build_and_test), | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 408 | # Elliptic curves. Run the test suites. | 
|  | 409 | 'curves': ExclusiveDomain(curve_symbols, build_and_test), | 
| Valerio Setti | ea8c88f | 2022-12-29 11:08:35 +0100 | [diff] [blame] | 410 | # Hash algorithms. Excluding exclusive domains of MD, RIPEMD, SHA1, | 
|  | 411 | # SHA224 and SHA384 because MBEDTLS_ENTROPY_C is extensively used | 
|  | 412 | # across various modules, but it depends on either SHA256 or SHA512. | 
|  | 413 | # As a consequence an "exclusive" test of anything other than SHA256 | 
|  | 414 | # or SHA512 with MBEDTLS_ENTROPY_C enabled is not possible. | 
| Andrzej Kurek | 228b12c | 2022-10-06 18:52:44 -0400 | [diff] [blame] | 415 | 'hashes': DualDomain(hash_symbols, build_and_test, | 
| Andrzej Kurek | a0cb4fa | 2022-10-14 07:06:43 -0400 | [diff] [blame] | 416 | exclude=r'MBEDTLS_(MD|RIPEMD|SHA1_)' \ | 
| Valerio Setti | b6bf7dc | 2022-12-22 14:28:03 +0100 | [diff] [blame] | 417 | '|MBEDTLS_SHA224_' \ | 
| Pol Henarejos | aa426e0 | 2023-02-08 12:52:10 +0100 | [diff] [blame] | 418 | '|MBEDTLS_SHA384_' \ | 
|  | 419 | '|MBEDTLS_SHA3_'), | 
| Andrzej Kurek | 98682b5 | 2023-01-23 06:16:23 -0500 | [diff] [blame] | 420 | # Key exchange types. | 
| Andrzej Kurek | 1ff7336 | 2022-11-02 04:50:16 -0400 | [diff] [blame] | 421 | 'kex': ExclusiveDomain(key_exchange_symbols, build_and_test), | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 422 | 'pkalgs': ComplementaryDomain(['MBEDTLS_ECDSA_C', | 
|  | 423 | 'MBEDTLS_ECP_C', | 
|  | 424 | 'MBEDTLS_PKCS1_V21', | 
|  | 425 | 'MBEDTLS_PKCS1_V15', | 
|  | 426 | 'MBEDTLS_RSA_C', | 
|  | 427 | 'MBEDTLS_X509_RSASSA_PSS_SUPPORT'], | 
|  | 428 | build_and_test), | 
|  | 429 | } | 
|  | 430 | self.jobs = {} | 
|  | 431 | for domain in self.domains.values(): | 
|  | 432 | for job in domain.jobs: | 
|  | 433 | self.jobs[job.name] = job | 
|  | 434 |  | 
|  | 435 | def get_jobs(self, name): | 
|  | 436 | """Return the list of jobs identified by the given name. | 
|  | 437 | A name can either be the name of a domain or the name of one specific job.""" | 
|  | 438 | if name in self.domains: | 
|  | 439 | return sorted(self.domains[name].jobs, key=lambda job: job.name) | 
|  | 440 | else: | 
|  | 441 | return [self.jobs[name]] | 
|  | 442 |  | 
| Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 443 | def run(options, job, conf, colors=NO_COLORS): | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 444 | """Run the specified job (a Job instance).""" | 
|  | 445 | subprocess.check_call([options.make_command, 'clean']) | 
| Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 446 | job.announce(colors, None) | 
| Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 447 | if not job.configure(conf, options, colors): | 
|  | 448 | job.announce(colors, False) | 
|  | 449 | return False | 
|  | 450 | conf.write() | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 451 | success = job.test(options) | 
| Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 452 | job.announce(colors, success) | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 453 | return success | 
|  | 454 |  | 
| Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 455 | def run_tests(options, domain_data, conf): | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 456 | """Run the desired jobs. | 
|  | 457 | domain_data should be a DomainData instance that describes the available | 
|  | 458 | domains and jobs. | 
| Andrzej Kurek | b8a97e7 | 2022-10-17 08:39:09 -0400 | [diff] [blame] | 459 | Run the jobs listed in options.tasks.""" | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 460 | if not hasattr(options, 'config_backup'): | 
|  | 461 | options.config_backup = options.config + '.bak' | 
| Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 462 | colors = Colors(options) | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 463 | jobs = [] | 
|  | 464 | failures = [] | 
|  | 465 | successes = [] | 
| Andrzej Kurek | b8a97e7 | 2022-10-17 08:39:09 -0400 | [diff] [blame] | 466 | for name in options.tasks: | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 467 | jobs += domain_data.get_jobs(name) | 
|  | 468 | backup_config(options) | 
|  | 469 | try: | 
|  | 470 | for job in jobs: | 
| Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 471 | success = run(options, job, conf, colors=colors) | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 472 | if not success: | 
|  | 473 | if options.keep_going: | 
|  | 474 | failures.append(job.name) | 
|  | 475 | else: | 
|  | 476 | return False | 
|  | 477 | else: | 
|  | 478 | successes.append(job.name) | 
| Gilles Peskine | bf7537d | 2019-01-29 18:52:16 +0100 | [diff] [blame] | 479 | restore_config(options) | 
|  | 480 | except: | 
|  | 481 | # Restore the configuration, except in stop-on-error mode if there | 
|  | 482 | # was an error, where we leave the failing configuration up for | 
|  | 483 | # developer convenience. | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 484 | if options.keep_going: | 
| Gilles Peskine | bf7537d | 2019-01-29 18:52:16 +0100 | [diff] [blame] | 485 | restore_config(options) | 
|  | 486 | raise | 
| Gilles Peskine | e85163b | 2019-01-29 18:50:03 +0100 | [diff] [blame] | 487 | if successes: | 
|  | 488 | log_line('{} passed'.format(' '.join(successes)), color=colors.bold_green) | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 489 | if failures: | 
| Gilles Peskine | e85163b | 2019-01-29 18:50:03 +0100 | [diff] [blame] | 490 | log_line('{} FAILED'.format(' '.join(failures)), color=colors.bold_red) | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 491 | return False | 
|  | 492 | else: | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 493 | return True | 
|  | 494 |  | 
| Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 495 | def main(): | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 496 | try: | 
| Andrzej Kurek | 01af84a | 2022-10-09 05:29:44 -0400 | [diff] [blame] | 497 | parser = argparse.ArgumentParser( | 
|  | 498 | formatter_class=argparse.RawDescriptionHelpFormatter, | 
|  | 499 | description= | 
|  | 500 | "Test Mbed TLS with a subset of algorithms.\n\n" | 
|  | 501 | "Example usage:\n" | 
| Andrzej Kurek | 629c412 | 2022-10-17 08:34:40 -0400 | [diff] [blame] | 502 | r"./tests/scripts/depends.py \!MBEDTLS_SHA1_C MBEDTLS_SHA256_C""\n" | 
| Andrzej Kurek | 01af84a | 2022-10-09 05:29:44 -0400 | [diff] [blame] | 503 | "./tests/scripts/depends.py MBEDTLS_AES_C hashes\n" | 
|  | 504 | "./tests/scripts/depends.py cipher_id cipher_chaining\n") | 
| Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 505 | parser.add_argument('--color', metavar='WHEN', | 
|  | 506 | help='Colorize the output (always/auto/never)', | 
|  | 507 | choices=['always', 'auto', 'never'], default='auto') | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 508 | parser.add_argument('-c', '--config', metavar='FILE', | 
|  | 509 | help='Configuration file to modify', | 
| Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 510 | default='include/mbedtls/mbedtls_config.h') | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 511 | parser.add_argument('-C', '--directory', metavar='DIR', | 
|  | 512 | help='Change to this directory before anything else', | 
|  | 513 | default='.') | 
|  | 514 | parser.add_argument('-k', '--keep-going', | 
|  | 515 | help='Try all configurations even if some fail (default)', | 
|  | 516 | action='store_true', dest='keep_going', default=True) | 
|  | 517 | parser.add_argument('-e', '--no-keep-going', | 
|  | 518 | help='Stop as soon as a configuration fails', | 
|  | 519 | action='store_false', dest='keep_going') | 
|  | 520 | parser.add_argument('--list-jobs', | 
|  | 521 | help='List supported jobs and exit', | 
|  | 522 | action='append_const', dest='list', const='jobs') | 
|  | 523 | parser.add_argument('--list-domains', | 
|  | 524 | help='List supported domains and exit', | 
|  | 525 | action='append_const', dest='list', const='domains') | 
|  | 526 | parser.add_argument('--make-command', metavar='CMD', | 
|  | 527 | help='Command to run instead of make (e.g. gmake)', | 
|  | 528 | action='store', default='make') | 
| Andrzej Kurek | 2c7993c | 2022-10-24 10:41:20 -0400 | [diff] [blame] | 529 | parser.add_argument('--unset-use-psa', | 
|  | 530 | help='Unset MBEDTLS_USE_PSA_CRYPTO before any test', | 
|  | 531 | action='store_true', dest='unset_use_psa') | 
| Andrzej Kurek | b8a97e7 | 2022-10-17 08:39:09 -0400 | [diff] [blame] | 532 | parser.add_argument('tasks', metavar='TASKS', nargs='*', | 
|  | 533 | help='The domain(s) or job(s) to test (default: all).', | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 534 | default=True) | 
|  | 535 | options = parser.parse_args() | 
|  | 536 | os.chdir(options.directory) | 
| Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 537 | conf = config.ConfigFile(options.config) | 
|  | 538 | domain_data = DomainData(options, conf) | 
|  | 539 |  | 
| Andrzej Kurek | b8a97e7 | 2022-10-17 08:39:09 -0400 | [diff] [blame] | 540 | if options.tasks is True: | 
|  | 541 | options.tasks = sorted(domain_data.domains.keys()) | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 542 | if options.list: | 
| Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 543 | for arg in options.list: | 
|  | 544 | for domain_name in sorted(getattr(domain_data, arg).keys()): | 
|  | 545 | print(domain_name) | 
|  | 546 | sys.exit(0) | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 547 | else: | 
| Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 548 | sys.exit(0 if run_tests(options, domain_data, conf) else 1) | 
| Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 549 | except Exception: # pylint: disable=broad-except | 
| Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 550 | traceback.print_exc() | 
| Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 551 | sys.exit(3) | 
|  | 552 |  | 
|  | 553 | if __name__ == '__main__': | 
|  | 554 | main() |