diff --git a/include/psa/crypto.h b/include/psa/crypto.h index f94830d83..c266f9fe7 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -1228,18 +1228,60 @@ psa_status_t psa_mac_abort(psa_mac_operation_t *operation); */ /** The type of the state data structure for multipart cipher operations. + * + * Before calling any function on a cipher operation object, the application + * must initialize it by any of the following means: + * - Set the structure to all-bits-zero, for example: + * \code + * psa_cipher_operation_t operation; + * memset(&operation, 0, sizeof(operation)); + * \endcode + * - Initialize the structure to logical zero values, for example: + * \code + * psa_cipher_operation_t operation = {0}; + * \endcode + * - Initialize the structure to the initializer #PSA_CIPHER_OPERATION_INIT, + * for example: + * \code + * psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; + * \endcode + * - Assign the result of the function psa_cipher_operation_init() + * to the structure, for example: + * \code + * psa_cipher_operation_t operation; + * operation = psa_cipher_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_cipher_operation_s psa_cipher_operation_t; +/** \def PSA_CIPHER_OPERATION_INIT + * + * This macro returns a suitable initializer for a cipher operation object of + * type #psa_cipher_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_CIPHER_OPERATION_INIT {0} +#endif + +/** Return an initial value for a cipher operation object. + */ +static psa_cipher_operation_t psa_cipher_operation_init(void); + /** Set the key for a multipart symmetric encryption operation. * * The sequence of operations to encrypt a message with a symmetric cipher * 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_cipher_operation_t, e.g. + * PSA_CIPHER_OPERATION_INIT. * -# Call psa_cipher_encrypt_setup() to specify the algorithm and key. * The key remains associated with the operation even if the content * of the key slot changes. @@ -1252,7 +1294,7 @@ typedef struct psa_cipher_operation_s psa_cipher_operation_t; * -# Call psa_cipher_finish(). * * The application may call psa_cipher_abort() at any time after the operation - * has been initialized with psa_cipher_encrypt_setup(). + * has been initialized. * * After a successful call to psa_cipher_encrypt_setup(), the application must * eventually terminate the operation. The following events terminate an @@ -1261,7 +1303,9 @@ typedef struct psa_cipher_operation_s psa_cipher_operation_t; * or psa_cipher_update(). * - A call to psa_cipher_finish() or psa_cipher_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_cipher_operation_t and not yet in use. * \param handle Handle to the key to use for the operation. * \param alg The cipher algorithm to compute * (\c PSA_ALG_XXX value such that @@ -1295,6 +1339,9 @@ psa_status_t psa_cipher_encrypt_setup(psa_cipher_operation_t *operation, * 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_cipher_operation_t, e.g. + * PSA_CIPHER_OPERATION_INIT. * -# Call psa_cipher_decrypt_setup() to specify the algorithm and key. * The key remains associated with the operation even if the content * of the key slot changes. @@ -1307,7 +1354,7 @@ psa_status_t psa_cipher_encrypt_setup(psa_cipher_operation_t *operation, * -# Call psa_cipher_finish(). * * The application may call psa_cipher_abort() at any time after the operation - * has been initialized with psa_cipher_decrypt_setup(). + * has been initialized. * * After a successful call to psa_cipher_decrypt_setup(), the application must * eventually terminate the operation. The following events terminate an @@ -1315,7 +1362,9 @@ psa_status_t psa_cipher_encrypt_setup(psa_cipher_operation_t *operation, * - A failed call to psa_cipher_update(). * - A call to psa_cipher_finish() or psa_cipher_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_cipher_operation_t and not yet in use. * \param handle Handle to the key to use for the operation. * \param alg The cipher algorithm to compute * (\c PSA_ALG_XXX value such that diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h index 5eb262405..ee3ecd776 100644 --- a/include/psa/crypto_struct.h +++ b/include/psa/crypto_struct.h @@ -145,6 +145,13 @@ struct psa_cipher_operation_s } ctx; }; +#define PSA_CIPHER_OPERATION_INIT {0, 0, 0, 0, 0, 0, {0}} +static inline struct psa_cipher_operation_s psa_cipher_operation_init( void ) +{ + const struct psa_cipher_operation_s v = PSA_CIPHER_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 8275a1c3c..6ba61baa4 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -755,6 +755,9 @@ PSA MAC verify: CMAC-AES-128, truncated to 4 bytes depends_on:MBEDTLS_CMAC_C:MBEDTLS_AES_C mac_verify:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":PSA_ALG_TRUNCATED_MAC(PSA_ALG_CMAC, 4):"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411":"dfa66747" +Cipher operation object initializers zero properly +cipher_operation_init: + PSA cipher setup: good, AES-CTR depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR cipher_setup:PSA_KEY_TYPE_AES:"000102030405060708090a0b0c0d0e0f":PSA_ALG_CTR:PSA_SUCCESS diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index e821165c1..0ed374918 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -165,7 +165,7 @@ static int exercise_cipher_key( psa_key_handle_t handle, psa_key_usage_t usage, psa_algorithm_t alg ) { - psa_cipher_operation_t operation; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; unsigned char iv[16] = {0}; size_t iv_length = sizeof( iv ); const unsigned char plaintext[16] = "Hello, world..."; @@ -1153,7 +1153,7 @@ void cipher_with_no_key_activity( ) psa_key_handle_t handle = 0; psa_status_t status; psa_key_policy_t policy = PSA_KEY_POLICY_INIT; - psa_cipher_operation_t operation; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; int exercise_alg = PSA_ALG_CTR; PSA_ASSERT( psa_crypto_init( ) ); @@ -1210,7 +1210,7 @@ void cipher_after_import_failure( data_t *data, int type_arg, int expected_import_status_arg ) { psa_key_handle_t handle = 0; - psa_cipher_operation_t operation; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; psa_key_type_t type = type_arg; psa_status_t status; psa_status_t expected_import_status = expected_import_status_arg; @@ -1492,7 +1492,7 @@ void cipher_key_policy( int policy_usage, { psa_key_handle_t handle = 0; psa_key_policy_t policy = PSA_KEY_POLICY_INIT; - psa_cipher_operation_t operation; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; psa_status_t status; PSA_ASSERT( psa_crypto_init( ) ); @@ -2082,6 +2082,31 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void cipher_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_cipher_operation_t func = psa_cipher_operation_init( ); + psa_cipher_operation_t init = PSA_CIPHER_OPERATION_INIT; + psa_cipher_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 cipher_setup( int key_type_arg, data_t *key, @@ -2092,7 +2117,7 @@ void cipher_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_cipher_operation_t operation; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; psa_key_policy_t policy = PSA_KEY_POLICY_INIT; psa_status_t status; @@ -2133,7 +2158,7 @@ void cipher_encrypt( int alg_arg, int key_type_arg, size_t output_buffer_size = 0; size_t function_output_length = 0; size_t total_output_length = 0; - psa_cipher_operation_t operation; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; psa_key_policy_t policy = PSA_KEY_POLICY_INIT; iv_size = PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ); @@ -2200,7 +2225,7 @@ void cipher_encrypt_multipart( int alg_arg, int key_type_arg, size_t output_buffer_size = 0; size_t function_output_length = 0; size_t total_output_length = 0; - psa_cipher_operation_t operation; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; psa_key_policy_t policy = PSA_KEY_POLICY_INIT; iv_size = PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ); @@ -2270,7 +2295,7 @@ void cipher_decrypt_multipart( int alg_arg, int key_type_arg, size_t output_buffer_size = 0; size_t function_output_length = 0; size_t total_output_length = 0; - psa_cipher_operation_t operation; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; psa_key_policy_t policy = PSA_KEY_POLICY_INIT; iv_size = PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ); @@ -2342,7 +2367,7 @@ void cipher_decrypt( int alg_arg, int key_type_arg, size_t output_buffer_size = 0; size_t function_output_length = 0; size_t total_output_length = 0; - psa_cipher_operation_t operation; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; psa_key_policy_t policy = PSA_KEY_POLICY_INIT; iv_size = PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ); @@ -2412,8 +2437,8 @@ void cipher_verify_output( int alg_arg, int key_type_arg, size_t output2_size = 0; size_t output2_length = 0; size_t function_output_length = 0; - psa_cipher_operation_t operation1; - psa_cipher_operation_t operation2; + psa_cipher_operation_t operation1 = PSA_CIPHER_OPERATION_INIT; + psa_cipher_operation_t operation2 = PSA_CIPHER_OPERATION_INIT; psa_key_policy_t policy = PSA_KEY_POLICY_INIT; PSA_ASSERT( psa_crypto_init( ) ); @@ -2497,8 +2522,8 @@ void cipher_verify_output_multipart( int alg_arg, size_t output2_buffer_size = 0; size_t output2_length = 0; size_t function_output_length; - psa_cipher_operation_t operation1; - psa_cipher_operation_t operation2; + psa_cipher_operation_t operation1 = PSA_CIPHER_OPERATION_INIT; + psa_cipher_operation_t operation2 = PSA_CIPHER_OPERATION_INIT; psa_key_policy_t policy = PSA_KEY_POLICY_INIT; PSA_ASSERT( psa_crypto_init( ) );