/* BEGIN_HEADER */
#include "test/drivers/test_driver.h"

#if defined(PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY)
/* Sanity checks on the output of RSA encryption.
 *
 * \param modulus               Key modulus. Must not have leading zeros.
 * \param private_exponent      Key private exponent.
 * \param alg                   An RSA algorithm.
 * \param input_data            The input plaintext.
 * \param buf                   The ciphertext produced by the driver.
 * \param length                Length of \p buf in bytes.
 */
static int sanity_check_rsa_encryption_result(
    psa_algorithm_t alg,
    const data_t *modulus, const data_t *private_exponent,
    const data_t *input_data,
    uint8_t *buf, size_t length )
{
#if defined(MBEDTLS_BIGNUM_C)
    mbedtls_mpi N, D, C, X;
    mbedtls_mpi_init( &N );
    mbedtls_mpi_init( &D );
    mbedtls_mpi_init( &C );
    mbedtls_mpi_init( &X );
#endif /* MBEDTLS_BIGNUM_C */

    int ok = 0;

    TEST_ASSERT( length == modulus->len );

#if defined(MBEDTLS_BIGNUM_C)
    /* Perform the private key operation */
    TEST_ASSERT( mbedtls_mpi_read_binary( &N, modulus->x, modulus->len ) == 0 );
    TEST_ASSERT( mbedtls_mpi_read_binary( &D,
                                          private_exponent->x,
                                          private_exponent->len ) == 0 );
    TEST_ASSERT( mbedtls_mpi_read_binary( &C, buf, length ) == 0 );
    TEST_ASSERT( mbedtls_mpi_exp_mod( &X, &C, &D, &N, NULL ) == 0 );

    /* Sanity checks on the padded plaintext */
    TEST_ASSERT( mbedtls_mpi_write_binary( &X, buf, length ) == 0 );

    if( alg == PSA_ALG_RSA_PKCS1V15_CRYPT )
    {
        TEST_ASSERT( length > input_data->len + 2 );
        TEST_EQUAL( buf[0], 0x00 );
        TEST_EQUAL( buf[1], 0x02 );
        TEST_EQUAL( buf[length - input_data->len - 1], 0x00 );
        ASSERT_COMPARE( buf + length - input_data->len, input_data->len,
                        input_data->x, input_data->len );
    }
    else if( PSA_ALG_IS_RSA_OAEP( alg ) )
    {
        TEST_EQUAL( buf[0], 0x00 );
        /* The rest is too hard to check */
    }
    else
    {
        TEST_ASSERT( ! "Encryption result sanity check not implemented for RSA algorithm" );
    }
#endif /* MBEDTLS_BIGNUM_C */

    ok = 1;

exit:
#if defined(MBEDTLS_BIGNUM_C)
    mbedtls_mpi_free( &N );
    mbedtls_mpi_free( &D );
    mbedtls_mpi_free( &C );
    mbedtls_mpi_free( &X );
#endif /* MBEDTLS_BIGNUM_C */
    return( ok );
}
#endif
/* END_HEADER */

/* BEGIN_DEPENDENCIES
 * depends_on:MBEDTLS_PSA_CRYPTO_C:MBEDTLS_PSA_CRYPTO_DRIVERS:PSA_CRYPTO_DRIVER_TEST
 * END_DEPENDENCIES
 */

/* BEGIN_CASE */
void sign_hash( int key_type_arg,
                int alg_arg,
                int force_status_arg,
                data_t *key_input,
                data_t *data_input,
                data_t *expected_output,
                int fake_output,
                int expected_status_arg )
{
    psa_status_t force_status = force_status_arg;
    psa_status_t expected_status = expected_status_arg;
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_algorithm_t alg = alg_arg;
    size_t key_bits;
    psa_key_type_t key_type = key_type_arg;
    unsigned char *signature = NULL;
    size_t signature_size;
    size_t signature_length = 0xdeadbeef;
    psa_status_t actual_status;
    mbedtls_test_driver_signature_sign_hooks =
        mbedtls_test_driver_signature_hooks_init();

    PSA_ASSERT( psa_crypto_init( ) );
    psa_set_key_type( &attributes,
                      key_type );
    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN_HASH );
    psa_set_key_algorithm( &attributes, alg );
    psa_import_key( &attributes,
                    key_input->x, key_input->len,
                    &key );

    mbedtls_test_driver_signature_sign_hooks.forced_status = force_status;
    if( fake_output == 1 )
    {
        mbedtls_test_driver_signature_sign_hooks.forced_output =
            expected_output->x;
        mbedtls_test_driver_signature_sign_hooks.forced_output_length =
            expected_output->len;
    }

    /* Allocate a buffer which has the size advertized by the
     * library. */
    PSA_ASSERT( psa_get_key_attributes( key, &attributes ) );
    key_bits = psa_get_key_bits( &attributes );
    signature_size = PSA_SIGN_OUTPUT_SIZE( key_type, key_bits, alg );

    TEST_ASSERT( signature_size != 0 );
    TEST_ASSERT( signature_size <= PSA_SIGNATURE_MAX_SIZE );
    ASSERT_ALLOC( signature, signature_size );

    actual_status = psa_sign_hash( key, alg,
                                   data_input->x, data_input->len,
                                   signature, signature_size,
                                   &signature_length );
    TEST_EQUAL( actual_status, expected_status );
    if( expected_status == PSA_SUCCESS )
    {
        ASSERT_COMPARE( signature, signature_length,
                        expected_output->x, expected_output->len );
    }
    TEST_EQUAL( mbedtls_test_driver_signature_sign_hooks.hits, 1 );

exit:
    psa_reset_key_attributes( &attributes );
    psa_destroy_key( key );
    mbedtls_free( signature );
    PSA_DONE( );
    mbedtls_test_driver_signature_sign_hooks =
        mbedtls_test_driver_signature_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void verify_hash( int key_type_arg,
                  int key_type_public_arg,
                  int alg_arg,
                  int force_status_arg,
                  int register_public_key,
                  data_t *key_input,
                  data_t *data_input,
                  data_t *signature_input,
                  int expected_status_arg )
{
    psa_status_t force_status = force_status_arg;
    psa_status_t expected_status = expected_status_arg;
    psa_algorithm_t alg = alg_arg;
    psa_key_type_t key_type = key_type_arg;
    psa_key_type_t key_type_public = key_type_public_arg;
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_status_t actual_status;
    mbedtls_test_driver_signature_verify_hooks =
        mbedtls_test_driver_signature_hooks_init();

    PSA_ASSERT( psa_crypto_init( ) );
    if( register_public_key )
    {
        psa_set_key_type( &attributes, key_type_public );
        psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_VERIFY_HASH );
        psa_set_key_algorithm( &attributes, alg );
        psa_import_key( &attributes,
                        key_input->x, key_input->len,
                        &key );
    }
    else
    {
        psa_set_key_type( &attributes, key_type );
        psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_VERIFY_HASH );
        psa_set_key_algorithm( &attributes, alg );
        psa_import_key( &attributes,
                        key_input->x, key_input->len,
                        &key );
    }

    mbedtls_test_driver_signature_verify_hooks.forced_status = force_status;

    actual_status = psa_verify_hash( key, alg,
                                     data_input->x, data_input->len,
                                     signature_input->x, signature_input->len );
    TEST_EQUAL( actual_status, expected_status );
    TEST_EQUAL( mbedtls_test_driver_signature_verify_hooks.hits, 1 );

exit:
    psa_reset_key_attributes( &attributes );
    psa_destroy_key( key );
    PSA_DONE( );
    mbedtls_test_driver_signature_verify_hooks =
        mbedtls_test_driver_signature_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void sign_message( int key_type_arg,
                   int alg_arg,
                   int force_status_arg,
                   data_t *key_input,
                   data_t *data_input,
                   data_t *expected_output,
                   int fake_output,
                   int expected_status_arg )
{
    psa_status_t force_status = force_status_arg;
    psa_status_t expected_status = expected_status_arg;
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_algorithm_t alg = alg_arg;
    size_t key_bits;
    psa_key_type_t key_type = key_type_arg;
    unsigned char *signature = NULL;
    size_t signature_size;
    size_t signature_length = 0xdeadbeef;
    psa_status_t actual_status;
    mbedtls_test_driver_signature_sign_hooks =
        mbedtls_test_driver_signature_hooks_init();

    PSA_ASSERT( psa_crypto_init( ) );
    psa_set_key_type( &attributes, key_type );
    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN_MESSAGE );
    psa_set_key_algorithm( &attributes, alg );
    psa_import_key( &attributes,
                    key_input->x, key_input->len,
                    &key );

    mbedtls_test_driver_signature_sign_hooks.forced_status = force_status;
    if( fake_output == 1 )
    {
        mbedtls_test_driver_signature_sign_hooks.forced_output =
            expected_output->x;
        mbedtls_test_driver_signature_sign_hooks.forced_output_length =
            expected_output->len;
    }

    /* Allocate a buffer which has the size advertized by the
     * library. */
    PSA_ASSERT( psa_get_key_attributes( key, &attributes ) );
    key_bits = psa_get_key_bits( &attributes );
    signature_size = PSA_SIGN_OUTPUT_SIZE( key_type, key_bits, alg );

    TEST_ASSERT( signature_size != 0 );
    TEST_ASSERT( signature_size <= PSA_SIGNATURE_MAX_SIZE );
    ASSERT_ALLOC( signature, signature_size );

    actual_status = psa_sign_message( key, alg,
                                      data_input->x, data_input->len,
                                      signature, signature_size,
                                      &signature_length );
    TEST_EQUAL( actual_status, expected_status );
    if( expected_status == PSA_SUCCESS )
    {
        ASSERT_COMPARE( signature, signature_length,
                        expected_output->x, expected_output->len );
    }
    /* In the builtin algorithm the driver is called twice. */
    TEST_EQUAL( mbedtls_test_driver_signature_sign_hooks.hits,
                force_status == PSA_ERROR_NOT_SUPPORTED ? 2 : 1 );

exit:
    psa_reset_key_attributes( &attributes );
    psa_destroy_key( key );
    mbedtls_free( signature );
    PSA_DONE( );
    mbedtls_test_driver_signature_sign_hooks =
        mbedtls_test_driver_signature_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void verify_message( int key_type_arg,
                     int key_type_public_arg,
                     int alg_arg,
                     int force_status_arg,
                     int register_public_key,
                     data_t *key_input,
                     data_t *data_input,
                     data_t *signature_input,
                     int expected_status_arg )
{
    psa_status_t force_status = force_status_arg;
    psa_status_t expected_status = expected_status_arg;
    psa_algorithm_t alg = alg_arg;
    psa_key_type_t key_type = key_type_arg;
    psa_key_type_t key_type_public = key_type_public_arg;
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_status_t actual_status;
    mbedtls_test_driver_signature_verify_hooks =
        mbedtls_test_driver_signature_hooks_init();

    PSA_ASSERT( psa_crypto_init( ) );
    if( register_public_key )
    {
        psa_set_key_type( &attributes, key_type_public );
        psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_VERIFY_MESSAGE );
        psa_set_key_algorithm( &attributes, alg );
        psa_import_key( &attributes,
                        key_input->x, key_input->len,
                        &key );
    }
    else
    {
        psa_set_key_type( &attributes, key_type );
        psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_VERIFY_MESSAGE );
        psa_set_key_algorithm( &attributes, alg );
        psa_import_key( &attributes,
                        key_input->x, key_input->len,
                        &key );
    }

    mbedtls_test_driver_signature_verify_hooks.forced_status = force_status;

    actual_status = psa_verify_message( key, alg,
                                        data_input->x, data_input->len,
                                        signature_input->x, signature_input->len );
    TEST_EQUAL( actual_status, expected_status );
    /* In the builtin algorithm the driver is called twice. */
    TEST_EQUAL( mbedtls_test_driver_signature_verify_hooks.hits,
                force_status == PSA_ERROR_NOT_SUPPORTED ? 2 : 1 );

exit:
    psa_reset_key_attributes( &attributes );
    psa_destroy_key( key );
    PSA_DONE( );
    mbedtls_test_driver_signature_verify_hooks =
        mbedtls_test_driver_signature_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE depends_on:PSA_WANT_ALG_ECDSA:PSA_WANT_ECC_SECP_R1_256 */
void generate_key( int force_status_arg,
                   data_t *fake_output,
                   int expected_status_arg )
{
    psa_status_t force_status = force_status_arg;
    psa_status_t expected_status = expected_status_arg;
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_algorithm_t alg = PSA_ALG_ECDSA( PSA_ALG_SHA_256 );
    const uint8_t *expected_output = NULL;
    size_t expected_output_length = 0;
    psa_status_t actual_status;
    uint8_t actual_output[PSA_KEY_EXPORT_ECC_KEY_PAIR_MAX_SIZE(256)] = {0};
    size_t actual_output_length;
    mbedtls_test_driver_key_management_hooks =
        mbedtls_test_driver_key_management_hooks_init();

    psa_set_key_type( &attributes,
                      PSA_KEY_TYPE_ECC_KEY_PAIR( PSA_ECC_FAMILY_SECP_R1 ) );
    psa_set_key_bits( &attributes, 256 );
    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_EXPORT );
    psa_set_key_algorithm( &attributes, alg );

    if( fake_output->len > 0 )
    {
        expected_output =
            mbedtls_test_driver_key_management_hooks.forced_output =
            fake_output->x;

        expected_output_length =
            mbedtls_test_driver_key_management_hooks.forced_output_length =
            fake_output->len;
    }

    mbedtls_test_driver_key_management_hooks.hits = 0;
    mbedtls_test_driver_key_management_hooks.forced_status = force_status;

    PSA_ASSERT( psa_crypto_init( ) );

    actual_status = psa_generate_key( &attributes, &key );
    TEST_EQUAL( mbedtls_test_driver_key_management_hooks.hits, 1 );
    TEST_EQUAL( actual_status, expected_status );

    if( actual_status == PSA_SUCCESS )
    {
        psa_export_key( key, actual_output, sizeof(actual_output), &actual_output_length );

        if( fake_output->len > 0 )
        {
            ASSERT_COMPARE( actual_output, actual_output_length,
                            expected_output, expected_output_length );
        }
        else
        {
            size_t zeroes = 0;
            for( size_t i = 0; i < sizeof(actual_output); i++ )
            {
                if( actual_output[i] == 0)
                    zeroes++;
            }
            TEST_ASSERT( zeroes != sizeof(actual_output) );
        }
    }
exit:
    psa_reset_key_attributes( &attributes );
    psa_destroy_key( key );
    PSA_DONE( );
    mbedtls_test_driver_key_management_hooks =
        mbedtls_test_driver_key_management_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void validate_key( int force_status_arg,
                   int location,
                   int owner_id_arg,
                   int id_arg,
                   int key_type_arg,
                   data_t *key_input,
                   int expected_status_arg )
{
    psa_key_lifetime_t lifetime =
                              PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION( \
                                  PSA_KEY_PERSISTENCE_DEFAULT, location);
    mbedtls_svc_key_id_t id = mbedtls_svc_key_id_make( owner_id_arg, id_arg );
    psa_status_t force_status = force_status_arg;
    psa_status_t expected_status = expected_status_arg;
    psa_key_type_t key_type = key_type_arg;
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_status_t actual_status;
    mbedtls_test_driver_key_management_hooks =
        mbedtls_test_driver_key_management_hooks_init();

    psa_set_key_id( &attributes, id );
    psa_set_key_type( &attributes,
                      key_type );
    psa_set_key_lifetime( &attributes, lifetime );
    psa_set_key_bits( &attributes, 0 );
    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_EXPORT );

    mbedtls_test_driver_key_management_hooks.forced_status = force_status;

    PSA_ASSERT( psa_crypto_init( ) );

    actual_status = psa_import_key( &attributes, key_input->x, key_input->len, &key );
    TEST_EQUAL( mbedtls_test_driver_key_management_hooks.hits, 1 );
    TEST_EQUAL( actual_status, expected_status );
    TEST_EQUAL( mbedtls_test_driver_key_management_hooks.location, location );
exit:
    psa_reset_key_attributes( &attributes );
    psa_destroy_key( key );
    PSA_DONE( );
    mbedtls_test_driver_key_management_hooks =
        mbedtls_test_driver_key_management_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void export_key( int force_status_arg,
                 data_t *fake_output,
                 int key_in_type_arg,
                 data_t *key_in,
                 int key_out_type_arg,
                 data_t *expected_output,
                 int expected_status_arg )
{
    psa_status_t force_status = force_status_arg;
    psa_status_t expected_status = expected_status_arg;
    psa_key_handle_t handle = 0;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_key_type_t input_key_type = key_in_type_arg;
    psa_key_type_t output_key_type = key_out_type_arg;
    const uint8_t *expected_output_ptr = NULL;
    size_t expected_output_length = 0;
    psa_status_t actual_status;
    uint8_t actual_output[PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(256)] = {0};
    size_t actual_output_length;
    mbedtls_test_driver_key_management_hooks =
        mbedtls_test_driver_key_management_hooks_init();

    psa_set_key_type( &attributes, input_key_type );
    psa_set_key_bits( &attributes, 256 );
    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_EXPORT );

    PSA_ASSERT( psa_crypto_init( ) );
    PSA_ASSERT( psa_import_key( &attributes, key_in->x, key_in->len, &handle ) );

    if( fake_output->len > 0 )
    {
        expected_output_ptr =
            mbedtls_test_driver_key_management_hooks.forced_output =
            fake_output->x;

        expected_output_length =
            mbedtls_test_driver_key_management_hooks.forced_output_length =
            fake_output->len;
    }
    else
    {
        expected_output_ptr = expected_output->x;
        expected_output_length = expected_output->len;
    }

    mbedtls_test_driver_key_management_hooks.hits = 0;
    mbedtls_test_driver_key_management_hooks.forced_status = force_status;

    if( PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY( output_key_type ) )
        actual_status = psa_export_public_key( handle, actual_output, sizeof(actual_output), &actual_output_length );
    else
        actual_status = psa_export_key( handle, actual_output, sizeof(actual_output), &actual_output_length );
    TEST_EQUAL( actual_status, expected_status );

    if( PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY( output_key_type ) &&
        !PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY( input_key_type ) )
        TEST_EQUAL( mbedtls_test_driver_key_management_hooks.hits, 1 );

    if( actual_status == PSA_SUCCESS )
    {
        ASSERT_COMPARE( actual_output, actual_output_length,
                        expected_output_ptr, expected_output_length );
    }
exit:
    psa_reset_key_attributes( &attributes );
    psa_destroy_key( handle );
    PSA_DONE( );
    mbedtls_test_driver_key_management_hooks =
        mbedtls_test_driver_key_management_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void key_agreement( int alg_arg,
                    int force_status_arg,
                    int our_key_type_arg,
                    data_t *our_key_data,
                    data_t *peer_key_data,
                    data_t *expected_output,
                    data_t* fake_output,
                    int expected_status_arg )
{
    psa_status_t force_status = force_status_arg;
    psa_status_t expected_status = expected_status_arg;
    psa_algorithm_t alg = alg_arg;
    psa_key_type_t our_key_type = our_key_type_arg;
    mbedtls_svc_key_id_t our_key = MBEDTLS_SVC_KEY_ID_INIT;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    const uint8_t *expected_output_ptr = NULL;
    size_t expected_output_length = 0;
    unsigned char *actual_output = NULL;
    size_t actual_output_length = ~0;
    size_t key_bits;
    psa_status_t actual_status;
    mbedtls_test_driver_key_agreement_hooks =
        mbedtls_test_driver_key_agreement_hooks_init();

    PSA_ASSERT( psa_crypto_init( ) );

    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_DERIVE );
    psa_set_key_algorithm( &attributes, alg );
    psa_set_key_type( &attributes, our_key_type );
    PSA_ASSERT( psa_import_key( &attributes,
                                our_key_data->x, our_key_data->len,
                                &our_key ) );

    PSA_ASSERT( psa_get_key_attributes( our_key, &attributes ) );
    key_bits = psa_get_key_bits( &attributes );

    TEST_LE_U( expected_output->len,
               PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE( our_key_type, key_bits ) );
    TEST_LE_U( PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE( our_key_type, key_bits ),
               PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE );

    if( fake_output->len > 0 )
    {
        expected_output_ptr =
            mbedtls_test_driver_key_agreement_hooks.forced_output =
            fake_output->x;

        expected_output_length =
            mbedtls_test_driver_key_agreement_hooks.forced_output_length =
            fake_output->len;
    }
    else
    {
        expected_output_ptr = expected_output->x;
        expected_output_length = expected_output->len;
    }

    mbedtls_test_driver_key_agreement_hooks.hits = 0;
    mbedtls_test_driver_key_agreement_hooks.forced_status = force_status;

    ASSERT_ALLOC( actual_output, expected_output->len );
    actual_status = psa_raw_key_agreement( alg, our_key,
                                       peer_key_data->x, peer_key_data->len,
                                       actual_output, expected_output->len,
                                       &actual_output_length ) ;
    TEST_EQUAL( actual_status, expected_status );
    TEST_EQUAL( mbedtls_test_driver_key_agreement_hooks.hits, 1 );

    if( actual_status == PSA_SUCCESS )
    {
        ASSERT_COMPARE( actual_output, actual_output_length,
                        expected_output_ptr, expected_output_length);
    }
    mbedtls_free( actual_output );
    actual_output = NULL;
    actual_output_length = ~0;

exit:
    psa_reset_key_attributes( &attributes );
    psa_destroy_key( our_key );
    PSA_DONE( );
    mbedtls_test_driver_key_agreement_hooks =
        mbedtls_test_driver_key_agreement_hooks_init();
}

/* END_CASE */

/* BEGIN_CASE */
void cipher_encrypt_validation( int alg_arg,
                                int key_type_arg,
                                data_t *key_data,
                                data_t *input )
{
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    psa_key_type_t key_type = key_type_arg;
    psa_algorithm_t alg = alg_arg;
    size_t iv_size = PSA_CIPHER_IV_LENGTH ( key_type, alg );
    unsigned char *output1 = NULL;
    size_t output1_buffer_size = 0;
    size_t output1_length = 0;
    unsigned char *output2 = NULL;
    size_t output2_buffer_size = 0;
    size_t output2_length = 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;
    mbedtls_test_driver_cipher_hooks = mbedtls_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 );

    output1_buffer_size = PSA_CIPHER_ENCRYPT_OUTPUT_SIZE( key_type, alg, input->len );
    output2_buffer_size = PSA_CIPHER_UPDATE_OUTPUT_SIZE( key_type, alg, input->len ) +
                          PSA_CIPHER_FINISH_OUTPUT_SIZE( key_type, alg );
    ASSERT_ALLOC( output1, output1_buffer_size );
    ASSERT_ALLOC( output2, output2_buffer_size );

    PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len,
                                &key ) );

    PSA_ASSERT( psa_cipher_encrypt( key, alg, input->x, input->len, output1,
                                    output1_buffer_size, &output1_length ) );
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, 1 );
    mbedtls_test_driver_cipher_hooks.hits = 0;

    PSA_ASSERT( psa_cipher_encrypt_setup( &operation, key, alg ) );
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, 1 );
    mbedtls_test_driver_cipher_hooks.hits = 0;

    PSA_ASSERT( psa_cipher_set_iv( &operation, output1, iv_size ) );
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, 1 );
    mbedtls_test_driver_cipher_hooks.hits = 0;

    PSA_ASSERT( psa_cipher_update( &operation,
                                   input->x, input->len,
                                   output2, output2_buffer_size,
                                   &function_output_length ) );
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, 1 );
    mbedtls_test_driver_cipher_hooks.hits = 0;

    output2_length += function_output_length;
    PSA_ASSERT( psa_cipher_finish( &operation,
                                   output2 + output2_length,
                                   output2_buffer_size - output2_length,
                                   &function_output_length ) );
    /* Finish will have called abort as well, so expecting two hits here */
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, 2 );
    mbedtls_test_driver_cipher_hooks.hits = 0;

    output2_length += function_output_length;

    PSA_ASSERT( psa_cipher_abort( &operation ) );
    // driver function should've been called as part of the finish() core routine
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, 0 );
    ASSERT_COMPARE( output1 + iv_size, output1_length - iv_size,
                    output2, output2_length );

exit:
    psa_cipher_abort( &operation );
    mbedtls_free( output1 );
    mbedtls_free( output2 );
    psa_destroy_key( key );
    PSA_DONE( );
    mbedtls_test_driver_cipher_hooks = mbedtls_test_driver_cipher_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void cipher_encrypt_multipart( int alg_arg,
                               int key_type_arg,
                               data_t *key_data,
                               data_t *iv,
                               data_t *input,
                               int first_part_size_arg,
                               int output1_length_arg,
                               int output2_length_arg,
                               data_t *expected_output,
                               int mock_output_arg,
                               int force_status_arg,
                               int expected_status_arg )
{
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    psa_key_type_t key_type = key_type_arg;
    psa_algorithm_t alg = alg_arg;
    psa_status_t status;
    psa_status_t expected_status = expected_status_arg;
    psa_status_t force_status = force_status_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;
    mbedtls_test_driver_cipher_hooks = mbedtls_test_driver_cipher_hooks_init();
    mbedtls_test_driver_cipher_hooks.forced_status = force_status;

    /* Test operation initialization */
    mbedtls_psa_cipher_operation_t mbedtls_operation =
            MBEDTLS_PSA_CIPHER_OPERATION_INIT;

    mbedtls_transparent_test_driver_cipher_operation_t transparent_operation =
            MBEDTLS_TRANSPARENT_TEST_DRIVER_CIPHER_OPERATION_INIT;

    mbedtls_opaque_test_driver_cipher_operation_t opaque_operation =
            MBEDTLS_OPAQUE_TEST_DRIVER_CIPHER_OPERATION_INIT;

    operation.ctx.mbedtls_ctx = mbedtls_operation;
    operation.ctx.transparent_test_driver_ctx = transparent_operation;
    operation.ctx.opaque_test_driver_ctx = opaque_operation;

    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_data->x, key_data->len,
                                &key ) );

    PSA_ASSERT( psa_cipher_encrypt_setup( &operation, key, alg ) );
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, 1 );
    mbedtls_test_driver_cipher_hooks.hits = 0;

    PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) );
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, ( force_status == PSA_SUCCESS ? 1 : 0 ) );
    mbedtls_test_driver_cipher_hooks.hits = 0;

    output_buffer_size = ( (size_t) input->len +
                           PSA_BLOCK_CIPHER_BLOCK_LENGTH( key_type ) );
    ASSERT_ALLOC( output, output_buffer_size );

    if( mock_output_arg )
    {
        mbedtls_test_driver_cipher_hooks.forced_output = expected_output->x;
        mbedtls_test_driver_cipher_hooks.forced_output_length = expected_output->len;
    }

    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( mbedtls_test_driver_cipher_hooks.hits, ( force_status == PSA_SUCCESS ? 1 : 0 ) );
    mbedtls_test_driver_cipher_hooks.hits = 0;

    TEST_ASSERT( function_output_length == output1_length );
    total_output_length += function_output_length;

    if( first_part_size < input->len )
    {
        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( mbedtls_test_driver_cipher_hooks.hits, 1 );
        mbedtls_test_driver_cipher_hooks.hits = 0;

        TEST_ASSERT( function_output_length == output2_length );
        total_output_length += function_output_length;
    }

    if( mock_output_arg )
    {
        mbedtls_test_driver_cipher_hooks.forced_output = NULL;
        mbedtls_test_driver_cipher_hooks.forced_output_length = 0;
    }

    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( mbedtls_test_driver_cipher_hooks.hits, ( force_status == PSA_SUCCESS ? 2 : 0 ) );
    mbedtls_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( mbedtls_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( key );
    PSA_DONE( );
    mbedtls_test_driver_cipher_hooks = mbedtls_test_driver_cipher_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void cipher_decrypt_multipart( int alg_arg,
                               int key_type_arg,
                               data_t *key_data,
                               data_t *iv,
                               data_t *input,
                               int first_part_size_arg,
                               int output1_length_arg,
                               int output2_length_arg,
                               data_t *expected_output,
                               int mock_output_arg,
                               int force_status_arg,
                               int expected_status_arg )
{
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    psa_key_type_t key_type = key_type_arg;
    psa_algorithm_t alg = alg_arg;
    psa_status_t status;
    psa_status_t expected_status = expected_status_arg;
    psa_status_t force_status = force_status_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;
    mbedtls_test_driver_cipher_hooks = mbedtls_test_driver_cipher_hooks_init();
    mbedtls_test_driver_cipher_hooks.forced_status = force_status;

    /* Test operation initialization */
    mbedtls_psa_cipher_operation_t mbedtls_operation =
            MBEDTLS_PSA_CIPHER_OPERATION_INIT;

    mbedtls_transparent_test_driver_cipher_operation_t transparent_operation =
            MBEDTLS_TRANSPARENT_TEST_DRIVER_CIPHER_OPERATION_INIT;

    mbedtls_opaque_test_driver_cipher_operation_t opaque_operation =
            MBEDTLS_OPAQUE_TEST_DRIVER_CIPHER_OPERATION_INIT;

    operation.ctx.mbedtls_ctx = mbedtls_operation;
    operation.ctx.transparent_test_driver_ctx = transparent_operation;
    operation.ctx.opaque_test_driver_ctx = opaque_operation;

    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_data->x, key_data->len,
                                &key ) );

    PSA_ASSERT( psa_cipher_decrypt_setup( &operation, key, alg ) );
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, 1 );
    mbedtls_test_driver_cipher_hooks.hits = 0;

    PSA_ASSERT( psa_cipher_set_iv( &operation, iv->x, iv->len ) );
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, ( force_status == PSA_SUCCESS ? 1 : 0 ) );
    mbedtls_test_driver_cipher_hooks.hits = 0;

    output_buffer_size = ( (size_t) input->len +
                           PSA_BLOCK_CIPHER_BLOCK_LENGTH( key_type ) );
    ASSERT_ALLOC( output, output_buffer_size );

    if( mock_output_arg )
    {
        mbedtls_test_driver_cipher_hooks.forced_output = expected_output->x;
        mbedtls_test_driver_cipher_hooks.forced_output_length = expected_output->len;
    }

    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( mbedtls_test_driver_cipher_hooks.hits, ( force_status == PSA_SUCCESS ? 1 : 0 ) );
    mbedtls_test_driver_cipher_hooks.hits = 0;

    TEST_ASSERT( function_output_length == output1_length );
    total_output_length += function_output_length;

    if( first_part_size < input->len )
    {
        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( mbedtls_test_driver_cipher_hooks.hits, ( force_status == PSA_SUCCESS ? 1 : 0 ) );
        mbedtls_test_driver_cipher_hooks.hits = 0;

        TEST_ASSERT( function_output_length == output2_length );
        total_output_length += function_output_length;
    }

    if( mock_output_arg )
    {
        mbedtls_test_driver_cipher_hooks.forced_output = NULL;
        mbedtls_test_driver_cipher_hooks.forced_output_length = 0;
    }

    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( mbedtls_test_driver_cipher_hooks.hits, ( force_status == PSA_SUCCESS ? 2 : 0 ) );
    mbedtls_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( mbedtls_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( key );
    PSA_DONE( );
    mbedtls_test_driver_cipher_hooks = mbedtls_test_driver_cipher_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void cipher_decrypt( int alg_arg,
                     int key_type_arg,
                     data_t *key_data,
                     data_t *iv,
                     data_t *input_arg,
                     data_t *expected_output,
                     int mock_output_arg,
                     int force_status_arg,
                     int expected_status_arg )
{
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    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 *input = NULL;
    size_t input_buffer_size = 0;
    unsigned char *output = NULL;
    size_t output_buffer_size = 0;
    size_t output_length = 0;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    mbedtls_test_driver_cipher_hooks = mbedtls_test_driver_cipher_hooks_init();
    mbedtls_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 );

    /* Allocate input buffer and copy the iv and the plaintext */
    input_buffer_size = ( (size_t) input_arg->len + (size_t) iv->len );
    if ( input_buffer_size > 0 )
    {
        ASSERT_ALLOC( input, input_buffer_size );
        memcpy( input, iv->x, iv->len );
        memcpy( input + iv->len, input_arg->x, input_arg->len );
    }

    output_buffer_size = PSA_CIPHER_DECRYPT_OUTPUT_SIZE( key_type, alg, input_buffer_size );
    ASSERT_ALLOC( output, output_buffer_size );

    PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len,
                                &key ) );

    if( mock_output_arg )
    {
        mbedtls_test_driver_cipher_hooks.forced_output = expected_output->x;
        mbedtls_test_driver_cipher_hooks.forced_output_length = expected_output->len;
    }

    status = psa_cipher_decrypt( key, alg, input, input_buffer_size, output,
                                 output_buffer_size, &output_length );
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, 1 );
    mbedtls_test_driver_cipher_hooks.hits = 0;

    TEST_EQUAL( status, expected_status );

    if( expected_status == PSA_SUCCESS )
    {
        ASSERT_COMPARE( expected_output->x, expected_output->len,
                        output, output_length );
    }

exit:
    mbedtls_free( input );
    mbedtls_free( output );
    psa_destroy_key( key );
    PSA_DONE( );
    mbedtls_test_driver_cipher_hooks = mbedtls_test_driver_cipher_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void cipher_entry_points( int alg_arg, int key_type_arg,
                          data_t *key_data, data_t *iv,
                          data_t *input )
{
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    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;
    mbedtls_test_driver_cipher_hooks = mbedtls_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_data->x, key_data->len,
                                &key ) );

    /*
     * Test encrypt failure
     * First test that if we don't force a driver error, encryption is
     * successful, then force driver error.
     */
    status = psa_cipher_encrypt(
        key, alg, input->x, input->len,
        output, output_buffer_size, &function_output_length );
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, 1 );
    TEST_EQUAL( status, PSA_SUCCESS );
    mbedtls_test_driver_cipher_hooks.hits = 0;

    mbedtls_test_driver_cipher_hooks.forced_status = PSA_ERROR_GENERIC_ERROR;
    /* Set the output buffer in a given state. */
    for( size_t i = 0; i < output_buffer_size; i++ )
        output[i] = 0xa5;

    status = psa_cipher_encrypt(
        key, alg, input->x, input->len,
        output, output_buffer_size, &function_output_length );
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, 1 );
    TEST_EQUAL( status, PSA_ERROR_GENERIC_ERROR );
    /*
     * Check that the output buffer is still in the same state.
     * This will fail if the output buffer is used by the core to pass the IV
     * it generated to the driver (and is not restored).
     */
    for( size_t i = 0; i < output_buffer_size; i++ )
    {
        TEST_EQUAL( output[i], 0xa5 );
    }
    mbedtls_test_driver_cipher_hooks.hits = 0;

    /* Test setup call, encrypt */
    mbedtls_test_driver_cipher_hooks.forced_status = PSA_ERROR_GENERIC_ERROR;
    status = psa_cipher_encrypt_setup( &operation, key, alg );
    /* When setup fails, it shouldn't call any further entry points */
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, 1 );
    TEST_EQUAL( status, mbedtls_test_driver_cipher_hooks.forced_status );
    mbedtls_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( mbedtls_test_driver_cipher_hooks.hits, 0 );

    /* Test setup call failure, decrypt */
    status = psa_cipher_decrypt_setup( &operation, key, alg );
    /* When setup fails, it shouldn't call any further entry points */
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, 1 );
    TEST_EQUAL( status, mbedtls_test_driver_cipher_hooks.forced_status );
    mbedtls_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( mbedtls_test_driver_cipher_hooks.hits, 0 );

    /* Test IV setting failure */
    mbedtls_test_driver_cipher_hooks.forced_status = PSA_SUCCESS;
    status = psa_cipher_encrypt_setup( &operation, key, alg );
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, 1 );
    TEST_EQUAL( status, mbedtls_test_driver_cipher_hooks.forced_status );
    mbedtls_test_driver_cipher_hooks.hits = 0;

    mbedtls_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( mbedtls_test_driver_cipher_hooks.hits, 2 );
    TEST_EQUAL( status, mbedtls_test_driver_cipher_hooks.forced_status );
    /* Failure should prevent further operations from executing on the driver */
    mbedtls_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( mbedtls_test_driver_cipher_hooks.hits, 0 );
    psa_cipher_abort( &operation );

    /* Test IV generation failure */
    mbedtls_test_driver_cipher_hooks.forced_status = PSA_SUCCESS;
    status = psa_cipher_encrypt_setup( &operation, key, alg );
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, 1 );
    TEST_EQUAL( status, mbedtls_test_driver_cipher_hooks.forced_status );
    mbedtls_test_driver_cipher_hooks.hits = 0;

    mbedtls_test_driver_cipher_hooks.forced_status = PSA_ERROR_GENERIC_ERROR;
    /* Set the output buffer in a given state. */
    for( size_t i = 0; i < 16; i++ )
        output[i] = 0xa5;

    status = psa_cipher_generate_iv( &operation, output, 16, &function_output_length );
    /* When generating the IV fails, it should call abort too */
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, 2 );
    TEST_EQUAL( status, mbedtls_test_driver_cipher_hooks.forced_status );
    /*
     * Check that the output buffer is still in the same state.
     * This will fail if the output buffer is used by the core to pass the IV
     * it generated to the driver (and is not restored).
     */
    for( size_t i = 0; i < 16; i++ )
    {
        TEST_EQUAL( output[i], 0xa5 );
    }
    /* Failure should prevent further operations from executing on the driver */
    mbedtls_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( mbedtls_test_driver_cipher_hooks.hits, 0 );
    psa_cipher_abort( &operation );

    /* Test update failure */
    mbedtls_test_driver_cipher_hooks.forced_status = PSA_SUCCESS;
    status = psa_cipher_encrypt_setup( &operation, key, alg );
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, 1 );
    TEST_EQUAL( status, mbedtls_test_driver_cipher_hooks.forced_status );
    mbedtls_test_driver_cipher_hooks.hits = 0;

    status = psa_cipher_set_iv( &operation, iv->x, iv->len );
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, 1 );
    TEST_EQUAL( status, mbedtls_test_driver_cipher_hooks.forced_status );
    mbedtls_test_driver_cipher_hooks.hits = 0;

    mbedtls_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( mbedtls_test_driver_cipher_hooks.hits, 2 );
    TEST_EQUAL( status, mbedtls_test_driver_cipher_hooks.forced_status );
    /* Failure should prevent further operations from executing on the driver */
    mbedtls_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( mbedtls_test_driver_cipher_hooks.hits, 0 );
    psa_cipher_abort( &operation );

    /* Test finish failure */
    mbedtls_test_driver_cipher_hooks.forced_status = PSA_SUCCESS;
    status = psa_cipher_encrypt_setup( &operation, key, alg );
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, 1 );
    TEST_EQUAL( status, mbedtls_test_driver_cipher_hooks.forced_status );
    mbedtls_test_driver_cipher_hooks.hits = 0;

    status = psa_cipher_set_iv( &operation, iv->x, iv->len );
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, 1 );
    TEST_EQUAL( status, mbedtls_test_driver_cipher_hooks.forced_status );
    mbedtls_test_driver_cipher_hooks.hits = 0;

    status = psa_cipher_update( &operation,
                                input->x, input->len,
                                output, output_buffer_size,
                                &function_output_length );
    TEST_EQUAL( mbedtls_test_driver_cipher_hooks.hits, 1 );
    TEST_EQUAL( status, mbedtls_test_driver_cipher_hooks.forced_status );
    mbedtls_test_driver_cipher_hooks.hits = 0;

    mbedtls_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( mbedtls_test_driver_cipher_hooks.hits, 2 );
    TEST_EQUAL( status, mbedtls_test_driver_cipher_hooks.forced_status );
    /* Failure should prevent further operations from executing on the driver */
    mbedtls_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( mbedtls_test_driver_cipher_hooks.hits, 0 );
    psa_cipher_abort( &operation );

exit:
    psa_cipher_abort( &operation );
    mbedtls_free( output );
    psa_destroy_key( key );
    PSA_DONE( );
    mbedtls_test_driver_cipher_hooks = mbedtls_test_driver_cipher_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void aead_encrypt( int key_type_arg, data_t *key_data,
                   int alg_arg,
                   data_t *nonce,
                   data_t *additional_data,
                   data_t *input_data,
                   data_t *expected_result,
                   int forced_status_arg )
{
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    psa_key_type_t key_type = key_type_arg;
    psa_algorithm_t alg = alg_arg;
    size_t key_bits;
    psa_status_t forced_status = forced_status_arg;
    unsigned char *output_data = NULL;
    size_t output_size = 0;
    size_t output_length = 0;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_status_t status = PSA_ERROR_GENERIC_ERROR;
    mbedtls_test_driver_aead_hooks = mbedtls_test_driver_aead_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_data->x, key_data->len,
                                &key ) );
    PSA_ASSERT( psa_get_key_attributes( key, &attributes ) );
    key_bits = psa_get_key_bits( &attributes );

    output_size = input_data->len + PSA_AEAD_TAG_LENGTH( key_type, key_bits,
                                                         alg );
    /* For all currently defined algorithms, PSA_AEAD_ENCRYPT_OUTPUT_SIZE
     * should be exact. */
    TEST_EQUAL( output_size,
                PSA_AEAD_ENCRYPT_OUTPUT_SIZE( key_type, alg, input_data->len ) );
    TEST_ASSERT( output_size <=
                 PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE( input_data->len ) );
    ASSERT_ALLOC( output_data, output_size );

    mbedtls_test_driver_aead_hooks.forced_status = forced_status;
    status = psa_aead_encrypt( key, alg,
                               nonce->x, nonce->len,
                               additional_data->x, additional_data->len,
                               input_data->x, input_data->len,
                               output_data, output_size,
                               &output_length );
    TEST_EQUAL( mbedtls_test_driver_aead_hooks.hits_encrypt, 1 );
    TEST_EQUAL( mbedtls_test_driver_aead_hooks.driver_status, forced_status );

    TEST_EQUAL( status, ( forced_status == PSA_ERROR_NOT_SUPPORTED ) ?
                        PSA_SUCCESS : forced_status );

    if( status == PSA_SUCCESS )
    {
        ASSERT_COMPARE( expected_result->x, expected_result->len,
                        output_data, output_length );
    }

exit:
    psa_destroy_key( key );
    mbedtls_free( output_data );
    PSA_DONE( );
    mbedtls_test_driver_aead_hooks = mbedtls_test_driver_aead_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void aead_decrypt( int key_type_arg, data_t *key_data,
                   int alg_arg,
                   data_t *nonce,
                   data_t *additional_data,
                   data_t *input_data,
                   data_t *expected_data,
                   int forced_status_arg )
{
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    psa_key_type_t key_type = key_type_arg;
    psa_algorithm_t alg = alg_arg;
    size_t key_bits;
    psa_status_t forced_status = forced_status_arg;
    unsigned char *output_data = NULL;
    size_t output_size = 0;
    size_t output_length = 0;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_status_t status = PSA_ERROR_GENERIC_ERROR;
    mbedtls_test_driver_aead_hooks = mbedtls_test_driver_aead_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_data->x, key_data->len,
                                &key ) );
    PSA_ASSERT( psa_get_key_attributes( key, &attributes ) );
    key_bits = psa_get_key_bits( &attributes );

    output_size = input_data->len - PSA_AEAD_TAG_LENGTH( key_type, key_bits,
                                                         alg );
    ASSERT_ALLOC( output_data, output_size );

    mbedtls_test_driver_aead_hooks.forced_status = forced_status;
    status = psa_aead_decrypt( key, alg,
                               nonce->x, nonce->len,
                               additional_data->x,
                               additional_data->len,
                               input_data->x, input_data->len,
                               output_data, output_size,
                               &output_length );
    TEST_EQUAL( mbedtls_test_driver_aead_hooks.hits_decrypt, 1 );
    TEST_EQUAL( mbedtls_test_driver_aead_hooks.driver_status, forced_status );

    TEST_EQUAL( status, ( forced_status == PSA_ERROR_NOT_SUPPORTED ) ?
                        PSA_SUCCESS : forced_status );

    if( status == PSA_SUCCESS )
    {
        ASSERT_COMPARE( expected_data->x, expected_data->len,
                        output_data, output_length );
    }

exit:
    psa_destroy_key( key );
    mbedtls_free( output_data );
    PSA_DONE( );
    mbedtls_test_driver_aead_hooks = mbedtls_test_driver_aead_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void mac_sign( int key_type_arg,
               data_t *key_data,
               int alg_arg,
               data_t *input,
               data_t *expected_mac,
               int forced_status_arg )
{
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    psa_key_type_t key_type = key_type_arg;
    psa_algorithm_t alg = alg_arg;
    psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    uint8_t *actual_mac = NULL;
    size_t mac_buffer_size =
        PSA_MAC_LENGTH( key_type, PSA_BYTES_TO_BITS( key_data->len ), alg );
    size_t mac_length = 0;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
    psa_status_t forced_status = forced_status_arg;
    mbedtls_test_driver_mac_hooks = mbedtls_test_driver_mac_hooks_init();

    TEST_ASSERT( mac_buffer_size <= PSA_MAC_MAX_SIZE );
    /* We expect PSA_MAC_LENGTH to be exact. */
    TEST_ASSERT( expected_mac->len == mac_buffer_size );

    PSA_ASSERT( psa_crypto_init( ) );

    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN_HASH );
    psa_set_key_algorithm( &attributes, alg );
    psa_set_key_type( &attributes, key_type );

    PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len,
                                &key ) );

    ASSERT_ALLOC( actual_mac, mac_buffer_size );
    mbedtls_test_driver_mac_hooks.forced_status = forced_status;

    /*
     * Calculate the MAC, one-shot case.
     */
    status = psa_mac_compute( key, alg,
                              input->x, input->len,
                              actual_mac, mac_buffer_size,
                              &mac_length );

    TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 1 );
    if( forced_status == PSA_SUCCESS ||
        forced_status == PSA_ERROR_NOT_SUPPORTED )
    {
        PSA_ASSERT( status );
    }
    else
        TEST_EQUAL( forced_status, status );

    PSA_ASSERT( psa_mac_abort( &operation ) );
    TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 1 );

    if( forced_status == PSA_SUCCESS )
    {
        ASSERT_COMPARE( expected_mac->x, expected_mac->len,
                        actual_mac, mac_length );
    }

    mbedtls_free( actual_mac );
    actual_mac = NULL;

exit:
    psa_mac_abort( &operation );
    psa_destroy_key( key );
    PSA_DONE( );
    mbedtls_free( actual_mac );
    mbedtls_test_driver_mac_hooks = mbedtls_test_driver_mac_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void mac_sign_multipart( int key_type_arg,
                         data_t *key_data,
                         int alg_arg,
                         data_t *input,
                         data_t *expected_mac,
                         int fragments_count,
                         int forced_status_arg )
{
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    psa_key_type_t key_type = key_type_arg;
    psa_algorithm_t alg = alg_arg;
    psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    uint8_t *actual_mac = NULL;
    size_t mac_buffer_size =
        PSA_MAC_LENGTH( key_type, PSA_BYTES_TO_BITS( key_data->len ), alg );
    size_t mac_length = 0;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
    psa_status_t forced_status = forced_status_arg;
    uint8_t *input_x = input->x;
    mbedtls_test_driver_mac_hooks = mbedtls_test_driver_mac_hooks_init();

    TEST_ASSERT( mac_buffer_size <= PSA_MAC_MAX_SIZE );
    /* We expect PSA_MAC_LENGTH to be exact. */
    TEST_ASSERT( expected_mac->len == mac_buffer_size );

    PSA_ASSERT( psa_crypto_init( ) );

    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN_HASH );
    psa_set_key_algorithm( &attributes, alg );
    psa_set_key_type( &attributes, key_type );

    PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len,
                                &key ) );

    ASSERT_ALLOC( actual_mac, mac_buffer_size );
    mbedtls_test_driver_mac_hooks.forced_status = forced_status;

    /*
     * Calculate the MAC, multipart case.
     */
    status = psa_mac_sign_setup( &operation, key, alg );
    TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 1 );

    if( forced_status == PSA_SUCCESS ||
        forced_status == PSA_ERROR_NOT_SUPPORTED )
    {
        PSA_ASSERT( status );
    }
    else
        TEST_EQUAL( forced_status, status );

    if ( fragments_count )
    {
        TEST_ASSERT( ( input->len / fragments_count ) > 0 );
    }

    for ( int i = 0; i < fragments_count; i++)
    {
        int fragment_size = input->len / fragments_count;
        if ( i == fragments_count - 1 )
            fragment_size += ( input->len % fragments_count );

        status = psa_mac_update( &operation,
                                input_x, fragment_size );
        if( forced_status == PSA_SUCCESS )
            TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 2 + i );
        else
            TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 1 );
        if( forced_status == PSA_SUCCESS ||
            forced_status == PSA_ERROR_NOT_SUPPORTED )
        {
            PSA_ASSERT( status );
        }
        else
            TEST_EQUAL( PSA_ERROR_BAD_STATE, status );
        input_x += fragment_size;
    }

    status = psa_mac_sign_finish( &operation,
                                  actual_mac, mac_buffer_size,
                                  &mac_length );
    if( forced_status == PSA_SUCCESS )
        TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 3 + fragments_count );
    else
        TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 1 );

    if( forced_status == PSA_SUCCESS ||
        forced_status == PSA_ERROR_NOT_SUPPORTED )
    {
        PSA_ASSERT( status );
    }
    else
        TEST_EQUAL( PSA_ERROR_BAD_STATE, status );

    PSA_ASSERT( psa_mac_abort( &operation ) );
    if( forced_status == PSA_SUCCESS )
        TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 3 + fragments_count );
    else
        TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 1 );

    if( forced_status == PSA_SUCCESS )
    {
        ASSERT_COMPARE( expected_mac->x, expected_mac->len,
                        actual_mac, mac_length );
    }

    mbedtls_free( actual_mac );
    actual_mac = NULL;

exit:
    psa_mac_abort( &operation );
    psa_destroy_key( key );
    PSA_DONE( );
    mbedtls_free( actual_mac );
    mbedtls_test_driver_mac_hooks = mbedtls_test_driver_mac_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void mac_verify( int key_type_arg,
                 data_t *key_data,
                 int alg_arg,
                 data_t *input,
                 data_t *expected_mac,
                 int forced_status_arg )
{
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    psa_key_type_t key_type = key_type_arg;
    psa_algorithm_t alg = alg_arg;
    psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_status_t status = PSA_ERROR_GENERIC_ERROR;
    psa_status_t forced_status = forced_status_arg;
    mbedtls_test_driver_mac_hooks = mbedtls_test_driver_mac_hooks_init();

    TEST_ASSERT( expected_mac->len <= PSA_MAC_MAX_SIZE );

    PSA_ASSERT( psa_crypto_init( ) );

    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_VERIFY_HASH );
    psa_set_key_algorithm( &attributes, alg );
    psa_set_key_type( &attributes, key_type );

    PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len,
                                &key ) );

    mbedtls_test_driver_mac_hooks.forced_status = forced_status;

    /*
     * Verify the MAC, one-shot case.
     */
    status = psa_mac_verify( key, alg,
                             input->x, input->len,
                             expected_mac->x, expected_mac->len );
    TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 1 );
    if( forced_status == PSA_SUCCESS ||
        forced_status == PSA_ERROR_NOT_SUPPORTED )
    {
        PSA_ASSERT( status );
    }
    else
        TEST_EQUAL( forced_status, status );

    PSA_ASSERT( psa_mac_abort( &operation ) );
    TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 1 );
exit:
    psa_mac_abort( &operation );
    psa_destroy_key( key );
    PSA_DONE( );
    mbedtls_test_driver_mac_hooks = mbedtls_test_driver_mac_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void mac_verify_multipart( int key_type_arg,
                           data_t *key_data,
                           int alg_arg,
                           data_t *input,
                           data_t *expected_mac,
                           int fragments_count,
                           int forced_status_arg )
{
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    psa_key_type_t key_type = key_type_arg;
    psa_algorithm_t alg = alg_arg;
    psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_status_t status = PSA_ERROR_GENERIC_ERROR;
    psa_status_t forced_status = forced_status_arg;
    uint8_t *input_x = input->x;
    mbedtls_test_driver_mac_hooks = mbedtls_test_driver_mac_hooks_init();

    TEST_ASSERT( expected_mac->len <= PSA_MAC_MAX_SIZE );

    PSA_ASSERT( psa_crypto_init( ) );

    psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_VERIFY_HASH );
    psa_set_key_algorithm( &attributes, alg );
    psa_set_key_type( &attributes, key_type );

    PSA_ASSERT( psa_import_key( &attributes, key_data->x, key_data->len,
                                &key ) );

    mbedtls_test_driver_mac_hooks.forced_status = forced_status;

    /*
     * Verify the MAC, multi-part case.
     */
    status = psa_mac_verify_setup( &operation, key, alg );
    TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 1 );

    if( forced_status == PSA_SUCCESS ||
        forced_status == PSA_ERROR_NOT_SUPPORTED )
    {
        PSA_ASSERT( status );
    }
    else
        TEST_EQUAL( forced_status, status );

    if ( fragments_count )
    {
        TEST_ASSERT( ( input->len / fragments_count ) > 0 );
    }

    for ( int i = 0; i < fragments_count; i++)
    {
        int fragment_size = input->len / fragments_count;
        if ( i == fragments_count - 1 )
            fragment_size += ( input->len % fragments_count );

        status = psa_mac_update( &operation,
                                input_x, fragment_size );
        if( forced_status == PSA_SUCCESS )
            TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 2 + i );
        else
            TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 1 );

        if( forced_status == PSA_SUCCESS ||
            forced_status == PSA_ERROR_NOT_SUPPORTED )
        {
            PSA_ASSERT( status );
        }
        else
            TEST_EQUAL( PSA_ERROR_BAD_STATE, status );
        input_x += fragment_size;
    }

    status = psa_mac_verify_finish( &operation,
                                    expected_mac->x,
                                    expected_mac->len );
    if( forced_status == PSA_SUCCESS )
        TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 3 + fragments_count );
    else
        TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 1 );

    if( forced_status == PSA_SUCCESS ||
        forced_status == PSA_ERROR_NOT_SUPPORTED )
    {
        PSA_ASSERT( status );
    }
    else
        TEST_EQUAL( PSA_ERROR_BAD_STATE, status );


    PSA_ASSERT( psa_mac_abort( &operation ) );
    if( forced_status == PSA_SUCCESS )
        TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 3 + fragments_count );
    else
        TEST_EQUAL( mbedtls_test_driver_mac_hooks.hits, 1 );

exit:
    psa_mac_abort( &operation );
    psa_destroy_key( key );
    PSA_DONE( );
    mbedtls_test_driver_mac_hooks = mbedtls_test_driver_mac_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE depends_on:PSA_CRYPTO_DRIVER_TEST:MBEDTLS_PSA_CRYPTO_DRIVERS:MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */
void builtin_key_export( int builtin_key_id_arg,
                         int builtin_key_type_arg,
                         int builtin_key_bits_arg,
                         int builtin_key_algorithm_arg,
                         data_t *expected_output,
                         int expected_status_arg )
{
    psa_key_id_t builtin_key_id = (psa_key_id_t) builtin_key_id_arg;
    psa_key_type_t builtin_key_type = (psa_key_type_t) builtin_key_type_arg;
    psa_algorithm_t builtin_key_alg = (psa_algorithm_t) builtin_key_algorithm_arg;
    size_t builtin_key_bits = (size_t) builtin_key_bits_arg;
    psa_status_t expected_status = expected_status_arg;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;

    mbedtls_svc_key_id_t key = mbedtls_svc_key_id_make( 0, builtin_key_id );
    uint8_t* output_buffer = NULL;
    size_t output_size = 0;
    psa_status_t actual_status;

    PSA_ASSERT( psa_crypto_init( ) );
    ASSERT_ALLOC( output_buffer, expected_output->len );

    actual_status = psa_export_key( key, output_buffer, expected_output->len, &output_size );

    if( expected_status == PSA_SUCCESS )
    {
        PSA_ASSERT( actual_status );
        TEST_EQUAL( output_size, expected_output->len );
        ASSERT_COMPARE( output_buffer, output_size,
                        expected_output->x, expected_output->len );

        PSA_ASSERT( psa_get_key_attributes( key, &attributes ) );
        TEST_EQUAL( psa_get_key_bits( &attributes ), builtin_key_bits );
        TEST_EQUAL( psa_get_key_type( &attributes ), builtin_key_type );
        TEST_EQUAL( psa_get_key_algorithm( &attributes ), builtin_key_alg );
    }
    else
    {
        if( actual_status != expected_status )
            fprintf( stderr, "Expected %d but got %d\n", expected_status, actual_status );
        TEST_EQUAL( actual_status, expected_status );
        TEST_EQUAL( output_size, 0 );
    }

exit:
    mbedtls_free( output_buffer );
    psa_reset_key_attributes( &attributes );
    psa_destroy_key( key );
    PSA_DONE( );
}
/* END_CASE */

/* BEGIN_CASE depends_on:PSA_CRYPTO_DRIVER_TEST:MBEDTLS_PSA_CRYPTO_DRIVERS:MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS */
void builtin_pubkey_export( int builtin_key_id_arg,
                            int builtin_key_type_arg,
                            int builtin_key_bits_arg,
                            int builtin_key_algorithm_arg,
                            data_t *expected_output,
                            int expected_status_arg )
{
    psa_key_id_t builtin_key_id = (psa_key_id_t) builtin_key_id_arg;
    psa_key_type_t builtin_key_type = (psa_key_type_t) builtin_key_type_arg;
    psa_algorithm_t builtin_key_alg = (psa_algorithm_t) builtin_key_algorithm_arg;
    size_t builtin_key_bits = (size_t) builtin_key_bits_arg;
    psa_status_t expected_status = expected_status_arg;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;

    mbedtls_svc_key_id_t key = mbedtls_svc_key_id_make( 0, builtin_key_id );
    uint8_t* output_buffer = NULL;
    size_t output_size = 0;
    psa_status_t actual_status;

    PSA_ASSERT( psa_crypto_init( ) );
    ASSERT_ALLOC( output_buffer, expected_output->len );

    actual_status = psa_export_public_key( key, output_buffer, expected_output->len, &output_size );

    if( expected_status == PSA_SUCCESS )
    {
        PSA_ASSERT( actual_status );
        TEST_EQUAL( output_size, expected_output->len );
        ASSERT_COMPARE( output_buffer, output_size,
                        expected_output->x, expected_output->len );

        PSA_ASSERT( psa_get_key_attributes( key, &attributes ) );
        TEST_EQUAL( psa_get_key_bits( &attributes ), builtin_key_bits );
        TEST_EQUAL( psa_get_key_type( &attributes ), builtin_key_type );
        TEST_EQUAL( psa_get_key_algorithm( &attributes ), builtin_key_alg );
    }
    else
    {
        TEST_EQUAL( actual_status, expected_status );
        TEST_EQUAL( output_size, 0 );
    }

exit:
    mbedtls_free( output_buffer );
    psa_reset_key_attributes( &attributes );
    psa_destroy_key( key );
    PSA_DONE( );
}
/* END_CASE */

/* BEGIN_CASE */
void hash_compute( int alg_arg,
                   data_t *input, data_t *hash,
                   int forced_status_arg,
                   int expected_status_arg )
{
    psa_algorithm_t alg = alg_arg;
    psa_status_t forced_status = forced_status_arg;
    psa_status_t expected_status = expected_status_arg;
    unsigned char *output = NULL;
    size_t output_length;

    mbedtls_test_driver_hash_hooks = mbedtls_test_driver_hash_hooks_init();
    mbedtls_test_driver_hash_hooks.forced_status = forced_status;

    PSA_ASSERT( psa_crypto_init( ) );
    ASSERT_ALLOC( output, PSA_HASH_LENGTH( alg ) );

    TEST_EQUAL( psa_hash_compute( alg, input->x, input->len,
                                  output, PSA_HASH_LENGTH( alg ),
                                  &output_length ), expected_status );
    TEST_EQUAL( mbedtls_test_driver_hash_hooks.hits, 1 );
    TEST_EQUAL( mbedtls_test_driver_hash_hooks.driver_status, forced_status );

    if( expected_status == PSA_SUCCESS )
    {
        ASSERT_COMPARE( output, output_length, hash->x, hash->len );
    }

exit:
    mbedtls_free( output );
    PSA_DONE( );
    mbedtls_test_driver_hash_hooks = mbedtls_test_driver_hash_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void hash_multipart_setup( int alg_arg,
                           data_t *input, data_t *hash,
                           int forced_status_arg,
                           int expected_status_arg )
{
    psa_algorithm_t alg = alg_arg;
    psa_status_t forced_status = forced_status_arg;
    psa_status_t expected_status = expected_status_arg;
    unsigned char *output = NULL;
    psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
    size_t output_length;

    mbedtls_test_driver_hash_hooks = mbedtls_test_driver_hash_hooks_init();
    ASSERT_ALLOC( output, PSA_HASH_LENGTH( alg ) );

    PSA_ASSERT( psa_crypto_init( ) );

    mbedtls_test_driver_hash_hooks.forced_status = forced_status;
    TEST_EQUAL( psa_hash_setup( &operation, alg ), expected_status );
    TEST_EQUAL( mbedtls_test_driver_hash_hooks.hits, 1 );
    TEST_EQUAL( mbedtls_test_driver_hash_hooks.driver_status, forced_status );

    if( expected_status == PSA_SUCCESS )
    {
        PSA_ASSERT( psa_hash_update( &operation, input->x, input->len ) );
        TEST_EQUAL( mbedtls_test_driver_hash_hooks.hits,
                    forced_status == PSA_ERROR_NOT_SUPPORTED ? 1 : 2 );
        TEST_EQUAL( mbedtls_test_driver_hash_hooks.driver_status, forced_status );

        PSA_ASSERT( psa_hash_finish( &operation,
                                     output, PSA_HASH_LENGTH( alg ),
                                     &output_length ) );
        TEST_EQUAL( mbedtls_test_driver_hash_hooks.hits,
                    forced_status == PSA_ERROR_NOT_SUPPORTED ? 1 : 4 );
        TEST_EQUAL( mbedtls_test_driver_hash_hooks.driver_status, forced_status );

        ASSERT_COMPARE( output, output_length, hash->x, hash->len );
    }

exit:
    psa_hash_abort( &operation );
    mbedtls_free( output );
    PSA_DONE( );
    mbedtls_test_driver_hash_hooks = mbedtls_test_driver_hash_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void hash_multipart_update( int alg_arg,
                            data_t *input, data_t *hash,
                            int forced_status_arg )
{
    psa_algorithm_t alg = alg_arg;
    psa_status_t forced_status = forced_status_arg;
    unsigned char *output = NULL;
    psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
    size_t output_length;

    mbedtls_test_driver_hash_hooks = mbedtls_test_driver_hash_hooks_init();
    ASSERT_ALLOC( output, PSA_HASH_LENGTH( alg ) );

    PSA_ASSERT( psa_crypto_init( ) );

    /*
     * Update inactive operation, the driver shouldn't be called.
     */
    TEST_EQUAL( psa_hash_update( &operation, input->x, input->len ),
                PSA_ERROR_BAD_STATE );
    TEST_EQUAL( mbedtls_test_driver_hash_hooks.hits, 0 );

    PSA_ASSERT( psa_hash_setup( &operation, alg ) );
    TEST_EQUAL( mbedtls_test_driver_hash_hooks.hits, 1 );
    TEST_EQUAL( mbedtls_test_driver_hash_hooks.driver_status, PSA_SUCCESS );

    mbedtls_test_driver_hash_hooks.forced_status = forced_status;
    TEST_EQUAL( psa_hash_update( &operation, input->x, input->len ),
                forced_status );
    /* One or two more calls to the driver interface: update or update + abort */
    TEST_EQUAL( mbedtls_test_driver_hash_hooks.hits,
                forced_status == PSA_SUCCESS ? 2 : 3 );
    TEST_EQUAL( mbedtls_test_driver_hash_hooks.driver_status, forced_status );

    if( forced_status == PSA_SUCCESS )
    {
        mbedtls_test_driver_hash_hooks = mbedtls_test_driver_hash_hooks_init();
        PSA_ASSERT( psa_hash_finish( &operation,
                                     output, PSA_HASH_LENGTH( alg ),
                                     &output_length ) );
        /* Two calls to the driver interface: update + abort */
        TEST_EQUAL( mbedtls_test_driver_hash_hooks.hits, 2 );
        TEST_EQUAL( mbedtls_test_driver_hash_hooks.driver_status, PSA_SUCCESS );

        ASSERT_COMPARE( output, output_length, hash->x, hash->len );
    }

exit:
    psa_hash_abort( &operation );
    mbedtls_free( output );
    PSA_DONE( );
    mbedtls_test_driver_hash_hooks = mbedtls_test_driver_hash_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void hash_multipart_finish( int alg_arg,
                            data_t *input, data_t *hash,
                            int forced_status_arg )
{
    psa_algorithm_t alg = alg_arg;
    psa_status_t forced_status = forced_status_arg;
    unsigned char *output = NULL;
    psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
    size_t output_length;

    mbedtls_test_driver_hash_hooks = mbedtls_test_driver_hash_hooks_init();
    ASSERT_ALLOC( output, PSA_HASH_LENGTH( alg ) );

    PSA_ASSERT( psa_crypto_init( ) );

    /*
     * Finish inactive operation, the driver shouldn't be called.
     */
    TEST_EQUAL( psa_hash_finish( &operation, output, PSA_HASH_LENGTH( alg ),
                                 &output_length ),
                PSA_ERROR_BAD_STATE );
    TEST_EQUAL( mbedtls_test_driver_hash_hooks.hits, 0 );

    PSA_ASSERT( psa_hash_setup( &operation, alg ) );
    TEST_EQUAL( mbedtls_test_driver_hash_hooks.hits, 1 );
    TEST_EQUAL( mbedtls_test_driver_hash_hooks.driver_status, PSA_SUCCESS );

    PSA_ASSERT( psa_hash_update( &operation, input->x, input->len ) );
    TEST_EQUAL( mbedtls_test_driver_hash_hooks.hits, 2 );
    TEST_EQUAL( mbedtls_test_driver_hash_hooks.driver_status, PSA_SUCCESS );

    mbedtls_test_driver_hash_hooks.forced_status = forced_status;
    TEST_EQUAL( psa_hash_finish( &operation,
                                 output, PSA_HASH_LENGTH( alg ),
                                 &output_length ),
                forced_status );
    /* Two more calls to the driver interface: finish + abort */
    TEST_EQUAL( mbedtls_test_driver_hash_hooks.hits, 4 );
    TEST_EQUAL( mbedtls_test_driver_hash_hooks.driver_status, forced_status );

    if( forced_status == PSA_SUCCESS )
        ASSERT_COMPARE( output, output_length, hash->x, hash->len );

exit:
    psa_hash_abort( &operation );
    mbedtls_free( output );
    PSA_DONE( );
    mbedtls_test_driver_hash_hooks = mbedtls_test_driver_hash_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void hash_clone( int alg_arg,
                 data_t *input, data_t *hash,
                 int forced_status_arg )
{
    psa_algorithm_t alg = alg_arg;
    psa_status_t forced_status = forced_status_arg;
    unsigned char *output = NULL;
    psa_hash_operation_t source_operation = PSA_HASH_OPERATION_INIT;
    psa_hash_operation_t target_operation = PSA_HASH_OPERATION_INIT;
    size_t output_length;

    mbedtls_test_driver_hash_hooks = mbedtls_test_driver_hash_hooks_init();
    ASSERT_ALLOC( output, PSA_HASH_LENGTH( alg ) );

    PSA_ASSERT( psa_crypto_init( ) );

    /*
     * Clone inactive operation, the driver shouldn't be called.
     */
    TEST_EQUAL( psa_hash_clone( &source_operation, &target_operation ),
                PSA_ERROR_BAD_STATE );
    TEST_EQUAL( mbedtls_test_driver_hash_hooks.hits, 0 );

    PSA_ASSERT( psa_hash_setup( &source_operation, alg ) );
    TEST_EQUAL( mbedtls_test_driver_hash_hooks.hits, 1 );
    TEST_EQUAL( mbedtls_test_driver_hash_hooks.driver_status, PSA_SUCCESS );

    mbedtls_test_driver_hash_hooks.forced_status = forced_status;
    TEST_EQUAL( psa_hash_clone( &source_operation, &target_operation ),
                forced_status );
    TEST_EQUAL( mbedtls_test_driver_hash_hooks.hits,
                forced_status == PSA_SUCCESS ? 2 : 3 );
    TEST_EQUAL( mbedtls_test_driver_hash_hooks.driver_status, forced_status );

    if( forced_status == PSA_SUCCESS )
    {
        mbedtls_test_driver_hash_hooks = mbedtls_test_driver_hash_hooks_init();
        PSA_ASSERT( psa_hash_update( &target_operation,
                                     input->x, input->len ) );
        TEST_EQUAL( mbedtls_test_driver_hash_hooks.hits, 1 );
        TEST_EQUAL( mbedtls_test_driver_hash_hooks.driver_status, PSA_SUCCESS );

        PSA_ASSERT( psa_hash_finish( &target_operation,
                                     output, PSA_HASH_LENGTH( alg ),
                                     &output_length ) );
        TEST_EQUAL( mbedtls_test_driver_hash_hooks.hits, 3 );
        TEST_EQUAL( mbedtls_test_driver_hash_hooks.driver_status, PSA_SUCCESS );

        ASSERT_COMPARE( output, output_length, hash->x, hash->len );
    }

exit:
    psa_hash_abort( &source_operation );
    psa_hash_abort( &target_operation );
    mbedtls_free( output );
    PSA_DONE( );
    mbedtls_test_driver_hash_hooks = mbedtls_test_driver_hash_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void asymmetric_encrypt_decrypt( int alg_arg,
                                 data_t *key_data,
                                 data_t *input_data,
                                 data_t *label,
                                 data_t *fake_output_encrypt,
                                 data_t *fake_output_decrypt,
                                 int forced_status_encrypt_arg,
                                 int forced_status_decrypt_arg,
                                 int expected_status_encrypt_arg,
                                 int expected_status_decrypt_arg )
{
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    psa_key_type_t key_type = PSA_KEY_TYPE_RSA_KEY_PAIR;
    psa_algorithm_t alg = alg_arg;
    size_t key_bits;
    unsigned char *output = NULL;
    size_t output_size;
    size_t output_length = ~0;
    unsigned char *output2 = NULL;
    size_t output2_size;
    size_t output2_length = ~0;
    psa_status_t forced_status_encrypt = forced_status_encrypt_arg;
    psa_status_t forced_status_decrypt = forced_status_decrypt_arg;
    psa_status_t expected_status_encrypt = expected_status_encrypt_arg;
    psa_status_t expected_status_decrypt = expected_status_decrypt_arg;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;

    PSA_ASSERT( psa_crypto_init( ) );
    mbedtls_test_driver_asymmetric_encryption_hooks =
        mbedtls_test_driver_asymmetric_encryption_hooks_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_data->x, key_data->len,
                                &key ) );

    /* Determine the maximum ciphertext length */
    PSA_ASSERT( psa_get_key_attributes( key, &attributes ) );
    key_bits = psa_get_key_bits( &attributes );

    mbedtls_test_driver_asymmetric_encryption_hooks.forced_status =
        forced_status_encrypt;
    if ( fake_output_encrypt->len > 0 )
    {
        mbedtls_test_driver_asymmetric_encryption_hooks.forced_output =
            fake_output_encrypt->x;
        mbedtls_test_driver_asymmetric_encryption_hooks.forced_output_length =
            fake_output_encrypt->len;
        output_size = fake_output_encrypt->len;
        ASSERT_ALLOC( output, output_size );
    }
    else
    {
        output_size = PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE( key_type, key_bits, alg );
        TEST_ASSERT( output_size <= PSA_ASYMMETRIC_ENCRYPT_OUTPUT_MAX_SIZE );
        ASSERT_ALLOC( output, output_size );
    }

    /* We test encryption by checking that encrypt-then-decrypt gives back
     * the original plaintext because of the non-optional random
     * part of encryption process which prevents using fixed vectors. */
    TEST_EQUAL( psa_asymmetric_encrypt( key, alg,
                                        input_data->x, input_data->len,
                                        label->x, label->len,
                                        output, output_size,
                                        &output_length ), expected_status_encrypt );
    /* We don't know what ciphertext length to expect, but check that
     * it looks sensible. */
    TEST_ASSERT( output_length <= output_size );

    if ( expected_status_encrypt == PSA_SUCCESS )
    {
        if ( fake_output_encrypt->len > 0 )
            ASSERT_COMPARE( fake_output_encrypt->x, fake_output_encrypt->len,
                output, output_length );
        else
        {
            mbedtls_test_driver_asymmetric_encryption_hooks.forced_status =
                forced_status_decrypt;
            if ( fake_output_decrypt->len > 0 )
            {
                mbedtls_test_driver_asymmetric_encryption_hooks.forced_output =
                    fake_output_decrypt->x;
                mbedtls_test_driver_asymmetric_encryption_hooks.forced_output_length =
                    fake_output_decrypt->len;
                output2_size = fake_output_decrypt->len;
                ASSERT_ALLOC( output2, output2_size );
            }
            else
            {
                output2_size = input_data->len;
                TEST_ASSERT( output2_size <=
                            PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE( key_type, key_bits, alg ) );
                TEST_ASSERT( output2_size <= PSA_ASYMMETRIC_DECRYPT_OUTPUT_MAX_SIZE );
                ASSERT_ALLOC( output2, output2_size );
            }

            TEST_EQUAL( psa_asymmetric_decrypt( key, alg,
                                                output, output_length,
                                                label->x, label->len,
                                                output2, output2_size,
                                                &output2_length ), expected_status_decrypt );
            if ( expected_status_decrypt == PSA_SUCCESS )
            {
                if ( fake_output_decrypt->len > 0 )
                    ASSERT_COMPARE( fake_output_decrypt->x, fake_output_decrypt->len,
                        output2, output2_length );
                else
                    ASSERT_COMPARE( input_data->x, input_data->len,
                        output2, output2_length );
            }
        }
    }

exit:
    /*
     * Key attributes may have been returned by psa_get_key_attributes()
     * thus reset them as required.
     */
    psa_reset_key_attributes( &attributes );

    psa_destroy_key( key );
    mbedtls_free( output );
    mbedtls_free( output2 );
    PSA_DONE( );
}
/* END_CASE */

/* BEGIN_CASE */
void asymmetric_decrypt( int alg_arg,
                         data_t *key_data,
                         data_t *input_data,
                         data_t *label,
                         data_t *expected_output_data,
                         data_t *fake_output_decrypt,
                         int forced_status_decrypt_arg,
                         int expected_status_decrypt_arg )
{
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    psa_key_type_t key_type = PSA_KEY_TYPE_RSA_KEY_PAIR;
    psa_algorithm_t alg = alg_arg;
    unsigned char *output = NULL;
    size_t output_size;
    size_t output_length = ~0;
    psa_status_t forced_status_decrypt = forced_status_decrypt_arg;
    psa_status_t expected_status_decrypt = expected_status_decrypt_arg;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;

    PSA_ASSERT( psa_crypto_init( ) );
    mbedtls_test_driver_asymmetric_encryption_hooks =
        mbedtls_test_driver_asymmetric_encryption_hooks_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_data->x, key_data->len,
                                &key ) );

    mbedtls_test_driver_asymmetric_encryption_hooks.forced_status =
        forced_status_decrypt;

    if ( fake_output_decrypt->len > 0 )
    {
        mbedtls_test_driver_asymmetric_encryption_hooks.forced_output =
            fake_output_decrypt->x;
        mbedtls_test_driver_asymmetric_encryption_hooks.forced_output_length =
            fake_output_decrypt->len;
        output_size = fake_output_decrypt->len;
        ASSERT_ALLOC( output, output_size );
    }
    else
    {
        output_size = expected_output_data->len;
        ASSERT_ALLOC( output, expected_output_data->len );
    }

    TEST_EQUAL( psa_asymmetric_decrypt( key, alg,
                                        input_data->x, input_data->len,
                                        label->x, label->len,
                                        output, output_size,
                                        &output_length ), expected_status_decrypt );
    if ( expected_status_decrypt == PSA_SUCCESS )
    {
        TEST_EQUAL( output_length, expected_output_data->len );
        ASSERT_COMPARE( expected_output_data->x, expected_output_data->len,
            output, output_length );
    }
exit:
    /*
     * Key attributes may have been returned by psa_get_key_attributes()
     * thus reset them as required.
     */
    psa_reset_key_attributes( &attributes );

    psa_destroy_key( key );
    mbedtls_free( output );
    PSA_DONE( );
}
/* END_CASE */

/* BEGIN_CASE */
void asymmetric_encrypt( int alg_arg,
                         data_t *key_data,
                         data_t *modulus,
                         data_t *private_exponent,
                         data_t *input_data,
                         data_t *label,
                         data_t *fake_output_encrypt,
                         int forced_status_encrypt_arg,
                         int expected_status_encrypt_arg )
{
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    psa_key_type_t key_type = PSA_KEY_TYPE_RSA_PUBLIC_KEY;
    psa_algorithm_t alg = alg_arg;
    unsigned char *output = NULL;
    size_t output_size;
    size_t output_length = ~0;
    psa_status_t forced_status_encrypt = forced_status_encrypt_arg;
    psa_status_t expected_status_encrypt = expected_status_encrypt_arg;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;

    PSA_ASSERT( psa_crypto_init( ) );
    mbedtls_test_driver_asymmetric_encryption_hooks =
        mbedtls_test_driver_asymmetric_encryption_hooks_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_data->x, key_data->len,
                                &key ) );

    PSA_ASSERT( psa_get_key_attributes( key, &attributes ) );
    size_t key_bits = psa_get_key_bits( &attributes );

    mbedtls_test_driver_asymmetric_encryption_hooks.forced_status =
        forced_status_encrypt;

    if ( fake_output_encrypt->len > 0 )
    {
        mbedtls_test_driver_asymmetric_encryption_hooks.forced_output =
            fake_output_encrypt->x;
        mbedtls_test_driver_asymmetric_encryption_hooks.forced_output_length =
            fake_output_encrypt->len;
        output_size = fake_output_encrypt->len;
        ASSERT_ALLOC( output, output_size );
    }
    else
    {
        output_size = PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE( key_type, key_bits, alg );
        ASSERT_ALLOC( output, output_size );
    }

    TEST_EQUAL( psa_asymmetric_encrypt( key, alg,
                                        input_data->x, input_data->len,
                                        label->x, label->len,
                                        output, output_size,
                                        &output_length ), expected_status_encrypt );
    if ( expected_status_encrypt == PSA_SUCCESS )
    {
        if( fake_output_encrypt->len > 0 )
        {
            TEST_EQUAL( fake_output_encrypt->len, output_length );
            ASSERT_COMPARE( fake_output_encrypt->x, fake_output_encrypt->len,
                     output, output_length );
        }
        else
        {
            /* Perform sanity checks on the output */
#if PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY
            if( PSA_KEY_TYPE_IS_RSA( key_type ) )
            {
                if( ! sanity_check_rsa_encryption_result(
                        alg, modulus, private_exponent,
                        input_data,
                        output, output_length ) )
                    goto exit;
            }
            else
#endif
            {
                (void) modulus;
                (void) private_exponent;
                TEST_ASSERT( ! "Encryption sanity checks not implemented for this key type" );
            }
        }
    }
exit:
    /*
     * Key attributes may have been returned by psa_get_key_attributes()
     * thus reset them as required.
     */
    psa_reset_key_attributes( &attributes );

    psa_destroy_key( key );
    mbedtls_free( output );
    PSA_DONE( );
}
/* END_CASE */

/* BEGIN_CASE */
void aead_encrypt_setup( int key_type_arg, data_t *key_data,
                         int alg_arg,
                         data_t *nonce,
                         data_t *additional_data,
                         data_t *input_data,
                         data_t *expected_ciphertext,
                         data_t *expected_tag,
                         int forced_status_arg,
                         int expected_status_arg )
{
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    psa_key_type_t key_type = key_type_arg;
    psa_algorithm_t alg = alg_arg;
    size_t key_bits;
    psa_status_t forced_status = forced_status_arg;
    psa_status_t expected_status = expected_status_arg;
    uint8_t *output_data = NULL;
    size_t output_size = 0;
    size_t output_length = 0;
    size_t finish_output_length = 0;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_status_t status = PSA_ERROR_GENERIC_ERROR;
    size_t tag_length = 0;
    uint8_t tag_buffer[PSA_AEAD_TAG_MAX_SIZE];

    psa_aead_operation_t operation = psa_aead_operation_init();

    mbedtls_test_driver_aead_hooks = mbedtls_test_driver_aead_hooks_init();

    PSA_INIT( );

    mbedtls_test_driver_aead_hooks.forced_status = forced_status;

    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_data->x, key_data->len,
                                &key ) );
    PSA_ASSERT( psa_get_key_attributes( key, &attributes ) );
    key_bits = psa_get_key_bits( &attributes );

    output_size = input_data->len + PSA_AEAD_TAG_LENGTH( key_type, key_bits,
                                                         alg );

    /* For all currently defined algorithms, PSA_AEAD_ENCRYPT_OUTPUT_SIZE
     * should be exact. */
    TEST_EQUAL( output_size,
                PSA_AEAD_ENCRYPT_OUTPUT_SIZE( key_type, alg, input_data->len ) );
    TEST_ASSERT( output_size <=
                 PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE( input_data->len ) );
    ASSERT_ALLOC( output_data, output_size );

    status = psa_aead_encrypt_setup( &operation, key, alg );

    TEST_EQUAL( status, expected_status );
    TEST_EQUAL( mbedtls_test_driver_aead_hooks.hits_encrypt_setup, 1 );

    if( status == PSA_SUCCESS )
    {
        /* Set the nonce. */
        PSA_ASSERT( psa_aead_set_nonce( &operation, nonce->x, nonce->len ) );

        TEST_EQUAL( mbedtls_test_driver_aead_hooks.hits_set_nonce,
                    forced_status == PSA_SUCCESS ? 1 : 0 );

        /* Check hooks hits and
         * set length (additional data and data to encrypt) */
        PSA_ASSERT( psa_aead_set_lengths( &operation, additional_data->len,
                                          input_data->len ) );

        TEST_EQUAL( mbedtls_test_driver_aead_hooks.hits_set_lengths,
                    forced_status == PSA_SUCCESS ? 1 : 0 );

        /* Pass the additional data */
        PSA_ASSERT( psa_aead_update_ad( &operation, additional_data->x,
                                        additional_data->len ) );

        TEST_EQUAL( mbedtls_test_driver_aead_hooks.hits_update_ad,
                    forced_status == PSA_SUCCESS ? 1 : 0 );

        /* Pass the data to encrypt */
        PSA_ASSERT( psa_aead_update( &operation, input_data->x, input_data->len,
                                     output_data, output_size, &output_length ) );

        TEST_EQUAL( mbedtls_test_driver_aead_hooks.hits_update,
                    forced_status == PSA_SUCCESS ? 1 : 0 );

        /* Finish the encryption operation */
        PSA_ASSERT( psa_aead_finish( &operation, output_data + output_length,
                                     output_size - output_length,
                                     &finish_output_length, tag_buffer,
                                     PSA_AEAD_TAG_MAX_SIZE, &tag_length ) );

        TEST_EQUAL( mbedtls_test_driver_aead_hooks.hits_finish,
                    forced_status == PSA_SUCCESS ? 1 : 0 );

        TEST_EQUAL( mbedtls_test_driver_aead_hooks.hits_abort,
                    forced_status == PSA_SUCCESS ? 1 : 0 );

        /* Compare output_data and expected_ciphertext */
        ASSERT_COMPARE( expected_ciphertext->x, expected_ciphertext->len,
                        output_data, output_length + finish_output_length );

        /* Compare tag and expected_tag */
        ASSERT_COMPARE( expected_tag->x, expected_tag->len, tag_buffer, tag_length );
    }

exit:
    /* Cleanup */
    PSA_ASSERT( psa_destroy_key( key ) );
    mbedtls_free( output_data );
    PSA_DONE( );
    mbedtls_test_driver_aead_hooks = mbedtls_test_driver_aead_hooks_init();
}
/* END_CASE */

/* BEGIN_CASE */
void aead_decrypt_setup( int key_type_arg, data_t *key_data,
                         int alg_arg,
                         data_t *nonce,
                         data_t *additional_data,
                         data_t *input_ciphertext,
                         data_t *input_tag,
                         data_t *expected_result,
                         int forced_status_arg,
                         int expected_status_arg )
{
    mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
    psa_key_type_t key_type = key_type_arg;
    psa_algorithm_t alg = alg_arg;
    unsigned char *output_data = NULL;
    size_t output_size = 0;
    size_t output_length = 0;
    size_t verify_output_length = 0;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_status_t forced_status = forced_status_arg;
    psa_status_t expected_status = expected_status_arg;
    psa_status_t status = PSA_ERROR_GENERIC_ERROR;

    psa_aead_operation_t operation = psa_aead_operation_init();
    mbedtls_test_driver_aead_hooks = mbedtls_test_driver_aead_hooks_init();

    PSA_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_data->x, key_data->len,
                                &key ) );

    output_size = input_ciphertext->len;

    ASSERT_ALLOC( output_data, output_size );

    mbedtls_test_driver_aead_hooks.forced_status = forced_status;

    status = psa_aead_decrypt_setup( &operation, key, alg );

    TEST_EQUAL( status, ( forced_status == PSA_ERROR_NOT_SUPPORTED ) ?
                        PSA_SUCCESS : forced_status );

    TEST_EQUAL( status, expected_status );
    TEST_EQUAL( mbedtls_test_driver_aead_hooks.hits_decrypt_setup, 1 );

    if( status == PSA_SUCCESS )
    {
        PSA_ASSERT( psa_aead_set_nonce( &operation, nonce->x, nonce->len ) );
        TEST_EQUAL( mbedtls_test_driver_aead_hooks.hits_set_nonce,
                    forced_status == PSA_SUCCESS ? 1 : 0 );

        PSA_ASSERT( psa_aead_set_lengths( &operation, additional_data->len,
                                                      input_ciphertext->len ) );

        TEST_EQUAL( mbedtls_test_driver_aead_hooks.hits_set_lengths,
                    forced_status == PSA_SUCCESS ? 1 : 0 );

        PSA_ASSERT( psa_aead_update_ad( &operation, additional_data->x,
                                                    additional_data->len ) );

        TEST_EQUAL( mbedtls_test_driver_aead_hooks.hits_update_ad,
                    forced_status == PSA_SUCCESS ? 1 : 0 );

        PSA_ASSERT( psa_aead_update( &operation, input_ciphertext->x,
                                     input_ciphertext->len, output_data,
                                     output_size, &output_length ) );

        TEST_EQUAL( mbedtls_test_driver_aead_hooks.hits_update,
                    forced_status == PSA_SUCCESS ? 1 : 0 );

        /* Offset applied to output_data in order to handle cases where verify()
         * outputs further data */
        PSA_ASSERT( psa_aead_verify( &operation, output_data + output_length,
                                     output_size - output_length,
                                     &verify_output_length, input_tag->x,
                                     input_tag->len ) );

        TEST_EQUAL( mbedtls_test_driver_aead_hooks.hits_verify,
                    forced_status == PSA_SUCCESS ? 1 : 0 );

        /* Since this is a decryption operation,
         * finish should never be hit */
        TEST_EQUAL( mbedtls_test_driver_aead_hooks.hits_finish, 0 );

        TEST_EQUAL( mbedtls_test_driver_aead_hooks.hits_abort,
                    forced_status == PSA_SUCCESS ? 1 : 0 );

        ASSERT_COMPARE( expected_result->x, expected_result->len,
                        output_data, output_length + verify_output_length );
    }

exit:
    PSA_ASSERT( psa_destroy_key( key ) );
    mbedtls_free( output_data );
    PSA_DONE( );
}
/* END_CASE */