
/*
 * =====================================================================================
 *
 *       Filename:  process_cmd.c
 *
 *    Description:  TUI process_cmd
 *
 *        Version:  1.0
 *        Created:  4/2/2020 11:32 AM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *        Company:  Samsung Electronics
 *        Copyright (c) 2020 by Samsung Electronics, All rights reserved.
 *
 * =====================================================================================
 */

/** Includes */
#include "process_cmd.h"

uint32_t gl_pin_verify[PIN_MAX_SIZE];
uint32_t gl_pin_verify_len;

uint8_t *g_certificate;
uint32_t g_certificate_len;
bool g_certificate_verified;

extern uint8_t g_pin[PIN_MAX_SIZE];
extern uint32_t g_pin_length;
extern bool g_display_normal_pinbox;

/*
 *  This is what happens after use click "OK" or all PIN numbers are entered
 *  Return:
 */
uint32_t processPinpadState() {
	uint32_t ret = 0;
	switch (getPinpadState()) {
	case MPOS_TUI_ST_VERIFY_ENTER:
		// verify PIN logic removed
		setPinpadState(MPOS_TUI_ST_VERIFY_MATCH);
		break;

	default:
		TUI_LOG_DEBUG("%s Error: current state is %u", __func__, getPinpadState());
		// should not come here
		//ret = SPAY_TPP_ERROR_INVALID_STATE;
	}
	//removeAllPin();
	clearPinData();

	return ret;
}

/**
 * @brief
 * mpos_ICCC_check
 *
 * Verify device integrity with ICCC device status API
 * @return MPOS status code
 */
tui_return_code_t mpos_ICCC_check(void)
{
        TUI_LOG("mpos_ICCC_check()");
        uint32_t result_code = ICCC_STATUS_RETURN_NOT_SECURE;
        uint32_t ret = ICCC_ERROR_DEVICE_STATUS_FAILED;
        uint32_t comp_type = ICCC_STATUS_COMP_TYPE_SOFT_INTEGRITY;
        uint32_t ta_status_msg_len = 0;
        uint8_t ta_status_msg[ICCC_STATUS_MAX_RESULT_MESSAGE];

        ret = Iccc_DeviceStatus_TA(comp_type, ta_status_msg, sizeof(ta_status_msg), &ta_status_msg_len, &result_code);
        if (ret != ICCC_SUCCESS)
        {
                TUI_LOG("Unable to verify device status");
                TUI_LOG_DEBUG("Unable to verify device status - Iccc_DeviceStatus_TA failed");
                return -1;
        }

        if (result_code != ICCC_STATUS_RETURN_SECURE)
        {
                TUI_LOG("Device is not secure");
                TUI_LOG_DEBUG("Iccc_DeviceStatus_TA return is not ICCC_STATUS_RETURN_SECURE. Device is not secure ");
                return -1;
        }

        return TUI_STATUS_SUCCESS;
}

void clearCertificate() {
    if (g_certificate != NULL) {
        TZ_free(g_certificate);
        g_certificate = NULL;
    }
    g_certificate_len = 0;
    g_certificate_verified = false;
}

tui_return_code_t saveCertificate(uint8_t *buf, uint32_t buflen) {
    clearCertificate();

    TUI_LOG_DEBUG("%s buflen=%d", __func__, buflen);

    g_certificate = (uint8_t*)TZ_malloc(buflen);
    g_certificate_len = buflen;
    g_certificate_verified = false;

    if (g_certificate == NULL) {
        TUI_LOG_DEBUG("%s allocation failed", __func__);
        return TUI_SEND_CERTIFICATE_FAILED;
    }
    memcpy(g_certificate, buf, buflen);

    return TUI_STATUS_SUCCESS;
}

tui_return_code_t verifyCertificate(uint8_t *buf, uint32_t bufLen) {
    uint32_t ret = TUI_STATUS_SUCCESS;
    uint8_t digest[SHA256_DIGEST_LENGTH];
    uint32_t digestLen;

    digestLen = SHA256_DIGEST_LENGTH;
    ret = TZ_digest_SHA256(buf, bufLen, digest, &digestLen);

    if (memcmp(digest, g_certificate, digestLen) != 0) {
        TUI_LOG_DEBUG("%s: The certificate data has integrity error. ret=%d", __func__, ret);
        for (int i = 0; i < digestLen; i++) {
            TUI_LOG_DEBUG("%s : digestLen[%d]=%d", __func__, i, (int) digest[i]);
        }
        for (int i = 0; i < g_certificate_len; i++) {
            TUI_LOG_DEBUG("%s : certificate[%d]=%d", __func__, i, (int) g_certificate[i]);
        }
        return -1;
    }
    g_certificate_verified = true;

    TUI_LOG_DEBUG("%s: Verify certificate ok.", __func__);

    ret = TUI_STATUS_SUCCESS;
    return ret;
}


/**
 * @brief
 * process_cmd
 * Process command
 *
 * @param[in] commandId - command id
 * @param[in] tci_msg   - tci message
 *
 * @return TUI status code
 */

tui_return_code_t process_cmd(uint32_t commandID,
			      tciMessage_t *sendmsg, uint32_t sendmsg_len,
			      tciMessage_t *respmsg, uint32_t respmsg_len) {
	tui_return_code_t ret = TUI_STATUS_SUCCESS;
	uint32_t device_status;

	switch (commandID) {
	case CMD_MPOSTUI_CHECK_DEVICE_INTEGRITY:
		TUI_LOG("CMD_MPOSTUI_INIT");
		// Device integrity check
		device_status = mpos_ICCC_check();
		if (device_status != TUI_STATUS_SUCCESS) {
			TUI_LOG("mpos_ICCC_check FAIL");
			ret = TUI_DEVICE_STATUS_CHECK_FAILED;
		}
		break;

	case CMD_MPOSTUI_SEND_CERTIFICATE:
		TUI_LOG("CMD_MPOSTUI_SEND_CERTIFICATE");
		
		// SRR-23454
		// Shouldn't the first part of this case always be performed in the TA_InvokeCommandEntryPoint? 
		// Shoulnd't the TA_InvokeCommandEntryPoint copy the passed value to the TA memory space to prevent the data from being modified while in use?
		if (sendmsg->payload.cmd.data.certificate.buflen > MAX_RESULT_BUFFER_LEN) {
			TUI_LOG_DEBUG("Buflen does not correspond to the expected size");
			return TUI_SEND_CERTIFICATE_FAILED;
		}

		ret = saveCertificate(sendmsg->payload.cmd.data.certificate.buffer, sendmsg->payload.cmd.data.certificate.buflen);
		break;

	case CMD_MPOSTUI_START_TUI_SESSION:
		TUI_LOG("CMD_OPEN_TUI_SESSION");

		if(sendmsg->payload.cmd.data.screenBackground.size > RESOURCE_BUFFER_SIZE) {
			TUI_LOG_DEBUG("%s Specified size %d bigger than array size %d", __func__, sendmsg->payload.cmd.data.screenBackground.size, RESOURCE_BUFFER_SIZE);
        	return TUI_START_TUI_SESSION_FAILED;
		}

		/* FIXME : skip temporarily, will do at sprint2
		ret = verifyCertificate(sendmsg->payload.cmd.data.screenBackground.buf, sendmsg->payload.cmd.data.screenBackground.size);
		if (ret) {
			TUI_LOG_DEBUG("%s: verifyCertificate failed, ret=%d", __func__, ret);
			ret = saveBackgroundResource(signature_error_resource[0], signature_error_sizes[0]);
			//return ret;
		} else {
			ret = saveBackgroundResource(sendmsg->payload.cmd.data.screenBackground.buf, sendmsg->payload.cmd.data.screenBackground.size);
			if (ret) {
				return ret;
			}
		}
		*/
		g_certificate_verified = true;

		ret = saveBackgroundResource(sendmsg->payload.cmd.data.screenBackground.buf, sendmsg->payload.cmd.data.screenBackground.size);
		if (ret) {
			ret = TUI_START_TUI_SESSION_FAILED;
			return ret;
		}

		setPinpadState(MPOS_TUI_ST_VERIFY_START);
		ret = launchPinpad(true, TYPE_NORMAL_PINBOX, g_certificate_verified);
		if (ret) {
			ret = TUI_START_TUI_SESSION_FAILED;
			return ret;
		}
		break;

	case CMD_MPOSTUI_CLOSE_TUI_SESSION:
		TUI_LOG("CMD_CLOSE_TUI_SESSION");
		ret = closeTuiSession();
		break;

	case CMD_MPOSTUI_SEND_PINPAD_IMAGES:
		TUI_LOG("CMD_SEND_PINPAD_IMAGES");
		ret = setPinPadImages(&sendmsg->payload.cmd.data.screenResourceArray);
		break;

	case CMD_MPOSTUI_SEND_PINBOX_IMAGES:
		TUI_LOG("CMD_SEND_PINBOX_IMAGES");
		ret = setPinBoxImages(&sendmsg->payload.cmd.data.setPinBox);
		break;

	default:
		TUI_LOG("wrong command ID %d",commandID);
		break;
	}

	return ret;
}
