diff --git a/ChangeLog.d/add_cipher_transparent_driver.txt b/ChangeLog.d/add_cipher_transparent_driver.txt new file mode 100644 index 0000000000..ce6f33d0d6 --- /dev/null +++ b/ChangeLog.d/add_cipher_transparent_driver.txt @@ -0,0 +1,4 @@ +Features + * Partial implementation of the new PSA Crypto accelerator APIs for + enabling symmetric cipher acceleration through crypto accelerators. + Contributed by Steven Cooreman in #3644. diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h index 67c53db928..a85a9bf4db 100644 --- a/include/psa/crypto_struct.h +++ b/include/psa/crypto_struct.h @@ -77,6 +77,16 @@ extern "C" { #include "mbedtls/sha256.h" #include "mbedtls/sha512.h" +typedef struct { + /** Unique ID indicating which driver got assigned to do the + * operation. Since driver contexts are driver-specific, swapping + * drivers halfway through the operation is not supported. + * ID values are auto-generated in psa_driver_wrappers.h */ + unsigned int id; + /** Context structure for the assigned driver, when id is not zero. */ + void* ctx; +} psa_operation_driver_context_t; + struct psa_hash_operation_s { psa_algorithm_t alg; @@ -158,16 +168,18 @@ struct psa_cipher_operation_s unsigned int key_set : 1; unsigned int iv_required : 1; unsigned int iv_set : 1; + unsigned int mbedtls_in_use : 1; /* Indicates mbed TLS is handling the operation. */ uint8_t iv_size; uint8_t block_size; union { unsigned dummy; /* Enable easier initializing of the union. */ mbedtls_cipher_context_t cipher; + psa_operation_driver_context_t driver; } ctx; }; -#define PSA_CIPHER_OPERATION_INIT {0, 0, 0, 0, 0, 0, {0}} +#define PSA_CIPHER_OPERATION_INIT {0, 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; diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 04ef28b0c6..931e2e9157 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -4037,34 +4037,6 @@ rsa_exit: /* Symmetric cryptography */ /****************************************************************/ -/* Initialize the cipher operation structure. Once this function has been - * called, psa_cipher_abort can run and will do the right thing. */ -static psa_status_t psa_cipher_init( psa_cipher_operation_t *operation, - psa_algorithm_t alg ) -{ - if( ! PSA_ALG_IS_CIPHER( alg ) ) - { - memset( operation, 0, sizeof( *operation ) ); - return( PSA_ERROR_INVALID_ARGUMENT ); - } - - operation->alg = alg; - operation->key_set = 0; - operation->iv_set = 0; - if( alg == PSA_ALG_ECB_NO_PADDING ) - { - operation->iv_required = 0; - } - else - { - operation->iv_required = 1; - } - operation->iv_size = 0; - operation->block_size = 0; - mbedtls_cipher_init( &operation->ctx.cipher ); - return( PSA_SUCCESS ); -} - static psa_status_t psa_cipher_setup( psa_cipher_operation_t *operation, psa_key_handle_t handle, psa_algorithm_t alg, @@ -4081,19 +4053,63 @@ static psa_status_t psa_cipher_setup( psa_cipher_operation_t *operation, /* A context must be freshly initialized before it can be set up. */ if( operation->alg != 0 ) - { return( PSA_ERROR_BAD_STATE ); - } - status = psa_cipher_init( operation, alg ); - if( status != PSA_SUCCESS ) - return( status ); + /* The requested algorithm must be one that can be processed by cipher. */ + if( ! PSA_ALG_IS_CIPHER( alg ) ) + return( PSA_ERROR_INVALID_ARGUMENT ); - status = psa_get_transparent_key( handle, &slot, usage, alg); + /* Fetch key material from key storage. */ + status = psa_get_key_from_slot( handle, &slot, usage, alg ); if( status != PSA_SUCCESS ) goto exit; - key_bits = psa_get_key_slot_bits( slot ); + /* Initialize the operation struct members, except for alg. The alg member + * is used to indicate to psa_cipher_abort that there are resources to free, + * so we only set it after resources have been allocated/initialized. */ + operation->key_set = 0; + operation->iv_set = 0; + operation->mbedtls_in_use = 0; + operation->iv_size = 0; + operation->block_size = 0; + if( alg == PSA_ALG_ECB_NO_PADDING ) + operation->iv_required = 0; + else + operation->iv_required = 1; + + /* Try doing the operation through a driver before using software fallback. */ + if( cipher_operation == MBEDTLS_ENCRYPT ) + status = psa_driver_wrapper_cipher_encrypt_setup( &operation->ctx.driver, + slot, + alg ); + else + status = psa_driver_wrapper_cipher_decrypt_setup( &operation->ctx.driver, + slot, + alg ); + + if( status == PSA_SUCCESS ) + { + /* Once the driver context is initialised, it needs to be freed using + * psa_cipher_abort. Indicate this through setting alg. */ + operation->alg = alg; + } + + if( status != PSA_ERROR_NOT_SUPPORTED || + psa_key_lifetime_is_external( slot->attr.lifetime ) ) + goto exit; + + /* Proceed with initializing an mbed TLS cipher context if no driver is + * available for the given algorithm & key. */ + mbedtls_cipher_init( &operation->ctx.cipher ); + + /* Once the cipher context is initialised, it needs to be freed using + * psa_cipher_abort. Indicate there is something to be freed through setting + * alg, and indicate the operation is being done using mbedtls crypto through + * setting mbedtls_in_use. */ + operation->alg = alg; + operation->mbedtls_in_use = 1; + + key_bits = psa_get_key_slot_bits( slot ); cipher_info = mbedtls_cipher_info_from_psa( alg, slot->attr.type, key_bits, NULL ); if( cipher_info == NULL ) { @@ -4146,7 +4162,6 @@ static psa_status_t psa_cipher_setup( psa_cipher_operation_t *operation, goto exit; #endif //MBEDTLS_CIPHER_MODE_WITH_PADDING - operation->key_set = 1; operation->block_size = ( PSA_ALG_IS_STREAM_CIPHER( alg ) ? 1 : PSA_BLOCK_CIPHER_BLOCK_SIZE( slot->attr.type ) ); if( ( alg & PSA_ALG_CIPHER_FROM_BLOCK_FLAG ) != 0 && @@ -4160,10 +4175,17 @@ static psa_status_t psa_cipher_setup( psa_cipher_operation_t *operation, operation->iv_size = 12; #endif + status = PSA_SUCCESS; + exit: - if( status == 0 ) + if( ret != 0 ) status = mbedtls_to_psa_error( ret ); - if( status != 0 ) + if( status == PSA_SUCCESS ) + { + /* Update operation flags for both driver and software implementations */ + operation->key_set = 1; + } + else psa_cipher_abort( operation ); return( status ); } @@ -4193,6 +4215,16 @@ psa_status_t psa_cipher_generate_iv( psa_cipher_operation_t *operation, { return( PSA_ERROR_BAD_STATE ); } + + if( operation->mbedtls_in_use == 0 ) + { + status = psa_driver_wrapper_cipher_generate_iv( &operation->ctx.driver, + iv, + iv_size, + iv_length ); + goto exit; + } + if( iv_size < operation->iv_size ) { status = PSA_ERROR_BUFFER_TOO_SMALL; @@ -4210,7 +4242,9 @@ psa_status_t psa_cipher_generate_iv( psa_cipher_operation_t *operation, status = psa_cipher_set_iv( operation, iv, *iv_length ); exit: - if( status != PSA_SUCCESS ) + if( status == PSA_SUCCESS ) + operation->iv_set = 1; + else psa_cipher_abort( operation ); return( status ); } @@ -4225,6 +4259,15 @@ psa_status_t psa_cipher_set_iv( psa_cipher_operation_t *operation, { return( PSA_ERROR_BAD_STATE ); } + + if( operation->mbedtls_in_use == 0 ) + { + status = psa_driver_wrapper_cipher_set_iv( &operation->ctx.driver, + iv, + iv_length ); + goto exit; + } + if( iv_length != operation->iv_size ) { status = PSA_ERROR_INVALID_ARGUMENT; @@ -4337,11 +4380,25 @@ psa_status_t psa_cipher_update( psa_cipher_operation_t *operation, { psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; size_t expected_output_size; - if( operation->alg == 0 ) { return( PSA_ERROR_BAD_STATE ); } + if( operation->iv_required && ! operation->iv_set ) + { + return( PSA_ERROR_BAD_STATE ); + } + + if( operation->mbedtls_in_use == 0 ) + { + status = psa_driver_wrapper_cipher_update( &operation->ctx.driver, + input, + input_length, + output, + output_size, + output_length ); + goto exit; + } if( ! PSA_ALG_IS_STREAM_CIPHER( operation->alg ) ) { @@ -4394,10 +4451,8 @@ psa_status_t psa_cipher_finish( psa_cipher_operation_t *operation, size_t *output_length ) { psa_status_t status = PSA_ERROR_GENERIC_ERROR; - int cipher_ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; uint8_t temp_output_buffer[MBEDTLS_MAX_BLOCK_LENGTH]; - - if( ! operation->key_set ) + if( operation->alg == 0 ) { return( PSA_ERROR_BAD_STATE ); } @@ -4406,6 +4461,15 @@ psa_status_t psa_cipher_finish( psa_cipher_operation_t *operation, return( PSA_ERROR_BAD_STATE ); } + if( operation->mbedtls_in_use == 0 ) + { + status = psa_driver_wrapper_cipher_finish( &operation->ctx.driver, + output, + output_size, + output_length ); + goto exit; + } + if( operation->ctx.cipher.unprocessed_len != 0 ) { if( operation->alg == PSA_ALG_ECB_NO_PADDING || @@ -4413,49 +4477,44 @@ psa_status_t psa_cipher_finish( psa_cipher_operation_t *operation, operation->ctx.cipher.operation == MBEDTLS_ENCRYPT ) ) { status = PSA_ERROR_INVALID_ARGUMENT; - goto error; + goto exit; } } - cipher_ret = mbedtls_cipher_finish( &operation->ctx.cipher, - temp_output_buffer, - output_length ); - if( cipher_ret != 0 ) - { - status = mbedtls_to_psa_error( cipher_ret ); - goto error; - } + status = mbedtls_to_psa_error( + mbedtls_cipher_finish( &operation->ctx.cipher, + temp_output_buffer, + output_length ) ); + if( status != PSA_SUCCESS ) + goto exit; if( *output_length == 0 ) ; /* Nothing to copy. Note that output may be NULL in this case. */ else if( output_size >= *output_length ) memcpy( output, temp_output_buffer, *output_length ); else - { status = PSA_ERROR_BUFFER_TOO_SMALL; - goto error; + +exit: + if( operation->mbedtls_in_use == 1 ) + mbedtls_platform_zeroize( temp_output_buffer, sizeof( temp_output_buffer ) ); + + if( status == PSA_SUCCESS ) + return( psa_cipher_abort( operation ) ); + else + { + *output_length = 0; + (void) psa_cipher_abort( operation ); + + return( status ); } - - mbedtls_platform_zeroize( temp_output_buffer, sizeof( temp_output_buffer ) ); - status = psa_cipher_abort( operation ); - - return( status ); - -error: - - *output_length = 0; - - mbedtls_platform_zeroize( temp_output_buffer, sizeof( temp_output_buffer ) ); - (void) psa_cipher_abort( operation ); - - return( status ); } psa_status_t psa_cipher_abort( psa_cipher_operation_t *operation ) { if( operation->alg == 0 ) { - /* The object has (apparently) been initialized but it is not + /* The object has (apparently) been initialized but it is not (yet) * in use. It's ok to call abort on such an object, and there's * nothing to do. */ return( PSA_SUCCESS ); @@ -4466,11 +4525,15 @@ psa_status_t psa_cipher_abort( psa_cipher_operation_t *operation ) if( ! PSA_ALG_IS_CIPHER( operation->alg ) ) return( PSA_ERROR_BAD_STATE ); - mbedtls_cipher_free( &operation->ctx.cipher ); + if( operation->mbedtls_in_use == 0 ) + psa_driver_wrapper_cipher_abort( &operation->ctx.driver ); + else + mbedtls_cipher_free( &operation->ctx.cipher ); operation->alg = 0; operation->key_set = 0; operation->iv_set = 0; + operation->mbedtls_in_use = 0; operation->iv_size = 0; operation->block_size = 0; operation->iv_required = 0; diff --git a/library/psa_crypto_driver_wrappers.c b/library/psa_crypto_driver_wrappers.c index cc51e2450e..d41209bbfb 100644 --- a/library/psa_crypto_driver_wrappers.c +++ b/library/psa_crypto_driver_wrappers.c @@ -38,6 +38,12 @@ /* Repeat above block for each JSON-declared driver during autogeneration */ +/* Auto-generated values depending on which drivers are registered. ID 0 is + * reserved for unallocated operations. */ +#if defined(PSA_CRYPTO_DRIVER_TEST) +#define PSA_CRYPTO_TRANSPARENT_TEST_DRIVER_ID (1) +#define PSA_CRYPTO_OPAQUE_TEST_DRIVER_ID (2) +#endif /* PSA_CRYPTO_DRIVER_TEST */ #endif /* MBEDTLS_PSA_CRYPTO_DRIVERS */ /* Support the 'old' SE interface when asked to */ @@ -370,4 +376,503 @@ psa_status_t psa_driver_wrapper_generate_key( const psa_key_attributes_t *attrib #endif /* PSA_CRYPTO_DRIVER_PRESENT */ } +/* + * Cipher functions + */ +psa_status_t psa_driver_wrapper_cipher_encrypt( + psa_key_slot_t *slot, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length ) +{ +#if defined(PSA_CRYPTO_DRIVER_PRESENT) && defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) + psa_status_t status = PSA_ERROR_INVALID_ARGUMENT; + psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(slot->attr.lifetime); + psa_key_attributes_t attributes = { + .core = slot->attr + }; + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = test_transparent_cipher_encrypt( &attributes, + slot->data.key.data, + slot->data.key.bytes, + alg, + input, + input_length, + output, + output_size, + output_length ); + /* Declared with fallback == true */ + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ + /* Fell through, meaning no accelerator supports this operation */ + return( PSA_ERROR_NOT_SUPPORTED ); + /* Add cases for opaque driver here */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TEST_DRIVER_LIFETIME: + return( test_opaque_cipher_encrypt( &attributes, + slot->data.key.data, + slot->data.key.bytes, + alg, + input, + input_length, + output, + output_size, + output_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ + default: + /* Key is declared with a lifetime not known to us */ + return( status ); + } +#else /* PSA_CRYPTO_DRIVER_PRESENT */ + (void) slot; + (void) alg; + (void) input; + (void) input_length; + (void) output; + (void) output_size; + (void) output_length; + + return( PSA_ERROR_NOT_SUPPORTED ); +#endif /* PSA_CRYPTO_DRIVER_PRESENT */ +} + +psa_status_t psa_driver_wrapper_cipher_decrypt( + psa_key_slot_t *slot, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length ) +{ +#if defined(PSA_CRYPTO_DRIVER_PRESENT) && defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) + psa_status_t status = PSA_ERROR_INVALID_ARGUMENT; + psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(slot->attr.lifetime); + psa_key_attributes_t attributes = { + .core = slot->attr + }; + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + status = test_transparent_cipher_decrypt( &attributes, + slot->data.key.data, + slot->data.key.bytes, + alg, + input, + input_length, + output, + output_size, + output_length ); + /* Declared with fallback == true */ + if( status != PSA_ERROR_NOT_SUPPORTED ) + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ + /* Fell through, meaning no accelerator supports this operation */ + return( PSA_ERROR_NOT_SUPPORTED ); + /* Add cases for opaque driver here */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TEST_DRIVER_LIFETIME: + return( test_opaque_cipher_decrypt( &attributes, + slot->data.key.data, + slot->data.key.bytes, + alg, + input, + input_length, + output, + output_size, + output_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ + default: + /* Key is declared with a lifetime not known to us */ + return( status ); + } +#else /* PSA_CRYPTO_DRIVER_PRESENT */ + (void) slot; + (void) alg; + (void) input; + (void) input_length; + (void) output; + (void) output_size; + (void) output_length; + + return( PSA_ERROR_NOT_SUPPORTED ); +#endif /* PSA_CRYPTO_DRIVER_PRESENT */ +} + +psa_status_t psa_driver_wrapper_cipher_encrypt_setup( + psa_operation_driver_context_t *operation, + psa_key_slot_t *slot, + psa_algorithm_t alg ) +{ +#if defined(PSA_CRYPTO_DRIVER_PRESENT) && defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) + psa_status_t status = PSA_ERROR_INVALID_ARGUMENT; + psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(slot->attr.lifetime); + psa_key_attributes_t attributes = { + .core = slot->attr + }; + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + operation->ctx = mbedtls_calloc( 1, sizeof(test_transparent_cipher_operation_t) ); + if( operation->ctx == NULL ) + return PSA_ERROR_INSUFFICIENT_MEMORY; + + status = test_transparent_cipher_encrypt_setup( operation->ctx, + &attributes, + slot->data.key.data, + slot->data.key.bytes, + alg ); + /* Declared with fallback == true */ + if( status == PSA_SUCCESS ) + operation->id = PSA_CRYPTO_TRANSPARENT_TEST_DRIVER_ID; + else + { + mbedtls_platform_zeroize( + operation->ctx, + sizeof( test_transparent_cipher_operation_t ) ); + mbedtls_free( operation->ctx ); + operation->ctx = NULL; + } + + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ + /* Fell through, meaning no accelerator supports this operation */ + return( PSA_ERROR_NOT_SUPPORTED ); + /* Add cases for opaque driver here */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TEST_DRIVER_LIFETIME: + operation->ctx = mbedtls_calloc( 1, sizeof(test_opaque_cipher_operation_t) ); + if( operation->ctx == NULL ) + return( PSA_ERROR_INSUFFICIENT_MEMORY ); + + status = test_opaque_cipher_encrypt_setup( operation->ctx, + &attributes, + slot->data.key.data, + slot->data.key.bytes, + alg ); + if( status == PSA_SUCCESS ) + operation->id = PSA_CRYPTO_OPAQUE_TEST_DRIVER_ID; + else + { + mbedtls_platform_zeroize( + operation->ctx, + sizeof( test_opaque_cipher_operation_t ) ); + mbedtls_free( operation->ctx ); + operation->ctx = NULL; + } + + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ + default: + /* Key is declared with a lifetime not known to us */ + return( PSA_ERROR_BAD_STATE ); + } +#else /* PSA_CRYPTO_DRIVER_PRESENT */ + (void)slot; + (void)alg; + (void)operation; + + return( PSA_ERROR_NOT_SUPPORTED ); +#endif /* PSA_CRYPTO_DRIVER_PRESENT */ +} + +psa_status_t psa_driver_wrapper_cipher_decrypt_setup( + psa_operation_driver_context_t *operation, + psa_key_slot_t *slot, + psa_algorithm_t alg ) +{ +#if defined(PSA_CRYPTO_DRIVER_PRESENT) && defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) + psa_status_t status = PSA_ERROR_INVALID_ARGUMENT; + psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(slot->attr.lifetime); + psa_key_attributes_t attributes = { + .core = slot->attr + }; + + switch( location ) + { + case PSA_KEY_LOCATION_LOCAL_STORAGE: + /* Key is stored in the slot in export representation, so + * cycle through all known transparent accelerators */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + operation->ctx = mbedtls_calloc( 1, sizeof(test_transparent_cipher_operation_t) ); + if( operation->ctx == NULL ) + return( PSA_ERROR_INSUFFICIENT_MEMORY ); + + status = test_transparent_cipher_decrypt_setup( operation->ctx, + &attributes, + slot->data.key.data, + slot->data.key.bytes, + alg ); + /* Declared with fallback == true */ + if( status == PSA_SUCCESS ) + operation->id = PSA_CRYPTO_TRANSPARENT_TEST_DRIVER_ID; + else + { + mbedtls_platform_zeroize( + operation->ctx, + sizeof( test_transparent_cipher_operation_t ) ); + mbedtls_free( operation->ctx ); + operation->ctx = NULL; + } + + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ + /* Fell through, meaning no accelerator supports this operation */ + return( PSA_ERROR_NOT_SUPPORTED ); + /* Add cases for opaque driver here */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TEST_DRIVER_LIFETIME: + operation->ctx = mbedtls_calloc( 1, sizeof(test_opaque_cipher_operation_t) ); + if( operation->ctx == NULL ) + return PSA_ERROR_INSUFFICIENT_MEMORY; + + status = test_opaque_cipher_decrypt_setup( operation->ctx, + &attributes, + slot->data.key.data, + slot->data.key.bytes, + alg ); + if( status == PSA_SUCCESS ) + operation->id = PSA_CRYPTO_OPAQUE_TEST_DRIVER_ID; + else + { + mbedtls_platform_zeroize( + operation->ctx, + sizeof( test_opaque_cipher_operation_t ) ); + mbedtls_free( operation->ctx ); + operation->ctx = NULL; + } + + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ + default: + /* Key is declared with a lifetime not known to us */ + return( PSA_ERROR_BAD_STATE ); + } +#else /* PSA_CRYPTO_DRIVER_PRESENT */ + (void)slot; + (void)alg; + (void)operation; + + return( PSA_ERROR_NOT_SUPPORTED ); +#endif /* PSA_CRYPTO_DRIVER_PRESENT */ +} + +psa_status_t psa_driver_wrapper_cipher_generate_iv( + psa_operation_driver_context_t *operation, + uint8_t *iv, + size_t iv_size, + size_t *iv_length ) +{ +#if defined(PSA_CRYPTO_DRIVER_PRESENT) && defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) + switch( operation->id ) + { +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TRANSPARENT_TEST_DRIVER_ID: + return( test_transparent_cipher_generate_iv( operation->ctx, + iv, + iv_size, + iv_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_OPAQUE_TEST_DRIVER_ID: + return( test_opaque_cipher_generate_iv( operation->ctx, + iv, + iv_size, + iv_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ + default: + /* Key is attached to a driver not known to us */ + return( PSA_ERROR_BAD_STATE ); + } +#else /* PSA_CRYPTO_DRIVER_PRESENT */ + (void) operation; + (void) iv; + (void) iv_size; + (void) iv_length; + + return( PSA_ERROR_NOT_SUPPORTED ); +#endif /* PSA_CRYPTO_DRIVER_PRESENT */ +} + +psa_status_t psa_driver_wrapper_cipher_set_iv( + psa_operation_driver_context_t *operation, + const uint8_t *iv, + size_t iv_length ) +{ +#if defined(PSA_CRYPTO_DRIVER_PRESENT) && defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) + switch( operation->id ) + { +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TRANSPARENT_TEST_DRIVER_ID: + return( test_transparent_cipher_set_iv( operation->ctx, + iv, + iv_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_OPAQUE_TEST_DRIVER_ID: + return( test_opaque_cipher_set_iv( operation->ctx, + iv, + iv_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ + default: + /* Key is attached to a driver not known to us */ + return( PSA_ERROR_BAD_STATE ); + } +#else /* PSA_CRYPTO_DRIVER_PRESENT */ + (void) operation; + (void) iv; + (void) iv_length; + + return( PSA_ERROR_NOT_SUPPORTED ); +#endif /* PSA_CRYPTO_DRIVER_PRESENT */ +} + +psa_status_t psa_driver_wrapper_cipher_update( + psa_operation_driver_context_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length ) +{ +#if defined(PSA_CRYPTO_DRIVER_PRESENT) && defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) + switch( operation->id ) + { +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TRANSPARENT_TEST_DRIVER_ID: + return( test_transparent_cipher_update( operation->ctx, + input, + input_length, + output, + output_size, + output_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_OPAQUE_TEST_DRIVER_ID: + return( test_opaque_cipher_update( operation->ctx, + input, + input_length, + output, + output_size, + output_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ + default: + /* Key is attached to a driver not known to us */ + return( PSA_ERROR_BAD_STATE ); + } +#else /* PSA_CRYPTO_DRIVER_PRESENT */ + (void) operation; + (void) input; + (void) input_length; + (void) output; + (void) output_length; + (void) output_size; + + return( PSA_ERROR_NOT_SUPPORTED ); +#endif /* PSA_CRYPTO_DRIVER_PRESENT */ +} + +psa_status_t psa_driver_wrapper_cipher_finish( + psa_operation_driver_context_t *operation, + uint8_t *output, + size_t output_size, + size_t *output_length ) +{ +#if defined(PSA_CRYPTO_DRIVER_PRESENT) && defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) + switch( operation->id ) + { +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TRANSPARENT_TEST_DRIVER_ID: + return( test_transparent_cipher_finish( operation->ctx, + output, + output_size, + output_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_OPAQUE_TEST_DRIVER_ID: + return( test_opaque_cipher_finish( operation->ctx, + output, + output_size, + output_length ) ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ + default: + /* Key is attached to a driver not known to us */ + return( PSA_ERROR_BAD_STATE ); + } +#else /* PSA_CRYPTO_DRIVER_PRESENT */ + (void) operation; + (void) output; + (void) output_size; + (void) output_length; + + return( PSA_ERROR_NOT_SUPPORTED ); +#endif /* PSA_CRYPTO_DRIVER_PRESENT */ +} + +psa_status_t psa_driver_wrapper_cipher_abort( + psa_operation_driver_context_t *operation ) +{ +#if defined(PSA_CRYPTO_DRIVER_PRESENT) && defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT) + psa_status_t status = PSA_ERROR_INVALID_ARGUMENT; + + /* The object has (apparently) been initialized but it is not in use. It's + * ok to call abort on such an object, and there's nothing to do. */ + if( operation->ctx == NULL && operation->id == 0 ) + return( PSA_SUCCESS ); + + switch( operation->id ) + { +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_TRANSPARENT_TEST_DRIVER_ID: + status = test_transparent_cipher_abort( operation->ctx ); + mbedtls_platform_zeroize( + operation->ctx, + sizeof( test_transparent_cipher_operation_t ) ); + mbedtls_free( operation->ctx ); + operation->ctx = NULL; + operation->id = 0; + + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#if defined(PSA_CRYPTO_DRIVER_TEST) + case PSA_CRYPTO_OPAQUE_TEST_DRIVER_ID: + status = test_opaque_cipher_abort( operation->ctx ); + mbedtls_platform_zeroize( + operation->ctx, + sizeof( test_opaque_cipher_operation_t ) ); + mbedtls_free( operation->ctx ); + operation->ctx = NULL; + operation->id = 0; + + return( status ); +#endif /* PSA_CRYPTO_DRIVER_TEST */ + default: + /* Operation is attached to a driver not known to us */ + return( PSA_ERROR_BAD_STATE ); + } +#else /* PSA_CRYPTO_DRIVER_PRESENT */ + (void)operation; + + return( PSA_ERROR_NOT_SUPPORTED ); +#endif /* PSA_CRYPTO_DRIVER_PRESENT */ +} + /* End of automatically generated file. */ diff --git a/library/psa_crypto_driver_wrappers.h b/library/psa_crypto_driver_wrappers.h index 42993792a6..0db15d6c3f 100644 --- a/library/psa_crypto_driver_wrappers.h +++ b/library/psa_crypto_driver_wrappers.h @@ -25,6 +25,9 @@ #include "psa/crypto.h" #include "psa/crypto_driver_common.h" +/* + * Signature functions + */ psa_status_t psa_driver_wrapper_sign_hash( psa_key_slot_t *slot, psa_algorithm_t alg, const uint8_t *hash, @@ -43,6 +46,65 @@ psa_status_t psa_driver_wrapper_verify_hash( psa_key_slot_t *slot, psa_status_t psa_driver_wrapper_generate_key( const psa_key_attributes_t *attributes, psa_key_slot_t *slot ); +/* + * Cipher functions + */ +psa_status_t psa_driver_wrapper_cipher_encrypt( + psa_key_slot_t *slot, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length ); + +psa_status_t psa_driver_wrapper_cipher_decrypt( + psa_key_slot_t *slot, + psa_algorithm_t alg, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length ); + +psa_status_t psa_driver_wrapper_cipher_encrypt_setup( + psa_operation_driver_context_t *operation, + psa_key_slot_t *slot, + psa_algorithm_t alg ); + +psa_status_t psa_driver_wrapper_cipher_decrypt_setup( + psa_operation_driver_context_t *operation, + psa_key_slot_t *slot, + psa_algorithm_t alg ); + +psa_status_t psa_driver_wrapper_cipher_generate_iv( + psa_operation_driver_context_t *operation, + uint8_t *iv, + size_t iv_size, + size_t *iv_length ); + +psa_status_t psa_driver_wrapper_cipher_set_iv( + psa_operation_driver_context_t *operation, + const uint8_t *iv, + size_t iv_length ); + +psa_status_t psa_driver_wrapper_cipher_update( + psa_operation_driver_context_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length ); + +psa_status_t psa_driver_wrapper_cipher_finish( + psa_operation_driver_context_t *operation, + uint8_t *output, + size_t output_size, + size_t *output_length ); + +psa_status_t psa_driver_wrapper_cipher_abort( + psa_operation_driver_context_t *operation ); + #endif /* PSA_CRYPTO_DRIVER_WRAPPERS_H */ /* End of automatically generated file. */ diff --git a/tests/include/test/drivers/cipher.h b/tests/include/test/drivers/cipher.h new file mode 100644 index 0000000000..ef787f7948 --- /dev/null +++ b/tests/include/test/drivers/cipher.h @@ -0,0 +1,180 @@ +/* + * Test driver for cipher functions + */ +/* Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PSA_CRYPTO_TEST_DRIVERS_CIPHER_H +#define PSA_CRYPTO_TEST_DRIVERS_CIPHER_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(PSA_CRYPTO_DRIVER_TEST) +#include + +#include "mbedtls/cipher.h" +typedef struct { + psa_algorithm_t alg; + unsigned int key_set : 1; + unsigned int iv_required : 1; + unsigned int iv_set : 1; + uint8_t iv_size; + uint8_t block_size; + mbedtls_cipher_context_t cipher; +} test_transparent_cipher_operation_t; + +typedef struct{ + unsigned int initialised : 1; + test_transparent_cipher_operation_t ctx; +} test_opaque_cipher_operation_t; + +typedef struct { + /* If non-null, on success, copy this to the output. */ + void *forced_output; + size_t forced_output_length; + /* If not PSA_SUCCESS, return this error code instead of processing the + * function call. */ + psa_status_t forced_status; + /* Count the amount of times one of the cipher driver functions is called. */ + unsigned long hits; +} test_driver_cipher_hooks_t; + +#define TEST_DRIVER_CIPHER_INIT { NULL, 0, PSA_SUCCESS, 0 } +static inline test_driver_cipher_hooks_t test_driver_cipher_hooks_init( void ) +{ + const test_driver_cipher_hooks_t v = TEST_DRIVER_CIPHER_INIT; + return( v ); +} + +extern test_driver_cipher_hooks_t test_driver_cipher_hooks; + +psa_status_t test_transparent_cipher_encrypt( + const psa_key_attributes_t *attributes, + const uint8_t *key, size_t key_length, + psa_algorithm_t alg, + const uint8_t *input, size_t input_length, + uint8_t *output, size_t output_size, size_t *output_length); + +psa_status_t test_transparent_cipher_decrypt( + const psa_key_attributes_t *attributes, + const uint8_t *key, size_t key_length, + psa_algorithm_t alg, + const uint8_t *input, size_t input_length, + uint8_t *output, size_t output_size, size_t *output_length); + +psa_status_t test_transparent_cipher_encrypt_setup( + test_transparent_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key, size_t key_length, + psa_algorithm_t alg); + +psa_status_t test_transparent_cipher_decrypt_setup( + test_transparent_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key, size_t key_length, + psa_algorithm_t alg); + +psa_status_t test_transparent_cipher_abort( + test_transparent_cipher_operation_t *operation); + +psa_status_t test_transparent_cipher_generate_iv( + test_transparent_cipher_operation_t *operation, + uint8_t *iv, + size_t iv_size, + size_t *iv_length); + +psa_status_t test_transparent_cipher_set_iv( + test_transparent_cipher_operation_t *operation, + const uint8_t *iv, + size_t iv_length); + +psa_status_t test_transparent_cipher_update( + test_transparent_cipher_operation_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +psa_status_t test_transparent_cipher_finish( + test_transparent_cipher_operation_t *operation, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/* + * opaque versions + */ +psa_status_t test_opaque_cipher_encrypt( + const psa_key_attributes_t *attributes, + const uint8_t *key, size_t key_length, + psa_algorithm_t alg, + const uint8_t *input, size_t input_length, + uint8_t *output, size_t output_size, size_t *output_length); + +psa_status_t test_opaque_cipher_decrypt( + const psa_key_attributes_t *attributes, + const uint8_t *key, size_t key_length, + psa_algorithm_t alg, + const uint8_t *input, size_t input_length, + uint8_t *output, size_t output_size, size_t *output_length); + +psa_status_t test_opaque_cipher_encrypt_setup( + test_opaque_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key, size_t key_length, + psa_algorithm_t alg); + +psa_status_t test_opaque_cipher_decrypt_setup( + test_opaque_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key, size_t key_length, + psa_algorithm_t alg); + +psa_status_t test_opaque_cipher_abort( + test_opaque_cipher_operation_t *operation); + +psa_status_t test_opaque_cipher_generate_iv( + test_opaque_cipher_operation_t *operation, + uint8_t *iv, + size_t iv_size, + size_t *iv_length); + +psa_status_t test_opaque_cipher_set_iv( + test_opaque_cipher_operation_t *operation, + const uint8_t *iv, + size_t iv_length); + +psa_status_t test_opaque_cipher_update( + test_opaque_cipher_operation_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +psa_status_t test_opaque_cipher_finish( + test_opaque_cipher_operation_t *operation, + uint8_t *output, + size_t output_size, + size_t *output_length); + +#endif /* PSA_CRYPTO_DRIVER_TEST */ +#endif /* PSA_CRYPTO_TEST_DRIVERS_CIPHER_H */ diff --git a/tests/include/test/drivers/test_driver.h b/tests/include/test/drivers/test_driver.h index 75135e0f42..7ee8e5eea3 100644 --- a/tests/include/test/drivers/test_driver.h +++ b/tests/include/test/drivers/test_driver.h @@ -24,5 +24,6 @@ #include "test/drivers/signature.h" #include "test/drivers/keygen.h" +#include "test/drivers/cipher.h" #endif /* PSA_CRYPTO_TEST_DRIVER_H */ diff --git a/tests/src/drivers/cipher.c b/tests/src/drivers/cipher.c new file mode 100644 index 0000000000..fa7c6a9e7e --- /dev/null +++ b/tests/src/drivers/cipher.c @@ -0,0 +1,611 @@ +/* + * Test driver for cipher functions. + * Currently only supports multi-part operations using AES-CTR. + */ +/* Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PSA_CRYPTO_DRIVERS) && defined(PSA_CRYPTO_DRIVER_TEST) +#include "psa/crypto.h" +#include "psa_crypto_core.h" +#include "mbedtls/cipher.h" + +#include "test/drivers/cipher.h" + +#include "test/random.h" + +#include + +/* Test driver implements AES-CTR only. Its default behaviour (when its return + * status is not overridden through the hooks) is to take care of all AES-CTR + * operations, and return PSA_ERROR_NOT_SUPPORTED for all others. + * Set test_driver_cipher_hooks.forced_status to PSA_ERROR_NOT_SUPPORTED to use + * fallback even for AES-CTR. */ +test_driver_cipher_hooks_t test_driver_cipher_hooks = TEST_DRIVER_CIPHER_INIT; + +static psa_status_t test_transparent_cipher_oneshot( + mbedtls_operation_t direction, + const psa_key_attributes_t *attributes, + const uint8_t *key, size_t key_length, + psa_algorithm_t alg, + const uint8_t *input, size_t input_length, + uint8_t *output, size_t output_size, size_t *output_length) +{ + test_driver_cipher_hooks.hits++; + + /* Test driver supports AES-CTR only, to verify operation calls. */ + if( alg != PSA_ALG_CTR || + psa_get_key_type( attributes ) != PSA_KEY_TYPE_AES ) + return( PSA_ERROR_NOT_SUPPORTED ); + + /* If test driver response code is not SUCCESS, we can return early */ + if( test_driver_cipher_hooks.forced_status != PSA_SUCCESS ) + return( test_driver_cipher_hooks.forced_status ); + + /* If test driver output is overridden, we don't need to do actual crypto */ + if( test_driver_cipher_hooks.forced_output != NULL ) + { + if( output_size < test_driver_cipher_hooks.forced_output_length ) + return( PSA_ERROR_BUFFER_TOO_SMALL ); + + memcpy( output, + test_driver_cipher_hooks.forced_output, + test_driver_cipher_hooks.forced_output_length ); + *output_length = test_driver_cipher_hooks.forced_output_length; + + return( test_driver_cipher_hooks.forced_status ); + } + + /* Run AES-CTR using the cipher module */ + { + mbedtls_test_rnd_pseudo_info rnd_info; + memset( &rnd_info, 0x5A, sizeof( mbedtls_test_rnd_pseudo_info ) ); + + const mbedtls_cipher_info_t *cipher_info = + mbedtls_cipher_info_from_values( MBEDTLS_CIPHER_ID_AES, + key_length * 8, + MBEDTLS_MODE_CTR ); + mbedtls_cipher_context_t cipher; + int ret = 0; + uint8_t temp_output_buffer[16] = {0}; + size_t temp_output_length = 0; + + if( direction == MBEDTLS_ENCRYPT ) + { + /* Oneshot encrypt needs to prepend the IV to the output */ + if( output_size < ( input_length + 16 ) ) + return( PSA_ERROR_BUFFER_TOO_SMALL ); + } + else + { + /* Oneshot decrypt has the IV prepended to the input */ + if( output_size < ( input_length - 16 ) ) + return( PSA_ERROR_BUFFER_TOO_SMALL ); + } + + if( cipher_info == NULL ) + return( PSA_ERROR_NOT_SUPPORTED ); + + mbedtls_cipher_init( &cipher ); + ret = mbedtls_cipher_setup( &cipher, cipher_info ); + if( ret != 0 ) + goto exit; + + ret = mbedtls_cipher_setkey( &cipher, + key, + key_length * 8, direction ); + if( ret != 0 ) + goto exit; + + if( direction == MBEDTLS_ENCRYPT ) + { + mbedtls_test_rnd_pseudo_info rnd_info; + memset( &rnd_info, 0x5A, sizeof( mbedtls_test_rnd_pseudo_info ) ); + + ret = mbedtls_test_rnd_pseudo_rand( &rnd_info, + temp_output_buffer, + 16 ); + if( ret != 0 ) + goto exit; + + ret = mbedtls_cipher_set_iv( &cipher, temp_output_buffer, 16 ); + } + else + ret = mbedtls_cipher_set_iv( &cipher, input, 16 ); + + if( ret != 0 ) + goto exit; + + if( direction == MBEDTLS_ENCRYPT ) + { + ret = mbedtls_cipher_update( &cipher, + input, input_length, + &output[16], output_length ); + if( ret == 0 ) + { + memcpy( output, temp_output_buffer, 16 ); + *output_length += 16; + } + } + else + ret = mbedtls_cipher_update( &cipher, + &input[16], input_length - 16, + output, output_length ); + + if( ret != 0 ) + goto exit; + + ret = mbedtls_cipher_finish( &cipher, + temp_output_buffer, + &temp_output_length ); + +exit: + if( ret != 0 ) + { + *output_length = 0; + memset(output, 0, output_size); + } + + mbedtls_cipher_free( &cipher ); + return( mbedtls_to_psa_error( ret ) ); + } +} + +psa_status_t test_transparent_cipher_encrypt( + const psa_key_attributes_t *attributes, + const uint8_t *key, size_t key_length, + psa_algorithm_t alg, + const uint8_t *input, size_t input_length, + uint8_t *output, size_t output_size, size_t *output_length) +{ + return ( + test_transparent_cipher_oneshot( + MBEDTLS_ENCRYPT, + attributes, + key, key_length, + alg, + input, input_length, + output, output_size, output_length) ); +} + +psa_status_t test_transparent_cipher_decrypt( + const psa_key_attributes_t *attributes, + const uint8_t *key, size_t key_length, + psa_algorithm_t alg, + const uint8_t *input, size_t input_length, + uint8_t *output, size_t output_size, size_t *output_length) +{ + return ( + test_transparent_cipher_oneshot( + MBEDTLS_DECRYPT, + attributes, + key, key_length, + alg, + input, input_length, + output, output_size, output_length) ); +} + +static psa_status_t test_transparent_cipher_setup( + mbedtls_operation_t direction, + test_transparent_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key, size_t key_length, + psa_algorithm_t alg) +{ + const mbedtls_cipher_info_t *cipher_info = NULL; + int ret = 0; + + test_driver_cipher_hooks.hits++; + + if( operation->alg != 0 ) + return( PSA_ERROR_BAD_STATE ); + + /* 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 ) ); + + /* Allow overriding return value for testing purposes */ + if( test_driver_cipher_hooks.forced_status != PSA_SUCCESS ) + return( test_driver_cipher_hooks.forced_status ); + + /* Test driver supports AES-CTR only, to verify operation calls. */ + if( alg != PSA_ALG_CTR || + psa_get_key_type( attributes ) != PSA_KEY_TYPE_AES ) + return( PSA_ERROR_NOT_SUPPORTED ); + + operation->alg = alg; + operation->iv_size = 16; + + cipher_info = mbedtls_cipher_info_from_values( MBEDTLS_CIPHER_ID_AES, + key_length * 8, + MBEDTLS_MODE_CTR ); + if( cipher_info == NULL ) + return( PSA_ERROR_NOT_SUPPORTED ); + + mbedtls_cipher_init( &operation->cipher ); + ret = mbedtls_cipher_setup( &operation->cipher, cipher_info ); + if( ret != 0 ) { + mbedtls_cipher_free( &operation->cipher ); + return( mbedtls_to_psa_error( ret ) ); + } + + ret = mbedtls_cipher_setkey( &operation->cipher, + key, + key_length * 8, direction ); + if( ret != 0 ) { + mbedtls_cipher_free( &operation->cipher ); + return( mbedtls_to_psa_error( ret ) ); + } + + operation->iv_set = 0; + operation->iv_required = 1; + operation->key_set = 1; + + return( test_driver_cipher_hooks.forced_status ); +} + +psa_status_t test_transparent_cipher_encrypt_setup( + test_transparent_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key, size_t key_length, + psa_algorithm_t alg) +{ + return ( test_transparent_cipher_setup( MBEDTLS_ENCRYPT, + operation, + attributes, + key, + key_length, + alg ) ); +} + +psa_status_t test_transparent_cipher_decrypt_setup( + test_transparent_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key, size_t key_length, + psa_algorithm_t alg) +{ + return ( test_transparent_cipher_setup( MBEDTLS_DECRYPT, + operation, + attributes, + key, + key_length, + alg ) ); +} + +psa_status_t test_transparent_cipher_abort( + test_transparent_cipher_operation_t *operation) +{ + test_driver_cipher_hooks.hits++; + + if( operation->alg == 0 ) + return( PSA_SUCCESS ); + if( operation->alg != PSA_ALG_CTR ) + return( PSA_ERROR_BAD_STATE ); + + mbedtls_cipher_free( &operation->cipher ); + + /* 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 ) ); + + return( PSA_SUCCESS ); +} + +psa_status_t test_transparent_cipher_generate_iv( + test_transparent_cipher_operation_t *operation, + uint8_t *iv, + size_t iv_size, + size_t *iv_length) +{ + psa_status_t status; + mbedtls_test_rnd_pseudo_info rnd_info; + memset( &rnd_info, 0x5A, sizeof( mbedtls_test_rnd_pseudo_info ) ); + + test_driver_cipher_hooks.hits++; + + if( test_driver_cipher_hooks.forced_status != PSA_SUCCESS ) + return( test_driver_cipher_hooks.forced_status ); + + if( operation->alg != PSA_ALG_CTR ) + return( PSA_ERROR_BAD_STATE ); + + if( operation->iv_set || ! operation->iv_required ) + return( PSA_ERROR_BAD_STATE ); + + if( iv_size < operation->iv_size ) + return( PSA_ERROR_BUFFER_TOO_SMALL ); + + status = mbedtls_to_psa_error( + mbedtls_test_rnd_pseudo_rand( &rnd_info, + iv, + operation->iv_size ) ); + if( status != PSA_SUCCESS ) + return( status ); + + *iv_length = operation->iv_size; + status = test_transparent_cipher_set_iv( operation, iv, *iv_length ); + + return( status ); +} + +psa_status_t test_transparent_cipher_set_iv( + test_transparent_cipher_operation_t *operation, + const uint8_t *iv, + size_t iv_length) +{ + psa_status_t status; + + test_driver_cipher_hooks.hits++; + + if( test_driver_cipher_hooks.forced_status != PSA_SUCCESS ) + return( test_driver_cipher_hooks.forced_status ); + + if( operation->alg != PSA_ALG_CTR ) + return( PSA_ERROR_BAD_STATE ); + + if( operation->iv_set || ! operation->iv_required ) + return( PSA_ERROR_BAD_STATE ); + + if( iv_length != operation->iv_size ) + return( PSA_ERROR_INVALID_ARGUMENT ); + + status = mbedtls_to_psa_error( + mbedtls_cipher_set_iv( &operation->cipher, iv, iv_length ) ); + + if( status == PSA_SUCCESS ) + operation->iv_set = 1; + + return( status ); +} + +psa_status_t test_transparent_cipher_update( + test_transparent_cipher_operation_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + psa_status_t status; + + test_driver_cipher_hooks.hits++; + + if( test_driver_cipher_hooks.forced_status != PSA_SUCCESS ) + return( test_driver_cipher_hooks.forced_status ); + + if( operation->alg != PSA_ALG_CTR ) + return( PSA_ERROR_BAD_STATE ); + + /* CTR is a stream cipher, so data in and out are always the same size */ + if( output_size < input_length ) + return( PSA_ERROR_BUFFER_TOO_SMALL ); + + status = mbedtls_to_psa_error( + mbedtls_cipher_update( &operation->cipher, input, + input_length, output, output_length ) ); + + if( status != PSA_SUCCESS ) + return status; + + if( test_driver_cipher_hooks.forced_output != NULL ) + { + if( output_size < test_driver_cipher_hooks.forced_output_length ) + return PSA_ERROR_BUFFER_TOO_SMALL; + + memcpy( output, + test_driver_cipher_hooks.forced_output, + test_driver_cipher_hooks.forced_output_length ); + *output_length = test_driver_cipher_hooks.forced_output_length; + } + + return( test_driver_cipher_hooks.forced_status ); +} + +psa_status_t test_transparent_cipher_finish( + test_transparent_cipher_operation_t *operation, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + psa_status_t status = PSA_ERROR_GENERIC_ERROR; + uint8_t temp_output_buffer[MBEDTLS_MAX_BLOCK_LENGTH]; + + test_driver_cipher_hooks.hits++; + + if( test_driver_cipher_hooks.forced_status != PSA_SUCCESS ) + return( test_driver_cipher_hooks.forced_status ); + + if( operation->alg != PSA_ALG_CTR ) + return( PSA_ERROR_BAD_STATE ); + + if( ! operation->key_set ) + return( PSA_ERROR_BAD_STATE ); + + if( operation->iv_required && ! operation->iv_set ) + return( PSA_ERROR_BAD_STATE ); + + status = mbedtls_to_psa_error( + mbedtls_cipher_finish( &operation->cipher, + temp_output_buffer, + output_length ) ); + + mbedtls_cipher_free( &operation->cipher ); + + if( status != PSA_SUCCESS ) + return( status ); + + if( *output_length == 0 ) + ; /* Nothing to copy. Note that output may be NULL in this case. */ + else if( output_size >= *output_length ) + memcpy( output, temp_output_buffer, *output_length ); + else + return( PSA_ERROR_BUFFER_TOO_SMALL ); + + + if( test_driver_cipher_hooks.forced_output != NULL ) + { + if( output_size < test_driver_cipher_hooks.forced_output_length ) + return PSA_ERROR_BUFFER_TOO_SMALL; + + memcpy( output, + test_driver_cipher_hooks.forced_output, + test_driver_cipher_hooks.forced_output_length ); + *output_length = test_driver_cipher_hooks.forced_output_length; + } + + return( test_driver_cipher_hooks.forced_status ); +} + +/* + * opaque versions, to do + */ +psa_status_t test_opaque_cipher_encrypt( + const psa_key_attributes_t *attributes, + const uint8_t *key, size_t key_length, + psa_algorithm_t alg, + const uint8_t *input, size_t input_length, + uint8_t *output, size_t output_size, size_t *output_length) +{ + (void) attributes; + (void) key; + (void) key_length; + (void) alg; + (void) input; + (void) input_length; + (void) output; + (void) output_size; + (void) output_length; + return( PSA_ERROR_NOT_SUPPORTED ); +} + +psa_status_t test_opaque_cipher_decrypt( + const psa_key_attributes_t *attributes, + const uint8_t *key, size_t key_length, + psa_algorithm_t alg, + const uint8_t *input, size_t input_length, + uint8_t *output, size_t output_size, size_t *output_length) +{ + (void) attributes; + (void) key; + (void) key_length; + (void) alg; + (void) input; + (void) input_length; + (void) output; + (void) output_size; + (void) output_length; + return( PSA_ERROR_NOT_SUPPORTED ); +} + +psa_status_t test_opaque_cipher_encrypt_setup( + test_opaque_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key, size_t key_length, + psa_algorithm_t alg) +{ + (void) operation; + (void) attributes; + (void) key; + (void) key_length; + (void) alg; + return( PSA_ERROR_NOT_SUPPORTED ); +} + +psa_status_t test_opaque_cipher_decrypt_setup( + test_opaque_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const uint8_t *key, size_t key_length, + psa_algorithm_t alg) +{ + (void) operation; + (void) attributes; + (void) key; + (void) key_length; + (void) alg; + return( PSA_ERROR_NOT_SUPPORTED ); +} + +psa_status_t test_opaque_cipher_abort( + test_opaque_cipher_operation_t *operation) +{ + (void) operation; + return( PSA_ERROR_NOT_SUPPORTED ); +} + +psa_status_t test_opaque_cipher_generate_iv( + test_opaque_cipher_operation_t *operation, + uint8_t *iv, + size_t iv_size, + size_t *iv_length) +{ + (void) operation; + (void) iv; + (void) iv_size; + (void) iv_length; + return( PSA_ERROR_NOT_SUPPORTED ); +} + +psa_status_t test_opaque_cipher_set_iv( + test_opaque_cipher_operation_t *operation, + const uint8_t *iv, + size_t iv_length) +{ + (void) operation; + (void) iv; + (void) iv_length; + return( PSA_ERROR_NOT_SUPPORTED ); +} + +psa_status_t test_opaque_cipher_update( + test_opaque_cipher_operation_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + (void) operation; + (void) input; + (void) input_length; + (void) output; + (void) output_size; + (void) output_length; + return( PSA_ERROR_NOT_SUPPORTED ); +} + +psa_status_t test_opaque_cipher_finish( + test_opaque_cipher_operation_t *operation, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + (void) operation; + (void) output; + (void) output_size; + (void) output_length; + return( PSA_ERROR_NOT_SUPPORTED ); +} +#endif /* MBEDTLS_PSA_CRYPTO_DRIVERS && PSA_CRYPTO_DRIVER_TEST */ diff --git a/tests/suites/test_suite_psa_crypto_driver_wrappers.data b/tests/suites/test_suite_psa_crypto_driver_wrappers.data index 74e61723f0..7abc256928 100644 --- a/tests/suites/test_suite_psa_crypto_driver_wrappers.data +++ b/tests/suites/test_suite_psa_crypto_driver_wrappers.data @@ -39,3 +39,114 @@ generate_key:PSA_ERROR_NOT_SUPPORTED:"":PSA_SUCCESS generate_key through transparent driver: error generate_key:PSA_ERROR_GENERIC_ERROR:"":PSA_ERROR_GENERIC_ERROR + +PSA symmetric encrypt: AES-CTR, 16 bytes, good +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_encrypt:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":"8f9408fe80a81d3e813da3c7b0b2bd32":0:PSA_SUCCESS:PSA_SUCCESS + +PSA symmetric encrypt: AES-CTR, 15 bytes, good +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_encrypt:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e11739317":"8f9408fe80a81d3e813da3c7b0b2bd":0:PSA_SUCCESS:PSA_SUCCESS + +PSA symmetric encrypt: AES-CTR, 16 bytes, fallback +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_encrypt:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":"8f9408fe80a81d3e813da3c7b0b2bd32":0:PSA_ERROR_NOT_SUPPORTED:PSA_SUCCESS + +PSA symmetric encrypt: AES-CTR, 15 bytes, fallback +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_encrypt:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e11739317":"8f9408fe80a81d3e813da3c7b0b2bd":0:PSA_ERROR_NOT_SUPPORTED:PSA_SUCCESS + +PSA symmetric encrypt: AES-CTR, 16 bytes, fake +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_encrypt:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":"d07a6a6e2687feb2":1:PSA_SUCCESS:PSA_SUCCESS + +PSA symmetric encrypt: AES-CTR, 15 bytes, fake +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_encrypt:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e11739317":"d07a6a6e2687feb2":1:PSA_SUCCESS:PSA_SUCCESS + +PSA symmetric decrypt: AES-CTR, 16 bytes, good +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_MODE_CTR +cipher_decrypt:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"396ee84fb75fdbb5c2b13c7fe5a654aa":"dd3b5e5319b7591daab1e1a92687feb2":0:PSA_SUCCESS:PSA_SUCCESS + +PSA symmetric decrypt: AES-CTR, 16 bytes, fallback +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_MODE_CTR +cipher_decrypt:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"396ee84fb75fdbb5c2b13c7fe5a654aa":"dd3b5e5319b7591daab1e1a92687feb2":0:PSA_ERROR_NOT_SUPPORTED:PSA_SUCCESS + +PSA symmetric decrypt: AES-CTR, 16 bytes, fake +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_CIPHER_MODE_CTR +cipher_decrypt:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"396ee84fb75fdbb5c2b13c7fe5a654aa":"d07a6a6e2687feb2":1:PSA_SUCCESS:PSA_SUCCESS + +PSA symmetric encryption multipart: AES-CTR, 11+5 bytes +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":11:11:5:"8f9408fe80a81d3e813da3c7b0b2bd32" + +PSA symmetric encryption multipart: AES-CTR, 16+16 bytes +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":16:16:16:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7baf71025f6ef6393ca587" + +PSA symmetric encryption multipart: AES-CTR, 12+20 bytes +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":12:12:20:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7baf71025f6ef6393ca587" + +PSA symmetric encryption multipart: AES-CTR, 20+12 bytes +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":20:20:12:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7baf71025f6ef6393ca587" + +PSA symmetric encryption multipart: AES-CTR, 12+10 bytes +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597":12:12:10:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7b" + +PSA symmetric encryption multipart: AES-CTR, 0+15 bytes +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e11739317":0:0:15:"8f9408fe80a81d3e813da3c7b0b2bd" + +PSA symmetric encryption multipart: AES-CTR, 15+0 bytes +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e11739317":15:15:0:"8f9408fe80a81d3e813da3c7b0b2bd" + +PSA symmetric encryption multipart: AES-CTR, 0+16 bytes +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":0:0:16:"8f9408fe80a81d3e813da3c7b0b2bd32" + +PSA symmetric encryption multipart: AES-CTR, 16+0 bytes +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_encrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":16:16:0:"8f9408fe80a81d3e813da3c7b0b2bd32" + +PSA symmetric decryption multipart: AES-CTR, 11+5 bytes +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":11:11:5:"8f9408fe80a81d3e813da3c7b0b2bd32" + +PSA symmetric decryption multipart: AES-CTR, 16+16 bytes +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":16:16:16:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7baf71025f6ef6393ca587" + +PSA symmetric decryption multipart: AES-CTR, 12+20 bytes +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":12:12:20:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7baf71025f6ef6393ca587" + +PSA symmetric decryption multipart: AES-CTR, 20+12 bytes +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597bcef1389318c7fc865ef":20:20:12:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7baf71025f6ef6393ca587" + +PSA symmetric decryption multipart: AES-CTR, 12+10 bytes +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a5434f378a597":12:12:10:"8f9408fe80a81d3e813da3c7b0b2bd321c965bb1de7b" + +PSA symmetric decryption multipart: AES-CTR, 0+15 bytes +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e11739317":0:0:15:"8f9408fe80a81d3e813da3c7b0b2bd" + +PSA symmetric decryption multipart: AES-CTR, 15+0 bytes +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e11739317":15:15:0:"8f9408fe80a81d3e813da3c7b0b2bd" + +PSA symmetric decryption multipart: AES-CTR, 0+16 bytes +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":0:0:16:"8f9408fe80a81d3e813da3c7b0b2bd32" + +PSA symmetric decryption multipart: AES-CTR, 16+0 bytes +depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR +cipher_decrypt_multipart:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a":16:16:0:"8f9408fe80a81d3e813da3c7b0b2bd32" + +Cipher driver: negative testing on all entry points +cipher_entry_points:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee22e409f96e93d7e117393172a" diff --git a/tests/suites/test_suite_psa_crypto_driver_wrappers.function b/tests/suites/test_suite_psa_crypto_driver_wrappers.function index 917798237e..951670d568 100644 --- a/tests/suites/test_suite_psa_crypto_driver_wrappers.function +++ b/tests/suites/test_suite_psa_crypto_driver_wrappers.function @@ -183,3 +183,536 @@ exit: test_driver_keygen_hooks = test_driver_keygen_hooks_init(); } /* END_CASE */ + +/* BEGIN_CASE */ +void cipher_encrypt( int alg_arg, int key_type_arg, + data_t *key, data_t *iv, + data_t *input, data_t *expected_output, + int mock_output_arg, + int force_status_arg, + int expected_status_arg ) +{ + psa_key_handle_t handle = 0; + psa_status_t status; + psa_key_type_t key_type = key_type_arg; + psa_algorithm_t alg = alg_arg; + psa_status_t expected_status = expected_status_arg; + psa_status_t force_status = force_status_arg; + unsigned char *output = NULL; + 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_INIT; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + test_driver_cipher_hooks = test_driver_cipher_hooks_init(); + test_driver_cipher_hooks.forced_status = force_status; + + PSA_ASSERT( psa_crypto_init( ) ); + + psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_ENCRYPT ); + psa_set_key_algorithm( &attributes, alg ); + psa_set_key_type( &attributes, key_type ); + + PSA_ASSERT( psa_import_key( &attributes, key->x, key->len, &handle ) ); + + PSA_ASSERT( psa_cipher_encrypt_setup( &operation, + handle, alg ) ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 1 ); + test_driver_cipher_hooks.hits = 0; + + PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) ); + TEST_EQUAL( test_driver_cipher_hooks.hits, ( force_status == PSA_SUCCESS ? 1 : 0 ) ); + test_driver_cipher_hooks.hits = 0; + + output_buffer_size = ( (size_t) input->len + + PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ) ); + ASSERT_ALLOC( output, output_buffer_size ); + + if( mock_output_arg ) + { + test_driver_cipher_hooks.forced_output = expected_output->x; + test_driver_cipher_hooks.forced_output_length = expected_output->len; + } + + PSA_ASSERT( psa_cipher_update( &operation, + input->x, input->len, + output, output_buffer_size, + &function_output_length ) ); + TEST_EQUAL( test_driver_cipher_hooks.hits, ( force_status == PSA_SUCCESS ? 1 : 0 ) ); + test_driver_cipher_hooks.hits = 0; + + if( mock_output_arg ) + { + test_driver_cipher_hooks.forced_output = NULL; + test_driver_cipher_hooks.forced_output_length = 0; + } + + total_output_length += function_output_length; + status = psa_cipher_finish( &operation, + output + total_output_length, + output_buffer_size - total_output_length, + &function_output_length ); + /* Finish will have called abort as well, so expecting two hits here */ + TEST_EQUAL( test_driver_cipher_hooks.hits, ( force_status == PSA_SUCCESS ? 2 : 0 ) ); + test_driver_cipher_hooks.hits = 0; + + total_output_length += function_output_length; + + TEST_EQUAL( status, expected_status ); + if( expected_status == PSA_SUCCESS ) + { + PSA_ASSERT( psa_cipher_abort( &operation ) ); + // driver function should've been called as part of the finish() core routine + TEST_EQUAL( test_driver_cipher_hooks.hits, 0 ); + ASSERT_COMPARE( expected_output->x, expected_output->len, + output, total_output_length ); + } + +exit: + psa_cipher_abort( &operation ); + mbedtls_free( output ); + psa_destroy_key( handle ); + PSA_DONE( ); + test_driver_cipher_hooks = test_driver_cipher_hooks_init(); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void cipher_encrypt_multipart( int alg_arg, int key_type_arg, + data_t *key, data_t *iv, + data_t *input, + int first_part_size_arg, + int output1_length_arg, int output2_length_arg, + data_t *expected_output ) +{ + psa_key_handle_t handle = 0; + psa_key_type_t key_type = key_type_arg; + psa_algorithm_t alg = alg_arg; + size_t first_part_size = first_part_size_arg; + size_t output1_length = output1_length_arg; + size_t output2_length = output2_length_arg; + unsigned char *output = NULL; + 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_INIT; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + test_driver_cipher_hooks = test_driver_cipher_hooks_init(); + + PSA_ASSERT( psa_crypto_init( ) ); + + psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_ENCRYPT ); + psa_set_key_algorithm( &attributes, alg ); + psa_set_key_type( &attributes, key_type ); + + PSA_ASSERT( psa_import_key( &attributes, key->x, key->len, &handle ) ); + + PSA_ASSERT( psa_cipher_encrypt_setup( &operation, + handle, alg ) ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 1 ); + test_driver_cipher_hooks.hits = 0; + + PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 1 ); + test_driver_cipher_hooks.hits = 0; + + output_buffer_size = ( (size_t) input->len + + PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ) ); + ASSERT_ALLOC( output, output_buffer_size ); + + TEST_ASSERT( first_part_size <= input->len ); + PSA_ASSERT( psa_cipher_update( &operation, input->x, first_part_size, + output, output_buffer_size, + &function_output_length ) ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 1 ); + test_driver_cipher_hooks.hits = 0; + + TEST_ASSERT( function_output_length == output1_length ); + total_output_length += function_output_length; + PSA_ASSERT( psa_cipher_update( &operation, + input->x + first_part_size, + input->len - first_part_size, + output + total_output_length, + output_buffer_size - total_output_length, + &function_output_length ) ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 1 ); + test_driver_cipher_hooks.hits = 0; + TEST_ASSERT( function_output_length == output2_length ); + total_output_length += function_output_length; + PSA_ASSERT( psa_cipher_finish( &operation, + output + total_output_length, + output_buffer_size - total_output_length, + &function_output_length ) ); + /* Finish will have called abort as well, so expecting two hits here */ + TEST_EQUAL( test_driver_cipher_hooks.hits, 2 ); + test_driver_cipher_hooks.hits = 0 ; + total_output_length += function_output_length; + PSA_ASSERT( psa_cipher_abort( &operation ) ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 0 ); + + ASSERT_COMPARE( expected_output->x, expected_output->len, + output, total_output_length ); + +exit: + psa_cipher_abort( &operation ); + mbedtls_free( output ); + psa_destroy_key( handle ); + PSA_DONE( ); + test_driver_cipher_hooks = test_driver_cipher_hooks_init(); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void cipher_decrypt_multipart( int alg_arg, int key_type_arg, + data_t *key, data_t *iv, + data_t *input, + int first_part_size_arg, + int output1_length_arg, int output2_length_arg, + data_t *expected_output ) +{ + psa_key_handle_t handle = 0; + + psa_key_type_t key_type = key_type_arg; + psa_algorithm_t alg = alg_arg; + size_t first_part_size = first_part_size_arg; + size_t output1_length = output1_length_arg; + size_t output2_length = output2_length_arg; + unsigned char *output = NULL; + 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_INIT; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + test_driver_cipher_hooks = test_driver_cipher_hooks_init(); + + PSA_ASSERT( psa_crypto_init( ) ); + + psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DECRYPT ); + psa_set_key_algorithm( &attributes, alg ); + psa_set_key_type( &attributes, key_type ); + + PSA_ASSERT( psa_import_key( &attributes, key->x, key->len, &handle ) ); + + PSA_ASSERT( psa_cipher_decrypt_setup( &operation, + handle, alg ) ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 1 ); + test_driver_cipher_hooks.hits = 0; + + PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 1 ); + test_driver_cipher_hooks.hits = 0; + + output_buffer_size = ( (size_t) input->len + + PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ) ); + ASSERT_ALLOC( output, output_buffer_size ); + + TEST_ASSERT( first_part_size <= input->len ); + PSA_ASSERT( psa_cipher_update( &operation, + input->x, first_part_size, + output, output_buffer_size, + &function_output_length ) ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 1 ); + test_driver_cipher_hooks.hits = 0; + + TEST_ASSERT( function_output_length == output1_length ); + total_output_length += function_output_length; + PSA_ASSERT( psa_cipher_update( &operation, + input->x + first_part_size, + input->len - first_part_size, + output + total_output_length, + output_buffer_size - total_output_length, + &function_output_length ) ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 1 ); + test_driver_cipher_hooks.hits = 0; + + TEST_ASSERT( function_output_length == output2_length ); + total_output_length += function_output_length; + PSA_ASSERT( psa_cipher_finish( &operation, + output + total_output_length, + output_buffer_size - total_output_length, + &function_output_length ) ); + /* Finish will have called abort as well, so expecting two hits here */ + TEST_EQUAL( test_driver_cipher_hooks.hits, 2 ); + test_driver_cipher_hooks.hits = 0; + total_output_length += function_output_length; + PSA_ASSERT( psa_cipher_abort( &operation ) ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 0 ); + + ASSERT_COMPARE( expected_output->x, expected_output->len, + output, total_output_length ); + +exit: + psa_cipher_abort( &operation ); + mbedtls_free( output ); + psa_destroy_key( handle ); + PSA_DONE( ); + test_driver_cipher_hooks = test_driver_cipher_hooks_init(); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void cipher_decrypt( int alg_arg, int key_type_arg, + data_t *key, data_t *iv, + data_t *input, data_t *expected_output, + int mock_output_arg, + int force_status_arg, + int expected_status_arg ) +{ + psa_key_handle_t handle = 0; + psa_status_t status; + psa_key_type_t key_type = key_type_arg; + psa_algorithm_t alg = alg_arg; + psa_status_t expected_status = expected_status_arg; + psa_status_t force_status = force_status_arg; + unsigned char *output = NULL; + 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_INIT; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + test_driver_cipher_hooks = test_driver_cipher_hooks_init(); + test_driver_cipher_hooks.forced_status = force_status; + + PSA_ASSERT( psa_crypto_init( ) ); + + psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DECRYPT ); + psa_set_key_algorithm( &attributes, alg ); + psa_set_key_type( &attributes, key_type ); + + PSA_ASSERT( psa_import_key( &attributes, key->x, key->len, &handle ) ); + + PSA_ASSERT( psa_cipher_decrypt_setup( &operation, + handle, alg ) ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 1 ); + test_driver_cipher_hooks.hits = 0; + + PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) ); + TEST_EQUAL( test_driver_cipher_hooks.hits, ( force_status == PSA_SUCCESS ? 1 : 0 ) ); + test_driver_cipher_hooks.hits = 0; + + output_buffer_size = ( (size_t) input->len + + PSA_BLOCK_CIPHER_BLOCK_SIZE( key_type ) ); + ASSERT_ALLOC( output, output_buffer_size ); + + if( mock_output_arg ) + { + test_driver_cipher_hooks.forced_output = expected_output->x; + test_driver_cipher_hooks.forced_output_length = expected_output->len; + } + + PSA_ASSERT( psa_cipher_update( &operation, + input->x, input->len, + output, output_buffer_size, + &function_output_length ) ); + TEST_EQUAL( test_driver_cipher_hooks.hits, ( force_status == PSA_SUCCESS ? 1 : 0 ) ); + test_driver_cipher_hooks.hits = 0; + + if( mock_output_arg ) + { + test_driver_cipher_hooks.forced_output = NULL; + test_driver_cipher_hooks.forced_output_length = 0; + } + + total_output_length += function_output_length; + status = psa_cipher_finish( &operation, + output + total_output_length, + output_buffer_size - total_output_length, + &function_output_length ); + /* Finish will have called abort as well, so expecting two hits here */ + TEST_EQUAL( test_driver_cipher_hooks.hits, ( force_status == PSA_SUCCESS ? 2 : 0 ) ); + test_driver_cipher_hooks.hits = 0; + + total_output_length += function_output_length; + TEST_EQUAL( status, expected_status ); + + if( expected_status == PSA_SUCCESS ) + { + PSA_ASSERT( psa_cipher_abort( &operation ) ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 0 ); + ASSERT_COMPARE( expected_output->x, expected_output->len, + output, total_output_length ); + } + +exit: + psa_cipher_abort( &operation ); + mbedtls_free( output ); + psa_destroy_key( handle ); + PSA_DONE( ); + test_driver_cipher_hooks = test_driver_cipher_hooks_init(); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void cipher_entry_points( int alg_arg, int key_type_arg, + data_t *key, data_t *iv, + data_t *input ) +{ + psa_key_handle_t handle = 0; + psa_status_t status; + psa_key_type_t key_type = key_type_arg; + psa_algorithm_t alg = alg_arg; + unsigned char *output = NULL; + size_t output_buffer_size = 0; + size_t function_output_length = 0; + psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + test_driver_cipher_hooks = test_driver_cipher_hooks_init(); + + ASSERT_ALLOC( output, input->len + 16 ); + output_buffer_size = input->len + 16; + + PSA_ASSERT( psa_crypto_init( ) ); + + psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT ); + psa_set_key_algorithm( &attributes, alg ); + psa_set_key_type( &attributes, key_type ); + + PSA_ASSERT( psa_import_key( &attributes, key->x, key->len, &handle ) ); + + /* Test setup call, encrypt */ + test_driver_cipher_hooks.forced_status = PSA_ERROR_GENERIC_ERROR; + status = psa_cipher_encrypt_setup( &operation, + handle, alg ); + /* When setup fails, it shouldn't call any further entry points */ + TEST_EQUAL( test_driver_cipher_hooks.hits, 1 ); + TEST_EQUAL( status, test_driver_cipher_hooks.forced_status ); + test_driver_cipher_hooks.hits = 0; + status = psa_cipher_set_iv( &operation, iv->x, iv->len ); + TEST_EQUAL( status, PSA_ERROR_BAD_STATE ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 0 ); + + /* Test setup call failure, decrypt */ + status = psa_cipher_decrypt_setup( &operation, + handle, alg ); + /* When setup fails, it shouldn't call any further entry points */ + TEST_EQUAL( test_driver_cipher_hooks.hits, 1 ); + TEST_EQUAL( status, test_driver_cipher_hooks.forced_status ); + test_driver_cipher_hooks.hits = 0; + status = psa_cipher_set_iv( &operation, iv->x, iv->len ); + TEST_EQUAL( status, PSA_ERROR_BAD_STATE ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 0 ); + + /* Test IV setting failure */ + test_driver_cipher_hooks.forced_status = PSA_SUCCESS; + status = psa_cipher_encrypt_setup( &operation, + handle, alg ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 1 ); + TEST_EQUAL( status, test_driver_cipher_hooks.forced_status ); + test_driver_cipher_hooks.hits = 0; + + test_driver_cipher_hooks.forced_status = PSA_ERROR_GENERIC_ERROR; + status = psa_cipher_set_iv( &operation, iv->x, iv->len ); + /* When setting the IV fails, it should call abort too */ + TEST_EQUAL( test_driver_cipher_hooks.hits, 2 ); + TEST_EQUAL( status, test_driver_cipher_hooks.forced_status ); + /* Failure should prevent further operations from executing on the driver */ + test_driver_cipher_hooks.hits = 0; + status = psa_cipher_update( &operation, + input->x, input->len, + output, output_buffer_size, + &function_output_length ); + TEST_EQUAL( status, PSA_ERROR_BAD_STATE ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 0 ); + psa_cipher_abort( &operation ); + + /* Test IV generation failure */ + test_driver_cipher_hooks.forced_status = PSA_SUCCESS; + status = psa_cipher_encrypt_setup( &operation, + handle, alg ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 1 ); + TEST_EQUAL( status, test_driver_cipher_hooks.forced_status ); + test_driver_cipher_hooks.hits = 0; + + test_driver_cipher_hooks.forced_status = PSA_ERROR_GENERIC_ERROR; + status = psa_cipher_generate_iv( &operation, output, 16, &function_output_length ); + /* When generating the IV fails, it should call abort too */ + TEST_EQUAL( test_driver_cipher_hooks.hits, 2 ); + TEST_EQUAL( status, test_driver_cipher_hooks.forced_status ); + /* Failure should prevent further operations from executing on the driver */ + test_driver_cipher_hooks.hits = 0; + status = psa_cipher_update( &operation, + input->x, input->len, + output, output_buffer_size, + &function_output_length ); + TEST_EQUAL( status, PSA_ERROR_BAD_STATE ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 0 ); + psa_cipher_abort( &operation ); + + /* Test update failure */ + test_driver_cipher_hooks.forced_status = PSA_SUCCESS; + status = psa_cipher_encrypt_setup( &operation, + handle, alg ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 1 ); + TEST_EQUAL( status, test_driver_cipher_hooks.forced_status ); + test_driver_cipher_hooks.hits = 0; + + status = psa_cipher_set_iv( &operation, iv->x, iv->len ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 1 ); + TEST_EQUAL( status, test_driver_cipher_hooks.forced_status ); + test_driver_cipher_hooks.hits = 0; + + test_driver_cipher_hooks.forced_status = PSA_ERROR_GENERIC_ERROR; + status = psa_cipher_update( &operation, + input->x, input->len, + output, output_buffer_size, + &function_output_length ); + /* When the update call fails, it should call abort too */ + TEST_EQUAL( test_driver_cipher_hooks.hits, 2 ); + TEST_EQUAL( status, test_driver_cipher_hooks.forced_status ); + /* Failure should prevent further operations from executing on the driver */ + test_driver_cipher_hooks.hits = 0; + status = psa_cipher_update( &operation, + input->x, input->len, + output, output_buffer_size, + &function_output_length ); + TEST_EQUAL( status, PSA_ERROR_BAD_STATE ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 0 ); + psa_cipher_abort( &operation ); + + /* Test finish failure */ + test_driver_cipher_hooks.forced_status = PSA_SUCCESS; + status = psa_cipher_encrypt_setup( &operation, + handle, alg ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 1 ); + TEST_EQUAL( status, test_driver_cipher_hooks.forced_status ); + test_driver_cipher_hooks.hits = 0; + + status = psa_cipher_set_iv( &operation, iv->x, iv->len ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 1 ); + TEST_EQUAL( status, test_driver_cipher_hooks.forced_status ); + test_driver_cipher_hooks.hits = 0; + + status = psa_cipher_update( &operation, + input->x, input->len, + output, output_buffer_size, + &function_output_length ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 1 ); + TEST_EQUAL( status, test_driver_cipher_hooks.forced_status ); + test_driver_cipher_hooks.hits = 0; + + test_driver_cipher_hooks.forced_status = PSA_ERROR_GENERIC_ERROR; + status = psa_cipher_finish( &operation, + output + function_output_length, + output_buffer_size - function_output_length, + &function_output_length ); + /* When the finish call fails, it should call abort too */ + TEST_EQUAL( test_driver_cipher_hooks.hits, 2 ); + TEST_EQUAL( status, test_driver_cipher_hooks.forced_status ); + /* Failure should prevent further operations from executing on the driver */ + test_driver_cipher_hooks.hits = 0; + status = psa_cipher_update( &operation, + input->x, input->len, + output, output_buffer_size, + &function_output_length ); + TEST_EQUAL( status, PSA_ERROR_BAD_STATE ); + TEST_EQUAL( test_driver_cipher_hooks.hits, 0 ); + psa_cipher_abort( &operation ); + +exit: + psa_cipher_abort( &operation ); + mbedtls_free( output ); + psa_destroy_key( handle ); + PSA_DONE( ); + test_driver_cipher_hooks = test_driver_cipher_hooks_init(); +} +/* END_CASE */ diff --git a/visualc/VS2010/mbedTLS.vcxproj b/visualc/VS2010/mbedTLS.vcxproj index 9d79298397..db8ec33899 100644 --- a/visualc/VS2010/mbedTLS.vcxproj +++ b/visualc/VS2010/mbedTLS.vcxproj @@ -238,6 +238,7 @@ +