/*
 * app_json.c
 */

#include <string.h>

#include <secrsa_err.h> // E_SECMATH_SUCCESS, E_SECMATH_FAILURE
#include <secrsa_padding.h> // S_BIGINT_POS
#include <qsee_hash.h> // qsee_hash, QSEE_RSA_PAD_PKCS1_PSS, QSEE_SHA256_HASH_SZ, QSEE_HASH_IDX_SHA256
#include <qsee_rsa.h> // QSEE_RSA_KEY, QSEE_RSA_PSS_PAD_INFO, qsee_rsa_sign_hash

#include "app_main.h"
#include "app_cipher.h"
#include "app_core.h"
#include "app_drk.h"
#include "app_json.h"
#include "app_readData.h"
#include "app_getDeviceStatus.h"

#include "tz_iccc_comdef.h"

static ta_iccc_payload_DIR_t payload_DIR;

static DIR_flags_t DIR_flags[] =
{
    {IMAGE_STATUS2,    &payload_DIR.binaryStatus.r},
    {IMAGE_STATUS1,    &payload_DIR.binaryStatus.b},
    {IMAGE_STATUS_BL,  &payload_DIR.binaryStatus.l},
    {IMAGE_STATUS3,    &payload_DIR.binaryStatus.s},
    {IMAGE_STATUS8,    &payload_DIR.binaryStatus.v},
    {IMAGE_STATUS9,    &payload_DIR.binaryStatus.p},
    {IMAGE_STATUS4,    &payload_DIR.binaryStatus.c},
    {IMAGE_STATUS6,    &payload_DIR.binaryStatus.u},
    {IMAGE_STATUS5,    &payload_DIR.binaryStatus.h},
    {IMAGE_STATUS7,    &payload_DIR.binaryStatus.o},
    {IMAGE_STATUS10,   &payload_DIR.binaryStatus.dtb},
    {IMAGE_STATUS11,   &payload_DIR.binaryStatus.dtbo},
    {WARRANTY_BIT,     &payload_DIR.wb},
    {TRUSTBOOT_FLAG,   &payload_DIR.tb},
    {WB_HISTORY,       &payload_DIR.reason},
    {EM_STATUS,        &payload_DIR.es},
    {EM_TOKEN,         &payload_DIR.et},
    {HDM_STATUS,       &payload_DIR.hs}
};

/* exception codes requested by BL team */
void amend_garbage_value_for_old_bl()
{
    if (payload_DIR.reason == 0) {
        payload_DIR.reason = '0';
        ICCC_LOG("TZ_ICCC: reason is 0 changed to ascii 0");
    }
    if (payload_DIR.es == 0xFFFFFFFF) {
        payload_DIR.es = 0;
        ICCC_LOG("TZ_ICCC: es is 0xFFFFFFFF changed to 0");
    }
    if (payload_DIR.et == 0xFFFFFFFF) {
        payload_DIR.et = 0;
        ICCC_LOG("TZ_ICCC: et is 0xFFFFFFFF changed to 0");
    }
}

uint32_t check_image_status_all()
{
    uint32_t ret = 0;
    for (uint8_t i = 0; i < IMAGE_STATUS_MAX; i++) {
        if (*DIR_flags[i].flag_value != IMAGE_STATUS_MARKET_USER_OFFICIAL && 
            // *DIR_flags[i].flag_value != IMAGE_STATUS_FACTORY_UNKNOWN_OFFICIAL && // Not downloaded in STAR/CROWN sdm845
            *DIR_flags[i].flag_value != IMAGE_STATUS_NOT_DOWNLOADED) {
            ICCC_LOG("TZ_ICCC: Bad value. %#x = %d", DIR_flags[i].flag, *DIR_flags[i].flag_value);
            ret = IMAGE_STATUS_RESULT_ABNORMAL;
        }
    }
    return ret;
}

/***** BASE64 - BEGIN *****/
/* base64 URL table */
const uint8_t base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";

/* padding_table represents how many '=' do we need if the remainder of length divided by 3
 * is 0, 1 and 2. */
const uint32_t padding_table[] = {0, 2, 1};

/**
 * Encode bytes in base 64
 * param[out] enc_buffer the buffer encoded in base 64
 * param[out] enc_buffer_len the length of the buffer encoded in base 64
 * param[in] enc_buffer_size the maximum size of the buffer encoded in base 64
 * param[in] buffer the buffer to encode in base 64
 * param[in] buffer_len the length of the buffer to encode in base 64
 */
uint32_t encode_base64(uint8_t *enc_buffer, uint32_t *enc_buffer_len, uint32_t enc_buffer_size, uint8_t *buffer, uint32_t buffer_len)
{
    uint32_t encode_len = 4 * ((buffer_len + 2) / 3);
    uint32_t i, j;

    if ((encode_len + 1) > enc_buffer_size) {
        ICCC_LOG("TZ_ICCC: Not enough buffer for encoding: %d > %d", (encode_len + 1), enc_buffer_size);
        return ICCC_ENCODE_ERROR;
    }

    *enc_buffer_len = encode_len;

    for (i = 0, j = 0; i < buffer_len;) {
        uint32_t octet_a = i < buffer_len ? (unsigned char)buffer[i++] : 0;
        uint32_t octet_b = i < buffer_len ? (unsigned char)buffer[i++] : 0;
        uint32_t octet_c = i < buffer_len ? (unsigned char)buffer[i++] : 0;

        uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;

        enc_buffer[j++] = base64_table[(triple >> 3 * 6) & 0x3F];
        enc_buffer[j++] = base64_table[(triple >> 2 * 6) & 0x3F];
        enc_buffer[j++] = base64_table[(triple >> 1 * 6) & 0x3F];
        enc_buffer[j++] = base64_table[(triple >> 0 * 6) & 0x3F];
    }

    for (i = 0; i < padding_table[buffer_len % 3]; i++) {
        enc_buffer[*enc_buffer_len - 1 - i] = '=';
    }

    enc_buffer[encode_len] = '\0';

    return ICCC_SUCCESS;
}

/**
 * Encode bytes in base 64 using the same input buffer, by encoding it backwards.
 * param[in/out] buffer: [in] the buffer array to encode in base 64 [out] the buffer encoded in
 * base64, null terminated.
 * param[in/out] buffer_len: [in] the length of the buffer to encode in base 64 [out] the length of
 * the buffer encoded in base64 (already includes padding).
 * param[in] buffer_size: the size of the underlying buffer.
 */
uint32_t encode_base64_in_place(uint8_t *buffer, uint32_t *buffer_len, uint32_t buffer_size)
{
    uint32_t encode_len = 4 * ((*buffer_len + 2) / 3);
    int i, j;
    uint32_t full_blocks, padding_size;

    if ((encode_len + 1) > buffer_size) {
      ICCC_LOG("TZ_ICCC: Not enough buffer for encoding: %d > %d", (encode_len + 1), buffer_size);
      return ICCC_ENCODE_ERROR;
    }

    full_blocks = (*buffer_len / 3) + 1;

    for (i = (full_blocks * 3) - 1, j = (full_blocks * 4) - 1; i > 0;) {
        uint32_t octet_c = (unsigned char)buffer[i--];
        uint32_t octet_b = (unsigned char)buffer[i--];
        uint32_t octet_a = i >= 0 ? (unsigned char)buffer[i--] : 0;

        uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;

        buffer[j--] = base64_table[(triple >> 0 * 6) & 0x3F];
        buffer[j--] = base64_table[(triple >> 1 * 6) & 0x3F];
        buffer[j--] = base64_table[(triple >> 2 * 6) & 0x3F];
        buffer[j--] = base64_table[(triple >> 3 * 6) & 0x3F];
    }

    padding_size = padding_table[*buffer_len % 3];
    *buffer_len = encode_len;

    for (i = 0; i < (int) padding_size; i++) {
        buffer[*buffer_len - 1 - i] = '=';
    }

    buffer[*buffer_len] = '\0';

    return ICCC_SUCCESS;
}
/***** BASE64 - END *****/

/***** JSON - BEGIN *****/
uint32_t append_char_to_json(uint8_t *buffer, uint32_t buffer_size, uint32_t *buffer_len, uint8_t c)
{
    if (*buffer_len + 2 > buffer_size) {
        ICCC_LOG("TZ_ICCC: Failed to write \'%c\'; buffer_size: %d buffer_len: %d", c, buffer_size, *buffer_len);
        return ICCC_JWS_ERROR;
    }
    buffer[*buffer_len] = c;
    buffer[*buffer_len + 1] = '\0';
    *buffer_len += 1;
    return ICCC_SUCCESS;
}

uint32_t append_char_value_to_json(uint8_t *buffer, uint32_t buffer_size, uint32_t *buffer_len, const char *name, uint32_t value)
{
    uint32_t ret = ICCC_JWS_ERROR;
    uint32_t size = buffer_size - *buffer_len;
    const char format[] = "\"%s\":\"%c\"";
    char c;
    char *aux;
    c = (uint8_t)value;
    if (size > 0) {
        aux = (char *)&buffer[*buffer_len];
        ret = snprintf(aux, (size_t) size, format, name, c);
        if (ret > 0 && ret < size) {
            *buffer_len += ret;
            ret = ICCC_SUCCESS;
        } else {
            ICCC_LOG("TZ_ICCC: Failed to write %d bytes to buffer of size %d bytes", ret, size);
            ret = ICCC_JWS_ERROR;
        }
    } else {
        ICCC_LOG("TZ_ICCC: Impossible to write to buffer of size %d bytes", size);
        ret = ICCC_JWS_ERROR;
    }
    return ret;
}

uint32_t append_int_value_to_json(uint8_t *buffer, uint32_t buffer_size, uint32_t *buffer_len, const char *name, uint32_t value)
{
    uint32_t ret = ICCC_JWS_ERROR;
    uint32_t size = buffer_size - *buffer_len;
    const char format[] = "\"%s\":%d";
    char *aux;
    if (size > 0) {
        aux = (char *)&buffer[*buffer_len];
        ret = snprintf(aux, (size_t) size, format, name, value);
        if (ret > 0 && ret < size) {
            *buffer_len += ret;
            ret = ICCC_SUCCESS;
        } else {
            ICCC_LOG("TZ_ICCC: Failed to write %d bytes to buffer of size %d bytes", ret, size);
            ret = ICCC_JWS_ERROR;
        }
    } else {
        ICCC_LOG("TZ_ICCC: Impossible to write to buffer of size %d bytes", size);
        ret = ICCC_JWS_ERROR;
    }
    return ret;
}

uint32_t append_inthex_value_to_json(uint8_t *buffer, uint32_t buffer_size, uint32_t *buffer_len, const char *name, uint32_t value)
{
    uint32_t ret = ICCC_JWS_ERROR;
    uint32_t size = buffer_size - *buffer_len;
    const char format[] = "\"%s\":\"%X\"";
    char *aux;
    if (size > 0) {
        aux = (char *)&buffer[*buffer_len];
        ret = snprintf(aux, (size_t) size, format, name, value);
        if (ret > 0 && ret < size) {
            *buffer_len += ret;
            ret = ICCC_SUCCESS;
        } else {
            ICCC_LOG("TZ_ICCC: Failed to write %d bytes to buffer of size %d bytes", ret, size);
            ret = ICCC_JWS_ERROR;
        }
    } else {
        ICCC_LOG("TZ_ICCC: Impossible to write to buffer of size %d bytes", size);
        ret = ICCC_JWS_ERROR;
    }
    return ret;
}

/*
 * if "char *format" is NULL, default format is "\"%s\":\"%s\""
 */
uint32_t append_string_value_to_json(uint8_t *buffer, uint32_t buffer_size, uint32_t *buffer_len, const char *name, uint8_t *value, char *format)
{
    uint32_t ret = ICCC_JWS_ERROR;
    uint32_t size = buffer_size - *buffer_len;
    char *aux;
    if (format == NULL)
      format = "\"%s\":\"%s\"";
    if (size > 0) {
        aux = (char *)&buffer[*buffer_len];
        ret = snprintf(aux, (size_t)size, format, name, value);
        if (ret > 0 && ret < size) {
            *buffer_len += ret;
            ret = ICCC_SUCCESS;
        } else {
            ICCC_LOG("TZ_ICCC: Failed to write %d bytes to buffer of size %d bytes", ret, size);
            ret = ICCC_JWS_ERROR;
        }
    } else {
        ICCC_LOG("TZ_ICCC: Impossible to write to buffer of size %d bytes", size);
        ret = ICCC_JWS_ERROR;
    }
    return ret;
}

uint32_t append_array_value_to_json(uint8_t *buffer, uint32_t buffer_size, uint32_t *buffer_len, const char *name, uint8_t (*array)[MAX_CERT_LENGTH], uint8_t num)
{
    uint32_t ret = ICCC_JWS_ERROR;
    uint32_t size = buffer_size - *buffer_len;
    int i;
    char *aux;

    if (num <= 0) {
        ICCC_LOG("TZ_ICCC: No certificate found");
        goto error;
    }

    if (size <= 0) {
        ICCC_LOG("TZ_ICCC: Impossible to write to buffer of size %d bytes", size);
        ret = ICCC_JWS_ERROR;
        goto error;
    }

    aux = (char *)&buffer[*buffer_len];
    ret = snprintf(aux, size, "\"%s\":[", name);
    if (ret <= 0 || ret >= size) {
        ICCC_LOG("TZ_ICCC: Failure writing certificate to payload. Return: %d Size: %d", ret, size);
        ret = ICCC_JWS_ERROR;
        goto error;
    }
    *buffer_len += ret;

    for (i = 0; i < num; i++) {
        size = buffer_size - *buffer_len;
        if (size <= 0) {
            ICCC_LOG("TZ_ICCC: Impossible to write to buffer of size %d bytes", size);
            ret = ICCC_JWS_ERROR;
            goto error;
        }
        if (i > 0) {
            ret = append_char_to_json(buffer, buffer_size, buffer_len, ',');
            if (ret != ICCC_SUCCESS) {
                goto error;
            }
        }
        aux = (char *)&buffer[*buffer_len];
        ret = snprintf(aux, size, "\"%s\"", array[i]);
        if (ret <= 0 || ret >= size) {
            ICCC_LOG("TZ_ICCC: Failure II writing certificate to payload. Return: %d Size: %d", ret, size);
            ret = ICCC_JWS_ERROR;
            goto error;
        }
        *buffer_len += ret;
        buffer[*buffer_len] = '\0';
    }
    ret = append_char_to_json(buffer, buffer_size, buffer_len, ']');
    if (ret != ICCC_SUCCESS) {
        goto error;
    }
    ret = ICCC_SUCCESS;

error:
    return ret;
}
/***** JSON - END *****/

/***** HEADER - BEGIN *****/
uint32_t generate_header(uint8_t *buffer, uint32_t *buffer_len, uint32_t buffer_size)
{
    const char version[] = "version", algorithm[] = "alg";
    uint8_t version_value[] = "1.0", algorithm_value[] = "PS256";
    uint32_t ret = ICCC_JWS_ERROR;

    if (append_char_to_json(buffer, buffer_size, buffer_len, '{') != ICCC_SUCCESS) {
        goto error;
    }
    if (append_string_value_to_json(buffer, buffer_size, buffer_len, version, version_value, NULL) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }
    if (append_string_value_to_json(buffer, buffer_size, buffer_len, algorithm, algorithm_value, NULL) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, '}') != ICCC_SUCCESS) {
        goto error;
    }
    ret = ICCC_SUCCESS;

error:
    return ret;
}
/***** HEADER - END *****/

/***** PAYLOAD - BEGIN *****/
uint32_t read_device_id(uint8_t *device_id) {
    uint32_t value0, value1;
    int ret = ICCC_JWS_ERROR;

    if (Iccc_Core_ReadData_TA(AP_SERIAL_0, &value0) != ICCC_SUCCESS) {
        ICCC_LOG("TZ_ICCC: Error reading device id 0");
        goto error;
    }
    if (Iccc_Core_ReadData_TA(AP_SERIAL_1, &value1) != ICCC_SUCCESS) {
        ICCC_LOG("TZ_ICCC: Error reading device id 1");
        goto error;
    }
    if (snprintf((char *)device_id, DEVICE_ID_SIZE, "0x%08x%08x", value1, value0) <= 0) {
        ICCC_LOG("TZ_ICCC: Error writing device id");
        goto error;
    }
    //ICCC_LOG("TZ_ICCC: device_id = %s", device_id);
    ret = ICCC_SUCCESS;

error:
    return ret;
}

uint32_t prepare_cert_chain(ta_iccc_status_app_req_t *request, ta_iccc_status_app_payload_t *payload) {
    uint32_t ret = ICCC_JWS_ERROR;
    int i;
    uint32_t enc_buffer_len; /* Ignored, as each buffer cert_chain[i] is \0 terminated */

    for (i = 0; i < request->certs_num; i++) {
        //ICCC_LOG("TZ_ICCC: Cert[%d] length: %d", i, request->certs_len[i]);
        ret = encode_base64(payload->cert_chain[i], &enc_buffer_len, MAX_CERT_LENGTH, request->certs[i], request->certs_len[i]);
        if (ret != ICCC_SUCCESS) {
            goto error;
        }
    }
    payload->certs_num = request->certs_num;

error:
    return ret;
}

uint32_t prepare_DIR_values()
{
    int ret = ICCC_ERROR_DEVICE_STATUS_FAILED;
    int len = sizeof(DIR_flags) / sizeof(DIR_flags_t);
    for (uint8_t i = 0; i < len; i++) {
        ret = Iccc_Core_ReadData_TA(DIR_flags[i].flag, DIR_flags[i].flag_value);
        if (ret != ICCC_SUCCESS) {
            ICCC_LOG("TZ_ICCC: Error reading DIR Flag. i:%d flag:%#x", i, DIR_flags[i].flag);
            goto error;
        }
    }
    payload_DIR.abs = check_image_status_all();
    amend_garbage_value_for_old_bl();
    ret = ICCC_SUCCESS;
error:
    return ret;
}

uint32_t generate_DIR_message(uint8_t *buffer, uint32_t buffer_size, uint32_t *buffer_len)
{
    const char WB[] = "WB", TB[] = "TB", ABS[] = "ABS",  reason[] = "Reason", binaryStatus[] = "BinaryStatus",
               R[] = "R", B[] = "B", L[] = "L",  S[] = "S", V[] = "V", P[] = "P", C[] = "C", U[] = "U",  H[] = "H", O[] = "O",
               DT[] = "DT", DO[] = "DO", ES[] = "ES", ET[] = "ET", HS[] = "HDM";

    uint32_t ret = ICCC_ERROR_DEVICE_STATUS_FAILED;

    ICCC_LOG("TZ_ICCC: generate_DIR_message");

    if (append_char_to_json(buffer, buffer_size, buffer_len, '{') != ICCC_SUCCESS) {
        goto error;
    }

    /* WB */
    if (append_int_value_to_json(buffer, buffer_size, buffer_len, WB, payload_DIR.wb) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }
    /* TB */
    if (append_int_value_to_json(buffer, buffer_size, buffer_len, TB, payload_DIR.tb) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }
    /* ABS */
    if (append_int_value_to_json(buffer, buffer_size, buffer_len, ABS, payload_DIR.abs) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }
    /* Reason */
    if (append_char_value_to_json(buffer, buffer_size, buffer_len, reason, payload_DIR.reason) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }
    /* BinaryStatus */
    if (append_string_value_to_json(buffer, buffer_size, buffer_len, binaryStatus, (uint8_t *)"{", "\"%s\":%s") != ICCC_SUCCESS) {
        goto error;
    }
    /* R */
    if (append_int_value_to_json(buffer, buffer_size, buffer_len, R, payload_DIR.binaryStatus.r) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }
    /* B */
    if (append_int_value_to_json(buffer, buffer_size, buffer_len, B, payload_DIR.binaryStatus.b) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }
    /* L */
    if (append_int_value_to_json(buffer, buffer_size, buffer_len, L, payload_DIR.binaryStatus.l) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }
    /* S */
    if (append_int_value_to_json(buffer, buffer_size, buffer_len, S, payload_DIR.binaryStatus.s) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }
    /* V */
    if (append_int_value_to_json(buffer, buffer_size, buffer_len, V, payload_DIR.binaryStatus.v) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }
    /* P */
    if (append_int_value_to_json(buffer, buffer_size, buffer_len, P, payload_DIR.binaryStatus.p) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }
    /* C */
    if (append_int_value_to_json(buffer, buffer_size, buffer_len, C, payload_DIR.binaryStatus.c) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }
    /* U */
    if (append_int_value_to_json(buffer, buffer_size, buffer_len, U, payload_DIR.binaryStatus.u) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }
    /* H */
    if (append_int_value_to_json(buffer, buffer_size, buffer_len, H, payload_DIR.binaryStatus.h) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }
    /* O */
    if (append_int_value_to_json(buffer, buffer_size, buffer_len, O, payload_DIR.binaryStatus.o) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }
    /* DTB */
    if (append_int_value_to_json(buffer, buffer_size, buffer_len, DT, payload_DIR.binaryStatus.dtb) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }
    /* DTBO */
    if (append_int_value_to_json(buffer, buffer_size, buffer_len, DO, payload_DIR.binaryStatus.dtbo) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }
    /* ES */
    if (append_int_value_to_json(buffer, buffer_size, buffer_len, ES, payload_DIR.es) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }
    /* ET */
    if (append_inthex_value_to_json(buffer, buffer_size, buffer_len, ET, payload_DIR.et) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }
    /* HDM */
    if (append_inthex_value_to_json(buffer, buffer_size, buffer_len, HS, payload_DIR.hs) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, '}') != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, '}') != ICCC_SUCCESS) {
        goto error;
    }
    ret = ICCC_SUCCESS;

error:
    if (ret != ICCC_SUCCESS) {
        ICCC_LOG("TZ_ICCC: Failed to generate DIR string");
    }
    return ret;
}

uint32_t prepare_payload(ta_iccc_status_app_req_t *request, uint32_t result_code, uint8_t *ta_status_msg, ta_iccc_status_app_payload_t *payload)
{
    uint32_t ret = ICCC_ERROR_DEVICE_STATUS_FAILED;

    payload->result_code = result_code;
    payload->result_msg = ta_status_msg; /* It is null terminated, so we dont need its length */
    payload->comp_type = request->comp_type;
    payload->nonce = request->nonce;

    ret = read_device_id(payload->device_id);
    if (ret != ICCC_SUCCESS) {
        ICCC_LOG("TZ_ICCC: Error preparing payload: device id");
        goto error;
    }

    ret = prepare_cert_chain(request, payload);
    if (ret != ICCC_SUCCESS) {
        ICCC_LOG("TZ_ICCC: Error preparing payload: cert chain");
        goto error;
    }

    ret = ICCC_SUCCESS;

error:
    return ret;
}

uint32_t generate_payload(uint8_t *buffer, uint32_t buffer_size, uint32_t *buffer_len, ta_iccc_status_app_payload_t *payload)
{
    const char result[] = "result", result_msg[] = "resultMessage", comp_type[] = "componentType",
               nonce[] = "nonce", device_id[] = "deviceId", cert_chain[] = "certChain";

    uint32_t ret = ICCC_JWS_ERROR;

    if (append_char_to_json(buffer, buffer_size, buffer_len, '{') != ICCC_SUCCESS) {
        goto error;
    }

    /* RESULT CODE */
    if (append_int_value_to_json(buffer, buffer_size, buffer_len, result, payload->result_code) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }

    /* RESULT MESSAGE */
    if (append_string_value_to_json(buffer, buffer_size, buffer_len, result_msg, payload->result_msg, NULL) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }

    /* COMPONENT TYPE */
    if (append_int_value_to_json(buffer, buffer_size, buffer_len, comp_type, payload->comp_type) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }

    /* NONCE */
    if (append_string_value_to_json(buffer, buffer_size, buffer_len, nonce, payload->nonce, NULL) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }

    /* DEVICE_ID */
    if (append_string_value_to_json(buffer, buffer_size, buffer_len, device_id, payload->device_id, NULL) != ICCC_SUCCESS) {
        goto error;
    }
    if (append_char_to_json(buffer, buffer_size, buffer_len, ',') != ICCC_SUCCESS) {
        goto error;
    }

    /* CERTIFICATE CHAIN */
    if (append_array_value_to_json(buffer, buffer_size, buffer_len, cert_chain, payload->cert_chain, payload->certs_num) != ICCC_SUCCESS) {
        goto error;
    }

    if (append_char_to_json(buffer, buffer_size, buffer_len, '}') != ICCC_SUCCESS) {
        goto error;
    }
    ret = ICCC_SUCCESS;

error:
    if (ret != ICCC_SUCCESS) {
        ICCC_LOG("TZ_ICCC: Failed to generate payload");
    }
    return ret;
}
/***** PAYLOAD - END *****/

/***** SIGNATURE - BEGIN *****/
uint32_t generate_signature(uint8_t *message, uint32_t *message_len, QSEE_RSA_KEY *rsa_key)
{
    uint32_t ret = ICCC_SIGNATURE_ERROR;
    uint8_t signature[ICCC_STATUS_APP_SIGN_SIZE];
    int signature_len = ICCC_STATUS_APP_SIGN_SIZE;

    /* Len - 1 to ignore the last '.' (period) that has already been appended */
    ret = TZ_sign_CKM_SHA256_RSA_PKCS_PSS(rsa_key, message, (*message_len) - 1, signature, &signature_len);
    if (ret != ICCC_SUCCESS) {
        ICCC_LOG("TZ_ICCC: Failed to sign: 0x%x\n", ret);
        ret = ICCC_ERROR_DEVICE_STATUS_FAILED;
        goto error;
    }

    //ICCC_LOG("TZ_ICCC: Sign len = %d", signature_len);
    memcpy(&message[*message_len], signature, signature_len);
    *message_len += signature_len;
    ret = ICCC_SUCCESS;

error:
    return ret;
}
/***** SIGNATURE - END *****/
