#include "fido_apdu.h"
#include "sec_apdu.h"
#include "tz_debug.h"
#include "time.h"

#define FIDO_MAX_LEN                                    2000
#define FIDO_UAF_LIB_VER                            "2017.08.21.01"

#define FIDOSTATUS_ESE_CHANNEL_OPEN_FAILED           0x0050
#define FIDOSTATUS_ESE_CHANNEL_CLOSE_FAILED          0x0051

#define cShortAPDU      0x00
#define cExtendedAPDU   0x01

#define rNoRSP          0x00
#define rShortAPDU      0x01
#define rExtendedAPDU   0x02


void lentobyte(uint8_t* bytearray, uint16_t inputdata, uint16_t index) {
	bytearray[index] = inputdata >> 8;
	bytearray[index+1] = (uint8_t)(inputdata & 0xff);
}

uint16_t bytetolen(uint8_t* inputarray, uint16_t index) {
	uint16_t len = 0;
    len = (inputarray[index] << 8) | inputarray[index+1];
    return len;
}

/**********************************/
FIDOSTATUS fido_spi_open() {
    int retryCnt = 0;

    for(retryCnt = 0; retryCnt < 3; retryCnt++) {
        if(spiOpen() == 0) break;
    }

    if(retryCnt == 3) {
        LOGE("FIDO SPI OPEN FAIL");
        spiClose();
        return FIDOSTATUS_SPI_OPEN_FAILED;
    }

    LOGI("FIDO SPI OPEN SUCCESS, retry counter = %d", retryCnt);

    return FIDOSTATUS_SUCCESS;
}
FIDOSTATUS fido_spi_close() {
    int retryCnt = 0;

    for(retryCnt = 0; retryCnt < 3; retryCnt++) {
        if(spiClose() == 0) break;
    }

    if(retryCnt == 3) {
        LOGE("FIDO SPI CLOSE FAIL");
        return FIDOSTATUS_SPI_CLOSE_FAILED;
    }

    LOGI("FIDO SPI CLOSE SUCCESS, retry counter = %d", retryCnt);

    return FIDOSTATUS_SUCCESS;
}

FIDOSTATUS fido_get_AAID(uint8_t* p_out_aaid1, uint16_t* p_out_aaid1_len,
                            uint8_t* p_out_aaid2, uint16_t* p_out_aaid2_len) {
	ESESTATUS			status;
	secEse_7816_cpdu_t	cur_cmd;
	secEse_7816_rpdu_t	cur_rsp;
	uint8_t rsp_data[MAX_RAPDU_DATA_SIZE];
    uint8_t fido_aid[] = {0xA0, 0x00, 0x00, 0x06, 0x47, 0xAF, 0x00, 0x01};
	uint8_t cn = 0x00;
    LOGI("FIDO UAF LIB VER : %s", FIDO_UAF_LIB_VER);
    LOGD( "     *********     fido_get_AAID is called     *********     ");

    status = secEseOpen(&cn);
	if (status != ESESTATUS_SUCCESS) {
        LOGE("     *********     get AAID channel open fail     *********     ");
        secEseClose(cn);
		return FIDOSTATUS_ESE_CHANNEL_OPEN_FAILED;
    }

    cur_cmd.cla = (0x00 & cn);
    cur_cmd.ins = 0x04;
    cur_cmd.p1 = 0x00;
    cur_cmd.p2 = 0x00;
    cur_cmd.lc = 0x00;
	// cpdu_type
	// 0 : short -> ShortAPDU
	// 1 : extended -> ExtendedAPDU
    cur_cmd.cpdu_type = cShortAPDU;
    cur_cmd.pdata = 0x00;
	// le_type
	// >=2 : extended
	// 1 : short?
	// 0 : absent
    cur_cmd.le_type = rShortAPDU;
    cur_cmd.le = 0x00;
    cur_rsp.pdata = rsp_data;


    //select
    secEseSelect(cn, fido_aid, 0, 8, &cur_rsp);
    if(cur_rsp.sw1 != 0x90) {
        LOGE("     *********     FIDO applet select error : %x %x     *********     ", cur_rsp.sw1, cur_rsp.sw2);
        return FIDOSTATUS_APPLET_SELECT_FAILED;
    }
    memset(cur_rsp.pdata, 0, cur_rsp.len);
	cur_rsp.sw1 = cur_rsp.sw2 = 0x00;

    cur_cmd.lc = 0;
    // transmit
    do {
        if(cur_rsp.sw1 == 0x61 || cur_rsp.sw1 == 0x63) {
            LOGD("FIDO get aaid DATA REMAINS");
            cur_cmd.ins = 0xc4;
            cur_cmd.le = cur_rsp.sw2;
            cur_cmd.lc = 1;
            cur_cmd.pdata[0] = 0x01;
            memset(cur_rsp.pdata, 0, 256);
        }

        LOGD("FIDO get aaid secTransmit starts");
        status = secEseTransmit( cn, &cur_cmd, &cur_rsp );

        if( status != ESESTATUS_SUCCESS) {
            LOGE("Cannot Communicate eSE. ESESTATUS = 0x%08X", status);
            return FIDOSTATUS_ESE_FAILED;
        }
        hex_print_tag("FIDO AAID", cur_rsp.pdata, cur_rsp.len);
    }while( cur_rsp.sw1 == 0x61 || cur_rsp.sw1 == 0x63);

    *p_out_aaid1_len = bytetolen(cur_rsp.pdata, 0);
    memcpy(p_out_aaid1, &cur_rsp.pdata[2], *p_out_aaid1_len);

    *p_out_aaid2_len = bytetolen(cur_rsp.pdata, 11);
    memcpy(p_out_aaid2, &cur_rsp.pdata[13], *p_out_aaid2_len);

    secEseClose(cn);

	return FIDOSTATUS_SUCCESS;
}


FIDOSTATUS createUserdata(uint8_t cn, uint16_t in_signalgandencoding, uint16_t in_publickeyalgandencoding,
						    uint8_t* p_in_keyhandleaccesstoken, uint16_t in_keyhandleaccesstoken_len,
						    uint8_t* p_in_username, uint8_t in_username_len,
						    uint8_t* p_in_appid, uint16_t in_appid_len,
						    uint8_t *p_output, uint16_t *p_output_len) {
    ESESTATUS			status;
	secEse_7816_cpdu_t	cur_cmd;
	secEse_7816_rpdu_t	cur_rsp;
    uint8_t cmd_data[MAX_CAPDU_DATA_SIZE];
	uint8_t rsp_data[MAX_RAPDU_DATA_SIZE];
	uint16_t TLV_idx = 0;
	uint8_t TLV[FIDO_MAX_LEN], fido_aid[] = {0xA0, 0x00, 0x00, 0x06, 0x47, 0xAF, 0x00, 0x01};

    LOGD("     *********     FIDO Create UserData is called     *********     ");
	// E0 : keyhandle token
	TLV[TLV_idx] = 0xE0;
	TLV_idx += 1;
	lentobyte(TLV, in_keyhandleaccesstoken_len, TLV_idx);
	TLV_idx += 2;
	memcpy(&TLV[TLV_idx], p_in_keyhandleaccesstoken, in_keyhandleaccesstoken_len);
	TLV_idx += in_keyhandleaccesstoken_len;

	// E1 : username
	TLV[TLV_idx] = 0xE1;
	TLV_idx += 1;
	lentobyte(TLV, in_username_len, TLV_idx);
	TLV_idx += 2;
	memcpy(&TLV[TLV_idx], p_in_username, in_username_len);
	TLV_idx += in_username_len;

	// E2 : appid
	TLV[TLV_idx] = 0xE2;
	TLV_idx += 1;
	lentobyte(TLV, in_appid_len, TLV_idx);
	TLV_idx += 2;
	memcpy(&TLV[TLV_idx], p_in_appid, in_appid_len);
	TLV_idx += in_appid_len;
    cur_rsp.pdata = rsp_data;
    cur_cmd.pdata = cmd_data;
    memset(cur_cmd.pdata, 0, MAX_CAPDU_DATA_SIZE);
    memcpy(cur_cmd.pdata, TLV, TLV_idx);
    cur_cmd.lc = TLV_idx;

    *p_output_len = 0;

    // cur_cmd apdu making
	cur_cmd.cla = (0x00 & cn);
    cur_cmd.cpdu_type = cShortAPDU;
    cur_cmd.le_type = rShortAPDU;
    cur_cmd.le = 0x00;
    cur_cmd.ins = 0x01;


	if(in_signalgandencoding == 0x0001) {		// 0x0001 = ecdsa
		cur_cmd.p1 = 0x11;
	}
	else if(in_signalgandencoding == 0x0003) {	// 0x0003 = rsa
		cur_cmd.p1 = 0x01;
	}
	else {
		return FIDOSTATUS_INVALID_SIGNALGO;
	}
    cur_cmd.p2 = 0x00;

    cur_rsp.sw1 = cur_rsp.sw2 = 0x00;

    //hex_print_tag("FIDO reg create data", cur_cmd.pdata, TLV_idx);
    LOGD("fido UserData transmit starts");
    // transmit
    do {
        if(cur_rsp.sw1 == 0x61 || cur_rsp.sw1 == 0x63) {
            LOGD("FIDO DATA REMAINS");
            cur_cmd.ins = 0xc1;
            cur_cmd.le = cur_rsp.sw2;
            cur_cmd.lc = 1;
            cur_cmd.pdata[0] = 0x01;
            memset(cur_rsp.pdata, 0, 256);
        }
	    status = secEseTransmit( cn, &cur_cmd, &cur_rsp );

	    if( status != ESESTATUS_SUCCESS) {
		    LOGE("Cannot Communicate eSE. ESESTATUS = 0x%08X", status);
            return FIDOSTATUS_ESE_FAILED;
	    }
        //hex_print_tag("FIDO", cur_rsp.pdata, cur_rsp.len);

        memcpy(&p_output[*p_output_len], cur_rsp.pdata, cur_rsp.len);
        *p_output_len += cur_rsp.len;
    }while( cur_rsp.sw1 == 0x61 || cur_rsp.sw1 == 0x63);

    if(cur_rsp.sw1 == 0x90 && cur_rsp.sw2 == 0x00) {
        return FIDOSTATUS_SUCCESS;
    }
    else return FIDOSTATUS_ESE_FAILED;
}

FIDOSTATUS fido_getAttestationBasicFull(uint8_t cn, uint16_t in_signalgandencoding, uint8_t* p_in_aaid, uint16_t in_aaid_len,
                                                        uint8_t *krd, uint16_t krd_len, uint8_t* p_output, uint16_t *p_output_len) {
    ESESTATUS			status;
	secEse_7816_cpdu_t	cur_cmd;
	secEse_7816_rpdu_t	cur_rsp;
	uint8_t cmd_data[MAX_CAPDU_DATA_SIZE];
	uint8_t rsp_data[MAX_RAPDU_DATA_SIZE];
	uint16_t TLV_idx = 0;
	uint8_t TLV[FIDO_MAX_LEN];

    LOGD("     *********     FIDO getAttestation called     *********     ");

    cur_cmd.pdata = cmd_data;
    cur_cmd.cpdu_type = cShortAPDU;
    cur_cmd.le_type = rShortAPDU;
    cur_cmd.le = 0x00;
	cur_rsp.pdata = rsp_data;

	cur_cmd.cla = (0x00 & cn);
    cur_cmd.ins = 0x01;

	if(in_signalgandencoding == 0x0001) {		// 0x0001 = ecdsa
		cur_cmd.p1 = 0x12;
	}
	else if(in_signalgandencoding == 0x0003) {	// 0x0003 = rsa
		cur_cmd.p1 = 0x02;
	}
	else {
		return FIDOSTATUS_INVALID_SIGNALGO;
	}
    cur_cmd.p2 = 0x00;

    TLV_idx = 0;

	// E0 : aaid
	TLV[TLV_idx++] = 0xE0;
	lentobyte(TLV, in_aaid_len, TLV_idx);
	TLV_idx += 2;
	memcpy(&TLV[TLV_idx], p_in_aaid, in_aaid_len);
	TLV_idx += in_aaid_len;

	// E1 : krd
	TLV[TLV_idx++] = 0xE1;
	lentobyte(TLV, krd_len, TLV_idx);
	TLV_idx += 2;
	memcpy(&TLV[TLV_idx], krd, krd_len);
	TLV_idx += krd_len;

    memcpy(cur_cmd.pdata, TLV, TLV_idx);
    cur_cmd.lc = TLV_idx;
    *p_output_len = 0;
    cur_rsp.sw1 = cur_rsp.sw2 = 0x00;

    LOGD("getAttestation transmit");
    do {
        if(cur_rsp.sw1 == 0x61 || cur_rsp.sw1 == 0x63) {
            LOGD("return data remains");
            cur_cmd.ins = 0xc1;
            cur_cmd.pdata[0] = 0x01;
            cur_cmd.le = cur_rsp.sw2;
            cur_cmd.lc = 1;
            memset(cur_rsp.pdata, 0, 256);
        }

	    status = secEseTransmit( cn, &cur_cmd, &cur_rsp );

	    if( status != ESESTATUS_SUCCESS) {
		    LOGE("Cannot Communicate eSE. ESESTATUS = 0x%08X", status);
		    return FIDOSTATUS_ESE_CHANNEL_OPEN_FAILED;;
	    }

        //hex_print_tag("FIDO attestation cur_rsp.len", cur_rsp.pdata, cur_rsp.len);
        memcpy(&p_output[*p_output_len], cur_rsp.pdata, cur_rsp.len);
        *p_output_len += cur_rsp.len;
    }while( cur_rsp.sw1 == 0x61 || cur_rsp.sw1 == 0x63);

    LOGD("     *********     getAttestation transmit ends : %d     *********     ", *p_output_len);

    if(cur_rsp.sw1 == 0x90 && cur_rsp.sw2 == 0x00) {
        return FIDOSTATUS_SUCCESS;
    }
    else return FIDOSTATUS_ESE_FAILED;

}

FIDOSTATUS fido_register (uint8_t* p_in_aaid, uint16_t in_aaid_len,
                        uint8_t* p_in_appid, uint16_t in_appid_len,
						uint8_t* p_in_finalchallengehash, uint16_t in_finalchallengehash_len,
						uint8_t* p_in_username, uint8_t in_username_len,
						uint8_t* p_in_attestationtype,  uint16_t in_attestationtype_len,
						uint8_t* p_in_keyhandleaccesstoken, uint16_t in_keyhandleaccesstoken_len,
						/*uint16_t in_authenticatorversion,*/ uint16_t in_signalgandencoding, uint16_t in_publickeyalgandencoding,
						uint8_t* p_out_tlvregisterresponse, uint16_t* p_out_tlvregisterresponse_len) {
	ESESTATUS			status;
	secEse_7816_rpdu_t	cur_rsp;
	uint8_t rsp_data[MAX_RAPDU_DATA_SIZE], fido_aid[] = {0xA0, 0x00, 0x00, 0x06, 0x47, 0xAF, 0x00, 0x01};
	uint8_t p_output[FIDO_MAX_LEN], krd[1000], assertioninfo[300], uafv1_reg_assertion[FIDO_MAX_LEN];
    uint8_t cn = 0x00, ret_cnt = 0;
    uint16_t krd_idx = 0, p_output_idx = 0, asrt_idx = 0;
    uint16_t p_output_len, krd_len = 0, tmp_len = 0;
    uint32_t regCounter = 0;

    LOGI("FIDO UAF LIB VER : %s", FIDO_UAF_LIB_VER);
    LOGD("     *********     FIDO Register Starts     *********     ");

    if(p_in_keyhandleaccesstoken == NULL ) {
        LOGE("     *********     TOKEN is NULL     *********     ");
        return FIDOSTATUS_INVALID_TOKEN;
    }
    if(in_keyhandleaccesstoken_len <= 0) {
        LOGE("     *********     Invalid TOKEN length    *********     ");
        return FIDOSTATUS_WRONG_TOKEN_LEN;
    }
    if(p_in_username == NULL)  {
        LOGE("     *********     Username is NULL    *********     ");
        return FIDOSTATUS_INVALID_USERNAME;
    }
    if(in_username_len > 128 || in_username_len <= 0)  {
        LOGE("     *********     Invalid Username length    *********     ");
        return FIDOSTATUS_WRONG_USERNAME_LEN;
    }


    if(p_in_appid == NULL ) {
        LOGE("     *********     APPID is NULL     *********     ");
        return FIDOSTATUS_INVALID_APPID;
    }
    if(in_appid_len <= 0) {
        LOGE("     *********     Invalid APPID length    *********     ");
        return FIDOSTATUS_WRONG_APPID_LEN;
    }
    if(p_in_aaid == NULL)  {
        LOGE("     *********     AAID is NULL    *********     ");
        return FIDOSTATUS_INVALID_AAID;
    }
    if(in_aaid_len <= 0)  {
        LOGE("     *********     Invalid AAID length    *********     ");
        return FIDOSTATUS_WRONG_AAID_LEN;
    }


    status = secEseOpen(&cn);
	if (status != ESESTATUS_SUCCESS) {
        LOGE("     *********     FIDO register channel open fail     *********     ");
        secEseClose(cn);
		return FIDOSTATUS_ESE_FAILED;
    }
    cur_rsp.pdata = rsp_data;
    //select
    secEseSelect(cn, fido_aid, 0, 8, &cur_rsp);
    if(cur_rsp.sw1 != 0x90) {
        LOGE("     *********     FIDO applet select error : %x %x     *********     ", cur_rsp.sw1, cur_rsp.sw2);
        return FIDOSTATUS_APPLET_SELECT_FAILED;
    }
    memset(cur_rsp.pdata, 0, cur_rsp.len);

    LOGD("Create User Data Start");
    for(ret_cnt = 0, status = FIDOSTATUS_FAILED; (ret_cnt < 3) && (status != FIDOSTATUS_SUCCESS); ret_cnt++) {
        status = createUserdata(cn, in_signalgandencoding, in_publickeyalgandencoding, p_in_keyhandleaccesstoken, in_keyhandleaccesstoken_len,
						    p_in_username, in_username_len, p_in_appid, in_appid_len, p_output, &p_output_len);
    }
    if(status != FIDOSTATUS_SUCCESS) {
        return FIDOSTATUS_ESE_FAILED;
    }
    LOGD("     *********     Create User Data Ends     *********     ");
    //hex_print_tag("FIDO", p_output, p_output_len);

    krd_idx = p_output_idx = asrt_idx = 0;

    // make krd
    krd[krd_idx++] = 0x3E;
    krd[krd_idx++] = 0x03;
    // reserved for len
    krd[krd_idx++] = 0x00;
    krd[krd_idx++] = 0x00;

    // aaid
    krd[krd_idx++] = 0x2E;
    krd[krd_idx++] = 0x0B;
    lentobyte(krd, in_aaid_len, krd_idx);
    krd_idx += 2;

    memcpy(&krd[krd_idx], p_in_aaid, in_aaid_len);
    krd_idx += in_aaid_len;

    LOGD("make assertion info");
        // make assertion info
        // tag
        assertioninfo[asrt_idx++] = 0x2E;
        assertioninfo[asrt_idx++] = 0x0E;
        // len
        assertioninfo[asrt_idx++] = 0x00;
        assertioninfo[asrt_idx++] = 0x07;

        // auth ver len
        tmp_len = bytetolen(p_output, p_output_idx);
        p_output_idx += 2;
        // auth ver
        memcpy(&assertioninfo[asrt_idx], &p_output[p_output_idx], tmp_len);
        asrt_idx += tmp_len;
        p_output_idx += tmp_len;

        // auth mode
        assertioninfo[asrt_idx++] = 0x01;

        // sign algorithm
        lentobyte(assertioninfo, in_signalgandencoding, asrt_idx);
        asrt_idx += 2;

        // pub key algorithm
        lentobyte(assertioninfo, in_publickeyalgandencoding, asrt_idx);
        asrt_idx += 2;

    //LOGD("assertion info : %d", asrt_idx);
    //hex_print_tag("FIDO", assertioninfo, asrt_idx);

    // copy assertion info to krd
    memcpy(&krd[krd_idx], assertioninfo, asrt_idx);
    krd_idx += asrt_idx;

    // hash
    // tag
    krd[krd_idx++] = 0x2E;
    krd[krd_idx++] = 0x0A;
    // len
    lentobyte(krd, in_finalchallengehash_len, krd_idx);
    krd_idx += 2;
    // copy hash to krd
    memcpy(&krd[krd_idx], p_in_finalchallengehash, in_finalchallengehash_len);
    krd_idx += in_finalchallengehash_len;

    // keyid counter pubkey
        // keyid tag
        krd[krd_idx++] = 0x2E;
        krd[krd_idx++] = 0x09;
        // keyid len
        memcpy(&krd[krd_idx], &p_output[p_output_idx], 2);
        tmp_len = bytetolen(p_output, p_output_idx);
        krd_idx      += 2;
        p_output_idx += 2;
        // keyid
        memcpy(&krd[krd_idx], &p_output[p_output_idx], tmp_len);
        krd_idx         += tmp_len;
        p_output_idx   += tmp_len;

        // counter tag
        krd[krd_idx++] = 0x2E;
        krd[krd_idx++] = 0x0D;
        // counter len
        memcpy(&krd[krd_idx], &p_output[p_output_idx], 2);
        tmp_len = bytetolen(p_output, p_output_idx);
        krd_idx      += 2;
        p_output_idx += 2;
        // counter
        memcpy(&krd[krd_idx], &p_output[p_output_idx], tmp_len);
        krd_idx         += tmp_len;
        p_output_idx   += tmp_len;

        // pub key tag
        krd[krd_idx++] = 0x2E;
        krd[krd_idx++] = 0x0C;
        // pub key len
        memcpy(&krd[krd_idx], &p_output[p_output_idx], 2);
        tmp_len = bytetolen(p_output, p_output_idx);
        krd_idx      += 2;
        p_output_idx += 2;
        // pub key
        memcpy(&krd[krd_idx], &p_output[p_output_idx], tmp_len);
        krd_idx         += tmp_len;
        p_output_idx   += tmp_len;

    // krd_idx == length of krd
    lentobyte(krd, (krd_idx - 4), 2);
    //hex_print_tag("FIDO KRD", krd, krd_idx);
    p_output_len = 0;
    memset(p_output, 0, FIDO_MAX_LEN);

    for(ret_cnt = 0, status = FIDOSTATUS_FAILED; (ret_cnt < 3) && (status != FIDOSTATUS_SUCCESS); ret_cnt++) {
        status = fido_getAttestationBasicFull(cn, in_signalgandencoding, p_in_aaid, in_aaid_len, krd, krd_idx, p_output, &p_output_len);
    } // p_output = attestation basic full

    tmp_len = 0;
    // uafv1_reg_assertion
    uafv1_reg_assertion[tmp_len++] = 0x3E;
    uafv1_reg_assertion[tmp_len++] = 0x01;
    uafv1_reg_assertion[tmp_len++] = 0x00;
    uafv1_reg_assertion[tmp_len++] = 0x00;
    memcpy(&uafv1_reg_assertion[tmp_len], krd, krd_idx);
    tmp_len += krd_idx;
    memcpy(&uafv1_reg_assertion[tmp_len], p_output, p_output_len);
    tmp_len += p_output_len;
    // (tmp len - 4) = data len of reg assertion
    lentobyte(uafv1_reg_assertion, (tmp_len - 4), 2);
    // this tmp len = total len of reg assertion
/*    if(tmp_len > 255) {
        int l;
        for(l = 1; (l - 1) * 255 <= tmp_len; l++) {
            LOGD("FIDO %d th reg assert", l);
            if((l*255) < tmp_len) hex_print_tag("FIDO reg asrt", &uafv1_reg_assertion[(l-1)*255], 255);
            else hex_print_tag("FIDO reg asrt", &uafv1_reg_assertion[(l-1)*255], (tmp_len - (l-1)*255));
        }
    }
    else hex_print_tag("FIDO reg assertion", uafv1_reg_assertion, tmp_len);*/

    // auth assertion
    p_out_tlvregisterresponse[0] = 0x28;
    p_out_tlvregisterresponse[1] = 0x0F;
    lentobyte(p_out_tlvregisterresponse, tmp_len, 2);
    // auth_assertion_len = uafv1_reg_assertion_len + 4(tag + len)
    // this tmp len = data len of auth assertion
    memcpy(&p_out_tlvregisterresponse[4], uafv1_reg_assertion, tmp_len);
    tmp_len += 4;
    LOGD("fido auth assertion, len = %d", tmp_len);
    // this tmp len = total len of auth assertion
    /*if(tmp_len > 255) {
        int l;
        for(l = 1; (l-1)*255 <= tmp_len; l++) {
            LOGD("FIDO %d st assert", l);
            if((l*255) <= tmp_len) hex_print_tag("FIDO", &p_out_tlvregisterresponse[(l-1)*255], 255);
            else hex_print_tag("FIDO", &p_out_tlvregisterresponse[(l-1)*255], (tmp_len - (l-1)*255));
        }
    }
    else hex_print_tag("FIDO auth assertion", p_out_tlvregisterresponse, tmp_len);
*/
    secEseClose(cn);

    LOGD("     *********     FIDO Register Ends     *********");

    return FIDOSTATUS_SUCCESS;
}

FIDOSTATUS fido_getCounters(uint8_t cn, uint16_t in_signalgandencoding,
                                        uint8_t* p_output, uint16_t* p_output_len) {
    // ins 02 or c2(2nd~) p1 11
    ESESTATUS			status;
	secEse_7816_cpdu_t	cur_cmd;
	secEse_7816_rpdu_t	cur_rsp;
	uint8_t cmd_data[MAX_CAPDU_DATA_SIZE];
	uint8_t rsp_data[MAX_RAPDU_DATA_SIZE];

    LOGD("     *********     FIDO getCounters is called     *********     ");

    cur_cmd.pdata = cmd_data;
    cur_cmd.cpdu_type = cShortAPDU;
    cur_cmd.le_type = rShortAPDU;
    cur_cmd.le = 0x00;
	cur_rsp.pdata = rsp_data;

	cur_cmd.cla = (0x00 & cn);
    cur_cmd.ins = 0x02;
    cur_cmd.lc = 0;

	if(in_signalgandencoding == 0x0001) {		// 0x0001 = ecdsa
		cur_cmd.p1 = 0x11;
	}
	else if(in_signalgandencoding == 0x0003) {	// 0x0003 = rsa
		cur_cmd.p1 = 0x01;
	}
	else {
		return FIDOSTATUS_INVALID_SIGNALGO;
	}
    cur_cmd.p2 = 0x00;
    LOGD("getCounters transmit");
	status = secEseTransmit( cn, &cur_cmd, &cur_rsp );

    if( status != ESESTATUS_SUCCESS) {
	    LOGE("Cannot Communicate eSE. ESESTATUS = 0x%08X", status);
        return FIDOSTATUS_ESE_FAILED;
	}
    hex_print_tag("FIDO getCounters transmit return", cur_rsp.pdata, cur_rsp.len);
    memcpy(p_output, cur_rsp.pdata, cur_rsp.len);
    *p_output_len = cur_rsp.len;

    return FIDOSTATUS_SUCCESS;
}

FIDOSTATUS fido_getSignature(uint8_t cn, uint8_t* p_in_keyid, uint16_t in_keyid_len,
                                            uint8_t* p_in_signedData, uint16_t in_signedData_len, uint16_t in_signalgandencoding,
                                            uint8_t* p_output, uint16_t* p_output_len) {
    // ins 02 p1 12
     ESESTATUS			status;
	secEse_7816_cpdu_t	cur_cmd;
	secEse_7816_rpdu_t	cur_rsp;
	uint8_t cmd_data[MAX_CAPDU_DATA_SIZE] = {0,};
	uint8_t rsp_data[MAX_RAPDU_DATA_SIZE] = {0,};
    uint8_t TLV[1000] = {0,};
    uint16_t TLV_idx = 0;

    LOGD("     *********     FIDO getSignature is called     *********     ");

    cur_cmd.pdata = cmd_data;
    cur_cmd.cpdu_type = cShortAPDU;
    cur_cmd.le_type = rShortAPDU;
    cur_cmd.le = 0x00;
    cur_cmd.p2 = 0x00;
	cur_rsp.pdata = rsp_data;

	cur_cmd.cla = (0x00 & cn);
    cur_cmd.ins = 0x02;
    cur_cmd.lc = 0;

	if(in_signalgandencoding == 0x0001) {		// 0x0001 = ecdsa
		cur_cmd.p1 = 0x12;
	}
	else if(in_signalgandencoding == 0x0003) {	// 0x0003 = rsa
		cur_cmd.p1 = 0x02;
	}
	else {
		return FIDOSTATUS_INVALID_SIGNALGO;
	}
    TLV_idx = 0;

    TLV[TLV_idx++] = 0xE0;
    lentobyte(TLV, in_keyid_len, TLV_idx);
    TLV_idx += 2;

    memcpy(&TLV[TLV_idx], p_in_keyid, in_keyid_len);
    TLV_idx += in_keyid_len;

    TLV[TLV_idx++] = 0xE1;
    lentobyte(TLV, in_signedData_len, TLV_idx);
    TLV_idx += 2;
    memcpy(&TLV[TLV_idx], p_in_signedData, in_signedData_len);
    TLV_idx += in_signedData_len;

    memcpy(cur_cmd.pdata, TLV, TLV_idx);
    cur_cmd.lc = TLV_idx;


    //hex_print_tag("FIDO getSignature transmit input", cur_cmd.pdata, cur_cmd.lc);

    LOGD("getSignature transmit starts");
	status = secEseTransmit( cn, &cur_cmd, &cur_rsp );

    if( status != ESESTATUS_SUCCESS) {
	    LOGE("Cannot Communicate eSE. ESESTATUS = 0x%08X", status);
        return FIDOSTATUS_ESE_FAILED;
	}

    hex_print_tag("FIDO getSignature transmit return", cur_rsp.pdata, cur_rsp.len);
    memcpy(p_output, cur_rsp.pdata, cur_rsp.len);
    *p_output_len = cur_rsp.len;


    return FIDOSTATUS_SUCCESS;
}

uint16_t fido_getUserlistCount(uint8_t cn, uint8_t* p_in_appid, uint16_t in_appid_len,
                                                uint8_t* p_in_keyhandleaccesstoken, uint16_t in_keyhandleaccesstoken_len,
                                                uint16_t in_signalgandencoding) {
    ESESTATUS			status;
	secEse_7816_cpdu_t	cur_cmd;
	secEse_7816_rpdu_t	cur_rsp;
	uint8_t cmd_data[MAX_CAPDU_DATA_SIZE];
	uint8_t rsp_data[MAX_RAPDU_DATA_SIZE];
    uint8_t inputData[FIDO_MAX_LEN];
    uint16_t inputLen = 0;

    LOGD("     *********     getUserlistCount is called     *********     ");

    cur_cmd.pdata = cmd_data;
    cur_cmd.cpdu_type = cShortAPDU;
    cur_cmd.le_type = rShortAPDU;
    cur_cmd.le = 0x00;
	cur_rsp.pdata = rsp_data;

	cur_cmd.cla = (0x00 & cn);
    cur_cmd.ins = 0x02;

	if(in_signalgandencoding == 0x0001) {		// 0x0001 = ecdsa
		cur_cmd.p1 = 0x13;
	}
	else if(in_signalgandencoding == 0x0003) {	// 0x0003 = rsa
		cur_cmd.p1 = 0x03;
	}
	else {
		return FIDOSTATUS_INVALID_SIGNALGO;
	}
    cur_cmd.p2 = 0x00;

    inputLen = 0;
    inputData[inputLen++] = 0xE0;
    lentobyte(inputData, in_appid_len, inputLen);
    inputLen += 2;
    memcpy(&inputData[inputLen], p_in_appid, in_appid_len);
    inputLen += in_appid_len;

    inputData[inputLen++] = 0xE1;
    lentobyte(inputData, in_keyhandleaccesstoken_len, inputLen);
    inputLen += 2;
    memcpy(&inputData[inputLen], p_in_keyhandleaccesstoken, in_keyhandleaccesstoken_len);
    inputLen += in_keyhandleaccesstoken_len;

    memcpy(cur_cmd.pdata, inputData, inputLen);
    cur_cmd.lc = inputLen;

    LOGD("getUserlistCount transmit");
	status = secEseTransmit( cn, &cur_cmd, &cur_rsp );

    if( status != ESESTATUS_SUCCESS) {
	    LOGE("Cannot Communicate eSE. ESESTATUS = 0x%08X", status);
        return FIDOSTATUS_ESE_FAILED;
	}

    return bytetolen(cur_rsp.pdata, 0);

}

FIDOSTATUS fido_getMoreUserlist(uint8_t cn, uint16_t index, uint8_t* p_in_appid, uint16_t in_appid_len,
                                                uint8_t* p_in_keyhandleaccesstoken, uint16_t in_keyhandleaccesstoken_len,
                                                uint16_t in_signalgandencoding, uint8_t* p_output, uint16_t* p_output_len) {
    ESESTATUS			status;
	secEse_7816_cpdu_t	cur_cmd;
	secEse_7816_rpdu_t	cur_rsp;
	uint8_t cmd_data[MAX_CAPDU_DATA_SIZE];
	uint8_t rsp_data[MAX_RAPDU_DATA_SIZE];
    uint8_t inputData[FIDO_MAX_LEN];
    uint16_t inputLen = 0;

    LOGD("     *********     FIDO getMoreUserlist is called     *********     ");

    cur_cmd.pdata = cmd_data;
    cur_cmd.cpdu_type = cShortAPDU;
    cur_cmd.le_type = rShortAPDU;
    cur_cmd.le = 0x00;
	cur_rsp.pdata = rsp_data;

	cur_cmd.cla = (0x00 & cn);
    cur_cmd.ins = 0x02;

	if(in_signalgandencoding == 0x0001) {		// 0x0001 = ecdsa
		cur_cmd.p1 = 0x14;
	}
	else if(in_signalgandencoding == 0x0003) {	// 0x0003 = rsa
		cur_cmd.p1 = 0x04;
	}
	else {
		return FIDOSTATUS_INVALID_SIGNALGO;
	}
    cur_cmd.p2 = 0x00;

    lentobyte(inputData, index, 0);
    inputLen += 2;

    inputData[inputLen++] = 0xE0;
    lentobyte(inputData, in_appid_len, inputLen);
    inputLen += 2;
    memcpy(&inputData[inputLen], p_in_appid, in_appid_len);
    inputLen += in_appid_len;

    inputData[inputLen++] = 0xE1;
    lentobyte(inputData, in_keyhandleaccesstoken_len, inputLen);
    inputLen += 2;
    memcpy(&inputData[inputLen], p_in_keyhandleaccesstoken, in_keyhandleaccesstoken_len);
    inputLen += in_keyhandleaccesstoken_len;

    memcpy(cur_cmd.pdata, inputData, inputLen);
    cur_cmd.lc = inputLen;

    LOGD("getMoreUserlist transmit %02x%02x%02x%02x%02x", cur_cmd.cla, cur_cmd.ins, cur_cmd.p1, cur_cmd.p2, cur_cmd.lc);

    memset(p_output, 0, 256);
    *p_output_len = 0;

    cur_rsp.sw1 = cur_rsp.sw2 = 0x00;
    do {

        if(cur_rsp.sw1 == 0x61 || cur_rsp.sw1 == 0x63) {
            LOGD("return data remains");
            cur_cmd.ins = 0xC2;
            cur_cmd.pdata[0] = 0x01;
            cur_cmd.le = cur_rsp.sw2;
            cur_cmd.lc = 1;
            memset(cur_rsp.pdata, 0, 256);
        }
        status = secEseTransmit( cn, &cur_cmd, &cur_rsp );

        if( status != ESESTATUS_SUCCESS) {
            LOGE("Cannot Communicate eSE. ESESTATUS = 0x%08X", status);
            return FIDOSTATUS_ESE_FAILED;
        }
        if(cur_rsp.sw1 == 0x00 && cur_rsp.sw2 == 0x03) {
            LOGE("UAF_CMD_STATUS_USER_NOT_ENROLLED!");
            return FIDOSTATUS_INVALID_USERNAME;
        }
        //hex_print_tag("FIDO getMoreUserlist transmit return", cur_rsp.pdata, cur_rsp.len);
        memcpy(&p_output[*p_output_len], cur_rsp.pdata, cur_rsp.len);
        *p_output_len += cur_rsp.len;
    }while( cur_rsp.sw1 == 0x61 || cur_rsp.sw1 == 0x63);

    LOGD("getUserlistCount transmit ends");
    if(cur_rsp.sw1 == 0x90 && cur_rsp.sw2 == 0x00)
        return FIDOSTATUS_SUCCESS;

    return FIDOSTATUS_ESE_FAILED;
}



FIDOSTATUS fido_sign (uint8_t* p_in_aaid, uint16_t in_aaid_len,
					uint8_t* p_in_appid, uint16_t in_appid_len,
					uint8_t* p_in_finalchallengehash, uint16_t in_finalchallengehash_len,
					uint8_t* p_in_transactioncontenthash, uint16_t in_transactioncontenthash_len,
					uint8_t* p_in_keyhandleaccesstoken , uint16_t in_keyhandleaccesstoken_len,
					uint8_t* p_in_keyid , uint16_t in_keyid_len,
					uint8_t in_authenticationmode, uint16_t in_signalgandencoding,
					uint8_t* p_in_authenticatornonce , uint16_t in_authenticatornonce_len,
					uint8_t* p_out_tlvsignresponse, uint16_t* p_out_tlvsignresponse_len) {
	ESESTATUS			status;
	secEse_7816_rpdu_t	cur_rsp;
	uint8_t rsp_data[MAX_RAPDU_DATA_SIZE], signedData[FIDO_MAX_LEN];
	uint8_t channel = 0x01;
	uint16_t TLV_idx = 0, tmpLen = 0, signedDataLen = 0;
	uint8_t fido_aid[] = {0xA0, 0x00, 0x00, 0x06, 0x47, 0xAF, 0x00, 0x01}, TLV[FIDO_MAX_LEN], tmp[200];
    uint8_t cn = 0x00;

    LOGI("FIDO UAF LIB VER : %s", FIDO_UAF_LIB_VER);
    LOGD("     *********     FIDO Sign starts     *********     ");

    status = secEseOpen(&cn);
	if (status != ESESTATUS_SUCCESS) {
        LOGE("FIDO Sign channel open fail");
        secEseClose(cn);
		return FIDOSTATUS_ESE_CHANNEL_OPEN_FAILED;
    }
    cur_rsp.pdata = rsp_data;

    LOGD("FIDO applet selected for sign");
    secEseSelect(cn, fido_aid, 0, 8, &cur_rsp);

    if(cur_rsp.sw1 != 0x90) {
        LOGE("FIDO applet select error : %x %x", cur_rsp.sw1, cur_rsp.sw2);
        secEseClose(cn);
        return FIDOSTATUS_ESE_FAILED;
    }
    memset(cur_rsp.pdata, 0, cur_rsp.len);

	TLV_idx = 0;
	// if keyid is NULL, all of key handle access tokens and usernames will be returned
	if(p_in_keyid == NULL && in_keyid_len == 0) {
        uint16_t userListCount = 0, userListIndex = 0;

        if(p_in_keyhandleaccesstoken == NULL ) {
            LOGE("     *********     Token is NULL     *********     ");
            return FIDOSTATUS_INVALID_TOKEN;
        }
        if(in_keyhandleaccesstoken_len <= 0) {
            LOGE("     *********     Invalid TOKEN length    *********     ");
            return FIDOSTATUS_WRONG_TOKEN_LEN;
        }

        if(p_in_appid == NULL ) {
            LOGE("     *********     APPID is NULL     *********     ");
            return FIDOSTATUS_INVALID_APPID;
        }
        if(in_appid_len <= 0) {
            LOGE("     *********     Invalid APPID length    *********     ");
            return FIDOSTATUS_WRONG_APPID_LEN;
        }

		userListCount = fido_getUserlistCount(cn, p_in_appid, in_appid_len,
            p_in_keyhandleaccesstoken, in_keyhandleaccesstoken_len, in_signalgandencoding);

        LOGD("     *********     FIDO getUserlistCount Ends     *********     ");


        //LOGD("FIDO userlist count = %02x", userListCount);
        userListIndex = 0x7FFF;

        while(userListCount--) {
            int i = 100;
            fido_getMoreUserlist(cn, userListIndex, p_in_appid, in_appid_len,
                p_in_keyhandleaccesstoken, in_keyhandleaccesstoken_len, in_signalgandencoding, tmp, &tmpLen);
            memcpy(&TLV[TLV_idx], tmp, tmpLen);
            userListIndex = bytetolen(tmp,0);
            //LOGD("Userlist index = %d", userListIndex);
            //hex_print_tag("FIDO userlist", tmp, tmpLen);
            TLV_idx += tmpLen;
            if(i-- < 0) break;
        }
        LOGD("     *********     FIDO getMoreUserlist Ends     *********     ");
	}
	// if keyid is NOT NULL, matching key handle access token and username will be returned
	else if(p_in_keyid != NULL && in_keyid_len != 0) {
        memset(tmp, 0, 200);
        tmpLen = 0;

        fido_getCounters(cn, in_signalgandencoding, tmp, &tmpLen);
        LOGD("     *********     FIDO getCounter Ends     *********     ");

        signedDataLen = 0;

        // TAG UAFV1 SIGNED DATA
        signedData[signedDataLen++] = 0x3E;
        signedData[signedDataLen++] = 0x04;
        signedData[signedDataLen++] = 0x00;
        signedData[signedDataLen++] = 0x00;

        // TAG AAID
        signedData[signedDataLen++] = 0x2E;
        signedData[signedDataLen++] = 0x0B;
        lentobyte(signedData, in_aaid_len, signedDataLen);
        signedDataLen +=2;
        memcpy(&signedData[signedDataLen], p_in_aaid, in_aaid_len);
        signedDataLen += in_aaid_len;

        // TAG Assertion INFO
        signedData[signedDataLen++] = 0x2E;
        signedData[signedDataLen++] = 0x0E;
        signedData[signedDataLen++] = 0x00;
        signedData[signedDataLen++] = 0x05;

            // authnr ver / mode / signalgandencoding
            signedData[signedDataLen++] = 0x00;
            signedData[signedDataLen++] = 0x01;
            signedData[signedDataLen++] = in_authenticationmode;
            lentobyte(signedData, in_signalgandencoding, signedDataLen);
            signedDataLen += 2;

        // authner nonce from TZ
        signedData[signedDataLen++] = 0x2E;
        signedData[signedDataLen++] = 0x0F;
        lentobyte(signedData, in_authenticatornonce_len, signedDataLen);
        signedDataLen+=2;
        memcpy(&signedData[signedDataLen], p_in_authenticatornonce, in_authenticatornonce_len);
        signedDataLen += in_authenticatornonce_len;

        // final challenge hash
        signedData[signedDataLen++] = 0x2E;
        signedData[signedDataLen++] = 0x0A;
        lentobyte(signedData, in_finalchallengehash_len, signedDataLen);
        signedDataLen+=2;
        memcpy(&signedData[signedDataLen], p_in_finalchallengehash, in_finalchallengehash_len);
        signedDataLen += in_finalchallengehash_len;

        // tc contect hash
        signedData[signedDataLen++] = 0x2E;
        signedData[signedDataLen++] = 0x10;
        if(in_authenticationmode == 0x02) { // authmode == 0x02 -> data >= 1
            lentobyte(signedData, in_transactioncontenthash_len, signedDataLen);
            signedDataLen+=2;
            memcpy(&signedData[signedDataLen], p_in_transactioncontenthash, in_transactioncontenthash_len);
            signedDataLen += in_transactioncontenthash_len;
        }
        else if(in_authenticationmode == 0x01) {
            signedData[signedDataLen++] = 0x00;
            signedData[signedDataLen++] = 0x00;
        }
        else {
            LOGE("auth mode error");
            secEseClose(cn);
            return FIDOSTATUS_INVALID_AUTH_MODE;
        }

        // keyid
        signedData[signedDataLen++] = 0x2E;
        signedData[signedDataLen++] = 0x09;
        lentobyte(signedData, in_keyid_len, signedDataLen);
        signedDataLen+=2;
        memcpy(&signedData[signedDataLen], p_in_keyid, in_keyid_len);
        signedDataLen += in_keyid_len;

        // tag_counter
        signedData[signedDataLen++] = 0x2E;
        signedData[signedDataLen++] = 0x0D;
        memcpy(&signedData[signedDataLen], tmp, tmpLen);
        signedDataLen += tmpLen;

        //signedData length set
        lentobyte(signedData, (signedDataLen - 4), 2);
        TLV_idx = 0;

        // tlv sign response
        TLV[TLV_idx++] = 0x28;
        TLV[TLV_idx++] = 0x0F;
        TLV[TLV_idx++] = 0x00;
        TLV[TLV_idx++] = 0x00;
            // tlv sign response - auth assertion
            TLV[TLV_idx++] = 0x3E;
            TLV[TLV_idx++] = 0x02;
            lentobyte(TLV, signedDataLen, TLV_idx);
            TLV_idx += 2;
            memcpy(&TLV[TLV_idx], signedData, signedDataLen);
            TLV_idx += signedDataLen;
            memset(tmp, 0, 200);

            // get signature
            fido_getSignature(cn, p_in_keyid, in_keyid_len, signedData, signedDataLen, in_signalgandencoding, tmp, &tmpLen);
            LOGD("     *********     FIDO getSignature Ends     *********     ");

            memcpy(&TLV[TLV_idx], tmp, tmpLen);
            TLV_idx += tmpLen;
            lentobyte(TLV, (TLV_idx - 4), 2);
	}
	else {
        secEseClose(cn);
		return FIDOSTATUS_INVALID_ARGUMENTS;
	}

    memcpy(p_out_tlvsignresponse, TLV, TLV_idx);
    *p_out_tlvsignresponse_len = TLV_idx;

/*    if(TLV_idx > 255) {
        int l;
        for(l = 1; (l - 1) * 255 <= TLV_idx; l++) {
            LOGD("FIDO %d th sign result", l);
            if((l*255) < TLV_idx) hex_print_tag("FIDO sign asrt", &TLV[(l-1)*255], 255);
            else hex_print_tag("FIDO sign result", &TLV[(l-1)*255], (TLV_idx - (l-1)*255));
        }
    }
    else hex_print_tag("FIDO sign assertion", TLV, TLV_idx);
    */

	secEseClose(cn);
	return FIDOSTATUS_SUCCESS;
}

FIDOSTATUS fido_deregister (uint8_t* p_in_appid, uint16_t in_appid_len,
						uint8_t* p_in_keyid, uint16_t in_keyid_len,
						uint8_t* p_in_keyhandleaccesstoken, uint16_t in_keyhandleaccesstoken_len,
						uint8_t* p_out_tlvderegisterresponse, uint16_t* p_out_tlvderegisterresponse_len) {
	ESESTATUS			status;
	secEse_7816_cpdu_t	cur_cmd;
	secEse_7816_rpdu_t	cur_rsp;
	uint8_t cmd_data[MAX_CAPDU_DATA_SIZE],  rsp_data[MAX_RAPDU_DATA_SIZE];
	uint8_t cn = 0x00;

    uint8_t TLV[FIDO_MAX_LEN], fido_aid[] = {0xA0, 0x00, 0x00, 0x06, 0x47, 0xAF, 0x00, 0x01};
    uint16_t TLV_idx = 0;

	cur_cmd.cpdu_type = cShortAPDU;
    cur_cmd.le_type = rShortAPDU;
    cur_cmd.le = 0x00;
	cur_rsp.pdata = rsp_data;
    cur_cmd.pdata = cmd_data;

	cur_cmd.cla = (0x00 & cn);
    cur_cmd.ins = 0x03;
	cur_cmd.p1 = 0x00;
    cur_cmd.p2 = 0x00;

    TLV_idx = 0;
    LOGI("FIDO UAF LIB VER : %s", FIDO_UAF_LIB_VER);
    LOGD("     *********     FIDO deregi Starts     *********     ");
	if(p_in_keyid != NULL && p_in_keyhandleaccesstoken != NULL) {
        LOGD("key id exist");
        // key id & kh token
        cur_cmd.p1 = 0x11;
        TLV[TLV_idx++] = 0xE0;
        lentobyte(TLV, in_keyid_len, TLV_idx);
        TLV_idx += 2;
        memcpy(&TLV[TLV_idx], p_in_keyid, in_keyid_len);
        TLV_idx += in_keyid_len;

        TLV[TLV_idx++] = 0xE1;
        lentobyte(TLV, in_keyhandleaccesstoken_len, TLV_idx);
        TLV_idx += 2;
        memcpy(&TLV[TLV_idx], p_in_keyhandleaccesstoken, in_keyhandleaccesstoken_len);
        TLV_idx += in_keyhandleaccesstoken_len;
	}
    else if( p_in_appid != NULL && p_in_keyhandleaccesstoken != NULL) {
        LOGD("app id exist");
        // app id & kh token
        cur_cmd.p1 = 0x12;
        TLV[TLV_idx++] = 0xE0;
        lentobyte(TLV, in_appid_len, TLV_idx);
        TLV_idx += 2;
        memcpy(&TLV[TLV_idx], p_in_appid, in_appid_len);
        TLV_idx += in_appid_len;

        TLV[TLV_idx++] = 0xE1;
        lentobyte(TLV, in_keyhandleaccesstoken_len, TLV_idx);
        TLV_idx += 2;
        memcpy(&TLV[TLV_idx], p_in_keyhandleaccesstoken, in_keyhandleaccesstoken_len);
        TLV_idx += in_keyhandleaccesstoken_len;
    }
    else if(p_in_keyhandleaccesstoken != NULL) {
        // kh token only
        LOGD("only kh token exist");
        cur_cmd.p1 = 0x13;
        TLV[TLV_idx++] = 0xE0;
        lentobyte(TLV, in_keyhandleaccesstoken_len, TLV_idx);
        TLV_idx += 2;
        memcpy(&TLV[TLV_idx], p_in_keyhandleaccesstoken, in_keyhandleaccesstoken_len);
        TLV_idx += in_keyhandleaccesstoken_len;
    }
    else {
        return FIDOSTATUS_INVALID_ARGUMENTS;
    }

    memcpy(cur_cmd.pdata, TLV, TLV_idx);
    cur_cmd.lc = TLV_idx;

	status = secEseOpen(&cn);
	if (status != ESESTATUS_SUCCESS) {
        LOGE("fido deregister channel open fail");
        secEseClose(cn);
        return FIDOSTATUS_ESE_CHANNEL_OPEN_FAILED;
	}

    LOGD("FIDO applet is selected for deregister");
    secEseSelect(cn, fido_aid, 0, 8, &cur_rsp);

    if(cur_rsp.sw1 != 0x90) {
        LOGE("FIDO applet select error : %x %x", cur_rsp.sw1, cur_rsp.sw2);
        secEseClose(cn);
        return FIDOSTATUS_ESE_FAILED;
    }

    memset(cur_rsp.pdata, 0, cur_rsp.len);

    LOGD("FIDO dereg transmit starts %02x %02x %02x %d", cur_cmd.ins, cur_cmd.p1, cur_cmd.p2, cur_cmd.lc);
    hex_print_tag("FIDO deregister transmit data", cur_cmd.pdata, cur_cmd.lc);
    status = secEseTransmit( cn, &cur_cmd, &cur_rsp );

    if( status != ESESTATUS_SUCCESS) {
        LOGE("Cannot Communicate eSE. ESESTATUS = 0x%08X", status);
        secEseClose(cn);
        return FIDOSTATUS_ESE_FAILED;
    }

    hex_print_tag("FIDO deregister transmit return", cur_rsp.pdata, cur_rsp.len);

    secEseClose(cn);
    LOGD("     *********     FIDO deregi ends     *********     ");
	return FIDOSTATUS_SUCCESS;
}
/**********************************/

