Expand psa_generate_tests to support constructor arguments

In macro_collector.py, base InputsForTest on PSAMacroEnumerator rather
than PSAMacroCollector. It didn't make much sense to use
PSAMacroCollector anymore since InputsForTest didn't use anything
other than the constructor.

psa_generate_tests now generates arguments for more macros.
In particular, it now collects macro arguments from
test_suite_psa_crypto_metadata. Algorithms with parameters are now
supported.

Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
This commit is contained in:
Gilles Peskine 2021-04-19 13:50:25 +02:00
parent ae9f14b159
commit b93f854f4c
4 changed files with 2835 additions and 146 deletions

View File

@ -105,6 +105,16 @@ class PSAMacroEnumerator:
'tag_length': [], 'tag_length': [],
'min_tag_length': [], 'min_tag_length': [],
} #type: Dict[str, List[str]] } #type: Dict[str, List[str]]
self.include_intermediate = False
def is_internal_name(self, name: str) -> bool:
"""Whether this is an internal macro. Internal macros will be skipped."""
if not self.include_intermediate:
if name.endswith('_BASE') or name.endswith('_NONE'):
return True
if '_CATEGORY_' in name:
return True
return name.endswith('_FLAG') or name.endswith('_MASK')
def gather_arguments(self) -> None: def gather_arguments(self) -> None:
"""Populate the list of values for macro arguments. """Populate the list of values for macro arguments.
@ -192,15 +202,6 @@ class PSAMacroCollector(PSAMacroEnumerator):
self.key_types_from_group = {} #type: Dict[str, str] self.key_types_from_group = {} #type: Dict[str, str]
self.algorithms_from_hash = {} #type: Dict[str, str] self.algorithms_from_hash = {} #type: Dict[str, str]
def is_internal_name(self, name: str) -> bool:
"""Whether this is an internal macro. Internal macros will be skipped."""
if not self.include_intermediate:
if name.endswith('_BASE') or name.endswith('_NONE'):
return True
if '_CATEGORY_' in name:
return True
return name.endswith('_FLAG') or name.endswith('_MASK')
def record_algorithm_subtype(self, name: str, expansion: str) -> None: def record_algorithm_subtype(self, name: str, expansion: str) -> None:
"""Record the subtype of an algorithm constructor. """Record the subtype of an algorithm constructor.
@ -301,7 +302,7 @@ class PSAMacroCollector(PSAMacroEnumerator):
self.read_line(line) self.read_line(line)
class InputsForTest(PSAMacroCollector): class InputsForTest(PSAMacroEnumerator):
# pylint: disable=too-many-instance-attributes # pylint: disable=too-many-instance-attributes
"""Accumulate information about macros to test. """Accumulate information about macros to test.
enumerate enumerate
@ -408,7 +409,8 @@ enumerate
name = m.group(1) name = m.group(1)
self.all_declared.add(name) self.all_declared.add(name)
if re.search(self._excluded_name_re, name) or \ if re.search(self._excluded_name_re, name) or \
name in self._excluded_names: name in self._excluded_names or \
self.is_internal_name(name):
return return
dest = self.table_by_prefix.get(m.group(2)) dest = self.table_by_prefix.get(m.group(2))
if dest is None: if dest is None:

View File

@ -94,23 +94,25 @@ class Information:
@staticmethod @staticmethod
def remove_unwanted_macros( def remove_unwanted_macros(
constructors: macro_collector.PSAMacroCollector constructors: macro_collector.PSAMacroEnumerator
) -> None: ) -> None:
# Mbed TLS doesn't support DSA. Don't attempt to generate any related # Mbed TLS doesn't support finite-field DH yet and will not support
# test case. # finite-field DSA. Don't attempt to generate any related test case.
constructors.key_types.discard('PSA_KEY_TYPE_DH_KEY_PAIR')
constructors.key_types.discard('PSA_KEY_TYPE_DH_PUBLIC_KEY')
constructors.key_types.discard('PSA_KEY_TYPE_DSA_KEY_PAIR') constructors.key_types.discard('PSA_KEY_TYPE_DSA_KEY_PAIR')
constructors.key_types.discard('PSA_KEY_TYPE_DSA_PUBLIC_KEY') constructors.key_types.discard('PSA_KEY_TYPE_DSA_PUBLIC_KEY')
constructors.algorithms_from_hash.pop('PSA_ALG_DSA', None)
constructors.algorithms_from_hash.pop('PSA_ALG_DETERMINISTIC_DSA', None)
def read_psa_interface(self) -> macro_collector.PSAMacroCollector: def read_psa_interface(self) -> macro_collector.PSAMacroEnumerator:
"""Return the list of known key types, algorithms, etc.""" """Return the list of known key types, algorithms, etc."""
constructors = macro_collector.InputsForTest() constructors = macro_collector.InputsForTest()
header_file_names = ['include/psa/crypto_values.h', header_file_names = ['include/psa/crypto_values.h',
'include/psa/crypto_extra.h'] 'include/psa/crypto_extra.h']
test_suites = ['tests/suites/test_suite_psa_crypto_metadata.data']
for header_file_name in header_file_names: for header_file_name in header_file_names:
with open(header_file_name, 'rb') as header_file: constructors.parse_header(header_file_name)
constructors.read_file(header_file) for test_cases in test_suites:
constructors.parse_test_cases(test_cases)
self.remove_unwanted_macros(constructors) self.remove_unwanted_macros(constructors)
constructors.gather_arguments() constructors.gather_arguments()
return constructors return constructors
@ -194,14 +196,18 @@ class NotSupported:
) )
# To be added: derive # To be added: derive
ECC_KEY_TYPES = ('PSA_KEY_TYPE_ECC_KEY_PAIR',
'PSA_KEY_TYPE_ECC_PUBLIC_KEY')
def test_cases_for_not_supported(self) -> Iterator[test_case.TestCase]: def test_cases_for_not_supported(self) -> Iterator[test_case.TestCase]:
"""Generate test cases that exercise the creation of keys of unsupported types.""" """Generate test cases that exercise the creation of keys of unsupported types."""
for key_type in sorted(self.constructors.key_types): for key_type in sorted(self.constructors.key_types):
if key_type in self.ECC_KEY_TYPES:
continue
kt = crypto_knowledge.KeyType(key_type) kt = crypto_knowledge.KeyType(key_type)
yield from self.test_cases_for_key_type_not_supported(kt) yield from self.test_cases_for_key_type_not_supported(kt)
for curve_family in sorted(self.constructors.ecc_curves): for curve_family in sorted(self.constructors.ecc_curves):
for constr in ('PSA_KEY_TYPE_ECC_KEY_PAIR', for constr in self.ECC_KEY_TYPES:
'PSA_KEY_TYPE_ECC_PUBLIC_KEY'):
kt = crypto_knowledge.KeyType(constr, [curve_family]) kt = crypto_knowledge.KeyType(constr, [curve_family])
yield from self.test_cases_for_key_type_not_supported( yield from self.test_cases_for_key_type_not_supported(
kt, param_descr='type') kt, param_descr='type')
@ -330,16 +336,9 @@ class StorageFormat:
def all_keys_for_types(self) -> Iterator[StorageKey]: def all_keys_for_types(self) -> Iterator[StorageKey]:
"""Generate test keys covering key types and their representations.""" """Generate test keys covering key types and their representations."""
for key_type in sorted(self.constructors.key_types): key_types = sorted(self.constructors.key_types)
for key_type in self.constructors.generate_expressions(key_types):
yield from self.keys_for_type(key_type) yield from self.keys_for_type(key_type)
for key_type in sorted(self.constructors.key_types_from_curve):
for curve in sorted(self.constructors.ecc_curves):
yield from self.keys_for_type(key_type, [curve])
## Diffie-Hellman (FFDH) is not supported yet, either in
## crypto_knowledge.py or in Mbed TLS.
# for key_type in sorted(self.constructors.key_types_from_group):
# for group in sorted(self.constructors.dh_groups):
# yield from self.keys_for_type(key_type, [group])
def keys_for_algorithm(self, alg: str) -> Iterator[StorageKey]: def keys_for_algorithm(self, alg: str) -> Iterator[StorageKey]:
"""Generate test keys for the specified algorithm.""" """Generate test keys for the specified algorithm."""
@ -365,9 +364,9 @@ class StorageFormat:
def all_keys_for_algorithms(self) -> Iterator[StorageKey]: def all_keys_for_algorithms(self) -> Iterator[StorageKey]:
"""Generate test keys covering algorithm encodings.""" """Generate test keys covering algorithm encodings."""
for alg in sorted(self.constructors.algorithms): algorithms = sorted(self.constructors.algorithms)
for alg in self.constructors.generate_expressions(algorithms):
yield from self.keys_for_algorithm(alg) yield from self.keys_for_algorithm(alg)
# To do: algorithm constructors with parameters
def all_test_cases(self) -> Iterator[test_case.TestCase]: def all_test_cases(self) -> Iterator[test_case.TestCase]:
"""Generate all storage format test cases.""" """Generate all storage format test cases."""

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff