Merge pull request #5092 from mprse/generate_key2

Generate test cases for PSA key generation
This commit is contained in:
Gilles Peskine 2021-11-10 20:55:35 +01:00 committed by GitHub
commit f1a7ea88d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 131 additions and 57 deletions

View file

@ -83,8 +83,6 @@ class TestCase:
out.write('depends_on:' + ':'.join(self.dependencies) + '\n')
out.write(self.function + ':' + ':'.join(self.arguments) + '\n')
def write_data_file(filename: str,
test_cases: Iterable[TestCase],
caller: Optional[str] = None) -> None:

View file

@ -96,7 +96,7 @@ def hack_dependencies_not_implemented(dependencies: List[str]) -> None:
if _implemented_dependencies is None:
_implemented_dependencies = \
read_implemented_dependencies('include/psa/crypto_config.h')
if not all(dep.lstrip('!') in _implemented_dependencies
if not all((dep.lstrip('!') in _implemented_dependencies or 'PSA_WANT' not in dep)
for dep in dependencies):
dependencies.append('DEPENDENCY_NOT_IMPLEMENTED_YET')
@ -155,30 +155,8 @@ def test_case_for_key_type_not_supported(
tc.set_arguments([key_type] + list(args))
return tc
def test_case_for_key_type_invalid_argument(
verb: str, key_type: str, bits: int,
dependencies: List[str],
*args: str,
param_descr: str = ''
) -> test_case.TestCase:
"""Return one test case exercising a key creation method
for an invalid argument when key is public.
"""
hack_dependencies_not_implemented(dependencies)
tc = test_case.TestCase()
short_key_type = re.sub(r'PSA_(KEY_TYPE|ECC_FAMILY)_', r'', key_type)
adverb = 'not' if dependencies else 'never'
if param_descr:
adverb = param_descr + ' ' + adverb
tc.set_description('PSA {} {} {}-bit invalid argument'
.format(verb, short_key_type, bits))
tc.set_function(verb + '_invalid_argument')
tc.set_dependencies(dependencies)
tc.set_arguments([key_type] + list(args))
return tc
class NotSupported:
"""Generate test cases for when something is not supported or argument is inavlid."""
"""Generate test cases for when something is not supported."""
def __init__(self, info: Information) -> None:
self.constructors = info.constructors
@ -193,13 +171,11 @@ class NotSupported:
param: Optional[int] = None,
param_descr: str = '',
) -> Iterator[test_case.TestCase]:
"""Return test cases exercising key creation when the given type is unsupported
or argument is invalid.
"""Return test cases exercising key creation when the given type is unsupported.
If param is present and not None, emit test cases conditioned on this
parameter not being supported. If it is absent or None, emit test cases
conditioned on the base type not being supported. If key is public emit test
case for invalid argument.
conditioned on the base type not being supported.
"""
if kt.name in self.ALWAYS_SUPPORTED:
# Don't generate test cases for key types that are always supported.
@ -227,14 +203,9 @@ class NotSupported:
# supported or not depending on implementation capabilities,
# only generate the test case once.
continue
if kt.name.endswith('_PUBLIC_KEY'):
yield test_case_for_key_type_invalid_argument(
'generate', kt.expression, bits,
finish_family_dependencies(generate_dependencies, bits),
str(bits),
param_descr=param_descr,
)
else:
# For public key we expect that key generation fails with
# INVALID_ARGUMENT. It is handled by KeyGenerate class.
if not kt.name.endswith('_PUBLIC_KEY'):
yield test_case_for_key_type_not_supported(
'generate', kt.expression, bits,
finish_family_dependencies(generate_dependencies, bits),
@ -261,6 +232,79 @@ class NotSupported:
yield from self.test_cases_for_key_type_not_supported(
kt, 0, param_descr='curve')
def test_case_for_key_generation(
key_type: str, bits: int,
dependencies: List[str],
*args: str,
result: str = ''
) -> test_case.TestCase:
"""Return one test case exercising a 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)
tc.set_description('PSA {} {}-bit'
.format(short_key_type, bits))
tc.set_dependencies(dependencies)
tc.set_function('generate_key')
tc.set_arguments([key_type] + list(args) + [result])
return tc
class KeyGenerate:
"""Generate positive and negative (invalid argument) test cases for key generation."""
def __init__(self, info: Information) -> None:
self.constructors = info.constructors
ECC_KEY_TYPES = ('PSA_KEY_TYPE_ECC_KEY_PAIR',
'PSA_KEY_TYPE_ECC_PUBLIC_KEY')
@staticmethod
def test_cases_for_key_type_key_generation(
kt: crypto_knowledge.KeyType
) -> Iterator[test_case.TestCase]:
"""Return test cases exercising key generation.
All key types can be generated except for public keys. For public key
PSA_ERROR_INVALID_ARGUMENT status is expected.
"""
result = 'PSA_SUCCESS'
import_dependencies = [psa_want_symbol(kt.name)]
if kt.params is not None:
import_dependencies += [psa_want_symbol(sym)
for i, sym in enumerate(kt.params)]
if kt.name.endswith('_PUBLIC_KEY'):
# The library checks whether the key type is a public key generically,
# before it reaches a point where it needs support for the specific key
# type, so it returns INVALID_ARGUMENT for unsupported public key types.
generate_dependencies = []
result = 'PSA_ERROR_INVALID_ARGUMENT'
else:
generate_dependencies = import_dependencies
if kt.name == 'PSA_KEY_TYPE_RSA_KEY_PAIR':
generate_dependencies.append("MBEDTLS_GENPRIME")
for bits in kt.sizes_to_test():
yield test_case_for_key_generation(
kt.expression, bits,
finish_family_dependencies(generate_dependencies, bits),
str(bits),
result
)
def test_cases_for_key_generation(self) -> Iterator[test_case.TestCase]:
"""Generate test cases that exercise the generation of keys."""
for key_type in sorted(self.constructors.key_types):
if key_type in self.ECC_KEY_TYPES:
continue
kt = crypto_knowledge.KeyType(key_type)
yield from self.test_cases_for_key_type_key_generation(kt)
for curve_family in sorted(self.constructors.ecc_curves):
for constr in self.ECC_KEY_TYPES:
kt = crypto_knowledge.KeyType(constr, [curve_family])
yield from self.test_cases_for_key_type_key_generation(kt)
class StorageKey(psa_storage.Key):
"""Representation of a key for storage format testing."""
@ -682,6 +726,8 @@ class TestGenerator:
test_case.write_data_file(filename, test_cases)
TARGETS = {
'test_suite_psa_crypto_generate_key.generated':
lambda info: KeyGenerate(info).test_cases_for_key_generation(),
'test_suite_psa_crypto_not_supported.generated':
lambda info: NotSupported(info).test_cases_for_not_supported(),
'test_suite_psa_crypto_storage_format.current':

View file

@ -0,0 +1,49 @@
/* BEGIN_HEADER */
#include "psa/crypto.h"
#include "test/psa_crypto_helpers.h"
#define INVALID_KEY_ID mbedtls_svc_key_id_make( 0, 0xfedcba98 )
/* END_HEADER */
/* BEGIN_DEPENDENCIES
* depends_on:MBEDTLS_PSA_CRYPTO_C
* END_DEPENDENCIES
*/
/* BEGIN_CASE */
void generate_key( int key_type_arg, int bits_arg, int expected_status_arg)
{
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
mbedtls_svc_key_id_t key_id = INVALID_KEY_ID;
// key lifetiem, usage flags, algorithm are irrelevant for this test
psa_key_type_t key_type = key_type_arg;
size_t bits = bits_arg;
psa_status_t expected_status = expected_status_arg;
PSA_ASSERT( psa_crypto_init( ) );
psa_set_key_type( &attributes, key_type );
psa_set_key_bits( &attributes, bits );
TEST_EQUAL( psa_generate_key( &attributes, &key_id ),
expected_status );
// Verify attributes of the created key on success
if ( expected_status == PSA_SUCCESS )
{
psa_reset_key_attributes(&attributes);
PSA_ASSERT( psa_get_key_attributes( key_id, &attributes ) );
TEST_EQUAL( psa_get_key_lifetime( &attributes ), PSA_KEY_LIFETIME_VOLATILE );
TEST_EQUAL( psa_get_key_usage_flags( &attributes ), 0 );
TEST_EQUAL( psa_get_key_algorithm( &attributes ), 0 );
TEST_EQUAL( psa_get_key_type( &attributes ), key_type );
TEST_EQUAL( psa_get_key_bits( &attributes ), bits );
}
exit:
psa_reset_key_attributes(&attributes);
psa_destroy_key( key_id );
PSA_DONE( );
}
/* END_CASE */

View file

@ -50,22 +50,3 @@ exit:
PSA_DONE( );
}
/* END_CASE */
/* BEGIN_CASE */
void generate_invalid_argument( int key_type, int bits )
{
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
mbedtls_svc_key_id_t key_id = INVALID_KEY_ID;
PSA_ASSERT( psa_crypto_init( ) );
psa_set_key_type( &attributes, key_type );
psa_set_key_bits( &attributes, bits );
TEST_EQUAL( psa_generate_key( &attributes, &key_id ),
PSA_ERROR_INVALID_ARGUMENT );
TEST_ASSERT( mbedtls_svc_key_id_equal( key_id, MBEDTLS_SVC_KEY_ID_INIT ) );
exit:
psa_destroy_key( key_id );
PSA_DONE( );
}
/* END_CASE */