/*
 * src/property.c
 *
 * Copyright (C) 2013, Samsung Electronics Co., Ltd.
 *
 * Properties' support
 */

#include <property.h>
#include "string.h"
#include <stdio.h>
#include <uuid.h>
#include <ta_custom_property.h>
#include <tee_internal_api.h>
#include "tee_prop_names.h"

#ifndef PLATFORM_LOG_TAG
#define PLATFORM_LOG_TAG "LIBGPAPI_PROP"
#endif
#include <tees_log.h>

#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof((arr)[0]))


char *strdup(const char *s);
extern char* uuid2string(const TEE_UUID* uuid, char* str); /* REMOVE */
extern char* u32_2string(const uint32_t* u_int, char* str);
/**
   Basic concepts:

   propSet - some set of properties in which we can find property by name, but
   can't iterate over propSet.

   enumerator - from the user point of view this is almost like propSet, but you
   CAN iterate over enumerator and get all properties.

   Implementation of propSet and enumerator is quite different. propSet is a
   tree of properties (see below) and 'keeps' data in property tree. Real root of
   tree of properties is stored in *_REAL variables(see below). Enumerator is
   just pointer somewhere inside of tree of properties and doesn't store any
   value.
*/


static struct __TEE_PropSetHandle ta_prop_root;
static struct __TEE_PropSetHandle client_prop_root;
static struct __TEE_PropSetHandle tee_prop_root;

enum prop_node_type {
    PROP_TYPE_DIR = 1,
    PROP_TYPE_LEAF = 2
};

enum prop_type {
    PROP_TYPE_STRING   = 1,
    PROP_TYPE_BOOL     = 2,
    PROP_TYPE_U32      = 3,
    PROP_TYPE_BINBLOCK = 4,
    PROP_TYPE_UUID     = 5,
    PROP_TYPE_IDENTITY = 6
} prop_type;

/**
   Properties are stored in a tree. Every node in the tree is a "struct prop_entry" type.
   Each property contains its name and has one of the types:
   PROP_TYPE_LEAF - for a terminating node (leaf of the tree)
   PROP_TYPE_DIR - for a non-terminating node

   leaf nodes contains pointer to the property value, dir node contains a list of its children nodes.

   For example tree containing only two properties "gpd.ta.appID" and
   "gpd.ta.singleInstance" looks like:

                          +----------------------+
                          | name = ""            |
                          | type = PROP_TYPE_DIR |
                          |                      |
                          +---------+------------+
                                    |
                                    |
                          +---------+------------+
                          | name = "gpd"         |
                          | type = PROP_TYPE_DIR |
                          |                      |
                          +---------+------------+
                                    |
                                    |
                                    |
                          +---------+------------+
                          | name = "ta"          |
                          | type = PROP_TYPE_DIR |
                          |                      |
                          +----------------------+
                              --/        \---
                            -/               \---
                         --/                     \---
                      --/                            \---
       +-------------/----------------+        +-----------\------------------+
       | name = "appID"               |        | name = "singleInstance"      |
       | type = PROP_TYPE_LEAF        |        | type = PROP_TYPE_LEAF        |
       | prop.type = PROP_TYPE_UUID   |        | prop.type = PROP_TYPE_BOOL   |
       | prop.size = sizeof(TEE_UUID) |        | prop.size = sizeof(bool)     |
       | prop.value = pointer to uuid |        | prop.value = pointer to bool |
       +------------------------------+        +------------------------------+
*/

struct prop_entry;

TAILQ_HEAD(prop_entry_list, prop_entry);

struct prop_entry {
    TAILQ_ENTRY(prop_entry) siblings;
    struct prop_entry * parent;
    enum prop_node_type node_type;
    const char * name;
/* if node_type == TYPE_DIR then 'children' should be used */
    union {
        struct {
            enum prop_type type;
            uint32_t size;
            void * value;
        } prop;
        struct prop_entry_list children;
    };
};

#ifdef CONFIG_ENABLE_TEE_DEBUG
#define IF_CONFIG_ENABLE_TEE_DEBUG(t, f) (t)
#else
#define IF_CONFIG_ENABLE_TEE_DEBUG(t, f) (f)
#endif

static TEE_UUID TEE_deviceID = { 0, 0, 0, {0,0,0,0,0,0,0,0}};
const TEE_UUID NilUuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
static unsigned int systemTimeProtectionLevel = 100;
static unsigned int TAPersistentTimeProtectionLevel = 100;
static unsigned int maxBigIntSize = 4 * 0xFFFF;

static bool ecc                      = true; /* elliptic curve cryptographic supported: Asymmetric Signature Schemes (ECDSA), Key Exchange Algorithms (ECDH) */
static unsigned int protectionLevel  = 100; /* anti rollback protection */
static char implementation_version_string[100] = "multibuild_gpapi";
static unsigned int implementation_version = 0;
static char firmware_manufacturer[] = "Samsung";
static bool securityIndicator      = true;  /* TRUE:Managed by TEE, FALSE:Managed by TA */
static unsigned int orientation    = 0x3;   /* 0x01:Portrait(Vertical Only), 0x02:Landscape(Horizontal Only), 0x3:Portrait or Landscape (Vertical or Horizontal) */
static unsigned int sessiontimeout = 10000; /* 10 seconds */
static char languages[3]           = "en";  /* ISO 693-1 codes */

/* TODO these properties should be configurable from TEE Admin Framework */
static uint32_t tee_dlm_data_available  = IF_CONFIG_ENABLE_TEE_DEBUG(64, 0);
static bool tee_debug_dlm_available = IF_CONFIG_ENABLE_TEE_DEBUG(true, false);
static uint32_t tee_pmr_data_available  = IF_CONFIG_ENABLE_TEE_DEBUG(64, 0);
static bool tee_debug_unlock_props  = false;

#ifdef CONFIG_ENABLE_TEE_SOCKETS
  static unsigned int socketsVersionNumber = SOCKET_VERSION; /* TEE Sockets. The version number of the specification the implementation conforms to */
#endif /* CONFIG_ENABLE_TEE_SOCKETS */

struct tee_prop_t {
    const char *name;
    int type;
    int size;
    char *value;
    TEE_Result (*init)(char *, int);
};

#ifdef CONFIG_CUSTOM_PROPERTY
/* This is a section created for the use of TAs that don't make use of user
 * defined properties. This section declaration resolves the required varaibles
 * __start_Custom_TA_property & __stop_Custom_TA_property
 */
DSO_EXPORT volatile const unsigned DUMMY__DECL __attribute__ ((section ("Custom_TA_property"), used));
#endif // CONFIG_CUSTOM_PROPERTY

static const struct tee_prop_t tee_prop[] = {
    {
        .name = "gpd.tee.apiversion",
        .type = PROP_TYPE_STRING,
        .size = 4,
        .value = "1.0",
    },
    {
        .name = "gpd.tee.description",
        .type = PROP_TYPE_STRING,
        .size = 37,
        .value = "Samsung Secure OS TEE Implementation",
    },
    {
        .name = "gpd.tee.deviceID",
        .type = PROP_TYPE_UUID,
        .size = sizeof (TEE_UUID),
        .value = (void *)&TEE_deviceID,
        .init = device_id_uuid_init,
    },
    {
        .name = "gpd.tee.systemTime.protectionLevel",
        .type = PROP_TYPE_U32,
        .size = sizeof (systemTimeProtectionLevel),
        .value = (void *)&systemTimeProtectionLevel,
    },
    {
        .name = "gpd.tee.TAPersistentTime.protectionLevel",
        .type = PROP_TYPE_U32,
        .size = sizeof (TAPersistentTimeProtectionLevel),
        .value = (void *)&TAPersistentTimeProtectionLevel,
    },
    {
        .name = "gpd.tee.arith.maxBigIntSize",
        .type = PROP_TYPE_U32,
        .size = sizeof (maxBigIntSize),
        .value = (void *)&maxBigIntSize,
    },
    {
        .name = "gpd.tee.cryptography.ecc",
        .type = PROP_TYPE_BOOL,
        .size = sizeof (ecc),
        .value = (void *)&ecc,
    },
    {
        .name = "gpd.tee.trustedStorage.antiRollback.protectionLevel",
        .type = PROP_TYPE_U32,
        .size = sizeof (protectionLevel),
        .value = (void *)&protectionLevel,
    },
    {
        .name = "gpd.tee.trustedos.implementation.version",
        .type = PROP_TYPE_STRING,
        .size = sizeof (implementation_version_string),
        .value = (void *)implementation_version_string,
    },
    {
        .name = "gpd.tee.trustedos.implementation.binaryversion",
        .type = PROP_TYPE_BINBLOCK,
        .size = sizeof (implementation_version),
        .value = (void *) &implementation_version,
    },
    {
        .name = "gpd.tee.firmware.manufacturer",
        .type = PROP_TYPE_STRING,
        .size = sizeof (firmware_manufacturer),
        .value = (void *)firmware_manufacturer,
    },
    {
        .name = "gpd.tee.tui.securityIndicator",
        .type = PROP_TYPE_BOOL,
        .size = sizeof (bool),
        .value = (void *)&securityIndicator,
    },
    {
        .name = "gpd.tee.tui.languages",
        .type = PROP_TYPE_STRING,
        .size = sizeof (languages),
        .value = (void *)&languages,
    },
    {
        .name = "gpd.tee.tui.orientation",
        .type = PROP_TYPE_U32,
        .size = sizeof (unsigned int),
        .value = (void *)&orientation,
    },
    {
        .name = "gpd.tee.tui.session.timeout",
        .type = PROP_TYPE_U32,
        .size = sizeof (unsigned int),
        .value = (void *)&sessiontimeout,
    },
    {
        .name = TEE_DBG_DLM_DATA_AVAILABLE_PROP_NAME,
        .type = PROP_TYPE_U32,
        .size = sizeof (uint32_t),
        .value = (void *)&tee_dlm_data_available,
    },
    {
        .name = TEE_DBG_PMR_DATA_AVAILABLE_PROP_NAME,
        .type = PROP_TYPE_U32,
        .size = sizeof (uint32_t),
        .value = (void *)&tee_pmr_data_available,
    },
    {
        .name = TEE_DBG_UNLOCK_PROP_NAME,
        .type = PROP_TYPE_BOOL,
        .size = sizeof (bool),
        .value = (void *)&tee_debug_unlock_props,
    },
    {
        .name = TEE_DBG_DLM_AVAILABLE_PROP_NAME,
        .type = PROP_TYPE_BOOL,
        .size = sizeof (bool),
        .value = (void *)&tee_debug_dlm_available,
    },
#ifdef CONFIG_ENABLE_TEE_SOCKETS
    {
        .name = "gpd.tee.sockets.version",
        .type = PROP_TYPE_U32,
        .size = sizeof (unsigned int),
        .value = (void *)&socketsVersionNumber,
    },
    {
        .name = "gpd.tee.sockets.tcp.version",
        .type = PROP_TYPE_U32,
        .size = sizeof (unsigned int),
        .value = (void *)&socketsVersionNumber,
    },
    {
        .name = "gpd.tee.sockets.tls.version",
        .type = PROP_TYPE_U32,
        .size = sizeof (unsigned int),
        .value = (void *)&socketsVersionNumber,
    },
#endif /* CONFIG_ENABLE_TEE_SOCKETS */
};

/** Allocates and attaches new node with name 'name' to node 'parent' */
static struct prop_entry * add_node(struct prop_entry *parent, const char *name, enum prop_node_type node_type)
{
    struct prop_entry *node = TEE_Malloc(sizeof(struct prop_entry), HINT_FILL_WITH_ZEROS);
    if (node == NULL) {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"Failed to allocate memory for property node\n");
        return NULL;
    }

    node->name = strdup(name);
    if (node->name == NULL) {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"Failed to allocate memory for node name\n");
        TEE_Free(node);
        return NULL;
    }
    node->parent = parent;
    node->node_type = node_type;
    TAILQ_INIT(&node->children);
    TAILQ_INSERT_HEAD(&parent->children, node, siblings);
    return node;
}

/** returns property with name "name" or NULL if no such property or this name is
    a DIR. Please note, that this function changes 'name'
*/
static struct prop_entry * get_prop_by_name(struct prop_entry *root,
                 char *name,
                 bool create_if_not_exists)
{
    struct prop_entry *tmp;
    bool is_dir;
    if (name == NULL) {
        return root;
    }

    /* name should point to a node name without dot symbols */
    char *next_dir = strstr(name, ".");
    if (next_dir) {
        *next_dir = '\0';
        next_dir++;
        is_dir = true;
    } else {
        is_dir = false;
    }

    if (root == NULL)
    {
        TEES_LOG(TEES_LOG_LEVEL_DEBUG,"root=%p\n", root);
        return NULL;
    }

    /* looking for suitable nodes among children */
    TAILQ_FOREACH(tmp, &root->children, siblings) {
        if (strcmp(tmp->name, name) == 0) {
            return get_prop_by_name(tmp, next_dir, create_if_not_exists);
        }
    }

    /* Node not found */
    if (create_if_not_exists) {
        root = add_node(root, name, is_dir ? PROP_TYPE_DIR : PROP_TYPE_LEAF);
        if (root == NULL) {
            return NULL;
        }
        return get_prop_by_name(root, next_dir, create_if_not_exists);
    }
    return NULL;
}

/** Looks for property with name 'name' inside tree 'root'
 @param root - root node of tree where property will be searched
 @param name - full name of property we are looking for
 @prop - return value, set to pointer on found property (if it's found)
 @return TEE_SUCCESS if property found, TEE_ERROR_ITEM_NOT_FOUND if it's not
 */

static TEE_Result find_prop_by_name(struct prop_entry *root,
                  const char *name,
                  struct prop_entry **prop)
{
    char *tmp_name = strdup(name);
     if (tmp_name == NULL) {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"Failed to allocate memory for porperty name\n");
        return TEE_ERROR_OUT_OF_MEMORY;
    }

    *prop = get_prop_by_name(root, tmp_name, false);
    TEE_Free(tmp_name);
     if (*prop == NULL || (*prop)->node_type != PROP_TYPE_LEAF) {
        return TEE_ERROR_ITEM_NOT_FOUND;
    } else {
        return TEE_SUCCESS;
    }
}


/** Adds property with name 'path' to the tree with root 'root'
 */
static TEE_Result add_prop_entry(struct prop_entry *root,
               const char *name,
               enum prop_type type,
               size_t size,
               const void *value)
{
    char *tmp_name = strdup(name);
    if (tmp_name == NULL) {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"Failed to allocate memory for porperty name\n");
        return TEE_ERROR_OUT_OF_MEMORY;
    }

    struct prop_entry *leaf = get_prop_by_name(root, tmp_name, true);
    TEE_Free(tmp_name);
    if (leaf == NULL) {
        return TEE_ERROR_OUT_OF_MEMORY;
    }

    leaf->prop.type = type;
    leaf->prop.size = size;
    leaf->prop.value = (void *)value;

    return TEE_SUCCESS;
}

/** set property with name 'prop' to value 'value' if leaf with name 'path'
  exists its size and content will be replaced by 'size' and 'value'
  appropriately. If such leaf does not exist it will be created (and all
  required dir nodes too). Data in 'value' will be copied in newly allocated
  memory.
*/
static TEE_Result set_prop_entry(struct prop_entry *root,
               const char *path,
               enum prop_type type,
               size_t size,
               const void *value)
{
    TEE_Result res;
    struct prop_entry *prop;
    void *new_value;

    res = find_prop_by_name(root, path, &prop);
    if (res != TEE_SUCCESS
     && res != TEE_ERROR_ITEM_NOT_FOUND) {
        return res;
    }

    new_value = TEE_Malloc(size, HINT_FILL_WITH_ZEROS);
    if (new_value == NULL) {
        return TEE_ERROR_OUT_OF_MEMORY;
    }
    TEE_MemMove(new_value, value, size);

    if (res == TEE_ERROR_ITEM_NOT_FOUND) {
        return add_prop_entry (root, path, type,
                               size, new_value);
    } else {
        if (prop->prop.value)
            TEE_Free(prop->prop.value);
        prop->prop.size = size;
        prop->prop.value = new_value;
    }

    return TEE_SUCCESS;
}

/** Creates 'root' node of tree
 */
static struct prop_entry *create_root_propset(void)
{
    struct prop_entry *root = TEE_Malloc(sizeof(struct prop_entry),HINT_FILL_WITH_ZEROS);
    if (!root) {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"Failed to allocate memory for property initialization\n");
        return NULL;
    }

    TAILQ_INIT(&root->children);
    root->node_type = PROP_TYPE_DIR;
    root->parent = NULL;
    root->name = strdup("");
    if (root->name == NULL) {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"Failed to allocate memory for root property name\n");
        TEE_Free(root);
        return NULL;
    }

    return root;
}

static void init_tee_propperties(void)
{
    tee_prop_root.prop = create_root_propset();
    if (tee_prop_root.prop == NULL) {
        TEE_Panic(TEE_ERROR_OUT_OF_MEMORY);
    }

    /* Call initialise functions */
    for (unsigned i = 0; i < ARRAY_SIZE(tee_prop); i++) {
        if (tee_prop[i].init) {
            TEE_Result ret = tee_prop[i].init(tee_prop[i].value, tee_prop[i].size);
            if (ret != TEE_SUCCESS) {
                TEE_Panic(ret);
            }
        }
    }

    /* Init TEE implementation properties */
    for (unsigned i = 0; i < ARRAY_SIZE(tee_prop); i++) {
        TEE_Result ret = set_prop_entry(tee_prop_root.prop,
                                        tee_prop[i].name,
                                        tee_prop[i].type,
                                        tee_prop[i].size,
                                        tee_prop[i].value);
        if (ret != TEE_SUCCESS) {
            TEE_Panic(ret);
        }
    }
}

static void init_ta_properties(const struct tainfo_packed * start_TA_property)
{
    TEE_Result ret;

    const struct tainfo_packed *taprop = start_TA_property;    

    ta_prop_root.prop = create_root_propset();
    if (ta_prop_root.prop == NULL) {
        TEE_Panic(TEE_ERROR_OUT_OF_MEMORY);
    }
    
    ret = set_prop_entry(ta_prop_root.prop, TA_APPID_PROP_NAME, PROP_TYPE_UUID,
                         sizeof (TEE_UUID), &taprop->uuid);
    if (ret != TEE_SUCCESS) {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"Failed to parse %s\n", TA_APPID_PROP_NAME);
        TEE_Panic(ret);
    }

    ret = set_prop_entry(ta_prop_root.prop, TA_SINGLEINSTANCE_PROP_NAME, PROP_TYPE_BOOL,
                         sizeof (bool), &taprop->singleInstance);
    if (ret != TEE_SUCCESS) {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"Failed to parse %s\n", TA_SINGLEINSTANCE_PROP_NAME);
        TEE_Panic(ret);
    }

    ret = set_prop_entry(ta_prop_root.prop, TA_MULTISESSION_PROP_NAME, PROP_TYPE_BOOL,
                         sizeof (bool), &taprop->multiSession);
    if (ret != TEE_SUCCESS) {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"Failed to parse %s\n", TA_MULTISESSION_PROP_NAME);
        TEE_Panic(ret);
    }

    ret = set_prop_entry(ta_prop_root.prop, TA_INSTANCEKEEPALIVE_PROP_NAME, PROP_TYPE_BOOL,
                         sizeof (bool), &taprop->instanceKeepAlive);
    if (ret != TEE_SUCCESS) {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"Failed to parse %s\n", TA_INSTANCEKEEPALIVE_PROP_NAME);
        TEE_Panic(ret);
    }

    ret = set_prop_entry(ta_prop_root.prop, TA_DATASIZE_PROP_NAME, PROP_TYPE_U32,
                         sizeof (unsigned int), &taprop->dataSize);
    if (ret != TEE_SUCCESS) {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"Failed to parse %s\n", TA_DATASIZE_PROP_NAME);
        TEE_Panic(ret);
    }

    ret = set_prop_entry(ta_prop_root.prop, TA_STACKSIZE_PROP_NAME, PROP_TYPE_U32,
                         sizeof (unsigned int), &taprop->stackSize);
    if (ret != TEE_SUCCESS) {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"Failed to parse %s\n", TA_STACKSIZE_PROP_NAME);
        TEE_Panic(ret);
    }

    ret = set_prop_entry(ta_prop_root.prop, TA_PRIV_TAAUTHORITY_PROP_NAME, PROP_TYPE_STRING,
                         strlen(taprop->ta_authority) + 1,
                         &taprop->ta_authority);
    if (ret != TEE_SUCCESS) {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"Failed to parse %s\n", TA_PRIV_TAAUTHORITY_PROP_NAME);
        TEE_Panic(ret);
    }

    ret = set_prop_entry(ta_prop_root.prop, TA_FIPSMODEENABLE_PROP_NAME, PROP_TYPE_BOOL,
                         sizeof (bool), &taprop->bFIPS_Mode_Enable);
    if (ret != TEE_SUCCESS) {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"Failed to parse %s\n", TA_FIPSMODEENABLE_PROP_NAME);
        TEE_Panic(ret);
    }

    ret = set_prop_entry(ta_prop_root.prop, TA_DBG_DLM_DATA_AVAILABLE_PROP_NAME, PROP_TYPE_U32,
                         sizeof (uint32_t), &taprop->dbg_dlm_data_available);
    if (ret != TEE_SUCCESS) {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"Failed to parse %s\n", TA_DBG_DLM_DATA_AVAILABLE_PROP_NAME);
        TEE_Panic(ret);
    }

    ret = set_prop_entry(ta_prop_root.prop, TA_DBG_PMR_DATA_AVAILABLE_PROP_NAME, PROP_TYPE_U32,
                         sizeof (uint32_t), &taprop->dbg_pmr_data_available);
    if (ret != TEE_SUCCESS) {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"Failed to parse %s\n", TA_DBG_PMR_DATA_AVAILABLE_PROP_NAME);
        TEE_Panic(ret);
    }

return;    


}

#ifdef CONFIG_CUSTOM_PROPERTY

static TEE_Result add_custom_ta_property(struct prop_custom *property, size_t propsize)
{
    TEE_Result ret = TEE_SUCCESS;

    /* sanity checks*/
    if ((!property) || (propsize == 0)) {
        return TEE_ERROR_BAD_PARAMETERS;
    }

    /* Add custom property, if exists */
    for (unsigned i = 0; i < propsize / sizeof(struct prop_custom); i++) {
        TEES_LOG(TEES_LOG_LEVEL_DEBUG,"Prop %d, name = %s\n", i, property[i].name);
        TEES_LOG(TEES_LOG_LEVEL_DEBUG,"Adding property %s, type=%d, size=%zu\n",
                property[i].name,
                property[i].type,
                property[i].size);
        ret = set_prop_entry(ta_prop_root.prop,
                             property[i].name,
                             property[i].type,
                             property[i].size,
                             property[i].value);
        if (ret != TEE_SUCCESS) {
            TEES_LOG(TEES_LOG_LEVEL_ERROR,"Error in adding custom property %d\n", ret);
            break;
        }
    }
    return ret;
}

static void init_custom_ta_properties(void)
{
    TEE_Result  res = TEE_SUCCESS;
    extern const char __start_Custom_TA_property;
    extern const char __stop_Custom_TA_property;
    const char *ptr_start = &__start_Custom_TA_property;
    const char *ptr_end = &__stop_Custom_TA_property;
    size_t section_size = (size_t)(ptr_end - ptr_start);

    TEES_LOG(TEES_LOG_LEVEL_DEBUG,"Adding Custom Properties\n");
    /* Sanity check for size */
    if ((section_size % sizeof(struct prop_custom)) != 0) {
        TEES_LOG(TEES_LOG_LEVEL_DEBUG,"No Valid User Defined Properties\n");
        return;
    }
    res = add_custom_ta_property((struct prop_custom *)ptr_start, section_size);
    if (res != TEE_SUCCESS) {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"Failed to Add user defined properties\n");
    }
    return;F
}
#endif // CONFIG_CUSTOM_PROPERTY

void init_properties(const void * start_TA_property)
{
    const struct tainfo_packed * _start_TA_property = (struct tainfo_packed *)start_TA_property;
    init_tee_propperties();
    init_ta_properties(_start_TA_property);
#ifdef CONFIG_CUSTOM_PROPERTY
    #error CONFIG_CUSTOM_PROPERTY is not implemented
    init_custom_ta_properties();
#endif /* CONFIG_CUSTOM_PROPERTY */
}

TEE_Result set_ident_prop_caid(void *caid)
{
    return set_prop_entry(client_prop_root.prop,
                          "samsung.ca.name",
                          PROP_TYPE_BINBLOCK,
                          CA_DIG_LEN,
                          caid);
}

TEE_Result set_client_ta_fips_enabled(bool fips_enabled)
{
    return set_prop_entry(client_prop_root.prop,
                          CLIENT_FIPSMODEENABLE_PROP_NAME,
                          PROP_TYPE_BOOL,
                          sizeof (bool),
                          &fips_enabled);
}

TEE_Result set_ident_prop(uint32_t login,
                          const TEE_UUID *uuid,
                          char *ta_authority)
{
    TEE_Result ret = TEE_SUCCESS;

    TEE_Identity ident = {.login = login,
                          .uuid = *uuid};

    ret = set_prop_entry(client_prop_root.prop,
                         "gpd.client.identity",
                         PROP_TYPE_IDENTITY,
                         sizeof(TEE_Identity),
                         &ident);

    if (ret != TEE_SUCCESS) {
        return ret;
    }

    ret = set_prop_entry(client_prop_root.prop,
                         "samsung.client.ta_authority",
                         PROP_TYPE_STRING,
                         strlen(ta_authority) + 1,
                         ta_authority);
    return ret;
}

TEE_Result property_set_client_session_id(const session_id_t *session_id)
{
    return set_prop_entry(client_prop_root.prop,
                          CLIENT_SESSION_ID_PROP_NAME,
                          PROP_TYPE_UUID,
                          sizeof(*session_id),
                          session_id);
}

/** returns first leaf under node 'parent' */
static struct prop_entry *get_first_leaf (struct prop_entry *parent)
{
    if (parent->node_type == PROP_TYPE_LEAF) {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"'parent' should be 'dir', looks like property internal issue\n");
        return parent;
    }
    struct prop_entry *child;
    TAILQ_FOREACH(child, &parent->children, siblings) {
        if (child->node_type == PROP_TYPE_LEAF) {
            return child;
        } else {
            return get_first_leaf(child);
        }
    }
    return NULL;
}

/** traverse through tree and looking for next leaf
 prop - leaf in a tree from which start looking
*/

static struct prop_entry* get_next_leaf(struct prop_entry *prop)
{
    /* if we at the root node we have to find first leaf*/
    if (prop->node_type == PROP_TYPE_DIR) {
        return get_first_leaf(prop);
    }

    while (prop->parent != NULL) {
        struct prop_entry *sibling = TAILQ_NEXT(prop, siblings);
        if (sibling == NULL) {
            /* That node is the last among siblings */
            /* Failed to find any leaf on this level, we have to go up one level and try again */
            prop = prop->parent;
            continue;
        }

        if (sibling->node_type == PROP_TYPE_DIR) {
            /* our sibling is dir, this mean he have at least one leaf */
            return get_first_leaf(sibling);
        } else {
            /* our sibling is leaf, return it */
            return sibling;
        }
    }

    return NULL;
}

/*
  TEE specification requires that four propSet defined:
  TEE_PROPSET_CURRENT_TA = 0xffffffff
  TEE_PROPSET_CURRENT_CLIENT = 0xfffffffe
  TEE_PROPSET_TEE_IMPLEMENTATION = 0xfffffffd
  TEE_PROPSET_CURRENT_CA = 0xfffffffc

  Every of that propSet contains its own set of properties. This function
  returns pointer on a real propSet or enumerator;
 */
static TEE_PropSetHandle get_real_enumerator(TEE_PropSetHandle propsetOrEnumerator)
{
    switch ((uintptr_t)propsetOrEnumerator) {
        case (uintptr_t)TEE_PROPSET_CURRENT_TA :
            return &ta_prop_root;

        case (uintptr_t)TEE_PROPSET_CURRENT_CLIENT :
            return &client_prop_root;

        case (uintptr_t)TEE_PROPSET_TEE_IMPLEMENTATION :
            return &tee_prop_root;

        default:
            return propsetOrEnumerator;
    }
}

static bool is_propset(TEE_PropSetHandle propsetOrEnumerator)
{
    return (get_real_enumerator(propsetOrEnumerator) != propsetOrEnumerator);
}

/* ------------ TEE implementation ------------ */
/* Helper for tests */
TEE_Result __TEE_SetProperty(
            const char *name,
            void *valueBuffer,
            size_t valueBufferLen,
            int type)
{
    return set_prop_entry(client_prop_root.prop,
                          name,
                          type,
                          valueBufferLen,
                          valueBuffer);
}


/* Helper function for GetPropertyAs... wrappers */
static TEE_Result __TEE_GetProperty(TEE_PropSetHandle propsetOrEnumerator,
                  const char *name,
                  void *valueBuffer,
                  uint32_t *valueBufferLen,
                  enum prop_type *type)
{
    struct prop_entry *prop;

    if (is_propset(propsetOrEnumerator)) {
        
        TEE_PropSetHandle enumerator = get_real_enumerator(propsetOrEnumerator);
        TEE_Result res = find_prop_by_name(enumerator->prop, name, &prop);
        if (res != TEE_SUCCESS) {
            return res;
        }
    } else {
        /* This is a propset, ignore name and return current property */
        prop = propsetOrEnumerator->prop;
    }

    if (prop == NULL) {
        /* enumerator not started or item missing */
        return TEE_ERROR_ITEM_NOT_FOUND;
    }
    *type = prop->prop.type;

    if (*valueBufferLen < prop->prop.size) {
        *valueBufferLen = prop->prop.size;
        return TEE_ERROR_SHORT_BUFFER;
    }

    TEE_MemMove(valueBuffer, prop->prop.value, (size_t)(prop->prop.size));
    *valueBufferLen = prop->prop.size;

    return TEE_SUCCESS;
}

static char base64_str[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static unsigned int mod_table[] = {0, 2, 1};

static char *base64_encode_str(const char *data,
            uint32_t input_length,
            uint32_t *output_length)
{
    uint32_t oct_1, oct_2, oct_3, triple;

    *output_length = 4 * ((input_length + 2) / 3) + 1;

    char *encoded_data = TEE_Malloc(*output_length, HINT_FILL_WITH_ZEROS);
    if (!encoded_data)
        return NULL;

    for (unsigned int i = 0, j = 0; i < input_length;) {

        oct_1 = i < input_length ? data[i++] : 0;
        oct_2 = i < input_length ? data[i++] : 0;
        oct_3 = i < input_length ? data[i++] : 0;

        triple = (oct_1 << 0x10) + (oct_2 << 0x08) + oct_3;

        encoded_data[j++] = base64_str[(triple >> 3 * 6) & 0x3F];
        encoded_data[j++] = base64_str[(triple >> 2 * 6) & 0x3F];
        encoded_data[j++] = base64_str[(triple >> 1 * 6) & 0x3F];
        encoded_data[j++] = base64_str[(triple >> 0 * 6) & 0x3F];
    }

    for (unsigned int i = 0; i < mod_table[input_length % 3]; i++)
        encoded_data[*output_length - 2 - i] = '=';

    encoded_data[*output_length - 1 ] = '\0';
    return encoded_data;
}

/**
   Make sure that enumeratos is indeed enumerator, throw error BAD_PARAMETERS otherwise.
   Macro must be used in all functions which works with enumerators only.
*/
#define CHECK_FOR_PROPSET(enumerator, ...)  do {                    \
        if (is_propset(enumerator)) {                               \
            TEES_LOG(TEES_LOG_LEVEL_ERROR,"%s can't be used for propset\n", __func__);  \
            return __VA_ARGS__ ;                                    \
        }                                                           \
    } while (0)

#define CHECK_FOR_PROPSET_OR_PANIC(enumerator, error_code)  do {    \
        if (is_propset(enumerator)) {                               \
            TEES_LOG(TEES_LOG_LEVEL_ERROR,"%s can't be used for propset\n", __func__);  \
            TEE_Panic(error_code);                                  \
        }                                                           \
    } while (0)

/** Make sure that enumerator started or throw error otherwise
 */
#define CHECK_ENUMERATOR_STARTED(enumerator, ...) do {  \
        if (enumerator->prop == NULL) {                 \
            return __VA_ARGS__;                         \
        }                                               \
    } while (0)

#define CHECK_IS_CORRECT_RETURN_VALUE(ret, allowed_ret1, allowed_ret2)  do {   \
        switch (ret) {                                                         \
        case TEE_SUCCESS:                                                      \
        case TEE_ERROR_OUT_OF_MEMORY:                                          \
        case allowed_ret1:                                                     \
        case allowed_ret2:                                                     \
            return (ret);                                                      \
        }                                                                      \
        TEE_Panic(ret);                                                        \
    } while (0)

/*
Description
The TEE_GetPropertyAsString function performs a lookup in a property set to retrieve an individual property
and convert its value into a printable string.
When the lookup succeeds, the implementation MUST convert the property into a printable
string and copy the result into the buffer described by valueBuffer and valueBufferLen.
Parameters
     propsetOrEnumerator: One of the TEE_PROPSET_XXX pseudo-handles or a handle on a property enumerator
     name: A pointer to the zero-terminated string containing the name of the property to retrieve.
    Its content is case-sensitive and it must be encoded in UTF-8.
    o If hPropSet is a property enumerator handle, name is ignored and can be NULL.
    o Otherwise, name cannot be NULL
     valueBuffer, valueBufferLen: Output buffer for the property value
Return Value
     TEE_SUCCESS: In case of success
     TEE_ERROR_ITEM_NOT_FOUND: If the property is not found or if name is not a valid UTF-8 encoding
     TEE_ERROR_SHORT_BUFFER: If the value buffer is not large enough to hold the whole property value
*/

TEE_Result TEE_GetPropertyAsString(
        TEE_PropSetHandle propsetOrEnumerator,
        const char *name,
        char *valueBuffer,
        uint32_t *valueBufferLen)
{
    TEE_Result res = TEE_SUCCESS;
    char bool_str[6];
    char uuid_str[37];
    char u32_str[11];
    enum prop_type type = PROP_TYPE_STRING;
    uint32_t size = *valueBufferLen;
    TEE_Identity tident;

    char *encoded_str;
    uint32_t encoded_size;

    res = __TEE_GetProperty(
        propsetOrEnumerator, name, valueBuffer, valueBufferLen, &type);
    if (res != TEE_SUCCESS && res != TEE_ERROR_SHORT_BUFFER) {
        if (res != TEE_ERROR_ITEM_NOT_FOUND && res != TEE_ERROR_OUT_OF_MEMORY) {
            TEE_Panic(res);
        }
        return res;
    }

    /* Convert prop type if needed */
    switch (type) {
    case PROP_TYPE_BOOL:
        *valueBufferLen = (uint32_t)sizeof(bool_str);
        if (size < (uint32_t)sizeof(bool_str))
            return TEE_ERROR_SHORT_BUFFER;

        if ((char)*valueBuffer == 0) {
            strncpy(bool_str, "false", 6);
        } else {
            strncpy(bool_str, "true", 5);
        }
        *valueBufferLen = (uint32_t)(strlen(bool_str)) + 1;

        strncpy(valueBuffer, bool_str, strlen(bool_str) + 1);
        break;

    case PROP_TYPE_BINBLOCK:
        encoded_size = 4 * ((*valueBufferLen + 2) / 3) + 1;

        if (size < encoded_size) {
            *valueBufferLen = encoded_size;
            return TEE_ERROR_SHORT_BUFFER;
        }

        encoded_str = base64_encode_str(valueBuffer,
        *valueBufferLen,
        &encoded_size);

        *valueBufferLen = encoded_size;
        if (!encoded_str)
            return TEE_ERROR_OUT_OF_MEMORY;

        TEE_MemMove(valueBuffer, encoded_str, (size_t)encoded_size);
        TEE_Free(encoded_str);

        break;

    case PROP_TYPE_U32:
        *valueBufferLen = (uint32_t)sizeof(u32_str);
        if (size < (uint32_t)sizeof(u32_str))
            return TEE_ERROR_SHORT_BUFFER;

        u32_2string((uint32_t*)(valueBuffer), u32_str);
        strncpy(valueBuffer, u32_str, sizeof(u32_str));
        break;
    case PROP_TYPE_UUID:
        *valueBufferLen = (uint32_t)sizeof(uuid_str);
        if (size < (uint32_t)sizeof(uuid_str))
            return TEE_ERROR_SHORT_BUFFER;

        uuid2string((TEE_UUID*)(valueBuffer), uuid_str);
        strncpy(valueBuffer, uuid_str, sizeof(uuid_str));
        break;
    case PROP_TYPE_IDENTITY:
        *valueBufferLen = 48;
        if (size < 48)
            return TEE_ERROR_SHORT_BUFFER;
        TEE_MemMove(&tident, valueBuffer, sizeof(TEE_Identity));
        {
            // Unpack uint32_t from packed structure to avoid unaligned access
            uint32_t u32 = tident.login;
            u32_2string(&u32, u32_str);
        }
        uuid2string(&tident.uuid, uuid_str);
        snprintf(valueBuffer, *valueBufferLen, "%s:%s", u32_str, uuid_str);
    case PROP_TYPE_STRING:
        break;

    default:
        TEE_Panic(TEE_ERROR_BAD_FORMAT);
        break;
    }

    return res;
}

/*
Description
The TEE_GetPropertyAsBool function retrieves a single property in a property set and converts its value to a Boolean.
If a property cannot be viewed as a Boolean, this function MUST return TEE_ERROR_BAD_FORMAT.
Otherwise, if this function succeeds, then calling the function TEE_GetPropertyAsString on the same name and with a sufficiently large output buffer MUST also succeed and return a string equal to true or false case-insensitive, depending on the value of the Boolean.
Parameters
     propsetOrEnumerator: One of the TEE_PROPSET_XXX pseudo-handles or a handle on a property enumerator
     name: A pointer to the zero-terminated string containing the name of the property to retrieve. Its content is case-sensitive and must be encoded in UTF-8.
    o If hPropSet is a property enumerator handle, name is ignored and can be NULL.
    o Otherwise, name cannot be NULL.
     value: A pointer to the variable that will contain the value of the property on success or false on error.
Return Value
     TEE_SUCCESS: In case of success
     TEE_ERROR_ITEM_NOT_FOUND: If the property is not found or if name is not a valid UTF-8 encoding
     TEE_ERROR_BAD_FORMAT: If the property value cannot be converted to a Boolean
*/
TEE_Result TEE_GetPropertyAsBool(
        TEE_PropSetHandle propsetOrEnumerator,
        const char *name,
        bool *value)
{
    TEE_Result res = TEE_SUCCESS;

    enum prop_type type = PROP_TYPE_BOOL;
    uint32_t size = (uint32_t)sizeof (bool);

    res = __TEE_GetProperty(
                  propsetOrEnumerator, name, value, &size, &type);

    if (type != PROP_TYPE_BOOL) {
        *value = false;
        return TEE_ERROR_BAD_FORMAT;
    }

    if (res != TEE_SUCCESS) {
        *value = false;
    }
    CHECK_IS_CORRECT_RETURN_VALUE(res, TEE_ERROR_ITEM_NOT_FOUND, TEE_ERROR_BAD_FORMAT);
}

/*
Description
The TEE_GetPropertyAsU32 function retrieves a single property in a property set and converts its value to a 32-bit unsigned integer.
If a property cannot be viewed as a 32-bit unsigned integer, this function MUST return TEE_ERROR_BAD_FORMAT.
Otherwise, if this function succeeds, then calling the function TEE_GetPropertyAsString on the same name and with a sufficiently
large output buffer MUST also succeed and return a string that is consistent with the following syntax:
integer: decimal-integer | hexadecimal-integer | binary-integer
decimal-integer: [0-9,_]+{K,M}?
hexadecimal-integer: 0[x,X][0-9,a-f,A-F,_]+
binary-integer: 0[b,B][0,1,_]+
Note that the syntax allows returning the integer either in decimal, hexadecimal, or binary format, that the
representation can mix cases and can include underscores to separate groups of digits, and finally that the decimal
representation may use K or M to denote multiplication by 1024 or 1048576 respectively.
For example, here are a few acceptable representations of the number 1024: 1K, 0X400, 0b100_0000_0000.
Parameters
     propsetOrEnumerator: One of the TEE_PROPSET_XXX pseudo-handles or a handle on a property enumerator
     name: A pointer to the zero-terminated string containing the name of the property to retrieve. Its content is
    case-sensitive and must be encoded in UTF-8.
    o If hPropSet is a property enumerator handle, name is ignored and can be NULL.
    o Otherwise, name cannot be NULL.
     value: A pointer to the variable that will contain the value of the property on success, or zero on error.
Return Value
     TEE_SUCCESS: In case of success
     TEE_ERROR_ITEM_NOT_FOUND: If the property is not found or if name is not a valid UTF-8 encoding
     TEE_ERROR_BAD_FORMAT: If the property value cannot be converted to an unsigned 32-bit integer
*/
TEE_Result TEE_GetPropertyAsU32(
        TEE_PropSetHandle propsetOrEnumerator,
        const char *name,
        uint32_t *value)
{
    TEE_Result res = TEE_SUCCESS;
    enum prop_type type = PROP_TYPE_U32;
    uint32_t size = (uint32_t)sizeof (uint32_t);

    res = __TEE_GetProperty(
                  propsetOrEnumerator, name, (char *)value, &size, &type);

    if (res == TEE_ERROR_SHORT_BUFFER
    || (res == TEE_SUCCESS && type != PROP_TYPE_U32)) {
        *value = 0;
        return TEE_ERROR_BAD_FORMAT;
    }

    if (res != TEE_SUCCESS) {
        *value = 0;
    }
    CHECK_IS_CORRECT_RETURN_VALUE(res, TEE_ERROR_ITEM_NOT_FOUND, TEE_ERROR_BAD_FORMAT);
}

/*
Description
The function TEE_GetPropertyAsBinaryBlock retrieves an individual property and converts its value into a binary block.
If a property cannot be viewed as a binary block, this function MUST return TEE_ERROR_BAD_FORMAT.
Otherwise, if this function succeeds, then calling the function TEE_GetPropertyAsString on the same name and
with a sufficiently large output buffer MUST also succeed and return a string that is consistent with a Base64 encoding
of the binary block as defined in RFC 2045 [6], section 6.8 but with the following tolerance:
 An Implementation is allowed not to encode the final padding = characters.
 An Implementation is allowed to insert characters that are not in the Base64 character set.
Parameters
     propsetOrEnumerator: One of the TEE_PROPSET_XXX pseudo-handles or a handle on a property enumerator
     name: A pointer to the zero-terminated string containing the name of the property to retrieve.
    Its content is case-sensitive and must be encoded in UTF-8.
    o If hPropSet is a property enumerator handle, name is ignored and can be NULL.
    o Otherwise, name cannot be NULL.
     valueBuffer, valueBufferLen: Output buffer for the binary block
Return Value
     TEE_SUCCESS: In case of success
     TEE_ERROR_ITEM_NOT_FOUND: If the property is not found or if name is not a valid UTF-8 encoding
     TEE_ERROR_BAD_FORMAT: If the property cannot be retrieved as a binary block
     TEE_ERROR_SHORT_BUFFER: If the value buffer is not large enough to hold the whole property value
*/

TEE_Result TEE_GetPropertyAsBinaryBlock(
        TEE_PropSetHandle propsetOrEnumerator,
        const char *name,
        void *valueBuffer,
        uint32_t *valueBufferLen)
{
    TEE_Result res = TEE_SUCCESS;
    enum prop_type type = PROP_TYPE_BINBLOCK;
    uint32_t bufferLen = *valueBufferLen;

    res = __TEE_GetProperty(
        propsetOrEnumerator, name,
        valueBuffer, &bufferLen, &type);

    if (type != PROP_TYPE_BINBLOCK) {
        memset(valueBuffer, 0, (size_t)(*valueBufferLen));
        return TEE_ERROR_BAD_FORMAT;
    }

    if (res != TEE_SUCCESS) {
        memset(valueBuffer, 0, (size_t)(*valueBufferLen));
    }
    *valueBufferLen = bufferLen;
    switch (res) {
    case TEE_SUCCESS:
    case TEE_ERROR_OUT_OF_MEMORY:
    case TEE_ERROR_ITEM_NOT_FOUND:
    case TEE_ERROR_BAD_FORMAT:
    case TEE_ERROR_SHORT_BUFFER:
        return res;
    }
    TEE_Panic(res);
}

/*
Description
The function TEE_GetPropertyAsUUID retrieves an individual property and converts its value into a UUID.
If a property cannot be viewed as a UUID, this function MUST return TEE_ERROR_BAD_FORMAT.
Otherwise, if this function succeeds, then calling the function TEE_GetPropertyAsString on the same name and with a
sufficiently large output buffer MUST also succeed and return a string that is consistent with the concrete syntax of UUIDs
defined in RFC 4122. Note that this string may mix character cases.
Parameters
     propsetOrEnumerator: One of the TEE_PROPSET_XXX pseudo-handles or a handle on a property enumerator
     name: A pointer to the zero-terminated string containing the name of the property to retrieve.
    Its content is case-sensitive and must be encoded in UTF-8.
    o If hPropSet is a property enumerator handle, name is ignored and can be NULL.
    o Otherwise, name cannot be NULL.
     value: A pointer filled with the UUID. Must not be NULL.
Return Value
     TEE_SUCCESS: In case of success
     TEE_ERROR_ITEM_NOT_FOUND: If the property is not found or if name is not a valid UTF-8 encoding
     TEE_ERROR_BAD_FORMAT: If the property cannot be converted into a UUID
*/
TEE_Result TEE_GetPropertyAsUUID(
        TEE_PropSetHandle propsetOrEnumerator,
        const char *name,
        TEE_UUID *value)
{
    TEE_Result res = TEE_SUCCESS;
    enum prop_type type = PROP_TYPE_UUID;
    uint32_t size = (uint32_t)sizeof (TEE_UUID);

    res = __TEE_GetProperty(
                  propsetOrEnumerator, name, value, &size, &type);

    if (res == TEE_ERROR_SHORT_BUFFER
    || (res == TEE_SUCCESS && type != PROP_TYPE_UUID)) {
        memset(value, 0, sizeof(TEE_UUID));
        return TEE_ERROR_BAD_FORMAT;
    }


    if (res != TEE_SUCCESS) {
        memset(value, 0, sizeof(TEE_UUID));
    }

    CHECK_IS_CORRECT_RETURN_VALUE(res, TEE_ERROR_ITEM_NOT_FOUND, TEE_ERROR_BAD_FORMAT);
}

/*
Description
The function TEE_GetPropertyAsIdentity retrieves an individual property and converts its value into a TEE_Identity.
If this function succeeds then retrieving the property as a printable string using
TEE_GetPropertyAsString must return a string consistent with the following syntax:
identity: integer (: uuid)?
where:
 The integer is consistent with the integer syntax described in the specification of the function TEE_GetPropertyAsU32 in section 4.4.3.
 If the identity UUID is Nil, then it can be omitted from the string representation of the property.
Parameters
     propsetOrEnumerator: One of the TEE_PROPSET_XXX pseudo-handles or a handle on a property enumerator
     name: A pointer to the zero-terminated string containing the name of the property to retrieve. Its content is case-sensitive and must be encoded in UTF-8.
    o If hPropSet is a property enumerator handle, name is ignored and can be NULL.
    o Otherwise, name cannot be NULL.
     value: A pointer filled with the identity. Must not be NULL.
Return Value
     TEE_SUCCESS: In case of success
     TEE_ERROR_ITEM_NOT_FOUND: If the property is not found or if name is not a valid UTF-8 encoding
     TEE_ERROR_BAD_FORMAT: If the property value cannot be converted into an Identity
*/
TEE_Result TEE_GetPropertyAsIdentity(
        TEE_PropSetHandle propsetOrEnumerator,
        const char *name,
        TEE_Identity *value)
{
    TEE_Result res = TEE_SUCCESS;
    enum prop_type type = PROP_TYPE_IDENTITY;
    uint32_t size = (uint32_t)sizeof (TEE_Identity);

    res = __TEE_GetProperty(
                  propsetOrEnumerator, name, value, &size, &type);

    if (res == TEE_ERROR_SHORT_BUFFER
       || (res == TEE_SUCCESS && type != PROP_TYPE_IDENTITY)) {
        memset(value, 0, sizeof(TEE_Identity));
        return TEE_ERROR_BAD_FORMAT;
    }

    if (res != TEE_SUCCESS) {
        memset(value, 0, sizeof(TEE_Identity));
    }
    CHECK_IS_CORRECT_RETURN_VALUE(res, TEE_ERROR_ITEM_NOT_FOUND, TEE_ERROR_BAD_FORMAT);
}

/*
Description
The function TEE_AllocatePropertyEnumerator allocates a property enumerator object. Once a handle on a
property enumerator has been allocated, it can be used to enumerate properties in a property set using the function
TEE_StartPropertyEnumerator.
Parameters
     enumerator: A pointer filled with an opaque handle on the property enumerator on success and with TEE_HANDLE_NULL on error
Return Value
     TEE_SUCCESS: In case of success
     TEE_ERROR_OUT_OF_MEMORY: If there are not enough resources to allocate the property enumerator
*/
TEE_Result TEE_AllocatePropertyEnumerator(
    TEE_PropSetHandle *enumerator)
{
    TEE_Result res = TEE_SUCCESS;

    *enumerator = TEE_Malloc(sizeof (struct __TEE_PropSetHandle), HINT_FILL_WITH_ZEROS);
    if (*enumerator == NULL) {
        res = TEE_ERROR_OUT_OF_MEMORY;
    }

    return res;
}

/*
Description
The function TEE_FreePropertyEnumerator deallocates a property enumerator object.
Parameters
     enumerator: A handle on the enumerator to TEE_Free
*/
void TEE_FreePropertyEnumerator(
    TEE_PropSetHandle enumerator)
{
    CHECK_FOR_PROPSET(enumerator);

    TEE_Free(enumerator);
}

/*
Description
The function TEE_StartPropertyEnumerator starts to enumerate the properties in an enumerator.
Once an enumerator is attached to a property set:
 Properties can be retrieved using one of the TEE_GetPropertyAsXXX functions, passing the enumerator handle as the
property set and NULL as the name.
 The function TEE_GetPropertyName can be used to retrieve the name of the current property in the enumerator.
 The function TEE_GetNextProperty can be used to advance the enumeration to the next property in the property set.
Parameters
     enumerator: A handle on the enumerator
     propSet: A pseudo-handle on the property set to enumerate. Must be one of the TEE_PROPSET_XXX pseudo-handles.
*/

void TEE_StartPropertyEnumerator(
    TEE_PropSetHandle enumerator,
    TEE_PropSetHandle propSet)
{
    CHECK_FOR_PROPSET(enumerator);
    enumerator->prop = get_first_leaf(get_real_enumerator(propSet)->prop);
}
/*
Description
The function TEE_ResetPropertyEnumerator resets a property enumerate to its state immediately after allocation.
If an enumeration is currently started, it is abandoned.
Parameters
     enumerator: A handle on the enumerator to reset
*/
void TEE_ResetPropertyEnumerator(
        TEE_PropSetHandle enumerator)
{
    CHECK_FOR_PROPSET(enumerator);
    if (enumerator) {
        memset(enumerator, 0, sizeof (struct __TEE_PropSetHandle));
    }
}

/*
Description
The function TEE_GetPropertyName gets the name of the current property in an enumerator.
The property name MUST be the valid UTF-8 encoding of a Unicode string containing no U+0000 code points.
Parameters
     enumerator: A handle on the enumerator
     nameBuffer, nameBufferLen: The buffer filled with the name
Return Value
     TEE_SUCCESS: In case of success
     TEE_ERROR_ITEM_NOT_FOUND: If there is no current property either because the enumerator has not started or
    because it has reached the end of the property set
     TEE_ERROR_SHORT_BUFFER: If the name buffer is not large enough to contain the property name
*/
TEE_Result TEE_GetPropertyName(
        TEE_PropSetHandle enumerator,
        void *nameBuffer,
        uint32_t *nameBufferLen)
{
    CHECK_FOR_PROPSET_OR_PANIC(enumerator, TEE_ERROR_BAD_PARAMETERS);
    CHECK_ENUMERATOR_STARTED(enumerator, TEE_ERROR_ITEM_NOT_FOUND);

    if (enumerator->prop->node_type == PROP_TYPE_DIR) {
        return TEE_ERROR_ITEM_NOT_FOUND;
    }

    uint32_t nameLen = strlen(enumerator->prop->name);
    /* traverse tree upward, calculating length of property full name */
    struct prop_entry *ancestor = enumerator->prop->parent;
    while (ancestor->parent != NULL) {
        nameLen += (uint32_t)strlen(ancestor->name) + 1;
        ancestor = ancestor->parent;
    }

    if (nameLen >= *nameBufferLen) {
        *nameBufferLen = nameLen + 1;
        return TEE_ERROR_SHORT_BUFFER;
    }
    *nameBufferLen = nameLen + 1;

    /* concatenating name of leaf and all its ancestors, please note that name
     * notation is reversed, so we have to fill nameBuffer starting from the
     * end */
    struct prop_entry *prop = enumerator->prop;
    char *name = (char*)nameBuffer + nameLen;

    while (prop->parent != NULL) {
        *name = '.';
        name -= strlen(prop->name);
        TEE_MemMove(name, prop->name, strlen(prop->name));
        name --;
        prop = prop->parent;
    }
    *((char*)nameBuffer + nameLen) = '\0';

    return TEE_SUCCESS;
}

/*
Description
The function TEE_GetNextProperty advances the enumerator to the next property.
Parameters
     enumerator: A handle on the enumerator
Return Value
     TEE_SUCCESS: In case of success
     TEE_ERROR_ITEM_NOT_FOUND: If the enumerator has reached the end of the property set or if it has not started
*/
TEE_Result TEE_GetNextProperty(
    TEE_PropSetHandle enumerator)
{
    CHECK_FOR_PROPSET_OR_PANIC(enumerator, TEE_ERROR_BAD_PARAMETERS);
    CHECK_ENUMERATOR_STARTED(enumerator, TEE_ERROR_ITEM_NOT_FOUND);

    struct prop_entry *leaf = get_next_leaf(enumerator->prop);

    if (leaf == NULL) {
        enumerator->prop = NULL;
        return TEE_ERROR_ITEM_NOT_FOUND;
    }

    if (leaf == enumerator->prop) {
        TEES_LOG(TEES_LOG_LEVEL_ERROR,"Trying to get next leaf, but get same leaf\n");
        TEE_Panic(TEE_ERROR_GENERIC);
    }
    enumerator->prop = leaf;

    return TEE_SUCCESS;
}

struct __TEE_PropSetHandle property_create_client_root(void)
{
    struct __TEE_PropSetHandle res;
    res.prop = create_root_propset();
    return res;
}

static void destroy_entry(struct prop_entry_list *parent, struct prop_entry *entry)
{
    struct prop_entry *node;
    struct prop_entry *tmp;

    if (entry->node_type == PROP_TYPE_DIR) {
        TAILQ_FOREACH_SAFE(node, &entry->children, siblings, tmp) {
            destroy_entry(&entry->children, node);
        }
    }

    if (parent) {
        TAILQ_REMOVE(parent, entry, siblings);
    }

    TEE_Free((void *)entry->name);
    TEE_Free(entry);
}

void property_destroy_client_root(void)
{
    destroy_entry(NULL, client_prop_root.prop);
    client_prop_root.prop = NULL;
}

void property_set_client_root(struct __TEE_PropSetHandle *root)
{
    if (root) {
        client_prop_root = *root;
    } else {
        client_prop_root.prop = NULL;
    }
}

