/**
 * @file tees_secure_object.c
 * @brief Blowfish-compatible Secure object API implementation for <t-base driver
 * @author Iaroslav Makarchuk (i.makarchuk@samsung.com)
 * @date Created Oct 3, 2016
 * @par In Samsung Ukraine R&D Center (SURC) under a contract between
 * @par LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine) and
 * @par "Samsung Elecrtronics Co", Ltd (Seoul, Republic of Korea)
 * @par Copyright: (c) Samsung Electronics Co, Ltd 2015. All rights reserved.
 *
 * This software is proprietary of Samsung Electronics.
 * No part of this software, either material or conceptual may be copied
 * or distributed, transmitted, transcribed, stored in a retrieval system
 * or translated into any human or computer language in any form by any means,
 * electronic, mechanical, manual or otherwise, or disclosed to third parties
 * without the express written permission of Samsung Electronics.
 */

#include <tees_secure_object.h>

#include "tlStd.h"
#include "TlApi/TlApi.h"

#include <tee_prop_names.h>

#include <uuid_utils.h>
#define UNWRAP_FLAGS  (TLAPI_UNWRAP_PERMIT_DELEGATED |  \
                       TLAPI_UNWRAP_PERMIT_CONTEXT_TL | \
                       TLAPI_UNWRAP_PERMIT_CONTEXT_SP | \
                       TLAPI_UNWRAP_PERMIT_CONTEXT_DEVICE)

static inline TEE_Result TlApiResultToTeeResult(uint32_t tl_api_result) {
  switch (tl_api_result) {
    case TLAPI_OK: {
      return TEE_SUCCESS;
    }
    case E_TLAPI_INVALID_INPUT: {
      return TEE_ERROR_BAD_PARAMETERS;
    }
    case E_TLAPI_CR_WRONG_OUTPUT_SIZE: {
      return TEE_ERROR_SHORT_BUFFER;
    }
    default: {
      return TEE_ERROR_GENERIC;
    }
  }
}

TEE_Result TEES_WrapSecureObject(const unsigned char *in, uint32_t in_len,
                                 unsigned char *out, uint32_t *out_len,
                                 SO_AccessControlInfoType *ac) {

  TEE_Result result = TEE_ERROR_BAD_PARAMETERS;
  tlApiSpTrustletId_t consumerTid;
  mcSoContext_t context;

  uint32_t req_len = MC_SO_SIZE(0, in_len);

  if (!in || !in_len || !out_len) {
    goto exit;
  }

  if (*out_len < req_len) {
    *out_len = req_len;
    result = TEE_ERROR_SHORT_BUFFER;
    goto exit;
  }

  if (!out) {
    goto exit;
  }

  context = MC_SO_CONTEXT_DEVICE;
  consumerTid.spid = MC_SPID_RESERVED/*MC_SPID_SYSTEM*/; // updated due to the incorrect
                                                         // behavior of tlApiWrapObjectExt/
                                                         // (tlApiUnwrapObjectExt with this
                                                         // value set to MC_SPID_SYSTEM
  if (ac) {
    TEE_MemMove(consumerTid.uuid.value, ac->ta_id.uuid, sizeof(ac->ta_id.uuid));
  }

  if (ac && ac->access_flags) {
    /* Currently we don't support wrappting for the whole authority */
    if (ac->access_flags & DELEGATED_AUTH_ID_AC ||
        ac->access_flags & AUTH_ID_AC) {
      result = TEE_ERROR_NOT_SUPPORTED;
      goto exit;
    }

    context = MC_SO_CONTEXT_TLT;

    if (ac->access_flags & TA_ID_AC) {
      TEE_UUID own_uuid;

      result = TEE_GetPropertyAsUUID(TEE_PROPSET_CURRENT_TA,
                                     TA_APPID_PROP_NAME, &own_uuid);
      if (TEE_SUCCESS != result) {
        goto exit;
      }

      result = TeeUuidToUuid(&own_uuid, (uint8_t *)consumerTid.uuid.value,
                             sizeof(consumerTid.uuid.value));

      if (TEE_SUCCESS != result) {
        goto exit;
      }
    }
  }

  result = TlApiResultToTeeResult(tlApiWrapObjectExt(in, 0, in_len, out,
                                                     out_len, context,
                                                     MC_SO_LIFETIME_PERMANENT,
                                                     &consumerTid,
                                                     TLAPI_WRAP_DEFAULT));
exit:
  return result;
}

TEE_Result TEES_UnwrapSecureObject(const unsigned char *in, uint32_t in_len,
                                   unsigned char *out, uint32_t *out_len) {
  TEE_Result result = TEE_ERROR_BAD_PARAMETERS;

  uint32_t header_len = sizeof(mcSoHeader_t) + MC_SO22_HASH_SIZE
                        + MC_SO22_RND_SIZE;

  if (!in || in_len <= header_len || !out_len) {
    goto exit;
  }

  if (*out_len < in_len - header_len) {
    *out_len = in_len - header_len;
    result = TEE_ERROR_SHORT_BUFFER;
    goto exit;
  }

  if (!out) {
    goto exit;
  }

  result = TlApiResultToTeeResult(tlApiUnwrapObjectExt((void *)in, in_len, out,
                                                       out_len, UNWRAP_FLAGS));

exit:
  return result;
}
