/* THIS FILE WAS AUTO-GENERATED BY psa_sim_generate.pl. DO NOT EDIT!! */

/* client calls */

/*
 *  Copyright The Mbed TLS Contributors
 *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
 */

#include <stdio.h>
#include <unistd.h>

/* Includes from psasim */
#include <client.h>
#include <util.h>
#include "psa_manifest/sid.h"
#include "psa_functions_codes.h"
#include "psa_sim_serialise.h"

/* Includes from mbedtls */
#include "mbedtls/version.h"
#include "psa/crypto.h"

#define CLIENT_PRINT(fmt, ...) \
    INFO("Client: " fmt, ##__VA_ARGS__)

static psa_handle_t handle = -1;

#if defined(MBEDTLS_PSA_CRYPTO_C)
#error "Error: MBEDTLS_PSA_CRYPTO_C must be disabled on client build"
#endif

int psa_crypto_call(int function,
                    uint8_t *in_params, size_t in_params_len,
                    uint8_t **out_params, size_t *out_params_len)
{
    // psa_outvec outvecs[1];
    if (handle < 0) {
        fprintf(stderr, "NOT CONNECTED\n");
        exit(1);
    }

    psa_invec invec;
    invec.base = in_params;
    invec.len = in_params_len;

    size_t max_receive = 24576;
    uint8_t *receive = malloc(max_receive);
    if (receive == NULL) {
        fprintf(stderr, "FAILED to allocate %u bytes\n", (unsigned) max_receive);
        exit(1);
    }

    size_t actual_received = 0;

    psa_outvec outvecs[2];
    outvecs[0].base = &actual_received;
    outvecs[0].len = sizeof(actual_received);
    outvecs[1].base = receive;
    outvecs[1].len = max_receive;

    psa_status_t status = psa_call(handle, function, &invec, 1, outvecs, 2);
    if (status != PSA_SUCCESS) {
        free(receive);
        return 0;
    }

    *out_params = receive;
    *out_params_len = actual_received;

    return 1;   // success
}

psa_status_t psa_crypto_init(void)
{
    const char *mbedtls_version;
    uint8_t *result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    mbedtls_version = mbedtls_version_get_string_full();
    CLIENT_PRINT("%s", mbedtls_version);

    CLIENT_PRINT("My PID: %d", getpid());

    CLIENT_PRINT("PSA version: %u", psa_version(PSA_SID_CRYPTO_SID));
    handle = psa_connect(PSA_SID_CRYPTO_SID, 1);

    if (handle < 0) {
        CLIENT_PRINT("Couldn't connect %d", handle);
        return PSA_ERROR_COMMUNICATION_FAILURE;
    }

    int ok = psa_crypto_call(PSA_CRYPTO_INIT, NULL, 0, &result, &result_length);
    CLIENT_PRINT("PSA_CRYPTO_INIT returned: %d", ok);

    if (!ok) {
        goto fail;
    }

    uint8_t *rpos = result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(&rpos, &rremain, &status);
    if (!ok) {
        goto fail;
    }

fail:
    free(result);

    return status;
}

void mbedtls_psa_crypto_free(void)
{
    /* Do not try to close a connection that was never started.*/
    if (handle == -1) {
        return;
    }

    CLIENT_PRINT("Closing handle");
    psa_close(handle);
    handle = -1;
}


psa_status_t psa_aead_abort(
    psa_aead_operation_t *operation
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_aead_operation_t_needs(*operation);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_aead_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_AEAD_ABORT,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_AEAD_ABORT server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_aead_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_aead_decrypt(
    mbedtls_svc_key_id_t key,
    psa_algorithm_t alg,
    const uint8_t *nonce, size_t  nonce_length,
    const uint8_t *additional_data, size_t  additional_data_length,
    const uint8_t *ciphertext, size_t  ciphertext_length,
    uint8_t *plaintext, size_t  plaintext_size,
    size_t *plaintext_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_psa_algorithm_t_needs(alg) +
        psasim_serialise_buffer_needs(nonce, nonce_length) +
        psasim_serialise_buffer_needs(additional_data, additional_data_length) +
        psasim_serialise_buffer_needs(ciphertext, ciphertext_length) +
        psasim_serialise_buffer_needs(plaintext, plaintext_size) +
        psasim_serialise_size_t_needs(*plaintext_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        nonce, nonce_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        additional_data, additional_data_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        ciphertext, ciphertext_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        plaintext, plaintext_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *plaintext_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_AEAD_DECRYPT,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_AEAD_DECRYPT server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        plaintext, plaintext_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        plaintext_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_aead_decrypt_setup(
    psa_aead_operation_t *operation,
    mbedtls_svc_key_id_t key,
    psa_algorithm_t alg
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_aead_operation_t_needs(*operation) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_psa_algorithm_t_needs(alg);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_aead_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_AEAD_DECRYPT_SETUP,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_AEAD_DECRYPT_SETUP server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_aead_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_aead_encrypt(
    mbedtls_svc_key_id_t key,
    psa_algorithm_t alg,
    const uint8_t *nonce, size_t  nonce_length,
    const uint8_t *additional_data, size_t  additional_data_length,
    const uint8_t *plaintext, size_t  plaintext_length,
    uint8_t *ciphertext, size_t  ciphertext_size,
    size_t *ciphertext_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_psa_algorithm_t_needs(alg) +
        psasim_serialise_buffer_needs(nonce, nonce_length) +
        psasim_serialise_buffer_needs(additional_data, additional_data_length) +
        psasim_serialise_buffer_needs(plaintext, plaintext_length) +
        psasim_serialise_buffer_needs(ciphertext, ciphertext_size) +
        psasim_serialise_size_t_needs(*ciphertext_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        nonce, nonce_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        additional_data, additional_data_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        plaintext, plaintext_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        ciphertext, ciphertext_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *ciphertext_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_AEAD_ENCRYPT,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_AEAD_ENCRYPT server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        ciphertext, ciphertext_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        ciphertext_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_aead_encrypt_setup(
    psa_aead_operation_t *operation,
    mbedtls_svc_key_id_t key,
    psa_algorithm_t alg
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_aead_operation_t_needs(*operation) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_psa_algorithm_t_needs(alg);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_aead_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_AEAD_ENCRYPT_SETUP,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_AEAD_ENCRYPT_SETUP server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_aead_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_aead_finish(
    psa_aead_operation_t *operation,
    uint8_t *ciphertext, size_t  ciphertext_size,
    size_t *ciphertext_length,
    uint8_t *tag, size_t  tag_size,
    size_t *tag_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_aead_operation_t_needs(*operation) +
        psasim_serialise_buffer_needs(ciphertext, ciphertext_size) +
        psasim_serialise_size_t_needs(*ciphertext_length) +
        psasim_serialise_buffer_needs(tag, tag_size) +
        psasim_serialise_size_t_needs(*tag_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_aead_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        ciphertext, ciphertext_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *ciphertext_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        tag, tag_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *tag_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_AEAD_FINISH,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_AEAD_FINISH server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_aead_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        ciphertext, ciphertext_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        ciphertext_length);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        tag, tag_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        tag_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_aead_generate_nonce(
    psa_aead_operation_t *operation,
    uint8_t *nonce, size_t  nonce_size,
    size_t *nonce_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_aead_operation_t_needs(*operation) +
        psasim_serialise_buffer_needs(nonce, nonce_size) +
        psasim_serialise_size_t_needs(*nonce_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_aead_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        nonce, nonce_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *nonce_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_AEAD_GENERATE_NONCE,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_AEAD_GENERATE_NONCE server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_aead_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        nonce, nonce_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        nonce_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_aead_set_lengths(
    psa_aead_operation_t *operation,
    size_t ad_length,
    size_t plaintext_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_aead_operation_t_needs(*operation) +
        psasim_serialise_size_t_needs(ad_length) +
        psasim_serialise_size_t_needs(plaintext_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_aead_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        ad_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        plaintext_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_AEAD_SET_LENGTHS,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_AEAD_SET_LENGTHS server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_aead_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_aead_set_nonce(
    psa_aead_operation_t *operation,
    const uint8_t *nonce, size_t  nonce_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_aead_operation_t_needs(*operation) +
        psasim_serialise_buffer_needs(nonce, nonce_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_aead_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        nonce, nonce_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_AEAD_SET_NONCE,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_AEAD_SET_NONCE server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_aead_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_aead_update(
    psa_aead_operation_t *operation,
    const uint8_t *input, size_t  input_length,
    uint8_t *output, size_t  output_size,
    size_t *output_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_aead_operation_t_needs(*operation) +
        psasim_serialise_buffer_needs(input, input_length) +
        psasim_serialise_buffer_needs(output, output_size) +
        psasim_serialise_size_t_needs(*output_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_aead_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        input, input_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        output, output_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *output_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_AEAD_UPDATE,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_AEAD_UPDATE server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_aead_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        output, output_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        output_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_aead_update_ad(
    psa_aead_operation_t *operation,
    const uint8_t *input, size_t  input_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_aead_operation_t_needs(*operation) +
        psasim_serialise_buffer_needs(input, input_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_aead_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        input, input_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_AEAD_UPDATE_AD,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_AEAD_UPDATE_AD server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_aead_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_aead_verify(
    psa_aead_operation_t *operation,
    uint8_t *plaintext, size_t  plaintext_size,
    size_t *plaintext_length,
    const uint8_t *tag, size_t  tag_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_aead_operation_t_needs(*operation) +
        psasim_serialise_buffer_needs(plaintext, plaintext_size) +
        psasim_serialise_size_t_needs(*plaintext_length) +
        psasim_serialise_buffer_needs(tag, tag_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_aead_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        plaintext, plaintext_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *plaintext_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        tag, tag_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_AEAD_VERIFY,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_AEAD_VERIFY server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_aead_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        plaintext, plaintext_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        plaintext_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_asymmetric_decrypt(
    mbedtls_svc_key_id_t key,
    psa_algorithm_t alg,
    const uint8_t *input, size_t  input_length,
    const uint8_t *salt, size_t  salt_length,
    uint8_t *output, size_t  output_size,
    size_t *output_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_psa_algorithm_t_needs(alg) +
        psasim_serialise_buffer_needs(input, input_length) +
        psasim_serialise_buffer_needs(salt, salt_length) +
        psasim_serialise_buffer_needs(output, output_size) +
        psasim_serialise_size_t_needs(*output_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        input, input_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        salt, salt_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        output, output_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *output_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_ASYMMETRIC_DECRYPT,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_ASYMMETRIC_DECRYPT server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        output, output_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        output_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_asymmetric_encrypt(
    mbedtls_svc_key_id_t key,
    psa_algorithm_t alg,
    const uint8_t *input, size_t  input_length,
    const uint8_t *salt, size_t  salt_length,
    uint8_t *output, size_t  output_size,
    size_t *output_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_psa_algorithm_t_needs(alg) +
        psasim_serialise_buffer_needs(input, input_length) +
        psasim_serialise_buffer_needs(salt, salt_length) +
        psasim_serialise_buffer_needs(output, output_size) +
        psasim_serialise_size_t_needs(*output_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        input, input_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        salt, salt_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        output, output_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *output_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_ASYMMETRIC_ENCRYPT,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_ASYMMETRIC_ENCRYPT server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        output, output_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        output_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


int psa_can_do_hash(
    psa_algorithm_t hash_alg
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    int value = 0;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_algorithm_t_needs(hash_alg);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        hash_alg);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_CAN_DO_HASH,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_CAN_DO_HASH server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_int(
        &rpos, &rremain,
        &value);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return value;
}


psa_status_t psa_cipher_abort(
    psa_cipher_operation_t *operation
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_cipher_operation_t_needs(*operation);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_cipher_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_CIPHER_ABORT,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_CIPHER_ABORT server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_cipher_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_cipher_decrypt(
    mbedtls_svc_key_id_t key,
    psa_algorithm_t alg,
    const uint8_t *input, size_t  input_length,
    uint8_t *output, size_t  output_size,
    size_t *output_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_psa_algorithm_t_needs(alg) +
        psasim_serialise_buffer_needs(input, input_length) +
        psasim_serialise_buffer_needs(output, output_size) +
        psasim_serialise_size_t_needs(*output_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        input, input_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        output, output_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *output_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_CIPHER_DECRYPT,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_CIPHER_DECRYPT server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        output, output_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        output_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_cipher_decrypt_setup(
    psa_cipher_operation_t *operation,
    mbedtls_svc_key_id_t key,
    psa_algorithm_t alg
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_cipher_operation_t_needs(*operation) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_psa_algorithm_t_needs(alg);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_cipher_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_CIPHER_DECRYPT_SETUP,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_CIPHER_DECRYPT_SETUP server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_cipher_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_cipher_encrypt(
    mbedtls_svc_key_id_t key,
    psa_algorithm_t alg,
    const uint8_t *input, size_t  input_length,
    uint8_t *output, size_t  output_size,
    size_t *output_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_psa_algorithm_t_needs(alg) +
        psasim_serialise_buffer_needs(input, input_length) +
        psasim_serialise_buffer_needs(output, output_size) +
        psasim_serialise_size_t_needs(*output_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        input, input_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        output, output_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *output_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_CIPHER_ENCRYPT,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_CIPHER_ENCRYPT server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        output, output_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        output_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_cipher_encrypt_setup(
    psa_cipher_operation_t *operation,
    mbedtls_svc_key_id_t key,
    psa_algorithm_t alg
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_cipher_operation_t_needs(*operation) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_psa_algorithm_t_needs(alg);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_cipher_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_CIPHER_ENCRYPT_SETUP,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_CIPHER_ENCRYPT_SETUP server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_cipher_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_cipher_finish(
    psa_cipher_operation_t *operation,
    uint8_t *output, size_t  output_size,
    size_t *output_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_cipher_operation_t_needs(*operation) +
        psasim_serialise_buffer_needs(output, output_size) +
        psasim_serialise_size_t_needs(*output_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_cipher_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        output, output_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *output_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_CIPHER_FINISH,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_CIPHER_FINISH server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_cipher_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        output, output_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        output_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_cipher_generate_iv(
    psa_cipher_operation_t *operation,
    uint8_t *iv, size_t  iv_size,
    size_t *iv_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_cipher_operation_t_needs(*operation) +
        psasim_serialise_buffer_needs(iv, iv_size) +
        psasim_serialise_size_t_needs(*iv_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_cipher_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        iv, iv_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *iv_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_CIPHER_GENERATE_IV,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_CIPHER_GENERATE_IV server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_cipher_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        iv, iv_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        iv_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_cipher_set_iv(
    psa_cipher_operation_t *operation,
    const uint8_t *iv, size_t  iv_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_cipher_operation_t_needs(*operation) +
        psasim_serialise_buffer_needs(iv, iv_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_cipher_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        iv, iv_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_CIPHER_SET_IV,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_CIPHER_SET_IV server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_cipher_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_cipher_update(
    psa_cipher_operation_t *operation,
    const uint8_t *input, size_t  input_length,
    uint8_t *output, size_t  output_size,
    size_t *output_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_cipher_operation_t_needs(*operation) +
        psasim_serialise_buffer_needs(input, input_length) +
        psasim_serialise_buffer_needs(output, output_size) +
        psasim_serialise_size_t_needs(*output_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_cipher_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        input, input_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        output, output_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *output_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_CIPHER_UPDATE,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_CIPHER_UPDATE server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_cipher_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        output, output_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        output_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_copy_key(
    mbedtls_svc_key_id_t source_key,
    const psa_key_attributes_t *attributes,
    mbedtls_svc_key_id_t *target_key
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_mbedtls_svc_key_id_t_needs(source_key) +
        psasim_serialise_psa_key_attributes_t_needs(*attributes) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(*target_key);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        source_key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_attributes_t(
        &pos, &remaining,
        *attributes);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        *target_key);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_COPY_KEY,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_COPY_KEY server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_mbedtls_svc_key_id_t(
        &rpos, &rremain,
        target_key);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_destroy_key(
    mbedtls_svc_key_id_t key
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_DESTROY_KEY,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_DESTROY_KEY server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_export_key(
    mbedtls_svc_key_id_t key,
    uint8_t *data, size_t  data_size,
    size_t *data_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_buffer_needs(data, data_size) +
        psasim_serialise_size_t_needs(*data_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        data, data_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *data_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_EXPORT_KEY,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_EXPORT_KEY server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        data, data_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        data_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_export_public_key(
    mbedtls_svc_key_id_t key,
    uint8_t *data, size_t  data_size,
    size_t *data_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_buffer_needs(data, data_size) +
        psasim_serialise_size_t_needs(*data_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        data, data_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *data_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_EXPORT_PUBLIC_KEY,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_EXPORT_PUBLIC_KEY server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        data, data_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        data_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_export_public_key_iop_abort(
    psa_export_public_key_iop_t *operation
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_export_public_key_iop_t_needs(*operation);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_export_public_key_iop_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_EXPORT_PUBLIC_KEY_IOP_ABORT,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_EXPORT_PUBLIC_KEY_IOP_ABORT server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_export_public_key_iop_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_export_public_key_iop_complete(
    psa_export_public_key_iop_t *operation,
    uint8_t *data, size_t  data_size,
    size_t *data_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_export_public_key_iop_t_needs(*operation) +
        psasim_serialise_buffer_needs(data, data_size) +
        psasim_serialise_size_t_needs(*data_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_export_public_key_iop_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        data, data_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *data_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_EXPORT_PUBLIC_KEY_IOP_COMPLETE,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_EXPORT_PUBLIC_KEY_IOP_COMPLETE server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_export_public_key_iop_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        data, data_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        data_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


uint32_t psa_export_public_key_iop_get_num_ops(
    psa_export_public_key_iop_t *operation
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    uint32_t value = 0;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_export_public_key_iop_t_needs(*operation);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        value = 0;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_export_public_key_iop_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_EXPORT_PUBLIC_KEY_IOP_GET_NUM_OPS,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_EXPORT_PUBLIC_KEY_IOP_GET_NUM_OPS server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_uint32_t(
        &rpos, &rremain,
        &value);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_export_public_key_iop_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return value;
}


psa_status_t psa_export_public_key_iop_setup(
    psa_export_public_key_iop_t *operation,
    mbedtls_svc_key_id_t key
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_export_public_key_iop_t_needs(*operation) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_export_public_key_iop_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_EXPORT_PUBLIC_KEY_IOP_SETUP,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_EXPORT_PUBLIC_KEY_IOP_SETUP server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_export_public_key_iop_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_generate_key(
    const psa_key_attributes_t *attributes,
    mbedtls_svc_key_id_t *key
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_key_attributes_t_needs(*attributes) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(*key);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_attributes_t(
        &pos, &remaining,
        *attributes);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        *key);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_GENERATE_KEY,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_GENERATE_KEY server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_mbedtls_svc_key_id_t(
        &rpos, &rremain,
        key);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_generate_key_custom(
    const psa_key_attributes_t *attributes,
    const psa_custom_key_parameters_t *custom,
    const uint8_t *custom_data, size_t  custom_data_length,
    mbedtls_svc_key_id_t *key
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_key_attributes_t_needs(*attributes) +
        psasim_serialise_psa_custom_key_parameters_t_needs(*custom) +
        psasim_serialise_buffer_needs(custom_data, custom_data_length) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(*key);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_attributes_t(
        &pos, &remaining,
        *attributes);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_custom_key_parameters_t(
        &pos, &remaining,
        *custom);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        custom_data, custom_data_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        *key);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_GENERATE_KEY_CUSTOM,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_GENERATE_KEY_CUSTOM server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_mbedtls_svc_key_id_t(
        &rpos, &rremain,
        key);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_generate_key_iop_abort(
    psa_generate_key_iop_t *operation
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_generate_key_iop_t_needs(*operation);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_generate_key_iop_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_GENERATE_KEY_IOP_ABORT,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_GENERATE_KEY_IOP_ABORT server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_generate_key_iop_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_generate_key_iop_complete(
    psa_generate_key_iop_t *operation,
    mbedtls_svc_key_id_t *key
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_generate_key_iop_t_needs(*operation) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(*key);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_generate_key_iop_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        *key);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_GENERATE_KEY_IOP_COMPLETE,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_GENERATE_KEY_IOP_COMPLETE server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_generate_key_iop_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_mbedtls_svc_key_id_t(
        &rpos, &rremain,
        key);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


uint32_t psa_generate_key_iop_get_num_ops(
    psa_generate_key_iop_t *operation
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    uint32_t value = 0;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_generate_key_iop_t_needs(*operation);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        value = 0;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_generate_key_iop_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_GENERATE_KEY_IOP_GET_NUM_OPS,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_GENERATE_KEY_IOP_GET_NUM_OPS server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_uint32_t(
        &rpos, &rremain,
        &value);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_generate_key_iop_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return value;
}


psa_status_t psa_generate_key_iop_setup(
    psa_generate_key_iop_t *operation,
    const psa_key_attributes_t *attributes
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_generate_key_iop_t_needs(*operation) +
        psasim_serialise_psa_key_attributes_t_needs(*attributes);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_generate_key_iop_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_attributes_t(
        &pos, &remaining,
        *attributes);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_GENERATE_KEY_IOP_SETUP,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_GENERATE_KEY_IOP_SETUP server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_generate_key_iop_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_generate_random(
    uint8_t *output, size_t  output_size
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_buffer_needs(output, output_size);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        output, output_size);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_GENERATE_RANDOM,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_GENERATE_RANDOM server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        output, output_size);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_get_key_attributes(
    mbedtls_svc_key_id_t key,
    psa_key_attributes_t *attributes
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_psa_key_attributes_t_needs(*attributes);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_attributes_t(
        &pos, &remaining,
        *attributes);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_GET_KEY_ATTRIBUTES,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_GET_KEY_ATTRIBUTES server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_key_attributes_t(
        &rpos, &rremain,
        attributes);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_hash_abort(
    psa_hash_operation_t *operation
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_hash_operation_t_needs(*operation);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_hash_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_HASH_ABORT,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_HASH_ABORT server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_hash_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_hash_clone(
    const psa_hash_operation_t *source_operation,
    psa_hash_operation_t *target_operation
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_hash_operation_t_needs(*source_operation) +
        psasim_serialise_psa_hash_operation_t_needs(*target_operation);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_hash_operation_t(
        &pos, &remaining,
        *source_operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_hash_operation_t(
        &pos, &remaining,
        *target_operation);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_HASH_CLONE,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_HASH_CLONE server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_hash_operation_t(
        &rpos, &rremain,
        target_operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_hash_compare(
    psa_algorithm_t alg,
    const uint8_t *input, size_t  input_length,
    const uint8_t *hash, size_t  hash_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_algorithm_t_needs(alg) +
        psasim_serialise_buffer_needs(input, input_length) +
        psasim_serialise_buffer_needs(hash, hash_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        input, input_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        hash, hash_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_HASH_COMPARE,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_HASH_COMPARE server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_hash_compute(
    psa_algorithm_t alg,
    const uint8_t *input, size_t  input_length,
    uint8_t *hash, size_t  hash_size,
    size_t *hash_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_algorithm_t_needs(alg) +
        psasim_serialise_buffer_needs(input, input_length) +
        psasim_serialise_buffer_needs(hash, hash_size) +
        psasim_serialise_size_t_needs(*hash_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        input, input_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        hash, hash_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *hash_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_HASH_COMPUTE,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_HASH_COMPUTE server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        hash, hash_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        hash_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_hash_finish(
    psa_hash_operation_t *operation,
    uint8_t *hash, size_t  hash_size,
    size_t *hash_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_hash_operation_t_needs(*operation) +
        psasim_serialise_buffer_needs(hash, hash_size) +
        psasim_serialise_size_t_needs(*hash_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_hash_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        hash, hash_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *hash_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_HASH_FINISH,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_HASH_FINISH server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_hash_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        hash, hash_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        hash_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_hash_setup(
    psa_hash_operation_t *operation,
    psa_algorithm_t alg
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_hash_operation_t_needs(*operation) +
        psasim_serialise_psa_algorithm_t_needs(alg);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_hash_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_HASH_SETUP,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_HASH_SETUP server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_hash_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_hash_update(
    psa_hash_operation_t *operation,
    const uint8_t *input, size_t  input_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_hash_operation_t_needs(*operation) +
        psasim_serialise_buffer_needs(input, input_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_hash_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        input, input_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_HASH_UPDATE,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_HASH_UPDATE server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_hash_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_hash_verify(
    psa_hash_operation_t *operation,
    const uint8_t *hash, size_t  hash_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_hash_operation_t_needs(*operation) +
        psasim_serialise_buffer_needs(hash, hash_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_hash_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        hash, hash_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_HASH_VERIFY,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_HASH_VERIFY server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_hash_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_import_key(
    const psa_key_attributes_t *attributes,
    const uint8_t *data, size_t  data_length,
    mbedtls_svc_key_id_t *key
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_key_attributes_t_needs(*attributes) +
        psasim_serialise_buffer_needs(data, data_length) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(*key);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_attributes_t(
        &pos, &remaining,
        *attributes);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        data, data_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        *key);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_IMPORT_KEY,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_IMPORT_KEY server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_mbedtls_svc_key_id_t(
        &rpos, &rremain,
        key);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


uint32_t psa_interruptible_get_max_ops(
    void
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    uint32_t value = 0;

    size_t needed =
        psasim_serialise_begin_needs() +
        0;

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        value = 0;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_INTERRUPTIBLE_GET_MAX_OPS,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_INTERRUPTIBLE_GET_MAX_OPS server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_uint32_t(
        &rpos, &rremain,
        &value);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return value;
}


void psa_interruptible_set_max_ops(
    uint32_t max_ops
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_uint32_t_needs(max_ops);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_uint32_t(
        &pos, &remaining,
        max_ops);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_INTERRUPTIBLE_SET_MAX_OPS,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_INTERRUPTIBLE_SET_MAX_OPS server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);
}


psa_status_t psa_key_agreement(
    mbedtls_svc_key_id_t private_key,
    const uint8_t *peer_key, size_t  peer_key_length,
    psa_algorithm_t alg,
    const psa_key_attributes_t *attributes,
    mbedtls_svc_key_id_t *key
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_mbedtls_svc_key_id_t_needs(private_key) +
        psasim_serialise_buffer_needs(peer_key, peer_key_length) +
        psasim_serialise_psa_algorithm_t_needs(alg) +
        psasim_serialise_psa_key_attributes_t_needs(*attributes) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(*key);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        private_key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        peer_key, peer_key_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_attributes_t(
        &pos, &remaining,
        *attributes);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        *key);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_KEY_AGREEMENT,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_KEY_AGREEMENT server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_mbedtls_svc_key_id_t(
        &rpos, &rremain,
        key);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_key_agreement_iop_abort(
    psa_key_agreement_iop_t *operation
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_key_agreement_iop_t_needs(*operation);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_agreement_iop_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_KEY_AGREEMENT_IOP_ABORT,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_KEY_AGREEMENT_IOP_ABORT server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_key_agreement_iop_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_key_agreement_iop_complete(
    psa_key_agreement_iop_t *operation,
    mbedtls_svc_key_id_t *key
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_key_agreement_iop_t_needs(*operation) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(*key);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_agreement_iop_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        *key);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_KEY_AGREEMENT_IOP_COMPLETE,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_KEY_AGREEMENT_IOP_COMPLETE server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_key_agreement_iop_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_mbedtls_svc_key_id_t(
        &rpos, &rremain,
        key);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


uint32_t psa_key_agreement_iop_get_num_ops(
    psa_key_agreement_iop_t *operation
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    uint32_t value = 0;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_key_agreement_iop_t_needs(*operation);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        value = 0;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_agreement_iop_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_KEY_AGREEMENT_IOP_GET_NUM_OPS,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_KEY_AGREEMENT_IOP_GET_NUM_OPS server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_uint32_t(
        &rpos, &rremain,
        &value);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_key_agreement_iop_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return value;
}


psa_status_t psa_key_agreement_iop_setup(
    psa_key_agreement_iop_t *operation,
    mbedtls_svc_key_id_t private_key,
    const uint8_t *peer_key, size_t  peer_key_length,
    psa_algorithm_t alg,
    const psa_key_attributes_t *attributes
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_key_agreement_iop_t_needs(*operation) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(private_key) +
        psasim_serialise_buffer_needs(peer_key, peer_key_length) +
        psasim_serialise_psa_algorithm_t_needs(alg) +
        psasim_serialise_psa_key_attributes_t_needs(*attributes);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_agreement_iop_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        private_key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        peer_key, peer_key_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_attributes_t(
        &pos, &remaining,
        *attributes);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_KEY_AGREEMENT_IOP_SETUP,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_KEY_AGREEMENT_IOP_SETUP server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_key_agreement_iop_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_key_derivation_abort(
    psa_key_derivation_operation_t *operation
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_key_derivation_operation_t_needs(*operation);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_derivation_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_KEY_DERIVATION_ABORT,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_KEY_DERIVATION_ABORT server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_key_derivation_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_key_derivation_get_capacity(
    const psa_key_derivation_operation_t *operation,
    size_t *capacity
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_key_derivation_operation_t_needs(*operation) +
        psasim_serialise_size_t_needs(*capacity);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_derivation_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *capacity);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_KEY_DERIVATION_GET_CAPACITY,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_KEY_DERIVATION_GET_CAPACITY server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        capacity);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_key_derivation_input_bytes(
    psa_key_derivation_operation_t *operation,
    psa_key_derivation_step_t step,
    const uint8_t *data, size_t  data_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_key_derivation_operation_t_needs(*operation) +
        psasim_serialise_psa_key_derivation_step_t_needs(step) +
        psasim_serialise_buffer_needs(data, data_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_derivation_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_derivation_step_t(
        &pos, &remaining,
        step);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        data, data_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_KEY_DERIVATION_INPUT_BYTES,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_KEY_DERIVATION_INPUT_BYTES server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_key_derivation_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_key_derivation_input_integer(
    psa_key_derivation_operation_t *operation,
    psa_key_derivation_step_t step,
    uint64_t value
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_key_derivation_operation_t_needs(*operation) +
        psasim_serialise_psa_key_derivation_step_t_needs(step) +
        psasim_serialise_uint64_t_needs(value);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_derivation_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_derivation_step_t(
        &pos, &remaining,
        step);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_uint64_t(
        &pos, &remaining,
        value);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_KEY_DERIVATION_INPUT_INTEGER,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_KEY_DERIVATION_INPUT_INTEGER server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_key_derivation_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_key_derivation_input_key(
    psa_key_derivation_operation_t *operation,
    psa_key_derivation_step_t step,
    mbedtls_svc_key_id_t key
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_key_derivation_operation_t_needs(*operation) +
        psasim_serialise_psa_key_derivation_step_t_needs(step) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_derivation_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_derivation_step_t(
        &pos, &remaining,
        step);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_KEY_DERIVATION_INPUT_KEY,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_KEY_DERIVATION_INPUT_KEY server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_key_derivation_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_key_derivation_key_agreement(
    psa_key_derivation_operation_t *operation,
    psa_key_derivation_step_t step,
    mbedtls_svc_key_id_t private_key,
    const uint8_t *peer_key, size_t  peer_key_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_key_derivation_operation_t_needs(*operation) +
        psasim_serialise_psa_key_derivation_step_t_needs(step) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(private_key) +
        psasim_serialise_buffer_needs(peer_key, peer_key_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_derivation_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_derivation_step_t(
        &pos, &remaining,
        step);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        private_key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        peer_key, peer_key_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_KEY_DERIVATION_KEY_AGREEMENT,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_KEY_DERIVATION_KEY_AGREEMENT server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_key_derivation_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_key_derivation_output_bytes(
    psa_key_derivation_operation_t *operation,
    uint8_t *output, size_t  output_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_key_derivation_operation_t_needs(*operation) +
        psasim_serialise_buffer_needs(output, output_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_derivation_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        output, output_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_KEY_DERIVATION_OUTPUT_BYTES,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_KEY_DERIVATION_OUTPUT_BYTES server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_key_derivation_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        output, output_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_key_derivation_output_key(
    const psa_key_attributes_t *attributes,
    psa_key_derivation_operation_t *operation,
    mbedtls_svc_key_id_t *key
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_key_attributes_t_needs(*attributes) +
        psasim_serialise_psa_key_derivation_operation_t_needs(*operation) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(*key);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_attributes_t(
        &pos, &remaining,
        *attributes);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_derivation_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        *key);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_KEY_DERIVATION_OUTPUT_KEY,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_KEY_DERIVATION_OUTPUT_KEY server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_key_derivation_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_mbedtls_svc_key_id_t(
        &rpos, &rremain,
        key);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_key_derivation_output_key_custom(
    const psa_key_attributes_t *attributes,
    psa_key_derivation_operation_t *operation,
    const psa_custom_key_parameters_t *custom,
    const uint8_t *custom_data, size_t  custom_data_length,
    mbedtls_svc_key_id_t *key
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_key_attributes_t_needs(*attributes) +
        psasim_serialise_psa_key_derivation_operation_t_needs(*operation) +
        psasim_serialise_psa_custom_key_parameters_t_needs(*custom) +
        psasim_serialise_buffer_needs(custom_data, custom_data_length) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(*key);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_attributes_t(
        &pos, &remaining,
        *attributes);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_derivation_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_custom_key_parameters_t(
        &pos, &remaining,
        *custom);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        custom_data, custom_data_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        *key);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_KEY_DERIVATION_OUTPUT_KEY_CUSTOM,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_KEY_DERIVATION_OUTPUT_KEY_CUSTOM server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_key_derivation_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_mbedtls_svc_key_id_t(
        &rpos, &rremain,
        key);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_key_derivation_set_capacity(
    psa_key_derivation_operation_t *operation,
    size_t capacity
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_key_derivation_operation_t_needs(*operation) +
        psasim_serialise_size_t_needs(capacity);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_derivation_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        capacity);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_KEY_DERIVATION_SET_CAPACITY,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_KEY_DERIVATION_SET_CAPACITY server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_key_derivation_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_key_derivation_setup(
    psa_key_derivation_operation_t *operation,
    psa_algorithm_t alg
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_key_derivation_operation_t_needs(*operation) +
        psasim_serialise_psa_algorithm_t_needs(alg);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_derivation_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_KEY_DERIVATION_SETUP,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_KEY_DERIVATION_SETUP server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_key_derivation_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_mac_abort(
    psa_mac_operation_t *operation
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_mac_operation_t_needs(*operation);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_mac_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_MAC_ABORT,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_MAC_ABORT server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_mac_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_mac_compute(
    mbedtls_svc_key_id_t key,
    psa_algorithm_t alg,
    const uint8_t *input, size_t  input_length,
    uint8_t *mac, size_t  mac_size,
    size_t *mac_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_psa_algorithm_t_needs(alg) +
        psasim_serialise_buffer_needs(input, input_length) +
        psasim_serialise_buffer_needs(mac, mac_size) +
        psasim_serialise_size_t_needs(*mac_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        input, input_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        mac, mac_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *mac_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_MAC_COMPUTE,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_MAC_COMPUTE server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        mac, mac_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        mac_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_mac_sign_finish(
    psa_mac_operation_t *operation,
    uint8_t *mac, size_t  mac_size,
    size_t *mac_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_mac_operation_t_needs(*operation) +
        psasim_serialise_buffer_needs(mac, mac_size) +
        psasim_serialise_size_t_needs(*mac_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_mac_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        mac, mac_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *mac_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_MAC_SIGN_FINISH,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_MAC_SIGN_FINISH server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_mac_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        mac, mac_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        mac_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_mac_sign_setup(
    psa_mac_operation_t *operation,
    mbedtls_svc_key_id_t key,
    psa_algorithm_t alg
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_mac_operation_t_needs(*operation) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_psa_algorithm_t_needs(alg);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_mac_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_MAC_SIGN_SETUP,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_MAC_SIGN_SETUP server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_mac_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_mac_update(
    psa_mac_operation_t *operation,
    const uint8_t *input, size_t  input_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_mac_operation_t_needs(*operation) +
        psasim_serialise_buffer_needs(input, input_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_mac_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        input, input_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_MAC_UPDATE,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_MAC_UPDATE server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_mac_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_mac_verify(
    mbedtls_svc_key_id_t key,
    psa_algorithm_t alg,
    const uint8_t *input, size_t  input_length,
    const uint8_t *mac, size_t  mac_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_psa_algorithm_t_needs(alg) +
        psasim_serialise_buffer_needs(input, input_length) +
        psasim_serialise_buffer_needs(mac, mac_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        input, input_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        mac, mac_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_MAC_VERIFY,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_MAC_VERIFY server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_mac_verify_finish(
    psa_mac_operation_t *operation,
    const uint8_t *mac, size_t  mac_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_mac_operation_t_needs(*operation) +
        psasim_serialise_buffer_needs(mac, mac_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_mac_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        mac, mac_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_MAC_VERIFY_FINISH,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_MAC_VERIFY_FINISH server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_mac_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_mac_verify_setup(
    psa_mac_operation_t *operation,
    mbedtls_svc_key_id_t key,
    psa_algorithm_t alg
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_mac_operation_t_needs(*operation) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_psa_algorithm_t_needs(alg);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_mac_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_MAC_VERIFY_SETUP,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_MAC_VERIFY_SETUP server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_mac_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_purge_key(
    mbedtls_svc_key_id_t key
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_PURGE_KEY,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_PURGE_KEY server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_raw_key_agreement(
    psa_algorithm_t alg,
    mbedtls_svc_key_id_t private_key,
    const uint8_t *peer_key, size_t  peer_key_length,
    uint8_t *output, size_t  output_size,
    size_t *output_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_algorithm_t_needs(alg) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(private_key) +
        psasim_serialise_buffer_needs(peer_key, peer_key_length) +
        psasim_serialise_buffer_needs(output, output_size) +
        psasim_serialise_size_t_needs(*output_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        private_key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        peer_key, peer_key_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        output, output_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *output_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_RAW_KEY_AGREEMENT,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_RAW_KEY_AGREEMENT server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        output, output_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        output_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


void psa_reset_key_attributes(
    psa_key_attributes_t *attributes
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_key_attributes_t_needs(*attributes);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_key_attributes_t(
        &pos, &remaining,
        *attributes);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_RESET_KEY_ATTRIBUTES,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_RESET_KEY_ATTRIBUTES server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_key_attributes_t(
        &rpos, &rremain,
        attributes);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);
}


psa_status_t psa_sign_hash(
    mbedtls_svc_key_id_t key,
    psa_algorithm_t alg,
    const uint8_t *hash, size_t  hash_length,
    uint8_t *signature, size_t  signature_size,
    size_t *signature_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_psa_algorithm_t_needs(alg) +
        psasim_serialise_buffer_needs(hash, hash_length) +
        psasim_serialise_buffer_needs(signature, signature_size) +
        psasim_serialise_size_t_needs(*signature_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        hash, hash_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        signature, signature_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *signature_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_SIGN_HASH,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_SIGN_HASH server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        signature, signature_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        signature_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_sign_hash_abort(
    psa_sign_hash_interruptible_operation_t *operation
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_sign_hash_interruptible_operation_t_needs(*operation);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_sign_hash_interruptible_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_SIGN_HASH_ABORT,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_SIGN_HASH_ABORT server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_sign_hash_interruptible_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_sign_hash_complete(
    psa_sign_hash_interruptible_operation_t *operation,
    uint8_t *signature, size_t  signature_size,
    size_t *signature_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_sign_hash_interruptible_operation_t_needs(*operation) +
        psasim_serialise_buffer_needs(signature, signature_size) +
        psasim_serialise_size_t_needs(*signature_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_sign_hash_interruptible_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        signature, signature_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *signature_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_SIGN_HASH_COMPLETE,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_SIGN_HASH_COMPLETE server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_sign_hash_interruptible_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        signature, signature_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        signature_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


uint32_t psa_sign_hash_get_num_ops(
    const psa_sign_hash_interruptible_operation_t *operation
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    uint32_t value = 0;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_sign_hash_interruptible_operation_t_needs(*operation);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        value = 0;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_sign_hash_interruptible_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_SIGN_HASH_GET_NUM_OPS,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_SIGN_HASH_GET_NUM_OPS server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_uint32_t(
        &rpos, &rremain,
        &value);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return value;
}


psa_status_t psa_sign_hash_start(
    psa_sign_hash_interruptible_operation_t *operation,
    mbedtls_svc_key_id_t key,
    psa_algorithm_t alg,
    const uint8_t *hash, size_t  hash_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_sign_hash_interruptible_operation_t_needs(*operation) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_psa_algorithm_t_needs(alg) +
        psasim_serialise_buffer_needs(hash, hash_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_sign_hash_interruptible_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        hash, hash_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_SIGN_HASH_START,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_SIGN_HASH_START server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_sign_hash_interruptible_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_sign_message(
    mbedtls_svc_key_id_t key,
    psa_algorithm_t alg,
    const uint8_t *input, size_t  input_length,
    uint8_t *signature, size_t  signature_size,
    size_t *signature_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_psa_algorithm_t_needs(alg) +
        psasim_serialise_buffer_needs(input, input_length) +
        psasim_serialise_buffer_needs(signature, signature_size) +
        psasim_serialise_size_t_needs(*signature_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        input, input_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        signature, signature_size);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_size_t(
        &pos, &remaining,
        *signature_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_SIGN_MESSAGE,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_SIGN_MESSAGE server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_return_buffer(
        &rpos, &rremain,
        signature, signature_size);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_size_t(
        &rpos, &rremain,
        signature_length);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_verify_hash(
    mbedtls_svc_key_id_t key,
    psa_algorithm_t alg,
    const uint8_t *hash, size_t  hash_length,
    const uint8_t *signature, size_t  signature_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_psa_algorithm_t_needs(alg) +
        psasim_serialise_buffer_needs(hash, hash_length) +
        psasim_serialise_buffer_needs(signature, signature_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        hash, hash_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        signature, signature_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_VERIFY_HASH,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_VERIFY_HASH server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_verify_hash_abort(
    psa_verify_hash_interruptible_operation_t *operation
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_verify_hash_interruptible_operation_t_needs(*operation);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_verify_hash_interruptible_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_VERIFY_HASH_ABORT,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_VERIFY_HASH_ABORT server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_verify_hash_interruptible_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_verify_hash_complete(
    psa_verify_hash_interruptible_operation_t *operation
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_verify_hash_interruptible_operation_t_needs(*operation);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_verify_hash_interruptible_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_VERIFY_HASH_COMPLETE,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_VERIFY_HASH_COMPLETE server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_verify_hash_interruptible_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


uint32_t psa_verify_hash_get_num_ops(
    const psa_verify_hash_interruptible_operation_t *operation
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    uint32_t value = 0;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_verify_hash_interruptible_operation_t_needs(*operation);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        value = 0;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_verify_hash_interruptible_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_VERIFY_HASH_GET_NUM_OPS,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_VERIFY_HASH_GET_NUM_OPS server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_uint32_t(
        &rpos, &rremain,
        &value);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return value;
}


psa_status_t psa_verify_hash_start(
    psa_verify_hash_interruptible_operation_t *operation,
    mbedtls_svc_key_id_t key,
    psa_algorithm_t alg,
    const uint8_t *hash, size_t  hash_length,
    const uint8_t *signature, size_t  signature_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_psa_verify_hash_interruptible_operation_t_needs(*operation) +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_psa_algorithm_t_needs(alg) +
        psasim_serialise_buffer_needs(hash, hash_length) +
        psasim_serialise_buffer_needs(signature, signature_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_verify_hash_interruptible_operation_t(
        &pos, &remaining,
        *operation);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        hash, hash_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        signature, signature_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_VERIFY_HASH_START,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_VERIFY_HASH_START server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_verify_hash_interruptible_operation_t(
        &rpos, &rremain,
        operation);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}


psa_status_t psa_verify_message(
    mbedtls_svc_key_id_t key,
    psa_algorithm_t alg,
    const uint8_t *input, size_t  input_length,
    const uint8_t *signature, size_t  signature_length
    )
{
    uint8_t *ser_params = NULL;
    uint8_t *ser_result = NULL;
    size_t result_length;
    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

    size_t needed =
        psasim_serialise_begin_needs() +
        psasim_serialise_mbedtls_svc_key_id_t_needs(key) +
        psasim_serialise_psa_algorithm_t_needs(alg) +
        psasim_serialise_buffer_needs(input, input_length) +
        psasim_serialise_buffer_needs(signature, signature_length);

    ser_params = malloc(needed);
    if (ser_params == NULL) {
        status = PSA_ERROR_INSUFFICIENT_MEMORY;
        goto fail;
    }

    uint8_t *pos = ser_params;
    size_t remaining = needed;
    int ok;
    ok = psasim_serialise_begin(&pos, &remaining);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_mbedtls_svc_key_id_t(
        &pos, &remaining,
        key);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_psa_algorithm_t(
        &pos, &remaining,
        alg);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        input, input_length);
    if (!ok) {
        goto fail;
    }
    ok = psasim_serialise_buffer(
        &pos, &remaining,
        signature, signature_length);
    if (!ok) {
        goto fail;
    }

    ok = psa_crypto_call(PSA_VERIFY_MESSAGE,
                         ser_params, (size_t) (pos - ser_params), &ser_result, &result_length);
    if (!ok) {
        printf("PSA_VERIFY_MESSAGE server call failed\n");
        goto fail;
    }

    uint8_t *rpos = ser_result;
    size_t rremain = result_length;

    ok = psasim_deserialise_begin(&rpos, &rremain);
    if (!ok) {
        goto fail;
    }

    ok = psasim_deserialise_psa_status_t(
        &rpos, &rremain,
        &status);
    if (!ok) {
        goto fail;
    }

fail:
    free(ser_params);
    free(ser_result);

    return status;
}
