/**
 * @file       pa_tz_api.h
 * @brief      Process authenticator API for trusted applications
 *
 * Main purpose of this module is providing interface to authenticate
 * NWD process inside SWD using provided authentication handler.
 * @author     Ivan Vorobiov (i.vorobiov@samsung.com)
 * @version    1.0
 * @date       Created Feb 12, 2016
 * @copyright  In Samsung Ukraine R&D Center (SURC) under a contract between
 * @copyright  LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine) and
 * @copyright  "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
 * @copyright  Copyright: (c) Samsung Electronics Co, Ltd 2016. All rights reserved.
**/

/**
 * @defgroup handler_api API to create/destroy authentication handler
 */

/**
 * @defgroup swd_api API to authenticate NWd application from trusted application
 */

/**
 * @defgroup rules API to add special constrains to authentication procedure
 * @ingroup swd_api
 */

#ifndef __PA_TZ_API_H__
#define __PA_TZ_API_H__

#include <stddef.h>
#include "pa_handler.h"

/**
 * Return codes of PA SWD library
 * @ingroup swd_api
 */
typedef enum {
  PA_TZ_SUCCESS                      = 0x00000000,  //!< The operation is completed successfully
  PA_TZ_GENERAL_ERROR                = 0x00100000,  //!< The operation is completed with error
  PA_TZ_INVALID_HANDLER              = 0x00100001,  //!< The provided handler is invalid
  PA_TZ_DRIVER_COMM_ERROR            = 0x00100002,  //!< Error in sending command to driver
  PA_TZ_MEMORY_PERM_ERROR            = 0x00100003,  //!< Wrong memory type error
  PA_TZ_VIRT_TO_PHYS_ERROR           = 0x00100004,  //!< Error in convertation virtual address to physical
  PA_TZ_ENCODE_AUTHENTICATION_FAILED = 0x00100005,  //!< The process did not pass to encode ASN1
  PA_TZ_DECODE_AUTHENTICATION_FAILED = 0x00100006,  //!< The process did not pass to decode ASN1
  PA_TZ_NON_SUPPORTED                = 0x00100007,  //!< The function is not supported for this platform
  PA_TZ_CALLER_IS_FORBIDEN           = 0x00100008,  //!< The function can not be called by current caller
  PA_TZ_INCOMPATIBLE_RULES           = 0x00100009,  //!< The passed rules are incompatible with handler

  PA_TZ_AUTHENTICATION_FAILED        = 0x00100010,  //!< The process did not pass authentication
  PA_TZ_AF_TASK_IS_NOT_FOUND         = 0x00100011,  //!< The process is not found in process tree
  PA_TZ_AF_INTEGRITY_IS_NONE         = 0x00100012,  //!< FIVE cleared integrity of process
  PA_TZ_AF_INTEGRITY_IS_NOT_READY    = 0x00100013,  //!< FIVE does not calculate integrity yet
  PA_TZ_AF_CERTIFICATE_IS_ABSENT     = 0x00100014,  //!< Handler does not have pointer to certificate
  PA_TZ_AF_CERTIFICATE_IS_INCORRECT  = 0x00100015,  //!< Certificate has incorrect structure or signature
  PA_TZ_AF_CERTIFICATE_IS_NOT_MATCH  = 0x00100016,  //!< Certificate not from this process (mapping with corresponded to certificate FIVE hash is not found)
  PA_TZ_AF_APPNAME_IS_INCORRECT      = 0x00100017,  //!< The process has another application name
  PA_TZ_AF_TASK_HAS_DUPLICATE        = 0x00100018,  //!< There are task with the same application name in the kernel
  PA_TZ_AF_DEVICE_IS_COMPROMISED     = 0x00110019,  //!< Device is compromised

  PA_TZ_CRYPTO_ERRORS                = 0x00110000,  //!< General errors in crypto module
  PA_TZ_SINGATURE_VALIDATION_FAILURE = 0x00110001,  //!< Signature validation failed

  PA_TZ_PROCA_NOT_SUPPORTED          = 0x00120000   //!< PROCA does not support the model
} PaTzResult;

/**
 * Types of memory address
 * @ingroup rules
 */
typedef enum {
  PA_MEMORY_SWD_VA,  //!< Virtual Address of memory in SWD
  PA_MEMORY_NWD_VA,  //!< Virtual Address of memory in client process NWD
  PA_MEMORY_PHYS     //!< Physical Address of memory
} PaTzMemoryType;

/**
 * kPaHandlerTidUnusedMark constant
 * @ingroup swd_api
 */
enum {
  kPaHandlerTidUnusedMark = 0xD0EF3071
};

/**
 * @brief Memory range type
 * @ingroup rules
 */
typedef struct {
  uint64_t addr;        //!< Start address of memory range
  size_t size;          //!< Size of memory range
  PaTzMemoryType type;  //!< Type of memory range
} PaTzMemoryRange;

/**
 * @brief Process Authenticator Rules
 * @details Information that passed to Authenticator and enable additional
 * process checks. E.g. check command buffer owning.
 * @ingroup rules
 */
typedef void *PaTzRules;

/**
 * @brief Pre-defined constant values
 */
enum PaTzConstantValues {
  kPaIdLength = 32,  //!< Length of PA ID
  kMaximalNameNumbers = 10 //! Maximal possible name numbers
};

/**
 * @brief Information that is returned from authentication procedure
 * about corresponded process.
 * @ingroup swd_api
 */
typedef struct {
  uint8_t id[kPaIdLength];        //!< PA ID, hash of [package name + APK public key(in case of java application)]
  uint64_t is_android_app :1;     //!< Android package type (1- native, 0- android packages).
  uint64_t is_thirdparty_app :1;  //!< Third party type (1- third party, 0- pre-installed applications).
  uint64_t is_weak_integrity :1;  //!< Type flag of integrity (1- weak integrity, 0- strong integrity).
} ProcessInfo;

/**
 * @brief Creates handler from PID of target process
 * @details PID should be obtained from Normal World by your own manner.
 * @ingroup handler_api
 * @param [in] pid Process ID
 * @param [out] handler
 * @return ::PA_TZ_SUCCESS, ::PA_TZ_GENERAL_ERROR
 */
PaTzResult PaTzHandlerCreateFromPid(int pid, PaHandler *handler);

/**
 * @brief Creates handler from target process name
 * @details For native applications, use full path of the executed file. (e.g. /system/bin/my_app)
 * <br>For java applications(APK), use package name. (e.g. com.android.myapp)
 * @ingroup handler_api
 * @param [in] process_name Process name
 * @param [out] handler
 * @return ::PA_TZ_SUCCESS, ::PA_TZ_GENERAL_ERROR
 */
PaTzResult PaTzHandlerCreateFromProcessName(const char *process_name, PaHandler *handler);

/**
 * @brief Destroys the authentication handler
 * @ingroup handler_api
 * @param [in] handler PA handler
 */
void PaTzHandlerDestroy(PaHandler *handler);

/**
 * @brief Authenticate NWD process corresponded to handler
 * @details The function checks that a correct process is presence in NWD user-space
 * and it is authenticated.
 * @ingroup swd_api
 * @param [in] handler Authentication handler passed from NWD
 *
 * Example of usage:
 * @code
 * // Trustlet Entry
 * void tz_app_cmd_handler(void *cmd, uint32_t cmdlen, void *rsp, uint32_t rsplen){
 * {
 *      PaTzResult auth_result;
 *      PaHandler handler;
 *      PaTzResult result = PaTzHandlerCreateFromProcessName("com.android.myapp", &handler);
 *
 *      auth_result = PaTzAuthenticate(handler);
 *      if (PA_TZ_PROCA_NOT_SUPPORTED == auth_result)
 *      {
 *          // This device does not support PROCA.
 *      }
 *      else if (PA_TZ_SUCCESS != auth_result)
 *      {
 *          // Authentication is failed
 *          return;
 *      }
 * }
 * @endcode
 *
 * @return ::PA_TZ_SUCCESS, if authentication is completed successful,
 *         ::PA_TZ_AUTHENTICATION_FAILED, if authentication is failed,
 *         ::PA_TZ_INVALID_HANDLER, if provided authentication handler is incorrect,
 *         ::PA_TZ_GENERAL_ERROR, if unexpected error is occurred
 */
PaTzResult PaTzAuthenticate(const PaHandler handler);

/**
 * @brief Authenticate NWD process corresponded to handler and check memory owning
 * @details The Process Authenticator additionally checks that corresponded process
 * owns provided command buffer.  May return unique identifier of process.
 * @ingroup swd_api
 * @param [in] handler Authentication handler passed from NWD
 * @param [in] buffer,bufferSize Command buffer
 * @param [out] process_info Pointer to output structure. May be NULL.
 * @return ::PA_TZ_SUCCESS, if authentication is completed successful,
 *         ::PA_TZ_AUTHENTICATION_FAILED, if authentication is failed,
 *         ::PA_TZ_INVALID_HANDLER, if provided authentication handler is incorrect,
 *         ::PA_TZ_GENERAL_ERROR, if unexpected error is occurred
 */
PaTzResult PaTzAuthenticateWithCommandBuffer(const PaHandler handler,
    const void *buffer, size_t bufferSize, ProcessInfo *process_info);

/**
 * @brief Authenticate NWd process using provided authentication handler and set of rules
 * @details NWd application checks for integrity and having additional attributes.
 * Supported list of attributes:
 * 1. Process name
 * 2. Memory range (application should be owner of the memory)
 * General case is authenticate caller application and check that is owned command buffer.
 * May return unique identifier of process.
 *
 * Example of usage:
 * @code
 * // Trustlet Entry
 * void tz_app_cmd_handler(void *cmd, uint32_t cmdlen, void *rsp, uint32_t rsplen){
 * {
 *      PaTzResult auth_result;
 *      PaTzResult result;
 *      PaHandler handler;
 *      int pid; // get target pid in custom manner
 *      const char* allowed_process = "/system/bin/my_process";
 *      PaTzMemoryRange mem = {cmd, cmdlen, PA_MEMORY_SWD_VA};
 *
 *      PaTzRules rules = PaTzRulesCreate();
 *      result = PaTzRulesAddProcessName(rules, allowed_process);
 *      if (PA_TZ_SUCCESS != result) {
 *          PaTzRulesDestroy(rules);
 *      }
 *      result = PaTzRulesAddMemoryRange(rules, mem);
 *      if (PA_TZ_SUCCESS != result) {
 *          PaTzRulesDestroy(rules);
 *      }
 * 
 *      result = PaTzHandlerCreateFromPid(pid, &handler); 
 *
 *      auth_result = PaTzAuthenticateWithRules(handler, rules, NULL);
 *      if (PA_TZ_PROCA_NOT_SUPPORTED == auth_result)
 *      {
 *          // This device does not support PROCA.
 *      }
 *      else if (PA_TZ_SUCCESS != auth_result)
 *      {
 *          // Authentication is failed
 *          return;
 *      }
 * }
 * @endcode
 *
 * @ingroup swd_api
 * @param [in] handler Authentication handler passed from NWd
 * @param [in] rules Authentication rules that should be checked, e.g.
 *             process name, memory owning. Can be NULL (does not additional check).
 * @param [out] process_info Pointer to output structure. May be NULL.
 * @return ::PA_TZ_SUCCESS, if authentication is completed successful,
 *         ::PA_TZ_AUTHENTICATION_FAILED, if authentication is failed,
 *         ::PA_TZ_INVALID_HANDLER, if provided authentication handler is incorrect,
 *         ::PA_TZ_INCOMPATIBLE_RULES, if handler is created from process name and
 *               process name as rule also is provided
 *         ::PA_TZ_GENERAL_ERROR, if unexpected error is occurred
 */
PaTzResult PaTzAuthenticateWithRules(const PaHandler handler,
    const PaTzRules rules, ProcessInfo *process_info);

/**
 * @brief Creates authentication rules and return its pointer.
 * @warning The memory is allocated inside heap. Need to be freed after use
 * PaTzRulesDestroy()
 * @ingroup rules
 *
 * @return Authentication rules instance
 */
PaTzRules PaTzRulesCreate(void);

/**
 * @brief Add process name as authentication factor.
 * @details Corresponded authentication blob and real process must
 * have provided process name. 
 * This rule cannot be added when handler is created with process name.
 * @ingroup rules
 * @param [in, out] rules Authentication rules
 * @param [in] process_name NULL-terminated string with process name
 * @return ::PA_TZ_SUCCESS, ::PA_TZ_GENERAL_ERROR
 */
PaTzResult PaTzRulesAddProcessName(PaTzRules rules, const char *process_name);

/**
 * @brief Add memory range as authentication factor.
 * @details Corresponded process must be the owner of provided memory.
 * @ingroup rules
 * @param [in, out] rules Authentication rules
 * @param [in] memory Pointer to pa_tz_memory_range_t structure
 * @return ::PA_TZ_SUCCESS, ::PA_TZ_GENERAL_ERROR
 */
PaTzResult PaTzRulesAddMemoryRange(PaTzRules rules, const PaTzMemoryRange *memory);

/**
 * @brief Destroys the authentication rules.
 * @details Clear all provided information. Should never fail.
 * @ingroup rules
 * @param [in, out] rules Authentication rules
 */
void PaTzRulesDestroy(PaTzRules rules);

#endif /* __PA_TZ_API_H__ */
