#if defined FACTORY_RESET

#include "tz_debug.h"
#include "sem.h"
#include "sec_apdu.h"
#include "ccm.h"
#include "crypto_module.h"

void isFactoryReset(p_cmd_t cmd, p_rsp_t rsp) {
    uint8_t channelId = 0;
    uint8_t data[MAX_RAPDU_DATA_SIZE] = {0,};
    secEse_7816_rpdu_t rpdu;
    uint8_t otp_key_blob[SSP_MAX_WRAPPED_OTP_KEY_SIZE] = {0,};
    uint32_t otp_key_blob_size;
    uint32_t current_pos, inputSize;
    int32_t ret = RET_SUCCESS;
    uint8_t fra_aid[] = {0xA0, 0x00, 0x00, 0x02, 0x20, 0x16, 0x03, 0x01, 0x03, 0x10, 0x00, 0x53, 0x4D, 0x46, 0x52, 0x41};
    uint8_t commandData[8] = {0,};
    static const uint32_t FRA_AID_LENGTH = 16;

    uint8_t kvn30keyset[48] = {0,}; // enc 16,mac 16, dek 16
    uint32_t kvn30keysetLen = 0;

    uint8_t kvn30_key_enc[AES_128_KEY_SIZE] = {0,};
    uint8_t kvn30_key_mac[AES_128_KEY_SIZE] = {0,};
    uint8_t kvn30_key_dek[AES_128_KEY_SIZE] = {0,};

// below variables was used to do factoryReset via SPI
    secEse_7816_cpdu_t cpdu;
    SCPSTATUS status = 0;

    rsp->ret = RET_ERR_TZ;
    rsp->status = RET_ERR_TZ;

    LOGD("isFactoryReset start in FRA.C");
    inputSize = cmd->dataLen;

    if (inputSize > 4 + SSP_MAX_WRAPPED_OTP_KEY_SIZE) {
        LOGE("Buffer is not enough");
        rsp->ret = RET_ERR_BUFFER_OVERFLOW;
        goto error;
    }

    // separate otp_key_blob from data
    current_pos = 0;
    memcpy(&otp_key_blob_size, cmd->data + current_pos, 4);
    current_pos += 4;
    if (otp_key_blob_size > sizeof(otp_key_blob)) {
        LOGE("Buffer is not enough");
        rsp->ret = RET_ERR_BUFFER_OVERFLOW;
        goto error;
    }
    memcpy(otp_key_blob, cmd->data + current_pos, otp_key_blob_size);
    current_pos += otp_key_blob_size;

    memset(&rpdu, 0, sizeof(secEse_7816_rpdu_t));
    rpdu.pdata = data;

    ret = secEseSelect(channelId, fra_aid, 0, FRA_AID_LENGTH, &rpdu);
    if(ret != ESESTATUS_SUCCESS){
        LOGE("isFactoryReset, failed to communicate");
        rsp->ret = RET_STATUS_FRA_APPLET_NOT_EXISTS;
        goto error;
    }

    LOGD("SW:0x%02x%02x",rpdu.sw1, rpdu.sw2);
    LOGD("NOE:0x%02x%02x, Version:0x%02x%02x",rpdu.pdata[0], rpdu.pdata[1], rpdu.pdata[2], rpdu.pdata[3]);

    if(rpdu.sw1 == 0x6a && rpdu.sw2 == 0x82) {
        LOGE("isFactoryReset, FRA applet is not exist");
        rsp->status = RET_STATUS_FRA_APPLET_NOT_EXISTS;
        rsp->ret = RET_STATUS_FRA_APPLET_NOT_EXISTS;
        goto error;
    } else if(rpdu.sw1 == 0x90 && rpdu.sw2 == 0x00) {
        if(rpdu.pdata[0] == 0x00 && rpdu.pdata[1] == 0x00){
            LOGI("isFactoryReset, did not have entries");
            rsp->status = RET_STATUS_DID_NOT_HAVE_CLEAR_LIST;
            rsp->ret = RET_SUCCESS;
            goto error;
        } else if(rpdu.pdata[0] > 0x00 || rpdu.pdata[1] > 0x00) {
            LOGI("isFactoryReset, Need to factoryReset");
            rsp->status = RET_STATUS_NEED_TO_FACTORY_RESET;
            rsp->ret = RET_STATUS_NEED_TO_FACTORY_RESET;
        } else {
            LOGE("isFactoryReset, UNKNOWN ERROR");
            rsp->status = RET_STATUS_FACTORY_RESET_UNKNOWN_ERROR;
            rsp->ret = RET_STATUS_FACTORY_RESET_UNKNOWN_ERROR;
            goto error;
        }
    } else { //21.04.22
        LOGE("isFactoryReset, UNKNOWN ERROR");
        rsp->status = RET_STATUS_FACTORY_RESET_UNKNOWN_ERROR;
        rsp->ret = RET_STATUS_FACTORY_RESET_UNKNOWN_ERROR;
        goto error;
    }

    //start fra
    //ret = scp03_kvn30(&channelId, fra_aid, FRA_AID_LENGTH, otp_key_blob, otp_key_blob_size, 0);
    // generate random keyset KVN#31
    LOGI("GET KVN30");
    // close channel for scp03
    // ssp kvn30 session open -> opensession with cmd -> close session in getKVN30Keyset
    ret = getKVN30Keyset(channelId, otp_key_blob, otp_key_blob_size, kvn30keyset, &kvn30keysetLen);
    if (0 != ret) {
        LOGE("Failed to get KVN30Keyset");
        //ret = RET_ERR_CCM_OPENSESSION_KVN30;
        rsp->ret = RET_ERR_CCM_OPENSESSION_KVN30; //21.04.22
        goto error;
    }
    // parse KVN30 keyset & save to buffers :: kvn30_key_enc, kvn30_key_mac, kvn30_key_dek each key length is 16byte
    if (kvn30keysetLen == 48) {
        memcpy(kvn30_key_enc, kvn30keyset, AES_128_KEY_SIZE);
        memcpy(kvn30_key_mac, kvn30keyset + AES_128_KEY_SIZE, AES_128_KEY_SIZE);
        memcpy(kvn30_key_dek, kvn30keyset + AES_128_KEY_SIZE + AES_128_KEY_SIZE, AES_128_KEY_SIZE);
    } else {
        LOGE("Failed to get KVN30Keyset. Invalid keyset length : kvn30keysetLen %u", kvn30keysetLen);
        //ret = RET_ERR_CCM_OPENSESSION_KVN30;
        rsp->ret = RET_ERR_CCM_OPENSESSION_KVN30; //21.04.22
        goto error;
    }

    LOGD("********************* [ SELECT FRA ] *******************");
    memset(&rpdu, 0, sizeof(secEse_7816_rpdu_t));
    memset(data, 0, MAX_RAPDU_DATA_SIZE);
    rpdu.pdata = data;
    ret = secEseSelect(channelId, fra_aid, 0, FRA_AID_LENGTH, &rpdu);
    if(ret != ESESTATUS_SUCCESS){
        LOGE("isFactoryReset, failed to communicate");
        rsp->ret = RET_STATUS_FRA_APPLET_NOT_EXISTS;
        goto error;
    }

    LOGD("********************* [ OPEN SESSION 30 ] *******************");
    ret = openSession(channelId, 0x30, kvn30_key_enc, kvn30_key_mac, kvn30_key_dek, fra_aid, FRA_AID_LENGTH, 0x03);
    if (ret != SCP_SUCCESS) {
        LOGE("Failed SCP03 KVN30 OPEN SESSION :: scpStatus : 0x%08x", ret);
        //ret = RET_ERR_CCM_OPENSESSION_KVN30;
        rsp->ret = RET_ERR_CCM_OPENSESSION_KVN30; //21.04.22
        goto error;
    }

    memset(&cpdu, 0, sizeof(secEse_7816_cpdu_t));
    memset(&rpdu, 0, sizeof(secEse_7816_rpdu_t));
    memset(data, 0, MAX_RAPDU_DATA_SIZE);
    rpdu.pdata = data;

    cpdu.cla = 0x80;
    cpdu.ins = 0xF4;
    cpdu.p1 = 0x00;
    cpdu.p2 = 0x00;
    cpdu.lc = 0x00;
    cpdu.le = 0x00;
    cpdu.le_type = 0x00;
    cpdu.pdata = commandData;

    status = apduTransceive (channelId, &cpdu, &rpdu);
    if (status != SCP_SUCCESS) {
        LOGE("isFactoryReset, factory reset Failed. sw1-sw2 : 0x%x%x", rpdu.sw1, rpdu.sw2);
        rsp->ret = RET_ERR_CHECK_FACTORY_RESET_FAIL;
        goto error;
    }

    LOGD("status Ret:0x%02x",status);
    //LOGD("final rpdu :0x%02x 0x%02x",rpdu.sw1, rpdu.sw2);

    memset(&rpdu, 0, sizeof(secEse_7816_rpdu_t));
    rpdu.pdata = data;

    ret = secEseSelect(channelId, fra_aid, 0, FRA_AID_LENGTH, &rpdu);
    LOGI("Ret:0x%02x",ret);
    if(ret != ESESTATUS_SUCCESS){
        LOGE("isFactoryReset, failed to communicate");
        rsp->ret = RET_STATUS_FRA_APPLET_NOT_EXISTS;
        goto error;
    }
    LOGD("isFactoryReset, failed to verify factory Reset, NOE:0x%02x%02x",rpdu.pdata[0], rpdu.pdata[1]);
    if(rpdu.pdata[0] == 0x00 && rpdu.pdata[1] == 0x00){
        rsp->ret = RET_SUCCESS;
        //rsp->status = RET_SUCCESS; //21.04.22
        rsp->status = RET_STATUS_NEED_TO_FACTORY_RESET;
    } else {
        LOGE("isFactoryReset, failed to verify factory Reset, NOE:0x%02x%02x",rpdu.pdata[0], rpdu.pdata[1]);
        rsp->ret = RET_ERR_CHECK_FACTORY_RESET_FAIL;
    }

error:
    crypto_clear_mem(kvn30keyset, sizeof(kvn30keyset));
    crypto_clear_mem(kvn30_key_enc, sizeof(kvn30_key_enc));
    crypto_clear_mem(kvn30_key_mac, sizeof(kvn30_key_mac));
    crypto_clear_mem(kvn30_key_dek, sizeof(kvn30_key_dek));

    LOGI("FRA FINISH, %d", rsp->ret);
}
#endif

