diff --git a/tests/include/test/drivers/aead.h b/tests/include/test/drivers/aead.h index a033e399d0..72016fe2d9 100644 --- a/tests/include/test/drivers/aead.h +++ b/tests/include/test/drivers/aead.h @@ -11,6 +11,8 @@ #include "mbedtls/build_info.h" #if defined(PSA_CRYPTO_DRIVER_TEST) +#include "test_driver_common.h" + #include typedef struct { diff --git a/tests/include/test/drivers/asymmetric_encryption.h b/tests/include/test/drivers/asymmetric_encryption.h index 0ac77087df..d2866b5ef4 100644 --- a/tests/include/test/drivers/asymmetric_encryption.h +++ b/tests/include/test/drivers/asymmetric_encryption.h @@ -11,6 +11,8 @@ #include "mbedtls/build_info.h" #if defined(PSA_CRYPTO_DRIVER_TEST) +#include "test_driver_common.h" + #include #include diff --git a/tests/include/test/drivers/cipher.h b/tests/include/test/drivers/cipher.h index 2fe47e4d7a..38c75aba72 100644 --- a/tests/include/test/drivers/cipher.h +++ b/tests/include/test/drivers/cipher.h @@ -11,6 +11,8 @@ #include "mbedtls/build_info.h" #if defined(PSA_CRYPTO_DRIVER_TEST) +#include "test_driver_common.h" + #include #include diff --git a/tests/include/test/drivers/hash.h b/tests/include/test/drivers/hash.h index ad48c45d52..4c2a050052 100644 --- a/tests/include/test/drivers/hash.h +++ b/tests/include/test/drivers/hash.h @@ -11,6 +11,8 @@ #include "mbedtls/build_info.h" #if defined(PSA_CRYPTO_DRIVER_TEST) +#include "test_driver_common.h" + #include typedef struct { diff --git a/tests/include/test/drivers/key_agreement.h b/tests/include/test/drivers/key_agreement.h index ca82b3ad96..d4b01d660b 100644 --- a/tests/include/test/drivers/key_agreement.h +++ b/tests/include/test/drivers/key_agreement.h @@ -11,6 +11,8 @@ #include "mbedtls/build_info.h" #if defined(PSA_CRYPTO_DRIVER_TEST) +#include "test_driver_common.h" + #include typedef struct { diff --git a/tests/include/test/drivers/key_management.h b/tests/include/test/drivers/key_management.h index 1d9bc43985..07d814dcd5 100644 --- a/tests/include/test/drivers/key_management.h +++ b/tests/include/test/drivers/key_management.h @@ -11,6 +11,8 @@ #include "mbedtls/build_info.h" #if defined(PSA_CRYPTO_DRIVER_TEST) +#include "test_driver_common.h" + #include #define PSA_CRYPTO_TEST_DRIVER_BUILTIN_AES_KEY_SLOT 0 diff --git a/tests/include/test/drivers/mac.h b/tests/include/test/drivers/mac.h index d92eff9038..dc741f923a 100644 --- a/tests/include/test/drivers/mac.h +++ b/tests/include/test/drivers/mac.h @@ -11,6 +11,8 @@ #include "mbedtls/build_info.h" #if defined(PSA_CRYPTO_DRIVER_TEST) +#include "test_driver_common.h" + #include typedef struct { diff --git a/tests/include/test/drivers/pake.h b/tests/include/test/drivers/pake.h index d292ca0daf..d79ed38488 100644 --- a/tests/include/test/drivers/pake.h +++ b/tests/include/test/drivers/pake.h @@ -11,6 +11,8 @@ #include "mbedtls/build_info.h" #if defined(PSA_CRYPTO_DRIVER_TEST) +#include "test_driver_common.h" + #include typedef struct { diff --git a/tests/include/test/drivers/signature.h b/tests/include/test/drivers/signature.h index 8c5703edf9..bb9d260306 100644 --- a/tests/include/test/drivers/signature.h +++ b/tests/include/test/drivers/signature.h @@ -11,6 +11,8 @@ #include "mbedtls/build_info.h" #if defined(PSA_CRYPTO_DRIVER_TEST) +#include "test_driver_common.h" + #include typedef struct { diff --git a/tests/include/test/drivers/test_driver_common.h b/tests/include/test/drivers/test_driver_common.h new file mode 100644 index 0000000000..a704adb2b4 --- /dev/null +++ b/tests/include/test/drivers/test_driver_common.h @@ -0,0 +1,28 @@ +/* Common definitions used by test drivers. */ +/* Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + */ + +#ifndef PSA_CRYPTO_TEST_DRIVERS_TEST_DRIVER_COMMON_H +#define PSA_CRYPTO_TEST_DRIVERS_TEST_DRIVER_COMMON_H + +#include "mbedtls/build_info.h" + +/* Use the same formatting for error code definitions as the standard + * error values, which must have a specific sequence of tokens for + * interoperability between implementations of different parts of PSA. + * This means no space between the cast and the - operator. + * This contradicts our code style, so we temporarily disable style checking. + * + * *INDENT-OFF* + */ + +/** Error code that test drivers return when they detect that an input + * parameter was not initialized properly. This normally indicates a + * bug in the core. + */ +#define PSA_ERROR_TEST_DETECTED_BAD_INITIALIZATION ((psa_status_t)-0x0201) + +/* *INDENT-ON* */ + +#endif /* test_driver_common.h */ diff --git a/tests/include/test/helpers.h b/tests/include/test/helpers.h index d08100f158..aff84748f0 100644 --- a/tests/include/test/helpers.h +++ b/tests/include/test/helpers.h @@ -166,6 +166,30 @@ const char *mbedtls_test_get_mutex_usage_error(void); void mbedtls_test_set_mutex_usage_error(const char *msg); #endif +/** + * \brief Check whether the given buffer is all-bits-zero. + * + * \param[in] buf Pointer to the buffer to check. + * \param size Buffer size in bytes. + * + * \retval 0 The given buffer has a nonzero byte. + * \retval 1 The given buffer is all-bits-zero (this includes the case + * of an empty buffer). + */ +int mbedtls_test_buffer_is_all_zero(const uint8_t *buf, size_t size); + +/** Check whether the object at the given address is all-bits-zero. + * + * \param[in] ptr A pointer to the object to check. + * This macro parameter may be evaluated more than once. + * + * \retval 0 The given object has a nonzero byte. + * \retval 1 The given object is all-bits-zero (this includes the case + * of an empty buffer). + */ +#define MBEDTLS_TEST_OBJECT_IS_ALL_ZERO(ptr) \ + (mbedtls_test_buffer_is_all_zero((const uint8_t *) (ptr), sizeof(*(ptr)))) + #if defined(MBEDTLS_BIGNUM_C) /** diff --git a/tests/include/test/psa_crypto_helpers.h b/tests/include/test/psa_crypto_helpers.h index 7ae0e30342..9b7dbd57a7 100644 --- a/tests/include/test/psa_crypto_helpers.h +++ b/tests/include/test/psa_crypto_helpers.h @@ -145,6 +145,35 @@ const char *mbedtls_test_helper_is_psa_leaking(void); while (0) +/** Initializer that doesn't set the embedded union to zero. + * + * Use this to validate that our code correctly handles platforms where + * `{0}` does not initialize a union to all-bits-zero, only the first member. + * Such behavior is uncommon, but compliant (see discussion in + * https://github.com/Mbed-TLS/mbedtls/issues/9814). + * You can portably simulate that behavior by using the `xxx_init_short()` + * initializer function instead of `{0}` or an official initializer + * `xxx_init()` or `XXX_INIT`. + */ +psa_hash_operation_t psa_hash_operation_init_short(void); +psa_mac_operation_t psa_mac_operation_init_short(void); +psa_cipher_operation_t psa_cipher_operation_init_short(void); +psa_aead_operation_t psa_aead_operation_init_short(void); +psa_key_derivation_operation_t psa_key_derivation_operation_init_short(void); +psa_pake_operation_t psa_pake_operation_init_short(void); +psa_sign_hash_interruptible_operation_t psa_sign_hash_interruptible_operation_init_short(void); +psa_verify_hash_interruptible_operation_t psa_verify_hash_interruptible_operation_init_short(void); +#if defined(PSA_KEY_AGREEMENT_IOP_INIT) +psa_key_agreement_iop_t psa_key_agreement_iop_init_short(void); +#endif +#if defined(PSA_GENERATE_KEY_IOP_INIT) +psa_generate_key_iop_t psa_generate_key_iop_init_short(void); +#endif +#if defined(PSA_EXPORT_PUBLIC_KEY_IOP_INIT) +psa_export_public_key_iop_t psa_export_public_key_iop_init_short(void); +#endif + + #if defined(RECORD_PSA_STATUS_COVERAGE_LOG) psa_status_t mbedtls_test_record_status(psa_status_t status, diff --git a/tests/src/drivers/test_driver_aead.c b/tests/src/drivers/test_driver_aead.c index 6992a066d2..f653d89b9b 100644 --- a/tests/src/drivers/test_driver_aead.c +++ b/tests/src/drivers/test_driver_aead.c @@ -149,6 +149,9 @@ psa_status_t mbedtls_test_transparent_aead_encrypt_setup( if (mbedtls_test_driver_aead_hooks.forced_status != PSA_SUCCESS) { mbedtls_test_driver_aead_hooks.driver_status = mbedtls_test_driver_aead_hooks.forced_status; + } else if (!MBEDTLS_TEST_OBJECT_IS_ALL_ZERO(operation)) { + mbedtls_test_driver_aead_hooks.driver_status = + PSA_ERROR_TEST_DETECTED_BAD_INITIALIZATION; } else { #if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \ defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_AEAD) @@ -186,6 +189,9 @@ psa_status_t mbedtls_test_transparent_aead_decrypt_setup( if (mbedtls_test_driver_aead_hooks.forced_status != PSA_SUCCESS) { mbedtls_test_driver_aead_hooks.driver_status = mbedtls_test_driver_aead_hooks.forced_status; + } else if (!MBEDTLS_TEST_OBJECT_IS_ALL_ZERO(operation)) { + mbedtls_test_driver_aead_hooks.driver_status = + PSA_ERROR_TEST_DETECTED_BAD_INITIALIZATION; } else { #if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \ defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_AEAD) diff --git a/tests/src/drivers/test_driver_cipher.c b/tests/src/drivers/test_driver_cipher.c index 90256fc4ea..9a9a77c702 100644 --- a/tests/src/drivers/test_driver_cipher.c +++ b/tests/src/drivers/test_driver_cipher.c @@ -139,16 +139,14 @@ psa_status_t mbedtls_test_transparent_cipher_encrypt_setup( { mbedtls_test_driver_cipher_hooks.hits++; - /* Wiping the entire struct here, instead of member-by-member. This is - * useful for the test suite, since it gives a chance of catching memory - * corruption errors should the core not have allocated (enough) memory for - * our context struct. */ - memset(operation, 0, sizeof(*operation)); - if (mbedtls_test_driver_cipher_hooks.forced_status != PSA_SUCCESS) { return mbedtls_test_driver_cipher_hooks.forced_status; } + if (!MBEDTLS_TEST_OBJECT_IS_ALL_ZERO(operation)) { + return PSA_ERROR_TEST_DETECTED_BAD_INITIALIZATION; + } + #if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \ defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_CIPHER) return libtestdriver1_mbedtls_psa_cipher_encrypt_setup( @@ -175,6 +173,10 @@ psa_status_t mbedtls_test_transparent_cipher_decrypt_setup( return mbedtls_test_driver_cipher_hooks.forced_status; } + if (!MBEDTLS_TEST_OBJECT_IS_ALL_ZERO(operation)) { + return PSA_ERROR_TEST_DETECTED_BAD_INITIALIZATION; + } + #if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \ defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_CIPHER) return libtestdriver1_mbedtls_psa_cipher_decrypt_setup( diff --git a/tests/src/drivers/test_driver_mac.c b/tests/src/drivers/test_driver_mac.c index f1cf504303..a123c22194 100644 --- a/tests/src/drivers/test_driver_mac.c +++ b/tests/src/drivers/test_driver_mac.c @@ -83,6 +83,9 @@ psa_status_t mbedtls_test_transparent_mac_sign_setup( if (mbedtls_test_driver_mac_hooks.forced_status != PSA_SUCCESS) { mbedtls_test_driver_mac_hooks.driver_status = mbedtls_test_driver_mac_hooks.forced_status; + } else if (!MBEDTLS_TEST_OBJECT_IS_ALL_ZERO(operation)) { + mbedtls_test_driver_mac_hooks.driver_status = + PSA_ERROR_TEST_DETECTED_BAD_INITIALIZATION; } else { #if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \ defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_MAC) @@ -120,6 +123,9 @@ psa_status_t mbedtls_test_transparent_mac_verify_setup( if (mbedtls_test_driver_mac_hooks.forced_status != PSA_SUCCESS) { mbedtls_test_driver_mac_hooks.driver_status = mbedtls_test_driver_mac_hooks.forced_status; + } else if (!MBEDTLS_TEST_OBJECT_IS_ALL_ZERO(operation)) { + mbedtls_test_driver_mac_hooks.driver_status = + PSA_ERROR_TEST_DETECTED_BAD_INITIALIZATION; } else { #if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \ defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_MAC) @@ -309,6 +315,9 @@ psa_status_t mbedtls_test_opaque_mac_sign_setup( if (mbedtls_test_driver_mac_hooks.forced_status != PSA_SUCCESS) { mbedtls_test_driver_mac_hooks.driver_status = mbedtls_test_driver_mac_hooks.forced_status; + } else if (!MBEDTLS_TEST_OBJECT_IS_ALL_ZERO(operation)) { + mbedtls_test_driver_mac_hooks.driver_status = + PSA_ERROR_TEST_DETECTED_BAD_INITIALIZATION; } else { (void) operation; (void) attributes; @@ -333,6 +342,9 @@ psa_status_t mbedtls_test_opaque_mac_verify_setup( if (mbedtls_test_driver_mac_hooks.forced_status != PSA_SUCCESS) { mbedtls_test_driver_mac_hooks.driver_status = mbedtls_test_driver_mac_hooks.forced_status; + } else if (!MBEDTLS_TEST_OBJECT_IS_ALL_ZERO(operation)) { + mbedtls_test_driver_mac_hooks.driver_status = + PSA_ERROR_TEST_DETECTED_BAD_INITIALIZATION; } else { (void) operation; (void) attributes; diff --git a/tests/src/drivers/test_driver_pake.c b/tests/src/drivers/test_driver_pake.c index c3ce326fe2..07d6977014 100644 --- a/tests/src/drivers/test_driver_pake.c +++ b/tests/src/drivers/test_driver_pake.c @@ -35,6 +35,9 @@ psa_status_t mbedtls_test_transparent_pake_setup( if (mbedtls_test_driver_pake_hooks.forced_setup_status != PSA_SUCCESS) { mbedtls_test_driver_pake_hooks.driver_status = mbedtls_test_driver_pake_hooks.forced_setup_status; + } else if (!MBEDTLS_TEST_OBJECT_IS_ALL_ZERO(operation)) { + mbedtls_test_driver_pake_hooks.driver_status = + PSA_ERROR_TEST_DETECTED_BAD_INITIALIZATION; } else { #if defined(MBEDTLS_TEST_LIBTESTDRIVER1) && \ defined(LIBTESTDRIVER1_MBEDTLS_PSA_BUILTIN_PAKE) diff --git a/tests/src/helpers.c b/tests/src/helpers.c index 1a157331b6..963897bdce 100644 --- a/tests/src/helpers.c +++ b/tests/src/helpers.c @@ -265,6 +265,16 @@ void mbedtls_test_set_mutex_usage_error(const char *msg) } #endif // #if defined(MBEDTLS_TEST_MUTEX_USAGE) +int mbedtls_test_buffer_is_all_zero(const uint8_t *buf, size_t size) +{ + for (size_t i = 0; i < size; i++) { + if (buf[i] != 0) { + return 0; + } + } + return 1; +} + #if defined(MBEDTLS_BIGNUM_C) unsigned mbedtls_test_get_case_uses_negative_0(void) diff --git a/tests/src/psa_crypto_helpers.c b/tests/src/psa_crypto_helpers.c index 197fd41980..9de2861e9f 100644 --- a/tests/src/psa_crypto_helpers.c +++ b/tests/src/psa_crypto_helpers.c @@ -98,6 +98,96 @@ const char *mbedtls_test_helper_is_psa_leaking(void) return NULL; } + + +psa_hash_operation_t psa_hash_operation_init_short(void) +{ + psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; + memset(&operation.ctx, '!', sizeof(operation.ctx)); + return operation; +} + +psa_mac_operation_t psa_mac_operation_init_short(void) +{ + psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; + memset(&operation.ctx, '!', sizeof(operation.ctx)); + return operation; +} + +psa_cipher_operation_t psa_cipher_operation_init_short(void) +{ + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; + memset(&operation.ctx, '!', sizeof(operation.ctx)); + return operation; +} + +psa_aead_operation_t psa_aead_operation_init_short(void) +{ + psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT; + memset(&operation.ctx, '!', sizeof(operation.ctx)); + return operation; +} + +psa_key_derivation_operation_t psa_key_derivation_operation_init_short(void) +{ + psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; + memset(&operation.ctx, '!', sizeof(operation.ctx)); + return operation; +} + +psa_pake_operation_t psa_pake_operation_init_short(void) +{ + psa_pake_operation_t operation = PSA_PAKE_OPERATION_INIT; + memset(&operation.computation_stage, '!', sizeof(operation.computation_stage)); + memset(&operation.data, '!', sizeof(operation.data)); + return operation; +} + +psa_sign_hash_interruptible_operation_t psa_sign_hash_interruptible_operation_init_short(void) +{ + psa_sign_hash_interruptible_operation_t operation = + PSA_SIGN_HASH_INTERRUPTIBLE_OPERATION_INIT; + memset(&operation.ctx, '!', sizeof(operation.ctx)); + return operation; +} + +psa_verify_hash_interruptible_operation_t psa_verify_hash_interruptible_operation_init_short(void) +{ + psa_verify_hash_interruptible_operation_t operation = + PSA_VERIFY_HASH_INTERRUPTIBLE_OPERATION_INIT; + memset(&operation.ctx, '!', sizeof(operation.ctx)); + return operation; +} + +#if defined(PSA_KEY_AGREEMENT_IOP_INIT) +psa_key_agreement_iop_t psa_key_agreement_iop_init_short(void) +{ + psa_key_agreement_iop_t operation = PSA_KEY_AGREEMENT_IOP_INIT; + /* No driver support, and thus no union, yet, at the time of writing */ + return operation; +} +#endif + +#if defined(PSA_GENERATE_KEY_IOP_INIT) +psa_generate_key_iop_t psa_generate_key_iop_init_short(void) +{ + psa_generate_key_iop_t operation = PSA_GENERATE_KEY_IOP_INIT; + /* No driver support, and thus no union, yet, at the time of writing */ + return operation; +} +#endif + +#if defined(PSA_EXPORT_PUBLIC_KEY_IOP_INIT) +psa_export_public_key_iop_t psa_export_public_key_iop_init_short(void) +{ + psa_export_public_key_iop_t operation = PSA_EXPORT_PUBLIC_KEY_IOP_INIT; + /* No driver support, and thus no union, yet, at the time of writing */ + return operation; +} +#endif + + + #if defined(RECORD_PSA_STATUS_COVERAGE_LOG) /** Name of the file where return statuses are logged by #RECORD_STATUS. */ #define STATUS_LOG_FILE_NAME "statuses.log"