#include "scpkm.h"
#include "tz_debug.h"

#include "ssp_service.h"
#include "ssp_util.h"

#include "GPCmd.h"
#include "SCP03_transceive.h"
#include "SCP03_crypto.h"
#include "crypto_module.h"

#define SEM_TEST_SERVICE_NAME       "SEM_TEST"
#define SEM_TEST_QSEE_NAME          "sem"
#define SEM_TEST_MC_UUID            {0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b}
#define SEM_TEST_BF_UUID            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x45, 0x4d, 0x65, 0x53, 0x45}
#define SEM_TEST_EXT_ID             {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
#define SEM_TEST_ASSOCIATED_SSD_AID {0xA0, 0x00, 0x00, 0x02, 0x20, 0x19, 0x03, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}

#define UCM_SERVICE_NAME            "UCM"
#define UCM_QSEE_NAME               "esecomm"
#define UCM_MC_UUID                 {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38}
#define UCM_BF_UUID                 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x73, 0x65, 0x63, 0x6f, 0x6d}
#define UCM_EXT_ID                  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
#define UCM_ASSOCIATED_SSD_AID      {0xA0, 0x00, 0x00, 0x02, 0x20, 0x19, 0x03, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}

#define SPAY_CHN_SERVICE_NAME       "SAMSUNG_PAY_CHN"
#define SPAY_CHN_QSEE_NAME          "chncmm_pay"
#define SPAY_CHN_MC_UUID            {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a}
#define SPAY_CHN_BF_UUID            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x48, 0x4E, 0x43, 0x4D, 0x4D}
#define SPAY_CHN_EXT_ID             {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
#define SPAY_CHN_ASSOCIATED_SSD_AID {0xA0, 0x00, 0x00, 0x02, 0x20, 0x19, 0x03, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}

#define DK_SERVICE_NAME             "DIGITAL_KEY"
#define DK_QSEE_NAME                "digital_key"
#define DK_MC_UUID                  {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89}
#define DK_BF_UUID                  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x69, 0x67, 0x69, 0x74, 0x4b}
#define DK_EXT_ID                   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
#define DK_ASSOCIATED_SSD_AID       {0xA0, 0x00, 0x00, 0x02, 0x20, 0x19, 0x03, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05}

#define MDL_SERVICE_NAME            "PASS_ESE"
#define MDL_QSEE_NAME               "passese"
#define MDL_MC_UUID                 {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95}
#define MDL_BF_UUID                 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x70, 0x73, 0x45, 0x53, 0x45}
#define MDL_EXT_ID                  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
#define MDL_ASSOCIATED_SSD_AID      {0xA0, 0x00, 0x00, 0x02, 0x20, 0x20, 0x03, 0x01, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}

#define MDL_TEST_SERVICE_NAME       "MDL_TEST"
#define MDL_TEST_QSEE_NAME          "mdl_test"
#define MDL_TEST_MC_UUID            {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
#define MDL_TEST_BF_UUID            {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x44, 0x4C, 0x54, 0x45, 0x53}
#define MDL_TEST_EXT_ID             {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
#define MDL_TEST_ASSOCIATED_SSD_AID {0xA0, 0x00, 0x00, 0x02, 0x20, 0x20, 0x03, 0x01, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}

key_list_info_t gKeyListInfo[] = {
    {SEM_TEST_SERVICE_NAME,
        SEM_TEST_QSEE_NAME, SEM_TEST_MC_UUID, SEM_TEST_BF_UUID, SEM_TEST_EXT_ID,
        SEM_TEST_ASSOCIATED_SSD_AID},
    {UCM_SERVICE_NAME,
        UCM_QSEE_NAME, UCM_MC_UUID, UCM_BF_UUID, UCM_EXT_ID,
        UCM_ASSOCIATED_SSD_AID},
    {SPAY_CHN_SERVICE_NAME,
        SPAY_CHN_QSEE_NAME, SPAY_CHN_MC_UUID, SPAY_CHN_BF_UUID, SPAY_CHN_EXT_ID,
        SPAY_CHN_ASSOCIATED_SSD_AID},
    {DK_SERVICE_NAME,
        DK_QSEE_NAME, DK_MC_UUID, DK_BF_UUID, DK_EXT_ID,
        DK_ASSOCIATED_SSD_AID},
    {MDL_SERVICE_NAME,
        MDL_QSEE_NAME, MDL_MC_UUID, MDL_BF_UUID, MDL_EXT_ID,
        MDL_ASSOCIATED_SSD_AID},
    {MDL_TEST_SERVICE_NAME,
        MDL_TEST_QSEE_NAME, MDL_TEST_MC_UUID, MDL_TEST_BF_UUID, MDL_TEST_EXT_ID,
        MDL_TEST_ASSOCIATED_SSD_AID},
};

uint32_t gKeyListInfo_size = sizeof(gKeyListInfo) / sizeof(key_list_info_t);
int32_t getKVN30Keyset(uint8_t channelId, const uint8_t *otp_key_blob, uint32_t otp_key_blob_size, uint8_t* outKeySet, uint32_t* outKeySetLen);

int32_t checkSeStateInternal(uint8_t appletAid[MAX_AID_SIZE], uint32_t appletAidLen, uint8_t associatedAid[MAX_AID_SIZE], uint32_t associatedAidLen) {
    uint8_t cn = 0;

    uint8_t scrs_applet[] = {0xA0, 0x00, 0x00, 0x01, 0x51, 0x43, 0x52, 0x53, 0x00};

    uint8_t cData[MAX_CAPDU_DATA_SIZE] = {0,};
    uint8_t rData[MAX_RAPDU_DATA_SIZE] = {0,};
    secEse_7816_cpdu_t cpdu;
    secEse_7816_rpdu_t rpdu;

    uint8_t tag4F[1] = {0x4F};
    uint8_t tag5C[1] = {0x5C};
    uint8_t tag9F70[2] = {0x9F, 0x70};
    uint8_t temp[1] = {0,};

    uint8_t ssd_selectable = FALSE;
    uint8_t ssd_exist = FALSE;
    uint8_t applet_exist = FALSE;
    int32_t result = 0;

    LOGD("checkSeStateInternal start");

    hex_print_tag_debug("appletAid", appletAid, appletAidLen);
    hex_print_tag_debug("associatedAid", associatedAid, associatedAidLen);

    if (ESESTATUS_SUCCESS != secEseOpen(&cn)) {
        LOGE("checkSeState channel open fail");
        result = RET_ERR_CEHCK_SE_STATE;
        goto error2;
    }

    //SELECT SCRS (aid: A00000015143525300)
    memset(&rpdu, 0, sizeof(secEse_7816_rpdu_t));
    rpdu.pdata = rData;
    if (cn < 1 || cn > 3 || ESESTATUS_SUCCESS != secEseSelect(cn, scrs_applet, 0, sizeof(scrs_applet), &rpdu) ) {
        LOGE("checkSeState failed to SELECT scrs_applet");
        hex_print_tag("scrs_applet", scrs_applet, sizeof(scrs_applet));
        result = RET_ERR_CEHCK_SE_STATE;
        goto error;
    }

    memset(&cpdu, 0, sizeof(secEse_7816_cpdu_t));
    memset(&rpdu, 0, sizeof(secEse_7816_rpdu_t));
    memset(cData, 0, MAX_CAPDU_DATA_SIZE);
    memset(rData, 0, MAX_RAPDU_DATA_SIZE);
    rpdu.pdata = rData;

//    * Send GET STATUS with tag '9F70'
//        - 80 F2 40 00 #(4F#(aid of associated SSD)5C#(9F70)) 00
//        - if the first byte of response data right after len of tag 9F70 is '07', then SSD is SELECTABLE

    BUFFER_APPEND( cData, cpdu.lc, tag4F, sizeof(tag4F));
    temp[0] = associatedAidLen;
    BUFFER_APPEND( cData, cpdu.lc, temp, sizeof(temp));
    BUFFER_APPEND( cData, cpdu.lc, associatedAid, associatedAidLen);
    BUFFER_APPEND( cData, cpdu.lc, tag5C, sizeof(tag5C));
    temp[0] = 2;
    BUFFER_APPEND( cData, cpdu.lc, temp, sizeof(temp));
    BUFFER_APPEND( cData, cpdu.lc, tag9F70, sizeof(tag9F70));

    cpdu.cla = 0x80;
    cpdu.ins = 0xF2;
    cpdu.p1 = 0x40;
    cpdu.p2 = 0x00;
    cpdu.pdata = cData;
    cpdu.le_type = 1;

    hex_print_tag_debug("cpdu.pdata", cpdu.pdata, cpdu.lc);

    if (ESESTATUS_SUCCESS != secEseTransmit(cn, &cpdu, &rpdu)) {
        LOGE("checkSeState failed to send APDU GET STATUS of associatedAid");
        result = RET_ERR_CEHCK_SE_STATE;
        goto error;
    }

    if (rpdu.sw1 == 0x90 && rpdu.sw2 == 0x00 && rpdu.len >= 2) {
        hex_print_tag_debug("rpdu.pdata", rpdu.pdata, rpdu.len);
        ssd_exist = TRUE;
        if (rpdu.pdata[rpdu.len - 2] == 0x07) {
            ssd_selectable = TRUE;
        } else {
            if (rpdu.pdata[rpdu.len - 2] == 0x0F) {
                LOGE("PERSO State");
            } else {
                LOGE("Unknown state : 0x%02x", rpdu.pdata[rpdu.len - 2]);
            }
        }
    } else if (rpdu.sw1 == 0x6a && rpdu.sw2 == 0x88) {
        LOGE("There is no associated SSD : sw1 0x6a,sw2 0x88");
    } else {
        LOGE("checkSeState failed. Invalid response : sw1 0x%2x,sw2 0x%2x,datalen %d", rpdu.sw1, rpdu.sw2, rpdu.len);
        result = RET_ERR_CEHCK_SE_STATE;
        goto error;
    }

    memset(&cpdu, 0, sizeof(secEse_7816_cpdu_t));
    memset(&rpdu, 0, sizeof(secEse_7816_rpdu_t));
    memset(cData, 0, MAX_CAPDU_DATA_SIZE);
    memset(rData, 0, MAX_RAPDU_DATA_SIZE);
    rpdu.pdata = rData;

//    * Send GET STATUS with tag '9F70'
//        - 80 F2 40 00 #(4F#(aid of applet)5C#(9F70)) 00
//        - if response status word is 6A88, then applet is absent

    BUFFER_APPEND( cData, cpdu.lc, tag4F, sizeof(tag4F));
    temp[0] = appletAidLen;
    BUFFER_APPEND( cData, cpdu.lc, temp, sizeof(temp));
    BUFFER_APPEND( cData, cpdu.lc, appletAid, appletAidLen);
    BUFFER_APPEND( cData, cpdu.lc, tag5C, sizeof(tag5C));
    temp[0] = 2;
    BUFFER_APPEND( cData, cpdu.lc, temp, sizeof(temp));
    BUFFER_APPEND( cData, cpdu.lc, tag9F70, sizeof(tag9F70));

    cpdu.cla = 0x80;
    cpdu.ins = 0xF2;
    cpdu.p1 = 0x40;
    cpdu.p2 = 0x00;
    cpdu.pdata = cData;
    cpdu.le_type = 1;

    hex_print_tag_debug("cpdu.pdata", cpdu.pdata, cpdu.lc);

    if (ESESTATUS_SUCCESS != secEseTransmit(cn, &cpdu, &rpdu)) {
        LOGE("checkSeState failed to send APDU GET STATUS of appletAid");
        result = RET_ERR_CEHCK_SE_STATE;
        goto error;
    }

    if (rpdu.sw1 == 0x90 && rpdu.sw2 == 0x00 && rpdu.len > 0) {
        applet_exist = TRUE;
        if (rpdu.len > 0) {
            hex_print_tag_debug("rpdu.pdata", rpdu.pdata, rpdu.len);
        }
    } else if (rpdu.sw1 == 0x6a && rpdu.sw2 == 0x88) {
        LOGE("There is no applet : sw1 0x6a,sw2 0x88");
    } else {
        LOGE("checkSeState failed. Invalid response : sw1 0x%2x,sw2 0x%2x,datalen %d", rpdu.sw1, rpdu.sw2, rpdu.len);
        result = RET_ERR_CEHCK_SE_STATE;
        goto error;
    }

//    - result: state of SE(Secure Element)
//      0: associated SSD is SELECTABLE and applet is exist
//      1: associated SSD is SELECTABLE and applet is not exist
//      2: associated SSD is not SELECTABLE and applet is exist
//      3: associated SSD is not SELECTABLE and applet is not exist
//      4: associated SSD is not exist and applet is not exist

    if (ssd_exist == TRUE && ssd_selectable == TRUE && applet_exist== TRUE) {
        result = SSD_SELECTABLE_APPLET_EXIST;
    } else if (ssd_exist == TRUE && ssd_selectable == TRUE && applet_exist == FALSE) {
        result = SSD_SELECTABLE_APPLET_NOT_EXIST;
    } else if (ssd_exist == TRUE && ssd_selectable == FALSE && applet_exist == TRUE) {
        result = SSD_NOT_SELECTABLE_APPLET_EXIST;
    } else if (ssd_exist == TRUE && ssd_selectable == FALSE && applet_exist == FALSE) {
        result = SSD_NOT_SELECTABLE_APPLET_NOT_EXIST;
    } else if (ssd_exist == FALSE && applet_exist == FALSE) {
        result = SSD_NOT_EXIST_APPLET_NOT_EXIST;
    } else if (ssd_exist == FALSE && applet_exist == TRUE) {
        result = SSD_NOT_EXIST_APPLET_EXIST;
    } else {
        LOGE("Threr is not proper state");
        result = RET_ERR_CEHCK_SE_STATE;
        goto error;
    }
    LOGD("state of SE : %d", result);

error:
    if (cn != 0) {
        secEseClose(cn);
    }

error2:
    LOGD("checkSeStateInternal end, returned: %d", result);
    return result;
}

void checkSeState(p_cmd_t cmd, p_rsp_t rsp) {
    uint8_t appletAid[MAX_AID_SIZE] = {0, };
    uint32_t appletAidLen;
    uint8_t associatedAid[MAX_AID_SIZE] = {0, };
    uint32_t associatedAidLen;

    uint32_t offset = 0, inputSize;
    int32_t result = 0;

    LOGD("checkSeState start");
    inputSize = cmd->dataLen;
    if (inputSize > 4 + MAX_AID_SIZE + 4 + MAX_AID_SIZE) {
        LOGE("Input data is over the buffer.");
        rsp->ret = RET_ERR_BUFFER_OVERFLOW;
        goto error;
    }
    if (inputSize == 0) {
        LOGE("Input data is exist");
        rsp->ret = RET_ERR_INVALID_INPUT_PARAMS;
        goto error;
    }

    memcpy(&appletAidLen, cmd->data + offset, 4);
    offset += 4;
    if (appletAidLen > MAX_AID_SIZE) {
        LOGE("appletAid length is over the buffer size");
        rsp->ret = RET_ERR_BUFFER_OVERFLOW;
        goto error;
    }
    memcpy(appletAid, cmd->data + offset, appletAidLen);
    offset += appletAidLen;
    hex_print_tag_debug("appletAid", appletAid, appletAidLen);

    memcpy(&associatedAidLen, cmd->data + offset, 4);
    offset += 4;
    if (associatedAidLen > MAX_AID_SIZE) {
        LOGE("associatedAid length is over the buffer size");
        rsp->ret = RET_ERR_BUFFER_OVERFLOW;
        goto error;
    }
    memcpy(associatedAid, cmd->data + offset, associatedAidLen);
    offset += associatedAidLen;
    hex_print_tag_debug("associatedAid", associatedAid, associatedAidLen);

    result = checkSeStateInternal(appletAid, appletAidLen, associatedAid, associatedAidLen);
    if (result < 0) {
        LOGE("checkSeStateInternal is failed");
        rsp->ret = result;
        goto error;
    } else {
        LOGI("state of SE : %d", result);
    }

    rsp->ret = RET_SUCCESS;
    rsp->status = result;

error:
    LOGD("checkSeState end, returned: %d", rsp->ret);
}

uint8_t genStoreKeyData(uint8_t *storeData, uint8_t maxBuffSize, uint8_t* Key30DEK, uint8_t* KeyENC, uint8_t* KeyMAC, uint8_t* KeyDEK) {
    uint8_t kcv_input[] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};

    uint8_t data1[] = {0xB9, 0x14, 0x95, 0x01, 0x18, 0x80, 0x01, 0x88, 0x81, 0x01, 0x10, 0x82, 0x01, 0x01, 0x83, 0x01, 0x31, 0x84, 0x03, 0x00, 0x00, 0x00};
    uint8_t data2[] = {0xB9, 0x14, 0x95, 0x01, 0x14, 0x80, 0x01, 0x88, 0x81, 0x01, 0x10, 0x82, 0x01, 0x02, 0x83, 0x01, 0x31, 0x84, 0x03, 0x00, 0x00, 0x00};
    uint8_t data3[] = {0xB9, 0x14, 0x95, 0x01, 0x48, 0x80, 0x01, 0x88, 0x81, 0x01, 0x10, 0x82, 0x01, 0x03, 0x83, 0x01, 0x31, 0x84, 0x03, 0x00, 0x00, 0x00};
    uint8_t data4[] = {0x81, 0x13, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
                       0x81, 0x13, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                       0x81, 0x13, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    uint8_t fullKcv1[AES_128_KEY_SIZE] = {0, };
    uint8_t fullKcv2[AES_128_KEY_SIZE] = {0, };
    uint8_t fullKcv3[AES_128_KEY_SIZE] = {0, };

    uint8_t cipheredKeyEnc[AES_128_KEY_SIZE] = {0, };
    uint8_t cipheredKeyMac[AES_128_KEY_SIZE] = {0, };
    uint8_t cipheredKeyDek[AES_128_KEY_SIZE] = {0, };

    uint8_t offset = 0;

    scp03_aes_encrypt(KeyENC, kcv_input, sizeof(kcv_input), fullKcv1, NULL, NO_PADDING);
    scp03_aes_encrypt(KeyMAC, kcv_input, sizeof(kcv_input), fullKcv2, NULL, NO_PADDING);
    scp03_aes_encrypt(KeyDEK, kcv_input, sizeof(kcv_input), fullKcv3, NULL, NO_PADDING);
    hex_print_tag_debug("fullKcv1", fullKcv1, AES_128_KEY_SIZE);
    hex_print_tag_debug("fullKcv2", fullKcv2, AES_128_KEY_SIZE);
    hex_print_tag_debug("fullKcv3", fullKcv3, AES_128_KEY_SIZE);

    memcpy(data1 + sizeof(data1) - 3,  fullKcv1, 3);
    memcpy(data2 + sizeof(data2) - 3,  fullKcv2, 3);
    memcpy(data3 + sizeof(data3) - 3,  fullKcv3, 3);
    hex_print_tag_debug("data1", data1, sizeof(data1));
    hex_print_tag_debug("data2", data2, sizeof(data2));
    hex_print_tag_debug("data3", data3, sizeof(data3));

    scp03_aes_encrypt(Key30DEK, KeyENC, AES_128_KEY_SIZE, cipheredKeyEnc, NULL, NO_PADDING);
    scp03_aes_encrypt(Key30DEK, KeyMAC, AES_128_KEY_SIZE, cipheredKeyMac, NULL, NO_PADDING);
    scp03_aes_encrypt(Key30DEK, KeyDEK, AES_128_KEY_SIZE, cipheredKeyDek, NULL, NO_PADDING);
    hex_print_tag_debug("cipheredKeyEnc", cipheredKeyEnc, sizeof(cipheredKeyEnc));
    hex_print_tag_debug("cipheredKeyMac", cipheredKeyMac, sizeof(cipheredKeyMac));
    hex_print_tag_debug("cipheredKeyDek", cipheredKeyDek, sizeof(cipheredKeyDek));

    memcpy(data4 + 3, cipheredKeyEnc, AES_128_KEY_SIZE);
    memcpy(data4 + 3 + AES_128_KEY_SIZE + 3, cipheredKeyMac, AES_128_KEY_SIZE);
    memcpy(data4 + 3 + AES_128_KEY_SIZE + 3 + AES_128_KEY_SIZE + 3, cipheredKeyDek, AES_128_KEY_SIZE);
    hex_print_tag_debug("data4", data4, sizeof(data4));

    storeData[offset++] = 0x00;
    storeData[offset++] = 0xB9;
    storeData[offset++] = sizeof(data1) + sizeof(data2) + sizeof(data3);
    if (offset +  sizeof(data1) > maxBuffSize) {
        LOGE("Buffer is not enough");
        return 0;
    }
    memcpy(storeData + offset, data1, sizeof(data1));
    offset += sizeof(data1);
    if (offset +  sizeof(data2) > maxBuffSize) {
        LOGE("Buffer is not enough");
        return 0;
    }
    memcpy(storeData + offset, data2, sizeof(data2));
    offset += sizeof(data2);
    if (offset +  sizeof(data3) > maxBuffSize) {
        LOGE("Buffer is not enough");
        return 0;
    }
    memcpy(storeData + offset, data3, sizeof(data3));
    offset += sizeof(data3);
    if (offset +  sizeof(data4) > maxBuffSize) {
        LOGE("Buffer is not enough");
        return 0;
    }
    memcpy(storeData + offset, data4, sizeof(data4));
    offset += sizeof(data4);
    
    hex_print_tag_debug("storeData", storeData, offset);

    return offset;    
}

void requestCredentials(p_cmd_t cmd, p_rsp_t rsp) {
    uint8_t cn = 0, i, j;

    uint8_t otp_key_blob[SSP_MAX_WRAPPED_OTP_KEY_SIZE] = {0, };
    uint32_t otp_key_blob_size = 0;

    uint8_t lccmDmsdAid[] = {0xa0, 0x00, 0x00, 0x01, 0x51, 0x53, 0x50, 0x41, 0x4c, 0x43, 0x43, 0x4d, 0x44, 0x4d};

    uint8_t appletAid[MAX_AID_SIZE] = {0, };
    uint32_t appletAidLen;

    uint8_t associatedAid[MAX_AID_SIZE] = {0, };
    uint32_t associatedAidLen;

    char serviceName[MAX_KEY_NAME_SIZE] = {0, };
    uint32_t serviceNameLen;

    uint8_t keyBlobs[SSP_MAX_SECURE_OBJECT_SIZE] = {0, };
    uint32_t keyBlobsLen = SSP_MAX_SECURE_OBJECT_SIZE;

    uint8_t cData[MAX_CAPDU_DATA_SIZE] = {0,};
    uint8_t rData[MAX_RAPDU_DATA_SIZE] = {0,};
    secEse_7816_cpdu_t cpdu;
    secEse_7816_rpdu_t rpdu;

    uint8_t rspData[MAX_RSP_CIPHERED_TEXT_SIZE] = {0,};

    uint8_t storeData[MAX_CAPDU_DATA_SIZE] = {0,};
    uint8_t storeDataLen = 0;

    uint8_t base_key[AES_256_KEY_SIZE] = {0, };

    uint8_t kvn30keyset[AES_128_KEY_SIZE * 3] = {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,};

    uint8_t kvn31keyset[AES_128_KEY_SIZE * 3] = {0,}; // enc 16,mac 16, dek 16
    uint32_t kvn31keysetLen = 0;

    uint8_t kvn31_key_enc[AES_128_KEY_SIZE] = {0,};
    uint8_t kvn31_key_mac[AES_128_KEY_SIZE] = {0,};
    uint8_t kvn31_key_dek[AES_128_KEY_SIZE] = {0,};

    uint32_t offset = 0, inputSize;
    int32_t result = 0;

    SCPSTATUS scpRet;

    LOGD("requestCredentials start");
    inputSize = cmd->dataLen;
    if (inputSize > 4 + SSP_MAX_WRAPPED_OTP_KEY_SIZE + 4 + MAX_AID_SIZE + 4 + MAX_AID_SIZE + 4 + MAX_KEY_NAME_SIZE) {
        LOGE("Input data is over the buffer.");
        rsp->ret = RET_ERR_BUFFER_OVERFLOW;
        goto error;
    }
    if (inputSize == 0) {
        LOGE("Input data is exist");
        rsp->ret = RET_ERR_INVALID_INPUT_PARAMS;
        goto error;
    }

    memcpy(&otp_key_blob_size, cmd->data + offset, 4);
    offset += 4;
    if (otp_key_blob_size > SSP_MAX_WRAPPED_OTP_KEY_SIZE) {
        LOGE("otp_key_blob length is over the buffer size");
        rsp->ret = RET_ERR_BUFFER_OVERFLOW;
        goto error2;
    }
    memcpy(otp_key_blob, cmd->data + offset, otp_key_blob_size);
    offset += otp_key_blob_size;
    hex_print_tag_debug("otp_key_blob", otp_key_blob, otp_key_blob_size);

    memcpy(&appletAidLen, cmd->data + offset, 4);
    offset += 4;
    if (appletAidLen > MAX_AID_SIZE) {
        LOGE("appletAid length is over the buffer size");
        rsp->ret = RET_ERR_BUFFER_OVERFLOW;
        goto error2;
    }
    memcpy(appletAid, cmd->data + offset, appletAidLen);
    offset += appletAidLen;
    hex_print_tag_debug("appletAid", appletAid, appletAidLen);

    memcpy(&associatedAidLen, cmd->data + offset, 4);
    offset += 4;
    if (associatedAidLen > MAX_AID_SIZE) {
        LOGE("associatedAid length is over the buffer size");
        rsp->ret = RET_ERR_BUFFER_OVERFLOW;
        goto error2;
    }
    memcpy(associatedAid, cmd->data + offset, associatedAidLen);
    offset += associatedAidLen;
    hex_print_tag_debug("associatedAid", associatedAid, associatedAidLen);

    memcpy(&serviceNameLen, cmd->data + offset, 4);
    offset += 4;
    if (serviceNameLen > MAX_KEY_NAME_SIZE) {
        LOGE("serviceName length is over the buffer size");
        rsp->ret = RET_ERR_BUFFER_OVERFLOW;
        goto error2;
    }
    memcpy(serviceName, cmd->data + offset, serviceNameLen);
    offset += serviceNameLen;
    LOGD("serviceName : %s", serviceName);

    result = checkSeStateInternal(appletAid, appletAidLen, associatedAid, associatedAidLen);
    if (result < 0) {
        LOGE("checkSeStateInternal is failed");
        rsp->ret = result;
        goto error;
    } else if (result == SSD_NOT_SELECTABLE_APPLET_EXIST) {
        LOGI("SE has already provisioned");

        crypto_get_tz_encryption_key(base_key);
        crypto_aes_256_cmac(kvn31_key_enc, base_key, "kvn31_key_enc", strlen("kvn31_key_enc"), appletAid, appletAidLen, associatedAid, associatedAidLen, NULL);
        crypto_aes_256_cmac(kvn31_key_mac, base_key, "kvn31_key_mac", strlen("kvn31_key_mac"), appletAid, appletAidLen, associatedAid, associatedAidLen, NULL);
        crypto_aes_256_cmac(kvn31_key_dek, base_key, "kvn31_key_dek", strlen("kvn31_key_dek"), appletAid, appletAidLen, associatedAid, associatedAidLen, NULL);
        goto wrapping;
    } else if (result != SSD_SELECTABLE_APPLET_EXIST) {
        LOGE("SE state is not correct");
        rsp->ret = RET_ERR_NOT_CORRECT_SE_STATE;
        goto error;
    } else {
        LOGI("state of SE : %d", result);
    }

    if (ESESTATUS_SUCCESS != secEseOpen(&cn)) {
        LOGE("requestCredentials channel open fail");
        rsp->ret = RET_ERR_REQUEST_CREDENTIALS;
        goto error2;
    }

    // ssp kvn30 session open -> opensession with cmd -> close session in getKVN30Keyset
    if (getKVN30Keyset(cn, otp_key_blob, otp_key_blob_size, kvn30keyset, &kvn30keysetLen) != RET_SUCCESS) {
        LOGE("Failed to get KVN30Keyset");
        rsp->ret = RET_ERR_REQUEST_CREDENTIALS;
        goto error;
    }

    // close channel for kvn30keyset
    secEseClose(cn);

    // parse KVN30 keyset & save to buffers :: kvn30_key_enc, kvn30_key_mac, kvn30_key_dek each key length is 16byte
    if (kvn30keysetLen == AES_128_KEY_SIZE * 3) {
        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);
        rsp->ret = RET_ERR_REQUEST_CREDENTIALS;
        goto error2;
    }

    // manage channel
    if (ESESTATUS_SUCCESS != secEseOpen(&cn)) {
        LOGE("requestCredentials channel open fail");
        rsp->ret = RET_ERR_REQUEST_CREDENTIALS;
        goto error2;
    }
    LOGD("channel ID : %d", cn);

    // select lccmDmsdAid
    memset(&rpdu, 0, sizeof(secEse_7816_rpdu_t));
    rpdu.pdata = rData;
    if (cn < 1 || cn > 3 || ESESTATUS_SUCCESS != secEseSelect(cn, lccmDmsdAid, 0, sizeof(lccmDmsdAid), &rpdu) ) {
        LOGE("Failed to select lccmDmsdAid");
        hex_print_tag("lccmDmsdAid", lccmDmsdAid, sizeof(lccmDmsdAid));
        rsp->ret = RET_ERR_REQUEST_CREDENTIALS;
        goto error;
    }

    // SCP opensession KVN#30
    // securityLevel : External Authentication Reference Control Prameter P1 (page 29/36) <<=====================
    scpRet = openSession(cn, 0x30, kvn30_key_enc, kvn30_key_mac, kvn30_key_dek, lccmDmsdAid, sizeof(lccmDmsdAid), 0x33);
    if (scpRet != SCP_SUCCESS) {
        LOGE("Failed SCP03 KVN30 OPEN SESSION, scpRet :%u", scpRet);
        rsp->ret = RET_ERR_SCP_FAIL;
        goto error;
    }
    LOGD("********************* [OPEN SESSION WITH KVN #30 SUCCESS] *******************");

    crypto_get_tz_encryption_key(base_key);
    crypto_aes_256_cmac(kvn31_key_enc, base_key, "kvn31_key_enc", strlen("kvn31_key_enc"), appletAid, appletAidLen, associatedAid, associatedAidLen, NULL);
    crypto_aes_256_cmac(kvn31_key_mac, base_key, "kvn31_key_mac", strlen("kvn31_key_mac"), appletAid, appletAidLen, associatedAid, associatedAidLen, NULL);
    crypto_aes_256_cmac(kvn31_key_dek, base_key, "kvn31_key_dek", strlen("kvn31_key_dek"), appletAid, appletAidLen, associatedAid, associatedAidLen, NULL);
    hex_print_tag_debug("kvn31_key_enc", kvn31_key_enc, AES_128_KEY_SIZE);
    hex_print_tag_debug("kvn31_key_mac", kvn31_key_mac, AES_128_KEY_SIZE);    
    hex_print_tag_debug("kvn31_key_dek", kvn31_key_dek, AES_128_KEY_SIZE);    

    memset(&cpdu, 0, sizeof(secEse_7816_cpdu_t));
    memset(&rpdu, 0, sizeof(secEse_7816_rpdu_t));
    memset(cData, 0, MAX_CAPDU_DATA_SIZE);
    memset(rData, 0, MAX_RAPDU_DATA_SIZE);
    rpdu.pdata = rData;

    cData[2] = associatedAidLen;
    if (sizeof(cData) - 2 > associatedAidLen) {
        memcpy(cData + 3, associatedAid, associatedAidLen);
    }

    cpdu.cla = 0x80;
    cpdu.ins = 0xE6;
    cpdu.p1 = 0x20;
    cpdu.p2 = 0x00;
    cpdu.pdata = cData;
    cpdu.lc = 2 + 1 + associatedAidLen + 3;
    cpdu.le_type = 1;

    scpRet = apduTransceive (cn, &cpdu, &rpdu);
    if (scpRet != SCP_SUCCESS || rpdu.sw1 != 0x90 || rpdu.sw2 != 0x00) {
        LOGE("Failed to install for perso, scpRet : %u, sw1-sw2 : 0x%x%x", scpRet, rpdu.sw1, rpdu.sw2);
        rsp->ret = RET_ERR_REQUEST_CREDENTIALS;
        goto error;
    }
    LOGD("********************* [INSTALL FOR PERSO WITH SSD's AID SUCCESS] *******************");

    storeDataLen = genStoreKeyData(storeData, (uint8_t)sizeof(storeData), kvn30_key_dek, kvn31_key_enc, kvn31_key_mac, kvn31_key_dek);
    scpRet = sendStoreDataCmd(cn, 0x88, 0x00, storeDataLen, storeData, rspData);
    if (scpRet != SCP_SUCCESS) {
        LOGE("Failed to sendStoreDataCmd");
        rsp->ret = RET_ERR_REQUEST_CREDENTIALS;
        goto error;
    }
    LOGD("********************* [STORE DATA SUCCESS] *******************");

    // close channel for store data
    secEseClose(cn);
    
wrapping:
    // manage channel
    if (ESESTATUS_SUCCESS != secEseOpen(&cn)) {
        LOGE("channel open fail");
        rsp->ret = RET_ERR_REQUEST_CREDENTIALS;
        goto error;
    }
    LOGD("channel ID : %d", cn);

    // select associatedAid
    memset(&rpdu, 0, sizeof(secEse_7816_rpdu_t));
    rpdu.pdata = rData;
    if (cn < 1 || cn > 3 || ESESTATUS_SUCCESS != secEseSelect(cn, associatedAid, 0, associatedAidLen, &rpdu) ) {
        LOGE("Failed to SELECT associatedAid");
        hex_print_tag("associatedAid", associatedAid, associatedAidLen);
        rsp->ret = RET_ERR_REQUEST_CREDENTIALS;
        goto error;
    }

    // SCP03 : open session KVN#31 again
    // securityLevel : External Authentication Reference Control Prameter P1 (page 29/36) <<=====================
    scpRet = openSession(cn, 0x31, kvn31_key_enc, kvn31_key_mac, kvn31_key_dek, associatedAid, associatedAidLen, 0x11);
    if (scpRet != SCP_SUCCESS) {
        LOGE("Failed SCP03 KVN31 OPEN SESSION, scpRet : %u", scpRet);
        rsp->ret = RET_ERR_SCP_FAIL;
        goto error;
    }
    LOGD("********************* [OPEN SESSION WITH KVN #31 SUCCESS] *******************");

    // close channel for store data
    secEseClose(cn);

    kvn31keysetLen = 0;
    memcpy(kvn31keyset + kvn31keysetLen, kvn31_key_enc, AES_128_KEY_SIZE);
    kvn31keysetLen += AES_128_KEY_SIZE;
    memcpy(kvn31keyset + kvn31keysetLen, kvn31_key_mac, AES_128_KEY_SIZE);
    kvn31keysetLen += AES_128_KEY_SIZE;
    memcpy(kvn31keyset + kvn31keysetLen, kvn31_key_dek, AES_128_KEY_SIZE);
    kvn31keysetLen += AES_128_KEY_SIZE;

    LOGD("keyListInfo_size : %u", gKeyListInfo_size);
    for (i = 0; i < gKeyListInfo_size; i++) {
        LOGD("List serviceName : %s", gKeyListInfo[i].service_name);
        LOGD("In   serviceName : %s", serviceName);
        if (strcmp((const char*)serviceName, (const char*)gKeyListInfo[i].service_name) == 0) {
            LOGD("List is matched, serviceName : %s", serviceName);
            for (j = 0; j < MAX_AID_SIZE; j++) {
                if (associatedAid[j] != gKeyListInfo[i].associated_ssd_aid[j]) {
                    LOGE("associatedAid is not mached");
                    hex_print_tag("associatedAid", associatedAid, associatedAidLen);
                    rsp->ret = RET_ERR_NOT_PERMITTED;
                    goto error;
                }
            }

            goto matched;
        }
    }
    LOGE("Not supported, serviceName : %s", serviceName);
    rsp->ret = RET_ERR_NOT_PERMITTED;
    goto error;

matched:
    // Wrap
#ifdef USE_QSEE
    if (ssp_wrap_secure_object( gKeyListInfo[i].key_id_qsee, kvn31keyset, sizeof(kvn31keyset), keyBlobs, &keyBlobsLen) == RET_SUCCESS)
#endif
#ifdef USE_MOBICORE
    if (ssp_wrap_secure_object( gKeyListInfo[i].key_id_mobicore, kvn31keyset, sizeof(kvn31keyset), keyBlobs, &keyBlobsLen) == RET_SUCCESS)
#endif
#if defined(USE_BLOWFISH) || defined (USE_TRUSTY_UNISOC)
    if (ssp_wrap_secure_object( gKeyListInfo[i].key_id_blowfish, kvn31keyset, sizeof(kvn31keyset), keyBlobs, &keyBlobsLen) == RET_SUCCESS)
#endif
    {
        hex_print_tag_debug("keyBlobs", keyBlobs, keyBlobsLen);
    } else {
        LOGE("Data wrapping is failed");
        rsp->ret = RET_ERR_DATA_WRAPPING_FAIL;
        goto error;
    }

    rsp->dataLen = keyBlobsLen;
    if ( MAX_DATA_SIZE < keyBlobsLen || sizeof(keyBlobs) < keyBlobsLen) {
        LOGE("keyBlobsLen length is over the buffer size");
        rsp->ret = RET_ERR_BUFFER_OVERFLOW;
        goto error;
    }
    memcpy(rsp->data, keyBlobs, keyBlobsLen);
    rsp->ret = RET_SUCCESS;


error:
    if (cn != 0) {
        secEseClose(cn);
    }

    crypto_clear_mem(base_key, sizeof(base_key));
    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));

    crypto_clear_mem(kvn31keyset, sizeof(kvn31keyset));
    crypto_clear_mem(kvn31_key_enc, sizeof(kvn31_key_enc));
    crypto_clear_mem(kvn31_key_mac, sizeof(kvn31_key_mac));
    crypto_clear_mem(kvn31_key_dek, sizeof(kvn31_key_dek));

error2:
    LOGD("requestCredentials end, returned: %d", rsp->ret);
}

#ifdef DEBUG_LOW
void scpKmTest(p_cmd_t cmd, p_rsp_t rsp) {
    uint8_t cn = 0;

    uint8_t  associatedAid[MAX_AID_SIZE];
    uint32_t associatedAidLen;

    uint8_t cData[MAX_CAPDU_DATA_SIZE] = {0,};
    uint8_t rData[MAX_RAPDU_DATA_SIZE] = {0,};
    secEse_7816_cpdu_t cpdu;
    secEse_7816_rpdu_t rpdu;

    uint8_t  keyBlobs[SSP_MAX_SECURE_OBJECT_SIZE] = {0, };
    uint32_t keyBlobsLen = SSP_MAX_SECURE_OBJECT_SIZE;
    uint8_t  tempKeyBlobs[SSP_MAX_SECURE_OBJECT_SIZE] = {0, };
    uint32_t tempKeyBlobsLen = SSP_MAX_SECURE_OBJECT_SIZE;

    uint8_t kvn31_key_enc[AES_128_KEY_SIZE] = {0,};
    uint8_t kvn31_key_mac[AES_128_KEY_SIZE] = {0,};
    uint8_t kvn31_key_dek[AES_128_KEY_SIZE] = {0,};

    uint32_t kvn31keysetLen;

    uint32_t offset = 0;

    LOGD("scpKmTest start");

    memcpy(&keyBlobsLen, cmd->data + offset, 4);
    offset += 4;
    if (keyBlobsLen > SSP_MAX_SECURE_OBJECT_SIZE) {
        LOGE("otp_key_blob length is over the buffer size");
        rsp->ret = RET_ERR_BUFFER_OVERFLOW;
        goto error2;
    }
    memcpy(keyBlobs, cmd->data + offset, keyBlobsLen);
    offset += keyBlobsLen;
    hex_print_tag_debug("keyBlobs", keyBlobs, keyBlobsLen);

    memcpy(&associatedAidLen, cmd->data + offset, 4);
    offset += 4;
    if (associatedAidLen > MAX_AID_SIZE) {
        LOGE("associatedAid length is over the buffer size");
        rsp->ret = RET_ERR_BUFFER_OVERFLOW;
        goto error2;
    }
    memcpy(associatedAid, cmd->data + offset, associatedAidLen);
    offset += associatedAidLen;
    hex_print_tag_debug("associatedAid", associatedAid, associatedAidLen);

    // manage channel
    if (ESESTATUS_SUCCESS != secEseOpen(&cn)) {
        LOGE("requestCredentials channel open fail");
        rsp->ret = RET_ERR_REQUEST_CREDENTIALS;
        goto error2;
    }
    LOGD("channel ID : %d", cn);

    // select associatedAid
    memset(&rpdu, 0, sizeof(secEse_7816_rpdu_t));
    rpdu.pdata = rData;
    if (cn < 1 || cn > 3 || ESESTATUS_SUCCESS != secEseSelect(cn, associatedAid, 0, associatedAidLen, &rpdu) ) {
        LOGE("checkSeState failed to SELECT");
        hex_print_tag("associatedAid", associatedAid, associatedAidLen);
        rsp->ret = RET_ERR_REQUEST_CREDENTIALS;
        goto error;
    }

    hex_print_tag_debug("keyBlobs", keyBlobs, keyBlobsLen);

#if defined(USE_BLOWFISH) || defined (USE_TRUSTY_UNISOC)
    uint8_t SEM_TEST_BF_UUID_LOCAL[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x45, 0x4d, 0x65, 0x53, 0x45};
    ssp_unwrap_secure_object(SEM_TEST_BF_UUID_LOCAL, keyBlobs, keyBlobsLen, tempKeyBlobs, &tempKeyBlobsLen);
#elif defined(USE_QSEE)
    ssp_unwrap_secure_object((uint8_t*)SEM_TEST_QSEE_NAME, keyBlobs, keyBlobsLen, tempKeyBlobs, &tempKeyBlobsLen);
#else
    ssp_unwrap_secure_object(keyBlobs, keyBlobsLen, tempKeyBlobs, &tempKeyBlobsLen);
#endif
    hex_print_tag_debug("unwrapped", tempKeyBlobs, tempKeyBlobsLen);

    if (tempKeyBlobsLen != AES_128_KEY_SIZE * 3) {
        LOGE("KVN32 key set is not correct length");
        goto error;
    }

    kvn31keysetLen = 0;
    memcpy(kvn31_key_enc, tempKeyBlobs + kvn31keysetLen, AES_128_KEY_SIZE);
    kvn31keysetLen += AES_128_KEY_SIZE;
    memcpy(kvn31_key_mac, tempKeyBlobs + kvn31keysetLen, AES_128_KEY_SIZE);
    kvn31keysetLen += AES_128_KEY_SIZE;
    memcpy(kvn31_key_dek, tempKeyBlobs + kvn31keysetLen, AES_128_KEY_SIZE);
    kvn31keysetLen += AES_128_KEY_SIZE;

    // SCP03 : open session KVN#31 again
    // securityLevel : External Authentication Reference Control Prameter P1 (page 29/36) <<=====================
    if (openSession(cn, 0x31, kvn31_key_enc, kvn31_key_mac, kvn31_key_dek, associatedAid, associatedAidLen, 0x11) != SCP_SUCCESS) {
        LOGE("Failed SCP03 KVN31 OPEN SESSION ::");
        rsp->ret = RET_ERR_REQUEST_CREDENTIALS;
        goto error;
    }
    LOGI("********************* [OPEN SESSION WITH KVN #31 SUCCESS] *******************");

    memset(&cpdu, 0, sizeof(secEse_7816_cpdu_t));
    memset(&rpdu, 0, sizeof(secEse_7816_rpdu_t));
    memset(cData, 0, MAX_CAPDU_DATA_SIZE);
    memset(rData, 0, MAX_RAPDU_DATA_SIZE);
    rpdu.pdata = rData;

    cpdu.cla = 0x80;
    cpdu.ins = 0xF2;
    cpdu.p1 = 0x40;
    cpdu.p2 = 0x00;
    cpdu.pdata = cData;
    cpdu.lc = 0x00;
    cpdu.le_type = 1;

    apduTransceive (cn, &cpdu, &rpdu);

    rsp->ret = RET_SUCCESS;

error:
    if (cn != 0) {
        secEseClose(cn);
    }

error2:
    LOGD("requestCredentials end, returned: %d", rsp->ret);
}
#endif

