PSA test case generation: operation fail: simplify NOT_SUPPORTED

In `generate_psa_tests.py, `OpFail.make_test_case()` is only ever used with
a single mechanism being not supported. Take advantage of that to simplify
parts of the function. Call `psa_test_case.TestCase.assumes_not_supported()`
instead of partly reinventing that wheel.

No change to the generated output.

Signed-off-by: Gilles Peskine <[email protected]>
This commit is contained in:
Gilles Peskine
2025-01-09 18:24:59 +01:00
parent bc6f8ac304
commit 78e4c8a73b
2 changed files with 19 additions and 14 deletions
+13 -14
View File
@@ -11,7 +11,7 @@ generate only the specified files.
import enum import enum
import re import re
import sys import sys
from typing import Callable, Dict, FrozenSet, Iterable, Iterator, List, Optional from typing import Callable, Dict, Iterable, Iterator, List, Optional
from mbedtls_framework import crypto_data_tests from mbedtls_framework import crypto_data_tests
from mbedtls_framework import crypto_knowledge from mbedtls_framework import crypto_knowledge
@@ -223,16 +223,19 @@ class OpFail:
category: crypto_knowledge.AlgorithmCategory, category: crypto_knowledge.AlgorithmCategory,
reason: 'Reason', reason: 'Reason',
kt: Optional[crypto_knowledge.KeyType] = None, kt: Optional[crypto_knowledge.KeyType] = None,
not_deps: FrozenSet[str] = frozenset(), not_supported: Optional[str] = None,
) -> test_case.TestCase: ) -> test_case.TestCase:
"""Construct a failure test case for a one-key or keyless operation.""" """Construct a failure test case for a one-key or keyless operation.
If `reason` is `Reason.NOT_SUPPORTED`, pass the not-supported
dependency symbol as the `not_supported` argument.
"""
#pylint: disable=too-many-arguments,too-many-locals #pylint: disable=too-many-arguments,too-many-locals
tc = psa_test_case.TestCase() tc = psa_test_case.TestCase()
pretty_alg = alg.short_expression() pretty_alg = alg.short_expression()
if reason == self.Reason.NOT_SUPPORTED: if reason == self.Reason.NOT_SUPPORTED:
short_deps = [re.sub(r'PSA_WANT_ALG_', r'', dep) assert not_supported is not None
for dep in not_deps] pretty_reason = '!' + re.sub(r'PSA_WANT_[A-Z]+_', r'', not_supported)
pretty_reason = '!' + '&'.join(sorted(short_deps))
else: else:
pretty_reason = reason.name.lower() pretty_reason = reason.name.lower()
if kt: if kt:
@@ -261,12 +264,8 @@ class OpFail:
'INVALID_ARGUMENT') 'INVALID_ARGUMENT')
arguments.append('PSA_ERROR_' + error) arguments.append('PSA_ERROR_' + error)
if reason == self.Reason.NOT_SUPPORTED: if reason == self.Reason.NOT_SUPPORTED:
# It isn't nice that we access the field directly. We should assert not_supported is not None
# call tc.assumes_not_supported() instead, but that requires tc.assumes_not_supported(not_supported)
# further refactoring here because that method assumes a
# mechanism symbol (e.g. PSA_KEY_TYPE_xxx), not a dependency
# symbol (e.g. PSA_WANT_KEY_TYPE_xxx) like we have here.
tc.negated_dependencies.update(not_deps)
tc.set_arguments(arguments) tc.set_arguments(arguments)
return tc return tc
@@ -281,7 +280,7 @@ class OpFail:
for dep in psa_information.automatic_dependencies(alg.base_expression): for dep in psa_information.automatic_dependencies(alg.base_expression):
yield self.make_test_case(alg, category, yield self.make_test_case(alg, category,
self.Reason.NOT_SUPPORTED, self.Reason.NOT_SUPPORTED,
not_deps=frozenset([dep])) not_supported=dep)
else: else:
# Incompatible operation, supported algorithm # Incompatible operation, supported algorithm
yield self.make_test_case(alg, category, self.Reason.INVALID) yield self.make_test_case(alg, category, self.Reason.INVALID)
@@ -299,7 +298,7 @@ class OpFail:
for dep in psa_information.automatic_dependencies(alg.base_expression): for dep in psa_information.automatic_dependencies(alg.base_expression):
yield self.make_test_case(alg, category, yield self.make_test_case(alg, category,
self.Reason.NOT_SUPPORTED, self.Reason.NOT_SUPPORTED,
kt=kt, not_deps=frozenset([dep])) kt=kt, not_supported=dep)
# Public key for a private-key operation # Public key for a private-key operation
if category.is_asymmetric() and kt.is_public(): if category.is_asymmetric() and kt.is_public():
yield self.make_test_case(alg, category, yield self.make_test_case(alg, category,
@@ -118,6 +118,9 @@ class TestCase(test_case.TestCase):
def assumes_not_supported(self, name: str) -> None: def assumes_not_supported(self, name: str) -> None:
"""Negate the given mechanism for automatic dependency generation. """Negate the given mechanism for automatic dependency generation.
`name` can be either a dependency symbol (``PSA_WANT_xxx``) or
a mechanism name (``PSA_KEY_TYPE_xxx``, etc.).
Call this function before set_arguments() for a test case that should Call this function before set_arguments() for a test case that should
run if the given mechanism is not supported. run if the given mechanism is not supported.
@@ -129,6 +132,9 @@ class TestCase(test_case.TestCase):
the key bit-size, this class assumes that only one bit-size is the key bit-size, this class assumes that only one bit-size is
involved in a given test case. involved in a given test case.
""" """
if name.startswith('PSA_WANT_'):
self.negated_dependencies.add(name)
return
if name == 'PSA_KEY_TYPE_RSA_KEY_PAIR' and \ if name == 'PSA_KEY_TYPE_RSA_KEY_PAIR' and \
self.key_bits is not None and \ self.key_bits is not None and \
self.key_pair_usage == ['GENERATE']: self.key_pair_usage == ['GENERATE']: