Merge pull request #125 from gilles-peskine-arm/mbedtls_test_psa_raw_key_agreement_with_self-iop-consistency-framework

Add consistency checks to mbedtls_test_psa_raw_key_agreement_with_self()
This commit is contained in:
Gilles Peskine
2025-04-17 10:33:51 +02:00
committed by GitHub
2 changed files with 64 additions and 19 deletions
+15 -4
View File
@@ -138,11 +138,22 @@ int mbedtls_test_psa_setup_key_derivation_wrap(
size_t capacity, int key_destroyable);
/** Perform a key agreement using the given key pair against its public key
* using psa_raw_key_agreement() and psa_key_agreement().
* (not combined with a key derivation).
*
* The result is discarded. The purpose of this function is to smoke-test a key.
* The result is discarded. Thus this function can be used for smoke-testing
* a key, and to validate input validation, but not to validate results.
*
* In case of failure, mark the current test case as failed.
* Depending on the library version, there can be multiple interfaces for key
* agreement. This test function performs the ones that are available amongst:
* - psa_raw_key_agreement()
* - psa_key_agreement()
* - psa_key_agreement_iop_setup() and psa_key_agreement_iop_complete()
*
* Mark the current test case as failed in the following cases:
* - Operational errors such as failure to allocate memory for an intermediate
* buffer.
* - Results are not consistent between the methods that are performed:
* different statuses, or inconsistent metadata, or different shared secret.
*
* \param alg A key agreement algorithm compatible with \p key.
* \param key A key that allows key agreement with \p alg.
@@ -150,7 +161,7 @@ int mbedtls_test_psa_setup_key_derivation_wrap(
* 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.
* \return The status from psa_raw_key_agreement().
*/
psa_status_t mbedtls_test_psa_raw_key_agreement_with_self(
psa_algorithm_t alg,
+49 -15
View File
@@ -732,9 +732,9 @@ psa_status_t mbedtls_test_psa_raw_key_agreement_with_self(
}
PSA_ASSERT(status);
status = psa_raw_key_agreement(alg, key,
public_key, public_key_length,
output, sizeof(output), &output_length);
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;
@@ -749,8 +749,11 @@ psa_status_t mbedtls_test_psa_raw_key_agreement_with_self(
}
#if MBEDTLS_VERSION_MAJOR >= 4
psa_status_t raw_status = status;
psa_set_key_type(&shared_secret_attributes, PSA_KEY_TYPE_DERIVE);
psa_set_key_usage_flags(&shared_secret_attributes, PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_EXPORT);
psa_set_key_usage_flags(&shared_secret_attributes,
PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_EXPORT);
status = psa_key_agreement(key, public_key, public_key_length, alg,
&shared_secret_attributes, &shared_secret_id);
@@ -759,8 +762,15 @@ psa_status_t mbedtls_test_psa_raw_key_agreement_with_self(
/* The key has been destroyed. */
status = PSA_SUCCESS;
goto exit;
} else if (status == PSA_SUCCESS) {
}
/* In this function, we expect either success or a validation failure,
* which should be identical for raw output and key output. So flag any
* discrepancy between the two (in particular a key creation failure)
* as a test failure. */
TEST_EQUAL(raw_status, status);
if (status == PSA_SUCCESS) {
status = psa_get_key_attributes(shared_secret_id, &export_attributes);
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
/* The key has been destroyed. */
@@ -768,18 +778,21 @@ psa_status_t mbedtls_test_psa_raw_key_agreement_with_self(
goto exit;
}
exported_size = PSA_EXPORT_KEY_OUTPUT_SIZE(psa_get_key_type(&export_attributes),
psa_get_key_bits(&export_attributes));
exported_size =
PSA_EXPORT_KEY_OUTPUT_SIZE(psa_get_key_type(&export_attributes),
psa_get_key_bits(&export_attributes));
TEST_CALLOC(exported, exported_size);
status = psa_export_key(shared_secret_id, exported, exported_size, &exported_length);
status = psa_export_key(shared_secret_id,
exported, exported_size, &exported_length);
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
/* The key has been destroyed. */
status = PSA_SUCCESS;
} else {
PSA_ASSERT(status);
TEST_MEMORY_COMPARE(exported, exported_length,
output, output_length);
}
PSA_ASSERT(status);
}
#if defined(MBEDTLS_ECP_RESTARTABLE) && defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH)
@@ -798,18 +811,39 @@ psa_status_t mbedtls_test_psa_raw_key_agreement_with_self(
/* The key has been destroyed. */
status = PSA_SUCCESS;
goto exit;
} else if (status == PSA_SUCCESS) {
}
/* In this function, we expect either success or a validation failure,
* which should be identical for one-shot and interruptible. For an
* interruptible operation, we insist on detecting error conditions
* early, in setup() rather than complete(). So flag any discrepancy
* between one-shot and interruptible-setup as a test failure. */
TEST_EQUAL(raw_status, status);
if (status == PSA_SUCCESS) {
do {
status = psa_key_agreement_iop_complete(&iop_operation, &shared_secret_id);
status = psa_key_agreement_iop_complete(&iop_operation,
&shared_secret_id);
} while (status == PSA_OPERATION_INCOMPLETE);
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
/* The key has been destroyed. */
status = PSA_SUCCESS;
} else {
PSA_ASSERT(status);
status = psa_export_key(shared_secret_id,
exported, exported_size,
&exported_length);
if (key_destroyable && status == PSA_ERROR_INVALID_HANDLE) {
/* The key has been destroyed. */
status = PSA_SUCCESS;
} else {
PSA_ASSERT(status);
TEST_MEMORY_COMPARE(exported, exported_length,
output, output_length);
}
}
PSA_ASSERT(status);
}
} else {
TEST_EQUAL(psa_key_agreement_iop_setup(&iop_operation, key, public_key,