diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 751c3803b..28211f2d0 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -1048,6 +1048,24 @@ psa_status_t psa_hash_verify(psa_hash_operation_t *operation, */ psa_status_t psa_hash_abort(psa_hash_operation_t *operation); +/** Clone a hash operation. + * + * \param[in] source_operation The active hash operation to clone. + * \param[in,out] target_operation The operation object to set up. + * It must be initialized but not active. + * + * \retval #PSA_SUCCESS + * \retval #PSA_ERROR_BAD_STATE + * \p source_operation is not an active hash operation. + * \retval #PSA_ERROR_BAD_STATE + * \p source_operation is active. + * \retval #PSA_ERROR_COMMUNICATION_FAILURE + * \retval #PSA_ERROR_HARDWARE_FAILURE + * \retval #PSA_ERROR_TAMPERING_DETECTED + */ +psa_status_t psa_hash_clone(const psa_hash_operation_t *source_operation, + psa_hash_operation_t *target_operation); + /**@}*/ /** \defgroup MAC Message authentication codes diff --git a/library/psa_crypto.c b/library/psa_crypto.c index be196e59a..a00c7d6ad 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -1507,6 +1507,67 @@ psa_status_t psa_hash_verify( psa_hash_operation_t *operation, return( PSA_SUCCESS ); } +psa_status_t psa_hash_clone(const psa_hash_operation_t *source_operation, + psa_hash_operation_t *target_operation) +{ + if( target_operation->alg != 0 ) + return( PSA_ERROR_BAD_STATE ); + + switch( source_operation->alg ) + { + case 0: + return( PSA_ERROR_BAD_STATE ); +#if defined(MBEDTLS_MD2_C) + case PSA_ALG_MD2: + mbedtls_md2_clone( &target_operation->ctx.md2, + &source_operation->ctx.md2 ); + break; +#endif +#if defined(MBEDTLS_MD4_C) + case PSA_ALG_MD4: + mbedtls_md4_clone( &target_operation->ctx.md4, + &source_operation->ctx.md4 ); + break; +#endif +#if defined(MBEDTLS_MD5_C) + case PSA_ALG_MD5: + mbedtls_md5_clone( &target_operation->ctx.md5, + &source_operation->ctx.md5 ); + break; +#endif +#if defined(MBEDTLS_RIPEMD160_C) + case PSA_ALG_RIPEMD160: + mbedtls_ripemd160_clone( &target_operation->ctx.ripemd160, + &source_operation->ctx.ripemd160 ); + break; +#endif +#if defined(MBEDTLS_SHA1_C) + case PSA_ALG_SHA_1: + mbedtls_sha1_clone( &target_operation->ctx.sha1, + &source_operation->ctx.sha1 ); + break; +#endif +#if defined(MBEDTLS_SHA256_C) + case PSA_ALG_SHA_224: + case PSA_ALG_SHA_256: + mbedtls_sha256_clone( &target_operation->ctx.sha256, + &source_operation->ctx.sha256 ); + break; +#endif +#if defined(MBEDTLS_SHA512_C) + case PSA_ALG_SHA_384: + case PSA_ALG_SHA_512: + mbedtls_sha512_clone( &target_operation->ctx.sha512, + &source_operation->ctx.sha512 ); + break; +#endif + default: + return( PSA_ERROR_NOT_SUPPORTED ); + } + + target_operation->alg = source_operation->alg; + return( PSA_SUCCESS ); +} /****************************************************************/ diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data index 36fbbed9e..f660809d5 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -544,6 +544,12 @@ hash_verify_bad_args: PSA hash finish: bad arguments hash_finish_bad_args: +PSA hash clone: source state +hash_clone_source_state: + +PSA hash clone: target state +hash_clone_target_state: + MAC operation object initializers zero properly mac_operation_init: diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index 4d0b2dcf1..7846aaf52 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -1924,6 +1924,92 @@ exit: } /* END_CASE */ +/* BEGIN_CASE depends_on:MBEDTLS_SHA256_C */ +void hash_clone_source_state( ) +{ + psa_algorithm_t alg = PSA_ALG_SHA_256; + unsigned char hash[PSA_HASH_MAX_SIZE]; + psa_hash_operation_t op_source = PSA_HASH_OPERATION_INIT; + psa_hash_operation_t op_init = PSA_HASH_OPERATION_INIT; + psa_hash_operation_t op_setup = PSA_HASH_OPERATION_INIT; + psa_hash_operation_t op_finished = PSA_HASH_OPERATION_INIT; + psa_hash_operation_t op_aborted = PSA_HASH_OPERATION_INIT; + size_t hash_len; + + PSA_ASSERT( psa_crypto_init( ) ); + PSA_ASSERT( psa_hash_setup( &op_source, alg ) ); + + PSA_ASSERT( psa_hash_setup( &op_setup, alg ) ); + PSA_ASSERT( psa_hash_setup( &op_finished, alg ) ); + PSA_ASSERT( psa_hash_finish( &op_finished, + hash, sizeof( hash ), &hash_len ) ); + PSA_ASSERT( psa_hash_setup( &op_aborted, alg ) ); + PSA_ASSERT( psa_hash_abort( &op_aborted ) ); + + TEST_EQUAL( psa_hash_clone( &op_source, &op_setup ), + PSA_ERROR_BAD_STATE ); + + PSA_ASSERT( psa_hash_clone( &op_source, &op_init ) ); + PSA_ASSERT( psa_hash_finish( &op_init, + hash, sizeof( hash ), &hash_len ) ); + PSA_ASSERT( psa_hash_clone( &op_source, &op_finished ) ); + PSA_ASSERT( psa_hash_finish( &op_finished, + hash, sizeof( hash ), &hash_len ) ); + PSA_ASSERT( psa_hash_clone( &op_source, &op_aborted ) ); + PSA_ASSERT( psa_hash_finish( &op_aborted, + hash, sizeof( hash ), &hash_len ) ); + +exit: + psa_hash_abort( &op_source ); + psa_hash_abort( &op_init ); + psa_hash_abort( &op_setup ); + psa_hash_abort( &op_finished ); + psa_hash_abort( &op_aborted ); + mbedtls_psa_crypto_free( ); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_SHA256_C */ +void hash_clone_target_state( ) +{ + psa_algorithm_t alg = PSA_ALG_SHA_256; + unsigned char hash[PSA_HASH_MAX_SIZE]; + psa_hash_operation_t op_init = PSA_HASH_OPERATION_INIT; + psa_hash_operation_t op_setup = PSA_HASH_OPERATION_INIT; + psa_hash_operation_t op_finished = PSA_HASH_OPERATION_INIT; + psa_hash_operation_t op_aborted = PSA_HASH_OPERATION_INIT; + psa_hash_operation_t op_target = PSA_HASH_OPERATION_INIT; + size_t hash_len; + + PSA_ASSERT( psa_crypto_init( ) ); + + PSA_ASSERT( psa_hash_setup( &op_setup, alg ) ); + PSA_ASSERT( psa_hash_setup( &op_finished, alg ) ); + PSA_ASSERT( psa_hash_finish( &op_finished, + hash, sizeof( hash ), &hash_len ) ); + PSA_ASSERT( psa_hash_setup( &op_aborted, alg ) ); + PSA_ASSERT( psa_hash_abort( &op_aborted ) ); + + PSA_ASSERT( psa_hash_clone( &op_setup, &op_target ) ); + PSA_ASSERT( psa_hash_finish( &op_target, + hash, sizeof( hash ), &hash_len ) ); + + TEST_EQUAL( psa_hash_clone( &op_init, &op_target ), PSA_ERROR_BAD_STATE ); + TEST_EQUAL( psa_hash_clone( &op_finished, &op_target ), + PSA_ERROR_BAD_STATE ); + TEST_EQUAL( psa_hash_clone( &op_aborted, &op_target ), + PSA_ERROR_BAD_STATE ); + +exit: + psa_hash_abort( &op_target ); + psa_hash_abort( &op_init ); + psa_hash_abort( &op_setup ); + psa_hash_abort( &op_finished ); + psa_hash_abort( &op_aborted ); + mbedtls_psa_crypto_free( ); +} +/* END_CASE */ + /* BEGIN_CASE */ void mac_operation_init( ) { diff --git a/tests/suites/test_suite_psa_crypto_hash.function b/tests/suites/test_suite_psa_crypto_hash.function index bdb2f98f1..8abd4e228 100644 --- a/tests/suites/test_suite_psa_crypto_hash.function +++ b/tests/suites/test_suite_psa_crypto_hash.function @@ -67,6 +67,7 @@ void hash_multi_part( int alg_arg, data_t *input, data_t *expected_hash ) unsigned char actual_hash[PSA_HASH_MAX_SIZE]; size_t actual_hash_length; psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT; + psa_hash_operation_t operation2 = PSA_HASH_OPERATION_INIT; uint32_t len = 0; PSA_ASSERT( psa_crypto_init( ) ); @@ -78,16 +79,23 @@ void hash_multi_part( int alg_arg, data_t *input, data_t *expected_hash ) PSA_ASSERT( psa_hash_update( &operation, input->x, len ) ); + PSA_ASSERT( psa_hash_clone( &operation, &operation2 ) ); PSA_ASSERT( psa_hash_update( &operation, input->x + len, input->len - len ) ); + PSA_ASSERT( psa_hash_update( &operation2, + input->x + len, input->len - len ) ); PSA_ASSERT( psa_hash_finish( &operation, actual_hash, sizeof( actual_hash ), &actual_hash_length ) ); - ASSERT_COMPARE( expected_hash->x, expected_hash->len, actual_hash, actual_hash_length ); + PSA_ASSERT( psa_hash_finish( &operation2, + actual_hash, sizeof( actual_hash ), + &actual_hash_length ) ); + ASSERT_COMPARE( expected_hash->x, expected_hash->len, + actual_hash, actual_hash_length ); } while( len++ != input->len ); exit: