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