diff --git a/scripts/mbedtls_dev/psa_storage.py b/scripts/mbedtls_dev/psa_storage.py index 88992a6fc..45f0380e7 100644 --- a/scripts/mbedtls_dev/psa_storage.py +++ b/scripts/mbedtls_dev/psa_storage.py @@ -101,12 +101,6 @@ class Key: LATEST_VERSION = 0 """The latest version of the storage format.""" - IMPLICIT_USAGE_FLAGS = { - 'PSA_KEY_USAGE_SIGN_HASH': 'PSA_KEY_USAGE_SIGN_MESSAGE', - 'PSA_KEY_USAGE_VERIFY_HASH': 'PSA_KEY_USAGE_VERIFY_MESSAGE' - } #type: Dict[str, str] - """Mapping of usage flags to the flags that they imply.""" - def __init__(self, *, version: Optional[int] = None, id: Optional[int] = None, #pylint: disable=redefined-builtin @@ -114,27 +108,18 @@ class Key: type: Exprable, #pylint: disable=redefined-builtin bits: int, usage: Exprable, alg: Exprable, alg2: Exprable, - material: bytes, #pylint: disable=used-before-assignment - implicit_usage: bool = True + material: bytes #pylint: disable=used-before-assignment ) -> None: self.version = self.LATEST_VERSION if version is None else version self.id = id #pylint: disable=invalid-name #type: Optional[int] self.lifetime = as_expr(lifetime) #type: Expr self.type = as_expr(type) #type: Expr self.bits = bits #type: int - self.original_usage = as_expr(usage) #type: Expr - self.updated_usage = self.original_usage #type: Expr + self.usage = as_expr(usage) #type: Expr self.alg = as_expr(alg) #type: Expr self.alg2 = as_expr(alg2) #type: Expr self.material = material #type: bytes - if implicit_usage: - for flag, extension in self.IMPLICIT_USAGE_FLAGS.items(): - if self.original_usage.value() & Expr(flag).value() and \ - self.original_usage.value() & Expr(extension).value() == 0: - self.updated_usage = Expr(self.updated_usage.string + - ' | ' + extension) - MAGIC = b'PSA\000KEY\000' @staticmethod @@ -166,7 +151,7 @@ class Key: if self.version == 0: attributes = self.pack('LHHLLL', self.lifetime, self.type, self.bits, - self.updated_usage, self.alg, self.alg2) + self.usage, self.alg, self.alg2) material = self.pack('L', len(self.material)) + self.material else: raise NotImplementedError diff --git a/tests/scripts/generate_psa_tests.py b/tests/scripts/generate_psa_tests.py index e7b373181..469f14b53 100755 --- a/tests/scripts/generate_psa_tests.py +++ b/tests/scripts/generate_psa_tests.py @@ -227,24 +227,50 @@ class NotSupported: class StorageKey(psa_storage.Key): """Representation of a key for storage format testing.""" + IMPLICIT_USAGE_FLAGS = { + 'PSA_KEY_USAGE_SIGN_HASH': 'PSA_KEY_USAGE_SIGN_MESSAGE', + 'PSA_KEY_USAGE_VERIFY_HASH': 'PSA_KEY_USAGE_VERIFY_MESSAGE' + } #type: Dict[str, str] + """Mapping of usage flags to the flags that they imply.""" + + def __init__( + self, + usage: str, + without_implicit_usage: Optional[bool] = False, + **kwargs + ) -> None: + """Prepare to generate a key. + + * `usage` : The usage flags used for the key. + * `without_implicit_usage`: Flag to defide to apply the usage extension + """ + super().__init__(usage=usage,**kwargs) + + if not without_implicit_usage: + for flag, implicit in self.IMPLICIT_USAGE_FLAGS.items(): + if self.usage.value() & psa_storage.Expr(flag).value() and \ + self.usage.value() & psa_storage.Expr(implicit).value() == 0: + self.usage = psa_storage.Expr(self.usage.string + ' | ' + implicit) + +class StorageTestData(StorageKey): + """Representation of test case data for storage format testing.""" + def __init__( self, description: str, expected_usage: Optional[str] = None, **kwargs ) -> None: - """Prepare to generate a key. + """Prepare to generate test data - * `description`: used for the the test case names - * `implicit_usage`: the usage flags generated as the expected usage - flags in the test cases. When testing implicit - usage flags, they can differ in the generated keys - and the expected usage flags in the test cases. + * `description` : used for the the test case names + * `expected_usage`: the usage flags generated as the expected usage flags + in the test cases. CAn differ from the usage flags + stored in the keys because of the usage flags extension. """ super().__init__(**kwargs) self.description = description #type: str - self.usage = psa_storage.as_expr(expected_usage) if expected_usage is not None else\ - self.original_usage #type: psa_storage.Expr + self.expected_usage = expected_usage if expected_usage else self.usage.string #type: str class StorageFormat: """Storage format stability test cases.""" @@ -263,7 +289,7 @@ class StorageFormat: self.version = version #type: int self.forward = forward #type: bool - def make_test_case(self, key: StorageKey) -> test_case.TestCase: + def make_test_case(self, key: StorageTestData) -> test_case.TestCase: """Construct a storage format test case for the given key. If ``forward`` is true, generate a forward compatibility test case: @@ -277,7 +303,7 @@ class StorageFormat: tc.set_description('PSA storage {}: {}'.format(verb, key.description)) dependencies = automatic_dependencies( key.lifetime.string, key.type.string, - key.usage.string, key.alg.string, key.alg2.string, + key.expected_usage, key.alg.string, key.alg2.string, ) dependencies = finish_family_dependencies(dependencies, key.bits) tc.set_dependencies(dependencies) @@ -298,7 +324,7 @@ class StorageFormat: extra_arguments = [' | '.join(flags) if flags else '0'] tc.set_arguments([key.lifetime.string, key.type.string, str(key.bits), - key.usage.string, key.alg.string, key.alg2.string, + key.expected_usage, key.alg.string, key.alg2.string, '"' + key.material.hex() + '"', '"' + key.hex() + '"', *extra_arguments]) @@ -307,21 +333,22 @@ class StorageFormat: def key_for_lifetime( self, lifetime: str, - ) -> StorageKey: + ) -> StorageTestData: """Construct a test key for the given lifetime.""" 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) description = 'lifetime: ' + short - return StorageKey(version=self.version, - id=1, lifetime=lifetime, - type='PSA_KEY_TYPE_RAW_DATA', bits=8, - usage='PSA_KEY_USAGE_EXPORT', alg=0, alg2=0, - material=b'L', - description=description) + key = StorageTestData(version=self.version, + id=1, lifetime=lifetime, + type='PSA_KEY_TYPE_RAW_DATA', bits=8, + usage='PSA_KEY_USAGE_EXPORT', alg=0, alg2=0, + material=b'L', + description=description) + return key - def all_keys_for_lifetimes(self) -> Iterator[StorageKey]: + def all_keys_for_lifetimes(self) -> Iterator[StorageTestData]: """Generate test keys covering lifetimes.""" lifetimes = sorted(self.constructors.lifetimes) expressions = self.constructors.generate_expressions(lifetimes) @@ -340,32 +367,34 @@ class StorageFormat: usage_flags: List[str], short: Optional[str] = None, test_implicit_usage: Optional[bool] = False - ) -> Iterator[StorageKey]: + ) -> Iterator[StorageTestData]: """Construct a test key for the given key usage.""" usage = ' | '.join(usage_flags) if usage_flags else '0' if short is None: short = re.sub(r'\bPSA_KEY_USAGE_', r'', usage) extra_desc = ' with implication' if test_implicit_usage else '' description = 'usage' + extra_desc + ': ' + short - yield StorageKey(version=self.version, - id=1, lifetime=0x00000001, - type='PSA_KEY_TYPE_RAW_DATA', bits=8, - usage=usage, alg=0, alg2=0, - material=b'K', - description=description, - implicit_usage=True) + key1 = StorageTestData(version=self.version, + id=1, lifetime=0x00000001, + type='PSA_KEY_TYPE_RAW_DATA', bits=8, + expected_usage=usage, + usage=usage, alg=0, alg2=0, + material=b'K', + description=description) + yield key1 + if test_implicit_usage: description = 'usage without implication' + ': ' + short - yield StorageKey(version=self.version, - id=1, lifetime=0x00000001, - type='PSA_KEY_TYPE_RAW_DATA', bits=8, - usage=usage, alg=0, alg2=0, - material=b'K', - description=description, - implicit_usage=False) + key2 = StorageTestData(version=self.version, + id=1, lifetime=0x00000001, + type='PSA_KEY_TYPE_RAW_DATA', bits=8, + without_implicit_usage=True, + usage=usage, alg=0, alg2=0, + material=b'K', + description=description) + yield key2 - - def generate_keys_for_usage_flags(self, **kwargs) -> Iterator[StorageKey]: + def generate_keys_for_usage_flags(self, **kwargs) -> Iterator[StorageTestData]: """Generate test keys covering usage flags.""" known_flags = sorted(self.constructors.key_usage_flags) yield from self.key_for_usage_flags(['0'], **kwargs) @@ -375,11 +404,11 @@ class StorageFormat: known_flags[1:] + [known_flags[0]]): yield from self.key_for_usage_flags([flag1, flag2], **kwargs) - def generate_key_for_all_usage_flags(self) -> Iterator[StorageKey]: + def generate_key_for_all_usage_flags(self) -> Iterator[StorageTestData]: known_flags = sorted(self.constructors.key_usage_flags) yield from self.key_for_usage_flags(known_flags, short='all known') - def all_keys_for_usage_flags(self) -> Iterator[StorageKey]: + def all_keys_for_usage_flags(self) -> Iterator[StorageTestData]: yield from self.generate_keys_for_usage_flags() yield from self.generate_key_for_all_usage_flags() @@ -387,7 +416,7 @@ class StorageFormat: self, key_type: str, params: Optional[Iterable[str]] = None - ) -> Iterator[StorageKey]: + ) -> Iterator[StorageTestData]: """Generate test keys for the given key type. For key types that depend on a parameter (e.g. elliptic curve family), @@ -404,20 +433,21 @@ class StorageFormat: r'', kt.expression) description = 'type: {} {}-bit'.format(short_expression, bits) - yield StorageKey(version=self.version, - id=1, lifetime=0x00000001, - type=kt.expression, bits=bits, - usage=usage_flags, alg=alg, alg2=alg2, - material=key_material, - description=description) + key = StorageTestData(version=self.version, + id=1, lifetime=0x00000001, + type=kt.expression, bits=bits, + usage=usage_flags, alg=alg, alg2=alg2, + material=key_material, + description=description) + yield key - def all_keys_for_types(self) -> Iterator[StorageKey]: + def all_keys_for_types(self) -> Iterator[StorageTestData]: """Generate test keys covering key types and their representations.""" 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) - def keys_for_algorithm(self, alg: str) -> Iterator[StorageKey]: + def keys_for_algorithm(self, alg: str) -> Iterator[StorageTestData]: """Generate test keys for the specified algorithm.""" # For now, we don't have information on the compatibility of key # types and algorithms. So we just test the encoding of algorithms, @@ -425,28 +455,30 @@ class StorageFormat: descr = re.sub(r'PSA_ALG_', r'', alg) descr = re.sub(r',', r', ', re.sub(r' +', r'', descr)) usage = 'PSA_KEY_USAGE_EXPORT' - yield StorageKey(version=self.version, - id=1, lifetime=0x00000001, - type='PSA_KEY_TYPE_RAW_DATA', bits=8, - usage=usage, alg=alg, alg2=0, - material=b'K', - description='alg: ' + descr) - yield StorageKey(version=self.version, - id=1, lifetime=0x00000001, - type='PSA_KEY_TYPE_RAW_DATA', bits=8, - usage=usage, alg=0, alg2=alg, - material=b'L', - description='alg2: ' + descr) + key1 = StorageTestData(version=self.version, + id=1, lifetime=0x00000001, + type='PSA_KEY_TYPE_RAW_DATA', bits=8, + usage=usage, alg=alg, alg2=0, + material=b'K', + description='alg: ' + descr) + yield key1 + key2 = StorageTestData(version=self.version, + id=1, lifetime=0x00000001, + type='PSA_KEY_TYPE_RAW_DATA', bits=8, + usage=usage, alg=0, alg2=alg, + material=b'L', + description='alg2: ' + descr) + yield key2 - def all_keys_for_algorithms(self) -> Iterator[StorageKey]: + def all_keys_for_algorithms(self) -> Iterator[StorageTestData]: """Generate test keys covering algorithm encodings.""" algorithms = sorted(self.constructors.algorithms) for alg in self.constructors.generate_expressions(algorithms): yield from self.keys_for_algorithm(alg) - def generate_all_keys(self) -> List[StorageKey]: + def generate_all_keys(self) -> List[StorageTestData]: """Generate all keys for the test cases.""" - keys = [] #type: List[StorageKey] + keys = [] #type: List[StorageTestData] keys += self.all_keys_for_lifetimes() keys += self.all_keys_for_usage_flags() keys += self.all_keys_for_types() @@ -479,7 +511,7 @@ class StorageFormatV0(StorageFormat): def __init__(self, info: Information) -> None: super().__init__(info, 0, False) - def all_keys_for_usage_flags(self) -> Iterator[StorageKey]: + def all_keys_for_usage_flags(self) -> Iterator[StorageTestData]: """Generate test keys covering usage flags.""" yield from self.generate_keys_for_usage_flags(test_implicit_usage=True) yield from self.generate_key_for_all_usage_flags() @@ -489,7 +521,7 @@ class StorageFormatV0(StorageFormat): implyer_usage: str, alg: str, key_type: crypto_knowledge.KeyType - ) -> StorageKey: + ) -> StorageTestData: # pylint: disable=too-many-locals """Generate test keys for the specified implicit usage flag, algorithm and key type combination. @@ -509,15 +541,16 @@ class StorageFormatV0(StorageFormat): key_type.expression) description = 'implied by {}: {} {} {}-bit'.format( usage_expression, alg_expression, key_type_expression, bits) - return StorageKey(version=self.version, - id=1, lifetime=0x00000001, - type=key_type.expression, bits=bits, - usage=material_usage_flags, - expected_usage=expected_usage_flags, - alg=alg, alg2=alg2, - material=key_material, - description=description, - implicit_usage=False) + key = StorageTestData(version=self.version, + id=1, lifetime=0x00000001, + type=key_type.expression, bits=bits, + usage=material_usage_flags, + expected_usage=expected_usage_flags, + without_implicit_usage=True, + alg=alg, alg2=alg2, + material=key_material, + description=description) + return key def gather_key_types_for_sign_alg(self) -> Dict[str, List[str]]: # pylint: disable=too-many-locals @@ -567,7 +600,7 @@ class StorageFormatV0(StorageFormat): alg_with_keys[alg] = [key_type] return alg_with_keys - def all_keys_for_implicit_usage(self) -> Iterator[StorageKey]: + def all_keys_for_implicit_usage(self) -> Iterator[StorageTestData]: """Generate test keys for usage flag extensions.""" # Generate a key type and algorithm pair for each extendable usage # flag to generate a valid key for exercising. The key is generated @@ -582,7 +615,7 @@ class StorageFormatV0(StorageFormat): if kt.is_valid_for_signature(usage): yield self.keys_for_implicit_usage(usage, alg, kt) - def generate_all_keys(self) -> List[StorageKey]: + def generate_all_keys(self) -> List[StorageTestData]: keys = super().generate_all_keys() keys += self.all_keys_for_implicit_usage() return keys