diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 2bc6807b2..694fdf4d5 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -705,18 +705,59 @@ psa_status_t psa_get_key_policy(psa_key_handle_t handle, */ /** The type of the state data structure for multipart hash operations. + * + * Before calling any function on a hash operation object, the application must + * initialize it by any of the following means: + * - Set the structure to all-bits-zero, for example: + * \code + * psa_hash_operation_t operation; + * memset(&operation, 0, sizeof(operation)); + * \endcode + * - Initialize the structure to logical zero values, for example: + * \code + * psa_hash_operation_t operation = {0}; + * \endcode + * - Initialize the structure to the initializer #PSA_HASH_OPERATION_INIT, + * for example: + * \code + * psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; + * \endcode + * - Assign the result of the function psa_hash_operation_init() + * to the structure, for example: + * \code + * psa_hash_operation_t operation; + * operation = psa_hash_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_hash_operation_s psa_hash_operation_t; +/** \def PSA_HASH_OPERATION_INIT + * + * This macro returns a suitable initializer for a hash operation object + * of type #psa_hash_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_HASH_OPERATION_INIT {0} +#endif + +/** Return an initial value for a hash operation object. + */ +static psa_hash_operation_t psa_hash_operation_init(void); + /** Start a multipart hash operation. * * The sequence of operations to calculate a hash (message digest) * 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_hash_operation_t, e.g. PSA_HASH_OPERATION_INIT. * -# Call psa_hash_setup() to specify the algorithm. * -# Call psa_hash_update() zero, one or more times, passing a fragment * of the message each time. The hash that is calculated is the hash @@ -725,7 +766,7 @@ typedef struct psa_hash_operation_s psa_hash_operation_t; * To compare the hash with an expected value, call psa_hash_verify(). * * The application may call psa_hash_abort() at any time after the operation - * has been initialized with psa_hash_setup(). + * has been initialized. * * After a successful call to psa_hash_setup(), the application must * eventually terminate the operation. The following events terminate an @@ -733,7 +774,9 @@ typedef struct psa_hash_operation_s psa_hash_operation_t; * - A failed call to psa_hash_update(). * - A call to psa_hash_finish(), psa_hash_verify() or psa_hash_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_hash_operation_t and not yet in use. * \param alg The hash algorithm to compute (\c PSA_ALG_XXX value * such that #PSA_ALG_IS_HASH(\p alg) is true). * diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h index 320466f8f..4a6e16857 100644 --- a/include/psa/crypto_struct.h +++ b/include/psa/crypto_struct.h @@ -85,6 +85,13 @@ struct psa_hash_operation_s } ctx; }; +#define PSA_HASH_OPERATION_INIT {0, {0}} +static inline struct psa_hash_operation_s psa_hash_operation_init( void ) +{ + const struct psa_hash_operation_s v = PSA_HASH_OPERATION_INIT; + return( v ); +} + #if defined(MBEDTLS_MD_C) typedef struct { diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data index 09029ffde..701a9a7bd 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -471,6 +471,9 @@ PSA key policy: agreement, wrong algorithm depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECDH_C agreement_key_policy:PSA_KEY_USAGE_DERIVE:PSA_ALG_ECDH(PSA_ALG_SELECT_RAW):PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_SECP256R1):"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":PSA_ALG_FFDH(PSA_ALG_SELECT_RAW) +Hash operation object initializers zero properly +hash_operation_init: + PSA hash setup: good, SHA-1 depends_on:MBEDTLS_SHA1_C hash_setup:PSA_ALG_SHA_1:PSA_SUCCESS diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index 535879964..ea4a8e10d 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -1787,13 +1787,38 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void hash_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_hash_operation_t func = psa_hash_operation_init( ); + psa_hash_operation_t init = PSA_HASH_OPERATION_INIT; + psa_hash_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 hash_setup( int alg_arg, int expected_status_arg ) { psa_algorithm_t alg = alg_arg; psa_status_t expected_status = expected_status_arg; - psa_hash_operation_t operation; + psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; psa_status_t status; PSA_ASSERT( psa_crypto_init( ) ); @@ -1817,7 +1842,7 @@ void hash_bad_order( ) 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 }; size_t hash_len; - psa_hash_operation_t operation; + psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; PSA_ASSERT( psa_crypto_init( ) ); @@ -1853,7 +1878,7 @@ void hash_verify_bad_args( ) 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55, 0xaa, 0xbb }; size_t expected_size = PSA_HASH_SIZE( alg ); - psa_hash_operation_t operation; + psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; PSA_ASSERT( psa_crypto_init( ) ); @@ -1883,7 +1908,7 @@ void hash_finish_bad_args( ) psa_algorithm_t alg = PSA_ALG_SHA_256; unsigned char hash[PSA_HASH_MAX_SIZE]; size_t expected_size = PSA_HASH_SIZE( alg ); - psa_hash_operation_t operation; + psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; size_t hash_len; PSA_ASSERT( psa_crypto_init( ) ); diff --git a/tests/suites/test_suite_psa_crypto_hash.function b/tests/suites/test_suite_psa_crypto_hash.function index 5931a2338..bdb2f98f1 100644 --- a/tests/suites/test_suite_psa_crypto_hash.function +++ b/tests/suites/test_suite_psa_crypto_hash.function @@ -21,7 +21,7 @@ void hash_finish( int alg_arg, data_t *input, data_t *expected_hash ) psa_algorithm_t alg = alg_arg; unsigned char actual_hash[PSA_HASH_MAX_SIZE]; size_t actual_hash_length; - psa_hash_operation_t operation; + psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; PSA_ASSERT( psa_crypto_init( ) ); @@ -43,7 +43,7 @@ exit: void hash_verify( int alg_arg, data_t *input, data_t *expected_hash ) { psa_algorithm_t alg = alg_arg; - psa_hash_operation_t operation; + psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; PSA_ASSERT( psa_crypto_init( ) ); @@ -66,7 +66,7 @@ void hash_multi_part( int alg_arg, data_t *input, data_t *expected_hash ) psa_algorithm_t alg = alg_arg; unsigned char actual_hash[PSA_HASH_MAX_SIZE]; size_t actual_hash_length; - psa_hash_operation_t operation; + psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; uint32_t len = 0; PSA_ASSERT( psa_crypto_init( ) );