#include "em_common.h"

static int em_token_get_meta(const uint8_t *src, em_default_meta * meta, uint32_t *offset, const uint32_t len_max);
static int em_token_get_element(const uint8_t *src, em_default_element *element, uint32_t *offset,
				const uint32_t len_max);
static int em_token_verify_token_signature(const uint8_t *data, const uint32_t len_data, const uint8_t *cert,
					   const uint32_t len_cert, const uint8_t *signature,
					   const uint32_t len_signature, uint64_t *flags);
static int em_token_check_expiration(const char *date_token_org, const char *date_server_org);
static int em_token_parse_token_info(em_token_info *tokeninfo, em_token_ptr *token_ptr);
static int em_token_parse_device_info(em_device_info *device_info, uint16_t num_of_devices, em_token_ptr *token_ptr);
static int em_token_parse_issuer_info(em_issuer_info *issuerinfo, em_token_ptr *token_ptr);
static int em_token_parse_mode_info(em_mode_info *modeinfo, em_token_ptr *token_ptr);
static int em_token_parse_validity_info(em_validity_info *valiinfo, em_token_ptr *token_ptr);
static int em_token_parse_integrity_info(em_integrity_info *integinfo, em_token_ptr *token_ptr);
static int em_token_parse_mode_db(em_mode_db *modedb, em_token_ptr *token_ptr);
static int em_token_parse(const uint8_t *token, em_token_ptr *token_ptr, em_parsed_token *parsed_token);
static int em_token_restore_tuc(uint8_t em_version, em_token_ptr *token_ptr, em_parsed_token *parsed_token,
				void *table_org);
static int em_token_make_tuc_v20(tuc_table_v20 *table, em_token_ptr *token_ptr, em_parsed_token *parsed_token);

static int em_token_get_meta(const uint8_t *src, em_default_meta *meta, uint32_t *offset, const uint32_t len_max)
{
	int ret;

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_GET_META, src, meta, offset);

	if (*offset + (uint32_t)sizeof(em_default_meta) > len_max) {
		LOGE("offset isn't normal(%u/%u)\n", (uint32_t)(*offset + sizeof(em_default_meta)), len_max);
		ret = EM_ERR_EM_TOKEN_GET_META_OFFSET;
		goto out;
	}

	memcpy(meta, src + *offset, sizeof(em_default_meta));
	*offset += (uint32_t)sizeof(em_default_meta);

	ret = EM_SUCCESS;
out:
	return ret;
}

static int em_token_get_element(const uint8_t *src, em_default_element *element, uint32_t *offset,
				const uint32_t len_max)
{
	int ret;

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_GET_ELEMENT, src, element, offset);

	if (*offset + (uint32_t)sizeof(em_default_element) > len_max) {
		LOGE("offset isn't normal(%u/%u)\n", (uint32_t)(*offset + sizeof(em_default_element)), len_max);
		ret = EM_ERR_EM_TOKEN_GET_ELEMENT_OFFSET;
		goto out;
	}

	memcpy(element, src + *offset, sizeof(em_default_element));
	*offset += (uint32_t)sizeof(em_default_element);

	ret = EM_SUCCESS;
out:
	return ret;

}

static int em_token_verify_token_signature(const uint8_t *data, const uint32_t len_data, const uint8_t *cert,
					   const uint32_t len_cert, const uint8_t *signature,
					   const uint32_t len_signature, uint64_t *flags)
{
	int ret;

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_VERIFY, data, cert, signature, flags);

	ret = em_crypto_verify_rsa_signature(cert, len_cert, signature, len_signature, data, len_data);
	if (ret != EM_SUCCESS && (uint32_t)ret != EM_DEV_OK) {
		LOGE("Failed to verify signature(0x%08x)\n", ret);
		goto out;
	}

	if ((uint32_t)ret == EM_DEV_OK)
		flags[1] |= EM_FLAGS_0_DEV_CERT;

	ret = EM_SUCCESS;
out:
	return ret;
}

static int em_token_check_expiration(const char *date_token_org, const char *date_server_org)
{
	int ret;

	char date_token[EM_LEN_DATE + 1] = {0,};
	char date_server[EM_LEN_DATE + 1] = {0,};

	uint32_t date_int_token = 0, date_int_server = 0;

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_CHECK_EXPIRATION, date_token_org, date_server_org);

	memcpy(date_token, date_token_org, EM_LEN_DATE);
	memcpy(date_server, date_server_org, EM_LEN_DATE);

	date_int_token = em_atoi(date_token);
	date_int_server = em_atoi(date_server);

	if (date_int_token == 0 || date_int_server == 0) {
		LOGE("em_atoi isn't working(%s/%u, %s/%u)\n", date_token, date_int_token, date_server, date_int_server);
		ret = EM_ERR_EM_TOKEN_CHECK_EXPIRATION_ATOI;
		goto out;
	}

	if (date_int_token < date_int_server) {
		LOGE("token is expired(%s/%s, %u/%u)\n", date_token, date_server, date_int_token, date_int_server);
		ret = EM_ERR_EM_TOKEN_CHECK_EXPIRATION_EXPIRED;
		goto out;
	}

	ret = EM_SUCCESS;
out:
	return ret;
}

int em_token_verify_token(em_context *ctx, em_parsed_token *parsed_token, em_token_ptr *token_ptr)
{
	int ret;

	int len_token = 0, loop = 0, ignore_did_offset = 0;
	uint8_t did_token[EM_LEN_DID + 1] = {0,};
	uint8_t flag_token = 0;
	uint32_t len_compare_did = 0;
	uint8_t priority_date[EM_LEN_PRIORITY_TIME] = {};

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_VERIFY_TOKEN, ctx, parsed_token, token_ptr);
	(void)ignore_did_offset;

#ifdef EMLITE
	len_compare_did = EM_LEN_DID - 4;
	ignore_did_offset = 2;
#else
#ifdef EMAS
	len_compare_did = EM_LEN_DID;
#else
	len_compare_did = EM_LEN_DID - 2;
#endif
#endif

	ret = em_token_parse(ctx->token, token_ptr, parsed_token);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to parse token(0x%08x)\n", ret);
		if (ret == EM_ERR_EM_TOKEN_PARSE_HEDAER_MAGIC)
			ctx->flags[2] |= EM_FLAGS_2_TOKEN_MAGIC_IS_UNKNOWN;
		goto out;
	}

	len_token = (uint32_t)((token_ptr->integrity_info - token_ptr->token_info) + (uint32_t)sizeof(em_header_info) +
			       ((uint32_t)sizeof(uint32_t) * parsed_token->token.num_of_devices) +
			       ((uint32_t)sizeof(uint32_t) * 8));
	ret = em_token_verify_token_signature(ctx->token, len_token, parsed_token->integrity.cert,
					      parsed_token->integrity.len_cert, parsed_token->integrity.signature,
					      parsed_token->integrity.len_signature, ctx->flags);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to verify token(0x%08x)\n", ret);
		ctx->flags[1] |= EM_FLAGS_1_EXIST_RETURN_TOKEN_REMOVE;
		goto out;
	}

	for (loop = 0; loop < parsed_token->token.num_of_devices; loop++) {
		memcpy(did_token, parsed_token->device[loop].did, EM_LEN_DID);

		if (em_strncasecmp((const char *)(ctx->did + ignore_did_offset),
				   (const char *)(did_token + ignore_did_offset), len_compare_did) == 0) {
			flag_token = 1;
			break;
		}
	}

	if (flag_token == 0) {
		LOGE("Installed token isn't for this device(%s/%s)\n", ctx->did, did_token);
		ret = EM_ERR_EM_TOKEN_VERIFY_DID;
		goto out;
	}

	if (ctx->flags[0] & EM_FLAGS_0_EXIST_DATE) {
		ret = em_token_check_expiration((const char *)parsed_token->validity.expiry_date,
						(const char *)ctx->date);
		if (ret != EM_SUCCESS) {
			ctx->flags[1] |= EM_FLAGS_1_EXIST_RETURN_TOKEN_EXPIRED | EM_FLAGS_1_EXIST_RETURN_TOKEN_REMOVE;
			LOGE("Failed to check expiration(0x%08x)\n", ret);
			goto out;
		}
#ifdef EMLITE
		if (ctx->flags[0] & EM_FLAGS_0_EXIST_PRIORITY_TIME)
			memcpy(priority_date, ctx->priority, EM_LEN_PRIORITY_TIME);
#else
		ret = em_esi_get_item(ctx->esi, EM_TYPE_ESI_ITEM_PRIORITY_TIME, priority_date, EM_LEN_PRIORITY_TIME);
		if (ret != EM_SUCCESS) {
			if ((uint32_t)ret == EM_ERR_EM_ESI_GET_ITEM_ITEM_IS_NOT_EXISTS) {
				LOGI("Not exists priority_date in ESI\n");
			} else {
				LOGI("Failed to get priority_date(0x%08x)\n", ret);
				goto out;
			}
		}
#endif
		if (memcmp(priority_date + EM_LEN_DATE, parsed_token->token.id, EM_LEN_TOKEN_ID) == 0) {
			ret = em_token_check_expiration((const char *)priority_date, (const char *)ctx->date);
			if (ret != EM_SUCCESS) {
				ctx->flags[1] |=
				    EM_FLAGS_1_EXIST_RETURN_TOKEN_EXPIRED | EM_FLAGS_1_EXIST_RETURN_TOKEN_REMOVE;
				LOGE("Failed to check expiration[P](0x%08x)\n", ret);
				goto out;
			}
		}
	}

	if (parsed_token->token.lsec_tok == EM_TYPE_TOKE_LSEC_TOK_ENABLED) {
		LOGI("token type is lsec!");
		ctx->flags[2] |= EM_FLAGS_2_ENABLED_LSEC_TOKEN;
	}

	LOGI("Token is verified\n");
	ret = EM_SUCCESS;
out:
	return ret;
}

static int em_token_parse_token_info(em_token_info *tokeninfo, em_token_ptr *token_ptr)
{
	int ret;
	uint32_t i;
	uint32_t offset = 0, len_max = 0;

	em_default_meta meta = {0,};
	em_default_element elem = {0,};

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_PARSE_TOKEN_INFO, tokeninfo, token_ptr);

	len_max = EM_LEN_TOKEN - (uint32_t)sizeof(em_header_info);

	ret = em_token_get_meta(token_ptr->token_info, &meta, &offset, len_max);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to get meta(0x%08x)\n", ret);
		goto out;
	}

	if (memcmp(meta.magic, EM_MAGIC_TOKEN, strlen(EM_MAGIC_TOKEN))) {
		LOGE("TOKE(%02x/%02x/%02x/%02x)\n", meta.magic[0], meta.magic[1], meta.magic[2],
		     meta.magic[3]);
		ret = EM_ERR_EM_TOKEN_PARSE_TOKEN_INFO_MAGIC;
		goto out;
	}

	for (i = 0; i < meta.num_of_data; i++) {
		if (offset + (uint32_t)sizeof(em_default_element) > len_max) {
			LOGE("offset isn't normal(%u/%u)\n", (uint32_t)(offset + sizeof(em_default_element)), len_max);
			ret = EM_ERR_EM_TOKEN_PARSE_TOKEN_INFO_OFFSET;
			goto out;
		}

		ret = em_token_get_element(token_ptr->token_info, &elem, &offset, len_max);
		if (ret != EM_SUCCESS) {
			LOGE("Failed to get element(0x%08x)\n", ret);
			goto out;
		}

		if (offset + elem.len > len_max) {
			LOGE("offset isn't normal(0x%08x/%u/%u)\n", elem.type,
			     (uint32_t)(offset + sizeof(em_default_element)), len_max);
			ret = EM_ERR_EM_TOKEN_PARSE_TOKEN_INFO_OFFSET_2;
			goto out;
		}

		switch (elem.type) {
		case EM_TYPE_INFO_TOKE_ID:
			if (elem.len != EM_LEN_TOKEN_ID) {
				LOGE("Unexpected token id size(%u)\n", elem.len);
				ret = EM_ERR_EM_TOKEN_PARSE_TOKEN_INFO_LEN_TOKE_ID;
				goto out;
			}

			memcpy(tokeninfo->id, token_ptr->token_info + offset, elem.len);
			break;

		case EM_TYPE_INFO_TOKE_UNIQUE_INFO:
			if (elem.len != sizeof(uint16_t)) {
				LOGE("Unexpected device info size(%u)\n", elem.len);
				ret = EM_ERR_EM_TOKEN_PARSE_TOKEN_INFO_LEN_UNIQUE;
				goto out;
			}

			memcpy(&tokeninfo->device_unique_info, token_ptr->token_info + offset, elem.len);
			break;

		case EM_TYPE_INFO_TOKE_NUM_DEVICES:
			if (elem.len != sizeof(uint16_t)) {
				LOGE("Unexpected num of device size(%u)\n", elem.len);
				ret = EM_ERR_EM_TOKEN_PARSE_TOKEN_INFO_LEN_DEVICE;
				goto out;
			}

			memcpy(&tokeninfo->num_of_devices, token_ptr->token_info + offset, elem.len);
			if (tokeninfo->num_of_devices > EM_LEN_MAX_DEVICE) {
				LOGE("Invalid num of devices(%u)\n", tokeninfo->num_of_devices);
				ret = EM_ERR_EM_TOKEN_PARSE_TOKEN_INFO_MAX_DEVICE;
				goto out;
			}
			break;

		case EM_TYPE_INFO_TOKE_LSEC_TOK:
			if (elem.len != sizeof(uint8_t)) {
				LOGE("%s : Unexpected num of lsec token(%02x)\n", __func__, tokeninfo->lsec_tok);
				ret = EM_ERR_EM_TOKEN_PARSE_TOKEN_INFO_LEN_LSEC_TOK;
				goto out;
			}

			memcpy(&tokeninfo->lsec_tok, token_ptr->token_info + offset, elem.len);
			break;

		default:
			LOGE("unknown type(0x%04x)\n", elem.type);
		}
		offset += elem.len;
	}

	ret = EM_SUCCESS;
out:
	return ret;
}

static int em_token_parse_device_info(em_device_info *device_info, uint16_t num_of_devices, em_token_ptr *token_ptr)
{
	int ret;
	uint32_t offset = 0, len_max;
	uint32_t i = 0, j = 0;

	em_default_meta meta = {0,};
	em_default_element elem = {0,};

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_PARSE_DEVICE_INFO, device_info, token_ptr);

	len_max = (uint32_t)(EM_LEN_TOKEN - (token_ptr->em_device_info[0] - token_ptr->token_info) -
			     (uint32_t)sizeof(em_header_info));

	if (num_of_devices > EM_LEN_MAX_DEVICE) {
		LOGE("number of devices is bigger than max(%u)\n", num_of_devices);
		ret = EM_ERR_EM_TOKEN_PARSE_DEVICE_INFO_MAX_DEVICE;
		goto out;
	}

	for (i = 0; i < num_of_devices; i++) {
		offset = 0;
		ret = em_token_get_meta(token_ptr->em_device_info[i], &meta, &offset, len_max);
		if (ret != EM_SUCCESS) {
			LOGE("Failed to get meta(0x%08x)\n", ret);
			goto out;
		}

		if (memcmp(meta.magic, EM_MAGIC_TOKEN_DEVICE, strlen(EM_MAGIC_TOKEN_DEVICE))) {
			LOGE("device info magic error\n");
			ret = EM_ERR_EM_TOKEN_PARSE_DEVICE_INFO_MAGIC;
			goto out;
		}

		for (j = 0; j < meta.num_of_data; j++) {
			if (offset + (uint32_t)sizeof(em_default_element) > len_max) {
				LOGE("offset isn't normal(%u/%u)\n", (uint32_t)(offset + sizeof(em_default_element)),
				     len_max);
				ret = EM_ERR_EM_TOKEN_PARSE_DEVICE_INFO_OFFSET;
				goto out;
			}

			ret = em_token_get_element(token_ptr->em_device_info[i], &elem, &offset, len_max);
			if (ret != EM_SUCCESS) {
				LOGE("Failed to get element(0x%08x)\n", ret);
				goto out;
			}

			if (offset + elem.len > len_max) {
				LOGE("offset isn't normal(0x%08x/%u/%u)\n", elem.type,
				     (uint32_t)(offset + sizeof(em_default_element)), len_max);
				ret = EM_ERR_EM_TOKEN_PARSE_DEVICE_INFO_OFFSET_2;
				goto out;
			}

			switch (elem.type) {
			case EM_TYPE_INFO_DEVI_MODEL_NAME:
				if (elem.len > EM_LEN_MODEL_NAME) {
					LOGE("Unexpected model name size(%u)\n", elem.len);
					ret = EM_ERR_EM_TOKEN_PARSE_DEVICE_INFO_MODEL_NAME;
					goto out;
				}

				memcpy(device_info[i].model_name, token_ptr->em_device_info[i] + offset, elem.len);
				break;

			case EM_TYPE_INFO_DEVI_DID:
				if (elem.len > EM_LEN_DID) {
					LOGE("Unexpected did size(%u)\n", elem.len);
					ret = EM_ERR_EM_TOKEN_PARSE_DEVICE_INFO_DEVICE_ID;
					goto out;
				}

				memcpy(device_info[i].did, token_ptr->em_device_info[i] + offset, elem.len);
				break;

			case EM_TYPE_INFO_DEVI_IMEI:
				if (elem.len > EM_LEN_IMEI) {
					LOGE("Unexpected imei size(%u)\n", elem.len);
					ret = EM_ERR_EM_TOKEN_PARSE_DEVICE_INFO_IMEI;
					goto out;
				}

				memcpy(device_info[i].imei, token_ptr->em_device_info[i] + offset, elem.len);
				break;

			default:
				LOGE("Unknown type(0x%04x)\n", elem.type);
			}
			offset += elem.len;
		}
	}

	ret = EM_SUCCESS;
out:
	return ret;
}

static int em_token_parse_issuer_info(em_issuer_info *issuerinfo, em_token_ptr *token_ptr)
{
	int ret;
	uint32_t i;
	uint32_t offset = 0, len_max = 0;

	em_default_meta meta = {0,};
	em_default_element elem = {0,};

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_PARSE_ISSUER_INFO, issuerinfo, token_ptr);

	len_max = (uint32_t)(EM_LEN_TOKEN - (token_ptr->issuer_info - token_ptr->token_info) -
			     (uint32_t)sizeof(em_header_info));

	ret = em_token_get_meta(token_ptr->issuer_info, &meta, &offset, len_max);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to get meta(0x%08x)\n", ret);
		goto out;
	}

	if (memcmp(meta.magic, EM_MAGIC_TOKEN_ISSUER, strlen(EM_MAGIC_TOKEN_ISSUER))) {
		LOGE("issuer info magic error\n");
		ret = EM_ERR_EM_TOKEN_PARSE_ISSUER_INFO_MAGIC;
		goto out;
	}

	for (i = 0; i < meta.num_of_data; i++) {
		if (offset + (uint32_t)sizeof(em_default_element) > len_max) {
			LOGE("offset isn't normal(%u/%u)\n", (uint32_t)(offset + sizeof(em_default_element)), len_max);
			ret = EM_ERR_EM_TOKEN_PARSE_ISSUER_INFO_OFFSET;
			goto out;
		}

		ret = em_token_get_element(token_ptr->issuer_info, &elem, &offset, len_max);
		if (ret != EM_SUCCESS) {
			LOGE("Failed to get element(0x%08x)\n", ret);
			goto out;
		}

		if (offset + elem.len > len_max) {
			LOGE("offset isn't normal(0x%08x/%u/%u)\n", elem.type,
			     (uint32_t)(offset + sizeof(em_default_element)), len_max);
			ret = EM_ERR_EM_TOKEN_PARSE_ISSUER_INFO_OFFSET_2;
			goto out;
		}

		switch (elem.type) {
		case EM_TYPE_INFO_ISSU_SINGLE_ID:
			if (elem.len > EM_LEN_SINGLE_ID) {
				LOGE("Unexpected single id size(%u)\n", elem.len);
				ret = EM_ERR_EM_TOKEN_PARSE_ISSUER_INFO_SINGLE_ID;
				goto out;
			}

			memcpy(issuerinfo->single_id, token_ptr->issuer_info + offset, elem.len);
			break;

		case EM_TYPE_INFO_ISSU_OTP:
			if (elem.len != EM_LEN_OTP) {
				LOGE("Unexpected otp size(%u)\n", elem.len);
				ret = EM_ERR_EM_TOKEN_PARSE_ISSUER_INFO_OTP;
				goto out;
			}

			memcpy(issuerinfo->otp, token_ptr->issuer_info + offset, elem.len);
			break;

		case EM_TYPE_INFO_ISSU_NONCE:
			if (elem.len != EM_LEN_NONCE) {
				LOGE("Unexpected nonce size(%u)\n", elem.len);
				ret = EM_ERR_EM_TOKEN_PARSE_ISSUER_INFO_NONCE;
				goto out;
			}

			memcpy(issuerinfo->nonce, token_ptr->issuer_info + offset, elem.len);
			break;

		case EM_TYPE_INFO_ISSU_SYSTEM_ID:
			if (elem.len > EM_LEN_SYSTEM_ID) {
				LOGE("Unexpected system id size(%u)\n", elem.len);
				ret = EM_ERR_EM_TOKEN_PARSE_ISSUER_INFO_SYSTEM_ID;
				goto out;
			}

			memcpy(issuerinfo->system_id, token_ptr->issuer_info + offset, elem.len);
			break;

		case EM_TYPE_INFO_ISSU_IP:
			if (elem.len > EM_LEN_IP_ADDR) {
				LOGE("Unexpected ip addr size(%u)\n", elem.len);
				ret = EM_ERR_EM_TOKEN_PARSE_ISSUER_INFO_IP;
				goto out;
			}

			memcpy(issuerinfo->ip_addr, token_ptr->issuer_info + offset, elem.len);
			break;

		case EM_TYPE_INFO_ISSU_MAC:
			if (elem.len > EM_LEN_MAC_ADDR) {
				LOGE("Unexpected mac addr size(%u)\n", elem.len);
				ret = EM_ERR_EM_TOKEN_PARSE_ISSUER_INFO_MAC;
				goto out;
			}

			memcpy(issuerinfo->mac_addr, token_ptr->issuer_info + offset, elem.len);
			break;

		default:
			LOGE("Unknown type(0x%04x)\n", elem.type);
		}
		offset += elem.len;
	}

	ret = EM_SUCCESS;
out:
	return ret;
}

static int em_token_parse_mode_info(em_mode_info *modeinfo, em_token_ptr *token_ptr)
{
	int ret;
	uint32_t i;
	uint32_t offset = 0, len_max = 0;

	em_default_meta meta = {0,};
	em_default_element elem = {0,};

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_PARSE_MODE_INFO, modeinfo, token_ptr);

	len_max =
	    (uint32_t)(EM_LEN_TOKEN - (token_ptr->mode_db - token_ptr->token_info) - (uint32_t)sizeof(em_header_info));

	ret = em_token_get_meta(token_ptr->mode_info, &meta, &offset, len_max);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to get meta(0x%08x)\n", ret);
		goto out;
	}

	if (meta.num_of_data > EM_LEN_MAX_MODE) {
		LOGE("num of modes is bigger than max(%u)\n", meta.num_of_data);
		ret = EM_ERR_EM_TOKEN_PARSE_MODE_INFO_MAX_MODE;
		goto out;
	}
	modeinfo->num_of_modes = meta.num_of_data;

	for (i = 0; i < meta.num_of_data; i++) {
		if (offset + (uint32_t)sizeof(em_default_element) > len_max) {
			LOGE("offset isn't normal(%u/%u)\n", (uint32_t)(offset + sizeof(em_default_element)), len_max);
			ret = EM_ERR_EM_TOKEN_PARSE_MODE_INFO_OFFSET;
			goto out;
		}

		ret = em_token_get_element(token_ptr->mode_info, &elem, &offset, len_max);
		if (ret != EM_SUCCESS) {
			LOGE("Failed to get element(0x%08x)\n", ret);
			goto out;
		}
		modeinfo->mode[i] = elem.type;
	}

	ret = EM_SUCCESS;
out:
	return ret;
}

static int em_token_parse_validity_info(em_validity_info *valiinfo, em_token_ptr *token_ptr)
{
	int ret;
	uint32_t i;
	uint32_t offset = 0, len_max = 0;

	em_default_meta meta = {0,};
	em_default_element elem = {0,};

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_PARSE_VALIDITY_INFO, valiinfo, token_ptr);

	len_max = (uint32_t)(EM_LEN_TOKEN -
			     (token_ptr->validity_info - token_ptr->token_info - (uint32_t)sizeof(em_header_info)));

	ret = em_token_get_meta(token_ptr->validity_info, &meta, &offset, len_max);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to get meta(0x%08x)\n", ret);
		goto out;
	}

	if (memcmp(meta.magic, EM_MAGIC_TOKEN_VALIDATE, strlen(EM_MAGIC_TOKEN_VALIDATE))) {
		LOGE("validity info magic error\n");
		ret = EM_ERR_EM_TOKEN_PARSE_VALIDITY_INFO_MAGIC;
		goto out;
	}

	for (i = 0; i < meta.num_of_data; i++) {
		if (offset + (uint32_t)sizeof(em_default_element) > len_max) {
			LOGE("offset isn't normal(%u/%u)\n", (uint32_t)(offset + sizeof(em_default_element)), len_max);
			ret = EM_ERR_EM_TOKEN_PARSE_VALIDITY_INFO_OFFSET;
			goto out;
		}

		ret = em_token_get_element(token_ptr->validity_info, &elem, &offset, len_max);
		if (ret != EM_SUCCESS) {
			LOGE("Failed to get element(0x%08x)\n", ret);
			goto out;
		}

		if (offset + elem.len > len_max) {
			LOGE("offset isn't normal(%08x/%u/%u)\n", elem.type, offset + elem.len, len_max);
			ret = EM_ERR_EM_TOKEN_PARSE_VALIDITY_INFO_MAGIC;
			goto out;
		}

		switch (elem.type) {
		case EM_TYPE_INFO_VALI_ISSUED_DATE:
			if (elem.len != EM_LEN_DATE) {
				LOGE("Unexpected issued date size(%u)\n", elem.len);
				ret = EM_ERR_EM_TOKEN_PARSE_VALIDITY_INFO_DATE;
				goto out;
			}

			memcpy(valiinfo->issued_date, token_ptr->validity_info + offset, elem.len);
			break;

		case EM_TYPE_INFO_VALI_EXPIRY_DATE:
			if (elem.len != EM_LEN_DATE) {
				LOGE("Unexpected expiry size(%u)\n", elem.len);
				ret = EM_ERR_EM_TOKEN_PARSE_VALIDITY_INFO_DATE_2;
				goto out;
			}

			memcpy(valiinfo->expiry_date, token_ptr->validity_info + offset, elem.len);
			break;

		default:
			LOGE("Unknown type(0x%04x)\n", elem.type);
		}

		offset += elem.len;
	}

	ret = EM_SUCCESS;
out:
	return ret;
}

static int em_token_parse_integrity_info(em_integrity_info *integinfo, em_token_ptr *token_ptr)
{
	int ret;
	uint32_t i;
	uint32_t offset = 0, len_max = 0;

	em_default_meta meta = {0,};
	em_default_element elem = {0,};

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_PARSE_INTEGRITY_INFO, integinfo, token_ptr);

	len_max = (uint32_t)(EM_LEN_TOKEN - (token_ptr->integrity_info - token_ptr->token_info) -
			     (uint32_t)sizeof(em_header_info));

	ret = em_token_get_meta(token_ptr->integrity_info, &meta, &offset, len_max);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to get meta(0x%08x)\n", ret);
		goto out;
	}

	if (memcmp(meta.magic, EM_MAGIC_TOKEN_INTEGRITY, strlen(EM_MAGIC_TOKEN_INTEGRITY))) {
		LOGE("INTE(%02x/%02x/%02x/%02x)\n", meta.magic[0], meta.magic[1], meta.magic[2],
		     meta.magic[3]);
		ret = EM_ERR_EM_TOKEN_PARSE_INTEGRITY_INFO_MAGIC;
		goto out;
	}

	for (i = 0; i < meta.num_of_data; i++) {
		if (offset + (uint32_t)sizeof(em_default_element) > len_max) {
			LOGE("offset isn't normal(%u/%u)\n", (uint32_t)(offset + sizeof(em_default_element)), len_max);
			ret = EM_ERR_EM_TOKEN_PARSE_INTEGRITY_INFO_OFFSET;
			goto out;
		}

		ret = em_token_get_element(token_ptr->integrity_info, &elem, &offset, len_max);
		if (ret != EM_SUCCESS) {
			LOGE("Failed to get element(0x%08x)\n", ret);
			goto out;
		}

		if (offset + elem.len > len_max) {
			LOGE("offset isn't normal(%08x/%u/%u)\n", elem.type, offset + elem.len, len_max);
			ret = EM_ERR_EM_TOKEN_PARSE_INTEGRITY_INFO_OFFSET2;
			goto out;
		}

		switch (elem.type) {
		case EM_TYPE_INFO_INTE_SIGNATURE:
			if (elem.len > EM_LEN_SIGNATURE) {
				LOGE("Unexpected sig size(%u)\n", elem.len);
				ret = EM_ERR_EM_TOKEN_PARSE_INTEGRITY_INFO_SIGN;
				goto out;
			}

			memcpy(integinfo->signature, token_ptr->integrity_info + offset, elem.len);
			integinfo->len_signature = elem.len;
			break;

		case EM_TYPE_INFO_INTE_SERVER_CERT:
			if (elem.len > EM_LEN_CERTIFICATE) {
				LOGE("Unexpected server cert size(%u)\n", elem.len);
				ret = EM_ERR_EM_TOKEN_PARSE_INTEGRITY_INFO_CERT;
				goto out;
			}

			memcpy(integinfo->cert, token_ptr->integrity_info + offset, elem.len);
			integinfo->len_cert = elem.len;
			break;

		default:
			LOGE("Unknown type(0x%04x)\n", elem.type);
		}

		offset += elem.len;
	}

	ret = EM_SUCCESS;
out:
	return ret;
}

static int em_token_parse_mode_db(em_mode_db *modedb, em_token_ptr *token_ptr)
{
	int ret;
	uint32_t i, j;
	uint32_t offset = 0, len_max = 0;

	em_default_meta meta = {0,};
	em_default_element elem = {0,};

	uint16_t mode_index = 0;
	em_modb_attr *mode_attrbutes = NULL;

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_PARSE_MODE_DB_INFO, modedb, token_ptr);

	len_max =
	    (uint32_t)(EM_LEN_TOKEN - (token_ptr->mode_db - token_ptr->token_info) - (uint32_t)sizeof(em_header_info));

	ret = em_token_get_meta(token_ptr->mode_db, &meta, &offset, len_max);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to get meta(0x%08x)\n", ret);
		goto out;
	}

	if (memcmp((char *)meta.magic, EM_MAGIC_TOKEN_MODB, strlen(EM_MAGIC_TOKEN_MODB))) {
		LOGE("mode db magic error(%02x/%02x/%02x/%02x)\n", meta.magic[0], meta.magic[1], meta.magic[2],
		     meta.magic[3]);
		ret = EM_ERR_EM_TOKEN_PARSE_MODE_DB_INFO_MAGIC;
		goto out;
	}

	if (meta.num_of_data > EM_LEN_MAX_MODE) {
		LOGE("Unexpected num of mode(%u)\n", meta.num_of_data);
		ret = EM_ERR_EM_TOKEN_PARSE_MODE_DB_INFO_NUM;
		goto out;
	}

	for (i = 0; i < meta.num_of_data; i++) {
		mode_index = 0;
		mode_attrbutes = NULL;

		if (offset + (uint32_t)sizeof(em_modb_data) > len_max) {
			LOGE("offset isn't normal(%u/%u)\n", (uint32_t)(offset + sizeof(em_modb_data)), len_max);
			ret = EM_ERR_EM_TOKEN_PARSE_MODE_DB_INFO_OFFSET_2;
			goto out;
		}

		memcpy(&mode_index, (token_ptr->mode_db) + offset, sizeof(uint16_t));

		memcpy(&modedb->data[mode_index], (token_ptr->mode_db) + offset,
		       sizeof(em_modb_data) - sizeof(em_modb_attr));
		offset += ((uint32_t)sizeof(em_modb_data) - (uint32_t)sizeof(em_modb_attr));

#ifdef EMAS
		LOGW("%s(0x%04x)\n", modedb->data[mode_index].name, modedb->data[mode_index].index);
#endif

#ifdef DEBUG_LOG
		LOGD("desc  : %s\n", modedb->data[mode_index].desc);
		LOGD("group_index : 0x%04x\n", modedb->data[mode_index].group_index);
		LOGD("attr_size  : %u\n", modedb->data[mode_index].len_attr);
		LOGD("num_of_attr  : %u\n", modedb->data[mode_index].num_of_attr);
#endif

		mode_attrbutes = &modedb->data[mode_index].attributes;

		for (j = 0; j < modedb->data[mode_index].num_of_attr; j++) {
			if (modedb->data[mode_index].len_attr > EM_LEN_MODB_ATTRIBUTE) {
				LOGE("Unexpected mode attr size(%u)\n", modedb->data[mode_index].len_attr);
				ret = EM_ERR_EM_TOKEN_PARSE_MODE_DB_INFO_ATTR;
				goto out;
			}

			ret = em_token_get_element(token_ptr->mode_db, &elem, &offset, len_max);
			if (ret != EM_SUCCESS) {
				LOGE("Failed to get element(0x%08x)\n", ret);
				goto out;
			}

#ifdef DEBUG_LOG
			LOGD("Get mode attribute - type(0x%04x)\n", elem.type);
#endif
			if (offset + elem.len > len_max) {
				LOGE("offset isn't normal(%08x/%u/%u)\n", elem.type, offset + elem.len, len_max);
				ret = EM_ERR_EM_TOKEN_PARSE_MODE_DB_INFO_OFFSET;
				goto out;
			}

			switch (elem.type) {
			case EM_TYPE_INFO_MODB_DEVICE_INFO:
				if (elem.len > sizeof(mode_attrbutes->dui)) {
					LOGE("Unexpected dui size(%u)\n", elem.len);
					ret = EM_ERR_EM_TOKEN_PARSE_MODE_DB_INFO_DUI;
					goto out;
				}

				memcpy(&mode_attrbutes->dui, token_ptr->mode_db + offset, elem.len);
#ifdef DEBUG_LOG
				LOGD("mode_attrbutes->dui : 0x%x\n", mode_attrbutes->dui);
#endif
				break;

			case EM_TYPE_INFO_MODB_HIDDEN:
				if (elem.len > sizeof(mode_attrbutes->hidden)) {
					LOGE("Unexpected hidden size(%u)\n", elem.len);
					ret = EM_ERR_EM_TOKEN_PARSE_MODE_DB_INFO_HIDDEN;
					goto out;
				}

				memcpy(&mode_attrbutes->hidden, token_ptr->mode_db + offset, elem.len);
#ifdef DEBUG_LOG
				LOGD("mode_attrbutes->hidden : 0x%x\n", mode_attrbutes->hidden);
#endif
				break;

			case EM_TYPE_INFO_MODB_MTUC:
				if (elem.len > sizeof(mode_attrbutes->is_mtuc_enabled)) {
					LOGE("Unexpected mtuc size(%u)\n", elem.len);
					ret = EM_ERR_EM_TOKEN_PARSE_MODE_DB_INFO_MTUC;
					goto out;
				}

				memcpy(&mode_attrbutes->is_mtuc_enabled, token_ptr->mode_db + offset, elem.len);
#ifdef DEBUG_LOG
				LOGD("mode_attrbutes->is_mtuc_enabled : 0x%x\n", mode_attrbutes->is_mtuc_enabled);
#endif
				break;

			case EM_TYPE_INFO_MODB_MTUC_VALUE:
				if (elem.len > sizeof(mode_attrbutes->mtuc_value)) {
					LOGE("Unexpected mtuc_value size(%u)\n", elem.len);
					ret = EM_ERR_EM_TOKEN_PARSE_MODE_DB_INFO_MTUC_V;
					goto out;
				}

				memcpy(&mode_attrbutes->mtuc_value, token_ptr->mode_db + offset, elem.len);
#ifdef DEBUG_LOG
				LOGD("mode_attrbutes->mtuc_value : %u\n", mode_attrbutes->mtuc_value);
#endif
				break;

			case EM_TYPE_INFO_MODB_EXCLUSIVE:
				if (elem.len > sizeof(mode_attrbutes->exclusive)) {
					LOGE("Unexpected exclusive size(%u)\n", elem.len);
					ret = EM_ERR_EM_TOKEN_PARSE_MODE_DB_INFO_EXCLUSIVE;
					goto out;
				}

				memcpy(&mode_attrbutes->exclusive, token_ptr->mode_db + offset, elem.len);
#ifdef DEBUG_LOG
				LOGD("mode_attrbutes->exclusive : 0x%x\n", mode_attrbutes->exclusive);
#endif
				break;

			case EM_TYPE_INFO_MODB_USED_ONCE:
				if (elem.len > sizeof(mode_attrbutes->used_once)) {
					LOGE("Unexpected used_once size(%u)\n", elem.len);
					ret = EM_ERR_EM_TOKEN_PARSE_MODE_DB_INFO_ONCE;
					goto out;
				}

				memcpy(&mode_attrbutes->used_once, token_ptr->mode_db + offset, elem.len);
#ifdef DEBUG_LOG
				LOGD("mode_attrbutes->used_once : 0x%x\n", mode_attrbutes->used_once);
#endif
				break;

			case EM_TYPE_INFO_MODB_EXTENSION:
				if (elem.len > EM_LEN_MODB_EXTENSEION) {
					LOGE("Unexpected ext size(%u)\n", elem.len);
					ret = EM_ERR_EM_TOKEN_PARSE_MODE_DB_INFO_EXTENSION;
					goto out;
				}

				memcpy(&mode_attrbutes->ext, token_ptr->mode_db + offset, elem.len);
#ifdef DEBUG_LOG
				LOGD("mode_attrbutes->ext : %s\n", mode_attrbutes->ext);
#endif
				mode_attrbutes->len_ext = elem.len;
				break;

			default:
				LOGE("Unknown type(0x%04x)\n", elem.type);
			}

			offset += elem.len;
		}
	}
	ret = EM_SUCCESS;

out:
	return ret;
}

static int em_token_parse(const uint8_t *token, em_token_ptr *token_ptr, em_parsed_token *parsed_token)
{
	int ret;

	uint32_t i = 0, offset = 0, temp_offset = 0, address = 0;

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_PARSE, token, token_ptr, parsed_token);

	/* Header */
	memcpy(&token_ptr->header, token, sizeof(em_header_info));
	if (memcmp(token_ptr->header.prefix, EM_MAGIC_HEADER_PREFIX, EM_LEN_HEADER_FIELD)) {
		LOGE("Token Prefix isn't matched(%02x/%02x/%02x)\n", token_ptr->header.prefix[0],
		     token_ptr->header.prefix[1], token_ptr->header.prefix[2]);
		ret = EM_ERR_EM_TOKEN_PARSE_HEDAER_MAGIC;
		goto out;
	}

	if (memcmp(token_ptr->header.type, "RMA", EM_LEN_HEADER_FIELD) != 0 &&
	    memcmp(token_ptr->header.type, "RSD", EM_LEN_HEADER_FIELD) != 0 &&
	    memcmp(token_ptr->header.type, "RWS", EM_LEN_HEADER_FIELD) != 0 &&
	    memcmp(token_ptr->header.type, "RSS", EM_LEN_HEADER_FIELD) != 0 &&
	    memcmp(token_ptr->header.type, "RJS", EM_LEN_HEADER_FIELD) != 0) {
		LOGE("This token type isn't support(%02x/%02x/%02x)\n", token_ptr->header.type[0],
		     token_ptr->header.type[1], token_ptr->header.type[2]);
		ret = EM_ERR_EM_TOKEN_PARSE_TOKEN_HEADER;
		goto out;
	}

	if (memcmp(token_ptr->header.version, EM_MAGIC_PACKET_VERSION2, EM_LEN_HEADER_VERSION) != 0) {
		LOGE("Token version isn't matched(%02x/%02x/%02x/%02x)\n", token_ptr->header.version[0],
		     token_ptr->header.version[1], token_ptr->header.version[2], token_ptr->header.version[3]);
		ret = EM_ERR_EM_TOKEN_PARSE_TOKEN_VERSION;
		goto out;
	}

	offset += (uint32_t)sizeof(em_header_info) + (uint32_t)sizeof(uint32_t);

	temp_offset = offset;
	for (i = 0; i < EM_LEN_NUM_OF_INFO_IN_TOKEN; i++) {
		memcpy(&address, token + temp_offset, sizeof(uint32_t));
		if (address > EM_LEN_TOKEN) {
			LOGE("[%u] offset isn't normal(%u)\n", i, address);
			ret = EM_ERR_EM_TOKEN_PARSE_TOKEN_OFFSET_INFO;
			goto out;
		}
		temp_offset += (uint32_t)sizeof(uint32_t);
	}

	memcpy(&address, token + offset, sizeof(uint32_t));
	token_ptr->token_info = (uint8_t *)token + address;
	offset += (uint32_t)sizeof(uint32_t);

	/* TOKEN INFO */
	ret = em_token_parse_token_info(&parsed_token->token, token_ptr);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to parse token info(0x%08x)\n", ret);
		goto out;
	}

	/* DEVICE INFO */
	for (i = 0; i < parsed_token->token.num_of_devices; i++) {
		memcpy(&address, token + offset, sizeof(uint32_t));
		token_ptr->em_device_info[i] = (uint8_t *)(token + address);
		offset += (uint32_t)sizeof(uint32_t);
	}

	ret = em_token_parse_device_info(parsed_token->device, parsed_token->token.num_of_devices, token_ptr);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to parse device info(0x%08x)\n", ret);
		goto out;
	}

	/* ISSUER INFO */
	memcpy(&address, token + offset, sizeof(uint32_t));
	token_ptr->issuer_info = (uint8_t *)(token + address);
	offset += (uint32_t)sizeof(uint32_t);
	ret = em_token_parse_issuer_info(&parsed_token->issuer, token_ptr);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to parse issuer info(0x%08x)\n", ret);
		goto out;
	}

	/* MODE INFO */
	memcpy(&address, token + offset, sizeof(uint32_t));
	token_ptr->mode_info = (uint8_t *)(token + address);
	offset += (uint32_t)sizeof(uint32_t);
	ret = em_token_parse_mode_info(&parsed_token->mode, token_ptr);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to parse mode info(0x%08x)\n", ret);
		goto out;
	}

	/* VALI INFO */
	memcpy(&address, token + offset, sizeof(uint32_t));
	token_ptr->validity_info = (uint8_t *)(token + address);
	offset += (uint32_t)sizeof(uint32_t);
	ret = em_token_parse_validity_info(&parsed_token->validity, token_ptr);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to parse validity info(0x%08x)\n", ret);
		goto out;
	}

	/* INTE INFO */
	memcpy(&address, token + offset, sizeof(uint32_t));
	token_ptr->integrity_info = (uint8_t *)(token + address);
	offset += (uint32_t)sizeof(uint32_t);
	ret = em_token_parse_integrity_info(&parsed_token->integrity, token_ptr);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to parse integrity info(0x%08x)\n", ret);
		goto out;
	}

	/* MODEDB INFO */
	memcpy(&address, token + offset, sizeof(uint32_t));
	token_ptr->mode_db = (uint8_t *)(token + address);
	offset += (uint32_t)sizeof(uint32_t);
	ret = em_token_parse_mode_db(&parsed_token->modedb, token_ptr);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to parse mode db(0x%08x)\n", ret);
		goto out;
	}

	/* GROUPDB INFO */
	memcpy(&address, token + offset, sizeof(uint32_t));
	token_ptr->group_db = (uint8_t *)(token + address);
	offset += (uint32_t)sizeof(uint32_t);
	if (memcmp(token_ptr->group_db, "GRDB", 4) != 0) {
		LOGE("group_db_info parse error\n");
		ret = EM_ERR_EM_TOKEN_PARSE_TOKEN_GROUP_DB;
		goto out;
	}

	ret = EM_SUCCESS;
out:
	return ret;
}

static int em_token_make_tuc_v20(tuc_table_v20 *table, em_token_ptr *token_ptr,
				 em_parsed_token *parsed_token)
{
	int ret, i = 0, j = 0;

	uint8_t *modb = NULL;
	uint8_t tucFlag = 0;

	tuc_v20 *temp_tuc = NULL;
	uint32_t size_of_attr = 0, num_of_attr = 0;
	uint16_t attr_type = 0, attr_len = 0;

	uint32_t offset = 0, len_max = 0;

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_MAKE_TUC_V20, table, token_ptr, parsed_token);

	len_max =
	    (uint32_t)(EM_LEN_TOKEN - (token_ptr->mode_db - token_ptr->token_info) - (uint32_t)sizeof(em_header_info));

	table->num_of_tuc = parsed_token->mode.num_of_modes;
	if (parsed_token->mode.num_of_modes > EM_LEN_MAX_MODE_V20) {
		LOGE("num_of_modes isn't normal(%u/%u)\n", parsed_token->mode.num_of_modes, EM_LEN_MAX_MODE_V20);
		ret = EM_ERR_EM_TOKEN_MAKE_TUC_V20_MAX_MODE;
		goto out;
	}

	modb = token_ptr->mode_db;
	offset += 4 + 4 + 4;
	for (i = 0; i < parsed_token->mode.num_of_modes; i++) {
		temp_tuc = &table->tucs[i];

		if (offset + (uint32_t)sizeof(em_modb_data) > len_max) {
			LOGE("offset isn't normal(%u/%u)\n", (uint32_t)(offset + sizeof(em_modb_data)), len_max);
			ret = EM_ERR_EM_TOKEN_MAKE_TUC_V20_OFFSET;
			goto out;
		}

		memcpy(&temp_tuc->mode_index, modb + offset, sizeof(uint16_t));
		offset += 2;   /* index */
		offset += 32;  /* mode data name */
		offset += 128; /* mode data desc */
		offset += 2;   /* mode data group index */

		memcpy(&size_of_attr, modb + offset, sizeof(uint32_t));
		offset += (uint32_t)sizeof(uint32_t);
		memcpy(&num_of_attr, modb + offset, sizeof(uint32_t));
		offset += (uint32_t)sizeof(uint32_t);

		for (j = 0; (uint32_t)j < num_of_attr; j++) {
			memcpy(&attr_type, modb + offset, sizeof(uint16_t));
			offset += (uint32_t)sizeof(uint16_t);
			memcpy(&attr_len, modb + offset, sizeof(uint16_t));
			offset += (uint32_t)sizeof(uint16_t);

			if (attr_type == EM_TYPE_TUC_VALUE) {
				memcpy(&temp_tuc->count, modb + offset, sizeof(uint32_t));
				offset += (uint32_t)sizeof(uint32_t);
			} else if (attr_type == EM_TYPE_TUC_USAGE_COUNT_TYPE) {
				memcpy(&tucFlag, modb + offset, sizeof(uint8_t));
				if (tucFlag == EM_TYPE_TUC_IS_ENABLE)
					temp_tuc->flags |= EM_TYPE_TUC_IS_ENABLE;
				else if (tucFlag == EM_TYPE_TUC_ONLY_ONCE)
					temp_tuc->flags |= EM_TYPE_TUC_ONLY_ONCE;

				offset += (uint32_t)sizeof(uint8_t);
			} else {
				offset += attr_len;
			}
		}
	}

	ret = EM_SUCCESS;
out:
	return ret;
}

static int em_token_restore_tuc(uint8_t em_version, em_token_ptr *token_ptr, em_parsed_token *parsed_token,
				void *table_org)
{
	int ret;
	tuc_table_v20 *table_v20 = NULL, table_new = {0,};

	uint16_t i = 0;

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_RESTORE_TUC, token_ptr, parsed_token, table_org);

	ret = em_token_make_tuc_v20(&table_new, token_ptr, parsed_token);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to make tuc v20(0x%08x)\n", ret);
		goto out;
	}

	table_v20 = (tuc_table_v20 *)table_org;
	for (i = 0; i < table_v20->num_of_tuc; i++) {
		if (table_v20->tucs[i].mode_index == table_new.tucs[i].mode_index) {
			if (!(table_v20->tucs[i].flags & EM_TYPE_TUC_ONLY_ONCE))
				continue;
			table_new.tucs[i].count = table_v20->tucs[i].count;
		} else {
			LOGE("Unknown tuc, please check it\n");
			ret = EM_ERR_EM_TOKEN_RESTORE_TUC_TABLE;
			goto out;
		}
	}
	memcpy(table_org, &table_new, sizeof(tuc_table_v20));

	ret = EM_SUCCESS;
out:
	return ret;
}

int em_token_is_installed(em_context *ctx)
{
	int ret;

	uint8_t token_id_esi[EM_LEN_TOKEN_ID + 1] = {0,};
	(void)token_id_esi;

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_IS_INSTALLED, ctx, ctx->parsed_token);

#ifndef EMLITE
	if (!(ctx->flags[2] & EM_FLAGS_2_ENABLED_LSEC_TOKEN)) {
		ret = em_esi_check_meta(ctx->esi);
		if (ret != EM_SUCCESS) {
			LOGE("Invalid ESI meta\n");
			goto out;
		}

		ret = em_esi_get_item(ctx->esi, EM_TYPE_ESI_ITEM_TOKEN_ID, token_id_esi, EM_LEN_TOKEN_ID);
		if (ret != EM_SUCCESS) {
			LOGE("Failed to get token_id from esi(0x%08x)\n", ret);
			goto out;
		}

		if (memcmp(token_id_esi, ctx->parsed_token->token.id, EM_LEN_TOKEN_ID) != 0) {
			LOGE("No matched token id\n");
			ret = EM_ERR_EM_TOKEN_IS_INSTALLED_TOKEN_ID;
			ctx->flags[1] |= EM_FLAGS_1_EXIST_RETURN_TOKEN_REMOVE;
			goto out;
		}
	}
#endif
	ret = EM_SUCCESS;
out:

	return ret;
}

int em_token_get_status(em_context *ctx)
{
	int ret, i = 0;

	em_esi_meta meta = {0,};
	(void)meta;

	tuc_table_v20 tuc_v20 = {0,};
	void *p_tuc = NULL, *p_tuc_origin = NULL;
	uint32_t len_tuc = 0;
	(void)tuc_v20;
	(void)p_tuc;
	(void)p_tuc_origin;
	(void)len_tuc;

	uint8_t token_id_esi[EM_LEN_TOKEN_ID + 1] = {0,};
	uint8_t priority_date[EM_LEN_TOKEN_ID + EM_LEN_DATE + 1] = {0,};
	(void)token_id_esi;
	(void)priority_date;

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_GET_STATUS, ctx, ctx->parsed_token);

	if (ctx->flags[1] & EM_FLAGS_0_DEV_CERT) {
		LOGE("Dev token is not allowed\n");
		ret = EM_ERR_EM_TOKEN_GET_STATUS_NOT_ALLOWED_CERT;
		goto out;
	}

	if (ctx->modes[0] == EM_MODE_REFILL_AND_CHECK && ctx->flags[0] & EM_FLAGS_0_EXIST_DATE) {
		LOGI("This is RAC\n");
		ret = EM_SUCCESS;
	} else {
		ret = EM_ERR_EM_TOKEN_GET_STATUS_NOT_ALLOWED_MODE;
		for (i = 0; i < ctx->parsed_token->mode.num_of_modes; i++) {
			if (ctx->modes[0] == ctx->parsed_token->mode.mode[i]) {
				LOGI("Requested mode(0x%04x) is exists in token\n", ctx->modes[0]);
				ret = EM_SUCCESS;
				break;
			}
		}
	}

	if (ret != EM_SUCCESS) {
		LOGE("Requested mode(0x%04x) isn't exists in token\n", ctx->modes[0]);
		goto out;
	}

	if (!(ctx->flags[0] & EM_FLAGS_0_EXIST_BOOTLOADER || ctx->flags[0] & EM_FLAGS_0_EXIST_IS_CALLER_CHECKED)) {
		ret = em_client_verify(ctx, ctx->parsed_token);
		if (ret != EM_SUCCESS) {
			LOGE("Failed to verify client(0x%08x)\n", ret);
			goto out;
		}
	}

#ifndef EMLITE
	if (ctx->flags[2] & EM_FLAGS_2_ENABLED_LSEC_TOKEN) {
		LOGI("This lsec token is verified");
		ret = EM_SUCCESS;
		goto out;
	}

	ret = em_esi_check_meta(ctx->esi);
	if (ret != EM_SUCCESS) {
		LOGE("Invalid ESI meta\n");
		goto out;
	}

	ret = em_esi_get_item(ctx->esi, EM_TYPE_ESI_ITEM_TOKEN_ID, token_id_esi, EM_LEN_TOKEN_ID);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to get token_id from esi(0x%08x)\n", ret);
		goto out;
	}

	if (memcmp(token_id_esi, ctx->parsed_token->token.id, EM_LEN_TOKEN_ID) != 0) {
		LOGE("No matched token id\n");
		ret = EM_ERR_EM_TOKEN_GET_STATUS_TOKEN_ID;
		ctx->flags[1] |= EM_FLAGS_1_EXIST_RETURN_TOKEN_REMOVE;
		goto out;
	}

	p_tuc = (void *)&tuc_v20;
	len_tuc = sizeof(tuc_table_v20);

	p_tuc_origin = (void *)em_calloc(1, len_tuc);
	if (p_tuc_origin == NULL) {
		LOGE("Failed to allocate tuc buffer\n");
		ret = EM_ERR_EM_TOKEN_GET_STATUS_ALLOCATE_BUFFER;
		goto out;
	}

	ret = em_get_tuc_table(ctx->esi, p_tuc, len_tuc);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to get tuc table(0x%08x)\n", ret);
		goto out;
	}

	memcpy(p_tuc_origin, p_tuc, len_tuc);

	if (ctx->flags[0] & EM_FLAGS_0_EXIST_DATE) {
		ret = em_esi_get_item(ctx->esi, EM_TYPE_ESI_ITEM_PRIORITY_TIME, priority_date, EM_LEN_DATE);
		if (ret == EM_SUCCESS) {
			if (memcmp(ctx->parsed_token->token.id, priority_date, EM_LEN_TOKEN_ID) == 0) {
				ret = em_token_check_expiration((const char *)(priority_date + EM_LEN_TOKEN_ID),
								(const char *)ctx->date);
				if (ret != EM_SUCCESS) {
					ctx->flags[1] |= EM_FLAGS_1_EXIST_RETURN_TOKEN_EXPIRED |
							 EM_FLAGS_1_EXIST_RETURN_TOKEN_REMOVE;
					LOGE("Failed to check expiration(0x%08x)\n", ret);
					goto out;
				}
			}
		}

		ret = em_token_restore_tuc(ctx->em_version, &ctx->token_ptr, ctx->parsed_token, p_tuc);
		if (ret != EM_SUCCESS) {
			LOGE("Failed to resotre tuc(0x%08x)\n", ret);
			goto out;
		}

		LOGI("tuc is recovered\n");
	} else {
		if (ctx->flags[0] & EM_FLAGS_0_EXIST_PLEASE_NO_COUNT) {
			LOGI("No count\n");
			ret = EM_SUCCESS;
			goto out;
		}

		for (i = 0; i < tuc_v20.num_of_tuc; i++) {
			if (tuc_v20.tucs[i].mode_index != ctx->modes[0])
				continue;

			if (!(tuc_v20.tucs[i].flags & EM_TYPE_TUC_IS_ENABLE) &&
			    !(tuc_v20.tucs[i].flags & EM_TYPE_TUC_ONLY_ONCE)) {
				LOGI("Requested mode(0x%04x) isn't related usage count(0x%08x)\n", ctx->modes[0],
				     tuc_v20.tucs[i].flags);
				break;
			}

			if (tuc_v20.tucs[i].count == 0) {
				LOGE("mode(%04x) can't be used(%u)\n", ctx->modes[0], tuc_v20.tucs[i].count);
				ret = EM_ERR_EM_TOKEN_GET_STATUS_TUC_ZERO;
				goto out;
			}

			tuc_v20.tucs[i].count = tuc_v20.tucs[i].count - 1;
		}
	}

	if (memcmp(p_tuc, p_tuc_origin, len_tuc) == 0) {
		LOGI("tuc table isn't changed\n");
		ret = EM_SUCCESS;
		goto out;
	}

	LOGI("tuc table is changed\n");
	ret = em_esi_update_item(ctx->em_version, ctx->esi, EM_TYPE_ESI_ITEM_TUC_TABLE_LEGACY, p_tuc, ctx->key,
				 EM_LEN_KEY_CORE_V20);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to update tuc(0x%08x)\n", ret);
		goto out;
	}

	em_esi_read_meta(&meta, ctx->esi);
	if (ctx->is_provision && memcmp(ctx->core_v20.magic, EM_MAGIC_EM_CORE, strlen(EM_MAGIC_EM_CORE)) == 0) {
		meta.write_counter += 1;
		ctx->core_v20.esi_ctr = meta.write_counter;
		ctx->flags[1] |= EM_FLAGS_1_WRITE_CORE;
	}

	ret = em_esi_update(ctx->em_version, ctx->esi, &meta, NULL, ctx->key, EM_LEN_KEY_CORE_V20);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to update esi(0x%08x)\n", ret);
		goto out;
	}

	ctx->flags[1] |= EM_FLAGS_1_EXIST_RETURN_ESI;
#endif // EMLITE

	ret = EM_SUCCESS;
out:
	if (p_tuc_origin)
		em_free(p_tuc_origin);

	return ret;
}

int em_token_install(em_context *ctx)
{
	int ret;

	em_esi_meta meta = {0,};
	tuc_table_v20 table_v20 = {0,};
	(void)meta;
	(void)table_v20;

	uint8_t last_token_id_esi[EM_LEN_TOKEN_ID] = {0,};
	uint8_t last_token_id_temp[EM_LEN_TOKEN_ID] = {0,};
	uint8_t last_token_id_temp_2[EM_LEN_TOKEN_ID] = {0,};
	uint32_t lti_type = 0;
	(void)last_token_id_esi;
	(void)last_token_id_temp;
	(void)last_token_id_temp_2;
	(void)lti_type;

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_INSTALL, ctx, ctx->parsed_token);

	if (ctx->cmd == EM_CMD_INSTALL_TOKEN) {
		if (!(ctx->flags[0] & EM_FLAGS_0_EXIST_BOOTLOADER)) {
			if (!(ctx->flags[0] & EM_FLAGS_0_EXIST_KEEPING_ITEM)) {
				LOGE("Keeping item isn't exists\n");
				ret = EM_ERR_EM_TOKEN_INSTALL_KEEPING_ITEM;
				goto out;
			}

			if (memcmp(ctx->keep.single_id, ctx->parsed_token->issuer.single_id, EM_LEN_SINGLE_ID) != 0) {
				LOGE("Requested single id isn't matched\n");
				ret = EM_ERR_EM_TOKEN_INSTALL_SINGLE_ID;
				goto out;
			}

			if (memcmp(ctx->keep.model_name, ctx->parsed_token->device[0].model_name, EM_LEN_MODEL_NAME) != 0) {
				LOGE("Rueqested model name isn't matched\n");
				ret = EM_ERR_EM_TOKEN_INSTALL_MODEL_NAME;
				goto out;
			}

			if (memcmp(ctx->keep.nonce, ctx->parsed_token->issuer.nonce, EM_LEN_NONCE) != 0) {
				LOGE("Requested nonce isn't matched\n");
				ret = EM_ERR_EM_TOKEN_INSTALL_NONCE;
				goto out;
			}

			if (strncmp((char *)ctx->token_ptr.header.type, "RMA", EM_LEN_HEADER_FIELD) &&
			    strncmp((char *)ctx->token_ptr.header.type, "RSD", EM_LEN_HEADER_FIELD)) {
				LOGE("Not support token type(%02x/%02x/%02x)\n", ctx->token_ptr.header.type[0],
				     ctx->token_ptr.header.type[1], ctx->token_ptr.header.type[2]);
				ret = EM_ERR_EM_TOKEN_INSTALL_NOT_SUPPORT_TYPE;
				goto out;
			}
		} else {
			if (strncmp((char *)ctx->token_ptr.header.type, "RWS", EM_LEN_HEADER_FIELD) &&
			    strncmp((char *)ctx->token_ptr.header.type, "RSS", EM_LEN_HEADER_FIELD)) {
				LOGE("Not support token type(%02x/%02x/%02x)\n", ctx->token_ptr.header.type[0],
				     ctx->token_ptr.header.type[1], ctx->token_ptr.header.type[2]);
				ret = EM_ERR_EM_TOKEN_INSTALL_NOT_SUPPORT_TYPE_2;
				goto out;
			}
		}
	} else if (ctx->cmd == EM_CMD_INSTALL_TOKEN_ESS_V1) {
		if (memcmp(ctx->keep.nonce, ctx->parsed_token->issuer.nonce, EM_LEN_NONCE) != 0) {
			LOGE("Requested nonce isn't matched\n");
			ret = EM_ERR_EM_TOKEN_INSTALL_NONCE_ESS;
			goto out;
		}
	}

	memcpy(ctx->token_id, ctx->parsed_token->token.id, EM_LEN_TOKEN_ID);

	if (ctx->flags[2] & EM_FLAGS_2_ENABLED_LSEC_TOKEN) {
		ret = EM_SUCCESS;
		goto out;
	}

#ifndef EMLITE
	ret = em_esi_check_meta(ctx->esi);
	if (ret != EM_SUCCESS) {
		LOGE("Invalid ESI meta\n");
		goto out;
	}

	ret = em_token_is_from_fac(ctx->parsed_token->integrity.cert, ctx->parsed_token->integrity.len_cert);
	if (ret != EM_SUCCESS && (uint32_t)ret != EM_ERR_EM_TOKEN_IS_FROM_FAC_FROM_FAC) {
		LOGE("Failed to check location where issued(0x%08x)\n", ret);
		goto out;
	}

	lti_type = ((uint32_t)ret == EM_ERR_EM_TOKEN_IS_FROM_FAC_FROM_FAC) ? EM_TYPE_ESI_ITEM_LATEST_FAC_TOKEN_ID
									   : EM_TYPE_ESI_ITEM_LATEST_TOKEN_ID;

	ret = em_esi_get_item(ctx->esi, lti_type, last_token_id_esi, EM_LEN_TOKEN_ID);
	if (ret == EM_SUCCESS) {
		if (lti_type == EM_TYPE_ESI_ITEM_LATEST_FAC_TOKEN_ID) {
			memcpy(last_token_id_temp, last_token_id_esi, 5);
			memcpy(last_token_id_temp_2, ctx->parsed_token->token.id, 5);

			if (memcmp(last_token_id_temp, last_token_id_temp_2, EM_LEN_TOKEN_ID) > 0) {
				LOGE("This token is already used\n");
				ret = EM_ERR_EM_TOKEN_INSTALL_ALREADY_USED_FAC;
				goto out;
			}
		} else {
			memcpy(last_token_id_temp, last_token_id_esi, 5);
			memcpy(last_token_id_temp + 5, last_token_id_esi + 10, 6);
			memcpy(last_token_id_temp_2, ctx->parsed_token->token.id, 5);
			memcpy(last_token_id_temp_2 + 5, ctx->parsed_token->token.id + 10, 6);

			if (memcmp(last_token_id_temp, last_token_id_temp_2, EM_LEN_TOKEN_ID) >= 0) {
				LOGE("This token is already used\n");
				ret = EM_ERR_EM_TOKEN_INSTALL_ALREADY_USED;
				goto out;
			}
		}
	}

	ret = em_esi_update_item(ctx->em_version, ctx->esi, lti_type, ctx->parsed_token->token.id, ctx->key,
				 EM_LEN_KEY_CORE_V20);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to update lti to esi(0x%08x)\n", ret);
		goto out;
	}

	ret = em_esi_update_item(ctx->em_version, ctx->esi, EM_TYPE_ESI_ITEM_TOKEN_ID, ctx->parsed_token->token.id,
				 ctx->key, EM_LEN_KEY_CORE_V20);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to update token id to esi(0x%08x)\n", ret);
		goto out;
	}

	ret = em_token_make_tuc_v20(&table_v20, &ctx->token_ptr, ctx->parsed_token);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to make tuc v20(0x%08x)\n", ret);
		goto out;
	}

	ret = em_esi_update_item(ctx->em_version, ctx->esi, EM_TYPE_ESI_ITEM_TUC_TABLE_LEGACY, (uint8_t *)&table_v20,
				 ctx->key, EM_LEN_KEY_CORE_V20);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to add tuc table v20 to esi(0x%08x)\n", ret);
		goto out;
	}

	em_esi_read_meta(&meta, ctx->esi);
	meta.write_counter += 1;

	ret = em_esi_update(ctx->em_version, ctx->esi, &meta, NULL, ctx->key, EM_LEN_KEY_CORE_V20);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to update esi(0x%08x)\n", ret);
		goto out;
	}

	if (memcmp(ctx->core_v20.magic, EM_MAGIC_EM_CORE, strlen(EM_MAGIC_EM_CORE)) == 0 && ctx->is_provision) {
		ctx->core_v20.esi_ctr = meta.write_counter;
		ctx->flags[1] |= EM_FLAGS_1_WRITE_CORE;
	}

	ctx->flags[1] |= EM_FLAGS_1_EXIST_RETURN_ESI;
#endif
	ctx->flags[1] |= EM_FLAGS_1_LTS_INSTALL_TOKEN;

	ret = EM_SUCCESS;
out:

	return ret;
}

int em_token_is_from_fac(const uint8_t *cert, const int len_cert)
{
	int ret = EM_SUCCESS;

	char uid[EM_LEN_CERT_UID] = {0,};
	char *uid_attr[EM_LEN_CERT_UID_ATTR] = {0,};
	int index = 0;

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_IS_FROM_FAC, cert);

	ret = em_crypto_get_subject_from_cert(cert, len_cert, EM_CERT_SUBJECT_UID, uid, sizeof(uid));
	if (ret != EM_SUCCESS) {
		LOGE("Failed to get uid from cert(0x%08x)\n", ret);
		goto out;
	}

	uid_attr[index] = em_strtok(uid, ":");
	while (uid_attr[index] != NULL)
		uid_attr[++index] = em_strtok(NULL, ":");

	if (uid_attr[2] == NULL) {
		LOGE("No server type\n");
		goto out;
	}

	if (memcmp(uid_attr[2], "10", 2) == 0) {
		LOGI("This is cert from factory\n");
		ret = EM_ERR_EM_TOKEN_IS_FROM_FAC_FROM_FAC;
	}

out:
	return ret;
}

int em_token_get_usage_count(em_context *ctx)
{
	int ret, i = 0;
	(void)i;

	tuc_table_v20 *table_v20 = NULL;
	(void)table_v20;

	uint8_t *buf = NULL;

	buf = (uint8_t *)em_calloc(sizeof(tuc_table), 1); // sizeof tuc_table > tuc_table_v20
	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_GET_USAGE_COUNT, ctx, buf);

#ifndef EMLITE
	ret = em_esi_check_meta(ctx->esi);
	if (ret != EM_SUCCESS) {
		LOGE("Invalid ESI meta\n");
		goto out;
	}

	ret = em_get_tuc_table(ctx->esi, buf, sizeof(tuc_table));
	if (ret != EM_SUCCESS) {
		LOGE("Failed to get tuc table(0x%08x)\n", ret);
		goto out;
	}

	table_v20 = (tuc_table_v20 *)buf;
	for (i = 0; i < table_v20->num_of_tuc; i++) {
		if (table_v20->tucs[i].mode_index == ctx->modes[0]) {
			if (!(table_v20->tucs[i].flags & EM_TYPE_TUC_IS_ENABLE) &&
			    !(table_v20->tucs[i].flags & EM_TYPE_TUC_ONLY_ONCE)) {
				ctx->ret_temp = 99999999;
				break;
			}
			ctx->ret_temp = table_v20->tucs[i].count;
			break;
		}
	}
#else
	ctx->ret_temp = 99999999;
#endif

	ret = EM_SUCCESS;
out:
	if (buf)
		em_free(buf);

	return ret;
}

static void em_token_set_no_token(uint8_t *buf, uint32_t buf_size, uint32_t *offset)
{
	*offset = 0;
	em_add_string(buf, buf_size, offset, (uint8_t *)EM_MAGIC_NOK, (uint32_t)strlen(EM_MAGIC_NOK));
	em_add_string(buf, buf_size, offset, (uint8_t *)EM_MAGIC_GET_MODE_TOKENINZER,
		      (uint32_t)strlen(EM_MAGIC_GET_MODE_TOKENINZER));
	em_add_string(buf, buf_size, offset, (uint8_t *)EM_MAGIC_GET_MODE_NO_TOKEN,
		      (uint32_t)strlen(EM_MAGIC_GET_MODE_NO_TOKEN));
}

int em_token_is_dev_device(em_context *ctx)
{
	int ret;
	uint8_t did_esi[EM_LEN_DID] = {0,};

#ifndef EMLITE
	if (ctx->flags[2] & EM_FLAGS_2_ENABLED_LSEC_TOKEN) {
		memcpy(did_esi, ctx->did, EM_LEN_DID);
	} else {
		ret = em_esi_check_meta(ctx->esi);
		if (ret != EM_SUCCESS) {
			LOGE("Invalid ESI meta\n");
			goto out;
		}

		ret = em_esi_get_item(ctx->esi, EM_TYPE_ESI_ITEM_DID, did_esi, EM_LEN_DID);
		if (ret != EM_SUCCESS) {
			LOGE("Failed to get did from esi(0x%08x)\n", ret);
			goto out;
		}
	}
#else
	memcpy(did_esi, ctx->did, EM_LEN_DID);
#endif

	if (memcmp(did_esi + 14, EM_MAGIC_USER_FUSE, 2) != 0)
		ctx->flags[1] |= EM_FLAGS_1_IS_DEV_DEVICE;

	ret = EM_SUCCESS;
out:
	return ret;
}

int em_token_get_only_mode(em_context *ctx, uint8_t *out, uint32_t *len_out)
{
	int ret;

	uint32_t index = 0, i = 0, len = 0;

	uint8_t did_esi[EM_LEN_DID] = {0,};
	uint8_t token_id_esi[EM_LEN_TOKEN_ID] = {0,};
	(void)did_esi;
	(void)token_id_esi;

	char str_tmp[EM_LEN_TOKEN_MODE_STRING] = {0,};

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_GET_ONLY_MODE, ctx, len_out, out, ctx->parsed_token);

#ifndef EMLITE
	if (!(ctx->flags[2] & EM_FLAGS_2_ENABLED_LSEC_TOKEN)) {
		ret = em_esi_check_meta(ctx->esi);
		if (ret != EM_SUCCESS) {
			LOGE("Invalid ESI meta\n");
			goto out;
		}

		ret = em_esi_get_item(ctx->esi, EM_TYPE_ESI_ITEM_TOKEN_ID, token_id_esi, EM_LEN_TOKEN_ID);
		if (ret != EM_SUCCESS) {
			LOGE("Failed to get token_id from esi(0x%08x)\n", ret);
			goto out;
		}

		ret = em_esi_get_item(ctx->esi, EM_TYPE_ESI_ITEM_DID, did_esi, EM_LEN_DID);
		if (ret != EM_SUCCESS) {
			LOGE("Failed to get did from esi(0x%08x)\n", ret);
			goto out;
		}

		if (memcmp(token_id_esi, ctx->parsed_token->token.id, EM_LEN_TOKEN_ID) != 0) {
			LOGE("Not matched token_id\n");
			ret = EM_ERR_EM_TOKEN_GET_ONLY_MODE_T_ID;
			goto out;
		}

		if (em_strncasecmp((const char *)did_esi, (const char *)ctx->parsed_token->device[0].did, EM_LEN_DID) != 0) {
			LOGE("Not matched did\n");
			ret = EM_ERR_EM_TOKEN_GET_ONLY_MODE_DID;
			goto out;
		}
	}
#endif

	if (ctx->parsed_token->mode.num_of_modes > EM_LEN_MAX_MODE) {
		LOGE("num of modes(%u) is bigger than max(%u)\n", ctx->parsed_token->mode.num_of_modes, EM_LEN_MAX_MODE);
		ret = EM_ERR_EM_TOKEN_GET_ONLY_MODE_MODE;
		goto out;
	}

	for (i = 0; i < ctx->parsed_token->mode.num_of_modes; i++) {
		em_itoa_for_mode(ctx->parsed_token->mode.mode[i], str_tmp);
		len = strlen(str_tmp);
		if (len > EM_LEN_TOKEN_MODE_STRING) {
			LOGE("Mode length isn't normal(%u)\n", len);
			ret = EM_ERR_EM_TOKEN_GET_ONLY_MODE_M_LEN;
			goto out;
		}

		if (index + len + 1 > EM_LEN_TOKEN_MODE_INFORMATION) {
			LOGE("buf isn't enough(%u)\n", len);
			LOGE("%s/%s\n", str_tmp, out);
			ret = EM_ERR_EM_TOKEN_GET_ONLY_MODE_BUF;
			goto out;
		}
		memcpy(out + index, str_tmp, len);
		if ((uint32_t)i != (uint32_t)(ctx->parsed_token->mode.num_of_modes - 1)) {
			out[index + len] = '_';
			index += len + 1;
		}
	}
	*len_out = index + len;

	ret = EM_SUCCESS;
out:

	return ret;
}

int em_token_get_mode_information(em_context *ctx)
{
	int ret;
	uint32_t index = 0;

	uint8_t *modes = NULL;
	uint32_t len_modes;

	modes = (uint8_t *)em_calloc(EM_LEN_TOKEN_MODE_INFORMATION, 1);
	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_GET_MODE_INFORMATION, ctx, modes);

	ret = em_token_is_dev_device(ctx);
	if (ret != EM_SUCCESS)
		goto out;

	em_add_string(ctx->message, EM_LEN_TOKEN_MODE_INFORMATION, &index, (uint8_t *)EM_MAGIC_OK,
		      (uint32_t)strlen(EM_MAGIC_OK));
	em_add_string(ctx->message, EM_LEN_TOKEN_MODE_INFORMATION, &index, (uint8_t *)EM_MAGIC_GET_MODE_TOKENINZER,
		      (uint32_t)strlen(EM_MAGIC_GET_MODE_TOKENINZER));

	if (ctx->flags[1] & EM_FLAGS_1_IS_DEV_DEVICE)
		em_add_string(ctx->message, EM_LEN_TOKEN_MODE_INFORMATION, &index,
			      (uint8_t *)EM_MAGIC_GET_MODE_FROM_DEV, (uint32_t)strlen(EM_MAGIC_GET_MODE_FROM_DEV));
	else
		em_add_string(ctx->message, EM_LEN_TOKEN_MODE_INFORMATION, &index,
			      (uint8_t *)EM_MAGIC_GET_MODE_FROM_TOKEN, (uint32_t)strlen(EM_MAGIC_GET_MODE_FROM_TOKEN));

	ret = em_token_get_only_mode(ctx, modes, &len_modes);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to get mode(0x%08x)\n", ret);

		if (ctx->flags[1] & EM_FLAGS_1_IS_DEV_DEVICE)
			LOGI("This is dev device and no token\n");
		else {
			memset(ctx->message, 0x00, index);
			em_token_set_no_token(ctx->message, EM_LEN_TOKEN_MODE_INFORMATION, &index);
		}

		goto msg;
	}

	em_add_string(ctx->message, EM_LEN_TOKEN_MODE_INFORMATION, &index, (uint8_t *)EM_MAGIC_GET_MODE_TOKENINZER,
		      (uint32_t)strlen(EM_MAGIC_GET_MODE_TOKENINZER));
	em_add_string(ctx->message, EM_LEN_TOKEN_MODE_INFORMATION, &index, modes, len_modes);

msg:
	ctx->len_message = index;
	ctx->flags[1] |= EM_FLAGS_1_EXIST_RETURN_MESSAGE;
	LOGI("message size : (%d)\n", ctx->len_message);

	ret = EM_SUCCESS;
out:
	if (modes)
		em_free(modes);

	return ret;
}

int em_token_get_mode_information_for_bit(em_context *ctx)
{
	int ret, i = 0;

	uint8_t token_id_esi[EM_LEN_TOKEN_ID] = {0,};
	(void)token_id_esi;

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_GET_MODE_BIT, ctx, ctx->parsed_token);

#ifndef EMLITE
	if (!(ctx->flags[2] & EM_FLAGS_2_ENABLED_LSEC_TOKEN)) {
		ret = em_esi_check_meta(ctx->esi);
		if (ret != EM_SUCCESS) {
			LOGE("Invalid ESI meta\n");
			goto out;
		}

		ret = em_esi_get_item(ctx->esi, EM_TYPE_ESI_ITEM_TOKEN_ID, token_id_esi, EM_LEN_TOKEN_ID);
		if (ret != EM_SUCCESS) {
			LOGE("Failed to get token_id from esi(0x%08x)\n", ret);
			goto out;
		}

		if (memcmp(token_id_esi, ctx->parsed_token->token.id, EM_LEN_TOKEN_ID) != 0) {
			LOGE("Not matched token_id\n");
			ret = EM_ERR_EM_TOKEN_GET_MODE_BIT_TOKEN_ID;
			goto out;
		}
	}
#endif

	if (ctx->parsed_token->mode.num_of_modes > EM_LEN_MAX_MODE) {
		LOGE("num of modes(%u) is bigger than max(%u)\n", ctx->parsed_token->mode.num_of_modes, EM_LEN_MAX_MODE);
		ret = EM_ERR_EM_TOKEN_GET_MODE_BIT_MODE;
		goto out;
	}

	for (i = 0; i < ctx->parsed_token->mode.num_of_modes; i++) {
		if (ctx->parsed_token->mode.mode[i] / 64 >= EM_LEN_GET_MODES_BIT_BUFFER) {
			LOGE("Mode flag buffer isn't enough(0x%08x)\n", ctx->parsed_token->mode.mode[i]);
			ret = EM_ERR_EM_TOKEN_GET_MODE_BIT_BUF;
			goto out;
		}

		ctx->mode_bits[(ctx->parsed_token->mode.mode[i]) / 64] |=
		    ((uint64_t)1 << ((ctx->parsed_token->mode.mode[i]) % 64));
	}

	LOGI("%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 "\n", ctx->mode_bits[0], ctx->mode_bits[1],
	     ctx->mode_bits[2], ctx->mode_bits[3]);
	ctx->flags[1] |= EM_FLAGS_1_EXIST_RETURN_MODES_BIT;
	ret = EM_SUCCESS;
out:

	return ret;
}

int em_token_check_time_msg(uint8_t *message, uint32_t len_message, em_context *ctx)
{
	int ret;
	uint32_t offset = 0;
	uint32_t len_ser_nonce, len_rtd_ack, index = 0;
	uint8_t del_cmd[EM_LEN_TRS_DEL_CMD + 1] = {0,};
	uint8_t token_id_esi[EM_LEN_TOKEN_ID + 1] = {0,};
	uint8_t enc_ser_nonce[EM_LEN_TRS_SER_NONCE + 1] = {0,};
	uint8_t ser_nonce[EM_LEN_TRS_SER_NONCE + 1] = {0,};
	uint8_t packet_wb_iv[EM_LEN_TRS_WB_IV + 1] = {0,};
	uint8_t wb_iv[EM_LEN_TRS_WB_IV + 1] = {0,};
	uint8_t rtd_ack[EM_LEN_RTD_ACK + 1] = {0,};
	uint8_t enc_rtd_ack[EM_LEN_RTD_ACK + 1] = {0,};

	em_header_info header = {0,};
	em_token_ptr token_ptr = {0,};
	em_integrity_info *integ = NULL;

	uint8_t msg[EM_LEN_NONCE + EM_LEN_DID + EM_LEN_TOKEN_ID + EM_LEN_DATE + EM_LEN_TRS_DEL_CMD + 1] = {0,};

	integ = (em_integrity_info *)em_calloc(sizeof(em_integrity_info), 1);
	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_CHECK_TIME_MSG, message, ctx, integ);

	memcpy(&header, message, sizeof(em_header_info));
	if (memcmp(header.prefix, EM_MAGIC_PACKET_ENG, strlen(EM_MAGIC_PACKET_ENG)) != 0) {
		LOGE("Unknown header magic(%02x/%02x/%02x\n", header.prefix[0], header.prefix[1], header.prefix[2]);
		ret = EM_ERR_EM_TOKEN_CHECK_TIME_MSG_MAGIC;
		goto out;
	}

	if (memcmp(header.type, EM_MAGIC_TYPE_TIME_RESPONSE, strlen(EM_MAGIC_TYPE_TIME_RESPONSE)) != 0) {
		LOGE("Unknown type(%02x/%02x/%02x)\n", header.type[0], header.type[1], header.type[2]);
		ret = EM_ERR_EM_TOKEN_CHECK_TIME_MSG_TYPE;
		goto out;
	}

	if (memcmp(header.version, EM_MAGIC_PACKET_VERSION4, strlen(EM_MAGIC_PACKET_VERSION4)) != 0) {
		LOGE("Unknown version(%02x/%02x/%02x/%02x)\n", header.version[0], header.version[1], header.version[2], header.version[3]);
		ret = EM_ERR_EM_TOKEN_CHECK_TIME_MSG_VERSION;
		goto out;
	}

	token_ptr.integrity_info = message + sizeof(em_header_info) + EM_LEN_TRS_PACKET_BODY;
	ret = em_token_parse_integrity_info(integ, &token_ptr);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to check integrity(0x%08x)\n", ret);
		goto out;
	}

	memcpy(msg, ctx->keep.nonce, EM_LEN_NONCE);
	offset += EM_LEN_NONCE;

	memcpy(msg + offset, ctx->did, EM_LEN_DID);
	offset += EM_LEN_DID;

#ifndef EMLITE
	ret = em_esi_get_item(ctx->esi, EM_TYPE_ESI_ITEM_TOKEN_ID, token_id_esi, EM_LEN_TOKEN_ID);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to get token_id from esi(0x%08x)\n", ret);
		goto out;
	}

	memcpy(msg + offset, token_id_esi, EM_LEN_TOKEN_ID);
	offset += EM_LEN_TOKEN_ID;
#else
	ret = em_token_get_token_id(ctx);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to get token id(0x%08x)\n", ret);
		goto out;
	}

	memcpy(msg + offset, ctx->token_id, EM_LEN_TOKEN_ID);
	offset += EM_LEN_TOKEN_ID;
#endif /* EMLITE */

	memcpy(msg + offset, message + sizeof(em_header_info), EM_LEN_DATE);
	offset += EM_LEN_DATE;

	memcpy(msg + offset, message + sizeof(em_header_info) + EM_LEN_DATE, EM_LEN_TRS_DEL_CMD);
	offset += EM_LEN_TRS_DEL_CMD;

	ret = em_crypto_verify_rsa_signature(integ->cert, integ->len_cert, integ->signature, integ->len_signature, msg,
					     offset);
	if (ret != EM_SUCCESS && (uint32_t)ret != EM_DEV_OK) {
		LOGE("Failed to verify signature(0x%08x)\n", ret);
		goto out;
	}

	memcpy(del_cmd, message + sizeof(em_header_info) + EM_LEN_DATE, EM_LEN_TRS_DEL_CMD);

#ifdef DEBUG_LOG
	LOGD("del command  : (0x%02x)\n", del_cmd[0]);
#endif

	offset = 0;
	em_add_string(ctx->message, EM_LEN_MESSAGE, &offset, del_cmd, EM_LEN_TRS_DEL_CMD);
	em_add_string(ctx->message, EM_LEN_MESSAGE, &offset, message + sizeof(em_header_info), EM_LEN_DATE);

	switch (del_cmd[0])
	{
	case EM_RTD_CMD_NONE:
		break;
	case EM_RTD_CMD_ACK:
		memcpy(enc_ser_nonce, message + sizeof(em_header_info) + EM_LEN_DATE + EM_LEN_TRS_DEL_CMD, EM_LEN_TRS_SER_NONCE);
		memcpy(packet_wb_iv, message + sizeof(em_header_info) + EM_LEN_DATE + EM_LEN_TRS_DEL_CMD + EM_LEN_TRS_SER_NONCE, EM_LEN_TRS_WB_IV);
		
		ret = em_wb_aes_ctr_decrypt(enc_ser_nonce, EM_LEN_TRS_SER_NONCE, ser_nonce,
									&len_ser_nonce, packet_wb_iv, EMWB_TAG_TKN_DEL);
		if (ret != EM_SUCCESS) {
			LOGE("Failed to wb-decrypt(0x%08x)\n", ret);
			goto out;
		}

		if (len_ser_nonce != EM_LEN_TRS_SER_NONCE) {
			LOGE("Incorrect decryption nonce size\n");
			ret = EM_ERR_EM_TOKEN_CHECK_TIME_MSG_NONCE_LEN;
			goto out;
		}

		ret = em_get_random(wb_iv, EM_LEN_TRS_WB_IV);
		if (ret != EM_LEN_TRS_WB_IV) {
			LOGE("Failed to generate iv(0x%08x)\n", ret);
			ret = EM_ERR_EM_TOKEN_CHECK_TIME_MSG_IV;
			goto out;
		}

		memcpy(rtd_ack, ctx->did, EM_LEN_DID);
		index += EM_LEN_DID;

		memcpy(rtd_ack + index, token_id_esi, EM_LEN_TOKEN_ID);
		index += EM_LEN_TOKEN_ID;

		memcpy(rtd_ack + index, ser_nonce, len_ser_nonce);
		index += len_ser_nonce;

		ret = em_wb_aes_ctr_encrypt(rtd_ack, EM_LEN_RTD_ACK, enc_rtd_ack,
									&len_rtd_ack, wb_iv, EMWB_TAG_TKN_DEL);
		if (ret != EM_SUCCESS) {
			LOGE("Failed to wb-encrypt(0x%08x)\n", ret);
			goto out;
		}

		if (len_rtd_ack != EM_LEN_RTD_ACK) {
			LOGE("Incorrect encryption rtd ack size\n");
			ret = EM_ERR_EM_TOKEN_CHECK_TIME_MSG_RTD_ACK_LEN;
			goto out;
		}

		em_add_string(ctx->message, EM_LEN_MESSAGE, &offset, (uint8_t *)"ENGTAK0003", sizeof(em_header_info));
		em_add_string(ctx->message, EM_LEN_MESSAGE, &offset, enc_rtd_ack, EM_LEN_RTD_ACK);
		em_add_string(ctx->message, EM_LEN_MESSAGE, &offset, wb_iv, EM_LEN_TRS_WB_IV);

	case EM_RTD_CMD_NO_ACK:
		ctx->flags[1] |= EM_FLAGS_1_EXIST_RETURN_TOKEN_REMOVE;
		break;
	default:
		LOGE("Failed to parse RTD command  : (0x%02x)\n", del_cmd[0]);
		ret = EM_ERR_EM_TOKEN_CHECK_TIME_MSG_DEL_CMD;
		goto out;
	}

	ctx->len_message = offset;
	ctx->flags[1] |= EM_FLAGS_1_EXIST_RETURN_MESSAGE;

	ret = EM_SUCCESS;
out:
	ctx->flags[1] |= EM_FLAGS_1_EXIST_RETURN_KEEPING_ITEM;

	memset(msg, 0, EM_LEN_NONCE + EM_LEN_DATE);
	memset(ctx->keep.nonce, 0, EM_LEN_NONCE);

	if (integ)
		em_free(integ);

	return ret;
}

int em_token_get_expiry_date(em_context *ctx, char *out_date)
{
	int ret;

	uint8_t token_id_esi[EM_LEN_TOKEN_ID] = {0,};
	(void)token_id_esi;

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_GET_EXPIRY_DATE, ctx, out_date, ctx->parsed_token);

#ifndef EMLITE
	if (!(ctx->flags[2] & EM_FLAGS_2_ENABLED_LSEC_TOKEN)) {
		ret = em_esi_check_meta(ctx->esi);
		if (ret != EM_SUCCESS) {
			LOGE("Invalid ESI meta\n");
			goto out;
		}

		ret = em_esi_get_item(ctx->esi, EM_TYPE_ESI_ITEM_TOKEN_ID, token_id_esi, EM_LEN_TOKEN_ID);
		if (ret != EM_SUCCESS) {
			LOGE("Failed to get token_id from esi(0x%08x)\n", ret);
			goto out;
		}

		if (memcmp((const char *)token_id_esi, (const char *)ctx->parsed_token->token.id, EM_LEN_TOKEN_ID) != 0) {
			LOGE("Not matched token id\n");
			ctx->flags[1] |= EM_FLAGS_1_EXIST_RETURN_TOKEN_REMOVE;
			ret = EM_ERR_EM_TOKEN_GET_EXPIRY_DATE_TOKEN_ID;
			goto out;
		}
	}
#endif

	memcpy(out_date, (const char *)ctx->parsed_token->validity.expiry_date, EM_LEN_DATE);
	ret = EM_SUCCESS;
out:

	return ret;
}

int em_do_init_core(em_context *ctx)
{
	int ret, i = 0;

	const uint16_t MODE_INIT_EM = 0x001F;

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_DO_INIT_CORE, ctx, ctx->parsed_token);

	ret = EM_ERR_EM_TOKEN_GET_STATUS_NOT_ALLOWED_MODE;
	for (i = 0; i < ctx->parsed_token->mode.num_of_modes; i++) {
		if (MODE_INIT_EM == ctx->parsed_token->mode.mode[i]) {
			LOGI("em init mode exists in token\n");
			ret = EM_SUCCESS;
			break;
		}
	}

	if (ret != EM_SUCCESS) {
		LOGE("em init mode doesn't exist in token\n");
		goto out;
	}

	if (ctx->is_provision) {
		memset(&ctx->core_v20, 0, sizeof(em_core_v20));
		ctx->flags[1] |= EM_FLAGS_1_WRITE_CORE;
	} else {
		LOGE("Don not need to initialize core\n");
	}

	ctx->flags[1] |= EM_FLAGS_1_DO_INIT_CORE;

	ret = EM_SUCCESS;
out:

	return ret;
}

int em_ft_token_mode(em_context *ctx)
{
	int ret, i = 0;

	uint8_t token_id_esi[EM_LEN_TOKEN_ID] = {0,};
	uint32_t offset = 0;
	(void)token_id_esi;

	EM_CHECK_NULL(__func__, EM_ERR_EM_FT_TOKEN_MODE, ctx, ctx->parsed_token);

#ifndef EMLITE
	if (!(ctx->flags[2] & EM_FLAGS_2_ENABLED_LSEC_TOKEN)) {
		ret = em_esi_check_meta(ctx->esi);
		if (ret != EM_SUCCESS) {
			LOGE("Invalid ESI meta\n");
			goto out;
		}

		ret = em_esi_get_item(ctx->esi, EM_TYPE_ESI_ITEM_TOKEN_ID, token_id_esi, EM_LEN_TOKEN_ID);
		if (ret != EM_SUCCESS) {
			LOGE("Failed to get token_id from esi(0x%08x)\n", ret);
			goto out;
		}

		if (memcmp(token_id_esi, ctx->parsed_token->token.id, EM_LEN_TOKEN_ID) != 0) {
			LOGE("Not matched token_id\n");
			ret = EM_ERR_EM_FT_TOKEN_MODE_TOKEN_ID;
			goto out;
		}
	}
#endif

	if (ctx->parsed_token->mode.num_of_modes > EM_LEN_MAX_MODE) {
		LOGE("num of modes(%u) is bigger than max(%u)\n", ctx->parsed_token->mode.num_of_modes, EM_LEN_MAX_MODE);
		ret = EM_ERR_EM_FT_TOKEN_MODE_MAX_MODE;
		goto out;
	}

	for (i = 0; i < ctx->parsed_token->mode.num_of_modes; i++) {
		if ((ctx->parsed_token->modedb.data[ctx->parsed_token->mode.mode[i]].group_index) ==
			EM_GROUP_ID_BINARY_FLASHING ||
		    (ctx->parsed_token->modedb.data[ctx->parsed_token->mode.mode[i]].group_index) ==
			EM_GROUP_ID_DEVICE_RECOVERY_FT ||
		    (ctx->parsed_token->modedb.data[ctx->parsed_token->mode.mode[i]].group_index) ==
			EM_GROUP_ID_DEVICE_MANUFACTURING_FT ||
		    (ctx->parsed_token->modedb.data[ctx->parsed_token->mode.mode[i]].group_index) == EM_GROUP_ID_DEBUGGING_FT) {
			em_add_string(
			    ctx->message, EM_LEN_MESSAGE, &offset,
			    (uint8_t *)(ctx->parsed_token->modedb.data[ctx->parsed_token->mode.mode[i]].name),
			    (uint32_t)strlen((const char *)ctx->parsed_token->modedb.data[ctx->parsed_token->mode.mode[i]].name));
			em_add_string(ctx->message, EM_LEN_MESSAGE, &offset, (uint8_t *)EM_MAGIC_GET_MODE_TOKENINZER,
				      (uint32_t)strlen(EM_MAGIC_GET_MODE_TOKENINZER));
		}
	}

	if (offset > 0) {
		ctx->len_message = offset - 1;
		ctx->message[ctx->len_message] = 0;
		ctx->flags[1] |= EM_FLAGS_1_EXIST_RETURN_MESSAGE;
	}

	ret = EM_SUCCESS;
out:

	return ret;
}

/*
 * Info format : Info version(01),
 *               Token id, Model name, Issuer id,
 *               Request date, Expiry date, Priority date,
 *               Server type (F:Fac, D:Dev), Modes info (index:tuc)
 */
int em_token_get_info(em_context *ctx)
{
	int ret, i = 0;

	tuc_table_v20 tuc_v20 = {0,};
	void *p_tuc = NULL;
	uint32_t len_tuc = 0;
	(void)tuc_v20;
	(void)p_tuc;
	(void)len_tuc;

	uint8_t token_id_esi[EM_LEN_TOKEN_ID + 1] = {0,};
	uint8_t priority_date[EM_LEN_PRIORITY_TIME + 1] = {0,};
	uint8_t str_mode[EM_LEN_STR_MODE_INDEX + 1] = {0,};
	uint8_t str_count[EM_LEN_STR_TUC_COUNT + 1] = {0,};
	(void)token_id_esi;
	(void)str_count;

	uint32_t index = 0, mode_index = 0;

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_GET_INFO, ctx, ctx->parsed_token);

#ifndef EMLITE
	if (!(ctx->flags[2] & EM_FLAGS_2_ENABLED_LSEC_TOKEN)) {
		ret = em_esi_check_meta(ctx->esi);
		if (ret != EM_SUCCESS) {
			LOGE("Invalid ESI meta\n");
			goto out;
		}

		ret = em_esi_get_item(ctx->esi, EM_TYPE_ESI_ITEM_TOKEN_ID, token_id_esi, EM_LEN_TOKEN_ID);
		if (ret != EM_SUCCESS) {
			LOGE("Failed to get token_id from esi(0x%08x)\n", ret);
			goto out;
		}

		if (memcmp(token_id_esi, ctx->parsed_token->token.id, EM_LEN_TOKEN_ID) != 0) {
			LOGE("No matched token id\n");
			ret = EM_ERR_EM_TOKEN_GET_INFO_TOKEN_ID;
			ctx->flags[1] |= EM_FLAGS_1_EXIST_RETURN_TOKEN_REMOVE;
			goto out;
		}
	}
#endif

	// Command Version
	em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)"01", 2);
	em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)",", 1);

	// Token ID
	em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)ctx->parsed_token->token.id, EM_LEN_TOKEN_ID);
	em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)",", 1);

	// Model Name
	if (strlen((const char *)ctx->parsed_token->device[0].model_name) > EM_LEN_MODEL_NAME) {
		LOGI("Invalid length of model\n");
		ret = EM_ERR_EM_TOKEN_GET_INFO_INVAILD_MODEL;
		goto out;
	}

	if (strlen((const char *)ctx->parsed_token->device[0].model_name) != 0) {
		em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)ctx->parsed_token->device[0].model_name,
			      (uint32_t)strlen((const char *)ctx->parsed_token->device[0].model_name));
	} else {
		em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)"NONE", 4);
	}
	em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)",", 1);

	// Issuer ID
	if (strlen((const char *)ctx->parsed_token->issuer.single_id) > EM_LEN_SINGLE_ID) {
		LOGI("Invalid length of issuer id\n");
		ret = EM_ERR_EM_TOKEN_GET_INFO_INVAILD_ISSUER_ID;
		goto out;
	}

	if (strlen((const char *)ctx->parsed_token->issuer.single_id) != 0) {
		em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)ctx->parsed_token->issuer.single_id,
			      (uint32_t)strlen((const char *)ctx->parsed_token->issuer.single_id));
	} else {
		em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)"UNKNOWN", 7);
	}
	em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)",", 1);

	// Req Date
	em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)ctx->parsed_token->validity.issued_date,
		      EM_LEN_DATE);
	em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)",", 1);

	// Expiry Date
	em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)ctx->parsed_token->validity.expiry_date,
		      EM_LEN_DATE);
	em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)",", 1);

#ifndef EMLITE
	// Priority Date
	ret = em_esi_get_item(ctx->esi, EM_TYPE_ESI_ITEM_PRIORITY_TIME, priority_date, EM_LEN_PRIORITY_TIME);
	if (ret == EM_SUCCESS) {
		if (memcmp(ctx->priority + EM_LEN_DATE, ctx->parsed_token->token.id, EM_LEN_TOKEN_ID) != 0)
			memcpy(priority_date, ctx->parsed_token->validity.expiry_date, EM_LEN_DATE);
	} else if ((uint32_t)ret == EM_ERR_EM_ESI_GET_ITEM_ITEM_IS_NOT_EXISTS) {
		memcpy(priority_date, ctx->parsed_token->validity.expiry_date, EM_LEN_DATE);
	} else if (ret != EM_SUCCESS) {
		LOGI("Failed to get priority_date(0x%08x)\n", ret);
		goto out;
	}
#else
	if (!(ctx->flags[0] & EM_FLAGS_0_EXIST_PRIORITY_TIME)) {
		memcpy(priority_date, ctx->parsed_token->validity.expiry_date, EM_LEN_DATE);
	} else {
		if (memcmp(ctx->priority + EM_LEN_DATE, ctx->parsed_token->token.id, EM_LEN_TOKEN_ID) == 0)
			memcpy(priority_date, ctx->priority, EM_LEN_DATE);
		else
			memcpy(priority_date, ctx->parsed_token->validity.expiry_date, EM_LEN_DATE);
	}
#endif

	em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)priority_date, EM_LEN_DATE);
	em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)",", 1);

	// Token Server Type
	ret = em_token_is_from_fac(ctx->parsed_token->integrity.cert, ctx->parsed_token->integrity.len_cert);
	if (ret != EM_SUCCESS && (uint32_t)ret != EM_ERR_EM_TOKEN_IS_FROM_FAC_FROM_FAC) {
		LOGE("Failed to check location where issued(0x%08x)\n", ret);
		goto out;
	}

	if ((uint32_t)ret == EM_ERR_EM_TOKEN_IS_FROM_FAC_FROM_FAC)
		em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)"F", 1);
	else
		em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)"D", 1);

	em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)",", 1);

	// ModeIndex:TUC
#ifdef EMLITE
	for (i = 0; i < ctx->parsed_token->mode.num_of_modes; i++) {
		mode_index = ctx->parsed_token->mode.mode[i];
		memset(str_mode, 0, strlen((const char *)str_mode));
		em_snprintf((char *)str_mode, em_get_digit_count(ctx->parsed_token->modedb.data[mode_index].index) + 1,
			    "%d", (int)ctx->parsed_token->modedb.data[mode_index].index);
		em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)str_mode,
			      (uint32_t)strlen((const char *)str_mode));
		em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)":", 1);
		em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)"99999999", 6);
		// ctx->parsed_token->modedb.data[i].attributes.mtuc_value;

		if (i + 1 != ctx->parsed_token->mode.num_of_modes)
			em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)"_", 1);
	}
#else
	p_tuc = (void *)&tuc_v20;
	len_tuc = sizeof(tuc_table_v20);

	ret = em_get_tuc_table(ctx->esi, p_tuc, len_tuc);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to get tuc table(0x%08x)\n", ret);
		goto out;
	}

	for (i = 0; i < tuc_v20.num_of_tuc; i++) {
		memset(str_mode, 0, strlen((const char *)str_mode));
		em_snprintf((char *)str_mode, em_get_digit_count(tuc_v20.tucs[i].mode_index) + 1, "%d",
			    (int)tuc_v20.tucs[i].mode_index);

		if (strlen((const char *)str_mode) > 4) {
			LOGI("Invalid length of tuc mode\n");
			ret = EM_ERR_EM_TOKEN_GET_INFO_STR_MODE;
			goto out;
		}

		em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)str_mode,
			      (uint32_t)strlen((const char *)str_mode));
		em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)":", 1);

		if (tuc_v20.tucs[i].flags & (EM_TYPE_TUC_IS_ENABLE | EM_TYPE_TUC_ONLY_ONCE)) {
			memset(str_count, 0, strlen((const char *)str_count));
			em_snprintf((char *)str_count, em_get_digit_count(tuc_v20.tucs[i].count) + 1, "%d",
				    (int)tuc_v20.tucs[i].count);
			if (strlen((const char *)str_count) > 4) {
				LOGI("Invalid length of tuc count\n");
				ret = EM_ERR_EM_TOKEN_GET_INFO_STR_COUNT;
				goto out;
			}
			em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)str_count,
				      (uint32_t)strlen((const char *)str_count));
		} else {
			em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)"99999999", 6);
		}

		if (i + 1 != tuc_v20.num_of_tuc)
			em_add_string(ctx->message, EM_LEN_MESSAGE, &index, (uint8_t *)"_", 1);
	}
#endif

	ctx->len_message = index;
	ctx->flags[1] |= EM_FLAGS_1_EXIST_RETURN_MESSAGE;

	ret = EM_SUCCESS;
out:
	LOGI("message size : (%d)\n", ctx->len_message);

	return ret;
}

int em_token_check_lsec_tok_cond(em_context *ctx)
{
	int ret;

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_CHK_LSEC_TOK, ctx, ctx->parsed_token);

	if (ctx->parsed_token->token.lsec_tok == EM_TYPE_TOKE_LSEC_TOK_ENABLED) {
		LOGI("token type is lsec!");
		ret = EM_SUCCESS;
		goto out;
	}

	ret = EM_ERR_EM_TOKEN_CHK_LSEC_TOK_NO_FEATURE;
out:

	return ret;
}

int em_token_get_token_id(em_context *ctx)
{
	int ret;

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_GET_TOKEN_ID, ctx, ctx->parsed_token);

	memcpy(ctx->token_id, ctx->parsed_token->token.id, EM_LEN_TOKEN_ID);
	ret = EM_SUCCESS;
out:
	return ret;
}

int em_token_set_priority_time(em_context *ctx)
{
	int ret;
	int i = 0;
	char priority_time[EM_LEN_PRIORITY_TIME + 1] = {0,};
	char token_expiry_date[EM_LEN_DATE + 1] = {0,};
	uint8_t current_count = 1;
	char current_count_string[EM_LEN_TOKEN_MODE_STRING] = {0,};
	char *date = (char *)em_calloc(sizeof(char), EM_LEN_DATE + 1);
	uint32_t len_message_local_var;	//for exynos bootloader

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_SET_PRIORITY_TIME, ctx, date);

	if (ctx->flags[2] & EM_FLAGS_2_TOKEN_VERIFICATION_FAILED) {
		LOGI("Pass setting priority time, because token isn't normal\n");
		ret = EM_ERR_EM_TOKEN_SET_PRIORITY_TIME_MAKE_NOTOKEN;
		goto make_message;
	}

	memcpy(date, ctx->message + strlen(EM_MAGIC_ESS_PREFIX_HEADER_SET_PRIORITY), EM_LEN_DATE);
	if (em_is_all_zero((unsigned char *)date, EM_LEN_DATE) == EM_SUCCESS) {
		LOGE("Failed to set priority time, server_date is all zero\n");
		ret = EM_ERR_EM_TOKEN_SET_PRIORITY_TIME_DATE;
		goto make_message;
	}

	for (i = 0; i < EM_LEN_DATE; i++) {
		if ('0' > date[i] || date[i] > '9') {
			LOGE("date isn't normal(%s)\n", date);
			ret = EM_ERR_EM_TOKEN_SET_PRIORITY_TIME_DATE_FORMAT;
			goto make_message;
		}
	}

	ret = em_token_get_expiry_date(ctx, token_expiry_date);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to get expiry date(0x%08x)\n", ret);
		goto make_message;
	}

	if (memcmp(token_expiry_date, date, EM_LEN_DATE) < 0) {
		LOGE("over date(%s/%s)\n", token_expiry_date, date);
		ret = EM_ERR_EM_TOKEN_SET_PRIORITY_TIME_BEYOND;
		goto make_message;
	}

#ifdef EMLITE
	ret = em_token_get_token_id(ctx);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to get token id(0x%08x)\n", ret);
		goto make_message;
	}

	if (!(ctx->flags[0] & EM_FLAGS_0_EXIST_PRIORITY_TIME)) {
		LOGI("There is no priority time in payload\n");
		ret = EM_ERR_EM_TOKEN_SET_PRIORITY_TIME_NO_PRIORITY_TIME;
		goto make_message;
	}

	if (em_is_all_zero(ctx->priority, EM_LEN_PRIORITY_TIME) == EM_SUCCESS) {
		LOGI("Not exists priority time");
	} // continue
#else
	ret = em_esi_get_item(ctx->esi, EM_TYPE_ESI_ITEM_TOKEN_ID, ctx->token_id, EM_LEN_TOKEN_ID);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to get token id(0x%08x)\n", ret);
		goto make_message;
	}

	ret = em_esi_get_item(ctx->esi, EM_TYPE_ESI_ITEM_PRIORITY_TIME, ctx->priority, EM_LEN_PRIORITY_TIME);
	if (ret != EM_SUCCESS) {
		if ((uint32_t)ret != EM_ERR_EM_ESI_GET_ITEM_ITEM_IS_NOT_EXISTS) {
			LOGE("Failed to get priority_time(0x%08x)\n", ret);
			goto make_message;
		}
		LOGI("Not exists priority time\n");
	} // continue
#endif
	else {
		if (memcmp(ctx->token_id, ctx->priority + EM_LEN_DATE, EM_LEN_TOKEN_ID) == 0) {
			LOGI("Matched TID\n");
			if ((uint8_t)ctx->priority[EM_LEN_PRIORITY_TIME - 1] >= EM_LEN_PRIORITY_TIME_COUNT) {
				LOGE("Failed to set priority_time, Excceed count(%d)!\n",
				     ctx->priority[EM_LEN_PRIORITY_TIME - 1]);
				ret = EM_ERR_EM_TOKEN_SET_PRIORITY_TIME_SET_COUNT;
				goto make_message;
			}
			current_count = ((ctx->priority[EM_LEN_PRIORITY_TIME - 1]) + 1);
		}
	}

	memcpy(priority_time, date, EM_LEN_DATE);
	memcpy(priority_time + EM_LEN_DATE, ctx->token_id, EM_LEN_TOKEN_ID);
	memcpy(priority_time + EM_LEN_DATE + EM_LEN_TOKEN_ID, &current_count, sizeof(uint8_t));

#ifdef EMLITE
	memcpy(ctx->priority, priority_time, EM_LEN_PRIORITY_TIME);
	ctx->flags[1] |= EM_FLAGS_1_EXIST_RETURN_PRIORITY_TIME;
#else
	ret = em_esi_update_item(ctx->em_version, ctx->esi, EM_TYPE_ESI_ITEM_PRIORITY_TIME, (uint8_t *)priority_time,
				 ctx->key, EM_LEN_KEY_CORE_V20);
	if (ret != EM_SUCCESS) {
		LOGE("%s : Failed to add update item(%08x)\n", __func__, ret);
		goto make_message;
	}

	ctx->flags[1] |= EM_FLAGS_1_EXIST_RETURN_ESI;
#endif
	ret = EM_SUCCESS;

make_message:
	ctx->len_message = 0;
	len_message_local_var = ctx->len_message;
	em_ess_update_req_msg(ctx->message, &len_message_local_var, (uint8_t *)EM_MAGIC_ESS_PREFIX_RETURN_COMMAND,
			      strlen(EM_MAGIC_ESS_PREFIX_RETURN_COMMAND), NULL, EM_LEN_MESSAGE,
			      strlen(EM_MAGIC_ESS_PREFIX_RETURN_COMMAND));
	em_ess_update_req_msg(ctx->message, &len_message_local_var, ctx->ess_command_type, 1,
			      (uint8_t *)EM_MAGIC_ESS_AT_COMMAND_DELIM, EM_LEN_MESSAGE, 1);
	if (ret != EM_SUCCESS)
		em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
			      (uint8_t *)EM_MAGIC_PRIORITY_NOK, (uint32_t)strlen(EM_MAGIC_PRIORITY_NOK));
	else
		em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
			      (uint8_t *)EM_MAGIC_PRIORITY_OK, (uint32_t)strlen(EM_MAGIC_PRIORITY_OK));

	em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
		      (uint8_t *)EM_MAGIC_PRIORITY_SEPARATOR, (uint32_t)strlen(EM_MAGIC_PRIORITY_SEPARATOR));

	if (ctx->flags[1] & EM_FLAGS_1_EXIST_RETURN_TOKEN_REMOVE ||
		ctx->flags[2] & EM_FLAGS_2_TOKEN_MAGIC_IS_UNKNOWN) {
		em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
			      (uint8_t *)EM_MAGIC_PRIORITY_NO_TOKEN, (uint32_t)strlen(EM_MAGIC_PRIORITY_NO_TOKEN));
		ctx->len_message = len_message_local_var;
		ret = EM_SUCCESS;
		goto out;
	}

	if (ret == EM_SUCCESS) {
		em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
			      (uint8_t *)date, (uint32_t)EM_LEN_DATE);
		em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
			      (uint8_t *)EM_MAGIC_PRIORITY_SEPARATOR, (uint32_t)strlen(EM_MAGIC_PRIORITY_SEPARATOR));
		em_itoa_for_mode(current_count, current_count_string);
		em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
			      (uint8_t *)current_count_string, (uint32_t)strlen(current_count_string));
	} else if ((uint32_t)ret == EM_ERR_EM_TOKEN_SET_PRIORITY_TIME_SET_COUNT) {
		em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
			      (uint8_t *)EM_MAGIC_PRIORITY_EXCEEDED_PR_COUNT,
			      (uint32_t)strlen(EM_MAGIC_PRIORITY_EXCEEDED_PR_COUNT));
	} else if ((uint32_t)ret == EM_ERR_EM_TOKEN_SET_PRIORITY_TIME_BEYOND) {
		em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
			      (uint8_t *)EM_MAGIC_PRIORITY_BEYOND_GENERAL,
			      (uint32_t)strlen(EM_MAGIC_PRIORITY_BEYOND_GENERAL));
		em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
			      (uint8_t *)EM_MAGIC_PRIORITY_SEPARATOR, (uint32_t)strlen(EM_MAGIC_PRIORITY_SEPARATOR));
		em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
			      (uint8_t *)token_expiry_date, (uint32_t)EM_LEN_DATE);
	} else {
		em_ess_update_req_msg(ctx->message, &len_message_local_var, (uint8_t *)EM_MAGIC_ESS_AT_COMMAND_ERROR,
				      strlen(EM_MAGIC_ESS_AT_COMMAND_ERROR), (uint8_t *)EM_MAGIC_ESS_AT_COMMAND_DELIM,
				      EM_LEN_MESSAGE, strlen(EM_MAGIC_ESS_AT_COMMAND_ERROR));
		em_snprintf((char *)(ctx->message + len_message_local_var), 8 + 1, "%08X", ret);
		len_message_local_var += 8;
		LOGE("Some process is wrong(0x%08x)\n", ret);
	}

	ctx->len_message = len_message_local_var;
	ret = EM_SUCCESS;
out:
	if (date)
		em_free(date);

	LOGI("%s : result %d(%s)\n", __func__, ret, ctx->message);
	return ret;
}

int em_token_get_priority_time(em_context *ctx)
{
	int ret;

	int flag = 0;
	char token_expiry_date[EM_LEN_DATE + 1] = {0,};
	char real_expiry_date[EM_LEN_DATE + 1] = {0,};
	uint8_t current_count = 0;
	char current_count_string[EM_LEN_TOKEN_MODE_STRING] = {0,};
	uint32_t len_message_local_var;	//for exynos bootloader

	EM_CHECK_NULL(__func__, EM_ERR_EM_TOKEN_GET_PRIORITY_TIME, ctx);

	if (ctx->flags[2] & EM_FLAGS_2_TOKEN_VERIFICATION_FAILED) {
		LOGI("Pass getting priority time, because token isn't normal\n");
		ret = EM_ERR_EM_TOKEN_GET_PRIORITY_TIME_MAKE_NOTOKEN;
		goto make_message;
	}

	ret = em_token_get_expiry_date(ctx, token_expiry_date);
	if (ret != EM_SUCCESS) {
		LOGE("Failed to get expiry date(0x%08x)\n", ret);
		goto make_message;
	}

	memcpy(real_expiry_date, token_expiry_date, EM_LEN_DATE);

#ifdef EMLITE
	ret = em_token_get_token_id(ctx);
	if (ret != EM_SUCCESS) {
		if ((uint32_t)ret != EM_ERR_EM_TOKEN_PARSE_HEDAER_MAGIC) {
			LOGI("Failed to get token id(0x%08x)\n", ret);
			goto make_message;
		}
		LOGI("Not exists priority time\n");
		ret = EM_SUCCESS;
		goto make_message;
	}

	if (!(ctx->flags[0] & EM_FLAGS_0_EXIST_PRIORITY_TIME)) {
		LOGI("There is no priority time in payload\n");
		ret = EM_SUCCESS;
		goto make_message;
	}

	if (em_is_all_zero(ctx->priority, EM_LEN_PRIORITY_TIME) == EM_SUCCESS) {
		LOGI("priority time not set");
		ret = EM_SUCCESS;
		goto make_message;
	}
#else
	ret = em_esi_get_item(ctx->esi, EM_TYPE_ESI_ITEM_PRIORITY_TIME, ctx->priority, EM_LEN_PRIORITY_TIME);
	if (ret != EM_SUCCESS) {
		if ((uint32_t)ret != EM_ERR_EM_ESI_GET_ITEM_ITEM_IS_NOT_EXISTS) {
			LOGE("Failed to get priority_time(0x%08x)\n", ret);
			goto make_message;
		}
		LOGI("Not exists priority time\n");
		ret = EM_SUCCESS;
		goto make_message;
	}

	ret = em_esi_get_item(ctx->esi, EM_TYPE_ESI_ITEM_TOKEN_ID, ctx->token_id, EM_LEN_TOKEN);
	if (ret != EM_SUCCESS) {
		if ((uint32_t)ret != EM_ERR_EM_ESI_GET_ITEM_ITEM_IS_NOT_EXISTS) {
			LOGE("Failed to get token id(0x%08x)\n", ret);
			goto make_message;
		}
	}
#endif

	if (memcmp(ctx->priority + EM_LEN_DATE, ctx->token_id, EM_LEN_TOKEN_ID) == 0) {
		if (memcmp(token_expiry_date, ctx->priority, EM_LEN_DATE) > 0)
			memcpy(real_expiry_date, ctx->priority, EM_LEN_DATE);

		current_count = ((ctx->priority[EM_LEN_PRIORITY_TIME - 1]));
		flag |= EM_PRIORITY_FLAG_MATCHED_TID;
	} else {
		LOGE("Not Matched token id\n");
		print_msg_hex((char *)"token_id", ctx->token_id, EM_LEN_TOKEN_ID);
		print_msg_hex((char *)"esi_token_id", (uint8_t *)(ctx->priority + EM_LEN_DATE), EM_LEN_TOKEN_ID);
	}

	ret = EM_SUCCESS;

make_message:
	ctx->len_message = 0;
	len_message_local_var = ctx->len_message;
	em_ess_update_req_msg(ctx->message, &len_message_local_var, (uint8_t *)EM_MAGIC_ESS_PREFIX_RETURN_COMMAND,
			      strlen(EM_MAGIC_ESS_PREFIX_RETURN_COMMAND), NULL, EM_LEN_MESSAGE,
			      strlen(EM_MAGIC_ESS_PREFIX_RETURN_COMMAND));
	em_ess_update_req_msg(ctx->message, &len_message_local_var, ctx->ess_command_type, 1,
			      (uint8_t *)EM_MAGIC_ESS_AT_COMMAND_DELIM, EM_LEN_MESSAGE, 1);

	if (ret == EM_SUCCESS) {
		em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
			      (uint8_t *)EM_MAGIC_PRIORITY_OK, (uint32_t)strlen(EM_MAGIC_PRIORITY_OK));
		em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
			      (uint8_t *)EM_MAGIC_PRIORITY_SEPARATOR, (uint32_t)strlen(EM_MAGIC_PRIORITY_SEPARATOR));

		em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
			      (uint8_t *)real_expiry_date, (uint32_t)EM_LEN_DATE);
		em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
			      (uint8_t *)EM_MAGIC_PRIORITY_SEPARATOR, (uint32_t)strlen(EM_MAGIC_PRIORITY_SEPARATOR));

		em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
			      (uint8_t *)token_expiry_date, (uint32_t)EM_LEN_DATE);
		em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
			      (uint8_t *)EM_MAGIC_PRIORITY_SEPARATOR, (uint32_t)strlen(EM_MAGIC_PRIORITY_SEPARATOR));

		if (flag & EM_PRIORITY_FLAG_MATCHED_TID)
			em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
				      ctx->priority, (uint32_t)EM_LEN_DATE);
		else
			em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
				      (uint8_t *)EM_MAGIC_PRIORITY_NONE, (uint32_t)strlen(EM_MAGIC_PRIORITY_NONE));

		em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
			      (uint8_t *)EM_MAGIC_PRIORITY_SEPARATOR, (uint32_t)strlen(EM_MAGIC_PRIORITY_SEPARATOR));

		em_itoa_for_mode(current_count, current_count_string);
		em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
			      (uint8_t *)current_count_string, (uint32_t)strlen(current_count_string));
	} else {
		if (ctx->flags[1] & EM_FLAGS_1_EXIST_RETURN_TOKEN_REMOVE ||
			ctx->flags[2] & EM_FLAGS_2_TOKEN_MAGIC_IS_UNKNOWN) {
			em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
				      (uint8_t *)EM_MAGIC_PRIORITY_NOK, (uint32_t)strlen(EM_MAGIC_PRIORITY_NOK));

			em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
				      (uint8_t *)EM_MAGIC_PRIORITY_SEPARATOR,
				      (uint32_t)strlen(EM_MAGIC_PRIORITY_SEPARATOR));

			em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
				      (uint8_t *)EM_MAGIC_PRIORITY_NO_TOKEN,
				      (uint32_t)strlen(EM_MAGIC_PRIORITY_NO_TOKEN));
		} else {
			em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
				      (uint8_t *)EM_MAGIC_PRIORITY_NOK, (uint32_t)strlen(EM_MAGIC_PRIORITY_NOK));

			em_add_string((uint8_t *)ctx->message, EM_LEN_MESSAGE, (uint32_t *)&len_message_local_var,
				      (uint8_t *)EM_MAGIC_PRIORITY_SEPARATOR,
				      (uint32_t)strlen(EM_MAGIC_PRIORITY_SEPARATOR));

			em_ess_update_req_msg(
			    ctx->message, &len_message_local_var, (uint8_t *)EM_MAGIC_ESS_AT_COMMAND_ERROR,
			    strlen(EM_MAGIC_ESS_AT_COMMAND_ERROR), (uint8_t *)EM_MAGIC_ESS_AT_COMMAND_DELIM,
			    EM_LEN_MESSAGE, strlen(EM_MAGIC_ESS_AT_COMMAND_ERROR));
			em_snprintf((char *)(ctx->message + len_message_local_var), 8 + 1, "%08X", ret);
			len_message_local_var += 8;
			LOGE("Some process is wrong(0x%08x)\n", ret);
		}
	}

	ctx->len_message = len_message_local_var;
	ret = EM_SUCCESS;
out:
	LOGI("result %s\n", ctx->message);
	return ret;
}
