From 3678deed9d315615c0b9ac523b7c4843919ce01d Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Tue, 4 Jun 2024 19:58:43 +0200 Subject: [PATCH 01/20] Add crypto config support for config.py Signed-off-by: Gabor Mezei --- scripts/config.py | 262 +++++++++++++++++++++++++++++---------- tests/scripts/depends.py | 2 +- 2 files changed, 200 insertions(+), 64 deletions(-) diff --git a/scripts/config.py b/scripts/config.py index 7c32db18dd..ad1f787bc9 100755 --- a/scripts/config.py +++ b/scripts/config.py @@ -19,6 +19,8 @@ Basic usage, to read the Mbed TLS configuration: import os import re +from abc import ABCMeta, abstractmethod + class Setting: """Representation of one Mbed TLS mbedtls_config.h setting. @@ -31,11 +33,12 @@ class Setting: * section: the name of the section that contains this symbol. """ # pylint: disable=too-few-public-methods - def __init__(self, active, name, value='', section=None): + def __init__(self, active, name, value='', section=None, configfile=None): self.active = active self.name = name self.value = value self.section = section + self.configfile = configfile class Config: """Representation of the Mbed TLS configuration. @@ -54,7 +57,7 @@ class Config: name to become set. """ - def __init__(self): + def __init__(self, **kw): self.settings = {} def __contains__(self, name): @@ -152,7 +155,7 @@ class Config: def is_full_section(section): """Is this section affected by "config.py full" and friends?""" - return section.endswith('support') or section.endswith('modules') + return section is None or section.endswith('support') or section.endswith('modules') def realfull_adapter(_name, active, section): """Activate all symbols found in the global and boolean feature sections. @@ -168,6 +171,22 @@ def realfull_adapter(_name, active, section): return active return True +UNSUPPORTED_FEATURE = frozenset([ + 'PSA_WANT_ALG_CBC_MAC', + 'PSA_WANT_ALG_XTS', + 'PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_DERIVE', + 'PSA_WANT_KEY_TYPE_DH_KEY_PAIR_DERIVE' +]) + +DEPRECATED_FEATURE = frozenset([ + 'PSA_WANT_KEY_TYPE_ECC_KEY_PAIR', + 'PSA_WANT_KEY_TYPE_RSA_KEY_PAIR' +]) + +UNSTABLE_FEATURE = frozenset([ + 'PSA_WANT_ECC_SECP_K1_224' +]) + # The goal of the full configuration is to have everything that can be tested # together. This includes deprecated or insecure options. It excludes: # * Options that require additional build dependencies or unusual hardware. @@ -236,7 +255,8 @@ def is_seamless_alt(name): def include_in_full(name): """Rules for symbols in the "full" configuration.""" - if name in EXCLUDE_FROM_FULL: + if name in (EXCLUDE_FROM_FULL | UNSUPPORTED_FEATURE | + DEPRECATED_FEATURE | UNSTABLE_FEATURE): return False if name.endswith('_ALT'): return is_seamless_alt(name) @@ -368,43 +388,21 @@ def no_platform_adapter(adapter): return adapter(name, active, section) return continuation -class ConfigFile(Config): - """Representation of the Mbed TLS configuration read for a file. - - See the documentation of the `Config` class for methods to query - and modify the configuration. - """ - - _path_in_tree = 'include/mbedtls/mbedtls_config.h' - default_path = [_path_in_tree, - os.path.join(os.path.dirname(__file__), - os.pardir, - _path_in_tree), - os.path.join(os.path.dirname(os.path.abspath(os.path.dirname(__file__))), - _path_in_tree)] - - def __init__(self, filename=None): - """Read the Mbed TLS configuration file.""" +class ConfigFile(metaclass=ABCMeta): + def __init__(self, default_path, filename=None, name=''): if filename is None: - for candidate in self.default_path: + for candidate in default_path: if os.path.lexists(candidate): filename = candidate break else: - raise Exception('Mbed TLS configuration file not found', - self.default_path) - super().__init__() - self.filename = filename - self.inclusion_guard = None - self.current_section = 'header' - with open(filename, 'r', encoding='utf-8') as file: - self.templates = [self._parse_line(line) for line in file] - self.current_section = None + raise Exception(name + ' configuration file not found', + default_path) - def set(self, name, value=None): - if name not in self.settings: - self.templates.append((name, '', '#define ' + name + ' ')) - super().set(name, value) + self.filename = filename + self.templates = [] + self.current_section = None + self.inclusion_guard = None _define_line_regexp = (r'(?P\s*)' + r'(?P(//\s*)?)' + @@ -420,39 +418,87 @@ class ConfigFile(Config): _ifndef_line_regexp, _section_line_regexp])) def _parse_line(self, line): - """Parse a line in mbedtls_config.h and return the corresponding template.""" + """Parse a line in the config file and return the corresponding template.""" line = line.rstrip('\r\n') m = re.match(self._config_line_regexp, line) if m is None: - return line + self.templates.append(line) + return None elif m.group('section'): self.current_section = m.group('section') - return line + self.templates.append(line) + return None elif m.group('inclusion_guard') and self.inclusion_guard is None: self.inclusion_guard = m.group('inclusion_guard') - return line + self.templates.append(line) + return None else: active = not m.group('commented_out') name = m.group('name') value = m.group('value') if name == self.inclusion_guard and value == '': # The file double-inclusion guard is not an option. - return line + self.templates.append(line) + return None template = (name, m.group('indentation'), m.group('define') + name + m.group('arguments') + m.group('separator')) - self.settings[name] = Setting(active, name, value, - self.current_section) - return template + self.templates.append(template) - def _format_template(self, name, indent, middle): + return (active, name, value, self.current_section) + + def parse_file(self): + with open(self.filename, 'r', encoding='utf-8') as file: + for line in file: + setting = self._parse_line(line) + if setting is not None: + yield setting + self.current_section = None + + @abstractmethod + def _format_template(self, setting, name, indent, middle): + pass + + def write_to_stream(self, settings, output): + """Write the whole configuration to output.""" + for template in self.templates: + if isinstance(template, str): + line = template + else: + name, _, _ = template + line = self._format_template(settings[name], *template) + output.write(line + '\n') + + def write(self, settings, filename=None): + """Write the whole configuration to the file it was read from. + + If filename is specified, write to this file instead. + """ + if filename is None: + filename = self.filename + with open(filename, 'w', encoding='utf-8') as output: + self.write_to_stream(settings, output) + +class MbedtlsConfigFile(ConfigFile): + _path_in_tree = 'include/mbedtls/mbedtls_config.h' + default_path = [_path_in_tree, + os.path.join(os.path.dirname(__file__), + os.pardir, + _path_in_tree), + os.path.join(os.path.dirname(os.path.abspath(os.path.dirname(__file__))), + _path_in_tree)] + + def __init__(self, filename=None): + super().__init__(self.default_path, filename, 'Mbed TLS') + self.current_section = 'header' + + def _format_template(self, setting, name, indent, middle): """Build a line for mbedtls_config.h for the given setting. The line has the form "#define " where is "#define ". """ - setting = self.settings[name] value = setting.value if value is None: value = '' @@ -470,24 +516,110 @@ class ConfigFile(Config): middle, value]).rstrip() - def write_to_stream(self, output): - """Write the whole configuration to output.""" - for template in self.templates: - if isinstance(template, str): - line = template - else: - line = self._format_template(*template) - output.write(line + '\n') +class CryptoConfigFile(ConfigFile): + _path_in_tree = 'tf-psa-crypto/include/psa/crypto_config.h' + default_path = [_path_in_tree, + os.path.join(os.path.dirname(__file__), + os.pardir, + _path_in_tree), + os.path.join(os.path.dirname(os.path.abspath(os.path.dirname(__file__))), + _path_in_tree)] + + def __init__(self, filename=None): + super().__init__(self.default_path, filename, 'Crypto') + + def _format_template(self, setting, name, indent, middle): + """Build a line for crypto_config.h for the given setting. + + The line has the form "#define " + where is "#define ". + """ + value = setting.value + if value is None: + value = '1' + if middle[-1] not in '\t ': + middle += ' ' + return ''.join([indent, + '' if setting.active else '//', + middle, + value]).rstrip() + +class MbedtlsConfig(Config): + """Representation of the Mbed TLS configuration read for a file. + + See the documentation of the `Config` class for methods to query + and modify the configuration. + """ + def __init__(self, mbedtls_config=None, **kw): + """Read the Mbed TLS configuration file.""" + super().__init__() + self.mbedtls_config = MbedtlsConfigFile(mbedtls_config) + self.settings.update({name: Setting(active, name, value, section, self.mbedtls_config) + for (active, name, value, section) + in self.mbedtls_config.parse_file()}) + + def set(self, name, value=None): + if name not in self.settings: + self.mbedtls_config.templates.append((name, '', '#define ' + name + ' ')) + super().set(name, value) def write(self, filename=None): - """Write the whole configuration to the file it was read from. + self.mbedtls_config.write(self.settings, filename) - If filename is specified, write to this file instead. - """ - if filename is None: - filename = self.filename - with open(filename, 'w', encoding='utf-8') as output: - self.write_to_stream(output) + def filename(self, name): + return self.mbedtls_config.filename + +class CryptoConfig(Config): + """Representation of the PSA crypto configuration read for a file. + + See the documentation of the `Config` class for methods to query + and modify the configuration. + """ + def __init__(self, crypto_config=None, **kw): + """Read the PSA crypto configuration file.""" + super().__init__() + self.crypto_config = CryptoConfigFile(crypto_config) + self.settings.update({name: Setting(active, name, value, section, self.crypto_config) + for (active, name, value, section) + in self.crypto_config.parse_file()}) + + def set(self, name, value=None): + if name in UNSUPPORTED_FEATURE: + raise ValueError('Feature is unsupported: \'{}\''.format(name)) + if name in UNSTABLE_FEATURE: + raise ValueError('Feature is unstable: \'{}\''.format(name)) + + if name not in self.settings: + self.crypto_config.templates.append((name, '', '#define ' + name + ' ' + '1')) + super().set(name, value) + + def write(self, filename=None): + self.crypto_config.write(self.settings, filename) + + def filename(self, name): + return self.crypto_config.filename + +class MultiConfig(MbedtlsConfig, CryptoConfig): + + def __init__(self, mbedtls_config, crypto_config): + super().__init__(mbedtls_config=mbedtls_config, crypto_config=crypto_config) + + _crypto_regexp = re.compile(r'$PSA_.*') + def _get_related_config(self, name): + if re.match(self._crypto_regexp, name): + return CryptoConfig + else: + return MbedtlsConfig + + def set(self, name, value=None): + super(self._get_related_config(name), self).set(name, value) + + def write(self, mbedtls_file=None, crypto_file=None): + self.mbedtls_config.write(self.settings, mbedtls_file) + self.crypto_config.write(self.settings, crypto_file) + + def filename(self, name): + return self.settings[name].configfile if __name__ == '__main__': def main(): @@ -498,7 +630,11 @@ if __name__ == '__main__': parser.add_argument('--file', '-f', help="""File to read (and modify if requested). Default: {}. - """.format(ConfigFile.default_path)) + """.format(MbedtlsConfigFile.default_path)) + parser.add_argument('--cryptofile', '-c', + help="""Crypto file to read (and modify if requested). + Default: {}. + """.format(CryptoConfigFile.default_path)) parser.add_argument('--force', '-o', action='store_true', help="""For the set command, if SYMBOL is not @@ -576,7 +712,7 @@ if __name__ == '__main__': excluding X.509 and TLS.""") args = parser.parse_args() - config = ConfigFile(args.file) + config = MultiConfig(args.file, args.cryptofile) if args.command is None: parser.print_help() return 1 @@ -590,7 +726,7 @@ if __name__ == '__main__': if not args.force and args.symbol not in config.settings: sys.stderr.write("A #define for the symbol {} " "was not found in {}\n" - .format(args.symbol, config.filename)) + .format(args.symbol, config.filename(args.symbol))) return 1 config.set(args.symbol, value=args.value) elif args.command == 'set-all': diff --git a/tests/scripts/depends.py b/tests/scripts/depends.py index fa17e134d3..55c7a5a1f9 100755 --- a/tests/scripts/depends.py +++ b/tests/scripts/depends.py @@ -541,7 +541,7 @@ def main(): default=True) options = parser.parse_args() os.chdir(options.directory) - conf = config.ConfigFile(options.config) + conf = config.MbedtlsConfig(options.config) domain_data = DomainData(options, conf) if options.tasks is True: From 62a9bd0f5d758dc1f3ac9ed40200a7b7c7b8fdb2 Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Fri, 7 Jun 2024 13:44:40 +0200 Subject: [PATCH 02/20] Update and add documentation Signed-off-by: Gabor Mezei --- scripts/config.py | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/scripts/config.py b/scripts/config.py index ad1f787bc9..120c827d6e 100755 --- a/scripts/config.py +++ b/scripts/config.py @@ -389,7 +389,10 @@ def no_platform_adapter(adapter): return continuation class ConfigFile(metaclass=ABCMeta): + """Representation of a configuration file.""" + def __init__(self, default_path, filename=None, name=''): + """Check if the config file exists.""" if filename is None: for candidate in default_path: if os.path.lexists(candidate): @@ -418,7 +421,9 @@ class ConfigFile(metaclass=ABCMeta): _ifndef_line_regexp, _section_line_regexp])) def _parse_line(self, line): - """Parse a line in the config file and return the corresponding template.""" + """Parse a line in the config file, save the templates representing the lines + and return the corresponding setting element. + """ line = line.rstrip('\r\n') m = re.match(self._config_line_regexp, line) if m is None: @@ -449,6 +454,7 @@ class ConfigFile(metaclass=ABCMeta): return (active, name, value, self.current_section) def parse_file(self): + """Parse the whole file and return the settings.""" with open(self.filename, 'r', encoding='utf-8') as file: for line in file: setting = self._parse_line(line) @@ -481,6 +487,8 @@ class ConfigFile(metaclass=ABCMeta): self.write_to_stream(settings, output) class MbedtlsConfigFile(ConfigFile): + """Representation of an MbedTLS configuration file.""" + _path_in_tree = 'include/mbedtls/mbedtls_config.h' default_path = [_path_in_tree, os.path.join(os.path.dirname(__file__), @@ -517,6 +525,8 @@ class MbedtlsConfigFile(ConfigFile): value]).rstrip() class CryptoConfigFile(ConfigFile): + """Representation of an Crypto configuration file.""" + _path_in_tree = 'tf-psa-crypto/include/psa/crypto_config.h' default_path = [_path_in_tree, os.path.join(os.path.dirname(__file__), @@ -545,7 +555,7 @@ class CryptoConfigFile(ConfigFile): value]).rstrip() class MbedtlsConfig(Config): - """Representation of the Mbed TLS configuration read for a file. + """Representation of the Mbed TLS configuration. See the documentation of the `Config` class for methods to query and modify the configuration. @@ -564,13 +574,17 @@ class MbedtlsConfig(Config): super().set(name, value) def write(self, filename=None): + """Write the whole configuration to the file it was read from. + + If filename is specified, write to this file instead. + """ self.mbedtls_config.write(self.settings, filename) def filename(self, name): return self.mbedtls_config.filename class CryptoConfig(Config): - """Representation of the PSA crypto configuration read for a file. + """Representation of the PSA crypto configuration. See the documentation of the `Config` class for methods to query and modify the configuration. @@ -594,12 +608,21 @@ class CryptoConfig(Config): super().set(name, value) def write(self, filename=None): + """Write the whole configuration to the file it was read from. + + If filename is specified, write to this file instead. + """ self.crypto_config.write(self.settings, filename) def filename(self, name): return self.crypto_config.filename class MultiConfig(MbedtlsConfig, CryptoConfig): + """Representation of MbedTLS and PSA crypto configuration + + See the documentation of the `Config` class for methods to query + and modify the configuration. + """ def __init__(self, mbedtls_config, crypto_config): super().__init__(mbedtls_config=mbedtls_config, crypto_config=crypto_config) @@ -615,6 +638,11 @@ class MultiConfig(MbedtlsConfig, CryptoConfig): super(self._get_related_config(name), self).set(name, value) def write(self, mbedtls_file=None, crypto_file=None): + """Write the whole configuration to the file it was read from. + + If mbedtls_file or crypto_file is specified, write the specific configuration + to the corresponding file instead. + """ self.mbedtls_config.write(self.settings, mbedtls_file) self.crypto_config.write(self.settings, crypto_file) From 92065ed28df019ea2e21e7cca4c2e991a73771bd Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Fri, 7 Jun 2024 13:47:59 +0200 Subject: [PATCH 03/20] Fix pylint issues Signed-off-by: Gabor Mezei --- scripts/config.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/scripts/config.py b/scripts/config.py index 120c827d6e..d73ce6c6b0 100755 --- a/scripts/config.py +++ b/scripts/config.py @@ -32,7 +32,7 @@ class Setting: present in mbedtls_config.h but commented out. * section: the name of the section that contains this symbol. """ - # pylint: disable=too-few-public-methods + # pylint: disable=too-few-public-methods, too-many-arguments def __init__(self, active, name, value='', section=None, configfile=None): self.active = active self.name = name @@ -57,6 +57,7 @@ class Config: name to become set. """ + # pylint: disable=unused-argument def __init__(self, **kw): self.settings = {} @@ -399,8 +400,8 @@ class ConfigFile(metaclass=ABCMeta): filename = candidate break else: - raise Exception(name + ' configuration file not found', - default_path) + raise ValueError(f'{name} configuration file not found: ' + f'{filename if filename else default_path}') self.filename = filename self.templates = [] @@ -565,8 +566,8 @@ class MbedtlsConfig(Config): super().__init__() self.mbedtls_config = MbedtlsConfigFile(mbedtls_config) self.settings.update({name: Setting(active, name, value, section, self.mbedtls_config) - for (active, name, value, section) - in self.mbedtls_config.parse_file()}) + for (active, name, value, section) + in self.mbedtls_config.parse_file()}) def set(self, name, value=None): if name not in self.settings: @@ -594,14 +595,14 @@ class CryptoConfig(Config): super().__init__() self.crypto_config = CryptoConfigFile(crypto_config) self.settings.update({name: Setting(active, name, value, section, self.crypto_config) - for (active, name, value, section) - in self.crypto_config.parse_file()}) + for (active, name, value, section) + in self.crypto_config.parse_file()}) def set(self, name, value=None): if name in UNSUPPORTED_FEATURE: - raise ValueError('Feature is unsupported: \'{}\''.format(name)) + raise ValueError(f'Feature is unsupported: \'{name}\'') if name in UNSTABLE_FEATURE: - raise ValueError('Feature is unstable: \'{}\''.format(name)) + raise ValueError(f'Feature is unstable: \'{name}\'') if name not in self.settings: self.crypto_config.templates.append((name, '', '#define ' + name + ' ' + '1')) @@ -637,6 +638,7 @@ class MultiConfig(MbedtlsConfig, CryptoConfig): def set(self, name, value=None): super(self._get_related_config(name), self).set(name, value) + # pylint: disable=arguments-renamed def write(self, mbedtls_file=None, crypto_file=None): """Write the whole configuration to the file it was read from. @@ -650,6 +652,7 @@ class MultiConfig(MbedtlsConfig, CryptoConfig): return self.settings[name].configfile if __name__ == '__main__': + #pylint: disable=too-many-statements def main(): """Command line mbedtls_config.h manipulation tool.""" parser = argparse.ArgumentParser(description=""" From ee521b6137903e7a7b27ac92441c3a7c3d1eda4b Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Fri, 7 Jun 2024 13:50:41 +0200 Subject: [PATCH 04/20] Restructure the configuration representation Signed-off-by: Gabor Mezei --- scripts/config.py | 84 ++++++++++++++++++++++++++++++----------------- 1 file changed, 54 insertions(+), 30 deletions(-) diff --git a/scripts/config.py b/scripts/config.py index d73ce6c6b0..8fda2e2aab 100755 --- a/scripts/config.py +++ b/scripts/config.py @@ -58,7 +58,7 @@ class Config: """ # pylint: disable=unused-argument - def __init__(self, **kw): + def __init__(self): self.settings = {} def __contains__(self, name): @@ -561,17 +561,18 @@ class MbedtlsConfig(Config): See the documentation of the `Config` class for methods to query and modify the configuration. """ - def __init__(self, mbedtls_config=None, **kw): + def __init__(self, filename=None): """Read the Mbed TLS configuration file.""" super().__init__() - self.mbedtls_config = MbedtlsConfigFile(mbedtls_config) - self.settings.update({name: Setting(active, name, value, section, self.mbedtls_config) + self.configfile = MbedtlsConfigFile(filename) + self.settings.update({name: Setting(active, name, value, section) for (active, name, value, section) - in self.mbedtls_config.parse_file()}) + in self.configfile.parse_file()}) def set(self, name, value=None): if name not in self.settings: - self.mbedtls_config.templates.append((name, '', '#define ' + name + ' ')) + self.configfile.templates.append((name, '', '#define ' + name + ' ')) + super().set(name, value) def write(self, filename=None): @@ -579,10 +580,10 @@ class MbedtlsConfig(Config): If filename is specified, write to this file instead. """ - self.mbedtls_config.write(self.settings, filename) + self.configfile.write(self.settings, filename) - def filename(self, name): - return self.mbedtls_config.filename + def filename(self): + return self.configfile.filename class CryptoConfig(Config): """Representation of the PSA crypto configuration. @@ -590,13 +591,13 @@ class CryptoConfig(Config): See the documentation of the `Config` class for methods to query and modify the configuration. """ - def __init__(self, crypto_config=None, **kw): + def __init__(self, filename=None): """Read the PSA crypto configuration file.""" super().__init__() - self.crypto_config = CryptoConfigFile(crypto_config) - self.settings.update({name: Setting(active, name, value, section, self.crypto_config) + self.configfile = CryptoConfigFile(filename) + self.settings.update({name: Setting(active, name, value, section) for (active, name, value, section) - in self.crypto_config.parse_file()}) + in self.configfile.parse_file()}) def set(self, name, value=None): if name in UNSUPPORTED_FEATURE: @@ -605,7 +606,8 @@ class CryptoConfig(Config): raise ValueError(f'Feature is unstable: \'{name}\'') if name not in self.settings: - self.crypto_config.templates.append((name, '', '#define ' + name + ' ' + '1')) + self.configfile.templates.append((name, '', '#define ' + name + ' ')) + super().set(name, value) def write(self, filename=None): @@ -613,43 +615,65 @@ class CryptoConfig(Config): If filename is specified, write to this file instead. """ - self.crypto_config.write(self.settings, filename) + self.configfile.write(self.settings, filename) - def filename(self, name): - return self.crypto_config.filename + def filename(self): + return self.configfile.filename -class MultiConfig(MbedtlsConfig, CryptoConfig): +class MultiConfig(Config): """Representation of MbedTLS and PSA crypto configuration See the documentation of the `Config` class for methods to query and modify the configuration. """ - def __init__(self, mbedtls_config, crypto_config): - super().__init__(mbedtls_config=mbedtls_config, crypto_config=crypto_config) + def __init__(self, mbedtls_filename=None, crypto__filename=None): + super().__init__() + self.mbedtls_configfile = MbedtlsConfigFile(mbedtls_filename) + self.crypto_configfile = CryptoConfigFile(crypto__filename) + self.settings.update({name: Setting(active, name, value, section, configfile) + for configfile in [self.mbedtls_configfile, self.crypto_configfile] + for (active, name, value, section) in configfile.parse_file()}) _crypto_regexp = re.compile(r'$PSA_.*') - def _get_related_config(self, name): - if re.match(self._crypto_regexp, name): - return CryptoConfig + def _get_configfile(self, name): + """Find a config type for a setting name + """ + if name in self.settings: + return self.settings[name].configfile + elif re.match(self._crypto_regexp, name): + return self.crypto_configfile else: - return MbedtlsConfig + return self.mbedtls_configfile def set(self, name, value=None): - super(self._get_related_config(name), self).set(name, value) + configfile = self._get_configfile(name) + + if configfile == self.crypto_configfile: + if name in UNSUPPORTED_FEATURE: + raise ValueError(f'Feature is unsupported: \'{name}\'') + if name in UNSTABLE_FEATURE: + raise ValueError(f'Feature is unstable: \'{name}\'') + + if name not in self.settings: + configfile.templates.append((name, '', '#define ' + name + ' ')) + + super().set(name, value) - # pylint: disable=arguments-renamed def write(self, mbedtls_file=None, crypto_file=None): """Write the whole configuration to the file it was read from. If mbedtls_file or crypto_file is specified, write the specific configuration to the corresponding file instead. """ - self.mbedtls_config.write(self.settings, mbedtls_file) - self.crypto_config.write(self.settings, crypto_file) + self.mbedtls_configfile.write(self.settings, mbedtls_file) + self.crypto_configfile.write(self.settings, crypto_file) - def filename(self, name): - return self.settings[name].configfile + def filename(self, name=None): + if not name: + return [config.filename for config in [self.mbedtls_configfile, self.crypto_configfile]] + + return self._get_configfile(name).filename if __name__ == '__main__': #pylint: disable=too-many-statements From d723b51befa33e34edeeba6d732cab0c104329a8 Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Fri, 7 Jun 2024 15:31:52 +0200 Subject: [PATCH 05/20] Fix for crypto config default value Signed-off-by: Gabor Mezei --- scripts/config.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/scripts/config.py b/scripts/config.py index 8fda2e2aab..0d65e771b0 100755 --- a/scripts/config.py +++ b/scripts/config.py @@ -599,12 +599,16 @@ class CryptoConfig(Config): for (active, name, value, section) in self.configfile.parse_file()}) - def set(self, name, value=None): + def set(self, name, value='1'): if name in UNSUPPORTED_FEATURE: raise ValueError(f'Feature is unsupported: \'{name}\'') if name in UNSTABLE_FEATURE: raise ValueError(f'Feature is unstable: \'{name}\'') + # The default value in the crypto config is '1' + if not value: + value = '1' + if name not in self.settings: self.configfile.templates.append((name, '', '#define ' + name + ' ')) @@ -655,6 +659,10 @@ class MultiConfig(Config): if name in UNSTABLE_FEATURE: raise ValueError(f'Feature is unstable: \'{name}\'') + # The default value in the crypto config is '1' + if not value: + value = '1' + if name not in self.settings: configfile.templates.append((name, '', '#define ' + name + ' ')) From 542fd3843789d72330a38899aa05d4a821933e33 Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Mon, 10 Jun 2024 14:07:42 +0200 Subject: [PATCH 06/20] Update unsupported and deprecated psa fearues handling Signed-off-by: Gabor Mezei --- scripts/config.py | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/scripts/config.py b/scripts/config.py index 0d65e771b0..929aee6502 100755 --- a/scripts/config.py +++ b/scripts/config.py @@ -172,22 +172,28 @@ def realfull_adapter(_name, active, section): return active return True -UNSUPPORTED_FEATURE = frozenset([ +PSA_UNSUPPORTED_FEATURE = frozenset([ 'PSA_WANT_ALG_CBC_MAC', 'PSA_WANT_ALG_XTS', 'PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_DERIVE', 'PSA_WANT_KEY_TYPE_DH_KEY_PAIR_DERIVE' ]) -DEPRECATED_FEATURE = frozenset([ +PSA_DEPRECATED_FEATURE = frozenset([ 'PSA_WANT_KEY_TYPE_ECC_KEY_PAIR', 'PSA_WANT_KEY_TYPE_RSA_KEY_PAIR' ]) -UNSTABLE_FEATURE = frozenset([ +PSA_UNSTABLE_FEATURE = frozenset([ 'PSA_WANT_ECC_SECP_K1_224' ]) +EXCLUDE_FROM_CRYPTO = frozenset( + PSA_UNSUPPORTED_FEATURE | + PSA_DEPRECATED_FEATURE | + PSA_UNSTABLE_FEATURE +) + # The goal of the full configuration is to have everything that can be tested # together. This includes deprecated or insecure options. It excludes: # * Options that require additional build dependencies or unusual hardware. @@ -230,6 +236,9 @@ EXCLUDE_FROM_FULL = frozenset([ 'MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN', # build dependency (clang+memsan) 'MBEDTLS_TEST_CONSTANT_FLOW_VALGRIND', # build dependency (valgrind headers) 'MBEDTLS_X509_REMOVE_INFO', # removes a feature + *PSA_UNSUPPORTED_FEATURE, + *PSA_DEPRECATED_FEATURE, + *PSA_UNSTABLE_FEATURE ]) def is_seamless_alt(name): @@ -256,8 +265,7 @@ def is_seamless_alt(name): def include_in_full(name): """Rules for symbols in the "full" configuration.""" - if name in (EXCLUDE_FROM_FULL | UNSUPPORTED_FEATURE | - DEPRECATED_FEATURE | UNSTABLE_FEATURE): + if name in EXCLUDE_FROM_FULL: return False if name.endswith('_ALT'): return is_seamless_alt(name) @@ -337,6 +345,8 @@ def include_in_crypto(name): 'MBEDTLS_PKCS7_C', # part of libmbedx509 ]: return False + if name in EXCLUDE_FROM_CRYPTO: + return False return True def crypto_adapter(adapter): @@ -355,6 +365,7 @@ def crypto_adapter(adapter): DEPRECATED = frozenset([ 'MBEDTLS_PSA_CRYPTO_SE_C', + *PSA_DEPRECATED_FEATURE ]) def no_deprecated_adapter(adapter): """Modify an adapter to disable deprecated symbols. @@ -600,9 +611,9 @@ class CryptoConfig(Config): in self.configfile.parse_file()}) def set(self, name, value='1'): - if name in UNSUPPORTED_FEATURE: + if name in PSA_UNSUPPORTED_FEATURE: raise ValueError(f'Feature is unsupported: \'{name}\'') - if name in UNSTABLE_FEATURE: + if name in PSA_UNSTABLE_FEATURE: raise ValueError(f'Feature is unstable: \'{name}\'') # The default value in the crypto config is '1' @@ -654,9 +665,9 @@ class MultiConfig(Config): configfile = self._get_configfile(name) if configfile == self.crypto_configfile: - if name in UNSUPPORTED_FEATURE: + if name in PSA_UNSUPPORTED_FEATURE: raise ValueError(f'Feature is unsupported: \'{name}\'') - if name in UNSTABLE_FEATURE: + if name in PSA_UNSTABLE_FEATURE: raise ValueError(f'Feature is unstable: \'{name}\'') # The default value in the crypto config is '1' From 8a64d8e34665ce64d9d5140887c407f1994d5b1f Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Mon, 10 Jun 2024 15:23:43 +0200 Subject: [PATCH 07/20] Only write config files if it is modified Signed-off-by: Gabor Mezei --- scripts/config.py | 56 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/scripts/config.py b/scripts/config.py index 929aee6502..ba5a00c2ff 100755 --- a/scripts/config.py +++ b/scripts/config.py @@ -418,6 +418,7 @@ class ConfigFile(metaclass=ABCMeta): self.templates = [] self.current_section = None self.inclusion_guard = None + self.modified = False _define_line_regexp = (r'(?P\s*)' + r'(?P(//\s*)?)' + @@ -495,6 +496,11 @@ class ConfigFile(metaclass=ABCMeta): """ if filename is None: filename = self.filename + + # Not modified so no need to write to the file + if not self.modified and filename == self.filename: + return + with open(filename, 'w', encoding='utf-8') as output: self.write_to_stream(settings, output) @@ -661,6 +667,10 @@ class MultiConfig(Config): else: return self.mbedtls_configfile + def __setitem__(self, name, value): + super().__setitem__(name, value) + self.settings[name].configfile.modified = True + def set(self, name, value=None): configfile = self._get_configfile(name) @@ -674,11 +684,55 @@ class MultiConfig(Config): if not value: value = '1' - if name not in self.settings: + if name in self.settings: + setting = self.settings[name] + if not setting.active or (value is not None and setting.value != value): + configfile.modified = True + else: configfile.templates.append((name, '', '#define ' + name + ' ')) + configfile.modified = True super().set(name, value) + def unset(self, name): + if name in self.settings and self.settings[name].active: + self.settings[name].configfile.modified = True + + super().unset(name) + + def adapt(self, adapter): + # Determine if the config files will be modified + unmodified = {config for config in [self.mbedtls_configfile, self.crypto_configfile] + if not config.modified} + if unmodified: + for setting in self.settings.values(): + if not setting.configfile.modified and \ + setting.active != adapter(setting.name, setting.active, setting.section): + setting.configfile.modified = True + unmodified.remove(setting.configfile) + if not unmodified: + break + + super().adapt(adapter) + + def change_matching(self, regexs, enable): + # Determine if the config files will be modified + if regexs: + regex = re.compile('|'.join(regexs)) + unmodified = {config for config in [self.mbedtls_configfile, self.crypto_configfile] + if not config.modified} + if unmodified: + for setting in self.settings.values(): + if not setting.configfile.modified and \ + setting.active != enable and \ + regex.search(setting.name): + setting.configfile.modified = True + unmodified.remove(setting.configfile) + if not unmodified: + break + + super().change_matching(regexs, enable) + def write(self, mbedtls_file=None, crypto_file=None): """Write the whole configuration to the file it was read from. From 93a6d1f6ecff4339a3d2ad11e909e86fe61a49c1 Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Wed, 26 Jun 2024 18:01:09 +0200 Subject: [PATCH 08/20] Make the `name` parameter mandatory for the constructor of `ConfigFile` Signed-off-by: Gabor Mezei --- scripts/config.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) mode change 100755 => 100644 scripts/config.py diff --git a/scripts/config.py b/scripts/config.py old mode 100755 new mode 100644 index ba5a00c2ff..fcc3fff686 --- a/scripts/config.py +++ b/scripts/config.py @@ -403,7 +403,7 @@ def no_platform_adapter(adapter): class ConfigFile(metaclass=ABCMeta): """Representation of a configuration file.""" - def __init__(self, default_path, filename=None, name=''): + def __init__(self, default_path, name, filename=None): """Check if the config file exists.""" if filename is None: for candidate in default_path: @@ -516,7 +516,7 @@ class MbedtlsConfigFile(ConfigFile): _path_in_tree)] def __init__(self, filename=None): - super().__init__(self.default_path, filename, 'Mbed TLS') + super().__init__(self.default_path, 'Mbed TLS', filename) self.current_section = 'header' def _format_template(self, setting, name, indent, middle): @@ -554,7 +554,7 @@ class CryptoConfigFile(ConfigFile): _path_in_tree)] def __init__(self, filename=None): - super().__init__(self.default_path, filename, 'Crypto') + super().__init__(self.default_path, 'Crypto', filename) def _format_template(self, setting, name, indent, middle): """Build a line for crypto_config.h for the given setting. From e7742b360d4e9dd237a3bfb373589f73c2da1a5d Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Wed, 26 Jun 2024 18:04:09 +0200 Subject: [PATCH 09/20] Unify the `_format_parameter` function among the `ConfigFile` subclasses Signed-off-by: Gabor Mezei --- scripts/config.py | 71 +++++++++++++++++------------------------------ 1 file changed, 26 insertions(+), 45 deletions(-) mode change 100644 => 100755 scripts/config.py diff --git a/scripts/config.py b/scripts/config.py old mode 100644 new mode 100755 index fcc3fff686..cd6a4b4f4a --- a/scripts/config.py +++ b/scripts/config.py @@ -19,7 +19,7 @@ Basic usage, to read the Mbed TLS configuration: import os import re -from abc import ABCMeta, abstractmethod +from abc import ABCMeta class Setting: """Representation of one Mbed TLS mbedtls_config.h setting. @@ -475,9 +475,29 @@ class ConfigFile(metaclass=ABCMeta): yield setting self.current_section = None - @abstractmethod - def _format_template(self, setting, name, indent, middle): - pass + #pylint: disable=no-self-use + def _format_template(self, setting, indent, middle): + """Build a line for mbedtls_config.h for the given setting. + + The line has the form "#define " + where is "#define ". + """ + value = setting.value + if value is None: + value = '' + # Normally the whitespace to separate the symbol name from the + # value is part of middle, and there's no whitespace for a symbol + # with no value. But if a symbol has been changed from having a + # value to not having one, the whitespace is wrong, so fix it. + if value: + if middle[-1] not in '\t ': + middle += ' ' + else: + middle = middle.rstrip() + return ''.join([indent, + '' if setting.active else '//', + middle, + value]).rstrip() def write_to_stream(self, settings, output): """Write the whole configuration to output.""" @@ -485,8 +505,8 @@ class ConfigFile(metaclass=ABCMeta): if isinstance(template, str): line = template else: - name, _, _ = template - line = self._format_template(settings[name], *template) + name, indent, middle = template + line = self._format_template(settings[name], indent, middle) output.write(line + '\n') def write(self, settings, filename=None): @@ -519,29 +539,6 @@ class MbedtlsConfigFile(ConfigFile): super().__init__(self.default_path, 'Mbed TLS', filename) self.current_section = 'header' - def _format_template(self, setting, name, indent, middle): - """Build a line for mbedtls_config.h for the given setting. - - The line has the form "#define " - where is "#define ". - """ - value = setting.value - if value is None: - value = '' - # Normally the whitespace to separate the symbol name from the - # value is part of middle, and there's no whitespace for a symbol - # with no value. But if a symbol has been changed from having a - # value to not having one, the whitespace is wrong, so fix it. - if value: - if middle[-1] not in '\t ': - middle += ' ' - else: - middle = middle.rstrip() - return ''.join([indent, - '' if setting.active else '//', - middle, - value]).rstrip() - class CryptoConfigFile(ConfigFile): """Representation of an Crypto configuration file.""" @@ -556,22 +553,6 @@ class CryptoConfigFile(ConfigFile): def __init__(self, filename=None): super().__init__(self.default_path, 'Crypto', filename) - def _format_template(self, setting, name, indent, middle): - """Build a line for crypto_config.h for the given setting. - - The line has the form "#define " - where is "#define ". - """ - value = setting.value - if value is None: - value = '1' - if middle[-1] not in '\t ': - middle += ' ' - return ''.join([indent, - '' if setting.active else '//', - middle, - value]).rstrip() - class MbedtlsConfig(Config): """Representation of the Mbed TLS configuration. From 9b0f9e77a0c10e70d0a0a2f9715f5d534d879493 Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Wed, 26 Jun 2024 18:08:17 +0200 Subject: [PATCH 10/20] Simplify set creation Signed-off-by: Gabor Mezei --- scripts/config.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/scripts/config.py b/scripts/config.py index cd6a4b4f4a..a9856679d9 100755 --- a/scripts/config.py +++ b/scripts/config.py @@ -188,11 +188,9 @@ PSA_UNSTABLE_FEATURE = frozenset([ 'PSA_WANT_ECC_SECP_K1_224' ]) -EXCLUDE_FROM_CRYPTO = frozenset( - PSA_UNSUPPORTED_FEATURE | - PSA_DEPRECATED_FEATURE | - PSA_UNSTABLE_FEATURE -) +EXCLUDE_FROM_CRYPTO = PSA_UNSUPPORTED_FEATURE | \ + PSA_DEPRECATED_FEATURE | \ + PSA_UNSTABLE_FEATURE # The goal of the full configuration is to have everything that can be tested # together. This includes deprecated or insecure options. It excludes: From f77722d67f049100577a89d992e6d5032f3c6bac Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Fri, 28 Jun 2024 16:49:33 +0200 Subject: [PATCH 11/20] Rename calss Signed-off-by: Gabor Mezei --- scripts/config.py | 10 +++++----- tests/scripts/depends.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/config.py b/scripts/config.py index a9856679d9..97d7555555 100755 --- a/scripts/config.py +++ b/scripts/config.py @@ -522,7 +522,7 @@ class ConfigFile(metaclass=ABCMeta): with open(filename, 'w', encoding='utf-8') as output: self.write_to_stream(settings, output) -class MbedtlsConfigFile(ConfigFile): +class MbedTLSConfigFile(ConfigFile): """Representation of an MbedTLS configuration file.""" _path_in_tree = 'include/mbedtls/mbedtls_config.h' @@ -551,7 +551,7 @@ class CryptoConfigFile(ConfigFile): def __init__(self, filename=None): super().__init__(self.default_path, 'Crypto', filename) -class MbedtlsConfig(Config): +class MbedTLSConfig(Config): """Representation of the Mbed TLS configuration. See the documentation of the `Config` class for methods to query @@ -560,7 +560,7 @@ class MbedtlsConfig(Config): def __init__(self, filename=None): """Read the Mbed TLS configuration file.""" super().__init__() - self.configfile = MbedtlsConfigFile(filename) + self.configfile = MbedTLSConfigFile(filename) self.settings.update({name: Setting(active, name, value, section) for (active, name, value, section) in self.configfile.parse_file()}) @@ -629,7 +629,7 @@ class MultiConfig(Config): def __init__(self, mbedtls_filename=None, crypto__filename=None): super().__init__() - self.mbedtls_configfile = MbedtlsConfigFile(mbedtls_filename) + self.mbedtls_configfile = MbedTLSConfigFile(mbedtls_filename) self.crypto_configfile = CryptoConfigFile(crypto__filename) self.settings.update({name: Setting(active, name, value, section, configfile) for configfile in [self.mbedtls_configfile, self.crypto_configfile] @@ -737,7 +737,7 @@ if __name__ == '__main__': parser.add_argument('--file', '-f', help="""File to read (and modify if requested). Default: {}. - """.format(MbedtlsConfigFile.default_path)) + """.format(MbedTLSConfigFile.default_path)) parser.add_argument('--cryptofile', '-c', help="""Crypto file to read (and modify if requested). Default: {}. diff --git a/tests/scripts/depends.py b/tests/scripts/depends.py index 55c7a5a1f9..509809965e 100755 --- a/tests/scripts/depends.py +++ b/tests/scripts/depends.py @@ -541,7 +541,7 @@ def main(): default=True) options = parser.parse_args() os.chdir(options.directory) - conf = config.MbedtlsConfig(options.config) + conf = config.MbedTLSConfig(options.config) domain_data = DomainData(options, conf) if options.tasks is True: From de6e192fd4eb545562a7204be2b4d65284057d79 Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Fri, 28 Jun 2024 17:10:50 +0200 Subject: [PATCH 12/20] Add documentation Signed-off-by: Gabor Mezei --- scripts/config.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/config.py b/scripts/config.py index 97d7555555..3ee21d1464 100755 --- a/scripts/config.py +++ b/scripts/config.py @@ -155,7 +155,11 @@ class Config: setting.active = enable def is_full_section(section): - """Is this section affected by "config.py full" and friends?""" + """Is this section affected by "config.py full" and friends? + + In a config file where the sections are not used the whole config file + is an empty section (with value None) and the whole file is affected. + """ return section is None or section.endswith('support') or section.endswith('modules') def realfull_adapter(_name, active, section): From 8d72ac60b3fad9c048b8cf8deb7a7af6c0e9d7a4 Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Fri, 28 Jun 2024 17:18:37 +0200 Subject: [PATCH 13/20] Fix error type Signed-off-by: Gabor Mezei --- scripts/config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/config.py b/scripts/config.py index 3ee21d1464..839e26a726 100755 --- a/scripts/config.py +++ b/scripts/config.py @@ -413,8 +413,8 @@ class ConfigFile(metaclass=ABCMeta): filename = candidate break else: - raise ValueError(f'{name} configuration file not found: ' - f'{filename if filename else default_path}') + raise FileNotFoundError(f'{name} configuration file not found: ' + f'{filename if filename else default_path}') self.filename = filename self.templates = [] From 3e2a550f12b9b230550942a89634a649116126ae Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Fri, 28 Jun 2024 17:27:19 +0200 Subject: [PATCH 14/20] Pass `ConfigFile` object as parameter for `MultiConfig` constructor Signed-off-by: Gabor Mezei --- scripts/config.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/scripts/config.py b/scripts/config.py index 839e26a726..518badbce0 100755 --- a/scripts/config.py +++ b/scripts/config.py @@ -631,10 +631,16 @@ class MultiConfig(Config): and modify the configuration. """ - def __init__(self, mbedtls_filename=None, crypto__filename=None): + def __init__(self, *configs): super().__init__() - self.mbedtls_configfile = MbedTLSConfigFile(mbedtls_filename) - self.crypto_configfile = CryptoConfigFile(crypto__filename) + for config in configs: + if isinstance(config, MbedTLSConfigFile): + self.mbedtls_configfile = config + elif isinstance(config, CryptoConfigFile): + self.crypto_configfile = config + else: + raise ValueError(f'Invalid configfile: {config}') + self.settings.update({name: Setting(active, name, value, section, configfile) for configfile in [self.mbedtls_configfile, self.crypto_configfile] for (active, name, value, section) in configfile.parse_file()}) @@ -823,7 +829,7 @@ if __name__ == '__main__': excluding X.509 and TLS.""") args = parser.parse_args() - config = MultiConfig(args.file, args.cryptofile) + config = MultiConfig(MbedTLSConfigFile(args.file), CryptoConfigFile(args.cryptofile)) if args.command is None: parser.print_help() return 1 From c5ff33cedf7b429d36543e79196b4109e319ba1f Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Fri, 28 Jun 2024 17:46:44 +0200 Subject: [PATCH 15/20] Move config file modification checking to the `Config` superclass Signed-off-by: Gabor Mezei --- scripts/config.py | 58 +++++++++++++---------------------------------- 1 file changed, 16 insertions(+), 42 deletions(-) diff --git a/scripts/config.py b/scripts/config.py index 518badbce0..9335edaf8f 100755 --- a/scripts/config.py +++ b/scripts/config.py @@ -129,7 +129,13 @@ class Config: """ if name not in self.settings: return - self.settings[name].active = False + + setting = self.settings[name] + # Check if modifying the config file + if setting.configfile and setting.active: + setting.configfile.modified = True + + setting.active = False def adapt(self, adapter): """Run adapter on each known symbol and (de)activate it accordingly. @@ -142,8 +148,12 @@ class Config: otherwise unset `name` (i.e. make it known but inactive). """ for setting in self.settings.values(): + is_active = setting.active setting.active = adapter(setting.name, setting.active, setting.section) + # Check if modifying the config file + if setting.configfile and setting.active != is_active: + setting.configfile.modified = True def change_matching(self, regexs, enable): """Change all symbols matching one of the regexs to the desired state.""" @@ -152,6 +162,9 @@ class Config: regex = re.compile('|'.join(regexs)) for setting in self.settings.values(): if regex.search(setting.name): + # Check if modifying the config file + if setting.configfile and setting.active != enable: + setting.configfile.modified = True setting.active = enable def is_full_section(section): @@ -565,7 +578,7 @@ class MbedTLSConfig(Config): """Read the Mbed TLS configuration file.""" super().__init__() self.configfile = MbedTLSConfigFile(filename) - self.settings.update({name: Setting(active, name, value, section) + self.settings.update({name: Setting(active, name, value, section, self.configfile) for (active, name, value, section) in self.configfile.parse_file()}) @@ -595,7 +608,7 @@ class CryptoConfig(Config): """Read the PSA crypto configuration file.""" super().__init__() self.configfile = CryptoConfigFile(filename) - self.settings.update({name: Setting(active, name, value, section) + self.settings.update({name: Setting(active, name, value, section, self.configfile) for (active, name, value, section) in self.configfile.parse_file()}) @@ -683,45 +696,6 @@ class MultiConfig(Config): super().set(name, value) - def unset(self, name): - if name in self.settings and self.settings[name].active: - self.settings[name].configfile.modified = True - - super().unset(name) - - def adapt(self, adapter): - # Determine if the config files will be modified - unmodified = {config for config in [self.mbedtls_configfile, self.crypto_configfile] - if not config.modified} - if unmodified: - for setting in self.settings.values(): - if not setting.configfile.modified and \ - setting.active != adapter(setting.name, setting.active, setting.section): - setting.configfile.modified = True - unmodified.remove(setting.configfile) - if not unmodified: - break - - super().adapt(adapter) - - def change_matching(self, regexs, enable): - # Determine if the config files will be modified - if regexs: - regex = re.compile('|'.join(regexs)) - unmodified = {config for config in [self.mbedtls_configfile, self.crypto_configfile] - if not config.modified} - if unmodified: - for setting in self.settings.values(): - if not setting.configfile.modified and \ - setting.active != enable and \ - regex.search(setting.name): - setting.configfile.modified = True - unmodified.remove(setting.configfile) - if not unmodified: - break - - super().change_matching(regexs, enable) - def write(self, mbedtls_file=None, crypto_file=None): """Write the whole configuration to the file it was read from. From 33dd293723a3598a3909deeef41456636b82f3a0 Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Fri, 28 Jun 2024 17:51:58 +0200 Subject: [PATCH 16/20] Give better name for class Signed-off-by: Gabor Mezei --- scripts/config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/config.py b/scripts/config.py index 9335edaf8f..132b2d4479 100755 --- a/scripts/config.py +++ b/scripts/config.py @@ -637,7 +637,7 @@ class CryptoConfig(Config): def filename(self): return self.configfile.filename -class MultiConfig(Config): +class CombinedConfig(Config): """Representation of MbedTLS and PSA crypto configuration See the documentation of the `Config` class for methods to query @@ -803,7 +803,7 @@ if __name__ == '__main__': excluding X.509 and TLS.""") args = parser.parse_args() - config = MultiConfig(MbedTLSConfigFile(args.file), CryptoConfigFile(args.cryptofile)) + config = CombinedConfig(MbedTLSConfigFile(args.file), CryptoConfigFile(args.cryptofile)) if args.command is None: parser.print_help() return 1 From 3de658664ba259fb73d74fb1597759b6a635945f Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Mon, 8 Jul 2024 16:14:10 +0200 Subject: [PATCH 17/20] Adjust temporarily the crypto config file location Signed-off-by: Gabor Mezei --- scripts/config.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/config.py b/scripts/config.py index 132b2d4479..c5a5495eb4 100755 --- a/scripts/config.py +++ b/scripts/config.py @@ -557,7 +557,12 @@ class MbedTLSConfigFile(ConfigFile): class CryptoConfigFile(ConfigFile): """Representation of an Crypto configuration file.""" - _path_in_tree = 'tf-psa-crypto/include/psa/crypto_config.h' + # Temporary, while Mbed TLS does not just rely on the TF-PSA-Crypto + # build system to build its crypto library. When it does, the + # condition can just be removed. + _path_in_tree = 'include/psa/crypto_config.h' \ + if os.path.isfile('include/psa/crypto_config.h') else \ + 'tf-psa-crypto/include/psa/crypto_config.h' default_path = [_path_in_tree, os.path.join(os.path.dirname(__file__), os.pardir, From 4706fe7f03469719c461ac7ce2447e8def4f5e97 Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Mon, 8 Jul 2024 17:00:55 +0200 Subject: [PATCH 18/20] Update documentation and comments Signed-off-by: Gabor Mezei --- scripts/config.py | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/scripts/config.py b/scripts/config.py index c5a5495eb4..491a43a03e 100755 --- a/scripts/config.py +++ b/scripts/config.py @@ -452,6 +452,7 @@ class ConfigFile(metaclass=ABCMeta): """Parse a line in the config file, save the templates representing the lines and return the corresponding setting element. """ + line = line.rstrip('\r\n') m = re.match(self._config_line_regexp, line) if m is None: @@ -483,6 +484,7 @@ class ConfigFile(metaclass=ABCMeta): def parse_file(self): """Parse the whole file and return the settings.""" + with open(self.filename, 'r', encoding='utf-8') as file: for line in file: setting = self._parse_line(line) @@ -492,11 +494,12 @@ class ConfigFile(metaclass=ABCMeta): #pylint: disable=no-self-use def _format_template(self, setting, indent, middle): - """Build a line for mbedtls_config.h for the given setting. + """Build a line for the config file for the given setting. The line has the form "#define " where is "#define ". """ + value = setting.value if value is None: value = '' @@ -516,6 +519,7 @@ class ConfigFile(metaclass=ABCMeta): def write_to_stream(self, settings, output): """Write the whole configuration to output.""" + for template in self.templates: if isinstance(template, str): line = template @@ -529,6 +533,7 @@ class ConfigFile(metaclass=ABCMeta): If filename is specified, write to this file instead. """ + if filename is None: filename = self.filename @@ -555,7 +560,7 @@ class MbedTLSConfigFile(ConfigFile): self.current_section = 'header' class CryptoConfigFile(ConfigFile): - """Representation of an Crypto configuration file.""" + """Representation of a Crypto configuration file.""" # Temporary, while Mbed TLS does not just rely on the TF-PSA-Crypto # build system to build its crypto library. When it does, the @@ -579,8 +584,10 @@ class MbedTLSConfig(Config): See the documentation of the `Config` class for methods to query and modify the configuration. """ + def __init__(self, filename=None): """Read the Mbed TLS configuration file.""" + super().__init__() self.configfile = MbedTLSConfigFile(filename) self.settings.update({name: Setting(active, name, value, section, self.configfile) @@ -588,6 +595,8 @@ class MbedTLSConfig(Config): in self.configfile.parse_file()}) def set(self, name, value=None): + """Set name to the given value and make it active.""" + if name not in self.settings: self.configfile.templates.append((name, '', '#define ' + name + ' ')) @@ -598,9 +607,12 @@ class MbedTLSConfig(Config): If filename is specified, write to this file instead. """ + self.configfile.write(self.settings, filename) def filename(self): + """Get the name of the config file.""" + return self.configfile.filename class CryptoConfig(Config): @@ -609,8 +621,10 @@ class CryptoConfig(Config): See the documentation of the `Config` class for methods to query and modify the configuration. """ + def __init__(self, filename=None): """Read the PSA crypto configuration file.""" + super().__init__() self.configfile = CryptoConfigFile(filename) self.settings.update({name: Setting(active, name, value, section, self.configfile) @@ -618,12 +632,14 @@ class CryptoConfig(Config): in self.configfile.parse_file()}) def set(self, name, value='1'): + """Set name to the given value and make it active.""" + if name in PSA_UNSUPPORTED_FEATURE: raise ValueError(f'Feature is unsupported: \'{name}\'') if name in PSA_UNSTABLE_FEATURE: raise ValueError(f'Feature is unstable: \'{name}\'') - # The default value in the crypto config is '1' + # If value is set to None correct it if not value: value = '1' @@ -637,9 +653,12 @@ class CryptoConfig(Config): If filename is specified, write to this file instead. """ + self.configfile.write(self.settings, filename) def filename(self): + """Get the name of the config file.""" + return self.configfile.filename class CombinedConfig(Config): @@ -665,8 +684,8 @@ class CombinedConfig(Config): _crypto_regexp = re.compile(r'$PSA_.*') def _get_configfile(self, name): - """Find a config type for a setting name - """ + """Find a config type for a setting name""" + if name in self.settings: return self.settings[name].configfile elif re.match(self._crypto_regexp, name): @@ -679,6 +698,8 @@ class CombinedConfig(Config): self.settings[name].configfile.modified = True def set(self, name, value=None): + """Set name to the given value and make it active.""" + configfile = self._get_configfile(name) if configfile == self.crypto_configfile: @@ -707,10 +728,16 @@ class CombinedConfig(Config): If mbedtls_file or crypto_file is specified, write the specific configuration to the corresponding file instead. """ + self.mbedtls_configfile.write(self.settings, mbedtls_file) self.crypto_configfile.write(self.settings, crypto_file) def filename(self, name=None): + """Get the names of the config files. + + If 'name' is specified return the name of the config file where it is defined. + """ + if not name: return [config.filename for config in [self.mbedtls_configfile, self.crypto_configfile]] From 91f1746f354a1d5f243a647b52962721fbee4f91 Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Wed, 17 Jul 2024 12:11:00 +0200 Subject: [PATCH 19/20] Remove sanity check for `None` value Signed-off-by: Gabor Mezei --- scripts/config.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/scripts/config.py b/scripts/config.py index 491a43a03e..150078a695 100755 --- a/scripts/config.py +++ b/scripts/config.py @@ -639,10 +639,6 @@ class CryptoConfig(Config): if name in PSA_UNSTABLE_FEATURE: raise ValueError(f'Feature is unstable: \'{name}\'') - # If value is set to None correct it - if not value: - value = '1' - if name not in self.settings: self.configfile.templates.append((name, '', '#define ' + name + ' ')) From 89e0901826899fbc78c9adef62a0965003094ff2 Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Thu, 25 Jul 2024 11:01:14 +0200 Subject: [PATCH 20/20] Update framework Signed-off-by: Gabor Mezei --- framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework b/framework index e8b4ae9bc4..331565b041 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit e8b4ae9bc4bf7e643ee46bf8ff4ef613be2de86f +Subproject commit 331565b041f794df2da76394b3b0039abce30355