/*
 * =====================================================================================
 *
 *       Filename:  cryptoPlatform.c
 *
 *    Description:  Execute cryptograpical operation.
 *
 *        Version:  1.0
 *        Created:  03/28/2017 04:45:34 PM
 *       Compiler:  armcc
 *
 *         Author:  Dongwook Shim (), dw.shim@samsung.com
 *        Company:  Samsung Electronics
 *
 *        Copyright (c) 2017 by Samsung Electronics, All rights reserved.
 *
 * =====================================================================================
 */

#include <stdint.h>
#include <string.h>

#include "CommLayerData.h"
#include "commonConfig.h"
#include "ServiceName.h"
#include "certGenerator.h"
#include "certParser.h"
#include "x509v3.h"
#include "keyManager.h"
#include "cryptoEngine.h" // for KeyGenInfo only
#include "cryptoPlatform.h"
#include "teeCryptoApi.h"
#include "log.h"
#include "sha/sha.h"
#include "objects/obj_mac.h"
#include "TLV.h"
#include "PlatformConfig.h"

#if (defined USE_QSEE_SFS)
#include "systemConfig.h"
#include "PlatformConfig.h"

#define DRK_KEY_PATH          COMMON_DIR/"prov_data/dev_root.dat"
#endif  // End of USE_QSEE_SFS

#if defined(DRKFEATURE_HWVAULT_ENABLE)
#include "HwVaultHal_api.h"
#endif

static uint8_t gGenRsaKeyPair[MAX_RSA_LEN];
static uint32_t gGenRsaKeyPairLen = 0;

static int32_t parseDeviceKeys(const uint8_t *plain, const uint32_t plainLen,
        uint8_t *cert, uint32_t *certLen, uint8_t *privKey, uint32_t *privKeyLen)
{
    Tlv_t *pTlv = (Tlv_t *)plain;
    uint32_t temp_certLen = 0;
    if(plain == NULL || plainLen < TAGLENGTH_FIELD_SIZE || cert == NULL || certLen == NULL ||
            privKey == NULL || privKeyLen == NULL)
    {
        LOGE("%s : Invalid agrument.", __func__);
        return ERR_TA_INVALID_ARGUMENT;
    }

    if(pTlv->tag != KEYBLOB_TAG_CERT)
    {
        LOGE("Wrong tag field of certificate, tag = %d", pTlv->tag);
        return ERR_TA_INVALID_BLOB;
    }

    if(pTlv->dataLen == 0 || pTlv->dataLen > MAX_CERT_LEN ||
            TAGLENGTH_FIELD_SIZE + pTlv->dataLen > plainLen)
    {
        LOGE("Invalid certificate size : %d.", pTlv->dataLen);
        return ERR_TA_INVALID_KEY_LENGTH;
    }

    temp_certLen = GET_UINT16_BIG(pTlv->data, 2);
    temp_certLen += 4; // Tag(1), Len(3)
    if (pTlv->dataLen >= temp_certLen) {
        *certLen = temp_certLen;
    } else {
        *certLen = pTlv->dataLen;
    }
    LOGI("%s : before Len - %d, after certLen - %d ", __func__, pTlv->dataLen, *certLen);
    memcpy(cert, pTlv->data, *certLen);

    pTlv = (Tlv_t *)(pTlv->data + pTlv->dataLen);

    if(pTlv->tag != KEYBLOB_TAG_PRIVATE_KEY)
    {
        LOGE("Wrong tag field of private key, tag = %d", pTlv->tag);
        return ERR_TA_INVALID_BLOB;
    }

    if(pTlv->dataLen == 0 || pTlv->dataLen > MAX_KEY_LEN ||
            TAGLENGTH_FIELD_SIZE * 2 + pTlv->dataLen + *certLen > plainLen)
    {
        LOGE("Invalid private keysize : %d.", pTlv->dataLen);
        return ERR_TA_INVALID_KEY_LENGTH;
    }

    memcpy(privKey, pTlv->data, pTlv->dataLen);
    *privKeyLen = pTlv->dataLen;

    return NOT_ERROR;
}

static int32_t getDeviceRootKey(const uint8_t *wrappedData, uint32_t wrappedDataLen,
        uint8_t *privKey, uint32_t *privKeyLen, uint8_t *cert, uint32_t *certLen)
{
    int ret = NOT_ERROR;
    uint8_t plainBuf[MAX_SKM_BUF_SIZE];
    uint32_t plainBufLen = sizeof(plainBuf);
#if !(defined USE_QSEE) || (defined USE_QSEE_PROV_SFS)
    const uint8_t TID[] = TID_PROV;
#endif  // End of !USE_QSEE || USE_QSEE_PROV_SFS

    if(wrappedData == NULL || privKey == NULL || privKeyLen == NULL || cert == NULL || certLen == NULL)
    {
        LOGE("%s : Invalid agrument.", __func__);
        return ERR_TA_INVALID_ARGUMENT;
    }

    if(wrappedDataLen > plainBufLen)
    {
        LOGE("Wrapped data is too big. %d %d.", wrappedDataLen, plainBufLen);
        return ERR_TA_BUFFER_OVERFLOW;
    }

    memset(plainBuf, 0, sizeof(plainBuf));

#if (defined USE_QSEE) && !(defined USE_QSEE_PROV_SFS)
#if (defined USE_QSEE_SFS)
    memcpy((char *)wrappedData, DRK_KEY_PATH, strlen(DRK_KEY_PATH));
    wrappedDataLen = strlen(DRK_KEY_PATH);
#endif  // End of USE_QSEE_SFS
    if((ret = openLocalSecureObject(wrappedData, wrappedDataLen, plainBuf, &plainBufLen)) != NOT_ERROR)
#else
    if((ret = openSecureObject(wrappedData, wrappedDataLen, plainBuf, &plainBufLen,
                    TID, sizeof(TID))) != NOT_ERROR)
#endif  // End of USE_QSEE && !USE_PROV_SFS
    {
        LOGE("Failed to unwrap DRK error %d.", ret);
        return ret;
    }

    ret = parseDeviceKeys(plainBuf, plainBufLen, cert, certLen, privKey, privKeyLen);

    memset(plainBuf, 0, sizeof(plainBuf));

    if(ret != NOT_ERROR)
        LOGE("Failed to parse DRK blob with error %d.", ret);

    return ret;
}

static int32_t populateKeyExt(uint8_t *pubKey,  uint32_t pubKeyLen, uint8_t *privKey, uint32_t privKeyLen,
        KEY **pKey, struct x509_certificate *cert)
{
    int32_t ret = NOT_ERROR;

    LOGI("%s start...", __func__);

    if(pubKey == NULL || privKey == NULL || pKey == NULL || cert == NULL)
    {
        LOGE("%s : Invalid argument.", __func__);
        return ERR_TA_INVALID_ARGUMENT;
    }

    if((ret = x509_certificate_parse(pubKey, pubKeyLen, cert)) != X509_PARSE_OK)
    {
        ret += ERR_TA_X509_PARSE_BASE;
        LOGE("Failed to parse X.509 certificate with error .%d", ret);
        goto cleanup;
    }

    if(*pKey == NULL)
        *pKey = KEY_new(getCertPublicKeyType(cert));

    if(*pKey == NULL)
    {
        LOGE("Failed to allocate key.");
        ret = ERR_TA_NOT_ENOUGH_MEMORY;
        goto cleanup;
    }

    if((ret = KEY_populate_keys(*pKey, cert->subject_public_key, cert->subject_public_key_len, privKey, privKeyLen)) != NOT_ERROR)
        LOGE("Failed to populate key with error %d.", ret);

cleanup:
    LOGI("%s end...", __func__);

    return ret;
}

static int32_t verifyKeyPair(uint8_t *pubKey,  uint32_t pubKeyLen, uint8_t *privKey, uint32_t privKeyLen)
{
    int32_t ret = NOT_ERROR;
    KEY *key = NULL;
    struct x509_certificate cert;

    LOGI("%s start...", __func__);

    if(pubKey == NULL || privKey == NULL)
    {
        LOGE("%s : Invalid argument.", __func__);
        return ERR_TA_INVALID_ARGUMENT;
    }

    memset(&cert, 0, sizeof(cert));

    if((ret = populateKeyExt(pubKey, pubKeyLen, privKey, privKeyLen, &key, &cert)) != NOT_ERROR)
    {
        LOGE("Failed to populate key with error %d.", ret);
        goto cleanup;
    }

    if((ret = KEY_check_keypair(key)) != NOT_ERROR)
        LOGE("Failed to check key pair with error %d.", ret);

cleanup:
    if(key)
        KEY_free(key);

    LOGI("%s end...", __func__);

    return ret;
}

int32_t verifyDeviceRootKey(void *wrappedBlob, uint32_t wrappedBlobLen, uint8_t * outDevInfo , uint32_t *outDevInfoLen)
{
    int32_t ret = NOT_ERROR;
    uint8_t drkCert[MAX_CERT_LEN], drkPrivKey[MAX_KEY_LEN];
    uint32_t drkCertLen = sizeof(drkCert), drkPrivKeyLen = sizeof(drkPrivKey);

    LOGI("%s start...", __func__);

    if(outDevInfo == NULL || outDevInfoLen == NULL || wrappedBlob == NULL || wrappedBlobLen == 0)
    {
        LOGE("%s : Invalid argument.", __func__);
        return ERR_TA_INVALID_ARGUMENT;
    }

    memset(drkCert, 0, sizeof(drkCert));
    memset(drkPrivKey, 0, sizeof(drkPrivKey));

    if((ret = getDeviceRootKey(wrappedBlob, wrappedBlobLen, drkPrivKey, &drkPrivKeyLen, drkCert, &drkCertLen)) != NOT_ERROR)
        goto cleanup;

    if((ret = verifyCertificateWithCA(drkCert, drkCertLen, NULL)) != NOT_ERROR)
    {
        LOGE("Failed to verify DRK cert with error %d.", ret);
        goto cleanup;
    }

    if((ret = verifyKeyPair(drkCert, drkCertLen, drkPrivKey, drkPrivKeyLen)) != NOT_ERROR)
    {
        LOGE("Failed to verify DRK key pair with error %d.", ret);
        goto cleanup;
    }

    if((ret = parseCert(drkCert, drkCertLen, outDevInfo, outDevInfoLen)) != NOT_ERROR)
    {
        LOGE("Failed to parseCert with error %d : ", ret);
        goto cleanup;
    }
cleanup:
    memset(drkPrivKey, 0, sizeof(drkPrivKey));
    LOGI("%s end...", __func__);

    return ret;
}

static int32_t verifyServiceKeyInfo(ServiceKeyInfo_t * serviceKeyInfo)
{
    if(serviceKeyInfo == NULL)
    {
        LOGE("%s : Invalid argument.", __func__);
        return ERR_TA_INVALID_ARGUMENT;
    }

    if(!isServiceNameRegistered(serviceKeyInfo->serviceName))
    {
        LOGE("%s is not registered SKM..", serviceKeyInfo->serviceName);
        return ERR_TA_PERMISSION_DENIED;
    }

    switch(serviceKeyInfo->keyLength)
    {
        case 0 :
            if(serviceKeyInfo->keyType == KEY_TYPE_EC)
                serviceKeyInfo->keyLength = EC_BIT_SIZE_DEFAULT;
            else
                serviceKeyInfo->keyLength = RSA_BIT_SIZE_DEFAULT;
            break;

        case RSA_BIT_SIZE_DEFAULT :
        case EC_BIT_SIZE_DEFAULT :
            break;

        case RSA_BIT_SIZE_MASTER_CARD :
            // Only master card can be set this length - requested by b.venkataram in MPS Lab-B2B Engineering
            if(strncmp(serviceKeyInfo->serviceName, MC_PAY_SERV_NAME,
                        strlen(serviceKeyInfo->serviceName) < strlen(MC_PAY_SERV_NAME) ?
                        strlen(MC_PAY_SERV_NAME) : strlen(serviceKeyInfo->serviceName)))
            {
                LOGE("Not allowed service key length : %d.", serviceKeyInfo->keyLength);
                return ERR_TA_INVALID_KEY_LENGTH;
            }
            break;

        default :
            LOGE("Not allowed service key length : %d.", serviceKeyInfo->keyLength);
            return ERR_TA_INVALID_KEY_LENGTH;
    }

    return NOT_ERROR;
}

static int32_t generateServiceKeyBlob(const uint8_t *drkBlob, const uint32_t drkBlobLen,
        uint8_t *serviceBlob, uint32_t *serviceBlobLen, ServiceKeyInfo_t *serviceKeyInfo,
        const uint8_t *attrs, const uint32_t attrsLen)
{
    int32_t ret = NOT_ERROR;
    uint8_t plainBlob[MAX_SKM_BUF_SIZE], targetTid[MAX_TID_SIZE];
    uint8_t drkCert[MAX_CERT_LEN], serviceCert[MAX_CERT_LEN], privKey[MAX_KEY_LEN];
    uint32_t plainBlobLen = sizeof(plainBlob), targetTidLen = sizeof(targetTid);
    uint32_t drkCertLen = sizeof(drkCert), serviceCertLen = sizeof(serviceCert), privKeyLen = sizeof(privKey);
    uint32_t keyType = 0;
    struct x509_certificate issuer;
    struct KeyGenInfo genInfo;
    KEY *drkKey = NULL, *serviceKey = NULL;
    Tlv_t *pTlv = (Tlv_t *)plainBlob;

    LOGI("%s start...", __func__);

    if(drkBlob == NULL || drkBlobLen == 0 || serviceBlob == NULL || serviceBlobLen == NULL || serviceKeyInfo == NULL)
    {
        LOGE("%s : Invalid argument.", __func__);
        return ERR_TA_INVALID_ARGUMENT;
    }

    if((ret = verifyServiceKeyInfo(serviceKeyInfo)) != NOT_ERROR)
    {
        LOGE("Invalid service key infomation with error %d.", ret);
        return ret;
    }

    memset(targetTid, 0, sizeof(targetTid));

    if((ret = getTidByServiceName(serviceKeyInfo->serviceName, (char *)targetTid, &targetTidLen)) != NOT_ERROR)
    {
        LOGE("Failed to get TID of service(%s). It seems not be registered in SKM.", serviceKeyInfo->serviceName);
        return ret;
    }

    if(attrs != NULL)
    {
        if((ret = parseSubstituteAttrs(attrs, attrsLen)) != NOT_ERROR)
        {
            LOGE("Failed to parse attrs with error %d.", ret);
            return ret;
        }
    }

    memset(drkCert, 0, sizeof(drkCert));
    memset(privKey, 0, sizeof(privKey));

    //  Read device root key (DRK).
    if ((ret = getDeviceRootKey(drkBlob, drkBlobLen, privKey, &privKeyLen, drkCert, &drkCertLen)) != NOT_ERROR) {
        LOGE("Failed to get device root key with error %d.", ret);
        return ret;
    }

    // Check DRK certificate on Samsung CA certificate.
    if((ret = verifyCertificateWithCA(drkCert, drkCertLen, NULL)) != NOT_ERROR)
    {
        LOGE("Failed to verify device root key with error %d.", ret);
        goto cleanup;
    }

    memset(&issuer, 0, sizeof(issuer));

    // Setup RSA struct for DRK.
    if((ret = populateKeyExt(drkCert, drkCertLen, privKey, privKeyLen, &drkKey, &issuer)) != NOT_ERROR)
    {
        LOGE("Failed to populate key with error %d.", ret);
        goto cleanup;
    }

    if((ret = KEY_check_keypair(drkKey)) != NOT_ERROR)
    {
        LOGE("Failed to verify key pair with error %d.", ret);
        goto cleanup;
    }

    memset(&genInfo, 0, sizeof(genInfo));

    switch(serviceKeyInfo->keyType)
    {
        case KEY_TYPE_RSA :
            keyType = RSA_KEY;
            genInfo.exponent = getTlvExponent();
            break;

        case KEY_TYPE_EC :
            keyType = ECC_KEY;
            break;

        default :
            LOGE("Supoorted cert type : %d", serviceKeyInfo->keyType);
            ret = ERR_TA_INVALID_ARGUMENT;
            goto cleanup;
    }

    genInfo.keyLen = serviceKeyInfo->keyLength;

    if((serviceKey = KEY_new(keyType)) == NULL)
    {
        LOGE("Failed to allocate service key structure.");
        ret = ERR_TA_NOT_ENOUGH_MEMORY;
        goto cleanup;
    }

    if((ret = KEY_generate_key(serviceKey, &genInfo)) != NOT_ERROR)
    {
        LOGE("Failed to generate service key with error %d.", ret);
        goto cleanup;
    }

    if((ret = KEY_check_keypair(serviceKey)) != NOT_ERROR)
    {
        LOGE("Failed to verify service key pair with error %d.", ret);
        goto cleanup;
    }

    if((ret = generateCertificate(serviceCert, &serviceCertLen, serviceKeyInfo, &issuer, serviceKey, drkKey)) != NOT_ERROR)
    {
        LOGE("Failed to generate service certificate with error %d.", ret);
        goto cleanup;
    }

    // Build ASN.1 representation of service private key.
    memset(privKey, 0, sizeof(privKey));
    privKeyLen = sizeof(privKey);

    if((ret = KEY_build_keypair(serviceKey, privKey, &privKeyLen)) != NOT_ERROR)
    {
        LOGE("Failed to build service private key with error %d.", ret);
        goto cleanup;
    }

#if (defined DEBUG)
    {
        struct x509_certificate x509ServiceCert;

        memset(&x509ServiceCert, 0, sizeof(x509ServiceCert));

        if((ret = x509_certificate_parse(serviceCert, serviceCertLen, &x509ServiceCert)) != X509_PARSE_OK)
        {
            LOGE("FUNC TEST : Failed to convert X.509 structure with error %d.", ret);
            goto cleanup;
        }

        if((ret = KEY_populate_keys(serviceKey, x509ServiceCert.subject_public_key,
                    x509ServiceCert.subject_public_key_len, privKey, privKeyLen)) != NOT_ERROR)
        {
            LOGE("FUNC TEST : Generated ASN.1 private RSA key is invalid with error %d.", ret);
            goto cleanup;
        }
        LOGD("FUNC TEST : Generated ASN.1 private RSA key is correct.");
    }
#endif  // End of DEBUG

    //  Service Key blob generation.
    memset(plainBlob, 0, sizeof(plainBlob));

    pTlv->tag = KEYBLOB_TAG_CERT;
    pTlv->dataLen = (uint16_t)drkCertLen;
    plainBlobLen -= TAGLENGTH_FIELD_SIZE;
    if(drkCertLen < plainBlobLen)
    {
        memcpy(pTlv->data, drkCert, drkCertLen);
        plainBlobLen -= drkCertLen;
    }
    else
    {
        LOGE("drkCertLen (%d) is too big.", drkCertLen);
        ret = ERR_TA_BUFFER_OVERFLOW;
        goto cleanup;
    }

    pTlv = (Tlv_t *)(pTlv->data + pTlv->dataLen);

    pTlv->tag = KEYBLOB_TAG_CERT;
    pTlv->dataLen = (uint16_t)serviceCertLen;
    plainBlobLen -= TAGLENGTH_FIELD_SIZE;
    if(serviceCertLen < plainBlobLen)
    {
        memcpy(pTlv->data, serviceCert, serviceCertLen);
        plainBlobLen -= serviceCertLen;
    }
    else
    {
        LOGE("serviceCertLen (%d) is too big.", serviceCertLen);
        ret = ERR_TA_BUFFER_OVERFLOW;
        goto cleanup;
    }

    pTlv = (Tlv_t *)(pTlv->data + pTlv->dataLen);

    pTlv->tag = KEYBLOB_TAG_PRIVATE_KEY;
    pTlv->dataLen = (uint16_t)privKeyLen;
    plainBlobLen -= TAGLENGTH_FIELD_SIZE;
    if(privKeyLen < plainBlobLen)
    {
        memcpy(pTlv->data, privKey, privKeyLen);
        plainBlobLen -= privKeyLen;
    }
    else
    {
        LOGE("privKeyLen (%d) is too big.", privKeyLen);
        ret = ERR_TA_BUFFER_OVERFLOW;
        goto cleanup;
    }

    pTlv = (Tlv_t *)(pTlv->data + pTlv->dataLen);

    pTlv->tag = KEYBLOB_TAG_TA_NAME;
    pTlv->dataLen = (uint16_t)targetTidLen;
    plainBlobLen -= TAGLENGTH_FIELD_SIZE;
    if(targetTidLen < plainBlobLen)
    {
        memcpy(pTlv->data, targetTid, targetTidLen);
    }
    else
    {
        LOGE("TIDLen (%d) is too big.", targetTidLen);
        ret = ERR_TA_BUFFER_OVERFLOW;
        goto cleanup;
    }

    pTlv = (Tlv_t *)(pTlv->data + pTlv->dataLen);

    plainBlobLen = (uint8_t *)pTlv - plainBlob;

    if(*serviceBlobLen < plainBlobLen)
    {
        LOGE("service blob len(%d) is too small. %d.", *serviceBlobLen, plainBlobLen);
        ret = ERR_TA_BUFFER_OVERFLOW;
        goto cleanup;
    }

    memset(serviceBlob, 0, *serviceBlobLen);
    memcpy(serviceBlob, plainBlob, plainBlobLen);
    *serviceBlobLen = plainBlobLen;

cleanup:
    if(serviceKey)
        KEY_free(serviceKey);

    if(drkKey)
        KEY_free(drkKey);

    memset(privKey, 0, sizeof(privKey));
    memset(plainBlob, 0, sizeof(plainBlob));

    LOGI("%s end...", __func__);

    return ret;
}

int32_t generateServiceKey(const uint8_t *drkBlob, const uint32_t drkBlobLen,
        uint8_t *serviceBlob, uint32_t *serviceBlobLen, ServiceKeyInfo_t *serviceKeyInfo,
        const uint8_t *attrs, const uint32_t attrsLen)
{
    int32_t ret = NOT_ERROR;
    uint8_t plainBlob[MAX_SKM_BUF_SIZE], targetTid[MAX_TID_SIZE];
    uint32_t plainBlobLen = sizeof(plainBlob), targetTidLen = sizeof(targetTid);

    LOGI("%s start...", __func__);

    memset(plainBlob, 0, sizeof(plainBlob));

    if(drkBlob == NULL || drkBlobLen == 0 || serviceBlob == NULL || serviceBlobLen == NULL || serviceKeyInfo == NULL)
    {
        LOGE("%s : Invalid argument.", __func__);
        return ERR_TA_INVALID_ARGUMENT;
    }

    memset(targetTid, 0, sizeof(targetTid));

    if((ret = getTidByServiceName(serviceKeyInfo->serviceName, (char *)targetTid, &targetTidLen)) != NOT_ERROR)
    {
        LOGE("Failed to get TID of service(%s). It seems not be registered in SKM.", serviceKeyInfo->serviceName);
        return ret;
    }

    if((ret = generateServiceKeyBlob(drkBlob, drkBlobLen, plainBlob, &plainBlobLen, serviceKeyInfo, attrs, attrsLen)) != NOT_ERROR)
    {
        LOGE("Failed to generate service key blob with error %d.", ret);
        return ret;
    }

    memset(serviceBlob, 0, *serviceBlobLen);

    if((ret = createSecureObject(plainBlob, plainBlobLen, serviceBlob, serviceBlobLen, targetTid, targetTidLen)) != NOT_ERROR)
        LOGE("Failed to make secure object for RSA service key with error %d", ret);

    memset(plainBlob, 0, sizeof(plainBlob));

    LOGI("%s end...", __func__);

    return ret;
}

int32_t generateServiceKeyV1(struct KeyInfo *keyInfo, const uint8_t *drkBlob, const uint32_t drkBlobLen,
        uint8_t *serviceBlob, uint32_t *serviceBlobLen, const uint8_t *attrs, const uint32_t attrsLen, KeyType_t keyType)
{
    int32_t ret = NOT_ERROR;
    ServiceKeyInfo_t serviceKeyInfo;
    uint8_t plainBlob[MAX_SKM_BUF_SIZE], targetTid[MAX_TID_SIZE];
    uint32_t plainBlobLen = sizeof(plainBlob), targetTidLen = sizeof(targetTid);
#if (defined USE_QSEE_SFS)
    const char dirPath[] = COMMON_DIR"/prov_data/";
#endif  // End of USE_QSEE_SFS

    LOGI("%s start...", __func__);

    if(keyInfo == NULL)
    {
        LOGE("%s : Invalid argument.", __func__);
        return ERR_TA_INVALID_ARGUMENT;
    }

    memset(plainBlob, 0, sizeof(plainBlob));
    memset(&serviceKeyInfo, 0, sizeof(serviceKeyInfo));
    memcpy(serviceKeyInfo.serviceName, keyInfo->serviceName, MAX_SERVICE_NAME);
    memcpy(serviceKeyInfo.model, keyInfo->model, sizeof(serviceKeyInfo.model));
    memcpy(serviceKeyInfo.serialNo, keyInfo->serialno, sizeof(serviceKeyInfo.serialNo));
    serviceKeyInfo.keyLength = keyInfo->keyLen;
    serviceKeyInfo.keyType = keyType;

    memset(targetTid, 0, sizeof(targetTid));

    if((ret = getTidByServiceName(serviceKeyInfo.serviceName, (char *)targetTid, &targetTidLen)) != NOT_ERROR)
    {
        LOGE("Failed to get TID of service(%s). It seems not be registered in SKM.", serviceKeyInfo.serviceName);
        return ret;
    }

    if((ret = generateServiceKeyBlob(drkBlob, drkBlobLen, plainBlob, &plainBlobLen, &serviceKeyInfo, attrs, attrsLen)) != NOT_ERROR)
    {
        LOGE("Failed to generate service key blob with error %d.", ret);
        return ret;
    }

    memset(serviceBlob, 0, *serviceBlobLen);

#if (defined USE_QSEE)
#if (defined USE_QSEE_SFS)
    strncpy((char *)serviceBlob, dirPath, strlen(dirPath));
    strncat((char *)serviceBlob, (char *)targetTid, strlen((char *)targetTid));
    strncat((char *)serviceBlob, "/", sizeof(char));
    strncat((char *)serviceBlob, (char *)targetTid, strlen((char *)targetTid));
    strncat((char *)serviceBlob, ".dat", strlen(".dat"));

    *serviceBlobLen = strlen((char *)serviceBlob);
#endif  // End of USE_QSEE_SFS
    if((ret = createLocalSecureObject(plainBlob, plainBlobLen, serviceBlob, serviceBlobLen)) != NOT_ERROR)
#else
    if((ret = createSecureObject(plainBlob, plainBlobLen, serviceBlob, serviceBlobLen, targetTid, targetTidLen)) != NOT_ERROR)
#endif
        LOGE("Failed to make secure object for RSA service key with error %d", ret);

    memset(plainBlob, 0, sizeof(plainBlob));

    LOGI("%s end...", __func__);

    return ret;
}

int32_t readDrkCertificateUID(uint8_t *uid, uint32_t *uidLen, const uint8_t *drkBlob, const uint32_t drkBlobLen)
{
    int32_t ret = NOT_ERROR;
    uint8_t drkCert[MAX_RSA_CERT_LEN], privKey[MAX_RSA_LEN];
    uint32_t drkCertLen = sizeof(drkCert), privKeyLen = sizeof(privKey);

    LOGI("%s start...", __func__);

    if(uid == NULL || uidLen == NULL || drkBlob == NULL || drkBlobLen == 0)
    {
        LOGE("%s : Invalid argument.", __func__);
        return ERR_TA_INVALID_ARGUMENT;
    }

    memset(drkCert, 0, sizeof(drkCert));
    memset(privKey, 0, sizeof(privKey));

    //  Read device root key (DRK).
    if((ret = getDeviceRootKey(drkBlob, drkBlobLen, privKey, &privKeyLen, drkCert, &drkCertLen)) != NOT_ERROR)
    {
        LOGE("Failed to get device root key with error %d.", ret);
        goto cleanup;
    }

    if((ret = verifyCertificateWithCA(drkCert, drkCertLen, NULL)) != NOT_ERROR)
    {
        LOGE("Failed to verifyCertificateWithCA with error %d : ", ret);
        goto cleanup;
    }

    ret = getCertUID(drkCert, drkCertLen, uid, *uidLen);
    *uidLen = strlen((char*)uid);

cleanup:
    memset(privKey, 0, sizeof(privKey));

    LOGI("%s end...", __func__);

    return ret;
}

int32_t getDrkCertificate(uint8_t *cert, uint32_t *certLen, const uint8_t *drkBlob, const uint32_t drkBlobLen)
{
    int32_t ret = NOT_ERROR;
    uint8_t drkCert[MAX_RSA_CERT_LEN], privKey[MAX_RSA_LEN];
    uint32_t drkCertLen = sizeof(drkCert), privKeyLen = sizeof(privKey);

    LOGI("%s start...", __func__);

    if(cert == NULL || certLen == NULL || drkBlob == NULL || drkBlobLen == 0)
    {
        LOGE("%s : Invalid argument.", __func__);
        return ERR_TA_INVALID_ARGUMENT;
    }

    memset(drkCert, 0, sizeof(drkCert));
    memset(privKey, 0, sizeof(privKey));

    //  Read device root key (DRK).
    if((ret = getDeviceRootKey(drkBlob, drkBlobLen, privKey, &privKeyLen, drkCert, &drkCertLen)) != NOT_ERROR)
    {
        LOGE("Failed to get device root key with error %d.", ret);
        goto cleanup;
    }

    if(*certLen < drkCertLen)
    {
        LOGE("Buffer is too small. %d %d.", *certLen, drkCertLen);
        ret = ERR_TA_BUFFER_OVERFLOW;
        goto cleanup;
    }

    memcpy(cert, drkCert, drkCertLen);
    *certLen = drkCertLen;

cleanup:
    memset(privKey, 0, sizeof(privKey));

    LOGI("%s end...", __func__);

    return ret;
}

#if (defined USE_QSEE)
int32_t getSharedServiceKey(struct KeyInfo* keyInfo, uint8_t *wrapped, uint32_t wrappedLen,
                            uint8_t *outData, uint32_t *outDataLen)
{
    int32_t ret = NOT_ERROR;
    uint8_t plainBuf[MAX_SKM_BUF_SIZE];
    uint32_t plainBufLen = sizeof(plainBuf);
    Tlv_t *pTlv = (Tlv_t *)plainBuf;
    uint8_t knoxTid[] = TID_KNOX;
#if (defined USE_QSEE_SFS)
    char keyPath[MAX_FILE_PATH_LEN], tid[MAX_TID_SIZE];
    const char dirPath[] = COMMON_DIR"/prov_data/";
    uint32_t tidLen = 0;
#endif  // End of USE_QSEE_SFS

    LOGI("%s()...", __func__);

    if(keyInfo == NULL || outData == NULL || outDataLen == NULL)
    {
        LOGE("%s : Invalid arguments.", __func__);
        return ERR_TA_INVALID_ARGUMENT;
    }

#if (defined USE_QSEE_SFS)
    memset(tid, 0, sizeof(tid));

    if((ret = getTidByServiceName((char *)keyInfo->serviceName, tid, &tidLen)) != NOT_ERROR)
    {
        LOGE("%s is not registered in white list.", (char *)keyInfo->serviceName);
        return ret;
    }

    memset(keyPath, 0, sizeof(keyPath));
    strncpy(keyPath, dirPath, strlen(dirPath));
    strncat(keyPath, tid, strlen(tid));
    strncat(keyPath, "/", sizeof(char));
    strncat(keyPath, tid, strlen(tid));
    strncat(keyPath, ".dat", strlen(".dat"));

    wrapped = (uint8_t *)keyPath;
    wrappedLen = strlen(keyPath);
#endif  // End of USE_QSEE_SFS

    memset(plainBuf, 0, sizeof(plainBuf));

    if((ret = openLocalSecureObject(wrapped, wrappedLen, plainBuf, &plainBufLen)) != NOT_ERROR)
    {
        LOGE("Failed to open local secure object for sharing with error %d.", ret);
        return ret;
    }

    if(pTlv->tag != KEYBLOB_TAG_CERT)
    {
        LOGE("Service key blob is invalid. 1st tag : %d.", pTlv->tag);
        ret = ERR_TA_INVALID_BLOB;
        goto cleanup;
    }

    pTlv = (Tlv_t *)(pTlv->data + pTlv->dataLen);

    if(pTlv->tag != KEYBLOB_TAG_CERT)
    {
        LOGE("Service key blob is invalid. 2nd tag : %d.", pTlv->tag);
        ret = ERR_TA_INVALID_BLOB;
        goto cleanup;
    }

    pTlv = (Tlv_t *)(pTlv->data + pTlv->dataLen);

    if(pTlv->tag != KEYBLOB_TAG_PRIVATE_KEY)
    {
        LOGE("Service key blob is invalid. 3rd tag : %d.", pTlv->tag);
        ret = ERR_TA_INVALID_BLOB;
        goto cleanup;
    }

    pTlv = (Tlv_t *)(pTlv->data + pTlv->dataLen);

    if(pTlv->tag != KEYBLOB_TAG_TA_NAME)
    {
        // TL_NAME_TAG didn't be added on intial version of SKM for KNOX key.
        // To have backward compatibility, add TL_NAME_TAG only for KNOX key.
        if(strncmp((char *)keyInfo->serviceName, KNOX_SERV_NAME, strlen(KNOX_SERV_NAME)) == 0)
        {
            LOGI("Intial version of KNOX key.");

            if(pTlv->data + sizeof(knoxTid) < &plainBuf[sizeof(plainBuf) - 1])
            {
                pTlv->tag = KEYBLOB_TAG_TA_NAME;
                pTlv->dataLen = (uint16_t)sizeof(knoxTid);
                memcpy(pTlv->data, knoxTid, sizeof(knoxTid));
            }
            else
            {
                LOGE("Blob size is too big.");
                ret = ERR_TA_BUFFER_OVERFLOW;
                goto cleanup;
            }
        }
        else
        {
            LOGE("Service key blob is invalid. 4th tag : %d.", pTlv->tag);
            ret = ERR_TA_INVALID_BLOB;
            goto cleanup;
        }
    }

    if(pTlv->dataLen > MAX_TID_SIZE)
    {
        LOGE("Service TID length is invalid - %d.", pTlv->dataLen);
        ret = ERR_TA_INVALID_ARGUMENT;
        goto cleanup;
    }

    if((ret = createSecureObject(plainBuf, plainBufLen, outData, outDataLen, pTlv->data, pTlv->dataLen)) != NOT_ERROR)
        LOGE("Failed to create secure object for service key with error %d.", ret);

    LOGI("%s()...Done!", __func__);
cleanup:
    memset(plainBuf, 0, sizeof(plainBuf));
    return ret;
}

#ifndef USE_QSEE_PROV_SFS
int32_t installDrkV1(const uint8_t *wrappedKey, const uint32_t wrappedKeyLen, uint8_t *outData, uint32_t *outDataLen)
{
    int32_t ret = NOT_ERROR;
    uint8_t plainBuf[MAX_SKM_BUF_SIZE];
    uint32_t plainBufLen = sizeof(plainBuf);
    const uint8_t tidProv[] = TID_PROV;

    if(wrappedKey == NULL || wrappedKeyLen == 0 || outData == NULL || outDataLen == NULL)
    {
        LOGE("Invalid parameters of DrkV1.");
        return ERR_TA_INVALID_ARGUMENT;
    }

    if((ret = openSecureObject(wrappedKey, wrappedKeyLen, plainBuf, &plainBufLen, tidProv, sizeof(tidProv))) != NOT_ERROR)
    {
        LOGE("Failed to open Prov's secure object with error %d.", ret);
        return ret;
    }

#if (defined USE_QSEE_SFS)
    memcpy(outData, DRK_KEY_PATH, strlen(DRK_KEY_PATH));
    *outDataLen = strlen(DRK_KEY_PATH);
#endif  // End of USE_QSEE_SFS

    if((ret = createLocalSecureObject(plainBuf, plainBufLen, outData, outDataLen)) != NOT_ERROR)
        LOGE("Failed to create local secure object with error %d.", ret);

    return ret;
}
#endif  // End of !USE_QSEE_PROV_SFS
#endif  // End of USE_QSEE

int32_t generateRsaKeyPair(uint8_t *outData, uint32_t *outDataLen, bool isSaveToFs)
{
    int32_t ret = NOT_ERROR;
    KEY* key = NULL;
    struct KeyGenInfo genInfo;
    uint8_t privKey[MAX_RSA_LEN];
    uint32_t privKeyLen = sizeof(privKey);
#if !(defined USE_QSEE)
    const uint8_t TID[] = TID_SKM;
#endif  // End of !USE_QSEE

    if(outData == NULL || outDataLen == NULL)
    {
        LOGE("%s : Invalid agrument.", __func__);
        return ERR_TA_INVALID_ARGUMENT;
    }

    memset(privKey, 0, sizeof(privKey));

    if((key = KEY_new(RSA_KEY)) == NULL)
    {
        LOGE("Failed to allocate key.");
        return ERR_TA_NOT_ENOUGH_MEMORY;
    }

    genInfo.keyLen = RSA_BIT_SIZE_DEFAULT;
    genInfo.exponent = getTlvExponent();

    if((ret = KEY_generate_key(key, &genInfo)) != NOT_ERROR)
    {
        LOGE("Failed to generate key with error %d.", ret);
        goto cleanup;
    }
#if (defined DEBUG)
    if((ret = KEY_check_keypair(key)) != NOT_ERROR)
    {
        LOGE("Failed private key verification with error %d.", ret);
        goto cleanup;
    }
#endif  // End of DEBUG.

    if((ret = KEY_build_keypair(key, privKey, &privKeyLen)) != NOT_ERROR)
    {
        LOGE("Failed to build ASN.1 encoded private key with error %d.", ret);
        goto cleanup;
    }

    if(*outDataLen < privKeyLen)
    {
        LOGE("Not enough memory to save key. %d %d.", *outDataLen, privKeyLen);
        ret = ERR_TA_INVALID_ARGUMENT;
        goto cleanup;
    }

    if(isSaveToFs)
    {
#if (defined USE_QSEE)
        if((ret = createLocalSecureObject(privKey, privKeyLen, outData, outDataLen)) != NOT_ERROR)
#else
        if((ret = createSecureObject(privKey, privKeyLen, outData, outDataLen, TID, sizeof(TID))) != NOT_ERROR)
#endif  // End of USE_QSEE
        {
            LOGE("Failed to create secure object with error %d.", ret);
            goto cleanup;
        }
    }
    else
    {
        memcpy(outData, privKey, privKeyLen);
        *outDataLen = privKeyLen;
        ret = NOT_ERROR;
    }

cleanup:
    memset(privKey, 0, sizeof(privKey));
    KEY_free(key);
    return ret;
}

int32_t generateCertificateSigningRequest(const uint8_t *modelName, const uint32_t modelNameLen,
        const uint8_t *huid, const uint32_t huidLen, const void *preGenKey, const uint32_t preGenKeyLen,
        const uint8_t *imei, const uint32_t imeiLen, uint8_t *csr, uint32_t *csrLen)
{
    int ret = NOT_ERROR;
    KEY *key = NULL;
    uint8_t targetTid[MAX_TID_SIZE];
    uint8_t rsaPubKey[MAX_RSA_LEN], rawDataBlob[CSR_DATA_MAX_SIZE], csrBlob[CSR_DATA_MAX_SIZE];
    uint32_t rsaPubKeyLen = sizeof(rsaPubKey), rawDataBlobLen = sizeof(rawDataBlob), csrBlobLen = sizeof(csrBlob), targetTidLen = sizeof(targetTid);
    uint8_t csrDigest[SHA256_DIGEST_LENGTH], signature[RSA_ENCRYPTED_KEY_SIZE];
    uint32_t signatureLen = sizeof(signature);

    (void) preGenKey;
    (void) preGenKeyLen;

    if (modelName == NULL || huid == NULL || csr == NULL || csrLen == NULL || modelNameLen == 0 || huidLen == 0)
    {
        LOGE("%s : Invalid agrument.", __func__);
        return ERR_TA_INVALID_ARGUMENT;
    }

    memset(gGenRsaKeyPair, 0, sizeof(gGenRsaKeyPair));

    gGenRsaKeyPairLen = 0;

    LOGE("%s start...", __func__);
    // Get private key.
    gGenRsaKeyPairLen = sizeof(gGenRsaKeyPair);
    if ((ret = generateRsaKeyPair(gGenRsaKeyPair, &gGenRsaKeyPairLen, false)) != NOT_ERROR)
    {
        LOGE("Failed to generate key.");
        gGenRsaKeyPairLen = 0;
        goto cleanup;
    }

    if ((key = KEY_new(RSA_KEY)) == NULL)
    {
        LOGE("Failed to allocate key.");
        ret = ERR_TA_NOT_ENOUGH_MEMORY;
        goto cleanup;
    }

    if ((ret = KEY_populate_keypair(key, gGenRsaKeyPair, gGenRsaKeyPairLen)) != NOT_ERROR)
    {
        LOGE("Failed to popluate key pair with error %d.", ret);
        goto cleanup;
    }

    if ((ret = KEY_check_keypair(key)) != NOT_ERROR)
    {
        LOGE("Failed to check key pair with error  %d.", ret);
        goto cleanup;
    }

    // Generate DRK public key ASN.1 data.
    if ((ret = KEY_build_public(key, rsaPubKey, &rsaPubKeyLen)) != NOT_ERROR)
    {
        LOGE("Failed to generate key with error %d.", ret);
        goto cleanup;
    }

    // Make raw data blob.
    memset(rawDataBlob, 0, sizeof(rawDataBlob));
    if((ret = tlvInit(rawDataBlob, sizeof(rawDataBlob))) != NOT_ERROR)
    {
        LOGE("TlvInit failed with error %d.", ret);
        goto cleanup;
    }

    if((ret = tlvAdd(rawDataBlob, sizeof(rawDataBlob), TLV_MODEL_NAME, modelName,
                (modelNameLen > MAX_MODEL_SIZE)? MAX_MODEL_SIZE : modelNameLen)) != NOT_ERROR)
    {
        LOGE("TlvAdd failed with error %d for Tag %d", ret, TLV_MODEL_NAME);
        goto cleanup;
    }

    if((ret = tlvAdd(rawDataBlob, sizeof(rawDataBlob), TLV_CERT, rsaPubKey, rsaPubKeyLen)) != NOT_ERROR)
    {
        LOGE("TlvAdd failed with error %d for Tag %d", ret, TLV_CERT);
        goto cleanup;
    }

    if((ret = tlvAdd(rawDataBlob, sizeof(rawDataBlob), TLV_HUID, huid, huidLen)) != NOT_ERROR)
    {
        LOGE("TlvAdd failed with error %d for Tag %d", ret, TLV_HUID);
        goto cleanup;
    }

    if((ret = tlvAdd(rawDataBlob, sizeof(rawDataBlob), TLV_IMEI, imei, imeiLen)) != NOT_ERROR)
    {
        LOGE("TlvAdd failed with error %d for Tag %d", ret, TLV_IMEI);
        goto cleanup;
    }

    rawDataBlobLen = (uint32_t)tlvSize(rawDataBlob, sizeof(rawDataBlob));

    if((ret = getShaDigest(rawDataBlob, rawDataBlobLen, csrDigest, sizeof(csrDigest), ALGO_SHA256)) != NOT_ERROR)
    {
        LOGE("Failed to generate csrBlobData hash, res = %d", ret);
        goto cleanup;
    }

    if((ret = KEY_sign(key, NID_sha256, csrDigest, sizeof(csrDigest),
                signature, &signatureLen)) != NOT_ERROR)
    {
        LOGE("Failed to sign keyblob with error %d.", ret);
        goto cleanup;
    }

#if (defined DEBUG)
    if((ret = KEY_verify(key, NID_sha256, csrDigest, sizeof(csrDigest), signature, signatureLen)) != NOT_ERROR)
    {
        LOGE("Failed to verify signature with error %d.", ret);
        goto cleanup;
    }
#endif

    if(csrBlobLen < rawDataBlobLen + signatureLen + 2 * TAGLENGTH_FIELD_SIZE)
    {
        LOGE("Outbuffer is too small. %d %d.",
                csrBlobLen, rawDataBlobLen + signatureLen + 2 * TAGLENGTH_FIELD_SIZE);
        ret = ERR_TA_BUFFER_OVERFLOW;
        goto cleanup;
    }

    memset(csrBlob, 0, sizeof(csrBlob));
    if((ret = tlvInit(csrBlob, sizeof(csrBlob))) != NOT_ERROR)
    {
        LOGE("TlvInit failed with error %d.", ret);
        goto cleanup;
    }

    if((ret = tlvAdd(csrBlob, sizeof(csrBlob), TLV_SIGN_DATA_BLOB, rawDataBlob, rawDataBlobLen)) != NOT_ERROR)
    {
        LOGE("TlvAdd failed with error %d for Tag %d", ret, TLV_SIGN_DATA_BLOB);
        goto cleanup;
    }

    if((ret = tlvAdd(csrBlob, sizeof(csrBlob), TLV_SIGNATURE, signature, signatureLen)) != NOT_ERROR)
    {
        LOGE("TlvAdd failed with error %d for Tag %d", ret, TLV_SIGNATURE);
        goto cleanup;
    }

    csrBlobLen = tlvSize(csrBlob, sizeof(csrBlob));

    memset(targetTid, 0, sizeof(targetTid));

    if((ret = getTidByServiceName(PROV_SERV_NAME, (char *)targetTid, &targetTidLen)) != NOT_ERROR)
    {
        LOGE("Failed to get TID of service(%s). It seems not be registered in SKM.", PROV_SERV_NAME);
        goto cleanup;
    }

    if((ret = createSecureObject(csrBlob, csrBlobLen, csr, csrLen, targetTid, sizeof(targetTid))) != NOT_ERROR)
        LOGE("Failed to make secure object of CSR with error %d.", ret);

cleanup:
    if(ret != NOT_ERROR)
    {
        memset(gGenRsaKeyPair, 0, sizeof(gGenRsaKeyPair));
        gGenRsaKeyPairLen = 0;
    }

    if(key)
        KEY_free(key);
    return ret;
}

int32_t installCertificate(const uint8_t* cert, uint32_t certLen, uint8_t *outData, uint32_t* outDataLen)
{
    int32_t ret = NOT_ERROR;
    struct x509_certificate x509Cert;
    KEY* key = NULL;
    uint8_t keyBlob[MAX_SKM_BUF_SIZE];
    Tlv_t *pTlv = (Tlv_t *)keyBlob;
#if !(defined USE_QSEE)
    const uint8_t TID[] = TID_SKM;
#endif  // End of !USE_QSEE

    if(cert == NULL || certLen == 0 || outData == NULL || outDataLen == NULL)
    {
        LOGE("%s : Invalid agrument.", __func__);
        return ERR_TA_INVALID_ARGUMENT;
    }

    if(gGenRsaKeyPairLen == 0)
    {
        LOGE("Generating CSR should be executed before calling this functioin.");
        return ERR_TA_UNSUPPORTED_CMD;
    }

    memset(&x509Cert, 0, sizeof(x509Cert));

    // Check certificate validation and get X.509 certificate.
    if((ret = verifyCertificateWithCA(cert, certLen, &x509Cert)) != NOT_ERROR)
    {
        LOGE("Failed verification of DRK cert with error %d.", ret);
        return ret;
    }

    if((ret = validateDrkCert(&x509Cert)) != NOT_ERROR)
    {
        LOGE("Failed to validate certificate with error %d.", ret);
        return ret;
    }

    if((key = KEY_new(getCertPublicKeyType(&x509Cert))) == NULL)
    {
        LOGE("Failed to allocate key.");
        return ERR_TA_NOT_ENOUGH_MEMORY;
    }

    if((ret = KEY_populate_keys(key, x509Cert.subject_public_key, x509Cert.subject_public_key_len,
                           gGenRsaKeyPair, gGenRsaKeyPairLen)) != NOT_ERROR)
    {
        LOGE("Failed to popluate key pair with error %d.", ret);
        goto cleanup;
    }

    if((ret = KEY_check_keypair(key)) != NOT_ERROR)
    {
        LOGE("Failed to check key pair with error  %d.", ret);
        goto cleanup;
    }

    // Make keyBlob.
    memset(keyBlob, 0, sizeof(keyBlob));
    pTlv->tag = KEYBLOB_TAG_CERT;
    pTlv->dataLen = SEC_HTONS(certLen);
    memcpy(pTlv->data, cert, certLen);
    pTlv = (Tlv_t *)(pTlv->data + certLen);
    pTlv->tag = KEYBLOB_TAG_PRIVATE_KEY;
    pTlv->dataLen = SEC_HTONS(gGenRsaKeyPairLen);
    memcpy(pTlv->data, gGenRsaKeyPair, gGenRsaKeyPairLen);

#if (defined USE_QSEE)
    if((ret = createLocalSecureObject(keyBlob, 2 * TAGLENGTH_FIELD_SIZE + certLen + gGenRsaKeyPairLen,
                    outData, outDataLen)) != NOT_ERROR) {
#else
    if((ret = createSecureObject(keyBlob, 2 * TAGLENGTH_FIELD_SIZE + certLen + gGenRsaKeyPairLen,
                    outData, outDataLen, TID, sizeof(TID))) != NOT_ERROR) {
#endif  // End of USE_QSEE
        LOGE("Failed to create secure object with error %d.", ret);
    }

cleanup:
    memset(keyBlob, 0, sizeof(keyBlob));
    memset(gGenRsaKeyPair, 0, sizeof(gGenRsaKeyPair));
    gGenRsaKeyPairLen = 0;
    KEY_free(key);
    return ret;
}

int32_t readDrkFromHwvault(uint8_t *outData, uint32_t *outDataLen) {
#if defined(DRKFEATURE_HWVAULT_ENABLE)
    uint32_t slot_id = 1,
             ret = 0,
             cred_len = 0;
    uint8_t *cred = NULL;

    LOGI("%s start", __func__);
    if(outData == NULL || outDataLen == NULL) {
        LOGE("%s : Invalid agrument.", __func__);
        return ERR_TA_INVALID_ARGUMENT;
    }

    ret = HwVaultHal_readCred(slot_id, &cred, &cred_len);
    if (ret == HV_ERROR_OK) {
        if (cred != NULL && cred_len > 0 && cred_len <= *outDataLen) {
            memcpy(outData, cred, cred_len);
            HwVaultHal_free(cred);
            LOGI("%s end", __func__);
            return NOT_ERROR;
        }
    } else {
        LOGE("HwVaultHal_readCred invalid return %u", ret);
    }

    if(cred) { HwVaultHal_free(cred); }
    return ERR_FROM_HWVAULT;
#else
    LOGD("skip ");
    return ERR_TA_UNSUPPORTED_CMD;
#endif
}
