diff --git a/scripts/mbedtls_dev/crypto_knowledge.py b/scripts/mbedtls_dev/crypto_knowledge.py index 82487d97f..f2775265c 100644 --- a/scripts/mbedtls_dev/crypto_knowledge.py +++ b/scripts/mbedtls_dev/crypto_knowledge.py @@ -25,6 +25,20 @@ from typing import Iterable, Optional, Tuple from mbedtls_dev.asymmetric_key_data import ASYMMETRIC_KEY_DATA +def short_expression(original: str) -> str: + """Abbreviate the expression, keeping it human-readable. + + If `level` is 0, just remove parts that are implicit from context, + such as a leading ``PSA_KEY_TYPE_``. + For larger values of `level`, also abbreviate some names in an + unambiguous, but ad hoc way. + """ + short = original + short = re.sub(r'\bPSA_(?:ALG|ECC_FAMILY|KEY_[A-Z]+)_', r'', short) + short = re.sub(r' +', r'', short) + return short + + BLOCK_CIPHERS = frozenset(['AES', 'ARIA', 'CAMELLIA', 'DES']) BLOCK_MAC_MODES = frozenset(['CBC_MAC', 'CMAC']) BLOCK_CIPHER_MODES = frozenset([ @@ -104,6 +118,13 @@ class KeyType: `self.name`. """ + def short_expression(self) -> str: + """Abbreviate the expression, keeping it human-readable. + + See `crypto_knowledge.short_expression`. + """ + return short_expression(self.expression) + def is_public(self) -> bool: """Whether the key type is for public keys.""" return self.name.endswith('_PUBLIC_KEY') @@ -376,6 +397,14 @@ class Algorithm: # Assume kdf_alg is either a valid KDF or 0. return not re.match(r'(?:0[Xx])?0+\s*\Z', kdf_alg) + + def short_expression(self) -> str: + """Abbreviate the expression, keeping it human-readable. + + See `crypto_knowledge.short_expression`. + """ + return short_expression(self.expression) + def can_do(self, category: AlgorithmCategory) -> bool: """Whether this algorithm fits the specified operation category.""" if category == self.category: diff --git a/tests/scripts/generate_psa_tests.py b/tests/scripts/generate_psa_tests.py index 4875cf9e5..68cd714f5 100755 --- a/tests/scripts/generate_psa_tests.py +++ b/tests/scripts/generate_psa_tests.py @@ -145,7 +145,7 @@ def test_case_for_key_type_not_supported( """ hack_dependencies_not_implemented(dependencies) tc = test_case.TestCase() - short_key_type = re.sub(r'PSA_(KEY_TYPE|ECC_FAMILY)_', r'', key_type) + short_key_type = crypto_knowledge.short_expression(key_type) adverb = 'not' if dependencies else 'never' if param_descr: adverb = param_descr + ' ' + adverb @@ -243,7 +243,7 @@ def test_case_for_key_generation( """ hack_dependencies_not_implemented(dependencies) tc = test_case.TestCase() - short_key_type = re.sub(r'PSA_(KEY_TYPE|ECC_FAMILY)_', r'', key_type) + short_key_type = crypto_knowledge.short_expression(key_type) tc.set_description('PSA {} {}-bit' .format(short_key_type, bits)) tc.set_dependencies(dependencies) @@ -335,7 +335,7 @@ class OpFail: """Construct a failure test case for a one-key or keyless operation.""" #pylint: disable=too-many-arguments,too-many-locals tc = test_case.TestCase() - pretty_alg = re.sub(r'PSA_ALG_', r'', alg.expression) + pretty_alg = alg.short_expression() if reason == self.Reason.NOT_SUPPORTED: short_deps = [re.sub(r'PSA_WANT_ALG_', r'', dep) for dep in not_deps] @@ -344,7 +344,7 @@ class OpFail: pretty_reason = reason.name.lower() if kt: key_type = kt.expression - pretty_type = re.sub(r'PSA_KEY_TYPE_', r'', key_type) + pretty_type = kt.short_expression() else: key_type = '' pretty_type = '' @@ -568,7 +568,7 @@ class StorageFormat: short = lifetime short = re.sub(r'PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION', r'', short) - short = re.sub(r'PSA_KEY_[A-Z]+_', r'', short) + short = crypto_knowledge.short_expression(short) description = 'lifetime: ' + short key = StorageTestData(version=self.version, id=1, lifetime=lifetime, @@ -610,8 +610,8 @@ class StorageFormat: material=b'K', description=description) if short is None: - key1.description += re.sub(r'\bPSA_KEY_USAGE_', r'', - key1.expected_usage.string) + usage_expr = key1.expected_usage.string + key1.description += crypto_knowledge.short_expression(usage_expr) else: key1.description += short return key1 @@ -648,12 +648,9 @@ class StorageFormat: alg1 = 0 if alg is None else alg.expression #type: psa_storage.Exprable alg2 = 0 key_material = kt.key_material(bits) - short_expression = re.sub(r'\bPSA_(?:KEY_TYPE|ECC_FAMILY)_', - r'', - kt.expression) - description = 'type: {} {}-bit'.format(short_expression, bits) + description = 'type: {} {}-bit'.format(kt.short_expression(), bits) if alg is not None: - description += ', ' + re.sub(r'PSA_ALG_', r'', alg.expression) + description += ', ' + alg.short_expression() key = StorageTestData(version=self.version, id=1, lifetime=0x00000001, type=kt.expression, bits=bits, @@ -696,8 +693,7 @@ class StorageFormat: # whether the key read from storage is suitable for an operation. # `keys_for_types` generate read tests with an algorithm and a # compatible key. - descr = re.sub(r'PSA_ALG_', r'', alg) - descr = re.sub(r',', r', ', re.sub(r' +', r'', descr)) + descr = crypto_knowledge.short_expression(alg) usage = ['PSA_KEY_USAGE_EXPORT'] key1 = StorageTestData(version=self.version, id=1, lifetime=0x00000001, @@ -776,12 +772,9 @@ class StorageFormatV0(StorageFormat): expected_usage_flags = material_usage_flags + [implicit_usage] alg2 = 0 key_material = key_type.key_material(bits) - usage_expression = re.sub(r'PSA_KEY_USAGE_', r'', implyer_usage) - alg_expression = re.sub(r'PSA_ALG_', r'', alg) - alg_expression = re.sub(r',', r', ', re.sub(r' +', r'', alg_expression)) - key_type_expression = re.sub(r'\bPSA_(?:KEY_TYPE|ECC_FAMILY)_', - r'', - key_type.expression) + usage_expression = crypto_knowledge.short_expression(implyer_usage) + alg_expression = crypto_knowledge.short_expression(alg) + key_type_expression = key_type.short_expression() description = 'implied by {}: {} {} {}-bit'.format( usage_expression, alg_expression, key_type_expression, bits) key = StorageTestData(version=self.version,