mirror of
https://github.com/yuzu-emu/mbedtls.git
synced 2024-12-25 01:05:41 +00:00
Refactor handlibg of the key usage flags
Move implicit usage flags handling to the StorageKey class. Create a subclass for test case data. Signed-off-by: gabor-mezei-arm <gabor.mezei@arm.com>
This commit is contained in:
parent
61739e3fd3
commit
e4b7499f74
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
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,
|
||||
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,
|
||||
implicit_usage=True)
|
||||
description=description)
|
||||
yield key1
|
||||
|
||||
if test_implicit_usage:
|
||||
description = 'usage without implication' + ': ' + short
|
||||
yield StorageKey(version=self.version,
|
||||
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,
|
||||
implicit_usage=False)
|
||||
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,
|
||||
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,
|
||||
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 StorageKey(version=self.version,
|
||||
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,
|
||||
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,
|
||||
implicit_usage=False)
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue