/*
 *
 * (c) Copyright 2018 Samsung Research America, Inc.
 *                  All rights reserved
 *
 *                  MCL-B2B Lab
 *
 *
 * File: utils.h
 * Author: r.kadir@samsung.com
 * Creation Date: Nov, 2018
 *
 */
/**
* Copyright (C) 2018 Samsung Electronics Co., Ltd. All rights reserved.
*
* Mobile Platform & Solutions Lab (MPS Lab),
* Samsung Electronics Co., Ltd.
*
* This software and its documentation are confidential and proprietary
* information of Samsung Electronics Co., Ltd.  No part of the software and
* documents may be copied, reproduced, transmitted, translated, or reduced to
* any electronic medium or machine-readable form without the prior written
* consent of Samsung Electronics.
*
* Samsung Electronics makes no representations with respect to the contents,
* and assumes no responsibility for any errors that might appear in the
* software and documents. This publication and the contents hereof are subject
* to change without notice.
*/

#ifndef UTILS_H_
#define UTILS_H_

#include "DDAR_TZ_Vendor_tl.h"
#include "dualdar_api.h"
#include "dualdar_crypto_tl.h"
#include "dualdar_globals.h"

#define ERR_MSG_AVAILABLE_BUFFER()		((gDualDarData.err_msg_buf_index < &gDualDarData.err_msg_buf[DUALDAR_MAX_ERROR_STR_LEN]) ? \
										(&gDualDarData.err_msg_buf[DUALDAR_MAX_ERROR_STR_LEN] - (gDualDarData.err_msg_buf_index)) : 0)

#define DUALDAR_ERROR(...)  			do {	\
		snprintf(ddar_log_msg, LOG_MSG_SIZE - 1, "DUALDAR ERROR - " __VA_ARGS__);	\
		ddar_log_msg[LOG_MSG_SIZE - 1] = '\0';	\
		DUALDAR_TA_LOG(ddar_log_msg);	\
	} while(0);
	// [SI-21921] [AFL x Fingerprint TA] Out-of-bounds Write in DUALDAR_ERROR
	// C:There are Out-of-bounds Write vulnerability in DUALDAR_ERROR macro.
	// err_msg_buf_index is a pointer and memory has not allocated. Out-of-bounds Write can happen.
	// M:err_msg_buf_index is not used. Using 'ddar_log_msg' instead of
// do { \
// 	DUALDAR_LOG(__VA_ARGS__);	\
// 	if (ERR_MSG_AVAILABLE_BUFFER()) { \
// 		snprintf(gDualDarData.err_msg_buf_index, ERR_MSG_AVAILABLE_BUFFER(), "|" __VA_ARGS__);	\
// 		gDualDarData.err_msg_buf[DUALDAR_MAX_ERROR_STR_LEN - 1] = '\0';	\
// 		gDualDarData.err_msg_buf_index = gDualDarData.err_msg_buf + strlen(gDualDarData.err_msg_buf); \
// 	} \
// } while(0);

#define DUALDAR_REL(...)			DUALDAR_LOG(__VA_ARGS__)

#define CHECK_RETURN(retval) \
	if (retval !=0) { \
		DUALDAR_ERROR("Function %s Line %d- Check Return Value failed", __FUNCTION__, __LINE__); \
		return retval; \
	}

#define LOG_CMD(cmd_len, cmd_struct, rsp_len, rsp_struct)				\
		 DUALDAR_LOG("cmd_len : %d, cmd_struct_len : %d", cmd_len, sizeof(cmd_struct)); \
		 DUALDAR_LOG("rsp_len : %d, rsp_struct_len : %d", rsp_len, sizeof(rsp_struct));

#define IS_VALID_BUFFER(cmd_len, cmd_struct, rsp_len, rsp_struct)				\
		((cmd_len) >= sizeof(cmd_struct) && (rsp_len) >= sizeof(rsp_struct))

/* Note :
 * Caller has to makesure the len is not reaching max of uint32_t
 * This routine shall not verify that.
 */
#define VALIDATE_BUF_LEN(len, maxlen) \
	if (len>maxlen) {	\
		DUALDAR_ERROR("Error length validation failed : " #len"= %d > " #maxlen " = %d", len, maxlen);	\
		return DUALDAR_INVALID_INPUT_PARAM;	\
	}

#define VALIDATE_BUFFER(buf, buf_len, max_buf_len)    \
    if (!buf) { \
        DUALDAR_ERROR("Invalid buf - " #buf); \
        return DUALDAR_INVALID_INPUT_PARAM;	\
    } \
    VALIDATE_BUF_LEN(buf_len, max_buf_len)

#define VALIDATE_BLOB_LEN(blob, maxlen) VALIDATE_BUF_LEN(blob.len, maxlen)

#define VALIDATE_CERT_CHAIN(certchain) \
	if(validate_cert_chain(certchain.numCerts, certchain.certs)!=DUALDAR_OK) { \
		DUALDAR_ERROR("Error validate_cert_chain failed : ");	\
		return DUALDAR_INVALID_INPUT_PARAM;	\
	}

#define BYTE1(val) ((uint8_t)(val>>8))
#define BYTE2(val) ((uint8_t)(val&0x00ff))

#define STRLEN(s) strlen((const char*)s)

#define SAFEMEMCPY(dst, src, srclen, maxdstlen) \
	VALIDATE_BUF_LEN((srclen), (maxdstlen)); \
	memcpy((dst), (src), (srclen));

#define SAFETOHEXSTRING(src, srclen, dst, maxdstlen, upper) \
	VALIDATE_BUF_LEN((srclen*2), (maxdstlen)); \
	tohexstring((src), (srclen), (dst), upper);

#define SAFEFROMHEXSTRING(src, srclen, dst, dstlen) \
	VALIDATE_BUF_LEN((srclen)/2, *(dstlen)); \
	tobytes((src), (srclen), (dst)); \
	*(dstlen) = (srclen)/2; \

#define SAFEFROMB64STRING(src, srclen, dst, dstlen) { \
	  if(base64_decode(src, srclen, dst, dstlen) != DUALDAR_OK) { \
		DUALDAR_ERROR("Error base64_decode failed : ");	\
		return DUALDAR_INVALID_INPUT_PARAM;	\
	  } \
   }

#define SAFETOB64STRING(src, srclen, dst, dstlen) { \
	  if(base64_encode(src, srclen, dst, dstlen) != DUALDAR_OK) { \
		DUALDAR_ERROR("Error base64_encode failed : ");	\
		return DUALDAR_INVALID_INPUT_PARAM;	\
	  } \
   }

#define HEXLEN(l) (l*2)

#define SETBIT(byte, pos)	byte |= (1 << pos)
#define CLEARBIT(byte, pos) byte &= ~(1 << pos)

#define DO_CHK_IF(a, b) \
		if(((a) + (b) < (a)) || ((a) + (b) < (b))) {  \
			DUALDAR_ERROR("%s - Check Return Value failed", __FUNCTION__); \
			return DUALDAR_INVALID_INPUT_PARAM; \
		}


//////////////////////////////////////////
// Hex Utils
//////////////////////////////////////////
void tobytes(
	uint8_t * hexstr,
	uint32_t hexstrlen,
	uint8_t * bytes
);
void tohexstring(
	uint8_t * bytes,
	int32_t byteslen,
	uint8_t * hexstring,
	uint8_t isUpper
);
//////////////////////////////////////////

///////////////////////////////////////////////
// Integer To ByteArray Utils
///////////////////////////////////////////////
void convertUInt16ToBytes(
	uint16_t i,
	uint8_t * bytes
);
void convertUInt32ToBytes(
	uint32_t i,
	uint8_t * bytes
);
uint32_t convertBytes2UInt32(
	uint8_t * bytes,
	int32_t numbytes
);

int32_t convertIntToVarBytes(
	uint32_t tlvlen,
	uint8_t * firstbyte,
	uint8_t * nextbytes
);

uint32_t convertStringToInteger(
	uint8_t * s
);
//////////////////////////////////////////

#define BUILDBUF(data, datalen, buf, offset, maxjsonbuflen) \
	if (datalen) {\
		retval = add_data_to_buf((uint8_t *)data, (uint32_t)datalen, (uint8_t *)buf, (uint32_t)maxjsonbuflen, (uint32_t *)offset); \
		CHECK_RETURN(retval); \
	}

uint32_t add_data_to_buf(
	uint8_t * data,
	uint32_t datalen,
	uint8_t * buf,
	uint32_t maxbuflen,
	uint32_t * offset
);

/////////////////////
// Dump Utilities
/////////////////////

#define	LOG_ENTRY_SIZE	128
#define	LOG_MSG_SIZE	(LOG_ENTRY_SIZE - sizeof(uint32_t) - sizeof(uint32_t))
extern char ddar_log_msg[LOG_MSG_SIZE];
extern void dbg_dump(char * label, uint8_t * data, uint32_t data_len);

#ifdef ENABLE_DDAR_LOG

#ifdef CONFIG_QSEE
#include <qsee_log.h>
#define DUALDAR_TA_LOG(...)   qsee_log(QSEE_LOG_MSG_ERROR, ## __VA_ARGS__)
#else
#define DUALDAR_TA_LOG(fmt, ...)   printf(fmt, ##__VA_ARGS__);printf("\n")
#endif /* USE_TEEGRIS */

#define DUALDAR_LOG(...)	do {	\
		snprintf(ddar_log_msg, LOG_MSG_SIZE - 1, "DUALDAR - " __VA_ARGS__);	\
		ddar_log_msg[LOG_MSG_SIZE - 1] = '\0';	\
		DUALDAR_TA_LOG(ddar_log_msg);	\
	} while(0);

#else
#define DUALDAR_LOG(...)
#endif

#ifdef ENABLE_DDAR_DEBUG_LOG
#define SPECIALDUMP(label, buf, len)	DUALDAR_LOG("Dump called for %s with ptr = %p and len = %d: ", label, buf, len);	//dbg_dump("specialdump", buf, len)
#define SPECIALDUMPBLOB(blob)			SPECIALDUMP(#blob, blob.buf, blob.len)
#define DUMP(label, buf, len)			DUALDAR_LOG("Dump called for %s with ptr = %p and len = %d: ", label, buf, len);	// dbg_dump(label, buf, len)
#define DUMPSTRING(label, buf, buflen)	print_str((uint8_t*)label, (uint8_t*)buf, (uint32_t)buflen)
#define DUMPINT(i)						DUALDAR_LOG("Dump called for %s value = %d: ", #i, i);
#define DUMPBLOB(blob)					DUMP(#blob, blob.buf, blob.len)
#define DUMPBLOBASSTRING(blob)			DUMPSTRING(#blob, blob.buf, blob.len)
#define LOG_CERT(cert)

#define LOGSTARTTIME()
#define LOGTIMETAKEN()
/*
#define LOGSTARTTIME() \
		uint64_t starttimestamp = 0; \
		TZ_get_secure_timestamp(&starttimestamp);

#define LOGTIMETAKEN() \
{ \
    uint64_t endtimestamp = 0; \
    if (DDAR_TZ_API_OK == TZ_get_secure_timestamp(&endtimestamp)) { \
		DUALDAR_LOG("Time Taken (%d milliseconds)", (endtimestamp - starttimestamp) / (1000)); \
    } \
}
*/

#else
#define SPECIALDUMP(label, buf, len)
#define SPECIALDUMPBLOB(blob)
#define DUMP(label, buf, len)
#define DUMPSTRING(label, buf, buflen)
#define DUMPINT(i)
#define DUMPBLOB(blob)
#define DUMPBLOBASSTRING(blob)
#define LOG_CERT(cert)

#define LOGSTARTTIME()
#define LOGTIMETAKEN()
#endif

#define FILLBLOB(blob, bloblen) FILLBLOBWITHVAL(blob, bloblen, 0x20)
#define FILLBLOBWITHVAL(blob, bloblen, val) fill_output_buf((uint8_t*)blob.buf, bloblen, val);blob.len = bloblen;
#define FILLBUFWITHVAL(buf, buflen, maxbuflen, val) fill_output_buf((uint8_t*)buf, maxbuflen, val);*buflen = maxbuflen;

void print_buf(
	uint8_t * label,
	uint8_t * buf,
	uint32_t buf_len
);

void print_str(
	uint8_t * label,
	uint8_t * buf,
	uint32_t buflen
);

void print_int(
	uint8_t * label,
	uint32_t i
);


void fill_output_buf(
	uint8_t * buf,
	uint32_t buf_len,
	uint32_t val
);



/* large number multiplication */
uint32_t dualdar_bn_mul(
	uint8_t * x,
	int x_len,
	uint8_t * y,
	int y_len,
	uint8_t * z,
	int z_len
);

void set_error_string(
	uint32_t errcode,
	uint8_t * destbuf
);

char *
_strncpy(char *dst, const char *src, size_t n);

#endif /* UTILS_H_ */
