/**
 * \file TLV.h
 * \brief Helper for creating TLV structures.
 * \author Roman Pasechnik (r.pasechnik@samsung.com)
 * \version 0.1
 * \date Created Dec 23, 2013
 * \par In Samsung Ukraine R&D Center (SURC) under a contract between
 * \par LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine) and
 * \par "Samsung Elecrtronics Co", Ltd (Seoul, Republic of Korea)
 * \par Copyright: (c) Samsung Electronics Co, Ltd 2012. All rights reserved.
 */

#ifndef __TLV_H__
#define __TLV_H__

#include <stddef.h>
#include <stdint.h>

// TLV Size.
#define TAG_FIELD_SIZE     0x01
#define LENGTH_FIELD_SIZE  0x02
#define TAGLENGTH_FIELD_SIZE (TAG_FIELD_SIZE + LENGTH_FIELD_SIZE)

/* TLV data types */
typedef enum
{
	TLV_EXPONENT = 1,
	TLV_ISSUER,
	TLV_HASH_ALGO,
	TLV_SUBJECT,
	TLV_KEYUSAGE,
	TLV_DN_QUALIFIER,
	TLV_EXT_KEYUSAGE,
	TLV_SIGN_DATA_BLOB,
	TLV_CERT_SM,
	TLV_CERT_SD,
	TLV_TIMESTAMP,
	TLV_WRAPPED_PCR,
	TLV_EXTEND_PCR_DATA,
	TLV_TID,
	TLV_WRAPPED_KEY,
	TLV_KEY_INFO,
	TLV_ATTRS,
	TLV_MODEL_NAME,
	TLV_HUID,
	TLV_PREGEN_KEYPAIR,
	TLV_CSR,
	TLV_IV,
	TLV_AUTH_TAG,
	TLV_AUTH_DATA,
	TLV_SIGNATURE,
	TLV_ENCRYPTED_DATA_BLOB,
	TLV_CERT,
	TLV_IMEI,
	TLV_SUBJECT_ALTER_NAME,
	TLV_RFNAME,
	TLV_WFNAME,
	TLV_RFDATA,
	TLV_WFDATA,
	TLV_RFSIZE,
	TLV_DI_STATUS = 101,
	TLV_DI_MODEM  = 102,
	TLV_DI_IMEI   = 104,
	TLV_DI_CID    = 108,
	TLV_DI_MODEL  = 116,
	TLV_DI_UID    = 132,
	TLV_DI_SPU    = 164,
	TLV_MAX,
	/* Identifier of the start of a TLV buffer */
	TLV_START_EX = 0xfd,
	TLV_START    = 0xfe
} TlvTag_t;

typedef struct
{
	uint8_t tag;
	uint16_t dataLen;
	uint8_t data[];
} __attribute__((packed)) Tlv_t;

/** tlvInit
 *
 * Initialize TLV buffer. Must be called before tlvAdd()
 *
 * tlv: buffer to initialize
 * tlvLen: size of allocated tlv buffer
 *
 * return: NOT_ERROR on success or error otherwise
 */
int tlvInit(uint8_t *tlv, size_t tlvLen);

/** tlvAdd
 *
 * Add new attribute to TLV buffer
 *
 * tlv: initialized tlv buffer
 * tlvLen: size of allocated tlv buffer (maximum size)
 * tag: identifier of attribute
 * value: pointer to value of the attribute. Representation depends on
 *        particular attribute
 * valueLen: size of value buffer
 *
 * return: NOT_ERROR on success or error otherwise
 */
int tlvAdd(uint8_t *tlvBuffer, size_t tlvBufferLen, TlvTag_t tag,
           const void *value, uint16_t valueLen);

/** tlvSize
 *
 * Return actual size of TLV buffer. This size should be passed to
 * generateServiceKeyEx.
 *
 * tlv: buffer initialized by tlvInit and constructed by tlvAdd
 * tlvLen: size of allocated tlv buffer (maximum size)
 *
 * return: actual size of TLV buffer on success or negative error code
 *         otherwise
 */
int tlvSize(const uint8_t *tlvBuffer, size_t tlvBufferLen);

/** tlvGet
 *
 * Get (tag, length, value) in tlv buffer of custom tlv element
 * specified by tlvNo
 *
 * tlv: buffer initialized by tlvInit and constructed by tlvAdd
 * tlvLen: size of allocated tlv buffer
 * tlvTag: desired tag to get
 * tag: pointer to tag, which will be fetched
 * length: pointer to length, which will be fetched
 * value: pointer to value, which will be fetched
 *
 * return: NOT_ERROR on success or negative error code
 */
int tlvGet(const uint8_t *tlvBuffer, size_t tlvBufferLen, TlvTag_t tag,
           uint16_t* length, uint8_t** value);
#endif
