From efb584d4c0a6c386460e2ff566033ceeda173502 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 21 Apr 2021 22:05:34 +0200 Subject: [PATCH] Add storage tests for lifetimes Test keys with various persistence levels, enumerated from the metadata tests. For read-only keys, do not attempt to create or destroy the key through the API, only to read a key that has been injected into storage directly through filesystem access. Do not test keys with a non-default location, since they require a driver and we do not yet have a dependency mechanism to require the presence of a driver for a specific location value. Signed-off-by: Gilles Peskine --- scripts/mbedtls_dev/psa_storage.py | 4 ++ tests/scripts/generate_psa_tests.py | 39 ++++++++++++++++++- ...ite_psa_crypto_storage_format.current.data | 16 ++++++++ ...t_suite_psa_crypto_storage_format.function | 22 ++++++++--- ...st_suite_psa_crypto_storage_format.v0.data | 20 ++++++++++ 5 files changed, 95 insertions(+), 6 deletions(-) diff --git a/scripts/mbedtls_dev/psa_storage.py b/scripts/mbedtls_dev/psa_storage.py index 3a740072e..45f0380e7 100644 --- a/scripts/mbedtls_dev/psa_storage.py +++ b/scripts/mbedtls_dev/psa_storage.py @@ -164,6 +164,10 @@ class Key: """ return self.bytes().hex() + def location_value(self) -> int: + """The numerical value of the location encoded in the key's lifetime.""" + return self.lifetime.value() >> 8 + class TestKey(unittest.TestCase): # pylint: disable=line-too-long diff --git a/tests/scripts/generate_psa_tests.py b/tests/scripts/generate_psa_tests.py index 6dd85859d..9e3e380a6 100755 --- a/tests/scripts/generate_psa_tests.py +++ b/tests/scripts/generate_psa_tests.py @@ -289,6 +289,38 @@ class StorageFormat: *extra_arguments]) return tc + def key_for_lifetime( + self, + lifetime: str, + ) -> StorageKey: + """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 + key = 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) + return key + + def all_keys_for_lifetimes(self) -> Iterator[StorageKey]: + """Generate test keys covering lifetimes.""" + lifetimes = sorted(self.constructors.lifetimes) + expressions = self.constructors.generate_expressions(lifetimes) + for lifetime in expressions: + # Don't attempt to create or load a volatile key in storage + if 'VOLATILE' in lifetime: + continue + # Don't attempt to create a read-only key in storage, + # but do attempt to load one. + if 'READ_ONLY' in lifetime and self.forward: + continue + yield self.key_for_lifetime(lifetime) + def key_for_usage_flags( self, usage_flags: List[str], @@ -389,12 +421,17 @@ class StorageFormat: # one go, which is a significant performance gain as the information # includes numerical values obtained by compiling a C program. keys = [] #type: List[StorageKey] + keys += self.all_keys_for_lifetimes() keys += self.all_keys_for_usage_flags() keys += self.all_keys_for_types() keys += self.all_keys_for_algorithms() for key in keys: + if key.location_value() != 0: + # Skip keys with a non-default location, because they + # require a driver and we currently have no mechanism to + # determine whether a driver is available. + continue yield self.make_test_case(key) - # To do: vary id, lifetime class TestGenerator: diff --git a/tests/suites/test_suite_psa_crypto_storage_format.current.data b/tests/suites/test_suite_psa_crypto_storage_format.current.data index 024420b31..4efa2ca3e 100644 --- a/tests/suites/test_suite_psa_crypto_storage_format.current.data +++ b/tests/suites/test_suite_psa_crypto_storage_format.current.data @@ -1,5 +1,21 @@ # Automatically generated by generate_psa_tests.py. Do not edit! +PSA storage save: lifetime: (DEFAULT, LOCAL_STORAGE) +depends_on:PSA_WANT_KEY_TYPE_RAW_DATA +key_storage_save:PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(PSA_KEY_PERSISTENCE_DEFAULT, PSA_KEY_LOCATION_LOCAL_STORAGE):PSA_KEY_TYPE_RAW_DATA:8:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"4c":"505341004b455900000000000100000001100800010000000000000000000000010000004c" + +PSA storage save: lifetime: (2, LOCAL_STORAGE) +depends_on:PSA_WANT_KEY_TYPE_RAW_DATA +key_storage_save:PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(2, PSA_KEY_LOCATION_LOCAL_STORAGE):PSA_KEY_TYPE_RAW_DATA:8:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"4c":"505341004b455900000000000200000001100800010000000000000000000000010000004c" + +PSA storage save: lifetime: (254, LOCAL_STORAGE) +depends_on:PSA_WANT_KEY_TYPE_RAW_DATA +key_storage_save:PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(254, PSA_KEY_LOCATION_LOCAL_STORAGE):PSA_KEY_TYPE_RAW_DATA:8:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"4c":"505341004b45590000000000fe00000001100800010000000000000000000000010000004c" + +PSA storage save: lifetime: PERSISTENT +depends_on:PSA_WANT_KEY_TYPE_RAW_DATA +key_storage_save:PSA_KEY_LIFETIME_PERSISTENT:PSA_KEY_TYPE_RAW_DATA:8:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"4c":"505341004b455900000000000100000001100800010000000000000000000000010000004c" + PSA storage save: usage: 0 depends_on:PSA_WANT_KEY_TYPE_RAW_DATA key_storage_save:0x0001:PSA_KEY_TYPE_RAW_DATA:8:0:0x0000:0x0000:"4b":"505341004b455900000000000100000001100800000000000000000000000000010000004b" diff --git a/tests/suites/test_suite_psa_crypto_storage_format.function b/tests/suites/test_suite_psa_crypto_storage_format.function index 34d63a745..003c70be0 100644 --- a/tests/suites/test_suite_psa_crypto_storage_format.function +++ b/tests/suites/test_suite_psa_crypto_storage_format.function @@ -8,6 +8,7 @@ #include #define TEST_FLAG_EXERCISE 0x00000001 +#define TEST_FLAG_READ_ONLY 0x00000002 /** Write a key with the given attributes and key material to storage. * Test that it has the expected representation. @@ -115,10 +116,22 @@ static int test_read_key( const psa_key_attributes_t *expected_attributes, psa_get_key_algorithm( expected_attributes ) ) ); } - /* Destroy the key. Confirm through direct access to the storage. */ - PSA_ASSERT( psa_destroy_key( key_id ) ); - TEST_EQUAL( PSA_ERROR_DOES_NOT_EXIST, - psa_its_get_info( uid, &storage_info ) ); + + if( flags & TEST_FLAG_READ_ONLY ) + { + /* Read-only keys cannot be removed through the API. + * The key will be removed through ITS in the cleanup code below. + * Purge the key from memory so that the test framework doesn't + * think the test is leaking it. */ + PSA_ASSERT( psa_purge_key( key_id ) ); + } + else + { + /* Destroy the key. Confirm through direct access to the storage. */ + PSA_ASSERT( psa_destroy_key( key_id ) ); + TEST_EQUAL( PSA_ERROR_DOES_NOT_EXIST, + psa_its_get_info( uid, &storage_info ) ); + } ok = 1; @@ -219,7 +232,6 @@ void key_storage_read( int lifetime_arg, int type_arg, int bits_arg, exit: psa_reset_key_attributes( &attributes ); - psa_destroy_key( key_id ); PSA_DONE( ); } /* END_CASE */ diff --git a/tests/suites/test_suite_psa_crypto_storage_format.v0.data b/tests/suites/test_suite_psa_crypto_storage_format.v0.data index ce1dc1e38..e228fa4db 100644 --- a/tests/suites/test_suite_psa_crypto_storage_format.v0.data +++ b/tests/suites/test_suite_psa_crypto_storage_format.v0.data @@ -1,5 +1,25 @@ # Automatically generated by generate_psa_tests.py. Do not edit! +PSA storage read: lifetime: (DEFAULT, LOCAL_STORAGE) +depends_on:PSA_WANT_KEY_TYPE_RAW_DATA +key_storage_read:PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(PSA_KEY_PERSISTENCE_DEFAULT, PSA_KEY_LOCATION_LOCAL_STORAGE):PSA_KEY_TYPE_RAW_DATA:8:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"4c":"505341004b455900000000000100000001100800010000000000000000000000010000004c":0 + +PSA storage read: lifetime: (READ_ONLY, LOCAL_STORAGE) +depends_on:PSA_WANT_KEY_TYPE_RAW_DATA +key_storage_read:PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(PSA_KEY_PERSISTENCE_READ_ONLY, PSA_KEY_LOCATION_LOCAL_STORAGE):PSA_KEY_TYPE_RAW_DATA:8:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"4c":"505341004b45590000000000ff00000001100800010000000000000000000000010000004c":TEST_FLAG_READ_ONLY + +PSA storage read: lifetime: (2, LOCAL_STORAGE) +depends_on:PSA_WANT_KEY_TYPE_RAW_DATA +key_storage_read:PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(2, PSA_KEY_LOCATION_LOCAL_STORAGE):PSA_KEY_TYPE_RAW_DATA:8:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"4c":"505341004b455900000000000200000001100800010000000000000000000000010000004c":0 + +PSA storage read: lifetime: (254, LOCAL_STORAGE) +depends_on:PSA_WANT_KEY_TYPE_RAW_DATA +key_storage_read:PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(254, PSA_KEY_LOCATION_LOCAL_STORAGE):PSA_KEY_TYPE_RAW_DATA:8:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"4c":"505341004b45590000000000fe00000001100800010000000000000000000000010000004c":0 + +PSA storage read: lifetime: PERSISTENT +depends_on:PSA_WANT_KEY_TYPE_RAW_DATA +key_storage_read:PSA_KEY_LIFETIME_PERSISTENT:PSA_KEY_TYPE_RAW_DATA:8:PSA_KEY_USAGE_EXPORT:0x0000:0x0000:"4c":"505341004b455900000000000100000001100800010000000000000000000000010000004c":0 + PSA storage read: usage: 0 depends_on:PSA_WANT_KEY_TYPE_RAW_DATA key_storage_read:0x0001:PSA_KEY_TYPE_RAW_DATA:8:0:0x0000:0x0000:"4b":"505341004b455900000000000100000001100800000000000000000000000000010000004b":0