From 0a271fde761d1692f250a56822a380b640326c30 Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Tue, 12 Mar 2024 16:34:02 +0000 Subject: [PATCH 01/17] Add key_destroyable parameter to mbedtls_test_psa_exercise_key This will allow us to use this smoke test to ensure that key slot content reads are only performed when we are registered to read a full slot. We will destroy the key on another thread while the key is being exercised, and fail the test if an unexpected error code is hit. Future commits will incrementally implement this new parameter. All current usages of this function have this parameter set to 0, in which case the new behaviour must be the same as the old behaviour Signed-off-by: Ryan Everett --- tests/include/test/psa_exercise_key.h | 18 ++++++++---- tests/src/psa_exercise_key.c | 29 +++++++++++-------- tests/suites/test_suite_pkparse.function | 2 +- tests/suites/test_suite_psa_crypto.function | 22 +++++++------- ...t_suite_psa_crypto_storage_format.function | 2 +- 5 files changed, 43 insertions(+), 30 deletions(-) diff --git a/tests/include/test/psa_exercise_key.h b/tests/include/test/psa_exercise_key.h index 44f5c08aa..fa57d8872 100644 --- a/tests/include/test/psa_exercise_key.h +++ b/tests/include/test/psa_exercise_key.h @@ -209,18 +209,26 @@ int mbedtls_test_psa_exported_key_sanity_check( * ``` * if( ! exercise_key( ... ) ) goto exit; * ``` + * To use this function for multi-threaded tests where the key + * may be destroyed at any point: call this function with key_destroyable set + * to 1, while another thread calls psa_destroy_key on the same key; + * this will test whether destroying the key in use leads to any corruption. * - * \param key The key to exercise. It should be capable of performing - * \p alg. - * \param usage The usage flags to assume. - * \param alg The algorithm to exercise. + * \param key The key to exercise. It should be capable of performing + * \p alg. + * \param usage The usage flags to assume. + * \param alg The algorithm to exercise. + * \param key_destroyable If set to 1, a failure due to the key not existing + * or the key being destroyed mid-operation will only + * be reported if the error code is unexpected. * * \retval 0 The key failed the smoke tests. * \retval 1 The key passed the smoke tests. */ int mbedtls_test_psa_exercise_key(mbedtls_svc_key_id_t key, psa_key_usage_t usage, - psa_algorithm_t alg); + psa_algorithm_t alg, + int key_destroyable); psa_key_usage_t mbedtls_test_psa_usage_to_exercise(psa_key_type_t type, psa_algorithm_t alg); diff --git a/tests/src/psa_exercise_key.c b/tests/src/psa_exercise_key.c index 7b81052c8..e5cce7939 100644 --- a/tests/src/psa_exercise_key.c +++ b/tests/src/psa_exercise_key.c @@ -948,38 +948,43 @@ exit: int mbedtls_test_psa_exercise_key(mbedtls_svc_key_id_t key, psa_key_usage_t usage, - psa_algorithm_t alg) + psa_algorithm_t alg, + int key_destroyable) { int ok = 0; - if (!check_key_attributes_sanity(key)) { + if (!check_key_attributes_sanity(key, key_destroyable)) { return 0; } if (alg == 0) { ok = 1; /* If no algorithm, do nothing (used for raw data "keys"). */ } else if (PSA_ALG_IS_MAC(alg)) { - ok = exercise_mac_key(key, usage, alg); + ok = exercise_mac_key(key, usage, alg, key_destroyable); } else if (PSA_ALG_IS_CIPHER(alg)) { - ok = exercise_cipher_key(key, usage, alg); + ok = exercise_cipher_key(key, usage, alg, key_destroyable); } else if (PSA_ALG_IS_AEAD(alg)) { - ok = exercise_aead_key(key, usage, alg); + ok = exercise_aead_key(key, usage, alg, key_destroyable); } else if (PSA_ALG_IS_SIGN(alg)) { - ok = exercise_signature_key(key, usage, alg); + ok = exercise_signature_key(key, usage, alg, key_destroyable); } else if (PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg)) { - ok = exercise_asymmetric_encryption_key(key, usage, alg); + ok = exercise_asymmetric_encryption_key(key, usage, alg, + key_destroyable); } else if (PSA_ALG_IS_KEY_DERIVATION(alg)) { - ok = exercise_key_derivation_key(key, usage, alg); + ok = exercise_key_derivation_key(key, usage, alg, key_destroyable); } else if (PSA_ALG_IS_RAW_KEY_AGREEMENT(alg)) { - ok = exercise_raw_key_agreement_key(key, usage, alg); + ok = exercise_raw_key_agreement_key(key, usage, alg, key_destroyable); } else if (PSA_ALG_IS_KEY_AGREEMENT(alg)) { - ok = exercise_key_agreement_key(key, usage, alg); + ok = exercise_key_agreement_key(key, usage, alg, key_destroyable); } else { TEST_FAIL("No code to exercise this category of algorithm"); } - ok = ok && exercise_export_key(key, usage); - ok = ok && exercise_export_public_key(key); + ok = ok && exercise_export_key(key, + usage, + key_destroyable); + ok = ok && exercise_export_public_key(key, + key_destroyable); exit: return ok; diff --git a/tests/suites/test_suite_pkparse.function b/tests/suites/test_suite_pkparse.function index 7dc8413c8..a06fc30bc 100644 --- a/tests/suites/test_suite_pkparse.function +++ b/tests/suites/test_suite_pkparse.function @@ -57,7 +57,7 @@ static int test_psa_bridge(const mbedtls_pk_context *ctx, if (mbedtls_test_can_exercise_psa_algorithm(exercise_alg)) { TEST_ASSERT(mbedtls_test_psa_exercise_key(psa_key, exercise_usage, - exercise_alg)); + exercise_alg, 0)); } mbedtls_test_set_step((unsigned long) -1); diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index 114159799..dfddbb94d 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -1379,7 +1379,7 @@ void *thread_generate_key(void *ctx) /* Do something with the key according * to its type and permitted usage. */ - if (!mbedtls_test_psa_exercise_key(key, gkc->usage, gkc->alg)) { + if (!mbedtls_test_psa_exercise_key(key, gkc->usage, gkc->alg, 0)) { psa_destroy_key(key); goto exit; } @@ -1715,7 +1715,7 @@ void import_export(data_t *data, * this doesn't directly validate the implementation, but it still helps * by cross-validating the test data with the sanity check code. */ if (!psa_key_lifetime_is_external(lifetime)) { - if (!mbedtls_test_psa_exercise_key(key, usage_arg, 0)) { + if (!mbedtls_test_psa_exercise_key(key, usage_arg, 0, 0)) { goto exit; } } @@ -1853,7 +1853,7 @@ void import_and_exercise_key(data_t *data, TEST_EQUAL(psa_get_key_bits(&got_attributes), bits); /* Do something with the key according to its type and permitted usage. */ - if (!mbedtls_test_psa_exercise_key(key, usage, alg)) { + if (!mbedtls_test_psa_exercise_key(key, usage, alg, 0)) { goto exit; } @@ -2529,10 +2529,10 @@ void key_policy_alg2(int key_type_arg, data_t *key_data, TEST_EQUAL(psa_get_key_algorithm(&got_attributes), alg); TEST_EQUAL(psa_get_key_enrollment_algorithm(&got_attributes), alg2); - if (!mbedtls_test_psa_exercise_key(key, usage, alg)) { + if (!mbedtls_test_psa_exercise_key(key, usage, alg, 0)) { goto exit; } - if (!mbedtls_test_psa_exercise_key(key, usage, alg2)) { + if (!mbedtls_test_psa_exercise_key(key, usage, alg2, 0)) { goto exit; } @@ -2663,10 +2663,10 @@ void copy_success(int source_usage_arg, } if (!psa_key_lifetime_is_external(target_lifetime)) { - if (!mbedtls_test_psa_exercise_key(target_key, expected_usage, expected_alg)) { + if (!mbedtls_test_psa_exercise_key(target_key, expected_usage, expected_alg, 0)) { goto exit; } - if (!mbedtls_test_psa_exercise_key(target_key, expected_usage, expected_alg2)) { + if (!mbedtls_test_psa_exercise_key(target_key, expected_usage, expected_alg2, 0)) { goto exit; } } @@ -9233,7 +9233,7 @@ void derive_key_exercise(int alg_arg, TEST_EQUAL(psa_get_key_bits(&got_attributes), derived_bits); /* Exercise the derived key. */ - if (!mbedtls_test_psa_exercise_key(derived_key, derived_usage, derived_alg)) { + if (!mbedtls_test_psa_exercise_key(derived_key, derived_usage, derived_alg, 0)) { goto exit; } @@ -9941,7 +9941,7 @@ void generate_key(int type_arg, TEST_EQUAL(psa_get_key_bits(&got_attributes), bits); /* Do something with the key according to its type and permitted usage. */ - if (!mbedtls_test_psa_exercise_key(key, usage, alg)) { + if (!mbedtls_test_psa_exercise_key(key, usage, alg, 0)) { goto exit; } @@ -10011,7 +10011,7 @@ void generate_key_ext(int type_arg, #endif /* Do something with the key according to its type and permitted usage. */ - if (!mbedtls_test_psa_exercise_key(key, usage, alg)) { + if (!mbedtls_test_psa_exercise_key(key, usage, alg, 0)) { goto exit; } @@ -10162,7 +10162,7 @@ void persistent_key_load_key_from_storage(data_t *data, } /* Do something with the key according to its type and permitted usage. */ - if (!mbedtls_test_psa_exercise_key(key, usage_flags, alg)) { + if (!mbedtls_test_psa_exercise_key(key, usage_flags, alg, 0)) { goto exit; } diff --git a/tests/suites/test_suite_psa_crypto_storage_format.function b/tests/suites/test_suite_psa_crypto_storage_format.function index bb1e2c68c..efaaba58a 100644 --- a/tests/suites/test_suite_psa_crypto_storage_format.function +++ b/tests/suites/test_suite_psa_crypto_storage_format.function @@ -187,7 +187,7 @@ static int test_read_key(const psa_key_attributes_t *expected_attributes, TEST_ASSERT(mbedtls_test_psa_exercise_key( key_id, psa_get_key_usage_flags(expected_attributes), - psa_get_key_algorithm(expected_attributes))); + psa_get_key_algorithm(expected_attributes), 0)); } From f08a93fbe599b85949940f9ac9366d842049197a Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Tue, 12 Mar 2024 16:00:08 +0000 Subject: [PATCH 02/17] Add key_destroyable parameter to check_key_attributes_sanity This function is currently only used in the exercise_key smoke test. Signed-off-by: Ryan Everett --- tests/src/psa_exercise_key.c | 37 ++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/tests/src/psa_exercise_key.c b/tests/src/psa_exercise_key.c index e5cce7939..30f21da90 100644 --- a/tests/src/psa_exercise_key.c +++ b/tests/src/psa_exercise_key.c @@ -38,7 +38,8 @@ static int lifetime_is_dynamic_secure_element(psa_key_lifetime_t lifetime) } #endif -static int check_key_attributes_sanity(mbedtls_svc_key_id_t key) +static int check_key_attributes_sanity(mbedtls_svc_key_id_t key, + int key_destroyable) { int ok = 0; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; @@ -46,8 +47,13 @@ static int check_key_attributes_sanity(mbedtls_svc_key_id_t key) mbedtls_svc_key_id_t id; psa_key_type_t type; size_t bits; - - PSA_ASSERT(psa_get_key_attributes(key, &attributes)); + psa_status_t status = psa_get_key_attributes(key, &attributes); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + psa_reset_key_attributes(&attributes); + return 1; + } + PSA_ASSERT(status); lifetime = psa_get_key_lifetime(&attributes); id = psa_get_key_id(&attributes); type = psa_get_key_type(&attributes); @@ -66,17 +72,20 @@ static int check_key_attributes_sanity(mbedtls_svc_key_id_t key) (MBEDTLS_SVC_KEY_ID_GET_KEY_ID(id) <= PSA_KEY_ID_USER_MAX)); } #if defined(MBEDTLS_PSA_CRYPTO_SE_C) - /* randomly-generated 64-bit constant, should never appear in test data */ - psa_key_slot_number_t slot_number = 0xec94d4a5058a1a21; - psa_status_t status = psa_get_key_slot_number(&attributes, &slot_number); - if (lifetime_is_dynamic_secure_element(lifetime)) { - /* Mbed TLS currently always exposes the slot number to - * applications. This is not mandated by the PSA specification - * and may change in future versions. */ - TEST_EQUAL(status, 0); - TEST_ASSERT(slot_number != 0xec94d4a5058a1a21); - } else { - TEST_EQUAL(status, PSA_ERROR_INVALID_ARGUMENT); + /* MBEDTLS_PSA_CRYPTO_SE_C does not support thread safety. */ + if (key_destroyable == 0) { + /* randomly-generated 64-bit constant, should never appear in test data */ + psa_key_slot_number_t slot_number = 0xec94d4a5058a1a21; + status = psa_get_key_slot_number(&attributes, &slot_number); + if (lifetime_is_dynamic_secure_element(lifetime)) { + /* Mbed TLS currently always exposes the slot number to + * applications. This is not mandated by the PSA specification + * and may change in future versions. */ + TEST_EQUAL(status, 0); + TEST_ASSERT(slot_number != 0xec94d4a5058a1a21); + } else { + TEST_EQUAL(status, PSA_ERROR_INVALID_ARGUMENT); + } } #endif From 77635508845a57a73722409904d12d31b4f3da45 Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Tue, 12 Mar 2024 16:02:23 +0000 Subject: [PATCH 03/17] Add key_destroyable parameter to exercise_mac_key If the key has been destroyed (and the new parameter is 1) then we test that psa_mac_abort succeeds in this scenario. Signed-off-by: Ryan Everett --- tests/src/psa_exercise_key.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/tests/src/psa_exercise_key.c b/tests/src/psa_exercise_key.c index 30f21da90..dc5b2bf00 100644 --- a/tests/src/psa_exercise_key.c +++ b/tests/src/psa_exercise_key.c @@ -119,20 +119,27 @@ exit: static int exercise_mac_key(mbedtls_svc_key_id_t key, psa_key_usage_t usage, - psa_algorithm_t alg) + psa_algorithm_t alg, + int key_destroyable) { psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; const unsigned char input[] = "foo"; unsigned char mac[PSA_MAC_MAX_SIZE] = { 0 }; size_t mac_length = sizeof(mac); - + psa_status_t status = PSA_SUCCESS; /* Convert wildcard algorithm to exercisable algorithm */ if (alg & PSA_ALG_MAC_AT_LEAST_THIS_LENGTH_FLAG) { alg = PSA_ALG_TRUNCATED_MAC(alg, PSA_MAC_TRUNCATED_LENGTH(alg)); } if (usage & PSA_KEY_USAGE_SIGN_HASH) { - PSA_ASSERT(psa_mac_sign_setup(&operation, key, alg)); + status = psa_mac_sign_setup(&operation, key, alg); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + PSA_ASSERT(psa_mac_abort(&operation)); + return 1; + } + PSA_ASSERT(status); PSA_ASSERT(psa_mac_update(&operation, input, sizeof(input))); PSA_ASSERT(psa_mac_sign_finish(&operation, @@ -145,7 +152,13 @@ static int exercise_mac_key(mbedtls_svc_key_id_t key, (usage & PSA_KEY_USAGE_SIGN_HASH ? PSA_SUCCESS : PSA_ERROR_INVALID_SIGNATURE); - PSA_ASSERT(psa_mac_verify_setup(&operation, key, alg)); + status = psa_mac_verify_setup(&operation, key, alg); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + PSA_ASSERT(psa_mac_abort(&operation)); + return 1; + } + PSA_ASSERT(status); PSA_ASSERT(psa_mac_update(&operation, input, sizeof(input))); TEST_EQUAL(psa_mac_verify_finish(&operation, mac, mac_length), From 70691f3082a1bc6e96ca038439f15700cb389788 Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Tue, 12 Mar 2024 16:04:45 +0000 Subject: [PATCH 04/17] Add key_destroyable parameter to psa_exercise_cipher_key If the key has been destroyed (and the new parameter is 1), we test that psa_cipher_abort succeeds in this scenario. Signed-off-by: Ryan Everett --- tests/src/psa_exercise_key.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/tests/src/psa_exercise_key.c b/tests/src/psa_exercise_key.c index dc5b2bf00..ff0d1c0a6 100644 --- a/tests/src/psa_exercise_key.c +++ b/tests/src/psa_exercise_key.c @@ -174,7 +174,8 @@ exit: static int exercise_cipher_key(mbedtls_svc_key_id_t key, psa_key_usage_t usage, - psa_algorithm_t alg) + psa_algorithm_t alg, + int key_destroyable) { psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; unsigned char iv[PSA_CIPHER_IV_MAX_SIZE] = { 0 }; @@ -186,13 +187,20 @@ static int exercise_cipher_key(mbedtls_svc_key_id_t key, size_t ciphertext_length = sizeof(ciphertext); unsigned char decrypted[sizeof(ciphertext)]; size_t part_length; + psa_status_t status = PSA_SUCCESS; PSA_ASSERT(psa_get_key_attributes(key, &attributes)); key_type = psa_get_key_type(&attributes); iv_length = PSA_CIPHER_IV_LENGTH(key_type, alg); if (usage & PSA_KEY_USAGE_ENCRYPT) { - PSA_ASSERT(psa_cipher_encrypt_setup(&operation, key, alg)); + status = psa_cipher_encrypt_setup(&operation, key, alg); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + PSA_ASSERT(psa_cipher_abort(&operation)); + return 1; + } + PSA_ASSERT(status); if (iv_length != 0) { PSA_ASSERT(psa_cipher_generate_iv(&operation, iv, sizeof(iv), @@ -210,12 +218,17 @@ static int exercise_cipher_key(mbedtls_svc_key_id_t key, } if (usage & PSA_KEY_USAGE_DECRYPT) { - psa_status_t status; int maybe_invalid_padding = 0; if (!(usage & PSA_KEY_USAGE_ENCRYPT)) { maybe_invalid_padding = !PSA_ALG_IS_STREAM_CIPHER(alg); } - PSA_ASSERT(psa_cipher_decrypt_setup(&operation, key, alg)); + status = psa_cipher_decrypt_setup(&operation, key, alg); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + PSA_ASSERT(psa_cipher_abort(&operation)); + return 1; + } + PSA_ASSERT(status); if (iv_length != 0) { PSA_ASSERT(psa_cipher_set_iv(&operation, iv, iv_length)); From fbe703de2a17e7e0a513f9074f55979794cb9fcd Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Tue, 12 Mar 2024 16:09:25 +0000 Subject: [PATCH 05/17] Add key_destroyable parameter to exercise_aead_key Signed-off-by: Ryan Everett --- tests/src/psa_exercise_key.c | 39 +++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/tests/src/psa_exercise_key.c b/tests/src/psa_exercise_key.c index ff0d1c0a6..89434bfdc 100644 --- a/tests/src/psa_exercise_key.c +++ b/tests/src/psa_exercise_key.c @@ -262,7 +262,8 @@ exit: static int exercise_aead_key(mbedtls_svc_key_id_t key, psa_key_usage_t usage, - psa_algorithm_t alg) + psa_algorithm_t alg, + int key_destroyable) { unsigned char nonce[PSA_AEAD_NONCE_MAX_SIZE] = { 0 }; size_t nonce_length; @@ -272,6 +273,7 @@ static int exercise_aead_key(mbedtls_svc_key_id_t key, unsigned char ciphertext[48] = "(wabblewebblewibblewobblewubble)"; size_t ciphertext_length = sizeof(ciphertext); size_t plaintext_length = sizeof(ciphertext); + psa_status_t status = PSA_SUCCESS; /* Convert wildcard algorithm to exercisable algorithm */ if (alg & PSA_ALG_AEAD_AT_LEAST_THIS_LENGTH_FLAG) { @@ -283,12 +285,17 @@ static int exercise_aead_key(mbedtls_svc_key_id_t key, nonce_length = PSA_AEAD_NONCE_LENGTH(key_type, alg); if (usage & PSA_KEY_USAGE_ENCRYPT) { - PSA_ASSERT(psa_aead_encrypt(key, alg, - nonce, nonce_length, - NULL, 0, - plaintext, sizeof(plaintext), - ciphertext, sizeof(ciphertext), - &ciphertext_length)); + status = psa_aead_encrypt(key, alg, + nonce, nonce_length, + NULL, 0, + plaintext, sizeof(plaintext), + ciphertext, sizeof(ciphertext), + &ciphertext_length); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + return 1; + } + PSA_ASSERT(status); } if (usage & PSA_KEY_USAGE_DECRYPT) { @@ -296,13 +303,17 @@ static int exercise_aead_key(mbedtls_svc_key_id_t key, (usage & PSA_KEY_USAGE_ENCRYPT ? PSA_SUCCESS : PSA_ERROR_INVALID_SIGNATURE); - TEST_EQUAL(psa_aead_decrypt(key, alg, - nonce, nonce_length, - NULL, 0, - ciphertext, ciphertext_length, - plaintext, sizeof(plaintext), - &plaintext_length), - verify_status); + status = psa_aead_decrypt(key, alg, + nonce, nonce_length, + NULL, 0, + ciphertext, ciphertext_length, + plaintext, sizeof(plaintext), + &plaintext_length); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + return 1; + } + TEST_ASSERT(status == verify_status); } return 1; From 6edd40819e29b942885bc96eb63d6275738e1543 Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Tue, 12 Mar 2024 16:11:01 +0000 Subject: [PATCH 06/17] Add key_destroyable parameter to exercise_signature_key Signed-off-by: Ryan Everett --- tests/src/psa_exercise_key.c | 54 ++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/tests/src/psa_exercise_key.c b/tests/src/psa_exercise_key.c index 89434bfdc..fde1187e7 100644 --- a/tests/src/psa_exercise_key.c +++ b/tests/src/psa_exercise_key.c @@ -337,7 +337,8 @@ static int can_sign_or_verify_message(psa_key_usage_t usage, static int exercise_signature_key(mbedtls_svc_key_id_t key, psa_key_usage_t usage, - psa_algorithm_t alg) + psa_algorithm_t alg, + int key_destroyable) { /* If the policy allows signing with any hash, just pick one. */ psa_algorithm_t hash_alg = PSA_ALG_SIGN_GET_HASH(alg); @@ -351,6 +352,7 @@ static int exercise_signature_key(mbedtls_svc_key_id_t key, TEST_FAIL("No hash algorithm for hash-and-sign testing"); #endif } + psa_status_t status = PSA_SUCCESS; if (usage & (PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH) && PSA_ALG_IS_SIGN_HASH(alg)) { @@ -367,10 +369,15 @@ static int exercise_signature_key(mbedtls_svc_key_id_t key, } if (usage & PSA_KEY_USAGE_SIGN_HASH) { - PSA_ASSERT(psa_sign_hash(key, alg, - payload, payload_length, - signature, sizeof(signature), - &signature_length)); + status = psa_sign_hash(key, alg, + payload, payload_length, + signature, sizeof(signature), + &signature_length); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + return 1; + } + PSA_ASSERT(status); } if (usage & PSA_KEY_USAGE_VERIFY_HASH) { @@ -378,10 +385,14 @@ static int exercise_signature_key(mbedtls_svc_key_id_t key, (usage & PSA_KEY_USAGE_SIGN_HASH ? PSA_SUCCESS : PSA_ERROR_INVALID_SIGNATURE); - TEST_EQUAL(psa_verify_hash(key, alg, - payload, payload_length, - signature, signature_length), - verify_status); + status = psa_verify_hash(key, alg, + payload, payload_length, + signature, signature_length); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + return 1; + } + TEST_ASSERT(status == verify_status); } } @@ -392,10 +403,15 @@ static int exercise_signature_key(mbedtls_svc_key_id_t key, size_t signature_length = sizeof(signature); if (usage & PSA_KEY_USAGE_SIGN_MESSAGE) { - PSA_ASSERT(psa_sign_message(key, alg, - message, message_length, - signature, sizeof(signature), - &signature_length)); + status = psa_sign_message(key, alg, + message, message_length, + signature, sizeof(signature), + &signature_length); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + return 1; + } + PSA_ASSERT(status); } if (usage & PSA_KEY_USAGE_VERIFY_MESSAGE) { @@ -403,10 +419,14 @@ static int exercise_signature_key(mbedtls_svc_key_id_t key, (usage & PSA_KEY_USAGE_SIGN_MESSAGE ? PSA_SUCCESS : PSA_ERROR_INVALID_SIGNATURE); - TEST_EQUAL(psa_verify_message(key, alg, - message, message_length, - signature, signature_length), - verify_status); + status = psa_verify_message(key, alg, + message, message_length, + signature, signature_length); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + return 1; + } + TEST_ASSERT(status == verify_status); } } From d48fc102d3d70094b52d1ab823859315b6befa3b Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Tue, 12 Mar 2024 16:12:41 +0000 Subject: [PATCH 07/17] Add key_destroyable parameter to exercise_asymmetric_encryption_key Signed-off-by: Ryan Everett --- tests/src/psa_exercise_key.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/tests/src/psa_exercise_key.c b/tests/src/psa_exercise_key.c index fde1187e7..470073930 100644 --- a/tests/src/psa_exercise_key.c +++ b/tests/src/psa_exercise_key.c @@ -438,7 +438,8 @@ exit: static int exercise_asymmetric_encryption_key(mbedtls_svc_key_id_t key, psa_key_usage_t usage, - psa_algorithm_t alg) + psa_algorithm_t alg, + int key_destroyable) { unsigned char plaintext[PSA_ASYMMETRIC_DECRYPT_OUTPUT_MAX_SIZE] = "Hello, world..."; @@ -446,22 +447,30 @@ static int exercise_asymmetric_encryption_key(mbedtls_svc_key_id_t key, "(wabblewebblewibblewobblewubble)"; size_t ciphertext_length = sizeof(ciphertext); size_t plaintext_length = 16; - + psa_status_t status = PSA_SUCCESS; if (usage & PSA_KEY_USAGE_ENCRYPT) { - PSA_ASSERT(psa_asymmetric_encrypt(key, alg, - plaintext, plaintext_length, - NULL, 0, - ciphertext, sizeof(ciphertext), - &ciphertext_length)); + status = psa_asymmetric_encrypt(key, alg, + plaintext, plaintext_length, + NULL, 0, + ciphertext, sizeof(ciphertext), + &ciphertext_length); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + return 1; + } + PSA_ASSERT(status); } if (usage & PSA_KEY_USAGE_DECRYPT) { - psa_status_t status = - psa_asymmetric_decrypt(key, alg, - ciphertext, ciphertext_length, - NULL, 0, - plaintext, sizeof(plaintext), - &plaintext_length); + status = psa_asymmetric_decrypt(key, alg, + ciphertext, ciphertext_length, + NULL, 0, + plaintext, sizeof(plaintext), + &plaintext_length); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + return 1; + } TEST_ASSERT(status == PSA_SUCCESS || ((usage & PSA_KEY_USAGE_ENCRYPT) == 0 && (status == PSA_ERROR_INVALID_ARGUMENT || From c1cc6686f084d647e42ec74304b7b1f8c82f06e1 Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Tue, 12 Mar 2024 16:17:43 +0000 Subject: [PATCH 08/17] Add key_destroyable parameter to key derivation smoke tests All current usages have this parameter set to 0 (in this case the behaviour of the test is unchanged) Signed-off-by: Ryan Everett --- tests/include/test/psa_exercise_key.h | 5 +- tests/src/psa_exercise_key.c | 77 +++++++++++++++------ tests/suites/test_suite_psa_crypto.function | 16 ++--- 3 files changed, 67 insertions(+), 31 deletions(-) diff --git a/tests/include/test/psa_exercise_key.h b/tests/include/test/psa_exercise_key.h index fa57d8872..713b09310 100644 --- a/tests/include/test/psa_exercise_key.h +++ b/tests/include/test/psa_exercise_key.h @@ -123,6 +123,9 @@ * \param input2 The first input to pass. * \param input2_length The length of \p input2 in bytes. * \param capacity The capacity to set. + * \param key_destroyable If set to 1, a failure due to the key not existing + * or the key being destroyed mid-operation will only + * be reported if the error code is unexpected. * * \return \c 1 on success, \c 0 on failure. */ @@ -132,7 +135,7 @@ int mbedtls_test_psa_setup_key_derivation_wrap( psa_algorithm_t alg, const unsigned char *input1, size_t input1_length, const unsigned char *input2, size_t input2_length, - size_t capacity); + size_t capacity, int key_destroyable); /** Perform a key agreement using the given key pair against its public key * using psa_raw_key_agreement(). diff --git a/tests/src/psa_exercise_key.c b/tests/src/psa_exercise_key.c index 470073930..7260f1a4d 100644 --- a/tests/src/psa_exercise_key.c +++ b/tests/src/psa_exercise_key.c @@ -489,16 +489,22 @@ int mbedtls_test_psa_setup_key_derivation_wrap( psa_algorithm_t alg, const unsigned char *input1, size_t input1_length, const unsigned char *input2, size_t input2_length, - size_t capacity) + size_t capacity, int key_destroyable) { PSA_ASSERT(psa_key_derivation_setup(operation, alg)); + psa_status_t status = PSA_SUCCESS; if (PSA_ALG_IS_HKDF(alg)) { PSA_ASSERT(psa_key_derivation_input_bytes(operation, PSA_KEY_DERIVATION_INPUT_SALT, input1, input1_length)); - PSA_ASSERT(psa_key_derivation_input_key(operation, - PSA_KEY_DERIVATION_INPUT_SECRET, - key)); + status = psa_key_derivation_input_key(operation, + PSA_KEY_DERIVATION_INPUT_SECRET, + key); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + return 1; + } + PSA_ASSERT(status); PSA_ASSERT(psa_key_derivation_input_bytes(operation, PSA_KEY_DERIVATION_INPUT_INFO, input2, @@ -507,13 +513,23 @@ int mbedtls_test_psa_setup_key_derivation_wrap( PSA_ASSERT(psa_key_derivation_input_bytes(operation, PSA_KEY_DERIVATION_INPUT_SALT, input1, input1_length)); - PSA_ASSERT(psa_key_derivation_input_key(operation, - PSA_KEY_DERIVATION_INPUT_SECRET, - key)); + status = psa_key_derivation_input_key(operation, + PSA_KEY_DERIVATION_INPUT_SECRET, + key); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + return 1; + } + PSA_ASSERT(status); } else if (PSA_ALG_IS_HKDF_EXPAND(alg)) { - PSA_ASSERT(psa_key_derivation_input_key(operation, - PSA_KEY_DERIVATION_INPUT_SECRET, - key)); + status = psa_key_derivation_input_key(operation, + PSA_KEY_DERIVATION_INPUT_SECRET, + key); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + return 1; + } + PSA_ASSERT(status); PSA_ASSERT(psa_key_derivation_input_bytes(operation, PSA_KEY_DERIVATION_INPUT_INFO, input2, @@ -523,9 +539,14 @@ int mbedtls_test_psa_setup_key_derivation_wrap( PSA_ASSERT(psa_key_derivation_input_bytes(operation, PSA_KEY_DERIVATION_INPUT_SEED, input1, input1_length)); - PSA_ASSERT(psa_key_derivation_input_key(operation, - PSA_KEY_DERIVATION_INPUT_SECRET, - key)); + status = psa_key_derivation_input_key(operation, + PSA_KEY_DERIVATION_INPUT_SECRET, + key); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + return 1; + } + PSA_ASSERT(status); PSA_ASSERT(psa_key_derivation_input_bytes(operation, PSA_KEY_DERIVATION_INPUT_LABEL, input2, input2_length)); @@ -537,9 +558,14 @@ int mbedtls_test_psa_setup_key_derivation_wrap( PSA_KEY_DERIVATION_INPUT_SALT, input2, input2_length)); - PSA_ASSERT(psa_key_derivation_input_key(operation, - PSA_KEY_DERIVATION_INPUT_PASSWORD, - key)); + status = psa_key_derivation_input_key(operation, + PSA_KEY_DERIVATION_INPUT_PASSWORD, + key); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + return 1; + } + PSA_ASSERT(status); } else if (alg == PSA_ALG_TLS12_ECJPAKE_TO_PMS) { PSA_ASSERT(psa_key_derivation_input_bytes(operation, PSA_KEY_DERIVATION_INPUT_SECRET, @@ -561,7 +587,8 @@ exit: static int exercise_key_derivation_key(mbedtls_svc_key_id_t key, psa_key_usage_t usage, - psa_algorithm_t alg) + psa_algorithm_t alg, + int key_destroyable) { psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; unsigned char input1[] = "Input 1"; @@ -575,14 +602,20 @@ static int exercise_key_derivation_key(mbedtls_svc_key_id_t key, if (!mbedtls_test_psa_setup_key_derivation_wrap(&operation, key, alg, input1, input1_length, input2, input2_length, - capacity)) { + capacity, key_destroyable)) { goto exit; } - PSA_ASSERT(psa_key_derivation_output_bytes(&operation, - output, - capacity)); - PSA_ASSERT(psa_key_derivation_abort(&operation)); + psa_status_t status = psa_key_derivation_output_bytes(&operation, + output, + capacity); + if (key_destroyable && status == PSA_ERROR_BAD_STATE) { + /* The key has been destroyed. */ + PSA_ASSERT(psa_key_derivation_abort(&operation)); + } else { + PSA_ASSERT(status); + PSA_ASSERT(psa_key_derivation_abort(&operation)); + } } return 1; diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index dfddbb94d..7ef8618ef 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -8780,7 +8780,7 @@ void derive_over_capacity(int alg_arg) if (!mbedtls_test_psa_setup_key_derivation_wrap(&operation, key, alg, input1, input1_length, input2, input2_length, - capacity)) { + capacity, 0)) { goto exit; } @@ -9099,7 +9099,7 @@ void derive_full(int alg_arg, if (!mbedtls_test_psa_setup_key_derivation_wrap(&operation, key, alg, input1->x, input1->len, input2->x, input2->len, - requested_capacity)) { + requested_capacity, 0)) { goto exit; } @@ -9216,7 +9216,7 @@ void derive_key_exercise(int alg_arg, if (!mbedtls_test_psa_setup_key_derivation_wrap(&operation, base_key, alg, input1->x, input1->len, input2->x, input2->len, - capacity)) { + capacity, 0)) { goto exit; } @@ -9286,7 +9286,7 @@ void derive_key_export(int alg_arg, if (!mbedtls_test_psa_setup_key_derivation_wrap(&operation, base_key, alg, input1->x, input1->len, input2->x, input2->len, - capacity)) { + capacity, 0)) { goto exit; } @@ -9299,7 +9299,7 @@ void derive_key_export(int alg_arg, if (!mbedtls_test_psa_setup_key_derivation_wrap(&operation, base_key, alg, input1->x, input1->len, input2->x, input2->len, - capacity)) { + capacity, 0)) { goto exit; } @@ -9370,7 +9370,7 @@ void derive_key_type(int alg_arg, &operation, base_key, alg, input1->x, input1->len, input2->x, input2->len, - PSA_KEY_DERIVATION_UNLIMITED_CAPACITY) == 0) { + PSA_KEY_DERIVATION_UNLIMITED_CAPACITY, 0) == 0) { goto exit; } @@ -9435,7 +9435,7 @@ void derive_key_ext(int alg_arg, &operation, base_key, alg, input1->x, input1->len, input2->x, input2->len, - PSA_KEY_DERIVATION_UNLIMITED_CAPACITY) == 0) { + PSA_KEY_DERIVATION_UNLIMITED_CAPACITY, 0) == 0) { goto exit; } @@ -9499,7 +9499,7 @@ void derive_key(int alg_arg, if (!mbedtls_test_psa_setup_key_derivation_wrap(&operation, base_key, alg, input1->x, input1->len, input2->x, input2->len, - SIZE_MAX)) { + SIZE_MAX, 0)) { goto exit; } From 8163028fbdd59898cefaa4201c1e06972d91f9dc Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Tue, 12 Mar 2024 16:21:12 +0000 Subject: [PATCH 09/17] Add key_destroyable parameter to raw key agreement smoke tests All current usages have this parameter set to 0 (meaning the behaviour of these tests hasn't changed). We also now return the actual error code, not GENERIC_ERROR Signed-off-by: Ryan Everett --- tests/include/test/psa_exercise_key.h | 5 ++- tests/src/psa_exercise_key.c | 38 +++++++++++++++------ tests/suites/test_suite_psa_crypto.function | 2 +- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/tests/include/test/psa_exercise_key.h b/tests/include/test/psa_exercise_key.h index 713b09310..23349166a 100644 --- a/tests/include/test/psa_exercise_key.h +++ b/tests/include/test/psa_exercise_key.h @@ -146,12 +146,15 @@ int mbedtls_test_psa_setup_key_derivation_wrap( * * \param alg A key agreement algorithm compatible with \p key. * \param key A key that allows key agreement with \p alg. + * \param key_destroyable If set to 1, a failure due to the key not existing + * or the key being destroyed mid-operation will only + * be reported if the error code is unexpected. * * \return \c 1 on success, \c 0 on failure. */ psa_status_t mbedtls_test_psa_raw_key_agreement_with_self( psa_algorithm_t alg, - mbedtls_svc_key_id_t key); + mbedtls_svc_key_id_t key, int key_destroyable); /** Perform a key agreement using the given key pair against its public key * using psa_key_derivation_raw_key(). diff --git a/tests/src/psa_exercise_key.c b/tests/src/psa_exercise_key.c index 7260f1a4d..b62a34b5d 100644 --- a/tests/src/psa_exercise_key.c +++ b/tests/src/psa_exercise_key.c @@ -668,7 +668,8 @@ exit: * private key against its own public key. */ psa_status_t mbedtls_test_psa_raw_key_agreement_with_self( psa_algorithm_t alg, - mbedtls_svc_key_id_t key) + mbedtls_svc_key_id_t key, + int key_destroyable) { psa_key_type_t private_key_type; psa_key_type_t public_key_type; @@ -677,25 +678,38 @@ psa_status_t mbedtls_test_psa_raw_key_agreement_with_self( size_t public_key_length; uint8_t output[1024]; size_t output_length; - /* Return GENERIC_ERROR if something other than the final call to - * psa_key_derivation_key_agreement fails. This isn't fully satisfactory, - * but it's good enough: callers will report it as a failed test anyway. */ - psa_status_t status = PSA_ERROR_GENERIC_ERROR; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - PSA_ASSERT(psa_get_key_attributes(key, &attributes)); + psa_status_t status = psa_get_key_attributes(key, &attributes); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + psa_reset_key_attributes(&attributes); + return PSA_SUCCESS; + } + PSA_ASSERT(status); + private_key_type = psa_get_key_type(&attributes); key_bits = psa_get_key_bits(&attributes); public_key_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(private_key_type); public_key_length = PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(public_key_type, key_bits); TEST_CALLOC(public_key, public_key_length); - PSA_ASSERT(psa_export_public_key(key, - public_key, public_key_length, - &public_key_length)); + status = psa_export_public_key(key, + public_key, public_key_length, + &public_key_length); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + status = PSA_SUCCESS; + goto exit; + } status = psa_raw_key_agreement(alg, key, public_key, public_key_length, output, sizeof(output), &output_length); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + status = PSA_SUCCESS; + goto exit; + } if (status == PSA_SUCCESS) { TEST_ASSERT(output_length <= PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE(private_key_type, @@ -717,14 +731,16 @@ exit: static int exercise_raw_key_agreement_key(mbedtls_svc_key_id_t key, psa_key_usage_t usage, - psa_algorithm_t alg) + psa_algorithm_t alg, + int key_destroyable) { int ok = 0; if (usage & PSA_KEY_USAGE_DERIVE) { /* We need two keys to exercise key agreement. Exercise the * private key against its own public key. */ - PSA_ASSERT(mbedtls_test_psa_raw_key_agreement_with_self(alg, key)); + PSA_ASSERT(mbedtls_test_psa_raw_key_agreement_with_self(alg, key, + key_destroyable)); } ok = 1; diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index 7ef8618ef..939095837 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -2572,7 +2572,7 @@ void raw_agreement_key_policy(int policy_usage, PSA_ASSERT(psa_import_key(&attributes, key_data->x, key_data->len, &key)); - status = mbedtls_test_psa_raw_key_agreement_with_self(exercise_alg, key); + status = mbedtls_test_psa_raw_key_agreement_with_self(exercise_alg, key, 0); TEST_EQUAL(status, expected_status); From 73e4ea37f497bb43937b55e826cb955461e257b3 Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Tue, 12 Mar 2024 16:29:55 +0000 Subject: [PATCH 10/17] Add key_destroyable parameter to non-raw key agreement smoke tests All current usages have this parameter set to 0 (this means the tests are unchanged). Remove the GENERIC_ERROR return behaviour, in favour of returning the actual status. Signed-off-by: Ryan Everett --- tests/include/test/psa_exercise_key.h | 5 ++- tests/src/psa_exercise_key.c | 43 +++++++++++++++------ tests/suites/test_suite_psa_crypto.function | 4 +- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/tests/include/test/psa_exercise_key.h b/tests/include/test/psa_exercise_key.h index 23349166a..f656b95f8 100644 --- a/tests/include/test/psa_exercise_key.h +++ b/tests/include/test/psa_exercise_key.h @@ -168,12 +168,15 @@ psa_status_t mbedtls_test_psa_raw_key_agreement_with_self( * \p key. * \param key A key pair object that is suitable for a key * agreement with \p operation. + * \param key_destroyable If set to 1, a failure due to the key not existing + * or the key being destroyed mid-operation will only + * be reported if the error code is unexpected. * * \return \c 1 on success, \c 0 on failure. */ psa_status_t mbedtls_test_psa_key_agreement_with_self( psa_key_derivation_operation_t *operation, - mbedtls_svc_key_id_t key); + mbedtls_svc_key_id_t key, int key_destroyable); /** Perform sanity checks on the given key representation. * diff --git a/tests/src/psa_exercise_key.c b/tests/src/psa_exercise_key.c index b62a34b5d..1cf45ac56 100644 --- a/tests/src/psa_exercise_key.c +++ b/tests/src/psa_exercise_key.c @@ -628,31 +628,45 @@ exit: * private key against its own public key. */ psa_status_t mbedtls_test_psa_key_agreement_with_self( psa_key_derivation_operation_t *operation, - mbedtls_svc_key_id_t key) + mbedtls_svc_key_id_t key, int key_destroyable) { psa_key_type_t private_key_type; psa_key_type_t public_key_type; size_t key_bits; uint8_t *public_key = NULL; size_t public_key_length; - /* Return GENERIC_ERROR if something other than the final call to - * psa_key_derivation_key_agreement fails. This isn't fully satisfactory, - * but it's good enough: callers will report it as a failed test anyway. */ - psa_status_t status = PSA_ERROR_GENERIC_ERROR; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - PSA_ASSERT(psa_get_key_attributes(key, &attributes)); + psa_status_t status = psa_get_key_attributes(key, &attributes); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + psa_reset_key_attributes(&attributes); + return PSA_SUCCESS; + } + PSA_ASSERT(status); + private_key_type = psa_get_key_type(&attributes); key_bits = psa_get_key_bits(&attributes); public_key_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(private_key_type); public_key_length = PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(public_key_type, key_bits); TEST_CALLOC(public_key, public_key_length); - PSA_ASSERT(psa_export_public_key(key, public_key, public_key_length, - &public_key_length)); + status = psa_export_public_key(key, public_key, public_key_length, + &public_key_length); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + status = PSA_SUCCESS; + goto exit; + } + PSA_ASSERT(status); status = psa_key_derivation_key_agreement( operation, PSA_KEY_DERIVATION_INPUT_SECRET, key, public_key, public_key_length); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + status = PSA_SUCCESS; + goto exit; + } exit: /* * Key attributes may have been returned by psa_get_key_attributes() @@ -750,7 +764,8 @@ exit: static int exercise_key_agreement_key(mbedtls_svc_key_id_t key, psa_key_usage_t usage, - psa_algorithm_t alg) + psa_algorithm_t alg, + int key_destroyable) { psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; unsigned char input[1] = { 0 }; @@ -781,7 +796,12 @@ static int exercise_key_agreement_key(mbedtls_svc_key_id_t key, hash length. Otherwise test should fail with INVALID_ARGUMENT. */ if (PSA_ALG_IS_HKDF_EXPAND(kdf_alg)) { psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; - PSA_ASSERT(psa_get_key_attributes(key, &attributes)); + psa_status_t status = psa_get_key_attributes(key, &attributes); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + ok = 1; + } + PSA_ASSERT(status); size_t key_bits = psa_get_key_bits(&attributes); psa_algorithm_t hash_alg = PSA_ALG_HKDF_GET_HASH(kdf_alg); @@ -790,7 +810,8 @@ static int exercise_key_agreement_key(mbedtls_svc_key_id_t key, } } - TEST_EQUAL(mbedtls_test_psa_key_agreement_with_self(&operation, key), + TEST_EQUAL(mbedtls_test_psa_key_agreement_with_self(&operation, key, + key_destroyable), expected_key_agreement_status); if (expected_key_agreement_status != PSA_SUCCESS) { diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index 939095837..8fb7d44b3 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -2490,7 +2490,7 @@ void agreement_key_policy(int policy_usage, &key)); PSA_ASSERT(psa_key_derivation_setup(&operation, exercise_alg)); - status = mbedtls_test_psa_key_agreement_with_self(&operation, key); + status = mbedtls_test_psa_key_agreement_with_self(&operation, key, 0); TEST_EQUAL(status, expected_status); @@ -8681,7 +8681,7 @@ void derive_input(int alg_arg, // When taking a private key as secret input, use key agreement // to add the shared secret to the derivation TEST_EQUAL(mbedtls_test_psa_key_agreement_with_self( - &operation, keys[i]), + &operation, keys[i], 0), expected_statuses[i]); } else { TEST_EQUAL(psa_key_derivation_input_key(&operation, steps[i], From fbf815d9cb178ac7bf3a883baf56fbaaa704257f Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Tue, 12 Mar 2024 16:32:29 +0000 Subject: [PATCH 11/17] Add key_destroyable parameter to key export smoke tests These are only called from mbedtls_test_psa_exercise_key Signed-off-by: Ryan Everett --- tests/src/psa_exercise_key.c | 62 +++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/tests/src/psa_exercise_key.c b/tests/src/psa_exercise_key.c index 1cf45ac56..5aed683eb 100644 --- a/tests/src/psa_exercise_key.c +++ b/tests/src/psa_exercise_key.c @@ -1002,7 +1002,8 @@ exit: } static int exercise_export_key(mbedtls_svc_key_id_t key, - psa_key_usage_t usage) + psa_key_usage_t usage, + int key_destroyable) { psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; uint8_t *exported = NULL; @@ -1010,25 +1011,31 @@ static int exercise_export_key(mbedtls_svc_key_id_t key, size_t exported_length = 0; int ok = 0; - PSA_ASSERT(psa_get_key_attributes(key, &attributes)); + psa_status_t status = psa_get_key_attributes(key, &attributes); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + psa_reset_key_attributes(&attributes); + return 1; + } + PSA_ASSERT(status); exported_size = PSA_EXPORT_KEY_OUTPUT_SIZE( psa_get_key_type(&attributes), psa_get_key_bits(&attributes)); TEST_CALLOC(exported, exported_size); - if ((usage & PSA_KEY_USAGE_EXPORT) == 0 && - !PSA_KEY_TYPE_IS_PUBLIC_KEY(psa_get_key_type(&attributes))) { - TEST_EQUAL(psa_export_key(key, exported, - exported_size, &exported_length), - PSA_ERROR_NOT_PERMITTED); + status = psa_export_key(key, exported, exported_size, &exported_length); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + ok = 1; + goto exit; + } else if ((usage & PSA_KEY_USAGE_EXPORT) == 0 && + !PSA_KEY_TYPE_IS_PUBLIC_KEY(psa_get_key_type(&attributes))) { + TEST_EQUAL(status, PSA_ERROR_NOT_PERMITTED); ok = 1; goto exit; } - - PSA_ASSERT(psa_export_key(key, - exported, exported_size, - &exported_length)); + PSA_ASSERT(status); ok = mbedtls_test_psa_exported_key_sanity_check( psa_get_key_type(&attributes), psa_get_key_bits(&attributes), exported, exported_length); @@ -1044,7 +1051,8 @@ exit: return ok; } -static int exercise_export_public_key(mbedtls_svc_key_id_t key) +static int exercise_export_public_key(mbedtls_svc_key_id_t key, + int key_destroyable) { psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; psa_key_type_t public_type; @@ -1053,16 +1061,27 @@ static int exercise_export_public_key(mbedtls_svc_key_id_t key) size_t exported_length = 0; int ok = 0; - PSA_ASSERT(psa_get_key_attributes(key, &attributes)); + psa_status_t status = psa_get_key_attributes(key, &attributes); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + psa_reset_key_attributes(&attributes); + return 1; + } + PSA_ASSERT(status); if (!PSA_KEY_TYPE_IS_ASYMMETRIC(psa_get_key_type(&attributes))) { exported_size = PSA_EXPORT_KEY_OUTPUT_SIZE( psa_get_key_type(&attributes), psa_get_key_bits(&attributes)); TEST_CALLOC(exported, exported_size); - TEST_EQUAL(psa_export_public_key(key, exported, - exported_size, &exported_length), - PSA_ERROR_INVALID_ARGUMENT); + status = psa_export_public_key(key, exported, + exported_size, &exported_length); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + ok = 1; + goto exit; + } + TEST_EQUAL(status, PSA_ERROR_INVALID_ARGUMENT); ok = 1; goto exit; } @@ -1073,9 +1092,14 @@ static int exercise_export_public_key(mbedtls_svc_key_id_t key) psa_get_key_bits(&attributes)); TEST_CALLOC(exported, exported_size); - PSA_ASSERT(psa_export_public_key(key, - exported, exported_size, - &exported_length)); + status = psa_export_public_key(key, exported, + exported_size, &exported_length); + if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) { + /* The key has been destroyed. */ + ok = 1; + goto exit; + } + PSA_ASSERT(status); ok = mbedtls_test_psa_exported_key_sanity_check( public_type, psa_get_key_bits(&attributes), exported, exported_length); From 50619991c8a49412536fc207bfefa69a15c76161 Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Tue, 12 Mar 2024 16:55:14 +0000 Subject: [PATCH 12/17] Add test function for concurrently using the same persistent key The thread functions can also be used in future tests for other key types and other test scenarios Signed-off-by: Ryan Everett --- tests/suites/test_suite_psa_crypto.function | 193 ++++++++++++++++++++ 1 file changed, 193 insertions(+) diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index 8fb7d44b3..6cb074449 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -1338,6 +1338,127 @@ exit: } #if defined(MBEDTLS_THREADING_PTHREAD) + +typedef struct same_key_context { + data_t *data; + mbedtls_svc_key_id_t key; + psa_key_attributes_t *attributes; + int type; + int bits; + /* The following two parameters are used to ensure that when multiple + * threads attempt to load/destroy the key, exactly one thread succeeds. */ + int key_loaded; + mbedtls_threading_mutex_t MBEDTLS_PRIVATE(key_loaded_mutex); +} +same_key_context; + +/* Attempt to import the key in ctx. This handles any valid error codes + * and reports an error for any invalid codes. This function also insures + * that once imported by some thread, all threads can use the key. */ +void *thread_import_key(void *ctx) +{ + mbedtls_svc_key_id_t returned_key_id; + same_key_context *skc = (struct same_key_context *) ctx; + psa_key_attributes_t got_attributes = PSA_KEY_ATTRIBUTES_INIT; + + /* Import the key, exactly one thread must succceed. */ + psa_status_t status = psa_import_key(skc->attributes, skc->data->x, + skc->data->len, &returned_key_id); + switch (status) { + case PSA_SUCCESS: + if (mbedtls_mutex_lock(&skc->key_loaded_mutex) == 0) { + if (skc->key_loaded) { + mbedtls_mutex_unlock(&skc->key_loaded_mutex); + /* More than one thread has succeeded, report a failure. */ + TEST_EQUAL(skc->key_loaded, 0); + } + skc->key_loaded = 1; + mbedtls_mutex_unlock(&skc->key_loaded_mutex); + } + break; + case PSA_ERROR_INSUFFICIENT_MEMORY: + /* If all of the key slots are reserved when a thread + * locks the mutex to reserve a new slot, it will return + * PSA_ERROR_INSUFFICIENT_MEMORY; this is correct behaviour. + * There is a chance for this to occur here when the number of + * threads running this function is larger than the number of + * free key slots. Each thread reserves an empty key slot, + * unlocks the mutex, then relocks it to finalize key creation. + * It is at that point where the thread sees that the key + * already exists, releases the reserved slot, + * and returns PSA_ERROR_ALREADY_EXISTS. + * There is no guarantee that the key is loaded upon this return + * code, so we can't test the key information. Just stop this + * thread from executing, note that this is not an error. */ + goto exit; + break; + case PSA_ERROR_ALREADY_EXISTS: + /* The key has been loaded by a different thread. */ + break; + default: + PSA_ASSERT(status); + } + /* At this point the key must exist, test the key information. */ + status = psa_get_key_attributes(skc->key, &got_attributes); + if (status == PSA_ERROR_INSUFFICIENT_MEMORY) { + /* This is not a test failure. The following sequence of events + * causes this to occur: + * 1: This thread successfuly imports a persistent key skc->key. + * 2: N threads reserve an empty key slot in psa_import_key, + * where N is equal to the number of free key slots. + * 3: A final thread attempts to reserve an empty key slot, kicking + * skc->key (which has no registered readers) out of its slot. + * 4: This thread calls psa_get_key_attributes(skc->key,...): + * it sees that skc->key is not in a slot, attempts to load it and + * finds that there are no free slots. + * This thread returns PSA_ERROR_INSUFFICIENT_MEMORY. + * + * The PSA spec allows this behaviour, it is an unavoidable consequence + * of allowing persistent keys to be kicked out of the key store while + * they are still valid. */ + goto exit; + } + PSA_ASSERT(status); + TEST_EQUAL(psa_get_key_type(&got_attributes), skc->type); + TEST_EQUAL(psa_get_key_bits(&got_attributes), skc->bits); + +exit: + /* Key attributes may have been returned by psa_get_key_attributes(), + * reset them as required. */ + psa_reset_key_attributes(&got_attributes); + return NULL; +} + +void *thread_use_and_destroy_key(void *ctx) +{ + same_key_context *skc = (struct same_key_context *) ctx; + + /* Do something with the key according + * to its type and permitted usage. */ + TEST_ASSERT(mbedtls_test_psa_exercise_key(skc->key, + skc->attributes->policy.usage, + skc->attributes->policy.alg, 1)); + + psa_status_t status = psa_destroy_key(skc->key); + if (status == PSA_SUCCESS) { + if (mbedtls_mutex_lock(&skc->key_loaded_mutex) == 0) { + /* Ensure that we are the only thread to succeed. */ + if (skc->key_loaded != 1) { + mbedtls_mutex_unlock(&skc->key_loaded_mutex); + //Will always fail + TEST_EQUAL(skc->key_loaded, 1); + } + skc->key_loaded = 0; + mbedtls_mutex_unlock(&skc->key_loaded_mutex); + } + } else { + TEST_EQUAL(status, PSA_ERROR_INVALID_HANDLE); + } + +exit: + return NULL; +} + typedef struct generate_key_context { psa_key_type_t type; psa_key_usage_t usage; @@ -1824,6 +1945,78 @@ exit: } /* END_CASE */ + +#if defined(MBEDTLS_THREADING_PTHREAD) +/* BEGIN_CASE depends_on:MBEDTLS_THREADING_PTHREAD:MBEDTLS_PSA_CRYPTO_STORAGE_C */ +void concurrently_use_same_persistent_key(data_t *data, + int type_arg, + int bits_arg, + int alg_arg, + int thread_count_arg) +{ + size_t thread_count = (size_t) thread_count_arg; + mbedtls_test_thread_t *threads = NULL; + mbedtls_svc_key_id_t key_id = mbedtls_svc_key_id_make(1, 1); + same_key_context skc; + skc.data = data; + skc.key = key_id; + skc.type = type_arg; + skc.bits = bits_arg; + skc.key_loaded = 0; + mbedtls_mutex_init(&skc.key_loaded_mutex); + psa_key_usage_t usage = mbedtls_test_psa_usage_to_exercise(skc.type, alg_arg); + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + + PSA_ASSERT(psa_crypto_init()); + + psa_set_key_id(&attributes, key_id); + psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_PERSISTENT); + psa_set_key_usage_flags(&attributes, usage); + psa_set_key_algorithm(&attributes, alg_arg); + psa_set_key_type(&attributes, type_arg); + psa_set_key_bits(&attributes, bits_arg); + skc.attributes = &attributes; + + TEST_CALLOC(threads, sizeof(mbedtls_test_thread_t) * thread_count); + + /* Test that when multiple threads import the same key, + * exactly one thread succeeds and the rest fail with valid errors. + * Also test that all threads can use the key as soon as it has been + * imported. */ + for (size_t i = 0; i < thread_count; i++) { + TEST_EQUAL( + mbedtls_test_thread_create(&threads[i], thread_import_key, + (void *) &skc), 0); + } + + /* Join threads. */ + for (size_t i = 0; i < thread_count; i++) { + TEST_EQUAL(mbedtls_test_thread_join(&threads[i]), 0); + } + + /* Test that when multiple threads use and destroy a key no corruption + * occurs, and exactly one thread succeeds when destroying the key. */ + for (size_t i = 0; i < thread_count; i++) { + TEST_EQUAL( + mbedtls_test_thread_create(&threads[i], thread_use_and_destroy_key, + (void *) &skc), 0); + } + + /* Join threads. */ + for (size_t i = 0; i < thread_count; i++) { + TEST_EQUAL(mbedtls_test_thread_join(&threads[i]), 0); + } + /* Ensure that one thread succeeded in destroying the key. */ + TEST_ASSERT(!skc.key_loaded); +exit: + psa_reset_key_attributes(&attributes); + mbedtls_mutex_free(&skc.key_loaded_mutex); + mbedtls_free(threads); + PSA_DONE(); +} +/* END_CASE */ +#endif + /* BEGIN_CASE */ void import_and_exercise_key(data_t *data, int type_arg, From f111f35478286a558a6e5690bd2cc731924b0f13 Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Tue, 12 Mar 2024 17:00:40 +0000 Subject: [PATCH 13/17] Add test cases for concurrently_use_same_persistent_key There is a 1-1 correlation between these test cases and the test cases for import_and_exercise_key. Signed-off-by: Ryan Everett --- tests/suites/test_suite_psa_crypto.data | 44 +++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data index b633c6f60..a3a457da8 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -4278,6 +4278,50 @@ PSA import/exercise: TLS 1.2 PRF SHA-256 depends_on:PSA_WANT_ALG_SHA_256:PSA_WANT_ALG_TLS12_PRF import_and_exercise_key:"c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0":PSA_KEY_TYPE_DERIVE:192:PSA_ALG_TLS12_PRF(PSA_ALG_SHA_256) +PSA concurrently import/exercise same key: RSA keypair, PKCS#1 v1.5 raw +depends_on:PSA_WANT_ALG_RSA_PKCS1V15_SIGN:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT +concurrently_use_same_persistent_key:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_TYPE_RSA_KEY_PAIR:1024:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:100 + +PSA concurrently import/exercise same key: RSA keypair, PSS-SHA-256 +depends_on:PSA_WANT_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT +concurrently_use_same_persistent_key:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_TYPE_RSA_KEY_PAIR:1024:PSA_ALG_RSA_PSS(PSA_ALG_SHA_256):100 + +PSA concurrently import/exercise same key: RSA keypair, PSS-any-salt-SHA-256 +depends_on:PSA_WANT_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT +concurrently_use_same_persistent_key:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_TYPE_RSA_KEY_PAIR:1024:PSA_ALG_RSA_PSS(PSA_ALG_SHA_256):100 + +PSA concurrently import/exercise same key: RSA public key, PKCS#1 v1.5 raw +depends_on:PSA_WANT_ALG_RSA_PKCS1V15_SIGN:PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY +concurrently_use_same_persistent_key:"30818902818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc30203010001":PSA_KEY_TYPE_RSA_PUBLIC_KEY:1024:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:100 + +PSA concurrently import/exercise same key: RSA public key, PSS-SHA-256 +depends_on:PSA_WANT_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY +concurrently_use_same_persistent_key:"30818902818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc30203010001":PSA_KEY_TYPE_RSA_PUBLIC_KEY:1024:PSA_ALG_RSA_PSS(PSA_ALG_SHA_256):100 + +PSA concurrently import/exercise same key: RSA public key, PSS-any-salt-SHA-256 +depends_on:PSA_WANT_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY +concurrently_use_same_persistent_key:"30818902818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc30203010001":PSA_KEY_TYPE_RSA_PUBLIC_KEY:1024:PSA_ALG_RSA_PSS_ANY_SALT(PSA_ALG_SHA_256):100 + +PSA concurrently import/exercise same key: ECP SECP256R1 keypair, ECDSA +depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_SECP_R1_256 +concurrently_use_same_persistent_key:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):256:PSA_ALG_ECDSA_ANY:100 + +PSA concurrently import/exercise same key: ECP SECP256R1 keypair, deterministic ECDSA +depends_on:PSA_WANT_ALG_DETERMINISTIC_ECDSA:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_SECP_R1_256 +concurrently_use_same_persistent_key:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):256:PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ):100 + +PSA concurrently import/exercise same key: ECP SECP256R1 keypair, ECDH +depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT:PSA_WANT_ECC_SECP_R1_256 +concurrently_use_same_persistent_key:"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):256:PSA_ALG_ECDH:100 + +PSA concurrently import/exercise same key: HKDF SHA-256 +depends_on:PSA_WANT_ALG_HKDF:PSA_WANT_ALG_SHA_256 +concurrently_use_same_persistent_key:"c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0":PSA_KEY_TYPE_DERIVE:192:PSA_ALG_HKDF(PSA_ALG_SHA_256):100 + +PSA concurrently import/exercise same key: TLS 1.2 PRF SHA-256 +depends_on:PSA_WANT_ALG_SHA_256:PSA_WANT_ALG_TLS12_PRF +concurrently_use_same_persistent_key:"c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0":PSA_KEY_TYPE_DERIVE:192:PSA_ALG_TLS12_PRF(PSA_ALG_SHA_256):100 + PSA sign hash: RSA PKCS#1 v1.5, raw depends_on:PSA_WANT_ALG_RSA_PKCS1V15_SIGN:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT sign_hash_deterministic:PSA_KEY_TYPE_RSA_KEY_PAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_ALG_RSA_PKCS1V15_SIGN_RAW:"616263":"2c7744983f023ac7bb1c55529d83ed11a76a7898a1bb5ce191375a4aa7495a633d27879ff58eba5a57371c34feb1180e8b850d552476ebb5634df620261992f12ebee9097041dbbea85a42d45b344be5073ceb772ffc604954b9158ba81ec3dc4d9d65e3ab7aa318165f38c36f841f1c69cb1cfa494aa5cbb4d6c0efbafb043a" From 6c488709d6bea8d2e2d23f72a6080d1c5abb3680 Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Thu, 14 Mar 2024 17:49:44 +0000 Subject: [PATCH 14/17] Fix typo in thread_import_key Signed-off-by: Ryan Everett --- tests/suites/test_suite_psa_crypto.function | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index 6cb074449..30d34264a 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -1361,7 +1361,7 @@ void *thread_import_key(void *ctx) same_key_context *skc = (struct same_key_context *) ctx; psa_key_attributes_t got_attributes = PSA_KEY_ATTRIBUTES_INIT; - /* Import the key, exactly one thread must succceed. */ + /* Import the key, exactly one thread must succeed. */ psa_status_t status = psa_import_key(skc->attributes, skc->data->x, skc->data->len, &returned_key_id); switch (status) { From 3de040f62d470dc44af1085b04c2a0c4ee0fe718 Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Thu, 14 Mar 2024 17:50:06 +0000 Subject: [PATCH 15/17] Use TEST_FAIL in threaded tests Signed-off-by: Ryan Everett --- tests/suites/test_suite_psa_crypto.function | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index 30d34264a..7a242fd73 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -1370,7 +1370,7 @@ void *thread_import_key(void *ctx) if (skc->key_loaded) { mbedtls_mutex_unlock(&skc->key_loaded_mutex); /* More than one thread has succeeded, report a failure. */ - TEST_EQUAL(skc->key_loaded, 0); + TEST_FAIL("The same key has been loaded into the key store multiple times."); } skc->key_loaded = 1; mbedtls_mutex_unlock(&skc->key_loaded_mutex); @@ -1445,8 +1445,7 @@ void *thread_use_and_destroy_key(void *ctx) /* Ensure that we are the only thread to succeed. */ if (skc->key_loaded != 1) { mbedtls_mutex_unlock(&skc->key_loaded_mutex); - //Will always fail - TEST_EQUAL(skc->key_loaded, 1); + TEST_FAIL("The same key has been destroyed multiple times."); } skc->key_loaded = 0; mbedtls_mutex_unlock(&skc->key_loaded_mutex); From 6de38ac91c2b626e4c0ac1094f0b92dadcffed05 Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Thu, 14 Mar 2024 17:50:39 +0000 Subject: [PATCH 16/17] Add missing PSA_ASSERT in mbedtls_test_psa_raw_key_agreement_with_self Signed-off-by: Ryan Everett --- tests/src/psa_exercise_key.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/src/psa_exercise_key.c b/tests/src/psa_exercise_key.c index 5aed683eb..937bd45d2 100644 --- a/tests/src/psa_exercise_key.c +++ b/tests/src/psa_exercise_key.c @@ -715,6 +715,7 @@ psa_status_t mbedtls_test_psa_raw_key_agreement_with_self( status = PSA_SUCCESS; goto exit; } + PSA_ASSERT(status); status = psa_raw_key_agreement(alg, key, public_key, public_key_length, From e1b50f38e40faffa12b9f0315e9fa2f581cc2ee0 Mon Sep 17 00:00:00 2001 From: Ryan Everett Date: Thu, 14 Mar 2024 17:51:09 +0000 Subject: [PATCH 17/17] Document unsupported concurrency scenario in psa_exercise_key Signed-off-by: Ryan Everett --- tests/include/test/psa_exercise_key.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/include/test/psa_exercise_key.h b/tests/include/test/psa_exercise_key.h index f656b95f8..f6be3073a 100644 --- a/tests/include/test/psa_exercise_key.h +++ b/tests/include/test/psa_exercise_key.h @@ -223,6 +223,14 @@ int mbedtls_test_psa_exported_key_sanity_check( * to 1, while another thread calls psa_destroy_key on the same key; * this will test whether destroying the key in use leads to any corruption. * + * There cannot be a set of concurrent calls: + * `mbedtls_test_psa_exercise_key(ki,...)` such that each ki is a unique + * persistent key not loaded into any key slot, and i is greater than the + * number of free key slots. + * This is because such scenarios can lead to unsupported + * `PSA_ERROR_INSUFFICIENT_MEMORY` return codes. + * + * * \param key The key to exercise. It should be capable of performing * \p alg. * \param usage The usage flags to assume.