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 |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 50 | import subprocess |
| 51 | import sys |
| 52 | import traceback |
Andrzej Kurek | 576803f | 2023-01-24 07:40:42 -0500 | [diff] [blame] | 53 | from typing import Union |
| 54 | |
Andrzej Kurek | 3b0215d | 2023-01-23 07:19:22 -0500 | [diff] [blame] | 55 | # Add the Mbed TLS Python library directory to the module search path |
Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 56 | import scripts_path # pylint: disable=unused-import |
| 57 | import config |
Gabor Mezei | 4e10d6c | 2024-08-03 14:26:13 +0200 | [diff] [blame] | 58 | from mbedtls_framework import c_build_helper |
Gabor Mezei | 402381d | 2024-09-24 19:46:54 +0200 | [diff] [blame] | 59 | from mbedtls_framework import crypto_knowledge |
| 60 | from mbedtls_framework import psa_information |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 61 | |
Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 62 | class Colors: # pylint: disable=too-few-public-methods |
Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 63 | """Minimalistic support for colored output. |
| 64 | Each field of an object of this class is either None if colored output |
| 65 | is not possible or not desired, or a pair of strings (start, stop) such |
| 66 | that outputting start switches the text color to the desired color and |
| 67 | stop switches the text color back to the default.""" |
| 68 | red = None |
| 69 | green = None |
Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 70 | cyan = None |
Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 71 | bold_red = None |
| 72 | bold_green = None |
| 73 | def __init__(self, options=None): |
Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 74 | """Initialize color profile according to passed options.""" |
Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 75 | if not options or options.color in ['no', 'never']: |
| 76 | want_color = False |
| 77 | elif options.color in ['yes', 'always']: |
| 78 | want_color = True |
| 79 | else: |
| 80 | want_color = sys.stderr.isatty() |
| 81 | if want_color: |
| 82 | # Assume ANSI compatible terminal |
| 83 | normal = '\033[0m' |
| 84 | self.red = ('\033[31m', normal) |
| 85 | self.green = ('\033[32m', normal) |
Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 86 | self.cyan = ('\033[36m', normal) |
Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 87 | self.bold_red = ('\033[1;31m', normal) |
| 88 | self.bold_green = ('\033[1;32m', normal) |
| 89 | NO_COLORS = Colors(None) |
| 90 | |
| 91 | def log_line(text, prefix='depends.py:', suffix='', color=None): |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 92 | """Print a status message.""" |
Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 93 | if color is not None: |
Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 94 | prefix = color[0] + prefix |
| 95 | suffix = suffix + color[1] |
| 96 | sys.stderr.write(prefix + ' ' + text + suffix + '\n') |
Gilles Peskine | 46c8256 | 2019-01-29 18:42:55 +0100 | [diff] [blame] | 97 | sys.stderr.flush() |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 98 | |
Gilles Peskine | 54aa5c6 | 2019-01-29 18:46:34 +0100 | [diff] [blame] | 99 | def log_command(cmd): |
| 100 | """Print a trace of the specified command. |
| 101 | cmd is a list of strings: a command name and its arguments.""" |
| 102 | log_line(' '.join(cmd), prefix='+') |
| 103 | |
Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 104 | def option_exists(conf, option): |
Andrzej Kurek | 81cf5ad | 2023-02-06 10:48:43 +0100 | [diff] [blame] | 105 | return option in conf.settings |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 106 | |
Andrzej Kurek | 576803f | 2023-01-24 07:40:42 -0500 | [diff] [blame] | 107 | def set_config_option_value(conf, option, colors, value: Union[bool, str]): |
| 108 | """Set/unset a configuration option, optionally specifying a value. |
| 109 | value can be either True/False (set/unset config option), or a string, |
| 110 | which will make a symbol defined with a certain value.""" |
Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 111 | if not option_exists(conf, option): |
| 112 | log_line('Symbol {} was not found in {}'.format(option, conf.filename), color=colors.red) |
| 113 | return False |
Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 114 | |
Andrzej Kurek | 3b0215d | 2023-01-23 07:19:22 -0500 | [diff] [blame] | 115 | if value is False: |
| 116 | log_command(['config.py', 'unset', option]) |
| 117 | conf.unset(option) |
Andrzej Kurek | 72082dc | 2023-02-06 10:49:46 +0100 | [diff] [blame] | 118 | elif value is True: |
| 119 | log_command(['config.py', 'set', option]) |
| 120 | conf.set(option) |
Andrzej Kurek | 3b0215d | 2023-01-23 07:19:22 -0500 | [diff] [blame] | 121 | else: |
Andrzej Kurek | 72082dc | 2023-02-06 10:49:46 +0100 | [diff] [blame] | 122 | log_command(['config.py', 'set', option, value]) |
| 123 | conf.set(option, value) |
Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 124 | return True |
| 125 | |
Gabor Mezei | 9ce6d24 | 2024-06-19 17:47:05 +0200 | [diff] [blame] | 126 | def set_reference_config(conf, colors): |
Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 127 | """Change the library configuration file (mbedtls_config.h) to the reference state. |
| 128 | The reference state is the one from which the tested configurations are |
| 129 | derived.""" |
Andrzej Kurek | a0cb4fa | 2022-10-14 07:06:43 -0400 | [diff] [blame] | 130 | # 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] | 131 | log_command(['config.py', 'full']) |
| 132 | conf.adapt(config.full_adapter) |
Andrzej Kurek | 3b0215d | 2023-01-23 07:19:22 -0500 | [diff] [blame] | 133 | set_config_option_value(conf, 'MBEDTLS_TEST_HOOKS', colors, False) |
Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 134 | |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 135 | class Job: |
| 136 | """A job builds the library in a specific configuration and runs some tests.""" |
| 137 | def __init__(self, name, config_settings, commands): |
| 138 | """Build a job object. |
| 139 | The job uses the configuration described by config_settings. This is a |
| 140 | dictionary where the keys are preprocessor symbols and the values are |
| 141 | booleans or strings. A boolean indicates whether or not to #define the |
| 142 | symbol. With a string, the symbol is #define'd to that value. |
| 143 | After setting the configuration, the job runs the programs specified by |
| 144 | commands. This is a list of lists of strings; each list of string is a |
| 145 | command name and its arguments and is passed to subprocess.call with |
| 146 | shell=False.""" |
| 147 | self.name = name |
| 148 | self.config_settings = config_settings |
| 149 | self.commands = commands |
| 150 | |
Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 151 | def announce(self, colors, what): |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 152 | '''Announce the start or completion of a job. |
| 153 | If what is None, announce the start of the job. |
| 154 | If what is True, announce that the job has passed. |
| 155 | If what is False, announce that the job has failed.''' |
| 156 | if what is True: |
Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 157 | log_line(self.name + ' PASSED', color=colors.green) |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 158 | elif what is False: |
Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 159 | log_line(self.name + ' FAILED', color=colors.red) |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 160 | else: |
Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 161 | log_line('starting ' + self.name, color=colors.cyan) |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 162 | |
Gabor Mezei | 9ce6d24 | 2024-06-19 17:47:05 +0200 | [diff] [blame] | 163 | def configure(self, conf, colors): |
Andrzej Kurek | a0cb4fa | 2022-10-14 07:06:43 -0400 | [diff] [blame] | 164 | '''Set library configuration options as required for the job.''' |
Gabor Mezei | 9ce6d24 | 2024-06-19 17:47:05 +0200 | [diff] [blame] | 165 | set_reference_config(conf, colors) |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 166 | for key, value in sorted(self.config_settings.items()): |
Andrzej Kurek | 3b0215d | 2023-01-23 07:19:22 -0500 | [diff] [blame] | 167 | ret = set_config_option_value(conf, key, colors, value) |
Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 168 | if ret is False: |
| 169 | return False |
| 170 | return True |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 171 | |
Gabor Mezei | 4e10d6c | 2024-08-03 14:26:13 +0200 | [diff] [blame] | 172 | def _consistency_check(self): |
| 173 | '''Check if the testable option is consistent with the goal. |
| 174 | |
| 175 | The purpose of this function to ensure that every option is set or unset according to |
| 176 | the settings. |
| 177 | ''' |
| 178 | log_command(['consistency check']) |
| 179 | c_name = None |
| 180 | exe_name = None |
| 181 | header = '#include "mbedtls/build_info.h"\n' |
| 182 | |
| 183 | # Generate a C error directive for each setting to test if it is active |
| 184 | for option, value in sorted(self.config_settings.items()): |
| 185 | header += '#if ' |
| 186 | if value: |
| 187 | header += '!' |
Gabor Mezei | c9f01cf | 2024-09-26 13:02:01 +0200 | [diff] [blame] | 188 | header += f'defined({option})\n' |
| 189 | header += f'#error "{option}"\n' |
Gabor Mezei | 4e10d6c | 2024-08-03 14:26:13 +0200 | [diff] [blame] | 190 | header += '#endif\n' |
| 191 | include_path = ['include', 'tf-psa-crypto/include', |
| 192 | 'tf-psa-crypto/drivers/builtin/include'] |
| 193 | |
| 194 | try: |
| 195 | # Generate a C file, build and run it |
| 196 | c_file, c_name, exe_name = c_build_helper.create_c_file(self.name) |
| 197 | c_build_helper.generate_c_file(c_file, 'depends.py', header, lambda x: '') |
| 198 | c_file.close() |
| 199 | c_build_helper.compile_c_file(c_name, exe_name, include_path) |
Gabor Mezei | 4e10d6c | 2024-08-03 14:26:13 +0200 | [diff] [blame] | 200 | return True |
| 201 | |
| 202 | except c_build_helper.CompileError as e: |
| 203 | # Read the command line output to find out which setting has been failed |
| 204 | failed = {m.group(1) for m in re.finditer('.*#error "(.*)"', e.message) if m} |
| 205 | log_line('Inconsistent config option(s):') |
| 206 | for option in sorted(failed): |
| 207 | log_line(' ' + option) |
Gabor Mezei | 4e10d6c | 2024-08-03 14:26:13 +0200 | [diff] [blame] | 208 | return False |
| 209 | |
| 210 | finally: |
| 211 | c_build_helper.remove_file_if_exists(c_name) |
| 212 | c_build_helper.remove_file_if_exists(exe_name) |
| 213 | |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 214 | def test(self, options): |
| 215 | '''Run the job's build and test commands. |
| 216 | Return True if all the commands succeed and False otherwise. |
| 217 | If options.keep_going is false, stop as soon as one command fails. Otherwise |
| 218 | run all the commands, except that if the first command fails, none of the |
| 219 | other commands are run (typically, the first command is a build command |
| 220 | and subsequent commands are tests that cannot run if the build failed).''' |
Gabor Mezei | 4e10d6c | 2024-08-03 14:26:13 +0200 | [diff] [blame] | 221 | if not self._consistency_check(): |
| 222 | return False |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 223 | built = False |
| 224 | success = True |
| 225 | for command in self.commands: |
Gilles Peskine | 54aa5c6 | 2019-01-29 18:46:34 +0100 | [diff] [blame] | 226 | log_command(command) |
Gilles Peskine | 35cb319 | 2024-02-12 14:16:05 +0100 | [diff] [blame] | 227 | env = os.environ.copy() |
| 228 | if 'MBEDTLS_TEST_CONFIGURATION' in env: |
| 229 | env['MBEDTLS_TEST_CONFIGURATION'] += '-' + self.name |
| 230 | ret = subprocess.call(command, env=env) |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 231 | if ret != 0: |
| 232 | if command[0] not in ['make', options.make_command]: |
| 233 | log_line('*** [{}] Error {}'.format(' '.join(command), ret)) |
| 234 | if not options.keep_going or not built: |
| 235 | return False |
| 236 | success = False |
| 237 | built = True |
| 238 | return success |
| 239 | |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 240 | # If the configuration option A requires B, make sure that |
Andrzej Kurek | 202932f | 2022-10-04 16:22:22 -0400 | [diff] [blame] | 241 | # B in REVERSE_DEPENDENCIES[A]. |
Gabor Mezei | 610e6e2 | 2024-08-03 14:33:21 +0200 | [diff] [blame] | 242 | # All the information here should be contained in check_config.h or check_crypto_config.h. |
| 243 | # This file includes a copy because it changes rarely and it would be a pain |
Gilles Peskine | 584c24a | 2019-01-29 19:30:40 +0100 | [diff] [blame] | 244 | # to extract automatically. |
Andrzej Kurek | 202932f | 2022-10-04 16:22:22 -0400 | [diff] [blame] | 245 | REVERSE_DEPENDENCIES = { |
Gabor Mezei | b50043b | 2024-06-18 20:30:36 +0200 | [diff] [blame] | 246 | 'PSA_WANT_KEY_TYPE_AES': ['PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128', |
| 247 | 'MBEDTLS_CTR_DRBG_C', |
Gabor Mezei | e6cfa3b | 2024-11-04 17:32:34 +0100 | [diff] [blame] | 248 | 'MBEDTLS_NIST_KW_C', |
| 249 | 'MBEDTLS_AES_C'], |
| 250 | 'PSA_WANT_KEY_TYPE_ARIA': ['MBEDTLS_ARIA_C'], |
| 251 | 'PSA_WANT_KEY_TYPE_CAMELLIA': ['MBEDTLS_CAMELLIA_C'], |
Gabor Mezei | b50043b | 2024-06-18 20:30:36 +0200 | [diff] [blame] | 252 | 'PSA_WANT_KEY_TYPE_CHACHA20': ['PSA_WANT_ALG_CHACHA20_POLY1305', |
Gabor Mezei | e6cfa3b | 2024-11-04 17:32:34 +0100 | [diff] [blame] | 253 | 'PSA_WANT_ALG_STREAM_CIPHER', |
| 254 | 'MBEDTLS_CHACHA20_C', |
| 255 | 'MBEDTLS_CHACHAPOLY_C'], |
| 256 | 'PSA_WANT_KEY_TYPE_DES': ['MBEDTLS_DES_C'], |
| 257 | 'PSA_WANT_ALG_CCM': ['PSA_WANT_ALG_CCM_STAR_NO_TAG', |
| 258 | 'MBEDTLS_CCM_C'], |
| 259 | 'PSA_WANT_ALG_CMAC': ['PSA_WANT_ALG_PBKDF2_AES_CMAC_PRF_128', |
| 260 | 'MBEDTLS_CMAC_C'], |
| 261 | 'PSA_WANT_ALG_GCM': ['MBEDTLS_GCM_C'], |
Gabor Mezei | 610e6e2 | 2024-08-03 14:33:21 +0200 | [diff] [blame] | 262 | |
Gabor Mezei | e191c03 | 2024-10-30 17:20:23 +0100 | [diff] [blame] | 263 | 'PSA_WANT_ALG_CBC_NO_PADDING': ['MBEDTLS_CIPHER_MODE_CBC'], |
| 264 | 'PSA_WANT_ALG_CBC_PKCS7': ['MBEDTLS_CIPHER_MODE_CBC'], |
| 265 | 'PSA_WANT_ALG_CFB': ['MBEDTLS_CIPHER_MODE_CFB'], |
| 266 | 'PSA_WANT_ALG_CTR': ['MBEDTLS_CIPHER_MODE_CTR'], |
| 267 | 'PSA_WANT_ALG_OFB': ['MBEDTLS_CIPHER_MODE_OFB'], |
Gabor Mezei | 610e6e2 | 2024-08-03 14:33:21 +0200 | [diff] [blame] | 268 | |
Gabor Mezei | 8f94485 | 2024-09-12 16:24:38 +0200 | [diff] [blame] | 269 | 'MBEDTLS_CIPHER_PADDING_PKCS7': ['MBEDTLS_PKCS5_C', |
| 270 | 'MBEDTLS_PKCS12_C', |
| 271 | 'PSA_WANT_ALG_CBC_PKCS7'], |
Gabor Mezei | 242806a | 2024-11-06 16:17:19 +0100 | [diff] [blame^] | 272 | 'MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS': ['MBEDTLS_CIPHER_MODE_CBC'], |
| 273 | 'MBEDTLS_CIPHER_PADDING_ZEROS': ['MBEDTLS_CIPHER_MODE_CBC'], |
| 274 | 'MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN': ['MBEDTLS_CIPHER_MODE_CBC'], |
Gabor Mezei | 610e6e2 | 2024-08-03 14:33:21 +0200 | [diff] [blame] | 275 | |
| 276 | 'MBEDTLS_ECP_DP_BP256R1_ENABLED': ['PSA_WANT_ECC_BRAINPOOL_P_R1_256'], |
| 277 | 'MBEDTLS_ECP_DP_BP384R1_ENABLED': ['PSA_WANT_ECC_BRAINPOOL_P_R1_384'], |
| 278 | 'MBEDTLS_ECP_DP_BP512R1_ENABLED': ['PSA_WANT_ECC_BRAINPOOL_P_R1_512'], |
| 279 | 'MBEDTLS_ECP_DP_CURVE25519_ENABLED': ['PSA_WANT_ECC_MONTGOMERY_255'], |
| 280 | 'MBEDTLS_ECP_DP_CURVE448_ENABLED': ['PSA_WANT_ECC_MONTGOMERY_448'], |
| 281 | 'MBEDTLS_ECP_DP_SECP192R1_ENABLED': ['PSA_WANT_ECC_SECP_R1_192'], |
| 282 | 'MBEDTLS_ECP_DP_SECP224R1_ENABLED': ['PSA_WANT_ECC_SECP_R1_224'], |
Gabor Mezei | 4fef797 | 2024-10-09 15:47:07 +0200 | [diff] [blame] | 283 | 'MBEDTLS_ECP_DP_SECP256R1_ENABLED': ['PSA_WANT_ECC_SECP_R1_256', |
| 284 | 'PSA_WANT_ALG_JPAKE', |
| 285 | 'MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED'], |
Gabor Mezei | 610e6e2 | 2024-08-03 14:33:21 +0200 | [diff] [blame] | 286 | 'MBEDTLS_ECP_DP_SECP384R1_ENABLED': ['PSA_WANT_ECC_SECP_R1_384'], |
| 287 | 'MBEDTLS_ECP_DP_SECP512R1_ENABLED': ['PSA_WANT_ECC_SECP_R1_512'], |
| 288 | 'MBEDTLS_ECP_DP_SECP521R1_ENABLED': ['PSA_WANT_ECC_SECP_R1_521'], |
| 289 | 'MBEDTLS_ECP_DP_SECP192K1_ENABLED': ['PSA_WANT_ECC_SECP_K1_192'], |
| 290 | 'MBEDTLS_ECP_DP_SECP256K1_ENABLED': ['PSA_WANT_ECC_SECP_K1_256'], |
| 291 | |
Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 292 | 'MBEDTLS_ECDSA_C': ['MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED', |
Gabor Mezei | 610e6e2 | 2024-08-03 14:33:21 +0200 | [diff] [blame] | 293 | 'MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED', |
| 294 | 'PSA_WANT_ALG_ECDSA', |
| 295 | 'PSA_WANT_ALG_DETERMINISTIC_ECDSA'], |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 296 | 'MBEDTLS_ECP_C': ['MBEDTLS_ECDSA_C', |
Gabor Mezei | 610e6e2 | 2024-08-03 14:33:21 +0200 | [diff] [blame] | 297 | 'MBEDTLS_ECDH_C', 'PSA_WANT_ALG_ECDH', |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 298 | 'MBEDTLS_ECJPAKE_C', |
Manuel Pégourié-Gonnard | ad45c4d | 2022-12-06 13:20:06 +0100 | [diff] [blame] | 299 | 'MBEDTLS_ECP_RESTARTABLE', |
Valerio Setti | 15e7044 | 2023-06-15 09:47:26 +0200 | [diff] [blame] | 300 | 'MBEDTLS_PK_PARSE_EC_EXTENDED', |
| 301 | 'MBEDTLS_PK_PARSE_EC_COMPRESSED', |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 302 | 'MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED', |
| 303 | 'MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED', |
| 304 | 'MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED', |
Ronald Cron | d8d2ea5 | 2022-10-04 15:48:06 +0200 | [diff] [blame] | 305 | 'MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED', |
Gabor Mezei | 610e6e2 | 2024-08-03 14:33:21 +0200 | [diff] [blame] | 306 | 'MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED', |
| 307 | 'PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY', |
| 308 | 'PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC', |
| 309 | 'PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT', |
| 310 | 'PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT', |
| 311 | 'PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE', |
| 312 | 'PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE'], |
| 313 | 'MBEDTLS_ECJPAKE_C': ['MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED', |
| 314 | 'PSA_WANT_ALG_JPAKE'], |
| 315 | 'MBEDTLS_PKCS1_V21': ['MBEDTLS_X509_RSASSA_PSS_SUPPORT', |
| 316 | 'PSA_WANT_ALG_RSA_OAEP', |
| 317 | 'PSA_WANT_ALG_RSA_PSS'], |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 318 | 'MBEDTLS_PKCS1_V15': ['MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED', |
| 319 | 'MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED', |
Gabor Mezei | 610e6e2 | 2024-08-03 14:33:21 +0200 | [diff] [blame] | 320 | 'MBEDTLS_KEY_EXCHANGE_RSA_ENABLED', |
| 321 | 'PSA_WANT_ALG_RSA_PKCS1V15_CRYPT', |
| 322 | 'PSA_WANT_ALG_RSA_PKCS1V15_SIGN'], |
Gabor Mezei | 8ec990b | 2024-07-31 17:14:04 +0200 | [diff] [blame] | 323 | 'MBEDTLS_RSA_C': ['MBEDTLS_PKCS1_V15', |
| 324 | 'MBEDTLS_PKCS1_V21', |
Gabor Mezei | 610e6e2 | 2024-08-03 14:33:21 +0200 | [diff] [blame] | 325 | 'MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED', |
| 326 | 'PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY', |
| 327 | 'PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC', |
| 328 | 'PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT', |
| 329 | 'PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_EXPORT', |
| 330 | 'PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_GENERATE'], |
| 331 | |
| 332 | 'MBEDTLS_MD5_C' : ['PSA_WANT_ALG_MD5'], |
| 333 | 'MBEDTLS_RIPEMD160_C' : ['PSA_WANT_ALG_RIPEMD160'], |
| 334 | 'MBEDTLS_SHA1_C' : ['PSA_WANT_ALG_SHA_1'], |
| 335 | 'MBEDTLS_SHA224_C': ['MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED', |
| 336 | 'MBEDTLS_ENTROPY_FORCE_SHA256', |
| 337 | 'MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT', |
| 338 | 'MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY', |
| 339 | 'PSA_WANT_ALG_SHA_224'], |
Gilles Peskine | 584c24a | 2019-01-29 19:30:40 +0100 | [diff] [blame] | 340 | 'MBEDTLS_SHA256_C': ['MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED', |
Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 341 | 'MBEDTLS_ENTROPY_FORCE_SHA256', |
Dave Rodgman | d680d4f | 2023-10-11 11:05:22 +0100 | [diff] [blame] | 342 | 'MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_IF_PRESENT', |
| 343 | 'MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_ONLY', |
Andrzej Kurek | 22b959d | 2022-10-16 12:51:41 -0400 | [diff] [blame] | 344 | 'MBEDTLS_LMS_C', |
Gabor Mezei | 610e6e2 | 2024-08-03 14:33:21 +0200 | [diff] [blame] | 345 | 'MBEDTLS_LMS_PRIVATE', |
| 346 | 'PSA_WANT_ALG_SHA_256', |
| 347 | 'PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS'], |
| 348 | 'MBEDTLS_SHA384_C' : ['PSA_WANT_ALG_SHA_384'], |
Valerio Setti | e7221a2 | 2022-12-16 11:53:45 +0100 | [diff] [blame] | 349 | 'MBEDTLS_SHA512_C': ['MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT', |
Gabor Mezei | 610e6e2 | 2024-08-03 14:33:21 +0200 | [diff] [blame] | 350 | 'MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY', |
| 351 | 'PSA_WANT_ALG_SHA_512'], |
| 352 | 'MBEDTLS_SHA3_C' : ['PSA_WANT_ALG_SHA3_224', |
| 353 | 'PSA_WANT_ALG_SHA3_256', |
| 354 | 'PSA_WANT_ALG_SHA3_384', |
| 355 | 'PSA_WANT_ALG_SHA3_512'], |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 356 | } |
| 357 | |
Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 358 | # 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] | 359 | # These are not necessarily dependencies, but just minimal required changes |
Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 360 | # 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] | 361 | EXCLUSIVE_GROUPS = { |
Andrzej Kurek | 65b2ac1 | 2022-10-14 08:09:16 -0400 | [diff] [blame] | 362 | 'MBEDTLS_SHA512_C': ['-MBEDTLS_SSL_COOKIE_C', |
Manuel Pégourié-Gonnard | 5a51d0d | 2023-03-22 13:04:08 +0100 | [diff] [blame] | 363 | '-MBEDTLS_SSL_TLS_C'], |
Andrzej Kurek | 65b2ac1 | 2022-10-14 08:09:16 -0400 | [diff] [blame] | 364 | 'MBEDTLS_ECP_DP_CURVE448_ENABLED': ['-MBEDTLS_ECDSA_C', |
| 365 | '-MBEDTLS_ECDSA_DETERMINISTIC', |
Gabor Mezei | 610e6e2 | 2024-08-03 14:33:21 +0200 | [diff] [blame] | 366 | '-MBEDTLS_ECJPAKE_C',], |
Andrzej Kurek | 65b2ac1 | 2022-10-14 08:09:16 -0400 | [diff] [blame] | 367 | 'MBEDTLS_ECP_DP_CURVE25519_ENABLED': ['-MBEDTLS_ECDSA_C', |
| 368 | '-MBEDTLS_ECDSA_DETERMINISTIC', |
Gabor Mezei | 610e6e2 | 2024-08-03 14:33:21 +0200 | [diff] [blame] | 369 | '-MBEDTLS_ECJPAKE_C'], |
Gabor Mezei | b50043b | 2024-06-18 20:30:36 +0200 | [diff] [blame] | 370 | 'PSA_WANT_KEY_TYPE_ARIA': ['-PSA_WANT_ALG_CMAC', |
| 371 | '-PSA_WANT_ALG_CCM', |
| 372 | '-PSA_WANT_ALG_GCM', |
| 373 | '-MBEDTLS_SSL_TICKET_C', |
| 374 | '-MBEDTLS_SSL_CONTEXT_SERIALIZATION'], |
| 375 | 'PSA_WANT_KEY_TYPE_CAMELLIA': ['-PSA_WANT_ALG_CMAC'], |
| 376 | 'PSA_WANT_KEY_TYPE_CHACHA20': ['-PSA_WANT_ALG_CMAC', |
| 377 | '-PSA_WANT_ALG_CCM', |
| 378 | '-PSA_WANT_ALG_GCM', |
| 379 | '-PSA_WANT_ALG_ECB_NO_PADDING'], |
| 380 | 'PSA_WANT_KEY_TYPE_DES': ['-PSA_WANT_ALG_CCM', |
| 381 | '-PSA_WANT_ALG_GCM', |
| 382 | '-MBEDTLS_SSL_TICKET_C', |
| 383 | '-MBEDTLS_SSL_CONTEXT_SERIALIZATION'], |
Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 384 | } |
| 385 | def handle_exclusive_groups(config_settings, symbol): |
| 386 | """For every symbol tested in an exclusive group check if there are other |
| 387 | defines to be altered. """ |
Andrzej Kurek | 202932f | 2022-10-04 16:22:22 -0400 | [diff] [blame] | 388 | for dep in EXCLUSIVE_GROUPS.get(symbol, []): |
Andrzej Kurek | 65b2ac1 | 2022-10-14 08:09:16 -0400 | [diff] [blame] | 389 | unset = dep.startswith('-') |
| 390 | dep = dep[1:] |
Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 391 | config_settings[dep] = not unset |
| 392 | |
Gabor Mezei | 95be5fb | 2024-10-30 17:21:49 +0100 | [diff] [blame] | 393 | def turn_off_dependencies(config_settings, exclude=None): |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 394 | """For every option turned off config_settings, also turn off what depends on it. |
Gabor Mezei | fb06101 | 2024-09-24 18:58:14 +0200 | [diff] [blame] | 395 | |
| 396 | An option O is turned off if config_settings[O] is False. |
| 397 | Handle the dependencies recursively. |
Gabor Mezei | 95be5fb | 2024-10-30 17:21:49 +0100 | [diff] [blame] | 398 | |
| 399 | If 'exclude' is a symbol, do not process it's dependencies. It is usefull when |
| 400 | two symbol has dependencies is common but need to be switched separately. |
Gabor Mezei | fb06101 | 2024-09-24 18:58:14 +0200 | [diff] [blame] | 401 | """ |
Gabor Mezei | 95be5fb | 2024-10-30 17:21:49 +0100 | [diff] [blame] | 402 | |
| 403 | # Recursively determine the excludable dependencies |
| 404 | excludes = set() |
| 405 | if exclude: |
| 406 | rev_excludes = set(REVERSE_DEPENDENCIES.get(exclude, [])) |
| 407 | while rev_excludes: |
| 408 | dep = rev_excludes.pop() |
| 409 | excludes.add(dep) |
| 410 | rev_excludes.update(set(REVERSE_DEPENDENCIES.get(dep, [])) - excludes) |
| 411 | |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 412 | for key, value in sorted(config_settings.items()): |
| 413 | if value is not False: |
| 414 | continue |
Gabor Mezei | fb06101 | 2024-09-24 18:58:14 +0200 | [diff] [blame] | 415 | |
Gabor Mezei | 95be5fb | 2024-10-30 17:21:49 +0100 | [diff] [blame] | 416 | # Save the processed settings to handle cross referencies. |
| 417 | # Mark the excluded dependencies as already processed to skip it. |
| 418 | history = excludes.copy() |
| 419 | revdep = set(REVERSE_DEPENDENCIES.get(key, [])) - excludes |
Gabor Mezei | 8ec990b | 2024-07-31 17:14:04 +0200 | [diff] [blame] | 420 | while revdep: |
| 421 | dep = revdep.pop() |
Gabor Mezei | fb06101 | 2024-09-24 18:58:14 +0200 | [diff] [blame] | 422 | history.add(dep) |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 423 | config_settings[dep] = False |
Gabor Mezei | fb06101 | 2024-09-24 18:58:14 +0200 | [diff] [blame] | 424 | # Do not add symbols which are already processed |
| 425 | revdep.update(set(REVERSE_DEPENDENCIES.get(dep, [])) - history) |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 426 | |
Andrzej Kurek | 228b12c | 2022-10-06 18:52:44 -0400 | [diff] [blame] | 427 | class BaseDomain: # pylint: disable=too-few-public-methods, unused-argument |
| 428 | """A base class for all domains.""" |
| 429 | def __init__(self, symbols, commands, exclude): |
| 430 | """Initialize the jobs container""" |
| 431 | self.jobs = [] |
| 432 | |
| 433 | class ExclusiveDomain(BaseDomain): # pylint: disable=too-few-public-methods |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 434 | """A domain consisting of a set of conceptually-equivalent settings. |
| 435 | 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] | 436 | with this symbol set and the others unset.""" |
Gilles Peskine | b1284cf | 2019-01-29 18:56:03 +0100 | [diff] [blame] | 437 | def __init__(self, symbols, commands, exclude=None): |
| 438 | """Build a domain for the specified list of configuration symbols. |
Andrzej Kurek | fe46949 | 2022-10-06 16:57:38 -0400 | [diff] [blame] | 439 | The domain contains a set of jobs that enable one of the elements |
| 440 | of symbols and disable the others. |
Gilles Peskine | b1284cf | 2019-01-29 18:56:03 +0100 | [diff] [blame] | 441 | Each job runs the specified commands. |
| 442 | If exclude is a regular expression, skip generated jobs whose description |
| 443 | would match this regular expression.""" |
Andrzej Kurek | 228b12c | 2022-10-06 18:52:44 -0400 | [diff] [blame] | 444 | super().__init__(symbols, commands, exclude) |
Andrzej Kurek | fe46949 | 2022-10-06 16:57:38 -0400 | [diff] [blame] | 445 | base_config_settings = {} |
| 446 | for symbol in symbols: |
| 447 | base_config_settings[symbol] = False |
| 448 | for symbol in symbols: |
| 449 | description = symbol |
| 450 | if exclude and re.match(exclude, description): |
| 451 | continue |
| 452 | config_settings = base_config_settings.copy() |
| 453 | config_settings[symbol] = True |
| 454 | handle_exclusive_groups(config_settings, symbol) |
Gabor Mezei | 95be5fb | 2024-10-30 17:21:49 +0100 | [diff] [blame] | 455 | turn_off_dependencies(config_settings, symbol) |
Andrzej Kurek | fe46949 | 2022-10-06 16:57:38 -0400 | [diff] [blame] | 456 | job = Job(description, config_settings, commands) |
| 457 | self.jobs.append(job) |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 458 | |
Andrzej Kurek | 228b12c | 2022-10-06 18:52:44 -0400 | [diff] [blame] | 459 | class ComplementaryDomain(BaseDomain): # pylint: disable=too-few-public-methods |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 460 | """A domain consisting of a set of loosely-related settings. |
| 461 | 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] | 462 | with this symbol unset. |
| 463 | If exclude is a regular expression, skip generated jobs whose description |
| 464 | would match this regular expression.""" |
Andrzej Kurek | 228b12c | 2022-10-06 18:52:44 -0400 | [diff] [blame] | 465 | def __init__(self, symbols, commands, exclude=None): |
Gilles Peskine | b1284cf | 2019-01-29 18:56:03 +0100 | [diff] [blame] | 466 | """Build a domain for the specified list of configuration symbols. |
| 467 | Each job in the domain disables one of the specified symbols. |
| 468 | Each job runs the specified commands.""" |
Andrzej Kurek | 228b12c | 2022-10-06 18:52:44 -0400 | [diff] [blame] | 469 | super().__init__(symbols, commands, exclude) |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 470 | for symbol in symbols: |
| 471 | description = '!' + symbol |
Andrzej Kurek | 228b12c | 2022-10-06 18:52:44 -0400 | [diff] [blame] | 472 | if exclude and re.match(exclude, description): |
| 473 | continue |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 474 | config_settings = {symbol: False} |
| 475 | turn_off_dependencies(config_settings) |
| 476 | job = Job(description, config_settings, commands) |
| 477 | self.jobs.append(job) |
| 478 | |
Andrzej Kurek | 228b12c | 2022-10-06 18:52:44 -0400 | [diff] [blame] | 479 | class DualDomain(ExclusiveDomain, ComplementaryDomain): # pylint: disable=too-few-public-methods |
Andrzej Kurek | a0cb4fa | 2022-10-14 07:06:43 -0400 | [diff] [blame] | 480 | """A domain that contains both the ExclusiveDomain and BaseDomain tests. |
Andrzej Kurek | f4b1867 | 2022-10-14 07:57:00 -0400 | [diff] [blame] | 481 | Both parent class __init__ calls are performed in any order and |
Andrzej Kurek | a0cb4fa | 2022-10-14 07:06:43 -0400 | [diff] [blame] | 482 | each call adds respective jobs. The job array initialization is done once in |
| 483 | BaseDomain, before the parent __init__ calls.""" |
Andrzej Kurek | 228b12c | 2022-10-06 18:52:44 -0400 | [diff] [blame] | 484 | |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 485 | class DomainData: |
Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 486 | """A container for domains and jobs, used to structurize testing.""" |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 487 | def config_symbols_matching(self, regexp): |
Andrzej Kurek | e05b17f | 2022-09-28 03:17:56 -0400 | [diff] [blame] | 488 | """List the mbedtls_config.h settings matching regexp.""" |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 489 | return [symbol for symbol in self.all_config_symbols |
| 490 | if re.match(regexp, symbol)] |
| 491 | |
Gabor Mezei | bd8e818 | 2024-11-06 11:23:23 +0100 | [diff] [blame] | 492 | # pylint: disable=too-many-locals |
Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 493 | def __init__(self, options, conf): |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 494 | """Gather data about the library and establish a list of domains to test.""" |
Dave Rodgman | 84125a1 | 2024-01-02 11:42:38 +0000 | [diff] [blame] | 495 | build_command = [options.make_command, 'CFLAGS=-Werror -O2'] |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 496 | build_and_test = [build_command, [options.make_command, 'test']] |
Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 497 | self.all_config_symbols = set(conf.settings.keys()) |
Gabor Mezei | 402381d | 2024-09-24 19:46:54 +0200 | [diff] [blame] | 498 | psa_info = psa_information.Information().constructors |
| 499 | algs = {crypto_knowledge.Algorithm(alg): symbol |
| 500 | for alg, symbol in ((alg, psa_information.psa_want_symbol(alg)) |
| 501 | for alg in psa_info.algorithms) |
| 502 | if symbol in self.all_config_symbols} |
Gabor Mezei | 06a060d | 2024-11-04 17:36:22 +0100 | [diff] [blame] | 503 | cipher_algs = {alg |
| 504 | for alg in algs |
| 505 | if alg.can_do(crypto_knowledge.AlgorithmCategory.CIPHER)} |
Gabor Mezei | 03cc592 | 2024-11-04 17:28:46 +0100 | [diff] [blame] | 506 | key_types = {crypto_knowledge.KeyType(expr): symbol |
| 507 | for key_type in psa_info.key_types |
| 508 | for expr, symbol in ((expr, psa_information.psa_want_symbol(key_type)) |
| 509 | for expr in psa_info.generate_expressions([key_type])) |
| 510 | if symbol in self.all_config_symbols} |
Gabor Mezei | 402381d | 2024-09-24 19:46:54 +0200 | [diff] [blame] | 511 | |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 512 | # Find hash modules by name. |
| 513 | hash_symbols = self.config_symbols_matching(r'MBEDTLS_(MD|RIPEMD|SHA)[0-9]+_C\Z') |
| 514 | # Find elliptic curve enabling macros by name. |
| 515 | curve_symbols = self.config_symbols_matching(r'MBEDTLS_ECP_DP_\w+_ENABLED\Z') |
| 516 | # Find key exchange enabling macros by name. |
| 517 | key_exchange_symbols = self.config_symbols_matching(r'MBEDTLS_KEY_EXCHANGE_\w+_ENABLED\Z') |
Gabor Mezei | b50043b | 2024-06-18 20:30:36 +0200 | [diff] [blame] | 518 | |
Gabor Mezei | fb6b0db | 2024-11-04 17:30:32 +0100 | [diff] [blame] | 519 | # Find cipher key types |
| 520 | cipher_key_types = {symbol |
| 521 | for key_type, symbol in key_types.items() |
| 522 | for alg in cipher_algs |
| 523 | if key_type.can_do(alg)} |
Gabor Mezei | 6f77baf | 2024-09-20 14:18:42 +0200 | [diff] [blame] | 524 | |
Gabor Mezei | 5a61086 | 2024-10-30 17:19:00 +0100 | [diff] [blame] | 525 | # Get cipher modes |
| 526 | cipher_chaining_symbols = {algs[cipher_alg] for cipher_alg in cipher_algs} |
Gabor Mezei | 6f77baf | 2024-09-20 14:18:42 +0200 | [diff] [blame] | 527 | |
| 528 | # Find block padding mode enabling macros by name. |
Gilles Peskine | 34a1557 | 2019-01-29 23:12:28 +0100 | [diff] [blame] | 529 | cipher_padding_symbols = self.config_symbols_matching(r'MBEDTLS_CIPHER_PADDING_\w+\Z') |
Gabor Mezei | 6f77baf | 2024-09-20 14:18:42 +0200 | [diff] [blame] | 530 | |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 531 | self.domains = { |
Gabor Mezei | fb6b0db | 2024-11-04 17:30:32 +0100 | [diff] [blame] | 532 | # Cipher key types |
| 533 | 'cipher_id': ExclusiveDomain(cipher_key_types, build_and_test), |
Gabor Mezei | 6f77baf | 2024-09-20 14:18:42 +0200 | [diff] [blame] | 534 | |
Gabor Mezei | a5f3529 | 2024-10-30 17:30:25 +0100 | [diff] [blame] | 535 | # XTS is not yet supported via the PSA API. |
| 536 | # See https://github.com/Mbed-TLS/mbedtls/issues/6384 |
Gilles Peskine | 34a1557 | 2019-01-29 23:12:28 +0100 | [diff] [blame] | 537 | 'cipher_chaining': ExclusiveDomain(cipher_chaining_symbols, |
Gabor Mezei | 6f77baf | 2024-09-20 14:18:42 +0200 | [diff] [blame] | 538 | build_and_test, |
| 539 | exclude=r'PSA_WANT_ALG_XTS'), |
| 540 | |
Gilles Peskine | 34a1557 | 2019-01-29 23:12:28 +0100 | [diff] [blame] | 541 | 'cipher_padding': ExclusiveDomain(cipher_padding_symbols, |
| 542 | build_and_test), |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 543 | # Elliptic curves. Run the test suites. |
| 544 | 'curves': ExclusiveDomain(curve_symbols, build_and_test), |
Valerio Setti | ea8c88f | 2022-12-29 11:08:35 +0100 | [diff] [blame] | 545 | # Hash algorithms. Excluding exclusive domains of MD, RIPEMD, SHA1, |
| 546 | # SHA224 and SHA384 because MBEDTLS_ENTROPY_C is extensively used |
| 547 | # across various modules, but it depends on either SHA256 or SHA512. |
| 548 | # As a consequence an "exclusive" test of anything other than SHA256 |
| 549 | # or SHA512 with MBEDTLS_ENTROPY_C enabled is not possible. |
Andrzej Kurek | 228b12c | 2022-10-06 18:52:44 -0400 | [diff] [blame] | 550 | 'hashes': DualDomain(hash_symbols, build_and_test, |
Andrzej Kurek | a0cb4fa | 2022-10-14 07:06:43 -0400 | [diff] [blame] | 551 | exclude=r'MBEDTLS_(MD|RIPEMD|SHA1_)' \ |
Valerio Setti | b6bf7dc | 2022-12-22 14:28:03 +0100 | [diff] [blame] | 552 | '|MBEDTLS_SHA224_' \ |
Pol Henarejos | aa426e0 | 2023-02-08 12:52:10 +0100 | [diff] [blame] | 553 | '|MBEDTLS_SHA384_' \ |
| 554 | '|MBEDTLS_SHA3_'), |
Andrzej Kurek | 98682b5 | 2023-01-23 06:16:23 -0500 | [diff] [blame] | 555 | # Key exchange types. |
Andrzej Kurek | 1ff7336 | 2022-11-02 04:50:16 -0400 | [diff] [blame] | 556 | 'kex': ExclusiveDomain(key_exchange_symbols, build_and_test), |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 557 | 'pkalgs': ComplementaryDomain(['MBEDTLS_ECDSA_C', |
| 558 | 'MBEDTLS_ECP_C', |
| 559 | 'MBEDTLS_PKCS1_V21', |
| 560 | 'MBEDTLS_PKCS1_V15', |
| 561 | 'MBEDTLS_RSA_C', |
| 562 | 'MBEDTLS_X509_RSASSA_PSS_SUPPORT'], |
| 563 | build_and_test), |
| 564 | } |
| 565 | self.jobs = {} |
| 566 | for domain in self.domains.values(): |
| 567 | for job in domain.jobs: |
| 568 | self.jobs[job.name] = job |
| 569 | |
| 570 | def get_jobs(self, name): |
| 571 | """Return the list of jobs identified by the given name. |
| 572 | A name can either be the name of a domain or the name of one specific job.""" |
| 573 | if name in self.domains: |
| 574 | return sorted(self.domains[name].jobs, key=lambda job: job.name) |
| 575 | else: |
| 576 | return [self.jobs[name]] |
| 577 | |
Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 578 | def run(options, job, conf, colors=NO_COLORS): |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 579 | """Run the specified job (a Job instance).""" |
| 580 | subprocess.check_call([options.make_command, 'clean']) |
Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 581 | job.announce(colors, None) |
Gabor Mezei | 9ce6d24 | 2024-06-19 17:47:05 +0200 | [diff] [blame] | 582 | if not job.configure(conf, colors): |
Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 583 | job.announce(colors, False) |
| 584 | return False |
| 585 | conf.write() |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 586 | success = job.test(options) |
Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 587 | job.announce(colors, success) |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 588 | return success |
| 589 | |
Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 590 | def run_tests(options, domain_data, conf): |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 591 | """Run the desired jobs. |
| 592 | domain_data should be a DomainData instance that describes the available |
| 593 | domains and jobs. |
Andrzej Kurek | b8a97e7 | 2022-10-17 08:39:09 -0400 | [diff] [blame] | 594 | Run the jobs listed in options.tasks.""" |
Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 595 | colors = Colors(options) |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 596 | jobs = [] |
| 597 | failures = [] |
| 598 | successes = [] |
Andrzej Kurek | b8a97e7 | 2022-10-17 08:39:09 -0400 | [diff] [blame] | 599 | for name in options.tasks: |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 600 | jobs += domain_data.get_jobs(name) |
Gabor Mezei | 035d7c8 | 2024-06-19 15:46:21 +0200 | [diff] [blame] | 601 | conf.backup() |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 602 | try: |
| 603 | for job in jobs: |
Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 604 | success = run(options, job, conf, colors=colors) |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 605 | if not success: |
| 606 | if options.keep_going: |
| 607 | failures.append(job.name) |
| 608 | else: |
| 609 | return False |
| 610 | else: |
| 611 | successes.append(job.name) |
Gabor Mezei | 035d7c8 | 2024-06-19 15:46:21 +0200 | [diff] [blame] | 612 | conf.restore() |
Gilles Peskine | bf7537d | 2019-01-29 18:52:16 +0100 | [diff] [blame] | 613 | except: |
| 614 | # Restore the configuration, except in stop-on-error mode if there |
| 615 | # was an error, where we leave the failing configuration up for |
| 616 | # developer convenience. |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 617 | if options.keep_going: |
Gabor Mezei | 035d7c8 | 2024-06-19 15:46:21 +0200 | [diff] [blame] | 618 | conf.restore() |
Gilles Peskine | bf7537d | 2019-01-29 18:52:16 +0100 | [diff] [blame] | 619 | raise |
Gilles Peskine | e85163b | 2019-01-29 18:50:03 +0100 | [diff] [blame] | 620 | if successes: |
| 621 | log_line('{} passed'.format(' '.join(successes)), color=colors.bold_green) |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 622 | if failures: |
Gilles Peskine | e85163b | 2019-01-29 18:50:03 +0100 | [diff] [blame] | 623 | log_line('{} FAILED'.format(' '.join(failures)), color=colors.bold_red) |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 624 | return False |
| 625 | else: |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 626 | return True |
| 627 | |
Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 628 | def main(): |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 629 | try: |
Andrzej Kurek | 01af84a | 2022-10-09 05:29:44 -0400 | [diff] [blame] | 630 | parser = argparse.ArgumentParser( |
| 631 | formatter_class=argparse.RawDescriptionHelpFormatter, |
| 632 | description= |
| 633 | "Test Mbed TLS with a subset of algorithms.\n\n" |
| 634 | "Example usage:\n" |
Andrzej Kurek | 629c412 | 2022-10-17 08:34:40 -0400 | [diff] [blame] | 635 | r"./tests/scripts/depends.py \!MBEDTLS_SHA1_C MBEDTLS_SHA256_C""\n" |
Andrzej Kurek | 01af84a | 2022-10-09 05:29:44 -0400 | [diff] [blame] | 636 | "./tests/scripts/depends.py MBEDTLS_AES_C hashes\n" |
| 637 | "./tests/scripts/depends.py cipher_id cipher_chaining\n") |
Gilles Peskine | 0fa7cbe | 2019-01-29 18:48:48 +0100 | [diff] [blame] | 638 | parser.add_argument('--color', metavar='WHEN', |
| 639 | help='Colorize the output (always/auto/never)', |
| 640 | choices=['always', 'auto', 'never'], default='auto') |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 641 | parser.add_argument('-c', '--config', metavar='FILE', |
| 642 | help='Configuration file to modify', |
Gabor Mezei | f5408f0 | 2024-06-14 15:25:46 +0200 | [diff] [blame] | 643 | default=config.MbedTLSConfigFile.default_path[0]) |
| 644 | parser.add_argument('-r', '--crypto-config', metavar='FILE', |
| 645 | help='Crypto configuration file to modify', |
| 646 | default=config.CryptoConfigFile.default_path[0]) |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 647 | parser.add_argument('-C', '--directory', metavar='DIR', |
| 648 | help='Change to this directory before anything else', |
| 649 | default='.') |
| 650 | parser.add_argument('-k', '--keep-going', |
| 651 | help='Try all configurations even if some fail (default)', |
| 652 | action='store_true', dest='keep_going', default=True) |
| 653 | parser.add_argument('-e', '--no-keep-going', |
| 654 | help='Stop as soon as a configuration fails', |
| 655 | action='store_false', dest='keep_going') |
| 656 | parser.add_argument('--list-jobs', |
| 657 | help='List supported jobs and exit', |
| 658 | action='append_const', dest='list', const='jobs') |
| 659 | parser.add_argument('--list-domains', |
| 660 | help='List supported domains and exit', |
| 661 | action='append_const', dest='list', const='domains') |
| 662 | parser.add_argument('--make-command', metavar='CMD', |
| 663 | help='Command to run instead of make (e.g. gmake)', |
| 664 | action='store', default='make') |
Andrzej Kurek | b8a97e7 | 2022-10-17 08:39:09 -0400 | [diff] [blame] | 665 | parser.add_argument('tasks', metavar='TASKS', nargs='*', |
| 666 | help='The domain(s) or job(s) to test (default: all).', |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 667 | default=True) |
| 668 | options = parser.parse_args() |
| 669 | os.chdir(options.directory) |
Gabor Mezei | f5408f0 | 2024-06-14 15:25:46 +0200 | [diff] [blame] | 670 | conf = config.CombinedConfig(config.MbedTLSConfigFile(options.config), |
| 671 | config.CryptoConfigFile(options.crypto_config)) |
Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 672 | domain_data = DomainData(options, conf) |
| 673 | |
Andrzej Kurek | b8a97e7 | 2022-10-17 08:39:09 -0400 | [diff] [blame] | 674 | if options.tasks is True: |
| 675 | options.tasks = sorted(domain_data.domains.keys()) |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 676 | if options.list: |
Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 677 | for arg in options.list: |
| 678 | for domain_name in sorted(getattr(domain_data, arg).keys()): |
| 679 | print(domain_name) |
| 680 | sys.exit(0) |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 681 | else: |
Andrzej Kurek | 3f93012 | 2022-10-26 08:08:26 -0400 | [diff] [blame] | 682 | sys.exit(0 if run_tests(options, domain_data, conf) else 1) |
Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 683 | except Exception: # pylint: disable=broad-except |
Gilles Peskine | b39e3ec | 2019-01-29 08:50:20 +0100 | [diff] [blame] | 684 | traceback.print_exc() |
Andrzej Kurek | 3322c22 | 2022-10-04 15:02:41 -0400 | [diff] [blame] | 685 | sys.exit(3) |
| 686 | |
| 687 | if __name__ == '__main__': |
| 688 | main() |