#include "DeviceInfo.h"
#include "DrkCommand.h"

namespace vendor    {
namespace samsung   {
namespace hardware  {
namespace security  {
namespace drk       {

int32_t  DrkCommand::CreateServiceKey(Bytes& in, Bytes& out)
{
    int32_t          ret = NOT_ERROR, lcCmdId = CMD_GENERATE_SERVICE_KEY;
    TLV              lcTlv, lcReqTlv;
    Bytes            lcSki, lcAttr, lcReq, lcSrvName;
    ServiceKeyInfo_t *lcSrvKeyInfo = NULL;

    if ((ret = lcTlv.decode(in)) != NOT_ERROR) {
        LOGME("inTlv.decode is failed. %d.", ret);
        goto end;
    }

    if ((ret = lcTlv.get(TLV_KEY_INFO, lcSki)) != NOT_ERROR) {
        LOGME("Getting tlv was failed s: %d", ret);
        goto end;
    }

    if ((ret = lcTlv.get(TLV_ATTRS, lcAttr)) != NOT_ERROR) {
        /* It is not a problem because Attr can be missed */
        LOGMD("There is no attr.");
    }

    if ((ret = DeviceInfo::MakeServiceKeyInfo(lcSki)) != NOT_ERROR) {
        LOGME("The size of struct is different");
        ret = ERR_INVALID_ARGUMENT;
        goto end;
    }

    lcSrvKeyInfo = (ServiceKeyInfo_t *)(uint8_t *)lcSki;
    if (lcSrvName.set((uint8_t *)lcSrvKeyInfo->serviceName, MAX_SERVICE_NAME) == NOT_ERROR) {
        SaveBigDataMsg(lcSrvName);
    }

    if ((ret = lcReqTlv.add(TLV_KEY_INFO, lcSki)) != NOT_ERROR) {
        LOGME("Getting tlv was failed s: %d", ret);
        goto end;
    }

    if (lcAttr.length() != 0) {
        if ((ret = lcReqTlv.add(TLV_ATTRS, lcAttr)) != NOT_ERROR) {
            LOGME("Getting tlv was failed s: %d", ret);
            goto end;
        }
    }

    if ((ret = lcReqTlv.encode(lcReq)) != NOT_ERROR) {
        LOGME("To encode tlv is failed. (%d)", ret);
        goto end;
    }

#ifndef USE_RELEASE
    if(!strncmp((char *)lcSrvKeyInfo->serviceName, "PROV", sizeof("PROV"))) {
        LOGMI("generate prov service key called");
        lcCmdId = CMD_GENERATE_PROV_SERVICE_KEY;
    }
#endif

    if ((ret = CommandWithWrappedKey(lcCmdId, lcReq, out)) != NOT_ERROR) {
        LOGME("To CreateServiceKey is failed with ret : %d.", ret);
    }
end:
    return ret;
}

void  DrkCommand::ReleaseServiceKey()
{
    return ReleaseTzSession();
}

int32_t  DrkCommand::VerifyDRK()
{
    int32_t ret = NOT_ERROR;
    Bytes lcIn, lcTzDI;
    DeviceInfo lcDI;

    if ((ret = CommandWithWrappedKey(CMD_VERIFY_DRK_KEY, lcIn, lcTzDI)) != NOT_ERROR) {
        LOGME("To verify DRK is failed with ret : %d.", ret);
        if((ret = CommandWithWrappedKey(CMD_VERIFY_BACKUP_KEY, lcIn, lcTzDI)) != NOT_ERROR) {
            LOGMI("To verify backup key is failed with ret : %d.", ret);
            goto end;
        }
    }

#ifdef STRENGTHEN_DRK_VERIFICAION
    if ((ret = lcDI.checkValidationCertwithDeviceInfo(lcTzDI)) != NOT_ERROR) {
        LOGME("To check validation Cert with DeviceInfo is failed with ret : %d.", ret);
    }
#endif

end:
    return ret;
}


int32_t  DrkCommand::ReadUID(Bytes& uid)
{
    int32_t ret = NOT_ERROR;
    Bytes   lcIn, lcOut;
    TLV     lcTlv;
    if ((ret = CommandWithWrappedKey(CMD_GET_DEV_INFO, lcIn, lcOut)) != NOT_ERROR) {
        LOGME("To get uid is failed with ret : %d.", ret);
        goto end;
    }

    if ((ret = lcTlv.decode(lcOut)) != NOT_ERROR) {
        LOGME("To decode tlv is failed with ret : %d.", ret);
        goto end;
    }

    if ((ret = lcTlv.get(TLV_HUID, uid)) != NOT_ERROR) {
        LOGME("To get tlv is failed with ret : %d.", ret);
        goto end;
    }

end:
    return ret;
}

int32_t  DrkCommand::ReadDRKCert(Bytes& cert)
{
    int32_t ret = NOT_ERROR;
    Bytes     lcIn;

    if ((ret = CommandWithWrappedKey(CMD_GET_DRK_CERT, lcIn, cert)) != NOT_ERROR) {
        LOGME("To get cert is failed with ret : %d.", ret);
        goto end;
    }

end:
    return ret;
}

int32_t  DrkCommand::SaveBigDataMsg(Bytes& in)
{
    int32_t    ret = NOT_ERROR;
    DeviceInfo lcDI;
    File        lcSaveBigData((char *)(DRK_DATA_DIR"/diag.dat"), APPEND);
    Bytes      lcIn, lcTzDI, lcOut;

    if ((ret = CommandWithWrappedKey(CMD_GET_DEV_INFO, lcIn, lcTzDI)) != NOT_ERROR) {
        LOGME("CommandWithWrappedKey is failed with ret : %d.", ret);
        goto end;
    }

    if ((ret = lcDI.MakeBigDataMsg(in, lcTzDI, lcOut)) != NOT_ERROR) {
        LOGME("To make bigdata msg is failed with ret : %d.", ret);
        goto end;
    }

    lcSaveBigData.writeFile(lcOut);
end:
    return ret;
}

int32_t  DrkCommand::GetDeviceInfo(Bytes& out)
{
    int32_t    ret = NOT_ERROR;
    DeviceInfo lcDI;
    Bytes      lcIn, lcTzDI;
    TLV        inTlv, outTlv;

    if ((ret = CommandWithWrappedKey(CMD_GET_DEV_INFO, lcIn, lcTzDI)) != NOT_ERROR) {
        LOGME("%s failed with ret : %d.", __func__, ret);
        goto end;
    }

    if ((ret = lcDI.MakeDeviceInfoMsg(lcTzDI, out)) != NOT_ERROR) {
        LOGME("To make deviceinfo msg is failed with ret : %d.", ret);
        goto end;
    }
end:
    return ret;
}
}  // namespace drk
}  // namespace security
}  // namespace hardware
}  // namespace samsung
}  // namespace vendor
