diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 694fdf4d5b..f94830d836 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -928,12 +928,51 @@ psa_status_t psa_hash_abort(psa_hash_operation_t *operation); */ /** The type of the state data structure for multipart MAC operations. + * + * Before calling any function on a MAC operation object, the application must + * initialize it by any of the following means: + * - Set the structure to all-bits-zero, for example: + * \code + * psa_mac_operation_t operation; + * memset(&operation, 0, sizeof(operation)); + * \endcode + * - Initialize the structure to logical zero values, for example: + * \code + * psa_mac_operation_t operation = {0}; + * \endcode + * - Initialize the structure to the initializer #PSA_MAC_OPERATION_INIT, + * for example: + * \code + * psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; + * \endcode + * - Assign the result of the function psa_mac_operation_init() + * to the structure, for example: + * \code + * psa_mac_operation_t operation; + * operation = psa_mac_operation_init(); + * \endcode * * This is an implementation-defined \c struct. Applications should not * make any assumptions about the content of this structure except * as directed by the documentation of a specific implementation. */ typedef struct psa_mac_operation_s psa_mac_operation_t; +/** \def PSA_MAC_OPERATION_INIT + * + * This macro returns a suitable initializer for a MAC operation object of type + * #psa_mac_operation_t. + */ +#ifdef __DOXYGEN_ONLY__ +/* This is an example definition for documentation purposes. + * Implementations should define a suitable value in `crypto_struct.h`. + */ +#define PSA_MAC_OPERATION_INIT {0} +#endif + +/** Return an initial value for a MAC operation object. + */ +static psa_mac_operation_t psa_mac_operation_init(void); + /** Start a multipart MAC calculation operation. * * This function sets up the calculation of the MAC @@ -944,6 +983,8 @@ typedef struct psa_mac_operation_s psa_mac_operation_t; * The sequence of operations to calculate a MAC is as follows: * -# Allocate an operation object which will be passed to all the functions * listed here. + * -# Initialize the operation object with one of the methods described in the + * documentation for #psa_mac_operation_t, e.g. PSA_MAC_OPERATION_INIT. * -# Call psa_mac_sign_setup() to specify the algorithm and key. * The key remains associated with the operation even if the content * of the key slot changes. @@ -954,14 +995,16 @@ typedef struct psa_mac_operation_s psa_mac_operation_t; * calculating the MAC value and retrieve it. * * The application may call psa_mac_abort() at any time after the operation - * has been initialized with psa_mac_sign_setup(). + * has been initialized. * * After a successful call to psa_mac_sign_setup(), the application must * eventually terminate the operation through one of the following methods: * - A failed call to psa_mac_update(). * - A call to psa_mac_sign_finish() or psa_mac_abort(). * - * \param[out] operation The operation object to use. + * \param[in,out] operation The operation object to set up. It must have + * been initialized as per the documentation for + * #psa_mac_operation_t and not yet in use. * \param handle Handle to the key to use for the operation. * \param alg The MAC algorithm to compute (\c PSA_ALG_XXX value * such that #PSA_ALG_IS_MAC(alg) is true). @@ -996,6 +1039,8 @@ psa_status_t psa_mac_sign_setup(psa_mac_operation_t *operation, * The sequence of operations to verify a MAC is as follows: * -# Allocate an operation object which will be passed to all the functions * listed here. + * -# Initialize the operation object with one of the methods described in the + * documentation for #psa_mac_operation_t, e.g. PSA_MAC_OPERATION_INIT. * -# Call psa_mac_verify_setup() to specify the algorithm and key. * The key remains associated with the operation even if the content * of the key slot changes. @@ -1007,14 +1052,16 @@ psa_status_t psa_mac_sign_setup(psa_mac_operation_t *operation, * the expected value. * * The application may call psa_mac_abort() at any time after the operation - * has been initialized with psa_mac_verify_setup(). + * has been initialized. * * After a successful call to psa_mac_verify_setup(), the application must * eventually terminate the operation through one of the following methods: * - A failed call to psa_mac_update(). * - A call to psa_mac_verify_finish() or psa_mac_abort(). * - * \param[out] operation The operation object to use. + * \param[in,out] operation The operation object to set up. It must have + * been initialized as per the documentation for + * #psa_mac_operation_t and not yet in use. * \param handle Handle to the key to use for the operation. * \param alg The MAC algorithm to compute (\c PSA_ALG_XXX value * such that #PSA_ALG_IS_MAC(\p alg) is true). diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h index 4a6e168573..efc30b804f 100644 --- a/include/psa/crypto_struct.h +++ b/include/psa/crypto_struct.h @@ -123,6 +123,13 @@ struct psa_mac_operation_s } ctx; }; +#define PSA_MAC_OPERATION_INIT {0, 0, 0, 0, 0, 0, 0, {0}} +static inline struct psa_mac_operation_s psa_mac_operation_init( void ) +{ + const struct psa_mac_operation_s v = PSA_MAC_OPERATION_INIT; + return( v ); +} + struct psa_cipher_operation_s { psa_algorithm_t alg; diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data index 701a9a7bd3..8275a1c3ca 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -527,6 +527,9 @@ hash_verify_bad_args: PSA hash finish: bad arguments hash_finish_bad_args: +MAC operation object initializers zero properly +mac_operation_init: + PSA MAC setup: good, HMAC-SHA-256 depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C mac_setup:PSA_KEY_TYPE_HMAC:"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f":PSA_ALG_HMAC(PSA_ALG_SHA_256):PSA_SUCCESS diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index ea4a8e10db..e821165c13 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -124,7 +124,7 @@ static int exercise_mac_key( psa_key_handle_t handle, psa_key_usage_t usage, psa_algorithm_t alg ) { - psa_mac_operation_t operation; + 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 ); @@ -1445,7 +1445,7 @@ void mac_key_policy( int policy_usage, { psa_key_handle_t handle = 0; psa_key_policy_t policy = PSA_KEY_POLICY_INIT; - psa_mac_operation_t operation; + psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; psa_status_t status; unsigned char mac[PSA_MAC_MAX_SIZE]; @@ -1924,6 +1924,31 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void mac_operation_init( ) +{ + /* Test each valid way of initializing the object, except for `= {0}`, as + * Clang 5 complains when `-Wmissing-field-initializers` is used, even + * though it's OK by the C standard. We could test for this, but we'd need + * to supress the Clang warning for the test. */ + psa_mac_operation_t func = psa_mac_operation_init( ); + psa_mac_operation_t init = PSA_MAC_OPERATION_INIT; + psa_mac_operation_t zero; + + memset( &zero, 0, sizeof( zero ) ); + + /* Although not technically guaranteed by the C standard nor the PSA Crypto + * specification, we test that all valid ways of initializing the object + * have the same bit pattern. This is a stronger requirement that may not + * be valid on all platforms or PSA Crypto implementations, but implies the + * weaker actual requirement is met: that a freshly initialized object, no + * matter how it was initialized, acts the same as any other valid + * initialization. */ + TEST_EQUAL( memcmp( &func, &zero, sizeof( zero ) ), 0 ); + TEST_EQUAL( memcmp( &init, &zero, sizeof( zero ) ), 0 ); +} +/* END_CASE */ + /* BEGIN_CASE */ void mac_setup( int key_type_arg, data_t *key, @@ -1934,7 +1959,7 @@ void mac_setup( int key_type_arg, psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; psa_status_t expected_status = expected_status_arg; - psa_mac_operation_t operation; + psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; psa_key_policy_t policy = PSA_KEY_POLICY_INIT; psa_status_t status; @@ -1970,7 +1995,7 @@ void mac_sign( int key_type_arg, psa_key_handle_t handle = 0; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; - psa_mac_operation_t operation; + psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; psa_key_policy_t policy = PSA_KEY_POLICY_INIT; /* Leave a little extra room in the output buffer. At the end of the * test, we'll check that the implementation didn't overwrite onto @@ -2027,7 +2052,7 @@ void mac_verify( int key_type_arg, psa_key_handle_t handle = 0; psa_key_type_t key_type = key_type_arg; psa_algorithm_t alg = alg_arg; - psa_mac_operation_t operation; + psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT; psa_key_policy_t policy = PSA_KEY_POLICY_INIT; TEST_ASSERT( expected_mac->len <= PSA_MAC_MAX_SIZE );