#ifdef SCP11_ENABLE
#include "SCP11.h"
#include "tz_debug.h"

#include "crypto_module.h"
#include "SCP03_crypto.h"
#define CHAIN_VERFIFICATION

#ifdef CHAIN_OCE_CERT
SCP11STATUS scp11_skpm_cert(skpm_cert_key_t *skpm_ka_kloc_cert_key, skpm_cert_key_t *skpm_cert_key) {
#ifdef DEBUG_LOW
// chain cert case : The payload is composed of a chain of certificates starting from the first (or only) CERT.KA-KLOC.ECDSA and ending with CERT.OCE.ECKA
    uint8_t cert_ka_kloc_ecka[] ={0x7F,0x21,0x81,0xB8,0x93,0x08,0x20,0x19,0x07,0x01,0x10,0x00,0x00,0x00,0x42,0x04,0x53,0x4B,0x50,0x4D,0x5F,0x20,0x08,0x53,0x4B,0x50,0x4D,0x5F,0x53,0x55,0x42,0x95,0x01,0x82,0x5F,0x25,0x04,0x20,0x19,0x07,0x01,0x5F,0x24,0x04,0x20,0x69,0x12,0x31,0x7F,0x49,0x46,0xB0,0x41,0x04,0xF3,0x1A,0x6C,0x36,0xDD,0xB0,0xF7,0xBC,0xF1,0x76,0x60,0x40,0x27,0x26,0x30,0x86,0x92,0x39,0xEA,0x9A,0x65,0x4A,0x23,0xB3,0xD1,0xAD,0xB9,0x2D,0xE8,0x27,0x74,0x5A,0x03,0xA7,0x31,0x6F,0xDC,0x54,0xC5,0xAB,0x8D,0xB9,0xD9,0x80,0x73,0x61,0xEB,0x06,0xBA,0x5F,0x7E,0x55,0xB1,0x66,0xE0,0xB3,0x76,0xD8,0xB3,0x3A,0x39,0xD7,0x7C,0x39,0xF0,0x01,0x00,0x5F,0x37,0x40,0x3C,0xE5,0xA2,0xDA,0x08,0xB3,0xA5,0x2C,0xED,0x06,0x67,0x76,0x34,0x1B,0xAE,0xFC,0x5B,0x80,0x57,0xA0,0xE7,0x26,0xD3,0x3F,0x47,0x82,0x16,0xF8,0x21,0x76,0xE6,0xF5,0xF4,0x0F,0x38,0x26,0xA2,0x69,0x54,0xFD,0x15,0xED,0xAC,0xF0,0xD8,0xD2,0x0F,0xFD,0x97,0xD9,0x7F,0x47,0x29,0xAA,0x6B,0xFE,0x68,0x83,0x54,0x8E,0xA5,0x45,0x2B,0x4A};
    uint8_t cert_oce_ecka[] ={0x7F,0x21,0x81,0xC0,0x93,0x08,0x20,0x19,0x07,0x01,0x10,0x00,0x00,0x00,0x42,0x08,0x53,0x4B,0x50,0x4D,0x5F,0x53,0x55,0x42,0x5F,0x20,0x0B,0x53,0x43,0x50,0x31,0x31,0x61,0x4E,0x5F,0x53,0x45,0x4D,0x95,0x02,0x00,0x80,0x5F,0x25,0x04,0x20,0x19,0x07,0x01,0x5F,0x24,0x04,0x20,0x69,0x12,0x31,0x7F,0x49,0x46,0xB0,0x41,0x04,0x7F,0xFB,0xEC,0x2E,0x86,0x2D,0x12,0xB1,0x11,0x02,0x43,0xEF,0xCB,0xE9,0x14,0x15,0xD7,0xD6,0x32,0xEE,0xCF,0x41,0x15,0x92,0xCB,0x26,0xD5,0x64,0xAF,0xA9,0xA8,0x37,0xB8,0x38,0x52,0x4E,0x10,0xEF,0x5E,0x60,0xF5,0x6A,0xB5,0xD1,0x4B,0xD8,0xFA,0xA8,0x97,0x91,0xBA,0x28,0xEE,0x14,0xA8,0xAB,0x82,0xE7,0x65,0x4C,0xEC,0xC1,0x82,0x4B,0xF0,0x01,0x00,0x5F,0x37,0x40,0x2F,0x44,0x9F,0x48,0xF8,0xA5,0x0C,0x3C,0x3D,0x5F,0x45,0x41,0x67,0xED,0xBA,0xB6,0xA7,0xA1,0xAB,0x89,0x88,0x49,0x79,0x25,0x05,0xAD,0x8F,0xE7,0x65,0x2B,0x05,0x08,0x60,0xF6,0x18,0xC6,0x1A,0xF0,0xCA,0xC9,0x2C,0xC3,0xCB,0xCD,0xA0,0xAA,0xFB,0x86,0x88,0x1B,0xDB,0x77,0x98,0x03,0x20,0x9F,0x3C,0xE7,0xF3,0x27,0x79,0xC3,0xEC,0x89};
// the below sk_oce_key is a fake key so scp11a shall be failed during mutual authentication
    uint8_t sk_oce_key[] = {0x1A,0x51,0x43,0xB3,0xD0,0xAF,0xE2,0xC6,0xCB,0x2D,0xE3,0x6A,0x54,0xC2,0xA3,0xC1,0x6A,0x2A,0x98,0xB6,0xF6,0x4A,0xFD,0xC0,0xE2,0x72,0x0F,0x8A,0x3E,0xE1,0xD9,0xF2};

#else
    uint8_t cert_ka_kloc_ecka[MAX_SCP11_DATA_SIZE];
    uint8_t cert_oce_ecka[MAX_SCP11_DATA_SIZE];
    uint8_t sk_oce_key[MAX_SCP11_DATA_SIZE];
#endif
    skpm_ka_kloc_cert_key->cert_oce_ecka_len=sizeof(cert_ka_kloc_ecka);
    memcpy(skpm_ka_kloc_cert_key->cert_oce_ecka,&cert_ka_kloc_ecka,skpm_ka_kloc_cert_key->cert_oce_ecka_len);
//    skpm_ka_kloc_cert_key->sk_oce_key_len=sizeof(sk_oce_key);
//    memcpy(skpm_ka_kloc_cert_key->sk_oce_key,&sk_oce_key,skpm_ka_kloc_cert_key->sk_oce_key_len);

    skpm_cert_key->cert_oce_ecka_len=sizeof(cert_oce_ecka);
    memcpy(skpm_cert_key->cert_oce_ecka,&cert_oce_ecka,skpm_cert_key->cert_oce_ecka_len);
    skpm_cert_key->sk_oce_key_len=sizeof(sk_oce_key);
    memcpy(skpm_cert_key->sk_oce_key,&sk_oce_key,skpm_cert_key->sk_oce_key_len);

    return SCP11_SUCCESS;
}
#else // #ifdef CHAIN_OCE_CERT
SCP11STATUS scp11_skpm_cert(skpm_cert_key_t *skpm_cert_key) {
#ifdef DEBUG_LOW
// NXP LCCM AMSD : real cert_oce_ecka + fake sk_oce_key -> shall be replaced with real sk_oce_key
    uint8_t cert_oce_ecka[] ={0x7F,0x21,0x81,0xBC,0x93,0x08,0x20,0x19,0x06,0x04,0x10,0x00,0x00,0x00,0x42,0x04,0x53,0x4B,0x50,0x4D,0x5F,0x20,0x0B,0x53,0x43,0x50,0x31,0x31,0x61,0x4E,0x5F,0x53,0x45,0x4D,0x95,0x02,0x00,0x80,0x5F,0x25,0x04,0x20,0x19,0x06,0x04,0x5F,0x24,0x04,0x20,0x69,0x12,0x31,0x7F,0x49,0x46,0xB0,0x41,0x04,0x7F,0xFB,0xEC,0x2E,0x86,0x2D,0x12,0xB1,0x11,0x02,0x43,0xEF,0xCB,0xE9,0x14,0x15,0xD7,0xD6,0x32,0xEE,0xCF,0x41,0x15,0x92,0xCB,0x26,0xD5,0x64,0xAF,0xA9,0xA8,0x37,0xB8,0x38,0x52,0x4E,0x10,0xEF,0x5E,0x60,0xF5,0x6A,0xB5,0xD1,0x4B,0xD8,0xFA,0xA8,0x97,0x91,0xBA,0x28,0xEE,0x14,0xA8,0xAB,0x82,0xE7,0x65,0x4C,0xEC,0xC1,0x82,0x4B,0xF0,0x01,0x00,0x5F,0x37,0x40,0x1B,0x0A,0xD7,0xDB,0x64,0x4A,0xAF,0x0F,0x5B,0x68,0x6C,0x5A,0xDF,0x21,0x08,0x33,0x53,0x77,0x16,0x22,0x16,0x01,0x39,0xF7,0x34,0xA0,0xEC,0x86,0x59,0x72,0xC4,0xCB,0xDB,0x05,0x15,0xD5,0x63,0x00,0x61,0xEC,0x43,0xEC,0x69,0x6B,0xF4,0x7E,0x2B,0x92,0xCF,0x17,0x00,0x8C,0x95,0xC7,0x5D,0xA2,0x48,0x5B,0xAA,0x1E,0xD6,0xE5,0xCD,0x94};
// the below sk_oce_key is a fake key so scp11a shall be failed during mutual authentication
    uint8_t sk_oce_key[] = {0x1A,0x51,0x43,0xB3,0xD0,0xAF,0xE2,0xC6,0xCB,0x2D,0xE3,0x6A,0x54,0xC2,0xA3,0xC1,0x6A,0x2A,0x98,0xB6,0xF6,0x4A,0xFD,0xC0,0xE2,0x72,0x0F,0x8A,0x3E,0xE1,0xD9,0xF2};


//Only Gem test key of ISD
//    uint8_t cert_oce_ecka[] ={0x7F,0x21,0x81,0xE0,0x93,0x10,0x54,0xEC,0x2C,0x7F,0x67,0x07,0x1E,0x4A,0x9F,0xB7,0x40,0xFF,0xFF,0xFF,0xFF,0xF1,0x42,0x10,0x47,0x54,0x4F,0x53,0x4E,0x4C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x5F,0x20,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x3B,0x36,0xE6,0x95,0x01,0x80,0x5F,0x25,0x04,0x20,0x15,0x01,0x01,0x5F,0x24,0x04,0x20,0x20,0x01,0x01,0x53,0x10,0x47,0x50,0x00,0x1A,0x00,0x08,0x20,0x30,0x01,0x18,0x47,0x50,0x00,0x1A,0x00,0x08,0x7F,0x49,0x46,0xB0,0x41,0x04,0xF4,0x64,0xAE,0xF2,0x8C,0x84,0x36,0x3A,0x09,0x29,0x65,0x39,0x7A,0x2C,0x02,0x7D,0x73,0x04,0x11,0x0C,0x71,0x33,0x76,0x4F,0x75,0xED,0x39,0x2B,0x8C,0xF9,0x79,0x03,0x89,0x39,0x2A,0xB1,0x46,0x1B,0x68,0x7D,0x20,0xE1,0xF6,0x5F,0xC7,0xC8,0xF1,0x30,0x46,0xA7,0x3A,0x4D,0xE1,0x83,0xA5,0xC0,0x9D,0x6F,0x4B,0xBA,0x94,0x2A,0x6E,0x7C,0xF0,0x01,0x00,0x5F,0x37,0x40,0xF0,0x65,0x64,0x33,0xDB,0x24,0x86,0xCD,0x38,0xD9,0xA0,0x8B,0xFA,0xF3,0x1A,0x43,0xD6,0xB0,0x68,0xDA,0x65,0x98,0xC2,0xFE,0x7A,0x5E,0xE2,0x83,0x50,0xE9,0x83,0x1B,0xAD,0x4A,0xF6,0xC8,0xAA,0xBB,0x26,0x3F,0x97,0x1C,0x29,0x12,0xA3,0x9C,0x04,0x6F,0xBE,0xAD,0x59,0x35,0x71,0x0C,0xB2,0xBC,0x36,0x41,0x0A,0x75,0x70,0xE7,0x1E,0x65};
//    uint8_t sk_oce_key[] = {0xF2,0x11,0x41,0xEC,0x9F,0x19,0x14,0x13,0xA2,0x8B,0xFE,0x5A,0xD9,0xAC,0x3D,0xA8,0x50,0x97,0x1F,0xF8,0xF4,0x57,0x7B,0x73,0xDC,0x93,0xFA,0x6E,0x3D,0xEB,0x82,0xC5};
//Only Gem test key of SP AMSD
//    uint8_t cert_oce_ecka[] ={0x7F,0x21,0x81,0xE0,0x93,0x10,0x54,0xEC,0x2C,0x7F,0x67,0x07,0x1E,0x4A,0x9F,0xB7,0x40,0xFF,0xFF,0xFF,0xFF,0xF1,0x42,0x10,0x47,0x54,0x4F,0x53,0x4E,0x4C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x5F,0x20,0x0A,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x3B,0x36,0xE6,0x95,0x01,0x80,0x5F,0x25,0x04,0x20,0x15,0x01,0x01,0x5F,0x24,0x04,0x20,0x20,0x01,0x01,0x53,0x10,0x47,0x50,0x00,0x1A,0x00,0x08,0x20,0x30,0x01,0x18,0x47,0x50,0x00,0x1A,0x00,0x08,0x7F,0x49,0x46,0xB0,0x41,0x04,0xF5,0x85,0xCD,0xE1,0x1F,0x6D,0x1B,0x3B,0x00,0x64,0x4E,0x57,0xB6,0xA0,0x80,0xCC,0xA6,0x62,0x6C,0xBD,0xCF,0x32,0x76,0x9D,0x54,0x84,0x7E,0xB0,0x7B,0x41,0x41,0x0E,0x73,0x53,0x6E,0x7C,0x1E,0xF6,0x54,0xA4,0x42,0x90,0xA0,0x37,0x0C,0x3E,0xE0,0x4C,0x5C,0xC8,0x25,0x8D,0x00,0x6A,0x9D,0xFB,0xA9,0xEE,0x63,0x3F,0xA6,0x45,0xB5,0x59,0xF0,0x01,0x00,0x5F,0x37,0x40,0xF0,0x65,0x64,0x33,0xDB,0x24,0x86,0xCD,0x38,0xD9,0xA0,0x8B,0xFA,0xF3,0x1A,0x43,0xD6,0xB0,0x68,0xDA,0x65,0x98,0xC2,0xFE,0x7A,0x5E,0xE2,0x83,0x50,0xE9,0x83,0x1B,0x2C,0x6D,0x46,0x59,0x35,0x71,0x4E,0xFA,0x92,0x4D,0x66,0x43,0xA1,0x61,0x13,0x04,0xC7,0x16,0x26,0x46,0xCB,0x22,0xBF,0x69,0x10,0x8A,0x3E,0x86,0xF3,0x18,0x8D,0x85};
//    uint8_t sk_oce_key[] = {0xAE,0xD5,0xF8,0xA2,0x0E,0xEF,0x9C,0x0B,0xFC,0x73,0x78,0x57,0xB4,0x1A,0x84,0x7A,0x34,0xE3,0x55,0x31,0x45,0x32,0xA7,0x2D,0x6F,0xC4,0x19,0xAC,0x35,0x42,0x42,0xF1};
#else
    uint8_t cert_oce_ecka[MAX_SCP11_DATA_SIZE];
    uint8_t sk_oce_key[MAX_SCP11_DATA_SIZE];
#endif

    skpm_cert_key->cert_oce_ecka_len=sizeof(cert_oce_ecka);
    memcpy(skpm_cert_key->cert_oce_ecka,&cert_oce_ecka,skpm_cert_key->cert_oce_ecka_len);

    skpm_cert_key->sk_oce_key_len=sizeof(sk_oce_key);
    memcpy(skpm_cert_key->sk_oce_key,&sk_oce_key,skpm_cert_key->sk_oce_key_len);

    return SCP11_SUCCESS;
}
#endif // #ifdef CHAIN_OCE_CERT



SCP11STATUS scp11_get_data(uint8_t channelId, get_data_t *get_data_key) {
    uint8_t data[MAX_RAPDU_DATA_SIZE] = {0,};
    uint8_t pk_sd_ecka[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t pk_sd_ecka_temp[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t signature[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t message[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t message_temp[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t digest[32] = {0, };
    int32_t ret = 0;
    uint32_t bufOffset = 0;
    uint32_t pk_sd_ecka_len = 0;
    uint32_t pk_sd_ecka_temp_len = 0;
    uint32_t signature_len = 0;
    uint32_t message_len = 0;
    uint32_t message_temp_len = 0;
    void* pCardMetadata = NULL;
    card_meta_struct_t_CERT_SD_ECKA cardMeta_CERT_SD_ECKA;
    card_meta_struct_t_CERT_SD_ECKA * pData = NULL;
    secEse_7816_cpdu_t cpdu;
    secEse_7816_rpdu_t rpdu;
    verify_signature_t input;

    #ifdef NXP
//    uint8_t pk_ca_klcc[]={0x04,0x78,0x6b,0xca,0xba,0x50,0x94,0x05,0x70,0x06,0xef,0x5a,0xa0,0xc3,0xa8,0xd1,0x8d,0x27,0x4b,0x1b,0x2a,0x94,0xc8,0x80,0x83,0x8f,0x11,0xe2,0x0b,0x68,0xd5,0x35,0xaf,0xaf,0x0c,0x2d,0xaa,0x3b,0x6d,0x11,0x0f,0x6e,0x93,0x32,0xd1,0x2e,0x6e,0x7f,0x52,0x54,0x9d,0xc2,0x6b,0x82,0x73,0xed,0x79,0x72,0x3a,0x89,0x29,0x4f,0x4d,0x2a,0x20};
// for LCCM AMSD
    uint8_t pk_ca_klcc[]={0x04,0x78,0x6b,0xca,0xba,0x50,0x94,0x05,0x70,0x06,0xef,0x5a,0xa0,0xc3,0xa8,0xd1,0x8d,0x27,0x4b,0x1b,0x2a,0x94,0xc8,0x80,0x83,0x8f,0x11,0xe2,0x0b,0x68,0xd5,0x35,0xaf,0xaf,0x0c,0x2d,0xaa,0x3b,0x6d,0x11,0x0f,0x6e,0x93,0x32,0xd1,0x2e,0x6e,0x7f,0x52,0x54,0x9d,0xc2,0x6b,0x82,0x73,0xed,0x79,0x72,0x3a,0x89,0x29,0x4f,0x4d,0x2a,0x20};
    #endif

    #ifdef GEM
//    uint8_t pk_ca_klcc[]={0x04,0x9d,0x89,0x9a,0xa9,0x03,0x5d,0x27,0x6d,0xae,0x20,0xd5,0x95,0x7f,0x1a,0x4e,0xa0,0xc2,0x4d,0x4b,0x41,0xe9,0x10,0xf9,0x76,0x95,0xee,0x88,0xc5,0xca,0xba,0xb0,0x73,0x4f,0x9e,0x33,0x9d,0x54,0xc3,0x60,0x9b,0x51,0x8c,0xd1,0x3b,0x71,0x8d,0xe7,0x6c,0x16,0x77,0x74,0x93,0x7c,0xe3,0x10,0xb6,0xd7,0x22,0xda,0xcc,0x08,0xa1,0x1f,0x58};
//    uint8_t pk_ca_klcc[]={0x04,0x71,0xB0,0x0F,0x2B,0x9A,0x57,0x43,0xE6,0xBC,0x40,0x4C,0x67,0x1F,0x68,0xBD,0x59,0xBD,0x56,0x1C,0x86,0x7E,0x3E,0x33,0x34,0x7B,0x43,0x9D,0x58,0xAF,0xD4,0x43,0xC7,0x7D,0x1A,0xE6,0xEB,0x25,0x62,0x8A,0x6E,0x40,0xD9,0xE1,0x9A,0x5B,0xB6,0xD5,0x7B,0xB3,0xFE,0x0D,0x1F,0xF4,0x34,0x1A,0x39,0xD3,0x77,0xE1,0x6F,0xE6,0x89,0xFF,0x48};
    uint8_t pk_ca_klcc[]={0x04,0xEE,0x99,0xCE,0xA1,0x61,0x3F,0x23,0xC9,0xC9,0x58,0xE3,0xB0,0xFF,0xCC,0xC6,0xEC,0x8D,0x21,0x2C,0x35,0x06,0x9E,0x92,0x82,0x71,0xAA,0x36,0xBD,0xFF,0xCF,0x05,0x81,0x3A,0xDC,0x04,0x5C,0x49,0xB1,0x73,0x12,0xA5,0x1A,0x3D,0xB4,0xA1,0x38,0x8D,0xFF,0x6E,0x64,0x99,0x3F,0xA6,0x09,0x95,0xAB,0x28,0x8B,0x39,0xB7,0x52,0x0A,0xFA,0x21};
    #endif

    #ifdef OT
// fake value just for OT build
    uint8_t pk_ca_klcc[]={0x04,0xEE,0x99,0xCE,0xA1,0x61,0x3F,0x23,0xC9,0xC9,0x58,0xE3,0xB0,0xFF,0xCC,0xC6,0xEC,0x8D,0x21,0x2C,0x35,0x06,0x9E,0x92,0x82,0x71,0xAA,0x36,0xBD,0xFF,0xCF,0x05,0x81,0x3A,0xDC,0x04,0x5C,0x49,0xB1,0x73,0x12,0xA5,0x1A,0x3D,0xB4,0xA1,0x38,0x8D,0xFF,0x6E,0x64,0x99,0x3F,0xA6,0x09,0x95,0xAB,0x28,0x8B,0x39,0xB7,0x52,0x0A,0xFA,0x21};
    #endif

    uint8_t cdata[] = {0xA6, 0x04, 0x83, 0x02, 0x11, 0x18};

    LOGI("scp11_get_data start");
    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 = 0xCA;
    cpdu.p1 = 0xBF;
    cpdu.p2 = 0x21;
    cpdu.lc = 0x06;
    cpdu.le = 0x00;
    cpdu.pdata = cdata;

    if (ESESTATUS_SUCCESS != secEseTransmit(channelId, &cpdu, &rpdu)) {
        LOGE("scp11_get_data failed to send APDU");
	return SCP11_GET_DATA_APDU_SEND_FAIL;
    }

    if(rpdu.sw1 == 0x90 && rpdu.sw2 == 0x00 && rpdu.len > 0) {
        if (rpdu.len > 0) {
            hex_print_tag_debug("cert.sd.ecka", rpdu.pdata, rpdu.len);
            LOGD("scp11_get_data pass. response : sw1 0x%2x,sw2 0x%2x,datalen %d",rpdu.sw1,rpdu.sw2,rpdu.len);
        }
    } else {
        LOGE("scp11_get_data failed. Invalid response : sw1 0x%2x,sw2 0x%2x,datalen %d",rpdu.sw1,rpdu.sw2,rpdu.len);
	return SCP11_GET_DATA_APDU_RETURN_FAIL;
    }

//parsing pk_sd_ecka,pk_sd_ecka_len,signiture from respond.

    pCardMetadata = &cardMeta_CERT_SD_ECKA;
    pData = (card_meta_struct_t_CERT_SD_ECKA *)pCardMetadata;

    memset(&pData->CERT_SD_ECKA_BF21_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_7F21_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_93_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_42_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_5F20_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_95_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_5F25_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_5F24_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_45_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_53_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_73_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_7F49_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_5F37_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_7F49_REAL_TLV, 0, sizeof(tlv_t));


    if (0 != scp11_parseBERTLV(FALSE, rpdu.pdata, &bufOffset, rpdu.len, TAG_CERT_SD_ECKA_BF21, &pData->CERT_SD_ECKA_BF21_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_BF21);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKA_BF21_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_BF21_TLV.tag, pData->CERT_SD_ECKA_BF21_TLV.dataLen, pData->CERT_SD_ECKA_BF21_TLV.dataOffset);

    message_temp_len=pData->CERT_SD_ECKA_BF21_TLV.dataLen;
    LOGD("message_temp_len : %d",message_temp_len);

    memcpy(&message_temp, rpdu.pdata + pData->CERT_SD_ECKA_BF21_TLV.dataOffset, message_temp_len);
    hex_print_tag_debug("message_temp", message_temp, message_temp_len);

    if (0 != scp11_parseBERTLV(FALSE, rpdu.pdata, &bufOffset, rpdu.len, TAG_CERT_SD_ECKA_7F21, &pData->CERT_SD_ECKA_7F21_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_7F21);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKA_7F21_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_7F21_TLV.tag, pData->CERT_SD_ECKA_7F21_TLV.dataLen, pData->CERT_SD_ECKA_7F21_TLV.dataOffset);


    if (0 != scp11_parseBERTLV(TRUE, rpdu.pdata, &bufOffset, rpdu.len, TAG_CERT_SD_ECKA_93, &pData->CERT_SD_ECKA_93_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_93);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKA_93_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_93_TLV.tag, pData->CERT_SD_ECKA_93_TLV.dataLen, pData->CERT_SD_ECKA_93_TLV.dataOffset);


    if (0 != scp11_parseBERTLV(TRUE, rpdu.pdata, &bufOffset, rpdu.len, TAG_CERT_SD_ECKA_42, &pData->CERT_SD_ECKA_42_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_42);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKA_42_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_42_TLV.tag, pData->CERT_SD_ECKA_42_TLV.dataLen, pData->CERT_SD_ECKA_42_TLV.dataOffset);


    if (0 != scp11_parseBERTLV(TRUE, rpdu.pdata, &bufOffset, rpdu.len, TAG_CERT_SD_ECKA_5F20, &pData->CERT_SD_ECKA_5F20_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_5F20);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKSCPSTATUSA_5F20_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_5F20_TLV.tag, pData->CERT_SD_ECKA_5F20_TLV.dataLen, pData->CERT_SD_ECKA_5F20_TLV.dataOffset);


    if (0 != scp11_parseBERTLV(TRUE, rpdu.pdata, &bufOffset, rpdu.len, TAG_CERT_SD_ECKA_95, &pData->CERT_SD_ECKA_95_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_95);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKA_95_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_95_TLV.tag, pData->CERT_SD_ECKA_95_TLV.dataLen, pData->CERT_SD_ECKA_95_TLV.dataOffset);

    ret = scp11_parseBERTLV(TRUE, rpdu.pdata, &bufOffset, rpdu.len, TAG_CERT_SD_ECKA_5F25, &pData->CERT_SD_ECKA_5F25_TLV);
    if (0 != ret) {
        if ( -2 == ret) {
            LOGE("It's ok TAG[%04X] is optional tag", TAG_CERT_SD_ECKA_5F25);
        } else {
            LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_5F25);
            return SCP11_PARBERTLV_FAIL;
        }
    } else {
        LOGD("CERT_SD_ECKA_5F25_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_5F25_TLV.tag, pData->CERT_SD_ECKA_5F25_TLV.dataLen, pData->CERT_SD_ECKA_5F25_TLV.dataOffset);
    }

    if (0 != scp11_parseBERTLV(TRUE, rpdu.pdata, &bufOffset, rpdu.len, TAG_CERT_SD_ECKA_5F24, &pData->CERT_SD_ECKA_5F24_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_5F24);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKA_5F24_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_5F24_TLV.tag, pData->CERT_SD_ECKA_5F24_TLV.dataLen, pData->CERT_SD_ECKA_5F24_TLV.dataOffset);


    if (0 != scp11_parseBERTLV(TRUE, rpdu.pdata, &bufOffset, rpdu.len, TAG_CERT_SD_ECKA_45, &pData->CERT_SD_ECKA_45_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_45);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKA_45_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_45_TLV.tag, pData->CERT_SD_ECKA_45_TLV.dataLen, pData->CERT_SD_ECKA_45_TLV.dataOffset);

    ret = scp11_parseBERTLV(TRUE, rpdu.pdata, &bufOffset, rpdu.len, TAG_CERT_SD_ECKA_53, &pData->CERT_SD_ECKA_53_TLV);
    if (0 != ret) {
        if ( -2 == ret) {
            LOGE("It's ok TAG[%04X] is optional tag", TAG_CERT_SD_ECKA_53);
        } else {
            LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_53);
            return SCP11_PARBERTLV_FAIL;
        }
    } else {
	LOGD("CERT_SD_ECKA_53_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_53_TLV.tag, pData->CERT_SD_ECKA_53_TLV.dataLen, pData->CERT_SD_ECKA_53_TLV.dataOffset);
    }

    ret = scp11_parseBERTLV(TRUE, rpdu.pdata, &bufOffset, rpdu.len, TAG_CERT_SD_ECKA_73, &pData->CERT_SD_ECKA_73_TLV);
    if (0 != ret) {
        if ( -2 == ret) {
            LOGE("It's ok TAG[%04X] is optional tag", TAG_CERT_SD_ECKA_73);
        } else {
            LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_73);
            return SCP11_PARBERTLV_FAIL;
        }
    } else {
	LOGD("CERT_SD_ECKA_73_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_73_TLV.tag, pData->CERT_SD_ECKA_73_TLV.dataLen, pData->CERT_SD_ECKA_73_TLV.dataOffset);
    }

    if (0 != scp11_parseBERTLV(TRUE, rpdu.pdata, &bufOffset, rpdu.len, TAG_CERT_SD_ECKA_7F49, &pData->CERT_SD_ECKA_7F49_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_7F49);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKA_7F49_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_7F49_TLV.tag, pData->CERT_SD_ECKA_7F49_TLV.dataLen, pData->CERT_SD_ECKA_7F49_TLV.dataOffset);

    if (0 != scp11_parseBERTLV(TRUE, rpdu.pdata, &bufOffset, rpdu.len, TAG_CERT_SD_ECKA_5F37, &pData->CERT_SD_ECKA_5F37_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_5F37);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKA_5F37_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_5F37_TLV.tag, pData->CERT_SD_ECKA_5F37_TLV.dataLen, pData->CERT_SD_ECKA_5F37_TLV.dataOffset);

    pk_sd_ecka_temp_len=pData->CERT_SD_ECKA_7F49_TLV.dataLen;
    signature_len=pData->CERT_SD_ECKA_5F37_TLV.dataLen;

    LOGD("pk_sd_ecka_temp_len : %d",pk_sd_ecka_temp_len);
    LOGD("signature_len : %d",signature_len);

    memcpy(&pk_sd_ecka_temp, rpdu.pdata + pData->CERT_SD_ECKA_7F49_TLV.dataOffset, pk_sd_ecka_temp_len);
    memcpy(&signature, rpdu.pdata + pData->CERT_SD_ECKA_5F37_TLV.dataOffset, signature_len);

    hex_print_tag_debug("pk_sd_ecka_temp", pk_sd_ecka_temp, pk_sd_ecka_temp_len);
    hex_print_tag_debug("signature", signature, signature_len);

    bufOffset=0;
    if (0 != scp11_parseBERTLV(TRUE, pk_sd_ecka_temp, &bufOffset, pk_sd_ecka_temp_len, TAG_CERT_SD_ECKA_7F49_REAL, &pData->CERT_SD_ECKA_7F49_REAL_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_7F49_REAL);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKA_7F49_REAL :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_7F49_REAL_TLV.tag, pData->CERT_SD_ECKA_7F49_REAL_TLV.dataLen, pData->CERT_SD_ECKA_7F49_REAL_TLV.dataOffset);

    pk_sd_ecka_len=pData->CERT_SD_ECKA_7F49_REAL_TLV.dataLen;
    memcpy(&pk_sd_ecka,  pk_sd_ecka_temp + pData->CERT_SD_ECKA_7F49_REAL_TLV.dataOffset, pk_sd_ecka_len);
    hex_print_tag_debug("pk_sd_ecka", pk_sd_ecka, pk_sd_ecka_len);

    message_len = message_temp_len - signature_len - 3 - 4;//3=signature tag+length size, 4=7f21 tag+length size
    LOGD("message_len : %d",message_len);

    memcpy(&message, 4+message_temp, message_len);
    hex_print_tag_debug("message", message, message_len);

    input.signature_len=signature_len;
    memcpy(input.signature,signature,input.signature_len);

    input.pk_ca_klcc_len=sizeof(pk_ca_klcc);
    memcpy(input.pk_ca_klcc,pk_ca_klcc,input.pk_ca_klcc_len);

    ret = crypto_sha256(digest, message, message_len, NULL );
    if (ESESTATUS_SUCCESS != ret) {
    	LOGE("scp11_crypto_sha256 Failed.");
        return SCP11_CRYPTO_SHA256_FAIL;
    }
    hex_print_tag_debug("digest", digest, sizeof(digest));

    input.digest_len=sizeof(digest);
    memcpy(input.digest,digest,input.digest_len);

    ret = scp11_verify_signature(input);
    if (ESESTATUS_SUCCESS != ret) {
            LOGE("scp11_verify_signature FAIL!");
            return SCP11_VERIFY_SIGNATURE_FAIL;
    }

    memcpy(get_data_key->pk_sd_ecka,&pk_sd_ecka,pk_sd_ecka_len);
    get_data_key->pk_sd_ecka_len=pk_sd_ecka_len;

    LOGI("scp11_get_data end");
    return SCP11_SUCCESS;
}

#ifdef CHAIN_OCE_CERT
#ifdef CHAIN_VERFIFICATION
SCP11STATUS scp11_cert_verification() {
//    uint8_t data[MAX_RAPDU_DATA_SIZE] = {0,};
    uint8_t pk_sd_ecka[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t pk_sd_ecka_temp[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t signature[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t message[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t message_temp[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t digest[32] = {0, };
    int32_t ret = 0;
    uint32_t bufOffset = 0;
    uint32_t pk_sd_ecka_len = 0;
    uint32_t pk_sd_ecka_temp_len = 0;
    uint32_t signature_len = 0;
    uint32_t message_len = 0;
//    uint32_t message_temp_len = 0;
    void* pCardMetadata = NULL;
    verify_signature_t input;
    uint32_t cert_oce_ecka_len;

// chain cert case : The payload is composed of a chain of certificates starting from the first (or only) CERT.KA-KLOC.ECDSA and ending with CERT.OCE.ECKA
//length : BC (less than FF => one command is enough)
//    uint8_t cert_ka_kloc_ecka[] ={0x7F,0x21,0x81,0xB8,0x93,0x08,0x20,0x19,0x06,0x26,0x10,0x00,0x00,0x00,0x42,0x04,0x53,0x4B,0x50,0x4D,0x5F,0x20,0x08,0x53,0x4B,0x50,0x4D,0x5F,0x53,0x55,0x42,0x95,0x01,0x82,0x5F,0x25,0x04,0x20,0x19,0x06,0x26,0x5F,0x24,0x04,0x20,0x69,0x12,0x31,0x7F,0x49,0x46,0xB0,0x41,0x04,0x35,0xC4,0x80,0x08,0x2F,0xD5,0xAE,0x06,0xE7,0x7F,0xFA,0x4C,0xA5,0x44,0xBA,0x37,0x82,0xBD,0x7C,0x7A,0x6E,0xC4,0x92,0xE5,0xE2,0x84,0x7C,0x3E,0x5B,0x01,0xA0,0x37,0x3A,0x40,0xCC,0xDA,0x7D,0xE1,0x22,0xEF,0xF8,0xA1,0x5F,0xC5,0x3B,0x6B,0x7C,0xE5,0x3D,0x31,0xD5,0x56,0x97,0xC9,0xDC,0x8C,0x5B,0xED,0xB8,0x3C,0x11,0x64,0xD1,0x45,0xF0,0x01,0x00,0x5F,0x37,0x40,0x6C,0x6F,0x4E,0xC0,0xA4,0xBA,0xC8,0x64,0xD4,0xAC,0x35,0x9D,0x35,0xE8,0x19,0x1C,0x70,0x93,0xE9,0xA5,0x4C,0xB5,0x57,0xC1,0x92,0xDF,0x14,0xC3,0x15,0x69,0xBC,0xF0,0xC8,0x55,0x30,0x0F,0x69,0x7A,0xF5,0x32,0x78,0xE6,0xC6,0xE3,0x0D,0x0E,0x1B,0xDD,0xAE,0xCB,0x61,0x9D,0xAB,0x32,0xFA,0x3D,0xFE,0xD3,0x96,0xC7,0x84,0xF6,0x84,0xB1};
//length : C4 (less than FF => one command is enough)
    uint8_t cert_oce_ecka[] ={0x7F,0x21,0x81,0xC0,0x93,0x08,0x20,0x19,0x06,0x26,0x10,0x00,0x00,0x00,0x42,0x08,0x53,0x4B,0x50,0x4D,0x5F,0x53,0x55,0x42,0x5F,0x20,0x0B,0x53,0x43,0x50,0x31,0x31,0x61,0x4E,0x5F,0x53,0x45,0x4D,0x95,0x02,0x00,0x80,0x5F,0x25,0x04,0x20,0x19,0x06,0x26,0x5F,0x24,0x04,0x20,0x69,0x12,0x31,0x7F,0x49,0x46,0xB0,0x41,0x04,0x7F,0xFB,0xEC,0x2E,0x86,0x2D,0x12,0xB1,0x11,0x02,0x43,0xEF,0xCB,0xE9,0x14,0x15,0xD7,0xD6,0x32,0xEE,0xCF,0x41,0x15,0x92,0xCB,0x26,0xD5,0x64,0xAF,0xA9,0xA8,0x37,0xB8,0x38,0x52,0x4E,0x10,0xEF,0x5E,0x60,0xF5,0x6A,0xB5,0xD1,0x4B,0xD8,0xFA,0xA8,0x97,0x91,0xBA,0x28,0xEE,0x14,0xA8,0xAB,0x82,0xE7,0x65,0x4C,0xEC,0xC1,0x82,0x4B,0xF0,0x01,0x00,0x5F,0x37,0x40,0xD9,0x0D,0x01,0xD6,0xD5,0xD0,0x01,0x70,0x96,0xD7,0x1B,0x37,0xA9,0x19,0xFB,0x05,0xB4,0xF7,0x81,0x59,0xA2,0x57,0x5E,0x87,0x64,0x3D,0xF0,0x28,0x29,0xE4,0x3C,0x09,0x53,0x02,0xD8,0xF3,0x7C,0x16,0x10,0x4F,0xFB,0xC2,0x2E,0x67,0xAA,0x5E,0x26,0x7B,0x03,0x8A,0x26,0xB4,0xAE,0x76,0xCB,0x71,0xF3,0x66,0x7C,0x3C,0xFA,0x59,0x36,0x82};


    #ifdef NXP
//    uint8_t pk_ca_klcc[]={0x04,0x78,0x6b,0xca,0xba,0x50,0x94,0x05,0x70,0x06,0xef,0x5a,0xa0,0xc3,0xa8,0xd1,0x8d,0x27,0x4b,0x1b,0x2a,0x94,0xc8,0x80,0x83,0x8f,0x11,0xe2,0x0b,0x68,0xd5,0x35,0xaf,0xaf,0x0c,0x2d,0xaa,0x3b,0x6d,0x11,0x0f,0x6e,0x93,0x32,0xd1,0x2e,0x6e,0x7f,0x52,0x54,0x9d,0xc2,0x6b,0x82,0x73,0xed,0x79,0x72,0x3a,0x89,0x29,0x4f,0x4d,0x2a,0x20};
// for LCCM AMSD
//    uint8_t pk_ca_kloc[]={0x04,0x57,0x45,0xE2,0x1B,0x2C,0x09,0xB7,0xE1,0x10,0x89,0x27,0xD7,0xBB,0x44,0x64,0x11,0xA4,0x68,0x06,0x95,0xAD,0xAD,0x98,0xFC,0x3B,0x91,0xDC,0x03,0xDF,0xE1,0xA5,0x80,0x75,0x91,0xAB,0x7D,0xDF,0x1C,0x44,0xD3,0x8C,0x1E,0x21,0xF6,0x50,0xD4,0xA3,0xE8,0x5D,0x31,0xC9,0xF8,0x6A,0xC6,0x1F,0xED,0x0C,0x69,0x62,0x6F,0xFC,0xB4,0x25,0x76};
    uint8_t pk_ka_kloc[]=
{0x04,0x04,0xF3,0x1A,0x6C,0x36,0xDD,0xB0,0xF7,0xBC,0xF1,0x76,0x60,0x40,0x27,0x26,0x30,0x86,0x92,0x39,0xEA,0x9A,0x65,0x4A,0x23,0xB3,0xD1,0xAD,0xB9,0x2D,0xE8,0x27,0x74,0x5A,0x03,0xA7,0x31,0x6F,0xDC,0x54,0xC5,0xAB,0x8D,0xB9,0xD9,0x80,0x73,0x61,0xEB,0x06,0xBA,0x5F,0x7E,0x55,0xB1,0x66,0xE0,0xB3,0x76,0xD8,0xB3,0x3A,0x39,0xD7,0x7C,0x39};
    #endif

    #ifdef GEM
//    uint8_t pk_ca_klcc[]={0x04,0x9d,0x89,0x9a,0xa9,0x03,0x5d,0x27,0x6d,0xae,0x20,0xd5,0x95,0x7f,0x1a,0x4e,0xa0,0xc2,0x4d,0x4b,0x41,0xe9,0x10,0xf9,0x76,0x95,0xee,0x88,0xc5,0xca,0xba,0xb0,0x73,0x4f,0x9e,0x33,0x9d,0x54,0xc3,0x60,0x9b,0x51,0x8c,0xd1,0x3b,0x71,0x8d,0xe7,0x6c,0x16,0x77,0x74,0x93,0x7c,0xe3,0x10,0xb6,0xd7,0x22,0xda,0xcc,0x08,0xa1,0x1f,0x58};
//    uint8_t pk_ca_klcc[]={0x04,0x71,0xB0,0x0F,0x2B,0x9A,0x57,0x43,0xE6,0xBC,0x40,0x4C,0x67,0x1F,0x68,0xBD,0x59,0xBD,0x56,0x1C,0x86,0x7E,0x3E,0x33,0x34,0x7B,0x43,0x9D,0x58,0xAF,0xD4,0x43,0xC7,0x7D,0x1A,0xE6,0xEB,0x25,0x62,0x8A,0x6E,0x40,0xD9,0xE1,0x9A,0x5B,0xB6,0xD5,0x7B,0xB3,0xFE,0x0D,0x1F,0xF4,0x34,0x1A,0x39,0xD3,0x77,0xE1,0x6F,0xE6,0x89,0xFF,0x48};
//    uint8_t pk_ca_kloc[]={0x04,0xEE,0x99,0xCE,0xA1,0x61,0x3F,0x23,0xC9,0xC9,0x58,0xE3,0xB0,0xFF,0xCC,0xC6,0xEC,0x8D,0x21,0x2C,0x35,0x06,0x9E,0x92,0x82,0x71,0xAA,0x36,0xBD,0xFF,0xCF,0x05,0x81,0x3A,0xDC,0x04,0x5C,0x49,0xB1,0x73,0x12,0xA5,0x1A,0x3D,0xB4,0xA1,0x38,0x8D,0xFF,0x6E,0x64,0x99,0x3F,0xA6,0x09,0x95,0xAB,0x28,0x8B,0x39,0xB7,0x52,0x0A,0xFA,0x21};
    uint8_t pk_ka_kloc[]={0x04,0x06,0x51,0x35,0xA6,0xD5,0x1A,0x41,0x66,0x11,0x16,0xB6,0x89,0x85,0x07,0x8F,0xED,0xB8,0x3D,0x7A,0x46,0x16,0x83,0xF5,0xBF,0x27,0x1B,0xAD,0x4A,0x58,0x95,0x7E,0x65,0x01,0x4E,0x4C,0x40,0x8F,0xFE,0x11,0x65,0x09,0xE6,0xC5,0xA9,0xAB,0x48,0xC3,0x27,0x5A,0xDF,0x6A,0x6D,0xA1,0x30,0x56,0x44,0xDB,0x98,0xEC,0x6A,0x2E,0x89,0xA7,0xC6};

    #endif

    #ifdef OT
// fake value just for OT build
//    uint8_t pk_ca_kloc[]={0x04,0xEE,0x99,0xCE,0xA1,0x61,0x3F,0x23,0xC9,0xC9,0x58,0xE3,0xB0,0xFF,0xCC,0xC6,0xEC,0x8D,0x21,0x2C,0x35,0x06,0x9E,0x92,0x82,0x71,0xAA,0x36,0xBD,0xFF,0xCF,0x05,0x81,0x3A,0xDC,0x04,0x5C,0x49,0xB1,0x73,0x12,0xA5,0x1A,0x3D,0xB4,0xA1,0x38,0x8D,0xFF,0x6E,0x64,0x99,0x3F,0xA6,0x09,0x95,0xAB,0x28,0x8B,0x39,0xB7,0x52,0x0A,0xFA,0x21};
    uint8_t pk_ka_kloc[]={0x04,0x06,0x51,0x35,0xA6,0xD5,0x1A,0x41,0x66,0x11,0x16,0xB6,0x89,0x85,0x07,0x8F,0xED,0xB8,0x3D,0x7A,0x46,0x16,0x83,0xF5,0xBF,0x27,0x1B,0xAD,0x4A,0x58,0x95,0x7E,0x65,0x01,0x4E,0x4C,0x40,0x8F,0xFE,0x11,0x65,0x09,0xE6,0xC5,0xA9,0xAB,0x48,0xC3,0x27,0x5A,0xDF,0x6A,0x6D,0xA1,0x30,0x56,0x44,0xDB,0x98,0xEC,0x6A,0x2E,0x89,0xA7,0xC6};
    #endif

    card_meta_struct_t_CERT_SD_ECKA cardMeta_CERT_SD_ECKA;
    card_meta_struct_t_CERT_SD_ECKA * pData = NULL;

    LOGI("scp11_cert_verification start");

//parsing pk_sd_ecka,pk_sd_ecka_len,signiture from respond.
    pCardMetadata = &cardMeta_CERT_SD_ECKA;
    pData = (card_meta_struct_t_CERT_SD_ECKA *)pCardMetadata;

//    memset(&pData->CERT_SD_ECKA_BF21_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_7F21_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_93_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_42_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_5F20_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_95_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_5F25_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_5F24_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_45_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_53_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_73_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_7F49_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_5F37_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_SD_ECKA_7F49_REAL_TLV, 0, sizeof(tlv_t));


//    skpm_cert_key_t *skpm_cert_key;
    cert_oce_ecka_len=sizeof(cert_oce_ecka);


/*
    if (0 != scp11_parseBERTLV(FALSE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_SD_ECKA_BF21, &pData->CERT_SD_ECKA_BF21_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_BF21);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKA_BF21_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_BF21_TLV.tag, pData->CERT_SD_ECKA_BF21_TLV.dataLen, pData->CERT_SD_ECKA_BF21_TLV.dataOffset);

    message_temp_len=pData->CERT_SD_ECKA_BF21_TLV.dataLen;
    LOGD("message_temp_len : %d",message_temp_len);

    memcpy(&message_temp, cert_oce_ecka + pData->CERT_SD_ECKA_BF21_TLV.dataOffset, message_temp_len);
    hex_print_tag_debug("message_temp", message_temp, message_temp_len);
*/
    if (0 != scp11_parseBERTLV(FALSE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_SD_ECKA_7F21, &pData->CERT_SD_ECKA_7F21_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_7F21);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKA_7F21_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_7F21_TLV.tag, pData->CERT_SD_ECKA_7F21_TLV.dataLen, pData->CERT_SD_ECKA_7F21_TLV.dataOffset);


    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_SD_ECKA_93, &pData->CERT_SD_ECKA_93_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_93);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKA_93_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_93_TLV.tag, pData->CERT_SD_ECKA_93_TLV.dataLen, pData->CERT_SD_ECKA_93_TLV.dataOffset);


    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_SD_ECKA_42, &pData->CERT_SD_ECKA_42_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_42);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKA_42_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_42_TLV.tag, pData->CERT_SD_ECKA_42_TLV.dataLen, pData->CERT_SD_ECKA_42_TLV.dataOffset);


    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_SD_ECKA_5F20, &pData->CERT_SD_ECKA_5F20_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_5F20);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKSCPSTATUSA_5F20_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_5F20_TLV.tag, pData->CERT_SD_ECKA_5F20_TLV.dataLen, pData->CERT_SD_ECKA_5F20_TLV.dataOffset);


    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_SD_ECKA_95, &pData->CERT_SD_ECKA_95_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_95);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKA_95_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_95_TLV.tag, pData->CERT_SD_ECKA_95_TLV.dataLen, pData->CERT_SD_ECKA_95_TLV.dataOffset);

    ret = scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_SD_ECKA_5F25, &pData->CERT_SD_ECKA_5F25_TLV);
    if (0 != ret) {
        if ( -2 == ret) {
            LOGE("It's ok TAG[%04X] is optional tag", TAG_CERT_SD_ECKA_5F25);
        } else {
            LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_5F25);
            return SCP11_PARBERTLV_FAIL;
        }
    } else {
        LOGD("CERT_SD_ECKA_5F25_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_5F25_TLV.tag, pData->CERT_SD_ECKA_5F25_TLV.dataLen, pData->CERT_SD_ECKA_5F25_TLV.dataOffset);
    }

    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_SD_ECKA_5F24, &pData->CERT_SD_ECKA_5F24_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_5F24);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKA_5F24_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_5F24_TLV.tag, pData->CERT_SD_ECKA_5F24_TLV.dataLen, pData->CERT_SD_ECKA_5F24_TLV.dataOffset);
/*

    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_SD_ECKA_45, &pData->CERT_SD_ECKA_45_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_45);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKA_45_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_45_TLV.tag, pData->CERT_SD_ECKA_45_TLV.dataLen, pData->CERT_SD_ECKA_45_TLV.dataOffset);

    ret = scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_SD_ECKA_53, &pData->CERT_SD_ECKA_53_TLV);
    if (0 != ret) {
        if ( -2 == ret) {
            LOGE("It's ok TAG[%04X] is optional tag", TAG_CERT_SD_ECKA_53);
        } else {
            LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_53);
            return SCP11_PARBERTLV_FAIL;
        }
    } else {
	LOGD("CERT_SD_ECKA_53_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_53_TLV.tag, pData->CERT_SD_ECKA_53_TLV.dataLen, pData->CERT_SD_ECKA_53_TLV.dataOffset);
    }

    ret = scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_SD_ECKA_73, &pData->CERT_SD_ECKA_73_TLV);
    if (0 != ret) {
        if ( -2 == ret) {
            LOGE("It's ok TAG[%04X] is optional tag", TAG_CERT_SD_ECKA_73);
        } else {
            LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_73);
            return SCP11_PARBERTLV_FAIL;
        }
    } else {
	LOGD("CERT_SD_ECKA_73_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_73_TLV.tag, pData->CERT_SD_ECKA_73_TLV.dataLen, pData->CERT_SD_ECKA_73_TLV.dataOffset);
    }
*/
    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_SD_ECKA_7F49, &pData->CERT_SD_ECKA_7F49_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_7F49);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKA_7F49_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_7F49_TLV.tag, pData->CERT_SD_ECKA_7F49_TLV.dataLen, pData->CERT_SD_ECKA_7F49_TLV.dataOffset);

    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_SD_ECKA_5F37, &pData->CERT_SD_ECKA_5F37_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_5F37);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKA_5F37_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_5F37_TLV.tag, pData->CERT_SD_ECKA_5F37_TLV.dataLen, pData->CERT_SD_ECKA_5F37_TLV.dataOffset);

    pk_sd_ecka_temp_len=pData->CERT_SD_ECKA_7F49_TLV.dataLen;
    signature_len=pData->CERT_SD_ECKA_5F37_TLV.dataLen;

    LOGD("pk_sd_ecka_temp_len : %d",pk_sd_ecka_temp_len);
    LOGD("signature_len : %d",signature_len);

    memcpy(&pk_sd_ecka_temp, cert_oce_ecka + pData->CERT_SD_ECKA_7F49_TLV.dataOffset, pk_sd_ecka_temp_len);
    memcpy(&signature, cert_oce_ecka + pData->CERT_SD_ECKA_5F37_TLV.dataOffset, signature_len);

    hex_print_tag_debug("pk_sd_ecka_temp", pk_sd_ecka_temp, pk_sd_ecka_temp_len);
    hex_print_tag_debug("signature", signature, signature_len);

    bufOffset=0;
    if (0 != scp11_parseBERTLV(TRUE, pk_sd_ecka_temp, &bufOffset, pk_sd_ecka_temp_len, TAG_CERT_SD_ECKA_7F49_REAL, &pData->CERT_SD_ECKA_7F49_REAL_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_SD_ECKA_7F49_REAL);
	return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_SD_ECKA_7F49_REAL :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_SD_ECKA_7F49_REAL_TLV.tag, pData->CERT_SD_ECKA_7F49_REAL_TLV.dataLen, pData->CERT_SD_ECKA_7F49_REAL_TLV.dataOffset);

    pk_sd_ecka_len=pData->CERT_SD_ECKA_7F49_REAL_TLV.dataLen;
    memcpy(&pk_sd_ecka,  pk_sd_ecka_temp + pData->CERT_SD_ECKA_7F49_REAL_TLV.dataOffset, pk_sd_ecka_len);
    hex_print_tag_debug("pk_sd_ecka", pk_sd_ecka, pk_sd_ecka_len);

    message_len = cert_oce_ecka_len - signature_len - 3 - 4;//3=signature tag+length size, 4=7f21 tag+length size
    LOGD("message_len : %d",message_len);

    memcpy(&message, 4+message_temp, message_len);
    hex_print_tag_debug("message", message, message_len);

    input.signature_len=signature_len;
    memcpy(input.signature,signature,input.signature_len);

    input.pk_ca_klcc_len=sizeof(pk_ka_kloc);
    memcpy(input.pk_ca_klcc,pk_ka_kloc,input.pk_ca_klcc_len);

    ret = crypto_sha256(digest, message, message_len, NULL );
    if (ESESTATUS_SUCCESS != ret) {
    	LOGE("scp11_crypto_sha256 Failed.");
        return SCP11_CRYPTO_SHA256_FAIL;
    }
    hex_print_tag_debug("digest", digest, sizeof(digest));

    input.digest_len=sizeof(digest);
    memcpy(input.digest,digest,input.digest_len);

    ret = scp11_verify_signature(input);
    if (ESESTATUS_SUCCESS != ret) {
            LOGE("scp11_verify_signature FAIL!");
            return SCP11_VERIFY_SIGNATURE_FAIL;
    }

    LOGI("scp11_cert_verification end");

    return SCP11_SUCCESS;
}
#endif //#ifdef CHAIN_VERFIFICATION

SCP11STATUS scp11_perform_security_operation(uint8_t channelId, skpm_cert_key_t *skpm_ka_kloc_cert_key, skpm_cert_key_t *skpm_cert_key, perform_security_operation_t *perform_security_operation_key) {
    uint8_t pk_oce_ecka_temp[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t pk_oce_ecka[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t cert_oce_ecka[MAX_SCP11_DATA_SIZE] = {0,},cert_ka_kloc_oce_ecka[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t data[MAX_RAPDU_DATA_SIZE] = {0,};
    int32_t ret = 0;
    uint32_t pk_oce_ecka_temp_len = 0;
    uint32_t pk_oce_ecka_len = 0;

    uint32_t cert_oce_ecka_len = 0, cert_ka_kloc_oce_ecka_len = 0;
    uint32_t bufOffset = 0;
    void* pCardMetadata = NULL;
    secEse_7816_cpdu_t cpdu, ka_cpdu;
    secEse_7816_rpdu_t rpdu, ka_rpdu;

    card_meta_struct_t_CERT_OCE_ECKA cardMeta_CERT_OCE_ECKA;
    card_meta_struct_t_CERT_OCE_ECKA * pData = NULL;

#ifdef CHAIN_VERFIFICATION
    LOGI("(chain) scp11_cert_verification start");
    scp11_cert_verification();
#endif //#ifdef CHAIN_VERFIFICATION

    LOGI("(chain) scp11_perform_security_operation start");

    LOGI("(ka-kloc) scp11_perform_security_operation start");
    memcpy(cert_ka_kloc_oce_ecka, &skpm_ka_kloc_cert_key->cert_oce_ecka, skpm_ka_kloc_cert_key->cert_oce_ecka_len);
    cert_ka_kloc_oce_ecka_len=skpm_ka_kloc_cert_key->cert_oce_ecka_len;
    hex_print_tag_debug("cert_oce_ecka", cert_ka_kloc_oce_ecka, cert_ka_kloc_oce_ecka_len);

    memset(&ka_cpdu, 0, sizeof(secEse_7816_cpdu_t));
    memset(&ka_rpdu, 0, sizeof(secEse_7816_rpdu_t));
    memset(data, 0, MAX_RAPDU_DATA_SIZE);
    ka_rpdu.pdata = data;

    ka_cpdu.cla = 0x80;
    ka_cpdu.ins = 0x2A;
    ka_cpdu.p1 = 0x18;
    ka_cpdu.p2 = 0x90;
    ka_cpdu.lc = cert_ka_kloc_oce_ecka_len;
    ka_cpdu.pdata = cert_ka_kloc_oce_ecka;
    ka_cpdu.le = 0x00;


    if (ESESTATUS_SUCCESS != secEseTransmit(channelId, &ka_cpdu, &ka_rpdu)) {
        LOGE("(ka-kloc) scp11_perform_security_operation failed to send APDU");
        return SCP11_PERFORM_SECURITY_OPERATION_APDU_SEND_FAIL;
    }

    if(ka_rpdu.sw1 == 0x90 && ka_rpdu.sw2 == 0x00) {
        LOGD("(ka-kloc) scp11_perform_security_operation pass. response : sw1 0x%2x,sw2 0x%2x,datalen %d",ka_rpdu.sw1,ka_rpdu.sw2,ka_rpdu.len);
    } else {
        LOGE("(ka-kloc) scp11_perform_security_operation failed. Invalid response : sw1 0x%2x,sw2 0x%2x,datalen %d",ka_rpdu.sw1,ka_rpdu.sw2,ka_rpdu.len);
        return SCP11_PERFORM_SECURITY_OPERATION_APDU_RETURN_FAIL;
    }


    LOGI("scp11_perform_security_operation start (leaf)");
    memcpy(cert_oce_ecka, &skpm_cert_key->cert_oce_ecka, skpm_cert_key->cert_oce_ecka_len);
    cert_oce_ecka_len=skpm_cert_key->cert_oce_ecka_len;
    hex_print_tag_debug("cert_oce_ecka", cert_oce_ecka, cert_oce_ecka_len);

    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 = 0x2A;
    cpdu.p1 = 0x18;
    cpdu.p2 = 0x10;
    cpdu.lc = cert_oce_ecka_len;
    cpdu.pdata = cert_oce_ecka;
    cpdu.le = 0x00;

//parsing pk_oce_ecka signiture from cert_oce_ecka.
    pCardMetadata = &cardMeta_CERT_OCE_ECKA;
    pData = (card_meta_struct_t_CERT_OCE_ECKA *)pCardMetadata;

    memset(&pData->CERT_OCE_ECKA_7F21_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_93_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_42_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_5F20_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_95_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_5F25_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_5F24_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_53_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_73_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_7F49_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_5F37_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_7F49_REAL_TLV, 0, sizeof(tlv_t));

    if (0 != scp11_parseBERTLV(FALSE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_7F21, &pData->CERT_OCE_ECKA_7F21_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_7F21);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_OCE_ECKA_7F21_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_7F21_TLV.tag, pData->CERT_OCE_ECKA_7F21_TLV.dataLen, pData->CERT_OCE_ECKA_7F21_TLV.dataOffset);


    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_93, &pData->CERT_OCE_ECKA_93_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_93);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_OCE_ECKA_93_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_93_TLV.tag, pData->CERT_OCE_ECKA_93_TLV.dataLen, pData->CERT_OCE_ECKA_93_TLV.dataOffset);


    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_42, &pData->CERT_OCE_ECKA_42_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_42);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_OCE_ECKA_42_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_42_TLV.tag, pData->CERT_OCE_ECKA_42_TLV.dataLen, pData->CERT_OCE_ECKA_42_TLV.dataOffset);


    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_5F20, &pData->CERT_OCE_ECKA_5F20_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_5F20);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_OCE_ECKA_5F20_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_5F20_TLV.tag, pData->CERT_OCE_ECKA_5F20_TLV.dataLen, pData->CERT_OCE_ECKA_5F20_TLV.dataOffset);


    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_95, &pData->CERT_OCE_ECKA_95_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_95);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_OCE_ECKA_95_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_95_TLV.tag, pData->CERT_OCE_ECKA_95_TLV.dataLen, pData->CERT_OCE_ECKA_95_TLV.dataOffset);

    ret = scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_5F25, &pData->CERT_OCE_ECKA_5F25_TLV);
    if (0 != ret) {
        if ( -2 == ret) {
            LOGE("It's ok TAG[%04X] is optional tag", TAG_CERT_OCE_ECKA_5F25);
        } else {
            LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_5F25);
            return SCP11_PARBERTLV_FAIL;
        }
    } else {
        LOGD("CERT_OCE_ECKA_5F25_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_5F25_TLV.tag, pData->CERT_OCE_ECKA_5F25_TLV.dataLen, pData->CERT_OCE_ECKA_5F25_TLV.dataOffset);
    }

    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_5F24, &pData->CERT_OCE_ECKA_5F24_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_5F24);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_OCE_ECKA_5F24_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_5F24_TLV.tag, pData->CERT_OCE_ECKA_5F24_TLV.dataLen, pData->CERT_OCE_ECKA_5F24_TLV.dataOffset);

    ret = scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_53, &pData->CERT_OCE_ECKA_53_TLV);
    if (0 != ret) {
        if ( -2 == ret) {
            LOGE("It's ok TAG[%04X] is optional tag", TAG_CERT_OCE_ECKA_53);
        } else {
            LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_53);
            return SCP11_PARBERTLV_FAIL;
        }
    } else {
        LOGD("CERT_OCE_ECKA_53_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_53_TLV.tag, pData->CERT_OCE_ECKA_53_TLV.dataLen, pData->CERT_OCE_ECKA_53_TLV.dataOffset);
    }

    ret = scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_73, &pData->CERT_OCE_ECKA_73_TLV);
    if (0 != ret) {
        if ( -2 == ret) {
            LOGE("It's ok TAG[%04X] is optional tag", TAG_CERT_OCE_ECKA_73);
        } else {
            LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_73);
            return SCP11_PARBERTLV_FAIL;
        }
    } else {
        LOGD("CERT_OCE_ECKA_73_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_73_TLV.tag, pData->CERT_OCE_ECKA_73_TLV.dataLen, pData->CERT_OCE_ECKA_73_TLV.dataOffset);
    }

    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_7F49, &pData->CERT_OCE_ECKA_7F49_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_7F49);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_OCE_ECKA_7F49_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_7F49_TLV.tag, pData->CERT_OCE_ECKA_7F49_TLV.dataLen, pData->CERT_OCE_ECKA_7F49_TLV.dataOffset);


    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_5F37, &pData->CERT_OCE_ECKA_5F37_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_5F37);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_OCE_ECKA_5F37_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_5F37_TLV.tag, pData->CERT_OCE_ECKA_5F37_TLV.dataLen, pData->CERT_OCE_ECKA_5F37_TLV.dataOffset);

    pk_oce_ecka_temp_len=pData->CERT_OCE_ECKA_7F49_TLV.dataLen;
    LOGD("pk_oce_ecka_temp_len : %d",pk_oce_ecka_temp_len);

    memcpy(&pk_oce_ecka_temp, cert_oce_ecka + pData->CERT_OCE_ECKA_7F49_TLV.dataOffset, pk_oce_ecka_temp_len);
    hex_print_tag_debug("pk_oce_ecka_temp", pk_oce_ecka_temp, pk_oce_ecka_temp_len);


    bufOffset=0;
    if (0 != scp11_parseBERTLV(TRUE, pk_oce_ecka_temp, &bufOffset, pk_oce_ecka_temp_len, TAG_CERT_OCE_ECKA_7F49_REAL, &pData->CERT_OCE_ECKA_7F49_REAL_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_7F49_REAL);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_OCE_ECKA_7F49_REAL :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_7F49_REAL_TLV.tag, pData->CERT_OCE_ECKA_7F49_REAL_TLV.dataLen, pData->CERT_OCE_ECKA_7F49_REAL_TLV.dataOffset);

    pk_oce_ecka_len=pData->CERT_OCE_ECKA_7F49_REAL_TLV.dataLen;
    memcpy(&pk_oce_ecka,  pk_oce_ecka_temp + pData->CERT_OCE_ECKA_7F49_REAL_TLV.dataOffset, pk_oce_ecka_len);
    hex_print_tag_debug("pk_oce_ecka", pk_oce_ecka, pk_oce_ecka_len);

    if (ESESTATUS_SUCCESS != secEseTransmit(channelId, &cpdu, &rpdu)) {
        LOGE("scp11_perform_security_operation failed to send APDU");
        return SCP11_PERFORM_SECURITY_OPERATION_APDU_SEND_FAIL;
    }

    if(rpdu.sw1 == 0x90 && rpdu.sw2 == 0x00) {
        LOGD("scp11_perform_security_operation pass. response : sw1 0x%2x,sw2 0x%2x,datalen %d",rpdu.sw1,rpdu.sw2,rpdu.len);
    } else {
        LOGE("scp11_perform_security_operation failed. Invalid response : sw1 0x%2x,sw2 0x%2x,datalen %d",rpdu.sw1,rpdu.sw2,rpdu.len);
        return SCP11_PERFORM_SECURITY_OPERATION_APDU_RETURN_FAIL;
    }

    memcpy(perform_security_operation_key->pk_oce_ecka,&pk_oce_ecka,pk_oce_ecka_len);
    perform_security_operation_key->pk_oce_ecka_len=pk_oce_ecka_len;

    LOGI("scp11_perform_security_operation end");
    return SCP11_SUCCESS;
}

#else // #ifdef CHAIN_OCE_CERT
SCP11STATUS scp11_perform_security_operation(uint8_t channelId, skpm_cert_key_t *skpm_cert_key, perform_security_operation_t *perform_security_operation_key) {
    uint8_t pk_oce_ecka_temp[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t pk_oce_ecka[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t cert_oce_ecka[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t data[MAX_RAPDU_DATA_SIZE] = {0,};
    int32_t ret = 0;
    uint32_t pk_oce_ecka_temp_len = 0;
    uint32_t pk_oce_ecka_len = 0;
    uint32_t cert_oce_ecka_len = 0;
    uint32_t bufOffset = 0;
    void* pCardMetadata = NULL;
    secEse_7816_cpdu_t cpdu;
    secEse_7816_rpdu_t rpdu;

    LOGI("scp11_perform_security_operation start");

    memcpy(cert_oce_ecka, &skpm_cert_key->cert_oce_ecka, skpm_cert_key->cert_oce_ecka_len);
    cert_oce_ecka_len=skpm_cert_key->cert_oce_ecka_len;
    hex_print_tag_debug("cert_oce_ecka", cert_oce_ecka, cert_oce_ecka_len);

    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 = 0x2A;
    cpdu.p1 = 0x18;
    cpdu.p2 = 0x10;
    cpdu.lc = cert_oce_ecka_len;
    cpdu.pdata = cert_oce_ecka;
    cpdu.le = 0x00;

//parsing pk_oce_ecka signiture from cert_oce_ecka.
    card_meta_struct_t_CERT_OCE_ECKA cardMeta_CERT_OCE_ECKA;
    pCardMetadata = &cardMeta_CERT_OCE_ECKA;
    card_meta_struct_t_CERT_OCE_ECKA * pData = (card_meta_struct_t_CERT_OCE_ECKA *)pCardMetadata;

    memset(&pData->CERT_OCE_ECKA_7F21_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_93_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_42_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_5F20_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_95_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_5F25_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_5F24_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_53_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_73_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_7F49_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_5F37_TLV, 0, sizeof(tlv_t));
    memset(&pData->CERT_OCE_ECKA_7F49_REAL_TLV, 0, sizeof(tlv_t));

    if (0 != scp11_parseBERTLV(FALSE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_7F21, &pData->CERT_OCE_ECKA_7F21_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_7F21);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_OCE_ECKA_7F21_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_7F21_TLV.tag, pData->CERT_OCE_ECKA_7F21_TLV.dataLen, pData->CERT_OCE_ECKA_7F21_TLV.dataOffset);


    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_93, &pData->CERT_OCE_ECKA_93_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_93);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_OCE_ECKA_93_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_93_TLV.tag, pData->CERT_OCE_ECKA_93_TLV.dataLen, pData->CERT_OCE_ECKA_93_TLV.dataOffset);


    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_42, &pData->CERT_OCE_ECKA_42_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_42);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_OCE_ECKA_42_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_42_TLV.tag, pData->CERT_OCE_ECKA_42_TLV.dataLen, pData->CERT_OCE_ECKA_42_TLV.dataOffset);


    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_5F20, &pData->CERT_OCE_ECKA_5F20_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_5F20);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_OCE_ECKA_5F20_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_5F20_TLV.tag, pData->CERT_OCE_ECKA_5F20_TLV.dataLen, pData->CERT_OCE_ECKA_5F20_TLV.dataOffset);


    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_95, &pData->CERT_OCE_ECKA_95_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_95);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_OCE_ECKA_95_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_95_TLV.tag, pData->CERT_OCE_ECKA_95_TLV.dataLen, pData->CERT_OCE_ECKA_95_TLV.dataOffset);

    ret = scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_5F25, &pData->CERT_OCE_ECKA_5F25_TLV);
    if (0 != ret) {
        if ( -2 == ret) {
            LOGE("It's ok TAG[%04X] is optional tag", TAG_CERT_OCE_ECKA_5F25);
        } else {
            LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_5F25);
            return SCP11_PARBERTLV_FAIL;
        }
    } else {
        LOGD("CERT_OCE_ECKA_5F25_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_5F25_TLV.tag, pData->CERT_OCE_ECKA_5F25_TLV.dataLen, pData->CERT_OCE_ECKA_5F25_TLV.dataOffset);
    }

    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_5F24, &pData->CERT_OCE_ECKA_5F24_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_5F24);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_OCE_ECKA_5F24_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_5F24_TLV.tag, pData->CERT_OCE_ECKA_5F24_TLV.dataLen, pData->CERT_OCE_ECKA_5F24_TLV.dataOffset);

    ret = scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_53, &pData->CERT_OCE_ECKA_53_TLV);
    if (0 != ret) {
        if ( -2 == ret) {
            LOGE("It's ok TAG[%04X] is optional tag", TAG_CERT_OCE_ECKA_53);
        } else {
            LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_53);
            return SCP11_PARBERTLV_FAIL;
        }
    } else {
        LOGD("CERT_OCE_ECKA_53_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_53_TLV.tag, pData->CERT_OCE_ECKA_53_TLV.dataLen, pData->CERT_OCE_ECKA_53_TLV.dataOffset);
    }

    ret = scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_73, &pData->CERT_OCE_ECKA_73_TLV);
    if (0 != ret) {
        if ( -2 == ret) {
            LOGE("It's ok TAG[%04X] is optional tag", TAG_CERT_OCE_ECKA_73);
        } else {
            LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_73);
            return SCP11_PARBERTLV_FAIL;
        }
    } else {
        LOGD("CERT_OCE_ECKA_73_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_73_TLV.tag, pData->CERT_OCE_ECKA_73_TLV.dataLen, pData->CERT_OCE_ECKA_73_TLV.dataOffset);
    }

    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_7F49, &pData->CERT_OCE_ECKA_7F49_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_7F49);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_OCE_ECKA_7F49_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_7F49_TLV.tag, pData->CERT_OCE_ECKA_7F49_TLV.dataLen, pData->CERT_OCE_ECKA_7F49_TLV.dataOffset);


    if (0 != scp11_parseBERTLV(TRUE, cert_oce_ecka, &bufOffset, cert_oce_ecka_len, TAG_CERT_OCE_ECKA_5F37, &pData->CERT_OCE_ECKA_5F37_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_5F37);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_OCE_ECKA_5F37_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_5F37_TLV.tag, pData->CERT_OCE_ECKA_5F37_TLV.dataLen, pData->CERT_OCE_ECKA_5F37_TLV.dataOffset);

    pk_oce_ecka_temp_len=pData->CERT_OCE_ECKA_7F49_TLV.dataLen;
    LOGD("pk_oce_ecka_temp_len : %d",pk_oce_ecka_temp_len);

    memcpy(&pk_oce_ecka_temp, cert_oce_ecka + pData->CERT_OCE_ECKA_7F49_TLV.dataOffset, pk_oce_ecka_temp_len);
    hex_print_tag_debug("pk_oce_ecka_temp", pk_oce_ecka_temp, pk_oce_ecka_temp_len);


    bufOffset=0;
    if (0 != scp11_parseBERTLV(TRUE, pk_oce_ecka_temp, &bufOffset, pk_oce_ecka_temp_len, TAG_CERT_OCE_ECKA_7F49_REAL, &pData->CERT_OCE_ECKA_7F49_REAL_TLV)) {
        LOGE("Wrong data: %04X", TAG_CERT_OCE_ECKA_7F49_REAL);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("CERT_OCE_ECKA_7F49_REAL :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->CERT_OCE_ECKA_7F49_REAL_TLV.tag, pData->CERT_OCE_ECKA_7F49_REAL_TLV.dataLen, pData->CERT_OCE_ECKA_7F49_REAL_TLV.dataOffset);

    pk_oce_ecka_len=pData->CERT_OCE_ECKA_7F49_REAL_TLV.dataLen;
    memcpy(&pk_oce_ecka,  pk_oce_ecka_temp + pData->CERT_OCE_ECKA_7F49_REAL_TLV.dataOffset, pk_oce_ecka_len);
    hex_print_tag_debug("pk_oce_ecka", pk_oce_ecka, pk_oce_ecka_len);

    if (ESESTATUS_SUCCESS != secEseTransmit(channelId, &cpdu, &rpdu)) {
        LOGE("scp11_perform_security_operation failed to send APDU");
        return SCP11_PERFORM_SECURITY_OPERATION_APDU_SEND_FAIL;
    }

    if(rpdu.sw1 == 0x90 && rpdu.sw2 == 0x00) {
        LOGD("scp11_perform_security_operation pass. response : sw1 0x%2x,sw2 0x%2x,datalen %d",rpdu.sw1,rpdu.sw2,rpdu.len);
    } else {
        LOGE("scp11_perform_security_operation failed. Invalid response : sw1 0x%2x,sw2 0x%2x,datalen %d",rpdu.sw1,rpdu.sw2,rpdu.len);
        return SCP11_PERFORM_SECURITY_OPERATION_APDU_RETURN_FAIL;
    }

    memcpy(perform_security_operation_key->pk_oce_ecka,&pk_oce_ecka,pk_oce_ecka_len);
    perform_security_operation_key->pk_oce_ecka_len=pk_oce_ecka_len;

    LOGI("scp11_perform_security_operation end");
    return SCP11_SUCCESS;
}
#endif // #ifdef CHAIN_OCE_CERT

SCP11STATUS scp11_mutual_authenticate(uint8_t channelId, uint8_t securityLevel, skpm_cert_key_t *skpm_cert_key, get_data_t *get_data_key, perform_security_operation_t *perform_security_operation_key, secure_session_key_t *secure_session_key) {
    uint8_t oce_receipt;
    uint8_t data[MAX_RAPDU_DATA_SIZE] = {0,};
    uint8_t digest1[32] = {0, };
    uint8_t digest2[32] = {0, };
    uint8_t mutual_authenticaten_capdu[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t counter1_temp[] = {0x00,0x00,0x00,0x01};
    uint8_t counter2_temp[] = {0x00,0x00,0x00,0x02};
    uint8_t SIZE_5F49_temp[] = {0x5F,0x49,0x41}; //pk_ecka always 65 bytes (prime256v1)
    uint8_t cdata_security_level_1[] = {0xA6,0x0D,0x90,0x02,0x11,0x01,0x95,0x01,0x34,0x80,0x01,0x88,0x81,0x01,0x10,0x5F,0x49,0x41};//+ecc_oce_key.pubkey_binary(65bytes)
    uint8_t cdata_security_level_3[] = {0xA6,0x0D,0x90,0x02,0x11,0x01,0x95,0x01,0x3C,0x80,0x01,0x88,0x81,0x01,0x10,0x5F,0x49,0x41};//+ecc_oce_key.pubkey_binary(65bytes)
    uint8_t sharedinfo_temp_security_level_1[] = {0x34,0x88,0x10}; //34 = C-MAC,R-MAC
    uint8_t sharedinfo_temp_security_level_3[] = {0x3C,0x88,0x10}; //3C = C-MAC,R-MAC,C-DEK,R-ENC
    uint8_t counter1[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t counter2[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t sharedinfo[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t SIZE_5F49[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t oce_receipt_key[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t shss[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t shse[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t s_enc[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t s_mac[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t s_rmac[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t pk_sd_ecka[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t epk_sd_ecka[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t pk_oce_ecka[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t sk_oce_key[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t Receipt[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t esk_oce_ecka[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t epk_oce_ecka[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t message[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t sha_buf1[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t sha_buf2[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t security_level_status[4] = {0,};
    uint32_t bufOffset = 0;
    uint32_t pk_sd_ecka_len = 0;
    uint32_t epk_sd_ecka_len = 0;
    uint32_t sk_oce_key_len = 0;
    uint32_t Receipt_len = 0;
    uint32_t esk_oce_ecka_len = 0;
    uint32_t epk_oce_ecka_len = 0;
    uint32_t pk_oce_ecka_len = 0;
    uint32_t message_len=0;
    uint32_t sha_buf_len = 0;
    uint32_t cdata_len = 0;
    uint32_t mutual_authenticaten_capdu_len = 0;
    uint32_t counter1_len=sizeof(counter1_temp);
    uint32_t counter2_len=sizeof(counter2_temp);
    uint32_t SIZE_5F49_len=sizeof(SIZE_5F49_temp);
    uint32_t sharedinfo_security_level_1_len = sizeof(sharedinfo_temp_security_level_1);
    uint32_t sharedinfo_security_level_3_len = sizeof(sharedinfo_temp_security_level_3);
    uint32_t sharedinfo_len = 0;
    int32_t ret;
    void* pCardMetadata = NULL;
    secEse_7816_cpdu_t cpdu;
    secEse_7816_rpdu_t rpdu;
    sk_ecc_key_t   esk_oce_key;
    pk_ecc_key_t   epk_oce_key;
    ss_key_t   shss_real_key;
    ss_key_t   shse_real_key;
    ESESTATUS status;

    card_meta_struct_t_MUTUAL_AUTH cardMeta_MUTUAL_AUTH;
    card_meta_struct_t_MUTUAL_AUTH * pData = NULL;

    security_level_status[0] = securityLevel & 0x01; // C-MAC
    security_level_status[1] = securityLevel & 0x02; // C-DECRYPTION
    security_level_status[2] = securityLevel & 0x10; // R-MAC
    security_level_status[3] = securityLevel & 0x20; // R-ENCRYPTION

    LOGI("scp11_mutual_authenticaten start");

    ret = scp11_generate_ecc_keypair(&esk_oce_key, &epk_oce_key);
    if (0 != ret) {
            LOGE("scp11_generate_ecc_keypair FAIL!");
            return SCP11_GENERATE_ECC_KEYPAIR_FAIL;
    }

    memcpy(esk_oce_ecka, &esk_oce_key.sk_ecc_key, esk_oce_key.sk_ecc_key_size);
    esk_oce_ecka_len=esk_oce_key.sk_ecc_key_size;
    hex_print_tag_debug("esk_oce_ecka", esk_oce_ecka, esk_oce_ecka_len);

    memcpy(epk_oce_ecka, &epk_oce_key.pk_ecc_key, epk_oce_key.pk_ecc_key_size);
    epk_oce_ecka_len= epk_oce_key.pk_ecc_key_size;
    hex_print_tag_debug("epk_oce_ecka", epk_oce_ecka, epk_oce_ecka_len);

    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;

    memcpy(counter1, counter1_temp, sizeof(counter1_temp));
    memcpy(counter2, counter2_temp, sizeof(counter2_temp));
    memcpy(SIZE_5F49, SIZE_5F49_temp, sizeof(SIZE_5F49_temp));
    counter1_len=sizeof(counter1_temp);
    counter2_len=sizeof(counter2_temp);
    SIZE_5F49_len=sizeof(SIZE_5F49_temp);

    if ((security_level_status[0] != 0) || (security_level_status[2] != 0)){
        sharedinfo_len=sharedinfo_security_level_1_len;
        memcpy(sharedinfo, sharedinfo_temp_security_level_1, sharedinfo_len);
        cdata_len=sizeof(cdata_security_level_1);
        memcpy(mutual_authenticaten_capdu, cdata_security_level_1, cdata_len);
    }
    if ((security_level_status[1] != 0) || (security_level_status[3] != 0)){
        sharedinfo_len=sharedinfo_security_level_3_len;
        memcpy(sharedinfo, sharedinfo_temp_security_level_3, sharedinfo_len);
        cdata_len=sizeof(cdata_security_level_3);
        memcpy(mutual_authenticaten_capdu, cdata_security_level_3, cdata_len);
    }

    memcpy(mutual_authenticaten_capdu + cdata_len, epk_oce_ecka, epk_oce_ecka_len);
    mutual_authenticaten_capdu_len = cdata_len + epk_oce_ecka_len;
    hex_print_tag_debug("scp11_mutual_authenticaten_capdu", mutual_authenticaten_capdu, mutual_authenticaten_capdu_len);

    cpdu.cla = 0x80;
    cpdu.ins = 0x82;
    cpdu.p1 = 0x18;
    cpdu.p2 = 0x11;
    cpdu.lc = 0x53;
    cpdu.pdata = mutual_authenticaten_capdu;
    cpdu.le = 0x00;

    if (ESESTATUS_SUCCESS != secEseTransmit(channelId, &cpdu, &rpdu)) {
        LOGE("scp11_mutual_authenticate failed to send APDU");
        return SCP11_MUTUAL_AUTHENTICATE_APDU_SEND_FAIL;
    }

    if(rpdu.sw1 == 0x90 && rpdu.sw2 == 0x00 && rpdu.len > 0) {
        if (rpdu.len > 0) {
            hex_print_tag_debug("epk.sd+receipt", rpdu.pdata, rpdu.len);
            LOGD("scp11_mutual_authenticate pass. response : sw1 0x%2x,sw2 0x%2x,datalen %d",rpdu.sw1,rpdu.sw2,rpdu.len);
        }
    } else {
        LOGE("scp11_mutual_authenticate failed. Invalid response : sw1 0x%2x,sw2 0x%2x,datalen %d",rpdu.sw1,rpdu.sw2,rpdu.len);
        return SCP11_MUTUAL_AUTHENTICATE_APDU_RETURN_FAIL;

    }

//parsing epk_sd_ecka,epk_sd_ecka_len,sd_receipt from respond.
    pCardMetadata = &cardMeta_MUTUAL_AUTH;
    pData = (card_meta_struct_t_MUTUAL_AUTH *)pCardMetadata;

    memset(&pData->ePK_SD_ECKA_5F49_TLV, 0, sizeof(tlv_t));
    memset(&pData->RECEIPT_86_TLV, 0, sizeof(tlv_t));


    if (0 != scp11_parseBERTLV(TRUE, rpdu.pdata, &bufOffset, rpdu.len, TAG_ePK_SD_ECKA_5F49 , &pData->ePK_SD_ECKA_5F49_TLV)) {
        LOGE("Wrong data: %04X", TAG_ePK_SD_ECKA_5F49);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("ePK_SD_ECKA_5F49_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->ePK_SD_ECKA_5F49_TLV.tag, pData->ePK_SD_ECKA_5F49_TLV.dataLen, pData->ePK_SD_ECKA_5F49_TLV.dataOffset);

     if (0 != scp11_parseBERTLV(TRUE, rpdu.pdata, &bufOffset, rpdu.len, TAG_RECEIPT_86, &pData->RECEIPT_86_TLV)) {
        LOGE("Wrong data: %04X", TAG_RECEIPT_86);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("RECEIPT_86_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->RECEIPT_86_TLV.tag, pData->RECEIPT_86_TLV.dataLen, pData->RECEIPT_86_TLV.dataOffset);

    epk_sd_ecka_len=pData->ePK_SD_ECKA_5F49_TLV.dataLen;
    Receipt_len=pData->RECEIPT_86_TLV.dataLen;

    LOGD("epk_sd_ecka_len : %d",epk_sd_ecka_len);
    LOGD("Receipt_len : %d",Receipt_len);

    memcpy(&epk_sd_ecka, rpdu.pdata + pData->ePK_SD_ECKA_5F49_TLV.dataOffset, epk_sd_ecka_len);
    memcpy(&Receipt, rpdu.pdata + pData->RECEIPT_86_TLV.dataOffset, Receipt_len);

    hex_print_tag_debug("epk_sd_ecka", epk_sd_ecka, epk_sd_ecka_len);
    hex_print_tag_debug("Receipt", Receipt, Receipt_len);

    memcpy(sk_oce_key, &skpm_cert_key->sk_oce_key, skpm_cert_key->sk_oce_key_len);
    sk_oce_key_len=skpm_cert_key->sk_oce_key_len;
    hex_print_tag_debug("sk_oce_key", sk_oce_key, sk_oce_key_len);

    memcpy(pk_sd_ecka, &get_data_key->pk_sd_ecka, get_data_key->pk_sd_ecka_len);
    pk_sd_ecka_len=get_data_key->pk_sd_ecka_len;
    hex_print_tag_debug("pk_sd_ecka", pk_sd_ecka, pk_sd_ecka_len);

    memcpy(pk_oce_ecka, &perform_security_operation_key->pk_oce_ecka, perform_security_operation_key->pk_oce_ecka_len );
    pk_oce_ecka_len=perform_security_operation_key->pk_oce_ecka_len;
    hex_print_tag_debug("pk_oce_ecka", pk_oce_ecka, pk_oce_ecka_len);

//shss : sk.oce, pk.sd
//shse : esk.oce, epk.sd
//shss
    ret = scp11_shared_secret(pk_oce_ecka, sk_oce_key, pk_sd_ecka, pk_sd_ecka_len, sk_oce_key_len, &shss_real_key);
    if (0 != ret) {
	LOGE("scp11_shared_secret(shss) Failed.");
        return SCP11_SHARED_SECRET_SHSS_FAIL;
    }
    memcpy(shss, &shss_real_key.ss_key, shss_real_key.ss_key_size);
    hex_print_tag_debug("shss", shss, shss_real_key.ss_key_size);

//shse
    ret = scp11_shared_secret(epk_oce_ecka, esk_oce_ecka, epk_sd_ecka, epk_sd_ecka_len, esk_oce_ecka_len, &shse_real_key);
    if (0 != ret) {
	LOGE("scp11_shared_secret(shse) Failed.");
        return SCP11_SHARED_SECRET_SHSE_FAIL;
    }
    memcpy(shse, &shse_real_key.ss_key, shse_real_key.ss_key_size);
    hex_print_tag_debug("shse", shse, shse_real_key.ss_key_size );



    sha_buf_len = shse_real_key.ss_key_size;
    memcpy(sha_buf1, &shse, sha_buf_len);
    memcpy(sha_buf2, &shse, sha_buf_len);


    memcpy(sha_buf1 + sha_buf_len, &shss, sha_buf_len);
    memcpy(sha_buf2 + sha_buf_len, &shss, sha_buf_len);
    sha_buf_len = sha_buf_len + shss_real_key.ss_key_size;

    memcpy(sha_buf1 + sha_buf_len, counter1, counter1_len);
    memcpy(sha_buf2 + sha_buf_len, counter2, counter2_len);
    sha_buf_len = sha_buf_len+counter1_len;

    memcpy(sha_buf1 + sha_buf_len, sharedinfo, sharedinfo_len);
    memcpy(sha_buf2 + sha_buf_len, sharedinfo, sharedinfo_len);
    sha_buf_len = sha_buf_len+sharedinfo_len;

    hex_print_tag_debug("sha_buf1", sha_buf1, sha_buf_len );
    hex_print_tag_debug("sha_buf2", sha_buf2, sha_buf_len );

// (shse||shss||00000001||348810)
    status = crypto_sha256(digest1, sha_buf1, sha_buf_len , NULL );
    if (ESESTATUS_SUCCESS != status) {
	LOGE("scp11_crypto_sha256 Failed.");
        return SCP11_CRYPTO_SHA256_FAIL;
    }
    hex_print_tag_debug("digest1", digest1, 32);

    memcpy(oce_receipt_key, digest1, 16);
    hex_print_tag_debug("oce_receipt_key", oce_receipt_key, 16);

    memcpy(s_enc, 16+digest1, 16);
    hex_print_tag_debug("s_enc", s_enc, 16);

// (shse||shss||00000002||348810)
    status = crypto_sha256(digest2, sha_buf2, sha_buf_len , NULL );
    if (ESESTATUS_SUCCESS != status) {
	LOGE("scp11_crypto_sha256 Failed.");
        return SCP11_CRYPTO_SHA256_FAIL;
    }
    hex_print_tag_debug("digest2", digest2, 32);

    memcpy(s_mac, digest2, 16);
    hex_print_tag_debug("s_mac", s_mac, 16);

    memcpy(s_rmac, 16+digest2, 16);
    hex_print_tag_debug("s_rmac", s_rmac, 16);

    memcpy(message, mutual_authenticaten_capdu, mutual_authenticaten_capdu_len);
    message_len = mutual_authenticaten_capdu_len;

    memcpy(message + message_len, SIZE_5F49, SIZE_5F49_len);
    message_len = message_len + SIZE_5F49_len;

    memcpy(message + message_len, epk_sd_ecka, epk_sd_ecka_len);
    message_len = message_len+epk_sd_ecka_len;

    hex_print_tag_debug("message", message, message_len );

    SCP03_AES_CMAC(oce_receipt_key, message, message_len, &oce_receipt);
    hex_print_tag_debug("oce_receipt", &oce_receipt, 16);

    if ( crypto_secure_mac_cmp(&oce_receipt,Receipt ) != 0 ) {
	LOGE("scp11_crypto_secure_mac_cmp Failed.");
        return SCP11_CRYPTO_SECURE_MAC_CMP_FAIL;
    }

    memcpy(secure_session_key->Receipt,&Receipt,16);
    memcpy(secure_session_key->s_enc,&s_enc,16);
    memcpy(secure_session_key->s_mac,&s_mac,16);
    memcpy(secure_session_key->s_rmac,&s_rmac,16);

    LOGI("scp11_mutual_authenticaten end");
    return SCP11_SUCCESS;
}

SCP11STATUS scp11_internal_authenticate(uint8_t channelId, uint8_t securityLevel, get_data_t *get_data_key, perform_security_operation_t *perform_security_operation_key, secure_session_key_t *secure_session_key) {
    uint8_t oce_receipt;
    uint8_t data[MAX_RAPDU_DATA_SIZE] = {0,};
    uint8_t digest1[32] = {0, };
    uint8_t digest2[32] = {0, };
    uint8_t internal_authenticaten_capdu[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t counter1_temp[] = {0x00,0x00,0x00,0x01};
    uint8_t counter2_temp[] = {0x00,0x00,0x00,0x02};
    uint8_t SIZE_5F49_temp[] = {0x5F,0x49,0x41}; //pk_ecka always 65 bytes (prime256v1)
    uint8_t cdata_security_level_1[] = {0xA6,0x0D,0x90,0x02,0x11,0x01,0x95,0x01,0x34,0x80,0x01,0x88,0x81,0x01,0x10,0x5F,0x49,0x41};//+ecc_oce_key.pubkey_binary(65bytes)
    uint8_t cdata_security_level_3[] = {0xA6,0x0D,0x90,0x02,0x11,0x01,0x95,0x01,0x3C,0x80,0x01,0x88,0x81,0x01,0x10,0x5F,0x49,0x41};//+ecc_oce_key.pubkey_binary(65bytes)
    uint8_t sharedinfo_temp_security_level_1[] = {0x34,0x88,0x10}; //34 = C-MAC,R-MAC
    uint8_t sharedinfo_temp_security_level_3[] = {0x3C,0x88,0x10}; //3C = C-MAC,R-MAC,C-DEK,R-ENC
    uint8_t counter1[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t counter2[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t sharedinfo[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t SIZE_5F49[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t oce_receipt_key[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t shss[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t shse[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t s_enc[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t s_mac[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t s_rmac[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t pk_sd_ecka[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t epk_sd_ecka[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t pk_oce_ecka[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t sk_oce_key[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t Receipt[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t esk_oce_ecka[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t epk_oce_ecka[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t message[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t sha_buf1[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t sha_buf2[MAX_SCP11_DATA_SIZE] = {0,};
    uint8_t security_level_status[4] = {0,};
    uint32_t bufOffset = 0;
    uint32_t pk_sd_ecka_len = 0;
    uint32_t epk_sd_ecka_len = 0;
    uint32_t Receipt_len = 0;
    uint32_t esk_oce_ecka_len = 0;
    uint32_t epk_oce_ecka_len = 0;
    uint32_t pk_oce_ecka_len = 0;
    uint32_t message_len=0;
    uint32_t sha_buf_len = 0;
    uint32_t cdata_len = 0;
    uint32_t internal_authenticaten_capdu_len = 0;
    uint32_t counter1_len=sizeof(counter1_temp);
    uint32_t counter2_len=sizeof(counter2_temp);
    uint32_t SIZE_5F49_len=sizeof(SIZE_5F49_temp);
    uint32_t sharedinfo_security_level_1_len = sizeof(sharedinfo_temp_security_level_1);
    uint32_t sharedinfo_security_level_3_len = sizeof(sharedinfo_temp_security_level_3);
    uint32_t sharedinfo_len = 0;
    int32_t ret;
    void* pCardMetadata = NULL;
    secEse_7816_cpdu_t cpdu;
    secEse_7816_rpdu_t rpdu;
    sk_ecc_key_t   esk_oce_key;
    pk_ecc_key_t   epk_oce_key;
    ss_key_t   shss_real_key;
    ss_key_t   shse_real_key;
    ESESTATUS status;

    card_meta_struct_t_INTERNAL_AUTH cardMeta_INTERNAL_AUTH;
    card_meta_struct_t_INTERNAL_AUTH * pData = NULL;

    security_level_status[0] = securityLevel & 0x01; // C-MAC
    security_level_status[1] = securityLevel & 0x02; // C-DECRYPTION
    security_level_status[2] = securityLevel & 0x10; // R-MAC
    security_level_status[3] = securityLevel & 0x20; // R-ENCRYPTION

    LOGI("scp11_internal_authenticaten start");

    ret = scp11_generate_ecc_keypair(&esk_oce_key, &epk_oce_key);
    if (0 != ret) {
            LOGE("scp11_generate_ecc_keypair FAIL!");
            return SCP11_GENERATE_ECC_KEYPAIR_FAIL;
    }

    memcpy(esk_oce_ecka, &esk_oce_key.sk_ecc_key, esk_oce_key.sk_ecc_key_size);
    esk_oce_ecka_len=esk_oce_key.sk_ecc_key_size;
    hex_print_tag_debug("esk_oce_ecka", esk_oce_ecka, esk_oce_ecka_len);

    memcpy(epk_oce_ecka, &epk_oce_key.pk_ecc_key, epk_oce_key.pk_ecc_key_size);
    epk_oce_ecka_len= epk_oce_key.pk_ecc_key_size;
    hex_print_tag_debug("epk_oce_ecka", epk_oce_ecka, epk_oce_ecka_len);

    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;

    memcpy(counter1, counter1_temp, sizeof(counter1_temp));
    memcpy(counter2, counter2_temp, sizeof(counter2_temp));
    memcpy(SIZE_5F49, SIZE_5F49_temp, sizeof(SIZE_5F49_temp));
    counter1_len=sizeof(counter1_temp);
    counter2_len=sizeof(counter2_temp);
    SIZE_5F49_len=sizeof(SIZE_5F49_temp);

    if ((security_level_status[0] != 0) || (security_level_status[2] != 0)){
        sharedinfo_len=sharedinfo_security_level_1_len;
        memcpy(sharedinfo, sharedinfo_temp_security_level_1, sharedinfo_len);
        cdata_len=sizeof(cdata_security_level_1);
        memcpy(internal_authenticaten_capdu, cdata_security_level_1, cdata_len);
    }
    if ((security_level_status[1] != 0) || (security_level_status[3] != 0)){
        sharedinfo_len=sharedinfo_security_level_3_len;
        memcpy(sharedinfo, sharedinfo_temp_security_level_3, sharedinfo_len);
        cdata_len=sizeof(cdata_security_level_3);
        memcpy(internal_authenticaten_capdu, cdata_security_level_3, cdata_len);
    }

    memcpy(internal_authenticaten_capdu + cdata_len, epk_oce_ecka, epk_oce_ecka_len);
    internal_authenticaten_capdu_len = cdata_len + epk_oce_ecka_len;
    hex_print_tag_debug("scp11_internal_authenticaten_capdu", internal_authenticaten_capdu, internal_authenticaten_capdu_len);

    cpdu.cla = 0x80;
    cpdu.ins = 0x88;
    cpdu.p1 = 0x18;
    cpdu.p2 = 0x11;
    cpdu.lc = 0x53;
    cpdu.pdata = internal_authenticaten_capdu;
    cpdu.le = 0x00;

    if (ESESTATUS_SUCCESS != secEseTransmit(channelId, &cpdu, &rpdu)) {
        LOGE("scp11_internal_authenticate failed to send APDU");
        return SCP11_INTERNAL_AUTHENTICATE_APDU_SEND_FAIL;
    }

    if(rpdu.sw1 == 0x90 && rpdu.sw2 == 0x00 && rpdu.len > 0) {
        if (rpdu.len > 0) {
            hex_print_tag_debug("epk.sd+receipt", rpdu.pdata, rpdu.len);
            LOGD("scp11_internal_authenticate pass. response : sw1 0x%2x,sw2 0x%2x,datalen %d",rpdu.sw1,rpdu.sw2,rpdu.len);
        }
    } else {
        LOGE("scp11_internal_authenticate failed. Invalid response : sw1 0x%2x,sw2 0x%2x,datalen %d",rpdu.sw1,rpdu.sw2,rpdu.len);
        return SCP11_INTERNAL_AUTHENTICATE_APDU_RETURN_FAIL;

    }

//parsing epk_sd_ecka,epk_sd_ecka_len,sd_receipt from respond.
    pCardMetadata = &cardMeta_INTERNAL_AUTH;
    pData = (card_meta_struct_t_INTERNAL_AUTH *)pCardMetadata;

    memset(&pData->ePK_SD_ECKA_5F49_TLV, 0, sizeof(tlv_t));
    memset(&pData->RECEIPT_86_TLV, 0, sizeof(tlv_t));


    if (0 != scp11_parseBERTLV(TRUE, rpdu.pdata, &bufOffset, rpdu.len, TAG_ePK_SD_ECKA_5F49 , &pData->ePK_SD_ECKA_5F49_TLV)) {
        LOGE("Wrong data: %04X", TAG_ePK_SD_ECKA_5F49);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("ePK_SD_ECKA_5F49_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->ePK_SD_ECKA_5F49_TLV.tag, pData->ePK_SD_ECKA_5F49_TLV.dataLen, pData->ePK_SD_ECKA_5F49_TLV.dataOffset);

     if (0 != scp11_parseBERTLV(TRUE, rpdu.pdata, &bufOffset, rpdu.len, TAG_RECEIPT_86, &pData->RECEIPT_86_TLV)) {
        LOGE("Wrong data: %04X", TAG_RECEIPT_86);
        return SCP11_PARBERTLV_FAIL;
    }
    LOGD("RECEIPT_86_TLV :: tag= %04X, dataLen= %08X, dataOffset=%08X",pData->RECEIPT_86_TLV.tag, pData->RECEIPT_86_TLV.dataLen, pData->RECEIPT_86_TLV.dataOffset);

    epk_sd_ecka_len=pData->ePK_SD_ECKA_5F49_TLV.dataLen;
    Receipt_len=pData->RECEIPT_86_TLV.dataLen;

    LOGD("epk_sd_ecka_len : %d",epk_sd_ecka_len);
    LOGD("Receipt_len : %d",Receipt_len);

    memcpy(&epk_sd_ecka, rpdu.pdata + pData->ePK_SD_ECKA_5F49_TLV.dataOffset, epk_sd_ecka_len);
    memcpy(&Receipt, rpdu.pdata + pData->RECEIPT_86_TLV.dataOffset, Receipt_len);

    hex_print_tag_debug("epk_sd_ecka", epk_sd_ecka, epk_sd_ecka_len);
    hex_print_tag_debug("Receipt", Receipt, Receipt_len);

    memcpy(pk_sd_ecka, &get_data_key->pk_sd_ecka, get_data_key->pk_sd_ecka_len);
    pk_sd_ecka_len=get_data_key->pk_sd_ecka_len;
    hex_print_tag_debug("pk_sd_ecka", pk_sd_ecka, pk_sd_ecka_len);

    memcpy(pk_oce_ecka, &perform_security_operation_key->pk_oce_ecka, perform_security_operation_key->pk_oce_ecka_len );
    pk_oce_ecka_len=perform_security_operation_key->pk_oce_ecka_len;
    hex_print_tag_debug("pk_oce_ecka", pk_oce_ecka, pk_oce_ecka_len);

//shss : esk.oce, pk.sd
//shse : esk.oce, epk.sd
//shss
    ret = scp11_shared_secret(pk_oce_ecka, sk_oce_key, pk_sd_ecka, pk_sd_ecka_len, esk_oce_ecka_len, &shss_real_key);
    if (0 != ret) {
	LOGE("scp11_shared_secret(shss) Failed.");
        return SCP11_SHARED_SECRET_SHSS_FAIL;
    }
    memcpy(shss, &shss_real_key.ss_key, shss_real_key.ss_key_size);
    hex_print_tag_debug("shss", shss, shss_real_key.ss_key_size);

//shse
    ret = scp11_shared_secret(epk_oce_ecka, esk_oce_ecka, epk_sd_ecka, epk_sd_ecka_len, esk_oce_ecka_len, &shse_real_key);
    if (0 != ret) {
	LOGE("scp11_shared_secret(shse) Failed.");
        return SCP11_SHARED_SECRET_SHSE_FAIL;
    }
    memcpy(shse, &shse_real_key.ss_key, shse_real_key.ss_key_size);
    hex_print_tag_debug("shse", shse, shse_real_key.ss_key_size );



    sha_buf_len = shse_real_key.ss_key_size;
    memcpy(sha_buf1, &shse, sha_buf_len);
    memcpy(sha_buf2, &shse, sha_buf_len);


    memcpy(sha_buf1 + sha_buf_len, &shss, sha_buf_len);
    memcpy(sha_buf2 + sha_buf_len, &shss, sha_buf_len);
    sha_buf_len = sha_buf_len + shss_real_key.ss_key_size;

    memcpy(sha_buf1 + sha_buf_len, counter1, counter1_len);
    memcpy(sha_buf2 + sha_buf_len, counter2, counter2_len);
    sha_buf_len = sha_buf_len+counter1_len;

    memcpy(sha_buf1 + sha_buf_len, sharedinfo, sharedinfo_len);
    memcpy(sha_buf2 + sha_buf_len, sharedinfo, sharedinfo_len);
    sha_buf_len = sha_buf_len+sharedinfo_len;

    hex_print_tag_debug("sha_buf1", sha_buf1, sha_buf_len );
    hex_print_tag_debug("sha_buf2", sha_buf2, sha_buf_len );

// (shse||shss||00000001||348810)
    status = crypto_sha256(digest1, sha_buf1, sha_buf_len , NULL );
    if (ESESTATUS_SUCCESS != status) {
	LOGE("scp11_crypto_sha256 Failed.");
        return SCP11_CRYPTO_SHA256_FAIL;
    }
    hex_print_tag_debug("digest1", digest1, 32);

    memcpy(oce_receipt_key, digest1, 16);
    hex_print_tag_debug("oce_receipt_key", oce_receipt_key, 16);

    memcpy(s_enc, 16+digest1, 16);
    hex_print_tag_debug("s_enc", s_enc, 16);

// (shse||shss||00000002||348810)
    status = crypto_sha256(digest2, sha_buf2, sha_buf_len , NULL );
    if (ESESTATUS_SUCCESS != status) {
	LOGE("scp11_crypto_sha256 Failed.");
        return SCP11_CRYPTO_SHA256_FAIL;
    }
    hex_print_tag_debug("digest2", digest2, 32);

    memcpy(s_mac, digest2, 16);
    hex_print_tag_debug("s_mac", s_mac, 16);

    memcpy(s_rmac, 16+digest2, 16);
    hex_print_tag_debug("s_rmac", s_rmac, 16);

    memcpy(message, internal_authenticaten_capdu, internal_authenticaten_capdu_len);
    message_len = internal_authenticaten_capdu_len;

    memcpy(message + message_len, SIZE_5F49, SIZE_5F49_len);
    message_len = message_len + SIZE_5F49_len;

    memcpy(message + message_len, epk_sd_ecka, epk_sd_ecka_len);
    message_len = message_len+epk_sd_ecka_len;

    hex_print_tag_debug("message", message, message_len );

    SCP03_AES_CMAC(oce_receipt_key, message, message_len, &oce_receipt);
    hex_print_tag_debug("oce_receipt", &oce_receipt, 16);

    if ( crypto_secure_mac_cmp(&oce_receipt,Receipt ) != 0 ) {
	LOGE("scp11_crypto_secure_mac_cmp Failed.");
        return SCP11_CRYPTO_SECURE_MAC_CMP_FAIL;
    }

    memcpy(secure_session_key->Receipt,&Receipt,16);
    memcpy(secure_session_key->s_enc,&s_enc,16);
    memcpy(secure_session_key->s_mac,&s_mac,16);
    memcpy(secure_session_key->s_rmac,&s_rmac,16);

    LOGI("scp11_internal_authenticaten end");
    return SCP11_SUCCESS;
}
#endif
