/*
 * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
 *
 * Created in Samsung Ukraine R&D Center (SRK) under a contract between
 * LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine)
 * and "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
 *
 *  Created on: Mar 17, 2016
 *  Author: Oleksandr Usatov <o.usatov@samsung.com>
 *  Brief: Trustlet command interface.
 */

#ifndef TIGER_TCI_H
#define TIGER_TCI_H

#include "TigerWsbuff.h"

#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>
#include <stddef.h>

#define TIGER_TA_SM_SIZE            (sizeof(qsc_send_cmd_req_t) + sizeof(qsc_send_cmd_rsp_t))

#define TIGER_HEAP_SIZE             (4096*8)
#define TIGER_STACK_SIZE            (4096*4)

/**
 * @brief Function to get bytes from bits
 */
#define BITS_TO_BYTES(BITS)         (uint32_t) ((BITS + 7) >> 3)

/**
 * @brief Function to get bits from bytes
 */
#define BYTES_TO_BITS(BYTES)        (uint32_t) (BYTES * 8)

#define MAX_KEY_SIZE_BITS           (4096)
#define MAX_KEY_SIZE_BYTES          BITS_TO_BYTES(MAX_KEY_SIZE_BITS)   // 512
#define MAX_EXPORT_SIZE_BYTES       (MAX_KEY_SIZE_BYTES * 4)  // FIXME (v.kopp): data size is chosen arbitrarily big
//#define MAX_IMPORT_SIZE_BYTES       (MAX_KEY_SIZE_BYTES * 8)  // FIXME (v.kopp): data size is chosen arbitrarily big
#define MAX_IMPORT_SIZE_BYTES       (TIGER_INPUT_LEN - sizeof(uint32_t))
#define MAX_FINISH_SIZE_BYTES       (2048) // zhongyue.li 1024 is enough?

#ifdef TZ_MODEL_QCOM
    //from qsee_sfs.h : SFS_MAX_FILENAME_SIZE 128
    #define MAX_OBJ_ID_SIZE_BYTES    128
#else
    #define MAX_OBJ_ID_SIZE_BYTES    64
#endif

#define MAX_CHALLENGE_NAME_SIZE     128

#define MAX_KEY_ALIAS_SIZE_BYTES    (MAX_OBJ_ID_SIZE_BYTES -(sizeof(TciProcessUid_t)) - 1)
                                    // [a.orlenko] GP TEE API specifies TEE_OBJECT_ID_MAX_LEN = 64
                                    // [o.kachkan] "-1" exlude length of OBJ_ID_UID_SEPARATOR(TigerTypeObjectId.c)

//#define MAX_DRK_MSG_SIZE_BYTES      (MAX_EXPORT_SIZE_BYTES * 3) // o.kachkan: contains 3 parts: DRK certificate, ATTK private key, ATTK certificate
                                                                // in <libdk_native_client_test.c>  this value is 8192,
                                                                // but actual wrapped file size is around 3500 bytes
                                                                //
#define MAX_DRK_MSG_SIZE_BYTES       (TIGER_INPUT_LEN - sizeof(uint32_t))
#define MAX_REQUEST_MSG_SIZE         (sizeof(TciRequest_t))
#define MAX_RESPONSE_MSG_SIZE        (sizeof(TciResponse_t))

#define MAX_SIGN_MSG_SIZE            (512)
#define MAX_SIGNATURE_SIZE_BYTES     (512)
#define MAX_JSON_BRACE_SIZE          (512)

#define MAX_AUTH_KEY_SIZE_BYTES      (256)
#define AUTH_TOKEN_SIZE_BYTES        (69) //sizeof(hw_auth_token) = 69
#define HMAC_SHA256_SIZE             (32)

#define DEVICE_SECURITY_LEVEL        (10)         // security level (maximum of 10, minimum 0)
                                                  // ATTK is unique for each device, while not store the
                                                  // MD5 value of ATTK[pri] in eFuse in order to verifying

#define TCI_VAR_NOT_USED(variable) do{(void)(variable);}while(0); // MACRO is copied from gpTypes.h to be used in NWd (TigerService).

#ifdef SVTS_CMD_ID_SUPPORT
#define TA_TAG        0xffff0000

#define SVTS_CMD_ID_SAVE_ATTK_CERT        (TA_TAG | 0x1)
#define SVTS_CMD_ID_SAVE_ATTK_PRIV        (TA_TAG | 0x2)
#define SVTS_CMD_ID_SAVE_DEVICE_CERT      (TA_TAG | 0x3)

#define SVTS_CMD_ID_REMOVE_ALL_FILES      (TA_TAG | 0x4)

#endif

/**
 * Command ID's for communication  between
 * Trusted Application Connector (TAC) and Trusted Application (TA).
 */
//typedef uint32_t TciCommandId_t;

typedef enum {
    TCI_CMD_ID_GENERATE_KEY                  = 0,  ///< Generate RSA key pair and store it in TEE.
    TCI_CMD_ID_EXISTS_KEY                    = 1,  ///< Check a key pair existence
    TCI_CMD_ID_EXPORT_KEY                    = 2,  ///< Export public key by alias
    TCI_CMD_ID_DELETE_KEY                    = 3,  ///< Delete key pair by alias
    TCI_CMD_ID_CLEAR_ALL                     = 4,  ///< Remove all persistent objects from the TEE Storage
    TCI_CMD_ID_INIT_SIGN                     = 5,  ///< init to sign message.
    TCI_CMD_ID_SIGN_FINISH                   = 6,  ///< Finish to sign message.
    TCI_CMD_ID_SAVE_ATTK_KEY                 = 7, ///< Unwrap ATTK key, generated by DRK-service and write it to RPMB
    TCI_CMD_ID_EXPORT_ATTK_PUB               = 8, ///< Export attk-pub key in pem format
    TCI_CMD_ID_CHECK_DEVICE_STATUS           = 9, ///< Check that ATTK and Device-key-pair generated and Device key registered on SSKDS.
    TCI_CMD_ID_SSKDS_SET_STATUS              = 10, ///< Set device registration status.
    TCI_CMD_ID_SETUP_AUTH_KEY                = 11, ///< Unwrap fingerprint daemon's key and place it to session context.
    TCI_CMD_ID_SSKDS_SET                     = 12, ///< SSKDS Operations
    TCI_CMD_ID_SSKDS_GET                     = 13, ///< SSKDS Operations
    TCI_CMD_ID_RUN_TA_TESTS                  = 14,
    TCI_CMD_ID_EXPORT_DEVICE_ID              = 15,
    TCI_CMD_ID_IMPORT_CHIP_NAME              = 16,
    TCI_CMD_ID_GET_UIDS                      = 17,
    TCI_CMD_ID_CLEAR_USER_DATA               = 18,
    TCI_CMD_ID_SSKDS_SIGN                    = 19,
    TCI_CMD_ID_CLEAR_SFS                     = 20,
    TCI_CMD_ID_SERVICE_CHECK_DEVICE_STATUS   = 21,

    TCI_CMD_ID_PROCESS_COMMAND               = 22,

#ifdef SVTS_CMD_ID_SUPPORT
    TCI_CMD_ID_SVTS_SAVE_ATTK_CERT           =  SVTS_CMD_ID_SAVE_ATTK_CERT  ,
    TCI_CMD_ID_SVTS_SAVE_ATTK_PRIV           =  SVTS_CMD_ID_SAVE_ATTK_PRIV  ,
    TCI_CMD_ID_SVTS_SAVE_DEVICE_CERT         =  SVTS_CMD_ID_SAVE_DEVICE_CERT,
    TCI_CMD_ID_SVTS_REMOVE_ALL_FILES         =  SVTS_CMD_ID_REMOVE_ALL_FILES,
#endif

} TciCommandId_t;

#if defined(__USE_TESTBED__)

#define DECLARE_TESTBED_FUNC(__func_name__) \
    TEE_Result test ##__func_name__(const uint8_t*, const uint32_t, uint8_t*, uint32_t*)

#define IMPL_TESTBED_FUNC(__func_name__) \
    TEE_Result test ##__func_name__(const uint8_t* data, const uint32_t lenData, uint8_t* response, uint32_t* lenRsp)

#define CALL_TESTBED_FUNC(__func_name__) \
    test ##__func_name__(data->value, data->len, testResponse, &size)

// Add More Test Comamnd Id Here.
typedef enum{
    TCI_TEST_RPMB_WRITE,
    TCI_TEST_RPMB_READ,
    TCI_TEST_RPMB_CLEAR,

    TCI_TEST_STORAGE_CREATE_NEW_FILE,
    TCI_TEST_STORAGE_CREATE_OPEN_FILE,
    TCI_TEST_STORAGE_OPEN_READ_FILE,

    TCI_TEST_PERSISTENT_OBJECT_READ,
    TCI_TEST_PERSISTENT_OBJECT_WRITE,
    TCI_TEST_PERSISTENT_OBJECT_WRITE_AND_READ,

    TCI_TEST_SSKDS_STORE_DEVICE_ID,

    TCI_TEST_DATASTORE_SET_COUNTER,
    TCI_TEST_DATASTORE_GET_COUNTER,
    TCI_TEST_DATASTORE_INC_COUNTER,
    TCI_TEST_DATASTORE_GET_INC_COUNTER,


    TCI_TEST_READ_SERIAL_NUMBER,

    TCI_TEST_CMDID_END,
} TCI_TEST_COMMAND_ID;
#endif

/**
 * Gets TCI Command Id string representation
 * @param aCmdId TCI Command Id
 * @return
 */
const char* getTciCommandIdStr(TciCommandId_t aCmdId);

/**
 * @brief TCI hardware info.
 */
typedef struct {
    uint32_t  chipId;
} TciHardwareInfo_t;

/**
 * @brief Key status.
 *        Get key status
 */
typedef enum {
    TCI_DEVICE_ATTK_NOT_FOUND   = 0,
    TCI_DEVICE_NOT_REGISTERED   = 1,  // DRK && ATTK exists, device not registered on server.
    TCI_DEVICE_REGISTERED       = 2,  // for ATTK: DRK && ATTK exists, device registered on server.
                                      // for DeviceKeys: Device Public & Private Keys & Certificate exist.
} TciDeviceStatus_t;

/**
 * Type to represent calling UID
 */
typedef uint32_t TciProcessUid_t;

/**
 * Handy structure to transfer key alias
 */
typedef struct {
    uint32_t length;
    uint8_t value[MAX_KEY_ALIAS_SIZE_BYTES + 1]; // Additional byte is added for termination '\0'.
} TciKeyAlias_t;

/**
 * Handy structure to transfer challenge
 */
typedef struct {
    uint32_t length;
    uint8_t value[MAX_CHALLENGE_NAME_SIZE + 1]; // Additional byte is added for termination '\0'.
} TciChallenge_t;

/*
 * The key can be identified by its user and alias
 * This structure contains both fields
 * All request structures requiring a key will contain this structure as its first attribute (C-inheritance)
 */
typedef struct {
    TciProcessUid_t uid;
    TciKeyAlias_t alias;
} TciKeyCredentials_t;

/**
 * Structure to export binary data
 */
typedef struct {
    uint32_t size;
    uint8_t bytes[MAX_EXPORT_SIZE_BYTES];
} TciExportedData_t;

/**
 * Structure to finish sign data
 */
typedef struct {
    uint32_t size;
    uint8_t bytes[MAX_FINISH_SIZE_BYTES];
} TciFinishSignData_t;

/**
 * Structure to import binary data
 */
typedef struct {
    uint32_t size;
    uint8_t bytes[MAX_IMPORT_SIZE_BYTES];
} TciImportedData_t;

/**
 * TCI_CMD_ID_INIT_SIGN
 */
typedef struct {
    TciKeyCredentials_t kc;
    TciChallenge_t challenge;
} TciInitSignMessage_t;

/**
 * TCI_CMD_ID_INIT_SIGN response
 */
typedef struct {
    uint64_t    sessionId;
} TciInitSignResponse_t;

/**
 * TCI_CMD_ID_SIGN_FINISH request
 */
typedef struct {
    uint64_t     sessionId;
} TciSignFinishRequest_t;

/**
 * TCI_CMD_ID_SIGN_FINISH response
 */
typedef struct {
    TciFinishSignData_t entry;
} TciSignFinishResponse_t;

/**
 * TCI_CMD_ID_GENERATE_KEY command.
 */
typedef struct {
    TciKeyCredentials_t kc;
} TciGenerateKeyPairMessage_t;

/**
 * TCI_CMD_ID_EXPORT_KEY
 */
typedef struct {
    TciKeyCredentials_t kc;
} TciExportEntryMessage_t;

/**
 * TCI_CMD_ID_DELETE_KEY
 */
typedef struct {
    TciKeyCredentials_t kc;
} TciDeleteKeyPairMessage_t;

/**
 * TCI_CMD_ID_EXISTS_KEY
 */
typedef struct {
    TciKeyCredentials_t kc;
} TciExistsKeyPairMessage_t;

/**
 * TCI_CMD_ID_SAVE_ATTK_KEY
 */
typedef struct {
    uint32_t    size;
    uint8_t     bytes[MAX_DRK_MSG_SIZE_BYTES];
} TciDrkDataMessage_t;

typedef struct {
    TciHardwareInfo_t hardwareInfo;
} TciSskdsSetData_t;

typedef struct {
    uint8_t status;
} TciSskdsDeviceStatus_t;

/**
 * TCI_CMD_ID_SETUP_AUTH_KEY
 */
typedef struct {
    uint32_t size;
    uint8_t bytes[MAX_KEY_SIZE_BYTES];
} TciSaveAuthKeyMessage_t;

/**
 * TCI_CMD_ID_CLEAR_UID_DATA
 */
typedef struct {
    TciProcessUid_t uid;
} TciClearUserDataMessage_t;

/**
 * TCI_CMD_ID_PROCESS_COMMAND
 */
typedef struct {
    uint32_t    length;
    uint8_t     value[TIGER_INPUT_LEN];
} TciProcessCommandMessage_t;

typedef enum {
    SSKDS_GET_DATA_CERTIFICATE_DRK   = 0,
    SSKDS_GET_DATA_CERTIFICATE_ATTK  = 1,
    SSKDS_GET_DATA_PUBLIC_KEY_ATTK   = 2,
} TciSskdsGetDataType_t;

typedef struct {
    TciSskdsGetDataType_t type;
} TciSskdsGetData_t;

/**
 * TCI request message.
 */
typedef struct{
    TciCommandId_t TciCommandId;
    union{
        uint32_t length;
        uint32_t reserve;
    };
    union {
        TciGenerateKeyPairMessage_t genKey;
        TciDrkDataMessage_t saveDrkData;
        TciExportEntryMessage_t expEntry;
        TciDeleteKeyPairMessage_t delKey;
        TciExistsKeyPairMessage_t existsKey;
        TciInitSignMessage_t initSignMessage;
        TciSignFinishRequest_t signFinishMessage;
        TciSskdsSetData_t sskdsSetData;
        TciSskdsDeviceStatus_t sskdsDeviceStatus;
        TciImportedData_t ssksdSign;
        TciSskdsGetData_t sskdsGet;
        TciSaveAuthKeyMessage_t saveAuthKeyMessage;
        TciClearUserDataMessage_t clearData;
    } request;
} __attribute__ ((packed)) TciRequest_t, *TciRequest_p;

typedef struct {
    TciExportedData_t entry;
} TciExportEntryResponse_t;

/**
 * TCI_CMD_ID_CHECK_DEVICE_STATUS
 */
typedef struct {
    TciDeviceStatus_t status;
} TciDeviceStatusResponse_t;

/**
 * TCI_CMD_ID_PROCESS_COMMAND
 */
typedef struct {
    uint32_t length;
    uint8_t value[TIGER_OUTPUT_LEN];
} TciProcessCommandResponse_t;

typedef struct {
    uint32_t fid;
} TciTransferFid_t;

/**
 * TCI response message.
 */
typedef union {
    TciExportEntryResponse_t exportEntry;
    TciInitSignResponse_t initSign;
    TciSignFinishResponse_t signFinish;
    TciDeviceStatusResponse_t deviceStatus;
    TciProcessCommandResponse_t responseEntry;
} TciResponse_t;

/**
 * @brief TEE Session Type
 */
typedef uint8_t TciTeeSessionType_t;
static const TciTeeSessionType_t TCI_TEE_SESSION_TYPE_SIMPLE  = 0;
static const TciTeeSessionType_t TCI_TEE_SESSION_TYPE_SIGN   = 1;

typedef struct {
    TciTeeSessionType_t type;
    void* data;
} TigerSessionContext_t;

/**
 * TA Session ID
 */
typedef uint64_t TciTaSessionId_t;

#ifdef __cplusplus
}
#endif

#endif // TIGER_TCI_H
