
/*
 * =====================================================================================
 *
 *       Filename:  hdm_wrapper.c
 *
 *    Description:  HDM wrap/unwrap manipulation
 *
 *        Version:  1.0
 *        Created:  09/16/2019 15:26:11 PM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *        Company:  Samsung Electronics
 *        Copyright (c) 2015 by Samsung Electronics, All rights reserved.
 *
 * =====================================================================================
 */

/** Includes */
#include "hdm_wrapper.h"
#include "qsee_message.h"
#include "TZ_Vendor_tl.h"

#include "qsee_cfg_prop.h"

#define MAX_DISTNAME_PREFIX_SZ 128
#define MAX_TANAME_SZ 32
#define MAX_FULLNAME_SZ 160

static void get_alt_rot_distname(char *i_appname, char *o_distname)
{
        const char *prop_name = "alt_rot_domain_name_dot";
        uint32_t ret_size = 0;
        size_t len = 0;
        qsee_cfg_propvar_t *ptr = NULL;
        uint32_t prop[2+(MAX_DISTNAME_PREFIX_SZ / sizeof(uint32_t))] = {0};
        char distname_prefix[MAX_DISTNAME_PREFIX_SZ] = {0};

        if (QSEE_CFG_SUCCESS != qsee_cfg_getpropval(prop_name,
                                                        strlen(prop_name)+1, 0,
                                                        (qsee_cfg_propvar_t *)&prop,
                                                        sizeof(prop), &ret_size)) {
                HDM_LOG("alt_rot_domain_name_dot read failed, using legacy appname");
                ret_size = strlcpy(o_distname, i_appname, MAX_TANAME_SZ);
                return;
        }

        ptr = (qsee_cfg_propvar_t *)prop;
        len = ret_size - sizeof(*ptr) +2*sizeof(ptr->val) + 1;
        if (len > sizeof(distname_prefix)) {
                HDM_LOG("alt_rot_domain_name : len invalied, using lagacy appname");
                ret_size = strlcpy(o_distname, i_appname, MAX_TANAME_SZ);
                return;
        }

        memcpy(distname_prefix, &ptr->val[1], len -1);
        distname_prefix[len-1] = '\0';

        strlcpy(o_distname, distname_prefix, MAX_DISTNAME_PREFIX_SZ);
        strlcat(o_distname, i_appname, MAX_FULLNAME_SZ);
}

/**
 * @brief
 * decapsulate
 *
 * @param[in]  *decapsulate_ptr - decapsulate object 
 * @param[in]   decapsulate_ptr_len - decapsulate object length 
 * @param[out] *unwrap_ptr - unwrap_ptr object 
 * @param[out] *unwrap_ptr_len - unwrap_ptr object length
 *
 * @return HDM status code
 */
hdm_return_code_t decapsulate(uint8_t *decapsulate_ptr, uint32_t decapsulate_ptr_len, uint8_t *unwrap_ptr, uint32_t *unwrap_ptr_len)
{
        hdm_return_code_t ret = HDM_STATUS_SUCCESS;
        char src_app[MAX_FULLNAME_SZ+1] = {0};
        char skm_app_name[MAX_FULLNAME_SZ+1] = {0};

        HDM_LOG("decapsulate()");

        if (decapsulate_ptr_len == 0 || decapsulate_ptr_len > HDM_DRK_MAX_BUF_LEN)
        {
                HDM_LOG("decapsulate - Abnormal key length");
                ret = HDM_UNWRAP_KEY_LENGTH_FAILED;
                goto error;
        }

        HDM_LOG_DEBUG("decapsulate - Before decapsulate");
        
        ret = qsee_decapsulate_inter_app_message(
            src_app,
            decapsulate_ptr,
            decapsulate_ptr_len,
            unwrap_ptr,
            unwrap_ptr_len);
        HDM_LOG_DEBUG("decapsulate - After decapsulate: ret: %d src_app: %s decapsulate_ptr_len: %d unwrapped_ptr_len: %d", ret, src_app, decapsulate_ptr_len, *unwrap_ptr_len);
        if (ret != QSEE_MESSAGE_SUCESS)
        {
                HDM_LOG("decapsulate - qsee_decapsulate_inter_app_message() FAILED : %x", ret);
                ret = HDM_UNWRAP_DECAPSULATE_ERROR;
                goto error;
        }
        else {
                get_alt_rot_distname("skm", skm_app_name);
                if (strncmp(src_app, skm_app_name, strlen(skm_app_name) + 1))
                {
                        HDM_LOG_DEBUG("decapsulate - source app name \"%s\" was not \"%s\"", src_app, skm_app_name);
                        ret = HDM_UNWRAP_APP_NAME_FAILED;
                        goto error;
                }
        }
        HDM_LOG_DEBUG("wrap - Decapsulate successful, proceeding to wrap");
error:
        return ret;
}

/**
 * @brief
 * wrap
 *
 * @param[in] *unwrapped_ptr - wrapped object 
 * @param[in] unwrapped_ptr_len - wrapped object length
 * @param[out] *wrapped_ptr - wrapped object 
 * @param[out] *wrapped_ptr_len - wrapped object length
 *
 * @return HDM status code
 */
hdm_return_code_t wrap(uint8_t *unwrapped_ptr, uint32_t unwrapped_ptr_len, uint8_t *wrapped_ptr, uint32_t *wrapped_ptr_len)
{
        hdm_return_code_t ret = HDM_STATUS_SUCCESS;
        uint32_t wrap_ret;

        HDM_LOG("wrap()");

        HDM_LOG_DEBUG("wrap - Before wrap: unwrapped_ptr_len: %d MAX wrap_len: %d", unwrapped_ptr_len, *wrapped_ptr_len);
        wrap_ret = TZ_wrap_persist_data(
            (uint8_t *)"tz_hdm",
            strlen("tz_hdm"),
            unwrapped_ptr,
            unwrapped_ptr_len,
            wrapped_ptr,
            wrapped_ptr_len);
        HDM_LOG_DEBUG("wrap - After wrap: unwrapped_ptr_len: %d wrap_len: %d", unwrapped_ptr_len, *wrapped_ptr_len);
        if (wrap_ret != TZ_API_OK)
        {
                HDM_LOG("wrap - TZ_wrap_data FAILED: %d", wrap_ret);
                ret = HDM_UNWRAP_FAILED_WRAP;
        }

        return ret;
}

/**
 * @brief
 * unwrap
 *
 * @param[in]  *wrapped_ptr - wrapped object
 * @param[in]  *wrapped_ptr_len - wrapped object length
 * @param[in]  is_wrapped_key - is wrapped object (only for QC)
 * @param[out] *unwrapped_ptr - unwrapped object
 * @param[out] *unwrapped_ptr_len - unwrapped object length
 *
 * @return HDM status code
 */
hdm_return_code_t unwrap(uint8_t *wrapped_ptr, uint32_t *wrapped_ptr_len, uint32_t is_wrapped_key, uint8_t *unwrapped_ptr, uint32_t *unwrapped_ptr_len)
{
        uint32_t wrap_ret;

        if (*wrapped_ptr_len == 0 || *wrapped_ptr_len > HDM_DRK_MAX_BUF_LEN)
        {
                HDM_LOG("unwrap - Abnormal key length");
                HDM_LOG_DEBUG("unwrap - Abnormal key length wrapped_ptr_len = %d", *wrapped_ptr_len);
                return HDM_UNWRAP_KEY_LENGTH_FAILED;
        }

        if (is_wrapped_key == 0)
        {
                wrap_ret = decapsulate(wrapped_ptr, *wrapped_ptr_len, unwrapped_ptr, unwrapped_ptr_len);

                if(wrap_ret != HDM_STATUS_SUCCESS){
                        HDM_LOG_DEBUG("decapsulate Fail");
                        return wrap_ret;
                }

                TEE_MemFill(wrapped_ptr, 0, HDM_DRK_MAX_BUF_LEN);
                *wrapped_ptr_len = HDM_DRK_MAX_BUF_LEN;
                wrap_ret = wrap(unwrapped_ptr, *unwrapped_ptr_len, wrapped_ptr, wrapped_ptr_len);
                if(wrap_ret != HDM_STATUS_SUCCESS){
                        HDM_LOG_DEBUG("wrap Fail");
                        return wrap_ret;
                }
        }
        else
        {
                HDM_LOG("unwrap()");
                HDM_LOG("unwrap - Before unwrap - wrapped_ptr_len: %d unwrapped_ptr_len: %d", *wrapped_ptr_len, *unwrapped_ptr_len);
                wrap_ret = TZ_unwrap_persist_data(
                    (uint8_t *)"tz_hdm",
                    strlen("tz_hdm"),
                    wrapped_ptr,
                    *wrapped_ptr_len,
                    unwrapped_ptr,
                    unwrapped_ptr_len);
                HDM_LOG("unwrap - After unwrap - wrapped_ptr_len: %d unwrapped_ptr_len: %d", *wrapped_ptr_len, *unwrapped_ptr_len);
                if (wrap_ret == TZ_API_ERROR_NO_KEY)
                {
                        HDM_LOG("unwrap - TZ_unwrap_data FAILED with no key: %d", wrap_ret);
                        return HDM_UNWRAP_FAILED_NO_KEY;
                }
                else if (wrap_ret == TZ_API_ERROR_VERSION_MISMATCH)
                {
                        HDM_LOG("unwrap - TZ_unwrap_data FAILED with version mismatch error: %d", wrap_ret);
                        return HDM_UNWRAP_VERSION_MISMATCH;
                }
                if (wrap_ret != TZ_API_OK)
                {
                        HDM_LOG("unwrap - TZ_unwrap_data FAILED: %d", wrap_ret);
                        return HDM_UNWRAP_FAILED;
                }
        }

        return HDM_STATUS_SUCCESS;
}
