/*
 * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
 *
 * Created in Samsung Ukraine R&D Center (SRK) under a contract between
 * LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine)
 * and "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
 */

/**
 * @file TigerCore.c
 * @brief TigerTa
 * @author Viktor Kopp (v.kopp@samsung.com)
 * @date Created Apr 26, 2016
 */

#include "TigerCore.h"

#include "TigerCounterDataStore.h"
#include "TigerKeyDataStore.h"
#include "TigerLogging.h"
#include "TigerStorageUtils.h"
#include "TigerMacroses.h"
#include "TigerSignMessage.h"
#include "TigerAttk.h"
#include "TigerSskds.h"
#include "TzwString.h"
#include "TigerFingerprintIdTable.h"
#include "TigerUtils.h"
#include "tf_wrapper.h"

#ifdef TIGER_BUILD_TESTS
    #include "TigerTests.h"
#endif

#define SOTER_ASK_ALIAS "soterASK"

static TEE_Result generateAndSaveToPersistenObject(const TigerObjectId_t* objId);
static TEE_Result getServiceDeviceStatus(TciDeviceStatus_t* deviceStatus);

TEE_Result processCommand(const void* _request, const uint32_t _sizeRequest,
                          void* response, const uint32_t sizeResponse) {
    LOG_FUNC_BEGIN

    TciRequest_p tciRequest = (TciRequest_p)_request;
    TciCommandId_t commandId = tciRequest->TciCommandId;

    void *request = &tciRequest->request;
    uint32_t sizeRequest = tciRequest->length;


    LOG_I("Command [%d]: %s", commandId, getTciCommandIdStr(commandId));
#ifdef __ARM_ARCH_64__
    LOG_D("sizeof(TciCommandId_t) = %zd", sizeof(TciCommandId_t));
    LOG_D("Request:  buffer = 0x%lx size = %u", (uintptr_t) request, sizeRequest);
    LOG_D("Response: buffer = 0x%lx size = %u", (uintptr_t) response, sizeResponse);
#else
    LOG_D("sizeof(TciCommandId_t) = %d", sizeof(TciCommandId_t));
    LOG_D("Request:  buffer = 0x%x size = %u", (uintptr_t) request, sizeRequest);
    LOG_D("Response: buffer = 0x%x size = %u", (uintptr_t) response, sizeResponse);
#endif

#ifdef __DEV_DEBUG__
    logRawByteArrayHex(request, _sizeRequest, "request raw data");
#else
   S_VAR_NOT_USED(_sizeRequest);
#endif

    TEE_Result status = TEE_ERROR_BAD_PARAMETERS;

    switch (commandId) {
        case TCI_CMD_ID_GENERATE_KEY:
        {
            const TciGenerateKeyPairMessage_t* pRequest = request;
            TIGER_CHECK_REQUEST_SIZE_RETURN();
            status = generateKeyPair(pRequest);
        }
        break;

        case TCI_CMD_ID_EXPORT_KEY:
        {
            const TciExportEntryMessage_t* pRequest = request;
            TciExportEntryResponse_t* pResponse = response;
            TIGER_CHECK_REQUEST_SIZE_RETURN();
            TIGER_CHECK_RESPONSE_SIZE_RETURN();
            status = exportKey(&(pRequest->kc.alias), pRequest->kc.uid, &(pResponse->entry));
        }
        break;

        case TCI_CMD_ID_DELETE_KEY:
        {
            const TciDeleteKeyPairMessage_t* pRequest = request;
            TIGER_CHECK_REQUEST_SIZE_RETURN();
            status = deleteKeyPair(&(pRequest->kc.alias), pRequest->kc.uid);
        }
        break;

        case TCI_CMD_ID_CLEAR_ALL:
        {
            status = clearAll(false);
        }
        break;

        case TCI_CMD_ID_EXISTS_KEY:
        {
            const TciExistsKeyPairMessage_t* pRequest = request;
            TIGER_CHECK_REQUEST_SIZE_RETURN();
            status = existKey(&(pRequest->kc.alias), pRequest->kc.uid);
        }
        break;

        case TCI_CMD_ID_INIT_SIGN:
        {
            const TciInitSignMessage_t* pRequest = request;
            TciInitSignResponse_t* pResponse = response;
            TIGER_CHECK_REQUEST_SIZE_RETURN();
            TIGER_CHECK_RESPONSE_SIZE_RETURN();
            status = initSign(pRequest, pResponse);
        }
        break;

        case TCI_CMD_ID_SIGN_FINISH:
        {
            const TciSignFinishRequest_t* pRequest = request;
            TciSignFinishResponse_t* pResponse = response;
            TIGER_CHECK_REQUEST_SIZE_RETURN();
            TIGER_CHECK_RESPONSE_SIZE_RETURN();
            status = finish(pRequest, &(pResponse->entry));
        }
        break;

        case TCI_CMD_ID_SAVE_ATTK_KEY:
        {
            const TciDrkDataMessage_t* pRequest = request;
            LOG_D("size of drk data message: 0x%08x", pRequest->size);
#ifdef __DEV_DEBUG__
            logRawByteArrayHex((uint8_t*)pRequest, pRequest->size + 4, "drk blob");
#endif
            TIGER_CHECK_REQUEST_SIZE_RETURN();
            status = saveAttestationKey(pRequest);
        }
        break;

        case TCI_CMD_ID_SSKDS_SET_STATUS:
        {
            const TciSskdsDeviceStatus_t* pRequest = request;
            TIGER_CHECK_REQUEST_SIZE_RETURN();
            status = setRegistrationStatus(pRequest->status);
        }
        break;

        case TCI_CMD_ID_CHECK_DEVICE_STATUS:
        {
            TciDeviceStatusResponse_t* pResponse = response;
            TIGER_CHECK_RESPONSE_SIZE_RETURN();
            status = getRegistrationStatus(&(pResponse->status));
        }
        break;

        case TCI_CMD_ID_SSKDS_SIGN:
        {
            const TciImportedData_t* pRequest = request;
            TciExportEntryResponse_t* pResponse = response;
            TIGER_CHECK_REQUEST_SIZE_RETURN();
            TIGER_CHECK_RESPONSE_SIZE_RETURN();
            pResponse->entry.size = MAX_EXPORT_SIZE_BYTES;
            status = signSskdsData(pRequest->bytes, pRequest->size, pResponse->entry.bytes, &pResponse->entry.size);
        }
        break;

        case TCI_CMD_ID_SSKDS_GET:
        {
            const TciSskdsGetData_t* pRequest = request;
            TciExportedData_t* pResponse = response;
            TIGER_CHECK_REQUEST_SIZE_RETURN();
            TIGER_CHECK_RESPONSE_SIZE_RETURN();
            status = getSskdsData(pRequest, pResponse);
        }
        break;

        case TCI_CMD_ID_EXPORT_DEVICE_ID:
        {
            TciExportEntryResponse_t* pResponse = response;
            TIGER_CHECK_RESPONSE_SIZE_RETURN();
            pResponse->entry.size = DEVICE_ID_SIZE;
            status = loadDeviceId(pResponse->entry.bytes, DEVICE_ID_SIZE);
        }
        break;

        case TCI_CMD_ID_IMPORT_CHIP_NAME:
        {
            const TciHardwareInfo_t* pRequest = request;
            TIGER_CHECK_REQUEST_SIZE_RETURN();
            uint8_t deviceId[DEVICE_ID_SIZE] = {0};
            status = generateDeviceId(pRequest->chipId, deviceId, sizeof(deviceId));
            TIGER_CHECK_TEE_STATUS_SUCCESS_RETURN("generateDeviceId");
            status = storeDeviceId(deviceId, sizeof(deviceId));
        }
        break;

        case TCI_CMD_ID_GET_UIDS:
        {
            TciExportEntryResponse_t* pResponse = response;
            TIGER_CHECK_RESPONSE_SIZE_RETURN();
            status = getClientUids(pResponse->entry.bytes, &pResponse->entry.size);
        }
        break;

        case TCI_CMD_ID_CLEAR_USER_DATA:
        {
            const TciClearUserDataMessage_t* pRequest = request;
            TIGER_CHECK_REQUEST_SIZE_RETURN();
            status = clearClientKeys(pRequest->uid);
        }
        break;

        case TCI_CMD_ID_CLEAR_SFS:
        {
            status = clearSFS();
        }
        break;

        case TCI_CMD_ID_SERVICE_CHECK_DEVICE_STATUS:
        {
            TciDeviceStatusResponse_t* pResponse = response;
            TIGER_CHECK_RESPONSE_SIZE_RETURN();
            status = getServiceDeviceStatus(&(pResponse->status));
        }
        break;

#ifdef TIGER_BUILD_TESTS
        case TCI_CMD_ID_RUN_TA_TESTS:
        {
            status = runTeeApiTests(sessionContext, request, sizeRequest, response, sizeResponse);
        }
        break;

#endif

#ifdef SVTS_CMD_ID_SUPPORT
        case TCI_CMD_ID_SVTS_SAVE_ATTK_CERT:
        {
            uint32_t cap = 1365;
            uint8_t* pRequest = request;

            if ((NULL == pRequest) || (sizeRequest != cap)) {
                LOG_E("Wrong request data, actual(%u), expected(%u)", sizeRequest, cap);
                return TEE_ERROR_BAD_PARAMETERS;
            }
            uint32_t size = *(uint32_t*)pRequest;
            status = saveToPersistentObject(TIGER_ATTK_CERT_ALIAS, pRequest + sizeof(uint32_t), size);
            TciDeviceStatusResponse_t* pResponse = response;
            pResponse->status = status;
        }
        break;

        case TCI_CMD_ID_SVTS_SAVE_ATTK_PRIV:
        {
            uint32_t cap = 1195;
            uint8_t* pRequest = request;

            if ((NULL == pRequest) || (sizeRequest != cap)) {
                LOG_E("Wrong request data, actual(%u), expected(%u)", sizeRequest, cap);
                return TEE_ERROR_BAD_PARAMETERS;
            }
            uint32_t size = *(uint32_t*)pRequest;
            status = saveAttk(pRequest + sizeof(uint32_t), size);
            TciDeviceStatusResponse_t* pResponse = response;
            pResponse->status = status;
        }
        break;

        case TCI_CMD_ID_SVTS_SAVE_DEVICE_CERT:
        {
            uint32_t cap = 1290;
            uint8_t* pRequest = request;

            if ((NULL == pRequest) || (sizeRequest != cap)) {
                LOG_E("Wrong request data, actual(%u), expected(%u)", sizeRequest, cap);
                return TEE_ERROR_BAD_PARAMETERS;
            }

            uint32_t size = *(uint32_t*)pRequest;
            status = saveToPersistentObject(TIGER_DRK_CERT_ALIAS, pRequest + sizeof(uint32_t), size);
            TciDeviceStatusResponse_t* pResponse = response;
            pResponse->status = status;
        }
        break;

        case TCI_CMD_ID_SVTS_REMOVE_ALL_FILES:
        {
            uint32_t cap = 0;
            uint8_t* pRequest = request;

            if ((NULL == pRequest) || (sizeRequest != cap)) {
                LOG_E("Wrong request data, actual(%u), expected(%u)", sizeRequest, cap);
                return TEE_ERROR_BAD_PARAMETERS;
            }
            status = deletePersistentObject((const uint8_t*)TIGER_REGISTRATION_INFO_ALIAS, strlen(((const char*)TIGER_REGISTRATION_INFO_ALIAS)));
            status += deletePersistentObject((const uint8_t*)TIGER_DRK_CERT_ALIAS, strlen(((const char*)TIGER_DRK_CERT_ALIAS)));
            status += deletePersistentObject((const uint8_t*)TIGER_DRK_CERT_ALIAS, strlen(((const char*)TIGER_DRK_CERT_ALIAS)));
            status += deletePersistentObject((const uint8_t*)TIGER_SESSION_ALIAS, strlen(((const char*)TIGER_SESSION_ALIAS)));

            TciDeviceStatusResponse_t* pResponse = response;
            pResponse->status = status;
        }
        break;
#endif

        default:
            status = TEE_ERROR_NOT_IMPLEMENTED;
        break;
    }

    LOG_FUNC_END

    return status;
}

TEE_Result clearAll(bool removeAttkCertificates) {
    LOG_FUNC_BEGIN;

    TEE_Result status = TEE_SUCCESS;
    TzwSfsObjectList_t objectEnumerator = TEE_HANDLE_NULL;

    do {
        status = tzwAllocateSfsObjectList(&objectEnumerator);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("tzwAllocateSfsObjectList failure.")

        status = tzwStartSfsObjectList(objectEnumerator);
        if (TEE_ERROR_ITEM_NOT_FOUND == status) {
            LOG_D("No object in the storage");
            status = TEE_SUCCESS;
            break;
        }
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("tzwStartSfsObjectList failure.")

        uint8_t objectID[MAX_OBJ_ID_SIZE_BYTES] = {0};
        uint32_t objectIDLen = 0;

        while (TEE_ERROR_ITEM_NOT_FOUND != tzwGetNextSfsObject(objectEnumerator, objectID, &objectIDLen)) {
            LOG_D("Deleting object: %.*s", objectIDLen, objectID);

            if ((!removeAttkCertificates) && (isPermanentObject(objectID, objectIDLen))) {
                    continue;
            }

            TzwSfsObject_t obj = TEE_HANDLE_NULL;
            status = tzwOpenSfsObject((void*) objectID, objectIDLen,
                    TEE_DATA_FLAG_ACCESS_READ | TEE_DATA_FLAG_ACCESS_WRITE | TEE_DATA_FLAG_ACCESS_WRITE_META,
                    &obj);
            if (TEE_SUCCESS != status) {
                LOG_E("TEE_OpenPersistentObject() failed. Result - %x ", status);
                continue;
            }
            tzwCloseAndDeleteSfsObject(obj);
        }
        status = TEE_SUCCESS;
    } while(0);

    tzwFreeSfsObjectList(objectEnumerator);

    LOG_FUNC_END;
    return status;
}

TEE_Result deleteKeyPair(const TciKeyAlias_t* const alias, TciProcessUid_t callingUid) {
    LOG_FUNC_BEGIN;

    TEE_Result status = TEE_SUCCESS;
    TigerObjectId_t* objId = NULL;
    status = tigerCreateKeyPairObjectId(alias, callingUid, &objId);
    TIGER_CHECK_TEE_STATUS_SUCCESS_RETURN("tigerCreateKeyPairObjectId");

    status = tigerDeleteKeyPair(objId);
    if (status != TEE_SUCCESS) {
        LOG_E("tigerDeleteKeyPair() failed.");
    }

    tigerFreeObjectId(objId);
    LOG_FUNC_END;
    return status;
}

TEE_Result exportKey(const TciKeyAlias_t* const alias, TciProcessUid_t callingUid, TciExportedData_t* key) {
    LOG_FUNC_BEGIN;

    TIGER_CHECK_FUNCTION_ARGUMENT_RETURN(alias != NULL);
    TIGER_CHECK_FUNCTION_ARGUMENT_RETURN(alias->length != 0);
    TIGER_CHECK_FUNCTION_ARGUMENT_RETURN(key != NULL);

    LOG_D("Exported certificate alias is %s", (const char*) alias->value);

    TEE_Result status = TEE_SUCCESS;
    TigerObjectId_t* objId = NULL;
    TigerObjectId_t* parentObjId = NULL;
    do {
        status = tigerCreateKeyPairObjectId(alias, callingUid, &objId);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("tigerCreateKeyPairObjectId");

        if(0 != tzwMemCompare(alias->value, SOTER_ASK_ALIAS, alias->length)) {
            status = tigerCreateAskKeyPairObjectId(SOTER_ASK_ALIAS, callingUid, &parentObjId);
            TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("tigerCreateKeyPairObjectId for parentObjectId");
        }
        key->size = MAX_EXPORT_SIZE_BYTES;
        status = tigerGenerateJsonCertificate(objId, parentObjId, callingUid, key->bytes, &key->size);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("tigerGenerateJsonCertificate");

        LOG_I("Generated JSON certificate. Length %d", key->size);
    } while(0);

    tigerFreeObjectId(objId);

    LOG_FUNC_END;
    return status;
}

TEE_Result generateKeyPair(const TciGenerateKeyPairMessage_t* const args) {
    LOG_FUNC_BEGIN;

    TIGER_CHECK_FUNCTION_ARGUMENT_RETURN(args != NULL);

    LOG_D("Start generate %.*s", args->kc.alias.length, args->kc.alias.value);

    TigerObjectId_t* objId = NULL;

    TEE_Result status = TEE_SUCCESS;
    do {
        status = tigerCreateKeyPairObjectId(&(args->kc.alias), args->kc.uid, &objId);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("tigerCreateKeyPairObjectId");

        status = generateAndSaveToPersistenObject(objId);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("generateAndSaveToPersistenObject");

        if (TEE_SUCCESS != status) {
            logTeeError(status, "Key generation failed: remove the key pair to avoid inconsistency.");
            // since something went wrong, we have to remove the key pair to avoid inconsistency
            tigerDeleteKeyPair(objId);
        }

        status = tigerIncCounter();
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("tigerIncrementCounter");

    } while (0);

    tigerFreeObjectId(objId);
    LOG_FUNC_END;

    return status;
}

TEE_Result existKey(const TciKeyAlias_t* const alias, TciProcessUid_t callingUid) {
    TIGER_CHECK_FUNCTION_ARGUMENT_RETURN(alias != NULL);

    TigerObjectId_t* objId = NULL;
    TEE_Result status = tigerCreateKeyPairObjectId(alias, callingUid, &objId);
    TIGER_CHECK_TEE_STATUS_SUCCESS_RETURN("tigerCreateKeyPairObjectId");

    status = tigerKeyPairExists(objId);
    tigerFreeObjectId(objId);
    return status;
}

TEE_Result generateAndSaveToPersistenObject(const TigerObjectId_t* objId) {
    LOG_FUNC_BEGIN;

    TIGER_CHECK_FUNCTION_ARGUMENT_RETURN(objId != NULL);
    // parentObjId can be NULL if it is ASK

    TigerKeyPair_t* keypair = NULL;
    TEE_Result status = TEE_SUCCESS;
    do {
        keypair = tigerAllocateKeyPair();
        TIGER_CHECK_BUFFER_ALLOCATED_BREAK(keypair);

        status = tigerGenerateKeyPair(keypair);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("tigerGenerateKeyPair");

        // try to save data
        status = tigerSaveKeyPair(objId, keypair);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("tigerSaveKeyPair");

    } while (0);

    // free memory
    tigerFreeKeyPair(keypair);

    LOG_FUNC_END;
    return status;
}

TEE_Result getClientUids(uint8_t* usersBuf, uint32_t* usersBufSize) {
    TIGER_CHECK_FUNCTION_ARGUMENT_RETURN(usersBuf != NULL);
    TIGER_CHECK_FUNCTION_ARGUMENT_RETURN(usersBufSize != NULL);

    const size_t uidSize = sizeof(TciProcessUid_t);
    TEE_Result status = TEE_SUCCESS;
    TzwSfsObjectList_t objectEnumerator = TEE_HANDLE_NULL;
    TigerObjectId_t* tigerObjId = NULL;
    *usersBufSize = 0;
    do {
        status = tzwAllocateSfsObjectList(&objectEnumerator);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("tzwAllocateSfsObjectList failure.")

        status = tzwStartSfsObjectList(objectEnumerator);
        if (TEE_ERROR_ITEM_NOT_FOUND == status) {
            LOG_D("No object in the storage");
            status = TEE_SUCCESS;
            break;
        }
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("tzwStartSfsObjectList failure.")

        tigerObjId = tigerAllocateObjectId();
        TIGER_CHECK_BUFFER_ALLOCATED_BREAK(tigerObjId)

        uint8_t objectId[MAX_OBJ_ID_SIZE_BYTES] = {0};
        uint32_t objectIdLen = 0;
        while (TEE_ERROR_ITEM_NOT_FOUND != tzwGetNextSfsObject(objectEnumerator, objectId, &objectIdLen)) {
            LOG_D("Found object: %.*s", objectIdLen, objectId);
            if (isPermanentObject(objectId, objectIdLen)) {
                continue;
            }

            status = tigerAssignObjectId(tigerObjId, objectId, objectIdLen);
            TIGER_CHECK_TEE_STATUS_SUCCESS_CONTINUE("tigerAssignObjectId")

            TciProcessUid_t objUid = 0;
            status = tigerGetUidFromObjectId(tigerObjId, &objUid);
            TIGER_CHECK_TEE_STATUS_SUCCESS_CONTINUE("tigerGetUidFromObjectId")

            LOG_D("userBufSize = %u", *usersBufSize);
            // TODO(v.kopp): since there is at least auth and ask keys uids will duplicate in the list
            tzwMemMove(&usersBuf[*usersBufSize], &objUid, uidSize);
            *usersBufSize += uidSize;
            if ((*usersBufSize) >= MAX_EXPORT_SIZE_BYTES) {
                LOG_E("Too many uids are in the storage: %u", *usersBufSize);
                status = TEE_ERROR_EXCESS_DATA;
                break;
            }
        }
        if (TEE_ERROR_EXCESS_DATA != status) {
            status = TEE_SUCCESS;
        }
    } while(0);

    tigerFreeObjectId(tigerObjId);
    tzwFreeSfsObjectList(objectEnumerator);

    return status;
}


TEE_Result clearClientKeys(TciProcessUid_t clientUid) {
    LOG_D("BEGIN----- %s(%u) -----", __func__, clientUid);

    TEE_Result status = TEE_SUCCESS;
    TzwSfsObjectList_t objectEnumerator = TEE_HANDLE_NULL;
    TigerObjectId_t* tigerObjId = NULL;
    do {
        status = tzwAllocateSfsObjectList(&objectEnumerator);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("tzwAllocateSfsObjectList.")

        status = tzwStartSfsObjectList(objectEnumerator);
        if (TEE_ERROR_ITEM_NOT_FOUND == status) {
            LOG_D("No objects in the storage");
            status = TEE_SUCCESS;
            break;
        }
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("tzwStartSfsObjectList")

        tigerObjId = tigerAllocateObjectId();
        TIGER_CHECK_BUFFER_ALLOCATED_BREAK(tigerObjId)

        uint8_t rawObjectID[MAX_OBJ_ID_SIZE_BYTES] = {0};
        uint32_t rawObjectIDLen = 0;
        while (TEE_ERROR_ITEM_NOT_FOUND != tzwGetNextSfsObject(objectEnumerator, rawObjectID, &rawObjectIDLen)) {
            if (isPermanentObject(rawObjectID, rawObjectIDLen)) {
                continue;
            }

            status = tigerAssignObjectId(tigerObjId, rawObjectID, rawObjectIDLen);
            TIGER_CHECK_TEE_STATUS_SUCCESS_CONTINUE("tigerAssignObjectId")

            TciProcessUid_t objUid = 0;
            status = tigerGetUidFromObjectId(tigerObjId, &objUid);
            TIGER_CHECK_TEE_STATUS_SUCCESS_CONTINUE("tigerGetUidFromObjectId")

            if (objUid == clientUid) {
                LOG_D("Deleting object: %.*s", rawObjectIDLen, rawObjectID);
                status = tigerDeleteKeyPair(tigerObjId);
                TIGER_CHECK_TEE_STATUS_SUCCESS_CONTINUE("tigerDeleteKeyPair")
            }
        }
        status = TEE_SUCCESS;
    } while(0);

    tzwFreeSfsObjectList(objectEnumerator);
    tigerFreeObjectId(tigerObjId);

    LOG_FUNC_END;
    return status;

}

TEE_Result getServiceDeviceStatus(TciDeviceStatus_t* deviceStatus) {
    LOG_FUNC_BEGIN;

   // *deviceStatus = getDeviceRegistrationStatus();

    *deviceStatus = TCI_DEVICE_NOT_REGISTERED;
    TzwSfsObject_t objHandle = TEE_HANDLE_NULL;
    TEE_Result status = TEE_ERROR_GENERIC;
    do {
        status = tzwOpenSfsObject((void*) TIGER_REGISTRATION_INFO_ALIAS, strlen(TIGER_REGISTRATION_INFO_ALIAS),
                                    TEE_DATA_FLAG_ACCESS_READ, &objHandle);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("Open device id object");

        // seek to device id in registration info file
        // this is not required because device Id is at the beginning of the file: offset is 0
        int32_t regCountOffset = getOffsetTo(REG_COUNT);
        TIGER_ASSERT(regCountOffset != -1);

        status = tzwSeekIntoSfsObject(objHandle, regCountOffset, TEE_DATA_SEEK_SET);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("Seek to device id");

        uint8_t loadedRegStatus = 0;
        uint32_t count = 0;
        status = tzwReadFromSfsObject(objHandle, &loadedRegStatus, sizeof(loadedRegStatus), &count);
        TIGER_CHECK_TEE_STATUS_SUCCESS_BREAK("Read from device id object");
        if (count != sizeof(loadedRegStatus)) {
            // this may happen for devices with old version of TA
            LOG_I("Could not read nb of registrations.");
        }

        LOG_I("Loaded registration status: %d", loadedRegStatus);
        if (loadedRegStatus > 0) {// 0 - not registered, >0 registered.
            *deviceStatus = TCI_DEVICE_REGISTERED;
        }
    } while(0);

    tzwCloseSfsObject(objHandle);

    LOG_FUNC_END;
    return status;
}
