#include "debug.h"

#include "skpm.h"
#include "skpm_certs.h"
#include "skpm_tls.h"
#include "skpm_util.h"
#include "skpm_crypto_util.h"
#include "skpm_ta_uuid.h"
#include "crypto_module.h"

#include "aes128-swbc-layer1-cbc.h"
#include "swbc-error.h"
#include "SWBC_DEC.h"

#ifdef SUPPORT_GUARDIAN_M
#include "grdm_app.h"
#include "grdm_common.h"
#endif

extern tls_session_info_t sOtaTlsSession;

static int32_t dec_text(const unsigned char **dec_table, const unsigned char *dec_tag, uint8_t mc[AES_128_KEY_SIZE], uint8_t iv[IV_SIZE], uint8_t *cipher, uint32_t cipher_size, uint8_t *plain, int32_t *plain_size) {
    int32_t ret = 0;
    uint8_t local_iv[IV_SIZE];
    aes128_swbc_layer1_cbc_ctx_t *ctx;

    memcpy(local_iv, iv, IV_SIZE);
    ctx = (aes128_swbc_layer1_cbc_ctx_t *)tz_malloc(sizeof(aes128_swbc_layer1_cbc_ctx_t));
    if (ctx == NULL) {
        return -1;
    }
    memset(ctx, 0, sizeof(aes128_swbc_layer1_cbc_ctx_t));

    ret = aes128_swbc_layer1_cbc_load(ctx, (const unsigned char **)NULL, (const unsigned char *)NULL, dec_table, dec_tag);
    if (SWBC_SUCCESS != ret){
        LOGE("table load error");
        goto error; 
    }

    ret = aes128_swbc_layer1_cbc_init(ctx, (const unsigned char *)mc, DECRYPT_MODE);
    if (SWBC_SUCCESS != ret) { //swbc decryption mode
        LOGE("init error");
        goto error;
    }

    ret = aes128_swbc_layer1_cbc_decrypt(ctx, (const unsigned char *)local_iv, (const unsigned char *)cipher, (unsigned char *)plain, (int)cipher_size, (int*)plain_size);
    if (SWBC_SUCCESS != ret) {
        LOGE("cbc mode decrypt error");
        goto error;
    }

error:
    tz_free(ctx);
    return ret;
}

key_list_info_t gKeyListInfo[] = {
    {"SKPM_FACTORY",
        INJECTION_TYPE_FACTORY,
        KEY_TYPE_ECC_P256 | KEY_TYPE_RSA_2048,
        CERT_TYPE_X509 | CERT_TYPE_CASD,
        ROOT_CERT_SKPM_TEST,
        SKPM_QSEE_NAME, SKPM_MC_UUID, SKPM_BF_UUID, SKPM_EXT_ID},
    {"SKPM_FACTORY_TEST",
        INJECTION_TYPE_FACTORY,
        KEY_TYPE_ECC_P256 | KEY_TYPE_RSA_2048,
        CERT_TYPE_X509 | CERT_TYPE_CASD,
        ROOT_CERT_SKPM_TEST,
        SKPM_QSEE_NAME, SKPM_MC_UUID, SKPM_BF_UUID, SKPM_EXT_ID},
    {"OCF",
        INJECTION_TYPE_FACTORY,
        KEY_TYPE_ECC_P256,
        CERT_TYPE_X509,
        ROOT_CERT_OCF,
        OCF_QSEE_NAME, OCF_MC_UUID, OCF_BF_UUID, OCF_EXT_ID},
    {"OCF_TEST",
        INJECTION_TYPE_FACTORY,
        KEY_TYPE_ECC_P256,
        CERT_TYPE_X509,
        ROOT_CERT_OCF_TEST,
        OCF_QSEE_NAME, OCF_MC_UUID, OCF_BF_UUID, OCF_EXT_ID},
};

#ifdef TIZEN
char verify_original[][VERIFY_INPUT_SIZE_MAX] = {
                        "/usr/apps/skpm/bin/skpm",
                        "/home/developer/skpm_key_installer_tizen",
                        "/usr/apps/com.samsung.skmsa/bin/SkmsAgent",
                        "/usr/bin/SkmsAgent"};
#else
char verify_original[][VERIFY_INPUT_SIZE_MAX] = {
                        "/data/skpm",
                        "skpm_key_installer",
                        "system_server",
                        "com.skms.android.agent:remote"};
#endif

void check_key_list(p_cmd_t cmd, p_rsp_t rsp) {
    int32_t ret = RET_SUCCESS;

    uint8_t injection_type, key_type;
    uint8_t key_name[MAX_KEY_NAME_SIZE] = "";

    uint8_t keyListBlob[WRAPPED_KEY_INFO_SIZE];
    uint32_t keyListBlob_size;

    uint32_t offset, key_name_size;

    key_list_info_t keyListInfo[MAX_KEY_LIST_INFO];
    uint32_t keyListInfo_size = 0, i;

    uint8_t wrappedOutDataBlob[WRAPPED_KEY_INFO_SIZE];
    uint32_t wrappedOutDataBlobSize;

    uint16_t list_ver;
    uint8_t list_sig[ECDSA_SIG_SIZE];

    uint8_t raw_sig_r[ECDSA_SIG_SIZE/2], raw_sig_s[ECDSA_SIG_SIZE/2];
    uint8_t sig_r[ECDSA_SIG_SIZE/2], sig_s[ECDSA_SIG_SIZE/2];
    int32_t sig_r_size, sig_s_size;

    EC_KEY *regen_eccKey = NULL;
    uint8_t sig_verify_key[] = {0x04,
        0xfc, 0x3f, 0x26, 0x17, 0xcb, 0x2b, 0xeb, 0xd9, 0xab, 0x77, 0x09, 0x6b, 0x6f, 0xde, 0x7f, 0x76,
        0x72, 0xb6, 0x4a, 0xcd, 0x7c, 0x5b, 0x1a, 0xb7, 0x04, 0x19, 0xc9, 0x2c, 0x07, 0xd9, 0x0a, 0x46,
        0x13, 0x74, 0x71, 0x64, 0x97, 0xb8, 0xf4, 0xc1, 0xb9, 0x25, 0x4c, 0x37, 0x71, 0xc6, 0xfb, 0x8a,
        0x30, 0x17, 0x6d, 0x2d, 0xb7, 0xa0, 0xf4, 0x3f, 0xd4, 0xad, 0xd8, 0x76, 0x69, 0xb5, 0x00, 0x9b};

    char verify_input[VERIFY_INPUT_SIZE_MAX] = "";
    uint32_t readFileSize = 0;
    uint32_t inputSize;

    LOGD("check_key_list started");

    inputSize = cmd->dataLen;
    if (inputSize > WRAPPED_KEY_INFO_SIZE) {
        LOGE("Input data is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (inputSize == 0) {
        LOGE("inputSize is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    offset = 0;
    injection_type = cmd->data[offset++];
    key_type = cmd->data[offset++];
    memcpy(&key_name_size, cmd->data + offset, 4);
    offset += 4;
    if (key_name_size > sizeof(key_name)) {
        LOGE("Input data is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (key_name_size == 0) {
        LOGE("key_name is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(key_name, cmd->data + offset, key_name_size);
    offset += key_name_size;
    memcpy(&readFileSize, cmd->data + offset, 4);
    offset += 4;
    if (readFileSize > sizeof(verify_input)) {
        LOGE("verify_input is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (readFileSize == 0) {
        LOGE("verify_input is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(verify_input, cmd->data + offset, readFileSize);
    offset += readFileSize;
    LOGD("verify_input : %s", verify_input);
    for (i = 0 ; i < (sizeof(verify_original) / VERIFY_INPUT_SIZE_MAX) ; i++) {
        LOGD("verify_input[%d] : %s", i , verify_original[i]);
        if (strcmp(verify_input, verify_original[i]) == 0) {
            // permitted
            LOGD("Caller is permitted, %s", verify_input);
            goto caller_is_permitted;
        }
    }

    LOGE("Caller is not permitted, %s", verify_input);
    ret = RET_ERR_CALLER_NOT_PERMITTED;
    goto error;

caller_is_permitted:
    memcpy(&keyListBlob_size, cmd->data + offset, 4);
    offset += 4;
    if (keyListBlob_size == 0xffffffff) {
        LOGI("Use default list");
        memcpy(keyListInfo, gKeyListInfo, sizeof(gKeyListInfo));
        keyListInfo_size = sizeof(gKeyListInfo) / sizeof(key_list_info_t);

    } else {
        if (keyListBlob_size > sizeof(keyListBlob)) {
            LOGE("keyListBlob is over the buffer.");
            ret = RET_ERR_BUFFER_NOT_ENOUGH;
            goto error;
        }
        if (keyListBlob_size == 0) {
            LOGE("keyListBlob is zero");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        memcpy(keyListBlob, cmd->data + offset, keyListBlob_size);
        offset += keyListBlob_size;
        hex_print_tag_debug("keyListBlob", keyListBlob, keyListBlob_size);

        offset = 0;
        // Version
        if (keyListBlob[offset++] != 0x01) {
            LOGE("Key version is not exist");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        offset += 2;
        list_ver = keyListBlob[offset++];
        list_ver |= keyListBlob[offset++];
        if ( ((uint8_t)list_ver == 0x01) && ((uint8_t)(list_ver >> 8) == 0x00) ) {
            // Supported versions
        } else {
            LOGE("key_list_ver is not matched, current ver. %02X.%02X", (uint8_t)list_ver, (uint8_t)(list_ver >> 8));
        }
        // KeyList
        if (keyListBlob[offset++] != 0x02) {
            LOGE("Key list is not exist");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        keyListInfo_size = keyListBlob[offset++];
        keyListInfo_size = keyListInfo_size << 8;
        keyListInfo_size |= keyListBlob[offset++];
        if (keyListInfo_size > sizeof(keyListInfo)) {
            LOGE("keyListInfo is over the buffer.");
            ret = RET_ERR_BUFFER_NOT_ENOUGH;
            goto error;
        }
        if (keyListInfo_size == 0) {
            LOGE("keyListInfo is zero");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        memcpy(&keyListInfo, keyListBlob + offset, keyListInfo_size);
        hex_print_tag_debug("keyListInfo", (uint8_t *)&keyListInfo, keyListInfo_size);
        offset += keyListInfo_size;
        keyListInfo_size = keyListInfo_size / sizeof(key_list_info_t);

        // Signature
        if (keyListBlob[offset++] != 0x03) {
            LOGE("Key signature is not exist");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        offset += 2;
        memcpy(list_sig, keyListBlob + offset, ECDSA_SIG_SIZE);
        hex_print_tag_debug("list_sig", list_sig, ECDSA_SIG_SIZE);

        memcpy(raw_sig_r, list_sig, 32);
        memcpy(raw_sig_s, list_sig + 32, 32);

        if (raw_sig_r[0] == 0x00) {
            memcpy(sig_r, raw_sig_r + 1, 31);
            sig_r_size = 31;
        } else {
            memcpy(sig_r, raw_sig_r, 32);
            sig_r_size = 32;
        }

        if (raw_sig_s[0] == 0x00) {
            memcpy(sig_s, raw_sig_s + 1, 31);
            sig_s_size = 31;
        } else {
            memcpy(sig_s, raw_sig_s, 32);
            sig_s_size = 32;
        }

        // verify signature
        crypto_regen_ecc_pubkey(&regen_eccKey, sig_verify_key, sizeof(sig_verify_key));
        ret = crypto_ecdsa_verify(MD_TYPE_SHA256, regen_eccKey, (uint8_t *)&keyListInfo, keyListInfo_size * sizeof(key_list_info_t), sig_r, sig_r_size, sig_s, sig_s_size);
        // Success :
        if (ret != CRYPTO_STATUS_SUCCESS) {
            LOGE("Failed to crypto_ecdsa_verify");
            ret = RET_ERR_VERIFY_FAIL;
            goto error;
        }
    }

    LOGD("keyListInfo_size : %u", keyListInfo_size);
    for (i = 0; i < keyListInfo_size; i++) {
        LOGD("List Key_name : %s, injection_type : 0x%02x, key_type : 0x%02x", keyListInfo[i].key_name, keyListInfo[i].injection_type, keyListInfo[i].key_type);
        LOGD("In   Key_name : %s, injection_type : 0x%02x, key_type : 0x%02x", key_name, injection_type, key_type);
        if (strcmp((const char*)key_name, (const char*)keyListInfo[i].key_name) == 0
            && (injection_type == (injection_type & keyListInfo[i].injection_type))
            && (key_type == (key_type & keyListInfo[i].key_type))) {
            LOGD("List is matched, key_name : %s, injection_type : 0x%02x, key_type : 0x%02x", key_name, injection_type, key_type);

            hex_print_tag_debug("unwrappedOutDataBlob", (uint8_t *)&keyListInfo, keyListInfo_size * sizeof(key_list_info_t));
            wrappedOutDataBlobSize = sizeof(wrappedOutDataBlob);
            if (wrapInternalData(SECURE_OBJECT_TYPE_KEY_LIST, (uint8_t *)&keyListInfo, (keyListInfo_size * sizeof(key_list_info_t)), wrappedOutDataBlob, &wrappedOutDataBlobSize) != STATUS_SUCCESS) {
                ret = RET_ERR_DATA_WRAPPING_FAIL;
                goto error;
            }
            hex_print_tag_debug("wrappedOutDataBlob", wrappedOutDataBlob, wrappedOutDataBlobSize);

            rsp->data[0] = keyListInfo[i].root_cert_id;
            if (wrappedOutDataBlobSize == 0) {
                LOGE("wrappedOutDataBlob is zero");
                ret = RET_ERR_WRONG_INPUT_FORMAT;
                goto error;
            }
            memcpy(rsp->data + 1, wrappedOutDataBlob, wrappedOutDataBlobSize);
            rsp->dataLen = wrappedOutDataBlobSize + 1;
            ret = RET_SUCCESS;

            goto error;
        }
    }

    LOGE("Not supported, key_name : %s, injection_type : 0x%02x, key_type : 0x%02x", key_name, injection_type, key_type);
    ret = RET_ERR_NOT_SUPPORT;

error:
    if (regen_eccKey != NULL) {
        crypto_clear_ecc_key(&regen_eccKey);
    }

    LOGD("check_key_list end : ret = %d", ret);
    rsp->ret = ret;
}

void check_caller_list(p_cmd_t cmd, p_rsp_t rsp) {
    int32_t ret = RET_SUCCESS;
    char verify_input[VERIFY_INPUT_SIZE_MAX + 1] = "";
    uint32_t inputSize, i;

    LOGD("check_caller_list started");
    inputSize = cmd->dataLen;
    if (inputSize > (sizeof(verify_input) - 1)) {
        LOGE("verify_input is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (inputSize == 0) {
        LOGE("verify_input is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(verify_input, cmd->data, inputSize);
    verify_input[inputSize] = '\0';
    LOGD("verify_input : %s", verify_input);
    for (i = 0 ; i < (sizeof(verify_original) / VERIFY_INPUT_SIZE_MAX) ; i++) {
        LOGD("verify_input[%d] : %s", i , verify_original[i]);
        if (strcmp(verify_input, verify_original[i]) == 0) {
            // permitted
            LOGD("Caller is permitted, %s", verify_input);
            ret = RET_SUCCESS;
            goto error;
        }
    }

    LOGE("Caller is not permitted, %s", verify_input);
    ret = RET_ERR_CALLER_NOT_PERMITTED;

error:
    LOGD("check_caller_list end : ret = %d", ret);
    rsp->ret = ret;
}

void factoryKeyInjection(p_cmd_t cmd, p_rsp_t rsp) {
    int32_t ret = RET_SUCCESS;

    uint8_t keyBlob[WRAPPED_KEY_INFO_SIZE];
    uint32_t keyBlobize;

    uint8_t mkC[AES_128_KEY_SIZE] = {0, };
    uint8_t mkI[AES_128_KEY_SIZE] = {0, };

    uint8_t iv[AES_BLOCK_SIZE];
    uint8_t hmac[SHA1_DIGEST_SIZE];
    uint8_t calculated_hmac[SHA1_DIGEST_SIZE];

    uint8_t sub_1_cert_block[MAX_CERT_SIZE];
    uint16_t sub_1_cert_blockSize = 0;

    uint8_t sub_2_cert_block[MAX_CERT_SIZE];
    uint16_t sub_2_cert_blockSize = 0;

    uint8_t leaf_cert_block[MAX_CERT_SIZE];
    uint16_t leaf_cert_blockSize = 0;

    uint8_t wrappedLeafKeyInfo[WRAPPED_MAX_LEAF_KEY_BLOB_SIZE];
    uint32_t wrappedLeafKeyInfoSize = 0;

    uint8_t wb_id = 0;

    uint8_t encrypted_key_block[WRAPPED_KEY_INFO_SIZE];
    uint16_t encrypted_key_blockSize;
    uint8_t decrypted_key_block[WRAPPED_KEY_INFO_SIZE];
    uint16_t decrypted_key_blockSize = sizeof(decrypted_key_block);
    uint32_t temp_decrypted_key_blockSize = sizeof(decrypted_key_block);

    uint8_t key_type;

    uint8_t key_name[MAX_KEY_NAME_SIZE];
    uint32_t key_name_size;

    uint8_t outDataBlob[WRAPPED_KEY_INFO_SIZE];
    uint32_t outDataBlobSize;
    uint8_t wrappedOutDataBlob[WRAPPED_KEY_INFO_SIZE];
    uint32_t wrappedOutDataBlobSize;

    uint32_t offset;
    uint32_t inputSize;

    const size_t wrappedLeafKeyInfoShift = 4 + SHA1_DIGEST_SIZE;

    uint8_t wb_id_0_iv[] = {
        0x67, 0xDB, 0xAB, 0x6E, 0x35, 0x1B, 0xE6, 0xEA, 0x13, 0xDA, 0x93, 0x20, 0xAE, 0x6F, 0x04, 0xF7};

    uint8_t wb_id_0_cihper[] = {
        0x6E, 0x61, 0xF3, 0x15, 0xB2, 0xD1, 0xC2, 0xA6, 0xC1, 0xBB, 0xF6, 0x6B, 0x25, 0x41, 0xC4, 0x6F,
        0x89, 0xDC, 0x43, 0x13, 0x5E, 0x22, 0xAF, 0x3B, 0x47, 0x25, 0x81, 0x89, 0x7A, 0xE7, 0x5E, 0xF7,
        0x1F, 0x02, 0xD2, 0x78, 0x6D, 0xDB, 0x55, 0x68, 0x58, 0x23, 0xDA, 0xF2, 0xFA, 0x55, 0x1D, 0xF0};

    uint8_t wb_id_1_iv[] = {
        0x25, 0x57, 0xEA, 0x60, 0xED, 0xA8, 0x57, 0xED, 0xC4, 0x24, 0x5B, 0x68, 0x17, 0x4A, 0xB0, 0x13};

    uint8_t wb_id_1_cihper[] = {
        0x80, 0xBF, 0x34, 0x12, 0xF5, 0x72, 0x00, 0x63, 0x45, 0x75, 0xE0, 0x8A, 0xA1, 0xC1, 0x94, 0x90,
        0xC5, 0x95, 0x01, 0x87, 0xFE, 0x6D, 0xBC, 0x9B, 0x43, 0xAA, 0x9E, 0x13, 0x69, 0x44, 0xE4, 0x10,
        0x7A, 0x61, 0xD3, 0x53, 0x10, 0x4A, 0xCB, 0xF7, 0x01, 0x71, 0xEB, 0x59, 0xD1, 0x08, 0xD0, 0xA8};

    uint8_t wb_id_2_iv[] = {
        0x1C, 0xB4, 0x8B, 0xAF, 0xA7, 0x4F, 0x8B, 0xE4, 0x23, 0x6B, 0x3E, 0xE8, 0xFF, 0x8D, 0xD1, 0x6F};

    uint8_t wb_id_2_cihper[] = {
        0x44, 0xFB, 0x3C, 0x39, 0x75, 0xF6, 0xA0, 0xF7, 0xFE, 0x5E, 0x40, 0x01, 0x7A, 0x7B, 0xB5, 0x35,
        0x42, 0x4F, 0x7E, 0x3F, 0xAC, 0x05, 0x7B, 0x9B, 0x0E, 0x6B, 0x65, 0xDF, 0xA4, 0x31, 0x57, 0x2E,
        0xE3, 0xFB, 0x35, 0x86, 0x6D, 0x83, 0x0E, 0x45, 0x0B, 0xBE, 0x2B, 0x89, 0x63, 0x71, 0x51, 0xF1};

    uint8_t wb_plain[sizeof(wb_id_0_cihper)] = {0, };
    int32_t wb_plainLen, error_code = 0;

    LOGI("factoryKeyInjection started");
    inputSize = cmd->dataLen;
    if (inputSize > WRAPPED_KEY_INFO_SIZE) {
        LOGE("Input data is over the buffer");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (inputSize == 0) {
        LOGE("cmd->data is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    // Parse input data : keyInfo, certInfo
    offset = 0;
    key_type = cmd->data[offset++];
    LOGD("key_type : %u", key_type);
    memcpy(&key_name_size, cmd->data + offset, 4);
    offset += 4;
    if (key_name_size > sizeof(key_name)) {
        LOGE("key_name is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (key_name_size == 0) {
        LOGE("key_name is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    memcpy(key_name, cmd->data + offset, key_name_size);
    offset += key_name_size;
    LOGD("key_name : %s", key_name);

    memcpy(&keyBlobize, cmd->data + offset, 4);
    offset += 4;
    if (keyBlobize > sizeof(keyBlob)) {
        LOGE("keyBlob is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (keyBlobize == 0) {
        LOGE("keyBlob is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(keyBlob, cmd->data + offset, keyBlobize);
    offset += keyBlobize;
    hex_print_tag_debug("keyBlob", keyBlob, keyBlobize);

    // Parse key Blob
    offset = 0;

retry_parse_sub_cert:
    if (keyBlob[offset] == 0x01) {
        if (keyBlob[offset + 1] == 0x11 || keyBlob[offset + 1] == 0x12) {
            // Sub 1, X509 or CASE
            sub_1_cert_blockSize = keyBlob[offset + 2];
            sub_1_cert_blockSize = sub_1_cert_blockSize << 8;
            sub_1_cert_blockSize |= keyBlob[offset + 3];
            // Add tag(2) and length(2) bytes
            sub_1_cert_blockSize += 4;
            if (sub_1_cert_blockSize > sizeof(sub_1_cert_block)) {
                LOGE("sub_1_cert_block is over the buffer.");
                ret = RET_ERR_BUFFER_NOT_ENOUGH;
                goto error;
            }
            if (sub_1_cert_blockSize == 0) {
                LOGE("sub_1_cert_block is zero");
                ret = RET_ERR_WRONG_INPUT_FORMAT;
                goto error;
            }
            memcpy(sub_1_cert_block, keyBlob + offset, sub_1_cert_blockSize);
            offset += sub_1_cert_blockSize;
            hex_print_tag_debug("sub_1_cert_block", sub_1_cert_block, sub_1_cert_blockSize);

            goto retry_parse_sub_cert;
        } else if (keyBlob[offset + 1] == 0x21 || keyBlob[offset + 1] == 0x22) {
            // Sub 2, X509 or CASE
            sub_2_cert_blockSize = keyBlob[offset + 2];
            sub_2_cert_blockSize = sub_2_cert_blockSize << 8;
            sub_2_cert_blockSize |= keyBlob[offset + 3];
            // Add tag(2) and length(2) bytes
            sub_2_cert_blockSize += 4;
            if (sub_2_cert_blockSize > sizeof(sub_2_cert_block)) {
                LOGE("sub_2_cert_block is over the buffer.");
                ret = RET_ERR_BUFFER_NOT_ENOUGH;
                goto error;
            }
            if (sub_2_cert_blockSize == 0) {
                LOGE("sub_2_cert_block is zero");
                ret = RET_ERR_WRONG_INPUT_FORMAT;
                goto error;
            }
            memcpy(sub_2_cert_block, keyBlob + offset, sub_2_cert_blockSize);
            offset += sub_2_cert_blockSize;
            hex_print_tag_debug("sub_2_cert_block", sub_2_cert_block, sub_2_cert_blockSize);

        } else {
            LOGE("Sub cert. tag is not correct");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
    }

    if (keyBlob[offset] == 0x02) {
        if (keyBlob[offset + 1] == 0x01 || keyBlob[offset + 1] == 0x02) {
            // Leaf, X509 or CASD
            leaf_cert_blockSize = keyBlob[offset + 2];
            leaf_cert_blockSize = leaf_cert_blockSize << 8;
            leaf_cert_blockSize |= keyBlob[offset + 3];
            // Add tag(2) and length(2) bytes
            leaf_cert_blockSize += 4;
            if (leaf_cert_blockSize > sizeof(leaf_cert_block)) {
                LOGE("leaf_cert_block is over the buffer.");
                ret = RET_ERR_BUFFER_NOT_ENOUGH;
                goto error;
            }
            if (leaf_cert_blockSize == 0) {
                LOGE("leaf_cert_block is zero");
                ret = RET_ERR_WRONG_INPUT_FORMAT;
                goto error;
            }
            memcpy(leaf_cert_block, keyBlob + offset, leaf_cert_blockSize);
            offset += leaf_cert_blockSize;
            hex_print_tag_debug("leaf_cert_block", leaf_cert_block, leaf_cert_blockSize);
        } else {
            LOGE("Leaf cert. tag is not correct");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
    } else {
        LOGE("Leaf cert is not exist");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    if (keyBlob[offset] == 0x03) {
        if (keyBlob[offset + 1] == key_type) {
            // Leaf priv, ECC P256 or RSA 2048
            wrappedLeafKeyInfoSize = keyBlob[offset + 2];
            wrappedLeafKeyInfoSize = wrappedLeafKeyInfoSize << 8;
            wrappedLeafKeyInfoSize |= keyBlob[offset + 3];
            // Add tag(2) and length(2) bytes
            wrappedLeafKeyInfoSize += 4;
            if (wrappedLeafKeyInfoSize > sizeof(wrappedLeafKeyInfo)) {
                LOGE("wrappedLeafKeyInfo is over the buffer.");
                ret = RET_ERR_BUFFER_NOT_ENOUGH;
                goto error;
            }
            if (wrappedLeafKeyInfoSize == 0) {
                LOGE("wrappedLeafKeyInfo is zero");
                ret = RET_ERR_WRONG_INPUT_FORMAT;
                goto error;
            }
            memcpy(wrappedLeafKeyInfo, keyBlob + offset, wrappedLeafKeyInfoSize);
            offset += wrappedLeafKeyInfoSize;
            hex_print_tag_debug("wrappedLeafKeyInfo", wrappedLeafKeyInfo, wrappedLeafKeyInfoSize);
        } else {
            LOGE("Leaf private. Key type is not matched");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
    } else {
        LOGE("wrappedLeafKeyInfo is not exist");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    // Parse keyInfo
    offset = 0;
    if (wrappedLeafKeyInfo[offset] != 0x03) {
        LOGE("Key tag is not correct");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    offset += 4;
    wb_id = wrappedLeafKeyInfo[offset++];
    LOGD("wb_id : %u", wb_id);
    memcpy(iv, wrappedLeafKeyInfo + offset, AES_BLOCK_SIZE);
    offset += AES_BLOCK_SIZE;
    hex_print_tag_debug("iv", iv, AES_BLOCK_SIZE);
    encrypted_key_blockSize = wrappedLeafKeyInfo[offset];
    encrypted_key_blockSize = encrypted_key_blockSize << 8;
    encrypted_key_blockSize |= wrappedLeafKeyInfo[offset + 1];
    offset += 2;
    if (encrypted_key_blockSize > sizeof(encrypted_key_block)) {
        LOGE("encrypted_key_block is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (encrypted_key_blockSize == 0) {
        LOGE("encrypted_key_block is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    if ( offset + encrypted_key_blockSize > wrappedLeafKeyInfoSize ){
        LOGE("wrappedLeafKeyInfo is over the buffer at parse encrypted_key_block");
        ret = RET_ERR_SRC_BUFFER_OVERFLOW;
        goto error;
    }

    if ( offset + encrypted_key_blockSize >= sizeof(wrappedLeafKeyInfo) ){
        LOGE("wrappedLeafKeyInfo buffer is less for encrypted_key_block");
        ret = RET_ERR_SRC_BUFFER_OVERFLOW;
        goto error;
    }

    memcpy(encrypted_key_block, wrappedLeafKeyInfo + offset, encrypted_key_blockSize);
    hex_print_tag_debug("encrypted_key_block", encrypted_key_block, encrypted_key_blockSize);
    offset += encrypted_key_blockSize;

    if ( offset + SHA1_DIGEST_SIZE > wrappedLeafKeyInfoSize ){
        LOGE("wrappedLeafKeyInfo is over the buffer at parse hmac");
        ret = RET_ERR_SRC_BUFFER_OVERFLOW;
        goto error;
    }

    if ( offset + SHA1_DIGEST_SIZE > sizeof(wrappedLeafKeyInfo) ){
        LOGE("wrappedLeafKeyInfo buffer is less for hmac");
        ret = RET_ERR_SRC_BUFFER_OVERFLOW;
        goto error;
    }

    memcpy(hmac, wrappedLeafKeyInfo + offset, SHA1_DIGEST_SIZE);
    offset += SHA1_DIGEST_SIZE;

    switch(wb_id) {
        case 0:
            hex_print_tag_debug("wb_id_0_iv", wb_id_0_iv, sizeof(wb_id_0_iv));
            hex_print_tag_debug("wb_id_0_cihper", wb_id_0_cihper, sizeof(wb_id_0_cihper));
            error_code = dec_text((const unsigned char **)SWBC_DEC_MC_SKPM_TEST, (const unsigned char *)SWBC_DEC_MC_SKPM_TEST_TAG, NULL,
                wb_id_0_iv, wb_id_0_cihper, sizeof(wb_id_0_cihper), wb_plain, &wb_plainLen);
            break;

        case 1:
            hex_print_tag_debug("wb_id_1_iv", wb_id_1_iv, sizeof(wb_id_1_iv));
            hex_print_tag_debug("wb_id_1_cihper", wb_id_1_cihper, sizeof(wb_id_1_cihper));
            error_code = dec_text((const unsigned char **)SWBC_DEC_MC_SKPM_FAC, (const unsigned char *)SWBC_DEC_MC_SKPM_FAC_TAG, NULL,
                wb_id_1_iv, wb_id_1_cihper, sizeof(wb_id_1_cihper), wb_plain, &wb_plainLen);
            break;

        case 2:
            hex_print_tag_debug("wb_id_2_iv", wb_id_2_iv, sizeof(wb_id_2_iv));
            hex_print_tag_debug("wb_id_2_cihper", wb_id_2_cihper, sizeof(wb_id_2_cihper));
            error_code = dec_text((const unsigned char **)SWBC_DEC_MC_SKPM_OTA, (const unsigned char *)SWBC_DEC_MC_SKPM_OTA_TAG, NULL,
                wb_id_2_iv, wb_id_2_cihper, sizeof(wb_id_2_cihper), wb_plain, &wb_plainLen);
            break;

        default:
            LOGE("Not supported wb_id");
            ret = RET_ERR_GET_MK_FACTORY;
            goto error;
    }

    if (SWBC_SUCCESS != error_code) {
        LOGE("getMk is failed");
        ret = RET_ERR_GET_MK_FACTORY;
        goto error;
    }

    //hex_print_tag_debug("wb_plain", wb_plain, wb_plainLen);

    if (wb_plainLen == AES_128_KEY_SIZE + AES_128_KEY_SIZE) {
        memcpy(mkC, wb_plain, AES_128_KEY_SIZE);
        memcpy(mkI, wb_plain + AES_128_KEY_SIZE, AES_128_KEY_SIZE);
        secure_memclear(wb_plain, wb_plainLen);
    } else {
        LOGE("wb_plain is not correct length");
        ret = RET_ERR_GET_MK_FACTORY;
        goto error;
    }

    if (wrappedLeafKeyInfoSize < wrappedLeafKeyInfoShift) {
        LOGE("wrappedLeafKeyInfoSize < wrappedLeafKeyInfoShift");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    crypto_hmac(MD_TYPE_SHA1, calculated_hmac, mkI, AES_128_KEY_SIZE, wrappedLeafKeyInfo + 4, wrappedLeafKeyInfoSize - wrappedLeafKeyInfoShift, NULL);

    if (crypto_secure_cmp(hmac, calculated_hmac, SHA1_DIGEST_SIZE) != 0) {
        LOGE("MAC is not correct");
        ret = RET_ERR_MAC_NOT_CORRECT;
        goto error;
    }

    crypto_aes_cbc_decrypt(encrypted_key_block, encrypted_key_blockSize, decrypted_key_block, &temp_decrypted_key_blockSize, iv, mkC, AES_128_KEY_SIZE);
    decrypted_key_blockSize = temp_decrypted_key_blockSize;

    hex_print_tag_debug("decrypted_key_block", decrypted_key_block, decrypted_key_blockSize);

    // Replace priv key from encrypted to decrypted
    offset = 2;
    wrappedLeafKeyInfo[offset++] = decrypted_key_blockSize >> 8;
    wrappedLeafKeyInfo[offset++] = decrypted_key_blockSize;
    if (decrypted_key_blockSize == 0) {
        LOGE("decrypted_key_block is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    if (decrypted_key_blockSize > (sizeof(wrappedLeafKeyInfo) - offset)) {
        LOGE("decrypted_key_blockSize is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    memcpy(wrappedLeafKeyInfo + offset, decrypted_key_block, decrypted_key_blockSize);
    offset += decrypted_key_blockSize;
    wrappedLeafKeyInfoSize = offset;
    hex_print_tag_debug("Replaced wrappedLeafKeyInfo", wrappedLeafKeyInfo, wrappedLeafKeyInfoSize);

    // ---------------------
    // Tag        Length  Value
    // ---------------------
    // 0x011X 0x0000 sub1 cert... (DER encoded : 0x0111 - X.509, 0x0112 - CASD) - Optional
    // 0x012X 0x0000 sub2 cert... (DER encoded : 0x0121 - X.509, 0x0122 - CASD) - Optional
    // 0x020X 0x0000 leaf cert... (DER encoded : 0x0201 - X.509, 0x0202 - CASD)
    // 0x0300 0x0000 leaf private key...(DER encoded : 0x0301 - EC Key (RFC 5915) , RSA Key - 0x0302)

    offset = 0;
    if (sub_1_cert_blockSize > 0) {
        memcpy(outDataBlob + offset, sub_1_cert_block, sub_1_cert_blockSize);
        offset += sub_1_cert_blockSize;
    }
    if (sub_2_cert_blockSize > 0) {
        memcpy(outDataBlob + offset, sub_2_cert_block, sub_2_cert_blockSize);
        offset += sub_2_cert_blockSize;
    }
    memcpy(outDataBlob + offset, leaf_cert_block, leaf_cert_blockSize);
    offset += leaf_cert_blockSize;
    memcpy(outDataBlob + offset, wrappedLeafKeyInfo, wrappedLeafKeyInfoSize);
    offset += wrappedLeafKeyInfoSize;

    outDataBlobSize = offset;
    hex_print_tag_debug("outDataBlob", outDataBlob, outDataBlobSize);

    ret = leaKeyPairVerification(outDataBlob, outDataBlobSize);
    if (ret != RET_SUCCESS) {
        LOGE("leaKeyPairVerification is failed");
        goto error;
    }

    wrappedOutDataBlobSize = sizeof(wrappedOutDataBlob);
    if (wrapInternalData(SECURE_OBJECT_TYPE_KEYBLOB, outDataBlob, outDataBlobSize, wrappedOutDataBlob, &wrappedOutDataBlobSize) != STATUS_SUCCESS) {
        ret = RET_ERR_DATA_WRAPPING_FAIL;
        goto error;
    }
    hex_print_tag_debug("wrappedOutDataBlob", wrappedOutDataBlob, wrappedOutDataBlobSize);

    rsp->dataLen = wrappedOutDataBlobSize;
    if (wrappedOutDataBlobSize == 0) {
        LOGE("wrappedOutDataBlobSize is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(rsp->data, wrappedOutDataBlob, wrappedOutDataBlobSize);

    ret = RET_SUCCESS;

error:
    secure_memclear(mkC, sizeof(mkC));
    secure_memclear(mkI, sizeof(mkI));

    LOGI("factoryKeyInjection end : ret = %d", ret);
    rsp->ret = ret;
}

void otaKeyInjection(p_cmd_t cmd, p_rsp_t rsp) {
    int32_t ret = RET_SUCCESS;

    uint8_t key_name[MAX_KEY_NAME_SIZE];
    uint32_t key_name_size;

    uint8_t key_type;

    uint8_t sub_1_cert_block[MAX_CERT_SIZE];
    uint16_t sub_1_cert_blockSize;

    uint8_t sub_2_cert_block[MAX_CERT_SIZE];
    uint16_t sub_2_cert_blockSize;

    uint8_t leaf_cert_block[MAX_CERT_SIZE];
    uint16_t leaf_cert_blockSize;

    uint8_t wrappedLeafKeyInfo[WRAPPED_MAX_LEAF_KEY_BLOB_SIZE];
    uint32_t wrappedLeafKeyInfoSize;

    uint8_t unwrappedLeafKeyInfo[WRAPPED_KEY_INFO_SIZE];
    uint32_t unwrappedLeafKeyInfoSize = sizeof(wrappedLeafKeyInfo);

    uint8_t key_block[WRAPPED_KEY_INFO_SIZE];
    uint16_t key_blockSize;

    uint8_t outDataBlob[WRAPPED_KEY_INFO_SIZE];
    uint32_t outDataBlobSize;

    uint8_t wrappedOutDataBlob[WRAPPED_KEY_INFO_SIZE];
    uint32_t wrappedOutDataBlobSize;

    uint32_t offset, temp_value;

    ecc_key_t eccLeafKeyInfo;
    rsa_key_t rsaLeafKeyInfo;

    uint32_t inputSize;

    LOGI("otaKeyInjection started");
    inputSize = cmd->dataLen;
    if (inputSize > WRAPPED_KEY_INFO_SIZE) {
        LOGE("Input data is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (inputSize == 0) {
        LOGE("cmd->data is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    // Parse input data : keyInfo, certInfo
    offset = 0;
    memcpy(&key_name_size, cmd->data + offset, 4);
    offset += 4;
    if (key_name_size > sizeof(key_name)) {
        LOGE("key_name is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (key_name_size == 0) {
        LOGE("key_name is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(key_name, cmd->data + offset, key_name_size);
    offset += key_name_size;
    LOGD("key_name : %s", key_name);
    key_type = cmd->data[offset++];
    LOGD("key_type : %u", key_type);
    memcpy(&temp_value, cmd->data + offset, 4);
    offset += 4;
    sub_1_cert_blockSize = temp_value;
    if (sub_1_cert_blockSize > sizeof(sub_1_cert_block)) {
        LOGE("sub_1_cert_block is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (sub_1_cert_blockSize != 0) {
        memcpy(sub_1_cert_block, cmd->data + offset, sub_1_cert_blockSize);
        offset += sub_1_cert_blockSize;
        hex_print_tag_debug("sub_1_cert_block", sub_1_cert_block, sub_1_cert_blockSize);
    }
    memcpy(&temp_value, cmd->data + offset, 4);
    offset += 4;
    sub_2_cert_blockSize = temp_value;
    if (sub_2_cert_blockSize > sizeof(sub_2_cert_block)) {
        LOGE("sub_2_cert_block is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (sub_2_cert_blockSize != 0) {
        memcpy(sub_2_cert_block, cmd->data + offset, sub_2_cert_blockSize);
        offset += sub_2_cert_blockSize;
        hex_print_tag_debug("sub_2_cert_block", sub_2_cert_block, sub_2_cert_blockSize);
    }
    memcpy(&temp_value, cmd->data + offset, 4);
    offset += 4;
    leaf_cert_blockSize = temp_value;
    if (leaf_cert_blockSize > sizeof(leaf_cert_block)) {
        LOGE("leaf_cert_block is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (leaf_cert_blockSize == 0) {
        LOGE("leaf_cert_block is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(leaf_cert_block, cmd->data + offset, leaf_cert_blockSize);
    offset += leaf_cert_blockSize;
    hex_print_tag_debug("leaf_cert_block", leaf_cert_block, leaf_cert_blockSize);
    memcpy(&wrappedLeafKeyInfoSize, cmd->data + offset, 4);
    offset += 4;
    if (wrappedLeafKeyInfoSize > sizeof(wrappedLeafKeyInfo)) {
        LOGE("wrappedLeafKeyInfo is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (wrappedLeafKeyInfoSize == 0) {
        LOGE("wrappedLeafKeyInfo is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(wrappedLeafKeyInfo, cmd->data + offset, wrappedLeafKeyInfoSize);
    offset += wrappedLeafKeyInfoSize;
    hex_print_tag_debug("wrappedLeafKeyInfo", wrappedLeafKeyInfo, wrappedLeafKeyInfoSize);

    // ---------------------
    // Tag        Length  Value
    // ---------------------
    // 0x011X 0x0000 sub1 cert... (DER encoded : 0x0111 - X.509, 0x0112 - CASD) - Optional
    // 0x012X 0x0000 sub2 cert... (DER encoded : 0x0121 - X.509, 0x0122 - CASD) - Optional
    // 0x020X 0x0000 leaf cert... (DER encoded : 0x0201 - X.509, 0x0202 - CASD)
    // 0x030X 0x0000 leaf private key...(DER encoded : 0x0301 - EC Key (RFC 5915) , RSA Key - 0x0302)

    if (key_type == KEY_TYPE_ECC_P256) {
        if (unwrapInternalData(SECURE_OBJECT_TYPE_ECC_KEY_INFO, wrappedLeafKeyInfo, wrappedLeafKeyInfoSize, unwrappedLeafKeyInfo, &unwrappedLeafKeyInfoSize) != STATUS_SUCCESS) {
            ret = RET_ERR_DATA_UNWRAPPING_FAIL;
            goto error;
        }
        if (unwrappedLeafKeyInfoSize != sizeof(ecc_key_t)) {
            LOGE("Not correct input format");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        memcpy(&eccLeafKeyInfo, unwrappedLeafKeyInfo, unwrappedLeafKeyInfoSize);

        hex_print_tag_debug("eccLeafKeyInfo", (uint8_t *)&eccLeafKeyInfo, unwrappedLeafKeyInfoSize);
        if (eccLeafKeyInfo.privkey_size > sizeof(eccLeafKeyInfo.privkey_binary))
        {
            LOGE("eccLeafKeyInfo.privkey_size > sizeof(eccLeafKeyInfo.privkey_binary)");
            ret = RET_ERR_BUFFER_NOT_ENOUGH;
            goto error;
        }
        if (eccLeafKeyInfo.pubkey_size > sizeof(eccLeafKeyInfo.pubkey_binary))
        {
            LOGE("eccLeafKeyInfo.pubkey_size > sizeof(eccLeafKeyInfo.pubkey_binary)");
            ret = RET_ERR_BUFFER_NOT_ENOUGH;
            goto error;
        }
        encodeAsn1EccPrivateKey(eccLeafKeyInfo, key_block, &key_blockSize);
    } else if (key_type == KEY_TYPE_RSA_2048) {
        if (unwrapInternalData(SECURE_OBJECT_TYPE_RSA_KEY_INFO, wrappedLeafKeyInfo, wrappedLeafKeyInfoSize, unwrappedLeafKeyInfo, &unwrappedLeafKeyInfoSize) != STATUS_SUCCESS) {
            ret = RET_ERR_DATA_UNWRAPPING_FAIL;
            goto error;
        }
        if (unwrappedLeafKeyInfoSize != sizeof(rsa_key_t)) {
            LOGE("Not correct input format");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        memcpy(&rsaLeafKeyInfo, unwrappedLeafKeyInfo, unwrappedLeafKeyInfoSize);
        hex_print_tag_debug("rsaLeafKeyInfo", (uint8_t *)&rsaLeafKeyInfo, unwrappedLeafKeyInfoSize);
        encodeAsn1RsaPrivateKey(rsaLeafKeyInfo, key_block, &key_blockSize);
    } else {
        LOGE("Not supported key_type");
        ret = RET_ERR_NOT_SUPPORT;
        goto error;
    }
    hex_print_tag_debug("encoded leaf key", key_block, key_blockSize);

    offset = 0;

    if (sub_1_cert_blockSize > 0) {
        if (sub_2_cert_blockSize > 0) {
            // CA sub cert. 1 & 2
            outDataBlob[offset++] = 0x01;
            if (sub_1_cert_block[0] == 0x30 && sub_1_cert_block[1] == 0x82) {
                // X.509
                outDataBlob[offset++] = 0x11;
            } else {
                // CASD
                outDataBlob[offset++] = 0x12;
            }
            outDataBlob[offset++] = sub_1_cert_blockSize >> 8;
            outDataBlob[offset++] = sub_1_cert_blockSize;
            if (sub_1_cert_blockSize == 0) {
                LOGE("sub_1_cert_block is zero");
                ret =  RET_ERR_WRONG_INPUT_FORMAT;
                goto error;
            }
            memcpy(outDataBlob + offset, sub_1_cert_block, sub_1_cert_blockSize);
            offset += sub_1_cert_blockSize;
            outDataBlob[offset++] = 0x01;
            if (sub_2_cert_block[0] == 0x30 && sub_2_cert_block[1] == 0x82) {
                // X.509
                outDataBlob[offset++] = 0x21;
            } else {
                // CASD
                outDataBlob[offset++] = 0x22;
            }
            outDataBlob[offset++] = sub_2_cert_blockSize >> 8;
            outDataBlob[offset++] = sub_2_cert_blockSize;
            if (sub_2_cert_blockSize == 0) {
                LOGE("sub_2_cert_block is zero");
                ret =  RET_ERR_WRONG_INPUT_FORMAT;
                goto error;
            }
            memcpy(outDataBlob + offset, sub_2_cert_block, sub_2_cert_blockSize);
            offset += sub_2_cert_blockSize;
        } else {
            // CA sub cert. 1
            outDataBlob[offset++] = 0x01;
            if (sub_1_cert_block[0] == 0x30 && sub_1_cert_block[1] == 0x82) {
                // X.509
                outDataBlob[offset++] = 0x11;
            } else {
                // CASD
                outDataBlob[offset++] = 0x12;
            }
            outDataBlob[offset++] = sub_1_cert_blockSize >> 8;
            outDataBlob[offset++] = sub_1_cert_blockSize;
            if (sub_1_cert_blockSize == 0) {
                LOGE("sub_1_cert_block is zero");
                ret =  RET_ERR_WRONG_INPUT_FORMAT;
                goto error;
            }
            memcpy(outDataBlob + offset, sub_1_cert_block, sub_1_cert_blockSize);
            offset += sub_1_cert_blockSize;
        }
    } else {
        // No CA sub
        LOGI("Sub CA does not exist");
    }

    outDataBlob[offset++] = 0x02;
    if (leaf_cert_block[0] == 0x30 && leaf_cert_block[1] == 0x82) {
        // X.509
        outDataBlob[offset++] = 0x01;
    } else {
        // CASD
        outDataBlob[offset++] = 0x02;
    }
    outDataBlob[offset++] = leaf_cert_blockSize >> 8;
    outDataBlob[offset++] = leaf_cert_blockSize;
    if (leaf_cert_blockSize == 0) {
        LOGE("leaf_cert_block is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(outDataBlob + offset, leaf_cert_block, leaf_cert_blockSize);
    offset += leaf_cert_blockSize;
    outDataBlob[offset++] = 0x03;
    if (key_type == KEY_TYPE_ECC_P256) {
        // ECC P256
        outDataBlob[offset++] = 0x01;
    } else if (key_type == KEY_TYPE_RSA_2048) {
        // RSA 2048
        outDataBlob[offset++] = 0x02;
    }
    outDataBlob[offset++] = key_blockSize >> 8;
    outDataBlob[offset++] = key_blockSize;
    if (key_blockSize == 0) {
        LOGE("key_block is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    if ((offset + key_blockSize) > sizeof(outDataBlob))
    {
        LOGE("(offset + key_blockSize) > sizeof(outDataBlob)");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    memcpy(outDataBlob + offset, key_block, key_blockSize);
    offset += key_blockSize;

    outDataBlobSize = offset;
    hex_print_tag_debug("outDataBlob", outDataBlob, outDataBlobSize);

    ret = leaKeyPairVerification(outDataBlob, outDataBlobSize);
    if (ret != RET_SUCCESS) {
        LOGE("leaKeyPairVerification is failed");
        goto error;
    }

    wrappedOutDataBlobSize = sizeof(wrappedOutDataBlob);
    if (wrapInternalData(SECURE_OBJECT_TYPE_KEYBLOB, outDataBlob, outDataBlobSize, wrappedOutDataBlob, &wrappedOutDataBlobSize) != STATUS_SUCCESS) {
        ret = RET_ERR_DATA_WRAPPING_FAIL;
        goto error;
    }
    hex_print_tag_debug("wrappedOutDataBlob", wrappedOutDataBlob, wrappedOutDataBlobSize);

    rsp->dataLen = wrappedOutDataBlobSize;
    if (wrappedOutDataBlobSize == 0) {
        LOGE("wrappedOutDataBlobSize is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(rsp->data, wrappedOutDataBlob, wrappedOutDataBlobSize);

    ret = RET_SUCCESS;

error:
    LOGI("otaKeyInjection end : ret = %d", ret);
    rsp->ret = ret;
}

int parseLenth(uint8_t lengthBytes[3], uint16_t *len) {
    uint16_t tempLen = 0;

    if (lengthBytes[0] == 0x82) {
        tempLen = lengthBytes[1];
        tempLen = tempLen << 8;
        tempLen |= lengthBytes[2];
        *len = tempLen;
        return 3;
    } else if (lengthBytes[0] == 0x81) {
        tempLen = lengthBytes[1];
        *len = tempLen;
        return 2;
    } else {
        tempLen = lengthBytes[0];
        *len = tempLen;
        return 1;
    }
}


/*
30 82 0310
30 82 02B4
    A0 03 020102
    02 09 00F63300B7599F0B5B
    30 0C 06082A8648CE3D0403020500
    30 81A6
        311F301D0603550403131653616D73756E6720456C656374726F6E696373204341311C301A060355040A131353616D73756E6720456C656374726F6E69637331173015060355040B130E53616D73756E67204D6F62696C65311330110603550407130A5375776F6E2063697479310B3009060355040613024B52312A3028060A0992268993F22C6401010C1A53616D73756E67446576696365526F6F7443414B65795F454343
    30 1E 170D3137303732353032353430305A170D3337303732303032353430305A
    30 81CA 312F302D06035504030C2653616D73756E6720456C656374726F6E696373204154542F414149443D353345432343303035311C
        30 1A 060355040A131353616D73756E6720456C656374726F6E696373
        31 17 3015060355040B130E53616D73756E67204D6F62696C65
        31 13 30110603550407130A5375776F6E2063697479
        31 0B 3009060355040613024B52
        31 3E 303C060A0992268993F22C6401010C2E454E473A32303137303732353A30333A46463A30303030303030443A4649444F3A464143453A4543435F50323536
    30 59
        30 13 06072A8648CE3D020106082A8648CE3D030107
        03 42 00041E583A077E663B2BAE962D7C7C103F3A90FB9B8472F2A049A2E11597A77FD23F6A6964FA13C4CE56407F28E6486CC6923F9F5D73F7B49D60B732D3B9F11F4823
    A3 81A2
        30 819F
            30 0E 0603551D0F0101FF0404030206C030
            3D 06 03551D1F0436
            30 34 3032A030A02E862C687474703A2F2F63726C2E73616D73756E672E636F6D2F73656375726974792F72646576696365732E63726C300F0603551D130101FF04053003020100303D06082B060105050701010431302F302D06082B060105050730018621687474703A2F2F6F6373702E73616D73756E672E636F6D2F73656375726974792F
30 0C 06082A8648CE3D0403020500
03 48 003045022100E8D9DBDA0CE099EE4AFE9D026A08E5F23146E5F6DC55CCE6B2FAE6EAF1C165EB02207C13651FCA2CE14A25A4590B62061F8EFB2CB8048E451A14F27D479AB34DAC31
*/

#define CHECK_LEAF_OFFSET(size) \
    if( (offset + (size)) > leaf_cert_blockSize ) { \
        LOGE("Not enough data"); \
        ret = RET_ERR_SRC_BUFFER_OVERFLOW; \
        goto error; \
    }

#define CHECK_LEAF_TAG(tag) \
    CHECK_LEAF_OFFSET(0); \
    if (leaf_cert_block[offset] != (tag)) { \
        LOGE("Input data foramt is not correct"); \
        ret = RET_ERR_WRONG_INPUT_FORMAT; \
        goto error; \
    }

// This function should be used for devices without SCrypto support
// Do NOT use this function or parts of this function for build with SCrypto!
// Please refer to leaf_blob_verify instead
int getPublicKeyFromCert(uint8_t* leaf_cert_block, const uint32_t leaf_cert_blockSize,
    uint8_t publicKey_block[MAX_CERT_SIZE], uint16_t *publicKey_blockSize)
{
    int32_t ret = RET_SUCCESS;
    uint32_t offset = 0;
    uint16_t temp_len;

    LOGD("getPublicKeyFromCert started");

    CHECK_LEAF_OFFSET(4);
    if (leaf_cert_block[offset] != 0x30 || leaf_cert_block[offset + 4] != 0x30) {
        LOGE("Input data foramt is not correct");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    offset += 8;

    // Tag : A0
    CHECK_LEAF_TAG(0xA0);
    offset ++;
    CHECK_LEAF_OFFSET(sizeof(temp_len));
    offset += parseLenth(leaf_cert_block + offset, &temp_len);
    offset += temp_len;

    // Tag : 02
    CHECK_LEAF_TAG(0x02);
    offset ++;
    CHECK_LEAF_OFFSET(sizeof(temp_len));
    offset += parseLenth(leaf_cert_block + offset, &temp_len);
    offset += temp_len;

    // Tag : 30
    CHECK_LEAF_TAG(0x30);
    offset ++;
    CHECK_LEAF_OFFSET(sizeof(temp_len));
    offset += parseLenth(leaf_cert_block + offset, &temp_len);
    offset += temp_len;

    // Tag : 30
    CHECK_LEAF_TAG(0x30);
    offset ++;
    CHECK_LEAF_OFFSET(sizeof(temp_len));
    offset += parseLenth(leaf_cert_block + offset, &temp_len);
    offset += temp_len;

    // Tag : 30
    CHECK_LEAF_TAG(0x30);
    offset ++;
    CHECK_LEAF_OFFSET(sizeof(temp_len));
    offset += parseLenth(leaf_cert_block + offset, &temp_len);
    offset += temp_len;

    // Tag : 30
    CHECK_LEAF_TAG(0x30);
    offset ++;
    CHECK_LEAF_OFFSET(sizeof(temp_len));
    offset += parseLenth(leaf_cert_block + offset, &temp_len);
    offset += temp_len;

    // Tag : 30 : Publickey
    CHECK_LEAF_TAG(0x30);
    offset ++;
    CHECK_LEAF_OFFSET(sizeof(temp_len));
    offset += parseLenth(leaf_cert_block + offset, &temp_len);

    // Tag : 30 - Sub tag 30 : Publickey
    CHECK_LEAF_TAG(0x30);
    offset ++;
    CHECK_LEAF_OFFSET(sizeof(temp_len));
    offset += parseLenth(leaf_cert_block + offset, &temp_len);
    offset += temp_len;

    // Tag : 30 - Sub tag 03 : Publickey
    CHECK_LEAF_TAG(0x03);
    offset ++;
    CHECK_LEAF_OFFSET(sizeof(temp_len));
    offset += parseLenth(leaf_cert_block + offset, &temp_len);

    *publicKey_blockSize = temp_len;
    CHECK_LEAF_OFFSET(*publicKey_blockSize);
    if (*publicKey_blockSize > MAX_CERT_SIZE) {
        LOGE("key_block is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }

    CHECK_LEAF_OFFSET(0);
    if (leaf_cert_block[offset] == 0x00) {
        offset++;
        *publicKey_blockSize = *publicKey_blockSize - 1;
    }
    memcpy(publicKey_block, leaf_cert_block + offset, *publicKey_blockSize);

    ret = RET_SUCCESS;

error:
    LOGD("getPublicKeyFromCert end : ret = %d", ret);

    return ret;
}
#undef CHECK_LEAF_TAG
#undef CHECK_LEAF_OFFSET

int leaKeyPairVerification(uint8_t outDataBlob[WRAPPED_KEY_INFO_SIZE], uint32_t outDataBlobSize) {
#ifdef USE_SCRYPTO
    return leaf_blob_verify( outDataBlob, outDataBlobSize );
#else
    int32_t ret = RET_SUCCESS;

    uint16_t sub_1_cert_blockSize = 0;
    uint16_t sub_2_cert_blockSize = 0;

    uint8_t leaf_cert_block[MAX_CERT_SIZE];
    uint16_t leaf_cert_blockSize;

    uint8_t key_block[WRAPPED_KEY_INFO_SIZE];
    uint16_t key_blockSize;

    uint8_t publicKey_block[MAX_CERT_SIZE];
    uint16_t publicKey_blockSize;

    uint32_t offset, i;
    uint16_t temp_len;

    ecc_key_t ecc_key;
    EC_KEY  *privKey = NULL, *pubKey = NULL;

    rsa_key_t rsa_key;
    RSA  *rsaKey = NULL;

    uint8_t modulus[300];
    uint32_t modulus_size;
    uint8_t publicExponent[5];
    uint32_t publicExponent_size;

    uint8_t testIn[AP_ID_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10};
    uint8_t sig_s[ECDSA_SIG_SIZE/2], sig_r[ECDSA_SIG_SIZE/2];
    uint32_t sig_s_len, sig_r_len;

    uint8_t sig[RSA_SIG_SIZE];
    uint32_t sig_size = RSA_SIG_SIZE;

    uint8_t key_type;

    LOGD("leaKeyPairVerification started");

    hex_print_tag_debug("outDataBlob", outDataBlob, outDataBlobSize);

    // Parse cert. key blob
    offset = 0;

    if (outDataBlob[offset] == 0x01) {
        // CA cert exist
        offset++;
        offset++;
        sub_1_cert_blockSize = outDataBlob[offset++];
        sub_1_cert_blockSize = sub_1_cert_blockSize << 8;
        sub_1_cert_blockSize |= outDataBlob[offset++];
        offset += sub_1_cert_blockSize;

        if (outDataBlob[offset] == 0x01) {
            // Second CA cert exist
            offset++;
            offset++;
            sub_2_cert_blockSize = outDataBlob[offset++];
            sub_2_cert_blockSize = sub_2_cert_blockSize << 8;
            sub_2_cert_blockSize |= outDataBlob[offset++];
            offset += sub_2_cert_blockSize;
        }
    } else {
        LOGI("Sub CAs does not exist");
    }

    if (outDataBlob[offset++] != 0x02) {
        LOGE("Input data foramt is not correct : No leaf cert");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    // Leaf
    offset++;
    leaf_cert_blockSize = outDataBlob[offset++];
    leaf_cert_blockSize = leaf_cert_blockSize << 8;
    leaf_cert_blockSize |= outDataBlob[offset++];
    if (leaf_cert_blockSize > sizeof(leaf_cert_block)) {
        LOGE("leaf_cert_block is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (leaf_cert_blockSize == 0) {
        LOGE("leaf_cert_block is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(leaf_cert_block, outDataBlob + offset, leaf_cert_blockSize);
    offset += leaf_cert_blockSize;
    hex_print_tag_debug("leaf_cert_block", leaf_cert_block, leaf_cert_blockSize);

    if (outDataBlob[offset++] != 0x03) {
        LOGE("Input data foramt is not correct : No leaf key blob");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    key_type = outDataBlob[offset++];
    LOGD("key_type : %u", key_type);
    key_blockSize = outDataBlob[offset++];
    key_blockSize = key_blockSize << 8;
    key_blockSize |= outDataBlob[offset++];
    if (key_blockSize > sizeof(key_block)) {
        LOGE("key_block is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (key_blockSize == 0) {
        LOGE("key_block is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(key_block, outDataBlob + offset, key_blockSize);
    offset += key_blockSize;
    hex_print_tag_debug("key_block", key_block, key_blockSize);

    // Parse private key blob
    if (key_type == KEY_TYPE_ECC_P256) {
        // ECC P256
        offset = 5;
        if (key_block[offset++] != 0x04) {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        ecc_key.privkey_size = key_block[offset++];
        if (ecc_key.privkey_size > sizeof(ecc_key.privkey_binary)) {
            LOGE("ecc_key.privkey_binary is over the buffer.");
            ret = RET_ERR_BUFFER_NOT_ENOUGH;
            goto error;
        }
        if (ecc_key.privkey_size == 0) {
            LOGE("ecc_key.privkey_binary is zero");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        memcpy(ecc_key.privkey_binary, key_block + offset, ecc_key.privkey_size);
        offset += ecc_key.privkey_size;
        hex_print_tag_debug("privkey_binary", ecc_key.privkey_binary, ecc_key.privkey_size);
        if (key_block[offset++] != 0xa0) {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        offset += key_block[offset];
        offset ++;
        if (key_block[offset++] != 0xa1) {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        offset += 4;
        ecc_key.pubkey_size = 65;
        memcpy(ecc_key.pubkey_binary, key_block + offset, ecc_key.pubkey_size);
        offset += ecc_key.pubkey_size;
        hex_print_tag_debug("pubkey_binary", ecc_key.pubkey_binary, ecc_key.pubkey_size);

        // Verifying
        if (crypto_regen_ecc_privkey(&privKey, ecc_key.privkey_binary, ecc_key.privkey_size) != CRYPTO_STATUS_SUCCESS) {
            LOGE("crypto_regen_ecc_privkey is failed");
            ret = RET_ERR_REGEN_ECC_KEY_FAIL;
            goto error;
        }
        if (crypto_regen_ecc_pubkey(&pubKey, ecc_key.pubkey_binary, ecc_key.pubkey_size) != CRYPTO_STATUS_SUCCESS) {
            LOGE("crypto_regen_ecc_privkey is failed");
            ret = RET_ERR_REGEN_ECC_KEY_FAIL;
            goto error;
        }

        if (crypto_ecdsa_sign(MD_TYPE_SHA256, privKey, testIn, sizeof(testIn), sig_r, &sig_r_len, sig_s, &sig_s_len) != CRYPTO_STATUS_SUCCESS) {
            LOGE("crypto_ecdsa_sign is failed");
            ret = RET_ERR_SIGN_FAIL;
            goto error;
        }
        hex_print_tag_debug("signature.r", sig_r, sig_s_len);
        hex_print_tag_debug("signature.s", sig_s, sig_r_len);

        if (crypto_ecdsa_verify(MD_TYPE_SHA256, pubKey, testIn, sizeof(testIn), sig_r, sig_r_len, sig_s, sig_s_len) != CRYPTO_STATUS_SUCCESS) {
            LOGE("crypto_ecdsa_verify is failed");
            ret = RET_ERR_VERIFY_FAIL;
            goto error;
        }

        // Get publik key from cert
        if (getPublicKeyFromCert(leaf_cert_block, leaf_cert_blockSize, publicKey_block, &publicKey_blockSize)) {
            LOGE("getPublicKeyFromCert is failed");
            ret = RET_ERR_VERIFY_FAIL;
            goto error;
        }
        hex_print_tag_debug("publicKey_block", publicKey_block, publicKey_blockSize);

        // Compare publickeys from cert and keyblob
        if (ecc_key.pubkey_size != publicKey_blockSize) {
            LOGE("pubkey_size size is not correct");
            ret = RET_ERR_VERIFY_FAIL;
            goto error;
        }

        for (i = 0; i < ecc_key.pubkey_size; i++) {
            if (ecc_key.pubkey_binary[i] != publicKey_block[i]) {
                LOGE("publicKey_block is not matched btw cert and keyblob");
                ret = RET_ERR_VERIFY_FAIL;
                goto error;
            }
        }
    } else if (key_type == KEY_TYPE_RSA_2048){
        // RSA 2048
        offset = 0;
        memset((uint8_t *)&rsa_key, 0, sizeof(rsa_key_t));

        if (key_block[offset] == 0x30) {
            offset += 4;
        } else {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        if (key_block[offset] == 0x02) {
            offset += 3;
        } else {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        if (key_block[offset] == 0x02) {
            offset += 1;
            if ((ret = parseTlvData(key_block + offset, key_blockSize - offset,rsa_key.modulus, sizeof(rsa_key.modulus), &(rsa_key.modulus_size))) < 0) {
                goto error;
            }
            offset += ret;
            hex_print_tag_debug("rsa_key.modulus", rsa_key.modulus, rsa_key.modulus_size);
         } else {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        if (key_block[offset] == 0x02) {
            offset += 1;
            if ((ret = parseTlvData(key_block + offset, key_blockSize - offset, rsa_key.publicExponent, sizeof(rsa_key.publicExponent), &(rsa_key.publicExponent_size))) < 0) {
                goto error;
            }
            offset += ret;
            hex_print_tag_debug("rsa_key.publicExponent", rsa_key.publicExponent, rsa_key.publicExponent_size);
         } else {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        if (key_block[offset] == 0x02) {
            offset += 1;
            if ((ret = parseTlvData(key_block + offset, key_blockSize - offset, rsa_key.privateExponent, sizeof(rsa_key.privateExponent), &(rsa_key.privateExponent_size))) < 0) {
                goto error;
            }
            offset += ret;
            hex_print_tag_debug("rsa_key.privateExponent", rsa_key.privateExponent, rsa_key.privateExponent_size);
         } else {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        if (key_block[offset] == 0x02) {
            offset += 1;
            if ((ret = parseTlvData(key_block + offset, key_blockSize - offset, rsa_key.prime1, sizeof(rsa_key.prime1), &(rsa_key.prime1_size))) < 0) {
                goto error;
            }
            offset += ret;
            hex_print_tag_debug("rsa_key.prime1", rsa_key.prime1, rsa_key.prime1_size);
         } else {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        if (key_block[offset] == 0x02) {
            offset += 1;
            if ((ret = parseTlvData(key_block + offset, key_blockSize - offset, rsa_key.prime2, sizeof(rsa_key.prime2), &(rsa_key.prime2_size))) < 0) {
                goto error;
            }
            offset += ret;
            hex_print_tag_debug("rsa_key.prime2", rsa_key.prime2, rsa_key.prime2_size);
         } else {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        if (key_block[offset] == 0x02) {
            offset += 1;
            if ((ret = parseTlvData(key_block + offset, key_blockSize - offset, rsa_key.exponent1, sizeof(rsa_key.exponent1), &(rsa_key.exponent1_size))) < 0) {
                goto error;
            }
            offset += ret;
            hex_print_tag_debug("rsa_key.exponent1", rsa_key.exponent1, rsa_key.exponent1_size);
        } else {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        if (key_block[offset] == 0x02) {
            offset += 1;
            if ((ret = parseTlvData(key_block + offset, key_blockSize - offset, rsa_key.exponent2, sizeof(rsa_key.exponent2), &(rsa_key.exponent2_size))) < 0) {
                goto error;
            }
            offset += ret;
            hex_print_tag_debug("rsa_key.exponent2", rsa_key.exponent2, rsa_key.exponent2_size);
         } else {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        if (key_block[offset] == 0x02) {
            offset += 1;
            if ((ret = parseTlvData(key_block + offset, key_blockSize - offset, rsa_key.coefficient, sizeof(rsa_key.coefficient), &(rsa_key.coefficient_size))) < 0) {
                goto error;
            }
            offset += ret;
            hex_print_tag_debug("rsa_key.coefficient", rsa_key.coefficient, rsa_key.coefficient_size);
         } else {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }

        // Verifying
        if (crypto_regen_rsa_privkey(&rsaKey, &rsa_key) != CRYPTO_STATUS_SUCCESS) {
            LOGE("crypto_regen_rsa_privkey is failed");
            ret = RET_ERR_REGEN_RSA_KEY_FAIL;
            goto error;
        }

        if (crypto_rsa_sign_pkcs(MD_TYPE_SHA256, 0, rsaKey, testIn, sizeof(testIn), sig, &sig_size) != CRYPTO_STATUS_SUCCESS) {
            LOGE("crypto_rsa_sign_pkcs is failed");
            ret = RET_ERR_SIGN_FAIL;
            goto error;
        }
        hex_print_tag_debug("sig", sig, sig_size);

        if (crypto_rsa_verify_pkcs(MD_TYPE_SHA256, 0, rsaKey, testIn, sizeof(testIn), sig, sig_size) != CRYPTO_STATUS_SUCCESS) {
            LOGE("crypto_rsa_verify_pkcs is failed");
            ret = RET_ERR_VERIFY_FAIL;
            goto error;
        }

        // Get publik key from cert
        if (getPublicKeyFromCert(leaf_cert_block, leaf_cert_blockSize, publicKey_block, &publicKey_blockSize)) {
            LOGE("getPublicKeyFromCert is failed");
            ret = RET_ERR_VERIFY_FAIL;
            goto error;
        }
        hex_print_tag_debug("publicKey_block", publicKey_block, publicKey_blockSize);

        //30 82 010A
        //02 82 0101 00D3B7650C26E4E2E34CEC369719E6D00E67552BF977C47DB8827841072E2F09CC51E260F186F1F5607716A373E766944BE2D81C8E98581FE349DA9CFBB9C30C19F5A160A0A75A8A5CE4D2736D1A2F58FE85E5BC940A075674DE8D08C1E33B93103B158A623D81469A252097B7C3961645DCC033B6F6D2FF851ED8C60C91D2E3063C7902A6373305934D10F228D6694ADA72AF78645490B335908B895B10C51DFC62BFEE065E43F00E9CD9A6709070F9766DE809D3666F51C782A55BA0BD54B6C7261202F0108CE72E6B875EF227ECE78644E35C72AABB1A164461069001879532683267F43C061B22BB078E3C138C66B3CC76FBE9406D943508212BC9B78964CF
        //02 03 010001

        // Parse rsa public key
        offset = 0;

        // Tag : 30
        if (publicKey_block[offset] != 0x30) {
            LOGE("Input data foramt is not correct");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        offset ++;
        offset += parseLenth(publicKey_block + offset, &temp_len);

        // Tag : 02 - Modulus
        if (publicKey_block[offset] != 0x02) {
            LOGE("Input data foramt is not correct");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        offset ++;
        offset += parseLenth(publicKey_block + offset, &temp_len);
        modulus_size = temp_len;
        if (modulus_size > sizeof(modulus)) {
            LOGE("modulus_size is over the buffer.");
            ret = RET_ERR_BUFFER_NOT_ENOUGH;
            goto error;
        }
        memcpy(modulus, publicKey_block + offset, modulus_size);
        hex_print_tag_debug("modulus", modulus, modulus_size);
        offset += modulus_size;

        // Tag : 02 - publicExponent
        if (publicKey_block[offset] != 0x02) {
            LOGE("Input data foramt is not correct");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        offset ++;
        offset += parseLenth(publicKey_block + offset, &temp_len);
        publicExponent_size = temp_len;
        if (publicExponent_size > sizeof(publicExponent)) {
            LOGE("modulus_size is over the buffer.");
            ret = RET_ERR_BUFFER_NOT_ENOUGH;
            goto error;
        }
        memcpy(publicExponent, publicKey_block + offset, publicExponent_size);
        hex_print_tag_debug("publicExponent", publicExponent, publicExponent_size);
        offset += publicExponent_size;

        // Compare publickeys from cert and keyblob
        if (rsa_key.modulus_size != modulus_size || rsa_key.publicExponent_size != publicExponent_size) {
            LOGE("pubkey_size size is not correct");
            ret = RET_ERR_VERIFY_FAIL;
            goto error;
        }

        for (i = 0; i < rsa_key.modulus_size; i++) {
            if (rsa_key.modulus[i] != modulus[i]) {
                LOGE("publicKey_block is not matched btw cert and keyblob");
                ret = RET_ERR_VERIFY_FAIL;
                goto error;
            }
        }

        for (i = 0; i < rsa_key.publicExponent_size; i++) {
            if (rsa_key.publicExponent[i] != publicExponent[i]) {
                LOGE("publicKey_block is not matched btw cert and keyblob");
                ret = RET_ERR_VERIFY_FAIL;
                goto error;
            }
        }
    }

    ret = RET_SUCCESS;

error:
    if (rsaKey != NULL) {
        crypto_clear_rsa_key(&rsaKey);
    }
    if (privKey != NULL) {
        crypto_clear_ecc_key(&privKey);
    }
    if (pubKey != NULL) {
        crypto_clear_ecc_key(&pubKey);
    }

    LOGD("leaKeyPairVerification end : ret = %d", ret);
    return ret;
#endif //USE_SCRYPTO
}

void injectedKeyVerification(p_cmd_t cmd, p_rsp_t rsp) {
    int32_t ret = RET_SUCCESS;

    uint8_t root_cert_id;
    uint8_t root_cert_type;

    uint8_t wrappedOutDataBlob[WRAPPED_KEY_INFO_SIZE];
    uint32_t wrappedOutDataBlobSize;

    uint8_t outDataBlob[WRAPPED_KEY_INFO_SIZE];
    uint32_t outDataBlobSize = sizeof(outDataBlob);

    uint8_t root_cert_block[MAX_CERT_SIZE];
    uint16_t root_cert_blockSize = 0;

    uint8_t sub_1_cert_block[MAX_CERT_SIZE];
    uint16_t sub_1_cert_blockSize = 0;

    uint8_t sub_2_cert_block[MAX_CERT_SIZE];
    uint16_t sub_2_cert_blockSize = 0;

    uint8_t leaf_cert_block[MAX_CERT_SIZE];
    uint16_t leaf_cert_blockSize = 0;

    uint8_t key_block[WRAPPED_KEY_INFO_SIZE];
    uint16_t key_blockSize;

    uint32_t offset;

    uint8_t key_type_in;

    ecc_key_t ecc_key;
    EC_KEY  *privKey = NULL, *pubKey = NULL;

    rsa_key_t rsa_key;
    RSA  *rsaKey = NULL;

    uint8_t key_type;

    uint8_t testIn[AP_ID_SIZE] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10};
    uint8_t sig_s[ECDSA_SIG_SIZE/2], sig_r[ECDSA_SIG_SIZE/2];
    uint32_t sig_s_len, sig_r_len;

    uint8_t sig[RSA_SIG_SIZE];
    uint32_t sig_size = RSA_SIG_SIZE;

    uint32_t inputSize;

    LOGI("injectedKeyVerification started");
    inputSize = cmd->dataLen;
    if (inputSize > WRAPPED_KEY_INFO_SIZE) {
        LOGE("Input data is over the buffer");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (inputSize == 0) {
        LOGE("cmd->data is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    // Parse input data : keyInfo, certInfo
    offset = 0;
    key_type_in = cmd->data[offset++];
    LOGD("key_type_in : %u", key_type_in);
    root_cert_id = cmd->data[offset++];
    LOGD("root_cert_id : %u", root_cert_id);
    memcpy(&wrappedOutDataBlobSize, cmd->data + offset, 4);
    offset += 4;
    if (wrappedOutDataBlobSize > sizeof(wrappedOutDataBlob)) {
        LOGE("wrappedOutDataBlob is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (wrappedOutDataBlobSize == 0) {
        LOGE("wrappedOutDataBlob is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(wrappedOutDataBlob, cmd->data + offset, wrappedOutDataBlobSize);
    offset += wrappedOutDataBlobSize;

    hex_print_tag_debug("wrappedOutDataBlob", wrappedOutDataBlob, wrappedOutDataBlobSize);
    if (unwrapInternalData(SECURE_OBJECT_TYPE_KEYBLOB, wrappedOutDataBlob, wrappedOutDataBlobSize, outDataBlob, &outDataBlobSize) != STATUS_SUCCESS) {
        ret = RET_ERR_DATA_UNWRAPPING_FAIL;
        goto error;
    }
    hex_print_tag_debug("outDataBlob", outDataBlob, outDataBlobSize);

    // Parse cert. key blob
    offset = 0;

    if (outDataBlob[offset] == 0x01) {
        // CA cert exist
        offset++;
        offset++;
        sub_1_cert_blockSize = outDataBlob[offset++];
        sub_1_cert_blockSize = sub_1_cert_blockSize << 8;
        sub_1_cert_blockSize |= outDataBlob[offset++];
        if (sub_1_cert_blockSize > sizeof(sub_1_cert_block)) {
            LOGE("sub_1_cert_block is over the buffer.");
            ret = RET_ERR_BUFFER_NOT_ENOUGH;
            goto error;
        }
        if (sub_1_cert_blockSize == 0) {
            LOGE("sub_1_cert_block is zero");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        memcpy(sub_1_cert_block, outDataBlob + offset, sub_1_cert_blockSize);
        offset += sub_1_cert_blockSize;
        hex_print_tag_debug("sub_1_cert_block", sub_1_cert_block, sub_1_cert_blockSize);

        if (outDataBlob[offset] == 0x01) {
            // Second CA cert exist
            offset++;
            offset++;
            sub_2_cert_blockSize = outDataBlob[offset++];
            sub_2_cert_blockSize = sub_2_cert_blockSize << 8;
            sub_2_cert_blockSize |= outDataBlob[offset++];
            if (sub_2_cert_blockSize > sizeof(sub_2_cert_block)) {
                LOGE("sub_2_cert_block is over the buffer.");
                ret = RET_ERR_BUFFER_NOT_ENOUGH;
                goto error;
            }
            if (sub_2_cert_blockSize == 0) {
                LOGE("sub_2_cert_block is zero");
                ret = RET_ERR_WRONG_INPUT_FORMAT;
                goto error;
            }
            memcpy(sub_2_cert_block, outDataBlob + offset, sub_2_cert_blockSize);
            offset += sub_2_cert_blockSize;
            hex_print_tag_debug("sub_2_cert_block", sub_2_cert_block, sub_2_cert_blockSize);
        }
    } else {
        LOGI("Sub CAs does not exist");
    }

    if (outDataBlob[offset++] != 0x02) {
        LOGE("Input data foramt is not correct : No leaf cert");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    // Leaf
    offset++;
    leaf_cert_blockSize = outDataBlob[offset++];
    leaf_cert_blockSize = leaf_cert_blockSize << 8;
    leaf_cert_blockSize |= outDataBlob[offset++];
    if (leaf_cert_blockSize > sizeof(leaf_cert_block)) {
        LOGE("leaf_cert_block is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (leaf_cert_blockSize == 0) {
        LOGE("leaf_cert_block is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(leaf_cert_block, outDataBlob + offset, leaf_cert_blockSize);
    offset += leaf_cert_blockSize;
    hex_print_tag_debug("leaf_cert_block", leaf_cert_block, leaf_cert_blockSize);

    if (outDataBlob[offset++] != 0x03) {
        LOGE("Input data foramt is not correct : No leaf key blob");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    key_type = outDataBlob[offset++];
    LOGD("key_type : %u", key_type);
    if (key_type_in != key_type) {
        LOGE("Key type is not machted");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    key_blockSize = outDataBlob[offset++];
    key_blockSize = key_blockSize << 8;
    key_blockSize |= outDataBlob[offset++];
    if (key_blockSize > sizeof(key_block)) {
        LOGE("key_block is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (key_blockSize == 0) {
        LOGE("key_block is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(key_block, outDataBlob + offset, key_blockSize);
    offset += key_blockSize;
    hex_print_tag_debug("key_block", key_block, key_blockSize);

    // Parse private key blob
    if (key_type == KEY_TYPE_ECC_P256) {
        // ECC P256
        offset = 5;
        if (key_block[offset++] != 0x04) {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        ecc_key.privkey_size = key_block[offset++];
        if (ecc_key.privkey_size > sizeof(ecc_key.privkey_binary)) {
            LOGE("ecc_key.privkey_binary is over the buffer.");
            ret = RET_ERR_BUFFER_NOT_ENOUGH;
            goto error;
        }
        if (ecc_key.privkey_size == 0) {
            LOGE("ecc_key.privkey_binary is zero");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        memcpy(ecc_key.privkey_binary, key_block + offset, ecc_key.privkey_size);
        offset += ecc_key.privkey_size;
        hex_print_tag_debug("privkey_binary", ecc_key.privkey_binary, ecc_key.privkey_size);
        if (key_block[offset++] != 0xa0) {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        offset += key_block[offset];
        offset ++;
        if (key_block[offset++] != 0xa1) {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        offset += 4;
        ecc_key.pubkey_size = 65;
        memcpy(ecc_key.pubkey_binary, key_block + offset, ecc_key.pubkey_size);
        //offset += ecc_key.pubkey_size;
        hex_print_tag_debug("pubkey_binary", ecc_key.pubkey_binary, ecc_key.pubkey_size);

        // Verifying
        if (crypto_regen_ecc_privkey(&privKey, ecc_key.privkey_binary, ecc_key.privkey_size) != CRYPTO_STATUS_SUCCESS) {
            LOGE("crypto_regen_ecc_privkey is failed");
            ret = RET_ERR_REGEN_ECC_KEY_FAIL;
            goto error;
        }
        if (crypto_regen_ecc_pubkey(&pubKey, ecc_key.pubkey_binary, ecc_key.pubkey_size) != CRYPTO_STATUS_SUCCESS) {
            LOGE("crypto_regen_ecc_privkey is failed");
            ret = RET_ERR_REGEN_ECC_KEY_FAIL;
            goto error;
        }

        if (crypto_ecdsa_sign(MD_TYPE_SHA256, privKey, testIn, sizeof(testIn), sig_r, &sig_r_len, sig_s, &sig_s_len) != CRYPTO_STATUS_SUCCESS) {
            LOGE("crypto_ecdsa_sign is failed");
            ret = RET_ERR_SIGN_FAIL;
            goto error;
        }
        hex_print_tag_debug("signature.r", sig_r, sig_s_len);
        hex_print_tag_debug("signature.s", sig_s, sig_r_len);

        if (crypto_ecdsa_verify(MD_TYPE_SHA256, pubKey, testIn, sizeof(testIn), sig_r, sig_r_len, sig_s, sig_s_len) != CRYPTO_STATUS_SUCCESS) {
            LOGE("crypto_ecdsa_verify is failed");
            ret = RET_ERR_VERIFY_FAIL;
            goto error;
        }
    } else if (key_type == KEY_TYPE_RSA_2048){
        // RSA 2048
        offset = 0;
        memset((uint8_t *)&rsa_key, 0, sizeof(rsa_key_t));

        if (key_block[offset] == 0x30) {
            offset += 4;
        } else {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        if (key_block[offset] == 0x02) {
            offset += 3;
        } else {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        if (key_block[offset] == 0x02) {
            offset += 1;
            if ((ret = parseTlvData(key_block + offset, key_blockSize - offset,rsa_key.modulus, sizeof(rsa_key.modulus), &(rsa_key.modulus_size))) < 0) {
                goto error;
            }
            offset += ret;
            hex_print_tag_debug("rsa_key.modulus", rsa_key.modulus, rsa_key.modulus_size);
         } else {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        if (key_block[offset] == 0x02) {
            offset += 1;
            if ((ret = parseTlvData(key_block + offset, key_blockSize - offset, rsa_key.publicExponent, sizeof(rsa_key.publicExponent), &(rsa_key.publicExponent_size))) < 0) {
                goto error;
            }
            offset += ret;
            hex_print_tag_debug("rsa_key.publicExponent", rsa_key.publicExponent, rsa_key.publicExponent_size);
         } else {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        if (key_block[offset] == 0x02) {
            offset += 1;
            if ((ret = parseTlvData(key_block + offset, key_blockSize - offset, rsa_key.privateExponent, sizeof(rsa_key.privateExponent), &(rsa_key.privateExponent_size))) < 0) {
                goto error;
            }
            offset += ret;
            hex_print_tag_debug("rsa_key.privateExponent", rsa_key.privateExponent, rsa_key.privateExponent_size);
         } else {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        if (key_block[offset] == 0x02) {
            offset += 1;
            if ((ret = parseTlvData(key_block + offset, key_blockSize - offset, rsa_key.prime1, sizeof(rsa_key.prime1), &(rsa_key.prime1_size))) < 0) {
                goto error;
            }
            offset += ret;
            hex_print_tag_debug("rsa_key.prime1", rsa_key.prime1, rsa_key.prime1_size);
         } else {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        if (key_block[offset] == 0x02) {
            offset += 1;
            if ((ret = parseTlvData(key_block + offset, key_blockSize - offset, rsa_key.prime2, sizeof(rsa_key.prime2), &(rsa_key.prime2_size))) < 0) {
                goto error;
            }
            offset += ret;
            hex_print_tag_debug("rsa_key.prime2", rsa_key.prime2, rsa_key.prime2_size);
         } else {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        if (key_block[offset] == 0x02) {
            offset += 1;
            if ((ret = parseTlvData(key_block + offset, key_blockSize - offset, rsa_key.exponent1, sizeof(rsa_key.exponent1), &(rsa_key.exponent1_size))) < 0) {
                goto error;
            }
            offset += ret;
            hex_print_tag_debug("rsa_key.exponent1", rsa_key.exponent1, rsa_key.exponent1_size);
        } else {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        if (key_block[offset] == 0x02) {
            offset += 1;
            if ((ret = parseTlvData(key_block + offset, key_blockSize - offset, rsa_key.exponent2, sizeof(rsa_key.exponent2), &(rsa_key.exponent2_size))) < 0) {
                goto error;
            }
            offset += ret;
            hex_print_tag_debug("rsa_key.exponent2", rsa_key.exponent2, rsa_key.exponent2_size);
         } else {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        if (key_block[offset] == 0x02) {
            offset += 1;
            if ((ret = parseTlvData(key_block + offset, key_blockSize - offset, rsa_key.coefficient, sizeof(rsa_key.coefficient), &(rsa_key.coefficient_size))) < 0) {
                goto error;
            }
            offset += ret;
            hex_print_tag_debug("rsa_key.coefficient", rsa_key.coefficient, rsa_key.coefficient_size);
         } else {
            LOGE("ERROR : PrivateKey tag not found");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }

        // Verifying
        if (crypto_regen_rsa_privkey(&rsaKey, &rsa_key) != CRYPTO_STATUS_SUCCESS) {
            LOGE("crypto_regen_rsa_privkey is failed");
            ret = RET_ERR_REGEN_RSA_KEY_FAIL;
            goto error;
        }

        if (crypto_rsa_sign_pkcs(MD_TYPE_SHA256, 0, rsaKey, testIn, sizeof(testIn), sig, &sig_size) != CRYPTO_STATUS_SUCCESS) {
            LOGE("crypto_rsa_sign_pkcs is failed");
            ret = RET_ERR_SIGN_FAIL;
            goto error;
        }
        hex_print_tag_debug("sig", sig, sig_size);

        if (crypto_rsa_verify_pkcs(MD_TYPE_SHA256, 0, rsaKey, testIn, sizeof(testIn), sig, sig_size) != CRYPTO_STATUS_SUCCESS) {
            LOGE("crypto_rsa_verify_pkcs is failed");
            ret = RET_ERR_VERIFY_FAIL;
            goto error;
        }

    }

    if (root_cert_id == ROOT_CERT_OCF) {
        root_cert_type = CERT_TYPE_X509;
        if (key_type == KEY_TYPE_ECC_P256) {
            root_cert_blockSize = sizeof(OCF_ROOT);
            memcpy(root_cert_block, OCF_ROOT, root_cert_blockSize);
        } else {
            LOGE("Not supported root cert id : %u, key_type : %u", root_cert_id, key_type);
            ret = RET_ERR_NOT_SUPPORT;
            goto error;
        }
    } else if (root_cert_id == ROOT_CERT_OCF_TEST) {
        root_cert_type = CERT_TYPE_X509;
        if (key_type == KEY_TYPE_ECC_P256 || key_type == KEY_TYPE_RSA_2048) {
            root_cert_blockSize = sizeof(OCF_TEST_ROOT);
            memcpy(root_cert_block, OCF_TEST_ROOT, root_cert_blockSize);
        } else {
            LOGE("Not supported root cert id : %u, key_type : %u", root_cert_id, key_type);
            ret = RET_ERR_NOT_SUPPORT;
            goto error;
        }
    } else if (root_cert_id == ROOT_CERT_DRK) {
        root_cert_type = CERT_TYPE_X509;
        if (key_type == KEY_TYPE_ECC_P256) {
            root_cert_blockSize = sizeof(DEV_ROOT_ECC256);
            memcpy(root_cert_block, DEV_ROOT_ECC256, root_cert_blockSize);
        } else if (key_type == KEY_TYPE_RSA_2048) {
            root_cert_blockSize = sizeof(DEV_ROOT_RSA2048);
            memcpy(root_cert_block, DEV_ROOT_RSA2048, root_cert_blockSize);
        } else {
            LOGE("Not supported root cert id : %u, key_type : %u", root_cert_id, key_type);
            ret = RET_ERR_NOT_SUPPORT;
            goto error;
        }
    } else if (root_cert_id == ROOT_CERT_SAMSUNG) {
        root_cert_type = CERT_TYPE_X509;
        if (key_type == KEY_TYPE_RSA_2048) {
            root_cert_blockSize = sizeof(SAMSUNG_ROOT_RSA4096);
            memcpy(root_cert_block, SAMSUNG_ROOT_RSA4096, root_cert_blockSize);
        } else {
            LOGE("Not supported root cert id : %u, key_type : %u", root_cert_id, key_type);
            ret = RET_ERR_NOT_SUPPORT;
            goto error;
        }
     } else if (root_cert_id == ROOT_CERT_SAMSUNG_TEST) {
         root_cert_type = CERT_TYPE_X509;
         if (key_type == KEY_TYPE_RSA_2048) {
             root_cert_blockSize = sizeof(SAMSUNG_TEST_ROOT_RSA4096);
             memcpy(root_cert_block, SAMSUNG_TEST_ROOT_RSA4096, root_cert_blockSize);
         } else {
             LOGE("Not supported root cert id : %u, key_type : %u", root_cert_id, key_type);
             ret = RET_ERR_NOT_SUPPORT;
             goto error;
         }
     } else if (root_cert_id == ROOT_CERT_SKPM_TEST) {
        root_cert_type = CERT_TYPE_X509;
        if (key_type == KEY_TYPE_ECC_P256) {
            root_cert_blockSize = sizeof(TEST_ROOT_ECC_P256);
            memcpy(root_cert_block, TEST_ROOT_ECC_P256, root_cert_blockSize);
        } else if (key_type == KEY_TYPE_RSA_2048) {
            root_cert_blockSize = sizeof(TEST_ROOT_RSA_2048);
            memcpy(root_cert_block, TEST_ROOT_RSA_2048, root_cert_blockSize);
        } else {
            LOGE("Not supported root cert id : %u, key_type : %u", root_cert_id, key_type);
            ret = RET_ERR_NOT_SUPPORT;
            goto error;
        }
    } else if (root_cert_id == ROOT_CERT_SCP11N_TEST) {
       root_cert_type = CERT_TYPE_RAW_PUBKEY;
       if (key_type == KEY_TYPE_ECC_P256) {
           root_cert_blockSize = sizeof(SCP11aN_QA);
           memcpy(root_cert_block, SCP11aN_QA, root_cert_blockSize);
       } else {
           LOGE("Not supported root cert id : %u, key_type : %u", root_cert_id, key_type);
           ret = RET_ERR_NOT_SUPPORT;
           goto error;
       }
    } else if (root_cert_id == ROOT_CERT_SCP11T_TEST) {
       root_cert_type = CERT_TYPE_RAW_PUBKEY;
       if (key_type == KEY_TYPE_ECC_P256) {
           root_cert_blockSize = sizeof(SCP11aT_QA);
           memcpy(root_cert_block, SCP11aT_QA, root_cert_blockSize);
       } else {
           LOGE("Not supported root cert id : %u, key_type : %u", root_cert_id, key_type);
           ret = RET_ERR_NOT_SUPPORT;
           goto error;
       }
    } else if (root_cert_id == ROOT_CERT_SCP11N) {
       root_cert_type = CERT_TYPE_RAW_PUBKEY;
       if (key_type == KEY_TYPE_ECC_P256) {
           root_cert_blockSize = sizeof(SCP11aN_PRD);
           memcpy(root_cert_block, SCP11aN_PRD, root_cert_blockSize);
       } else {
           LOGE("Not supported root cert id : %u, key_type : %u", root_cert_id, key_type);
           ret = RET_ERR_NOT_SUPPORT;
           goto error;
       }
    } else if (root_cert_id == ROOT_CERT_SCP11T) {
       root_cert_type = CERT_TYPE_RAW_PUBKEY;
       if (key_type == KEY_TYPE_ECC_P256) {
           root_cert_blockSize = sizeof(SCP11aT_PRD);
           memcpy(root_cert_block, SCP11aT_PRD, root_cert_blockSize);
       } else {
           LOGE("Not supported root cert id : %u, key_type : %u", root_cert_id, key_type);
           ret = RET_ERR_NOT_SUPPORT;
           goto error;
       }
    } else {
        LOGE("Not supported root cert id : %u", root_cert_id);
        ret = RET_ERR_NOT_SUPPORT;
        goto error;
    }

    // Certificates
    offset = 0;

    // Root cert.
    outDataBlob[offset++] = 0x00;
    // X.509
    outDataBlob[offset++] = root_cert_type;
    outDataBlob[offset++] = root_cert_blockSize >> 8;
    outDataBlob[offset++] = root_cert_blockSize;
    if (root_cert_blockSize == 0) {
        LOGE("root_cert_block is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(outDataBlob + offset, root_cert_block, root_cert_blockSize);
    offset += root_cert_blockSize;

    if (sub_1_cert_blockSize > 0) {
        if (sub_2_cert_blockSize > 0) {
            // CA sub cert. 1 & 2
            outDataBlob[offset++] = 0x01;
            if (sub_1_cert_block[0] == 0x30 && sub_1_cert_block[1] == 0x82) {
                // X.509
                outDataBlob[offset++] = 0x11;
            } else {
                // CASD
                outDataBlob[offset++] = 0x12;
            }
            outDataBlob[offset++] = sub_1_cert_blockSize >> 8;
            outDataBlob[offset++] = sub_1_cert_blockSize;
            if (sub_1_cert_blockSize == 0) {
                LOGE("sub_1_cert_block is zero");
                ret = RET_ERR_WRONG_INPUT_FORMAT;
                goto error;
            }
            memcpy(outDataBlob + offset, sub_1_cert_block, sub_1_cert_blockSize);
            offset += sub_1_cert_blockSize;
            outDataBlob[offset++] = 0x01;
            if (sub_2_cert_block[0] == 0x30 && sub_2_cert_block[1] == 0x82) {
                // X.509
                outDataBlob[offset++] = 0x21;
            } else {
                // CASD
                outDataBlob[offset++] = 0x22;
            }
            outDataBlob[offset++] = sub_2_cert_blockSize >> 8;
            outDataBlob[offset++] = sub_2_cert_blockSize;
            if (sub_2_cert_blockSize == 0) {
                LOGE("sub_2_cert_block is zero");
                ret = RET_ERR_WRONG_INPUT_FORMAT;
                goto error;
            }
            memcpy(outDataBlob + offset, sub_2_cert_block, sub_2_cert_blockSize);
            offset += sub_2_cert_blockSize;
        } else {
            // CA sub cert. 1
            outDataBlob[offset++] = 0x01;
            if (sub_1_cert_block[0] == 0x30 && sub_1_cert_block[1] == 0x82) {
                // X.509
                outDataBlob[offset++] = 0x11;
            } else {
                // CASD
                outDataBlob[offset++] = 0x12;
            }
            outDataBlob[offset++] = sub_1_cert_blockSize >> 8;
            outDataBlob[offset++] = sub_1_cert_blockSize;
            if (sub_1_cert_blockSize == 0) {
                LOGE("sub_1_cert_block is zero");
                ret = RET_ERR_WRONG_INPUT_FORMAT;
                goto error;
            }
            memcpy(outDataBlob + offset, sub_1_cert_block, sub_1_cert_blockSize);
            offset += sub_1_cert_blockSize;
        }
    }

    outDataBlob[offset++] = 0x02;
    if (leaf_cert_block[0] == 0x30 && leaf_cert_block[1] == 0x82) {
        // X.509
        outDataBlob[offset++] = CERT_TYPE_X509;
    } else {
        // CASD
        outDataBlob[offset++] = CERT_TYPE_CASD;
    }
    outDataBlob[offset++] = leaf_cert_blockSize >> 8;
    outDataBlob[offset++] = leaf_cert_blockSize;
    if (leaf_cert_blockSize == 0) {
        LOGE("leaf_cert_block is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(outDataBlob + offset, leaf_cert_block, leaf_cert_blockSize);
    offset += leaf_cert_blockSize;

    hex_print_tag_debug("outDataBlob", outDataBlob, offset);

    rsp->dataLen = offset;
    if (offset == 0) {
        LOGE("outDataBlobSize is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(rsp->data, outDataBlob, offset);

    ret = RET_SUCCESS;

error:
    if (rsaKey != NULL) {
        crypto_clear_rsa_key(&rsaKey);
    }
    if (privKey != NULL) {
        crypto_clear_ecc_key(&privKey);
    }
    if (pubKey != NULL) {
        crypto_clear_ecc_key(&pubKey);
    }

    LOGI("injectedKeyVerification end : ret = %d", ret);
    rsp->ret = ret;
}

void readInjectedKeyUID(p_cmd_t cmd, p_rsp_t rsp) {
    int32_t ret = RET_SUCCESS;

    uint8_t leafCertType;

    uint8_t wrappedOutDataBlob[WRAPPED_KEY_INFO_SIZE];
    uint32_t wrappedOutDataBlobSize;

    uint8_t outDataBlob[WRAPPED_KEY_INFO_SIZE];
    uint32_t outDataBlobSize = sizeof(outDataBlob);

    uint8_t sub_1_cert_block[MAX_CERT_SIZE];
    uint16_t sub_1_cert_blockSize = 0;

    uint8_t sub_2_cert_block[MAX_CERT_SIZE];
    uint16_t sub_2_cert_blockSize = 0;

    uint8_t leaf_cert_block[MAX_CERT_SIZE];
    uint16_t leaf_cert_blockSize = 0;

    uint32_t offset, inputSize;

    LOGI("readInjectedKeyUID started");
    inputSize = cmd->dataLen;
    if (inputSize > WRAPPED_KEY_INFO_SIZE) {
        LOGE("Input data is over the buffer");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (inputSize == 0) {
        LOGE("cmd->data is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    // Parse input data : keyInfo, certInfo
    wrappedOutDataBlobSize = inputSize;
    memcpy(wrappedOutDataBlob, cmd->data, wrappedOutDataBlobSize);

    hex_print_tag_debug("wrappedOutDataBlob", wrappedOutDataBlob, wrappedOutDataBlobSize);
    if (unwrapInternalData(SECURE_OBJECT_TYPE_KEYBLOB, wrappedOutDataBlob, wrappedOutDataBlobSize, outDataBlob, &outDataBlobSize) != STATUS_SUCCESS) {
        ret = RET_ERR_DATA_UNWRAPPING_FAIL;
        goto error;
    }
    hex_print_tag_debug("outDataBlob", outDataBlob, outDataBlobSize);

    // Parse cert. key blob
    offset = 0;

    if (outDataBlob[offset] == 0x01) {
        // CA cert exist
        offset++;
        offset++;
        sub_1_cert_blockSize = outDataBlob[offset++];
        sub_1_cert_blockSize = sub_1_cert_blockSize << 8;
        sub_1_cert_blockSize |= outDataBlob[offset++];
        if (sub_1_cert_blockSize > sizeof(sub_1_cert_block)) {
            LOGE("sub_1_cert_block is over the buffer.");
            ret = RET_ERR_BUFFER_NOT_ENOUGH;
            goto error;
        }
        if (sub_1_cert_blockSize== 0) {
            LOGE("sub_1_cert_block is zero");
            ret = RET_ERR_WRONG_INPUT_FORMAT;
            goto error;
        }
        memcpy(sub_1_cert_block, outDataBlob + offset, sub_1_cert_blockSize);
        offset += sub_1_cert_blockSize;
        hex_print_tag_debug("sub_1_cert_block", sub_1_cert_block, sub_1_cert_blockSize);

        if (outDataBlob[offset] == 0x01) {
            // Second CA cert exist
            offset++;
            offset++;
            sub_2_cert_blockSize = outDataBlob[offset++];
            sub_2_cert_blockSize = sub_2_cert_blockSize << 8;
            sub_2_cert_blockSize |= outDataBlob[offset++];
            if (sub_2_cert_blockSize > sizeof(sub_2_cert_block)) {
                LOGE("sub_2_cert_block is over the buffer.");
                ret = RET_ERR_BUFFER_NOT_ENOUGH;
                goto error;
            }
            if (sub_2_cert_blockSize== 0) {
                LOGE("sub_2_cert_block is zero");
                ret = RET_ERR_WRONG_INPUT_FORMAT;
                goto error;
            }
            memcpy(sub_2_cert_block, outDataBlob + offset, sub_2_cert_blockSize);
            offset += sub_2_cert_blockSize;
            hex_print_tag_debug("sub_2_cert_block", sub_2_cert_block, sub_2_cert_blockSize);
        }
    }

    if (outDataBlob[offset++] != 0x02) {
        LOGE("Input data foramt is not correct");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    // Leaf
    leafCertType = outDataBlob[offset++];
    leaf_cert_blockSize = outDataBlob[offset++];
    leaf_cert_blockSize = leaf_cert_blockSize << 8;
    leaf_cert_blockSize |= outDataBlob[offset++];
    if (leaf_cert_blockSize > sizeof(leaf_cert_block)) {
        LOGE("leaf_cert_block is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (leaf_cert_blockSize== 0) {
        LOGE("leaf_cert_block is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(leaf_cert_block, outDataBlob + offset, leaf_cert_blockSize);
    offset += leaf_cert_blockSize;
    hex_print_tag_debug("leaf_cert_block", leaf_cert_block, leaf_cert_blockSize);

    rsp->data[0] = leafCertType;
    memcpy(rsp->data + 1, leaf_cert_block, leaf_cert_blockSize);
    rsp->dataLen = 1 + leaf_cert_blockSize;

    ret = RET_SUCCESS;

error:
    LOGI("readInjectedKeyUID end : ret = %d", ret);
    rsp->ret = ret;
}

void injectedKeySharing(p_cmd_t cmd, p_rsp_t rsp) {
    int32_t ret = RET_SUCCESS;

    uint8_t injection_type, key_type;

    uint8_t key_name[MAX_KEY_NAME_SIZE] = "";
    uint32_t key_name_size;

    uint8_t outDataBlob[WRAPPED_KEY_INFO_SIZE];
    uint32_t outDataBlobSize = sizeof(outDataBlob);

    uint8_t wrappedOutDataBlob[WRAPPED_KEY_INFO_SIZE];
    uint32_t wrappedOutDataBlobSize;

    uint8_t wrappedKeyListInfo[WRAPPED_KEY_INFO_SIZE];
    uint32_t wrappedKeyListInfoSize;

    key_list_info_t keyListInfo[MAX_KEY_LIST_INFO];
    uint32_t keyListInfo_size = sizeof(keyListInfo);

    uint32_t offset, i, inputSize;

    LOGI("injectedKeySharing started");
    inputSize = cmd->dataLen;
    if (inputSize > WRAPPED_KEY_INFO_SIZE) {
        LOGE("Input data is over the buffer");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (inputSize == 0) {
        LOGE("cmd->data is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    offset = 0;
    injection_type = cmd->data[offset++];
    key_type = cmd->data[offset++];

    memcpy(&key_name_size, cmd->data + offset, 4);
    offset += 4;
    if (key_name_size > sizeof(key_name)) {
        LOGE("key_name is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (key_name_size == 0) {
        LOGE("key_name is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(key_name, cmd->data + offset, key_name_size);
    offset += key_name_size;

    memcpy(&wrappedOutDataBlobSize, cmd->data + offset, 4);
    offset += 4;
    if (wrappedOutDataBlobSize > sizeof(wrappedOutDataBlob)) {
        LOGE("wrappedOutDataBlob is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (wrappedOutDataBlobSize == 0) {
        LOGE("wrappedOutDataBlob is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(wrappedOutDataBlob, cmd->data + offset, wrappedOutDataBlobSize);
    offset += wrappedOutDataBlobSize;
    hex_print_tag_debug("wrappedOutDataBlob", wrappedOutDataBlob, wrappedOutDataBlobSize);
    if (unwrapInternalData(SECURE_OBJECT_TYPE_KEYBLOB, wrappedOutDataBlob, wrappedOutDataBlobSize, outDataBlob, &outDataBlobSize) != STATUS_SUCCESS) {
        ret = RET_ERR_DATA_UNWRAPPING_FAIL;
        goto error;
    }
    hex_print_tag_debug("outDataBlob", outDataBlob, outDataBlobSize);

    memcpy(&wrappedKeyListInfoSize, cmd->data + offset, 4);
    offset += 4;
    if (wrappedKeyListInfoSize > sizeof(wrappedKeyListInfo)) {
        LOGE("wrappedKeyListInfo is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (wrappedKeyListInfoSize == 0) {
        LOGE("wrappedKeyListInfo is zero");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(wrappedKeyListInfo, cmd->data + offset, wrappedKeyListInfoSize);
    offset += wrappedKeyListInfoSize;
    hex_print_tag_debug("wrappedKeyListInfo", wrappedKeyListInfo, wrappedKeyListInfoSize);
    if (unwrapInternalData(SECURE_OBJECT_TYPE_KEY_LIST, wrappedKeyListInfo, wrappedKeyListInfoSize, (uint8_t*)&keyListInfo, &keyListInfo_size) != STATUS_SUCCESS) {
        ret = RET_ERR_DATA_UNWRAPPING_FAIL;
        goto error;
    }
    hex_print_tag_debug("unwrappedKeyListInfo", (uint8_t *)keyListInfo, keyListInfo_size);
    keyListInfo_size = (keyListInfo_size / sizeof(key_list_info_t));
    LOGD("keyListInfo_size : %u", keyListInfo_size);
    if (keyListInfo_size > MAX_KEY_LIST_INFO) {
        LOGE("keyListInfo_size is over the buffer");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    for (i = 0; i < keyListInfo_size; i++) {
        if (strcmp((const char*)key_name, (const char*)keyListInfo[i].key_name) == 0
            && (injection_type == (injection_type & keyListInfo[i].injection_type))
            && (key_type == (key_type & keyListInfo[i].key_type))) {
            LOGD("List is matched, key_name : %s, injection_type : 0x%02x, key_type : 0x%02x", key_name, injection_type, key_type);
            LOGD("Machted key list info id : %u", i);
            goto matched;
        }
    }

    LOGE("Not supported, key_name : %s, injection_type : 0x%02x, key_type : 0x%02x", key_name, injection_type, key_type);
    ret = RET_ERR_NOT_SUPPORT;
    goto error;

matched:
    ret = leaKeyPairVerification(outDataBlob, outDataBlobSize);
    if (ret != RET_SUCCESS) {
        LOGE("leaKeyPairVerification is failed");
        goto error;
    }

    wrappedOutDataBlobSize = sizeof(wrappedOutDataBlob);
#ifdef USE_QSEE
    ret = wrap_secure_object(keyListInfo[i].key_id_qsee, outDataBlob, outDataBlobSize, wrappedOutDataBlob, &wrappedOutDataBlobSize);
#endif
#ifdef USE_MOBICORE
    ret = wrap_secure_object(keyListInfo[i].key_id_mobicore, outDataBlob, outDataBlobSize, wrappedOutDataBlob, &wrappedOutDataBlobSize);
#endif
#ifdef USE_BLOWFISH
    ret = wrap_secure_object(keyListInfo[i].key_id_blowfish, outDataBlob, outDataBlobSize, wrappedOutDataBlob, &wrappedOutDataBlobSize);
#endif
    if (ret == STATUS_FAILED) {
        LOGE("outDataBlob wrapping failed");
        ret = RET_ERR_DATA_WRAPPING_FAIL;
        goto error;
    }
    hex_print_tag_debug("wrappedOutDataBlob", wrappedOutDataBlob, wrappedOutDataBlobSize);
    rsp->dataLen = wrappedOutDataBlobSize;
    if (wrappedOutDataBlobSize == 0) {
        LOGE("wrappedOutDataBlobSize is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(rsp->data, wrappedOutDataBlob, wrappedOutDataBlobSize);
    ret = RET_SUCCESS;

error:
    LOGI("injectedKeySharing end : ret = %d", ret);
    rsp->ret = ret;
}

void generateLeafEccKeyPair(p_rsp_t rsp) {
    EC_KEY  *ecc_key = NULL;
    ecc_key_t keyInfo;
    int32_t ret = RET_SUCCESS;

    uint8_t wrappedKeyInfo[WRAPPED_MAX_LEAF_KEY_BLOB_SIZE];
    uint32_t wrappedKeyInfoSize = sizeof(wrappedKeyInfo);

    LOGD("generateLeafEccKeyPair started");

    if (crypto_gen_ecc_key(&ecc_key, &keyInfo) != CRYPTO_STATUS_SUCCESS) {
        LOGE("generateLeafEccKeyPair : crypto_gen_ecc_key is failed");
        ret = RET_ERR_GEN_ECC_KEY_FAIL;
        goto error;
    }

    if (wrapInternalData(SECURE_OBJECT_TYPE_ECC_KEY_INFO, (uint8_t *)&keyInfo, sizeof(ecc_key_t), wrappedKeyInfo, &wrappedKeyInfoSize) != STATUS_SUCCESS) {
        ret = RET_ERR_DATA_WRAPPING_FAIL;
        goto error;
    }

    hex_print_tag_debug("wrappedKeyInfo", wrappedKeyInfo, wrappedKeyInfoSize);

    if (wrappedKeyInfoSize > sizeof(wrappedKeyInfo)) {
        LOGE("wrappedKeyInfo is over the buffer.");
        ret = RET_ERR_SRC_BUFFER_OVERFLOW;
        goto error;
    }

    rsp->dataLen = wrappedKeyInfoSize;
    if (wrappedKeyInfoSize > sizeof(rsp->data)) {
        LOGE("rsp->data is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (wrappedKeyInfoSize == 0) {
        LOGE("wrappedKeyInfoSize is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(rsp->data, wrappedKeyInfo, wrappedKeyInfoSize);

error:
    if (ecc_key != NULL) {
        crypto_clear_ecc_key(&ecc_key);
    }

    LOGD("generateLeafEccKeyPair end : ret = %d", ret);
    rsp->ret = ret;
}

void getLeafEccPubkey(p_cmd_t cmd, p_rsp_t rsp) {
    int32_t ret = RET_SUCCESS;

    uint8_t wrappedKeyInfo[WRAPPED_MAX_LEAF_KEY_BLOB_SIZE];
    uint32_t wrappedKeyInfoSize;

    uint8_t unwrappedKeyInfo[WRAPPED_MAX_LEAF_KEY_BLOB_SIZE];
    uint32_t unwrappedKeyInfoSize = sizeof(unwrappedKeyInfo);

    ecc_key_t keyInfo;
    uint32_t inputSize;

    LOGD("getLeafEccPubkey started");
    inputSize = cmd->dataLen;
    if (inputSize > WRAPPED_MAX_LEAF_KEY_BLOB_SIZE) {
        LOGE("Input data is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (inputSize == 0) {
        LOGE("cmd->data is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    wrappedKeyInfoSize = inputSize;
    memcpy(wrappedKeyInfo, cmd->data, wrappedKeyInfoSize);
    if (unwrapInternalData(SECURE_OBJECT_TYPE_ECC_KEY_INFO, wrappedKeyInfo, wrappedKeyInfoSize, unwrappedKeyInfo, &unwrappedKeyInfoSize) != STATUS_SUCCESS) {
        ret = RET_ERR_DATA_UNWRAPPING_FAIL;
        goto error;
    }
    if (unwrappedKeyInfoSize != sizeof(ecc_key_t)) {
        LOGE("Not correct input format");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(&keyInfo, unwrappedKeyInfo, unwrappedKeyInfoSize);

    // Without uncompressed tag as 0x04
    if (keyInfo.pubkey_size != ECC_PUBKEY_SIZE) {
        LOGE("pubkey_size is correct");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    rsp->dataLen = keyInfo.pubkey_size - 1;
    memcpy(rsp->data, (keyInfo.pubkey_binary) + 1, keyInfo.pubkey_size - 1);
    hex_print_tag_debug("getLeafEccPubkey", rsp->data, keyInfo.pubkey_size - 1);

error:
    LOGD("getLeafEccPubkey end : ret = %d", ret);
    rsp->ret = ret;
}

void signWithLeafEccKey(p_cmd_t cmd, p_rsp_t rsp) {
    int32_t ret = RET_SUCCESS;

    EC_KEY *ecc_key = NULL;

    uint8_t input[MAX_SIGNATURE_INPUT_SIZE];
    uint32_t inputLen = 0;

    uint8_t signature[MAX_SIGNATURE_SIZE];
    uint32_t signatureLen = MAX_SIGNATURE_SIZE;

    uint8_t sig_r[ECDSA_SIG_SIZE / 2], sig_s[ECDSA_SIG_SIZE / 2];
    uint32_t sig_r_Len = 0, sig_s_Len = 0;

    uint8_t wrappedKeyInfo[WRAPPED_MAX_LEAF_KEY_BLOB_SIZE];
    uint32_t wrappedKeyInfoSize;

    uint8_t unwrappedKeyInfo[WRAPPED_MAX_LEAF_KEY_BLOB_SIZE];
    uint32_t unwrappedKeyInfoSize = sizeof(unwrappedKeyInfo);

    ecc_key_t keyInfo;

    uint32_t offset = 0;
    uint32_t inputSize;

    LOGD("signWithLeafEccKey started");
    inputSize = cmd->dataLen;
    if (inputSize > WRAPPED_MAX_LEAF_KEY_BLOB_SIZE) {
        LOGE("Input data is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (inputSize == 0) {
        LOGE("cmd->data is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    memcpy(&wrappedKeyInfoSize, cmd->data + offset, 4);
    offset += 4;
    if (wrappedKeyInfoSize > sizeof(wrappedKeyInfo)) {
        LOGE("wrappedKeyInfo is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (wrappedKeyInfoSize == 0) {
        LOGE("wrappedKeyInfo is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    memcpy(wrappedKeyInfo, cmd->data + offset, wrappedKeyInfoSize);
    offset += wrappedKeyInfoSize;
    memcpy(&inputLen, cmd->data + offset, 4);
    offset += 4;
    if (inputLen > sizeof(input)) {
        LOGE("input is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (inputLen == 0) {
        LOGE("input is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    memcpy(input, cmd->data + offset, inputLen);
    offset += inputLen;

    hex_print_tag_debug("input", input, offset);

    if (unwrapInternalData(SECURE_OBJECT_TYPE_ECC_KEY_INFO, wrappedKeyInfo, wrappedKeyInfoSize, unwrappedKeyInfo, &unwrappedKeyInfoSize) != STATUS_SUCCESS) {
        ret = RET_ERR_DATA_UNWRAPPING_FAIL;
        goto error;
    }
    if (unwrappedKeyInfoSize != sizeof(ecc_key_t)) {
        LOGE("Not correct input format");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(&keyInfo, unwrappedKeyInfo, unwrappedKeyInfoSize);
    if (keyInfo.privkey_size != ECC_PRIVKEY_SIZE && keyInfo.privkey_size != ECC_PRIVKEY_SIZE - 1) {
        LOGE("privkey_binary is not correct");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    LOGD("Sign with Leaf ECC");
    hex_print_tag_debug("keyInfo.privkey_binary", keyInfo.privkey_binary, keyInfo.privkey_size);
    if (crypto_regen_ecc_privkey(&ecc_key, keyInfo.privkey_binary, keyInfo.privkey_size) != CRYPTO_STATUS_SUCCESS) {
        LOGE("signWithLeafEccKey : crypto_regen_ecc_privkey is failed");
        ret = RET_ERR_REGEN_ECC_KEY_FAIL;
        goto error;
    }

    if (crypto_ecdsa_sign(MD_TYPE_NONE, ecc_key, input, inputLen, sig_r, &sig_r_Len, sig_s, &sig_s_Len) != CRYPTO_STATUS_SUCCESS) {
        LOGE("signWithLeafEccKey : crypto_ecdsa_sign is failed");
        ret = RET_ERR_SIGN_FAIL;
        goto error;
    }
    rebuildAsn1FromRawSigWithEcc(sig_r, sig_r_Len, sig_s, sig_s_Len, signature, &signatureLen);

    hex_print_tag_debug("signature", signature, signatureLen);
    rsp->dataLen = signatureLen;
    if (signatureLen == 0) {
        LOGE("signatureLen is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(rsp->data, signature, signatureLen);

error:
    if (ecc_key != NULL) {
        crypto_clear_ecc_key(&ecc_key);
    }

    LOGD("signWithLeafEccKey end : ret = %d", ret);
    rsp->ret = ret;
}

void generateLeafRsaKeyPair(p_rsp_t rsp) {
    RSA  *rsa_key = NULL;
    rsa_key_t keyInfo;
    int32_t ret = RET_SUCCESS;

    uint8_t wrappedKeyInfo[WRAPPED_MAX_LEAF_KEY_BLOB_SIZE];
    uint32_t wrappedKeyInfoSize = sizeof(wrappedKeyInfo);

    LOGD("generateLeafRsaKeyPair started");

    if (crypto_gen_rsa_key(&rsa_key, &keyInfo) != CRYPTO_STATUS_SUCCESS) {
        LOGE("generateLeafRsaKeyPair : crypto_gen_rsa_key is failed");
        ret = RET_ERR_GEN_RSA_KEY_FAIL;
        goto error;
    }

    if (wrapInternalData(SECURE_OBJECT_TYPE_RSA_KEY_INFO, (uint8_t *)&keyInfo, sizeof(rsa_key_t), wrappedKeyInfo, &wrappedKeyInfoSize) != STATUS_SUCCESS) {
        ret = RET_ERR_DATA_WRAPPING_FAIL;
        goto error;
    }

    LOGD("wrappedKeyInfoSize : %u", wrappedKeyInfoSize);
    rsp->dataLen = wrappedKeyInfoSize;
    if (wrappedKeyInfoSize == 0) {
        LOGE("wrappedKeyInfoSize is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(rsp->data, wrappedKeyInfo, wrappedKeyInfoSize);

error:
    if (rsa_key != NULL) {
        crypto_clear_rsa_key(&rsa_key);
    }

    LOGD("generateLeafRsaKeyPair end : ret = %d", ret);
    rsp->ret = ret;
}

void getLeafRsaPubkey(p_cmd_t cmd, p_rsp_t rsp) {
    int32_t ret = RET_SUCCESS;

    uint8_t wrappedKeyInfo[WRAPPED_MAX_LEAF_KEY_BLOB_SIZE];
    uint32_t wrappedKeyInfoSize;

    uint8_t unwrappedKeyInfo[WRAPPED_MAX_LEAF_KEY_BLOB_SIZE];
    uint32_t unwrappedKeyInfoSize = sizeof(unwrappedKeyInfo);

    rsa_key_t keyInfo;

    LOGD("getLeafRsaPubkey started");
    wrappedKeyInfoSize = cmd->dataLen;
    if (wrappedKeyInfoSize > WRAPPED_MAX_LEAF_KEY_BLOB_SIZE) {
        LOGE("Input data is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (wrappedKeyInfoSize == 0) {
        LOGE("cmd->data is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    memcpy(wrappedKeyInfo, cmd->data, wrappedKeyInfoSize);
    if (unwrapInternalData(SECURE_OBJECT_TYPE_RSA_KEY_INFO, wrappedKeyInfo, wrappedKeyInfoSize, unwrappedKeyInfo, &unwrappedKeyInfoSize) != STATUS_SUCCESS) {
        ret = RET_ERR_DATA_UNWRAPPING_FAIL;
        goto error;
    }
    if (unwrappedKeyInfoSize != sizeof(rsa_key_t)) {
        LOGE("Not correct input format");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(&keyInfo, unwrappedKeyInfo, unwrappedKeyInfoSize);

    rsp->dataLen = keyInfo.modulus_size;
    if (keyInfo.modulus_size != RSA_KEY_COMPONENT_SIZE) {
        LOGE("modulus_size is not correct");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    memcpy(rsp->data, keyInfo.modulus, keyInfo.modulus_size);
    hex_print_tag_debug("getLeafRsaPubkey", rsp->data, keyInfo.modulus_size);

error:
    LOGD("getLeafRsaPubkey end : ret = %d", ret);
    rsp->ret = ret;
}

void signWithLeafRsaKey(p_cmd_t cmd, p_rsp_t rsp) {
    int32_t ret = RET_SUCCESS;

    RSA *rsa_key = NULL;

    uint8_t input[MAX_SIGNATURE_INPUT_SIZE];
    uint32_t inputLen = 0;

    uint8_t signature[MAX_SIGNATURE_SIZE];
    uint32_t signatureLen = MAX_SIGNATURE_SIZE;

    uint8_t wrappedKeyInfo[WRAPPED_MAX_LEAF_KEY_BLOB_SIZE];
    uint32_t wrappedKeyInfoSize;

    uint8_t unwrappedKeyInfo[WRAPPED_MAX_LEAF_KEY_BLOB_SIZE];
    uint32_t unwrappedKeyInfoSize = sizeof(unwrappedKeyInfo);

    rsa_key_t keyInfo;

    uint32_t offset = 0;
    uint32_t inputSize;

    LOGD("signWithLeafRsaKey started");
    inputSize = cmd->dataLen;
    if (inputSize > WRAPPED_MAX_LEAF_KEY_BLOB_SIZE) {
        LOGE("Input data is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (inputSize == 0) {
        LOGE("cmd->data is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    memcpy(&wrappedKeyInfoSize, cmd->data + offset, 4);
    offset += 4;
    if (wrappedKeyInfoSize > sizeof(wrappedKeyInfo)) {
        LOGE("wrappedKeyInfo is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (wrappedKeyInfoSize == 0) {
        LOGE("wrappedKeyInfo is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(wrappedKeyInfo, cmd->data + offset, wrappedKeyInfoSize);
    offset += wrappedKeyInfoSize;
    memcpy(&inputLen, cmd->data + offset, 4);
    offset += 4;
    if (inputLen > sizeof(input)) {
        LOGE("input is over the buffer.");
        ret = RET_ERR_BUFFER_NOT_ENOUGH;
        goto error;
    }
    if (inputLen == 0) {
        LOGE("input is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(input, cmd->data + offset, inputLen);
    offset += inputLen;

    hex_print_tag_debug("input", input, offset);

    if (unwrapInternalData(SECURE_OBJECT_TYPE_RSA_KEY_INFO, wrappedKeyInfo, wrappedKeyInfoSize, unwrappedKeyInfo, &unwrappedKeyInfoSize) != STATUS_SUCCESS) {
        ret = RET_ERR_DATA_UNWRAPPING_FAIL;
        goto error;
    }

    if (unwrappedKeyInfoSize != sizeof(rsa_key_t)) {
        LOGE("Not correct input format");
        ret = RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(&keyInfo, unwrappedKeyInfo, unwrappedKeyInfoSize);

    if (keyInfo.privateExponent_size != RSA_KEY_COMPONENT_SIZE && keyInfo.privateExponent_size != RSA_KEY_COMPONENT_SIZE - 1) {
        LOGE("privateExponent_size is not correct");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }

    LOGD("Sign with Leaf RSA");
    if (crypto_regen_rsa_privkey(&rsa_key, &keyInfo) != CRYPTO_STATUS_SUCCESS) {
        LOGE("signWithLeafRsaKey : crypto_regen_rsa_privkey is failed");
        ret = RET_ERR_REGEN_RSA_KEY_FAIL;
        goto error;
    }

    if (crypto_rsa_sign_pkcs(MD_TYPE_SHA256, 1, rsa_key, input, inputLen, signature, &signatureLen) != CRYPTO_STATUS_SUCCESS) {
        LOGE("signWithLeafRsaKey : crypto_rsa_sign_pkcs is failed");
        ret = RET_ERR_SIGN_FAIL;
        goto error;
    }
    hex_print_tag_debug("signature", signature, signatureLen);
    rsp->dataLen = signatureLen;
    if (signatureLen == 0) {
        LOGE("signatureLen is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(rsp->data, signature, signatureLen);

error:
    if (rsa_key != NULL) {
        crypto_clear_rsa_key(&rsa_key);
    }

    LOGD("signWithLeafRsaKey end : ret = %d", ret);
    rsp->ret = ret;
}

void readBoardName(p_rsp_t rsp) {
    int32_t ret = RET_SUCCESS;
    char boardName[255] = {0, };
#ifdef TZ_CHIPSET
    char tz_chipset[] = TZ_CHIPSET;
    char *parsed_tz_chipset;
#endif

    LOGI("readBoardName started");

#ifdef TZ_CHIPSET
    LOGD("tz_chipset : %s, len : %d", tz_chipset, strlen(tz_chipset));
    parsed_tz_chipset = strtok(tz_chipset, "_");
    if (parsed_tz_chipset != NULL) {
        LOGD("parsed_tz_chipset : %s, len : %d", parsed_tz_chipset, strlen(parsed_tz_chipset));
        if (strncmp(parsed_tz_chipset, "exynos", 5) == 0) {
            strcat(boardName, "universal");
            strcat(boardName, parsed_tz_chipset + 6);
#ifdef TIZEN
            strcat(boardName, "_tizen");
#endif
        } else if (strncmp(parsed_tz_chipset, "sm7150", 6) == 0) {
            strcat(boardName, "sm6150");
        } else {
            strcat(boardName, parsed_tz_chipset);
        }
    } else {
        ret = RET_ERR_TZ;
    }
#else
    LOGD("TZ_CHIPSET is not set");

    ret = RET_ERR_TZ;
#endif
    LOGD("boardName : %s, len : %d", boardName, strlen(boardName));

    if (ret == RET_SUCCESS) {
        rsp->dataLen = strlen(boardName);
        memcpy(rsp->data, boardName, rsp->dataLen);
    }

    LOGI("readBoardName end : ret = %d", ret);
    rsp->ret = ret;
}

#ifdef SUPPORT_GUARDIAN_M
void guardianmGetTlsSessionInfo(p_rsp_t rsp) {
    int32_t ret = RET_SUCCESS;

    uint8_t wrappedKeyInfo[WRAPPED_KEY_INFO_SIZE];
    uint32_t wrappedKeyInfoSize = sizeof(wrappedKeyInfo);

    uint32_t current_pos = 0;

    LOGD("guardianmGetTlsSessionInfo started");

    memset((uint8_t *)&sOtaTlsSession, 0, sizeof(tls_session_info_t));
    // Add gaurdian m flag
    sOtaTlsSession.isGuardianM = 1;

    if (wrapInternalData(SECURE_OBJECT_TYPE_TLS_SESSION_INFO, (uint8_t *)&sOtaTlsSession, sizeof(tls_session_info_t), wrappedKeyInfo, &wrappedKeyInfoSize) != STATUS_SUCCESS) {
        ret = RET_ERR_DATA_WRAPPING_FAIL;
        goto error;
    }

    memcpy(rsp->data + current_pos, &wrappedKeyInfoSize, 4);
    current_pos += 4;
    if (wrappedKeyInfoSize == 0) {
        LOGE("wrappedKeyInfo is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(rsp->data + current_pos, wrappedKeyInfo, wrappedKeyInfoSize);
    current_pos += wrappedKeyInfoSize;

    rsp->dataLen = current_pos;
    ret = RET_SUCCESS;

error:
    LOGD("guardianmGetTlsSessionInfo end : ret = %d", ret);

    rsp->ret = ret;
}

void guardianmGetCertificates(p_rsp_t rsp) {
    int32_t ret = RET_SUCCESS;
    GRDM_RESULT grdm_ret;

    uint32_t offset = 0;

    uint8_t guardianMSubCert[MAX_CERT_SIZE];
    uint32_t guardianMSubCertLen = sizeof(guardianMSubCert);

    uint8_t guardianMCert[MAX_CERT_SIZE];
    uint32_t guardianMCertLen = sizeof(guardianMCert);

    LOGD("guardianmGetCertificates started");

    grdm_ret = grdm_openLogicalChannel();
    if (grdm_ret != GRDM_NO_ERROR) {
        LOGE("grdm_openLogicalChannel is failed");
        ret = RET_ERR_GRDM_OPERATION;
        goto error;
    }

    grdm_ret = grdm_getAttesCertificate(ATTESTATION_SUBCA, guardianMSubCert, &guardianMSubCertLen);
    if (grdm_ret != GRDM_NO_ERROR) {
        LOGE("grdm_getAttesCertificate (ATTESTATION_SUBCA) is failed");
        ret = RET_ERR_GRDM_OPERATION;
        goto error;
    }
    hex_print_tag_debug("ATTESTATION_SUBCA", guardianMSubCert, guardianMSubCertLen);

    grdm_ret = grdm_getAttesCertificate(ATTESTATION_ENDENTITY, guardianMCert, &guardianMCertLen);
    if (grdm_ret != GRDM_NO_ERROR) {
        LOGE("grdm_openLogicalChannel (ATTESTATION_ENDENTITY) is failed");
        ret = RET_ERR_GRDM_OPERATION;
        goto error;
    }
    hex_print_tag_debug("ATTESTATION_ENDENTITY", guardianMCert, guardianMCertLen);

    grdm_ret = grdm_closeLogicalChannel();
    if (grdm_ret != GRDM_NO_ERROR) {
        LOGE("grdm_closeLogicalChannel is failed");
    }

    memcpy(rsp->data + offset, &guardianMSubCertLen, 4);
    offset += 4;
    if (guardianMSubCertLen == 0) {
        LOGE("guardianMSubCertLen is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(rsp->data + offset, guardianMSubCert, guardianMSubCertLen);
    offset += guardianMSubCertLen;

    memcpy(rsp->data + offset, &guardianMCertLen, 4);
    offset += 4;
    if (guardianMCertLen == 0) {
        LOGE("guardianMCertLen is zero");
        ret =  RET_ERR_WRONG_INPUT_FORMAT;
        goto error;
    }
    memcpy(rsp->data + offset, guardianMCert, guardianMCertLen);
    offset += guardianMCertLen;

    rsp->dataLen = offset;

error:
    LOGD("guardianmGetCertificates end : ret = %d", ret);
    rsp->ret = ret;
}

uint16_t guardianmSignWithClientKey(uint8_t md_type, uint8_t *in, uint32_t inLen,
        uint8_t *sigAsn1Encoded, uint32_t *sigAsn1EncodedLen) {
    int32_t ret = RET_SUCCESS;
    GRDM_RESULT grdm_ret;

    LOGI("guardianmSignWithClientKey");

    hex_print_tag_debug("input", in, inLen);

    grdm_ret = grdm_openLogicalChannel();
    if (grdm_ret != GRDM_NO_ERROR) {
        LOGE("grdm_openLogicalChannel is failed");
        ret = RET_ERR_GRDM_OPERATION;
        goto error;
    }

    grdm_ret = grdm_ecdsa_AttesKey(ATTESTATION_ENDENTITY, in, inLen, sigAsn1Encoded, sigAsn1EncodedLen);
    if (grdm_ret != GRDM_NO_ERROR) {
        LOGE("grdm_getAttesSignature is failed");
        ret = RET_ERR_GRDM_OPERATION;
        goto error;
    }
    hex_print_tag_debug("sigAsn1Encoded", sigAsn1Encoded, *sigAsn1EncodedLen);

    grdm_ret = grdm_closeLogicalChannel();
    if (grdm_ret != GRDM_NO_ERROR) {
        LOGE("grdm_closeLogicalChannel is failed");
    }

    ret = CRYPTO_STATUS_SUCCESS;

error:
    LOGD("guardianmSignWithClientKey end : ret = %d", ret);
    return ret;
}
#endif
