/*!
 * \file    wsm_api.h
 * \brief   New WSM API starting from version 3.
 * \author  Igor Savynikh (i.savynikh@samsung.com), Oleksii Chekanin (o.chekanin@samsung.com), Pavlo Marusyk (p.marusik@samsung.com)
 * \version 0.1
 * \date    Created Mar 31, 2017 10:00 AM
 * \par     In Samsung Kyiv R&D Center (SRK) under a contract between
 * \par     LLC "Samsung Electronics Ukraine Company" (Kyiv, Ukraine) and "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
 * \par     Copyright: (c) Samsung Electronics Co, Ltd 2017. All rights reserved.
 **/

#ifndef __WSM_H__
#define __WSM_H__

#include <stdint.h>
#include <stddef.h>

#include "wsm_definitions_v3.h"


#ifdef __cplusplus
extern "C" {
#endif // ifdef __cplusplus

/**
 * \brief WSM_Connect() makes all work to establish secure channel. Maximum amount of
 * simultaneously opened connections is restricted by <8>.
 *
 * \details This function is initial WSM call before any interactions with WSM.
 *
 * If there is no secure connection between 2 devices, WSM will establish it.
 * WSM will not create secure connection if it is already present!
 * In case of broken connection, this function re-establish it.
 *
 * The only output parameter is "id" generated by WSM and passed to another WSM API.
 *
 * WSM_Connect() replaces all Auth and ReAuth WSM API in versions 1 and 2
 * to rid Client Applications of routines.
 *
 * WSM version 1 and 2 provides capability to boost re-authentication by
 * using ESAPKey. Please avoid using this parameter, because it deprecated!
 * Starting from version 3.0.0 WSM will manage appropriate data by itself
 * without no efforts from Client Application.
 *
 * Please pay attention that WSM designed to support connections with several devices.
 * Client Application specifies unique transport information for each device(MAC address, port, UUID, etc.)
 * and call WSM_Connect() to establish connection with specified device.
 * In case of connection attempt to already connected device no additional connection will be done!
 *
 * \param [in] config - [configuration](@ref wsm_config_t) is an object with
 * all information required by WSM. Required fields are:
 * \li [transport](@ref wsm_transport_t) contains all information
 *   to setup connection via transport protocol. Required fields:
 * * identity;
 * * type;
 * * connection_timeout;
 * * read_timeout;
 * * client_socket - if identity is WSM_CLIENT or server if identity is WSM_SERVER
 * * protocol;
 * * callbacks if CA preferred to implement transport callbacks by itself;
 *
 * \li [auth](@ref wsm_auth_settings_t) contains information for authentication and re-authentication.
 * Required fields are:
 * * protocol;
 *   Set this variable to WSM_AUTH_PROTOCOL_V1 or WSM_REAUTH_PROTOCOL_V1 to work with WSM version 1.
 *   Please note that WSM provides smooth compatibility only with version 2! If CA doesn't set this variable
 *   WSM version 3 cannot establish connection with WSM version 1!
 *
 *   If you don't communicate via WSM version 1, use WSM_AUTH_PROTOCOL to initiate authentication
 *   or WSM_REAUTH_PROTOCOL for re-authentication.
 *
 * * options.server_id;
 * * options.client_id;
 *
 * * options.esap is a pointer to old WSM data "ESAPKey" and added to
 *   preserve backward compatibility with versions 1 and 2.
 *   Can be left uniniatilized if CA doesn't use it.
 *
 * * ESAP_key_update flag used only if options.esap.key points to byte array with ESAPKey.
 *
 * \param [in,out] session_id - unique identifier generated by WSM for each *connection* and associated with Client Application.
 * If Client Application opens connection with another device or another application, it receives new identifier for
 * connection with this second device. Old identifier for the first connection is still valid.
 * Another WSM functions use this identifier to find out which session interact with.
 *
 * \note In case of broken connection Client Application calls WSM_Connect() again and
 * pass pointer to variable with identifier generated for fist connection with specified device.
 *
 * \note All input data in config object is copied by WSM internally.
 *
 * \return returns 0 (WSM_SUCCESS) when connection established successfully,
 * otherwise - appropriate error code of type [wsm_result_t](@ref wsm_result_t):
 * \li WSM_ERR_INVALID_INPUT
 * \li WSM_ERR_OUT_OF_MEMORY
 * \li WSM_ERR_AUTHENTICATION
 * \li WSM_ERR_UNABLE_TO_CONNECT
 * \li WSM_ERR_BROKEN_CONNECTION
 * \li WSM_ERR_SYSTEM_ERROR
 *
 * \sa WSM_Disconnect
 */
wsm_result_t __attribute__((visibility("default")))
WSM_Connect(WSM_SESSION_ID *session_id, const wsm_config_t *config);

/*!
 * \brief WSM_CreateAppsKey() creates AppsKey used for symmetric encipherment
 * with [WSM_Send()](@ref WSM_Send()) and [WSM_Receive()](@ref WSM_Receive())
 *
 * \details This API call creates unique random encryption key for Client Application
 * according to *id* and stores it in *appkey_id* argument.
 *
 * \note AppsKey can be created only after successful execution of WSM_Connect()!
 *
 * \param [in] session: identifier of WSM session;
 * \param [out] appskey: identifier associated with created key when operation completed successfully;
 * \param [in] thread_id: identifier of thread communicate to;
 * \param [in] options: contains settings required for key creation (optional parameter for V3 api, can be NULL).
 *                      if options == NULL then options.type = WSM_APPSKEY_DEFAULT; options.length = WSM_APPSKEY_LENGTH_DEFAULT;
 *
 * \return [wsm_result_t](@ref wsm_result_t) value:
 * \li WSM_SUCCESS - successful execution
 * \li WSM_ERR_INVALID_INPUT - one of input arguments is wrong
 *
 * \sa WSM_DestroyAppsKey()
 */
wsm_result_t __attribute__((visibility("default")))
WSM_CreateAppsKey(const WSM_SESSION_ID session_id, WSM_APPSKEY_ID *appskey,
                  const wsm_thread_id_t thread_id, const wsm_appskey_options_t *options);

/*!
 * \brief WSM_Send() encrypts input "plaintext" data if requested
 * and sends it to remote device.
 *
 * \details This API call encrypt "plaintext" data according to mode using
 * key associated with "AppsKey" and then sends "ciphertext" to specified
 * "thread" on remote device associated with specified "session_id".
 *
 * \param [in] appskey: is an identifier of key created by "WSM_CreateAppsKey";
 * \param [in] ctx: a set of options defining current data transmission. Includes encipherment, thread id and some other features.
 * \param [in] plaintext: data to send through secure channel;
 * \param [in] plaintext_len: is amount of data in "plaintext" buffer in bytes. Should not be larger than WSM_MAX_MESSAGE_LENGTH.
 *
 * \return WSM_SUCCESS when operations complete successfully, otherwise
 * appropriate error code:
 * \li WSM_ERR_BROKEN_CONNECTION - transport connection has broken
 * \li WSM_ERR_INCOMPLETE_TRANSFER - sent bytes amount less than outcoming packet length
 * \li WSM_ERR_NOT_SUPPORTED - operation not supported. (only when "WSM_CRYPTO_MODE_DECRYPT_AND_WRAP" mode is set.
 * \li WSM_ERR_RECONNECT_REQUIRED - required to reconnect (call at first WSM_Disconnect() and after that WSM_Connect) because of error related to TrustZone
 *
 * \sa WSM_CreateAppsKey()
 * \sa WSM_Receive()
 */
wsm_result_t __attribute__((visibility("default")))
WSM_Send(const WSM_APPSKEY_ID appskey_id, const transmission_ctx_t *ctx, const uint8_t *plaintext,
         const uint32_t plaintext_len);
/*!
 * \brief WSM_Receive() receives WSM packet from remote device and decrypts it.
 *
 * \details This API call waits for data from remote device according to
 * [transport settings](@ref wsm_transport_settings_t) passed in [config](@ref wsm_config_t).
 * After that decrypt received encrypted data according to [mode](@ref wsm_crypto_mode) and store result in *out*.
 * Actual decrypted data length will be stored in *out_len*.
 *
 * \note Output value with mode WSM_DECRYPT_AND_WRAP will be wrapped after decryption.
 *
 * \param [in] appskey: is an identifier of key created by WSM_CreateAppsKey()
 * \param [in] ctx: a set of options defining current data transmission. Includes encipherment, thread id and some other features.
 * \param [out] buff: is a pointer to buffer where output result will be stored in.
 * \param [in,out] buff_size: is actual length of output data in buffer.
 *                            Should not be larger than WSM_MAX_MESSAGE_LENGTH.
 *                            If an error occurs, the return value is zero.
 *
 * \return WSM_SUCCESS when operation completed successfully, otherwise appropriate error code:
 * \li WSM_ERR_BROKEN_CONNECTION - transport connection has broken
 * \li WSM_ERR_INCOMPLETE_TRANSFER - received bytes amount less than incoming packet length
 * \li WSM_ERR_NOT_SUPPORTED - operation not supported. (only when
 *     "WSM_CRYPTO_MODE_DECRYPT_AND_WRAP" mode is set, but WSM works in NWD mode).
 * \li WSM_ERR_RECONNECT_REQUIRED - required to reconnect (call at first WSM_Disconnect() and after that WSM_Connect) because of error related to TrustZone
 * \li WSM_ERR_MESSAGE_BUFFER_FULL - received too many unexpected messages.
 * \sa WSM_CreateAppsKey()
 * \sa WSM_Send()
 */
wsm_result_t __attribute__((visibility("default")))
WSM_Receive(const WSM_APPSKEY_ID appskey, const transmission_ctx_t *ctx, uint8_t *buff,
            uint32_t *buff_size);

/*!
 * \brief WSM_destroyAppsKey() destroy encryption key specified by *id*.
 *
 * \details This API call removes key by *appkey_id* and releases all associated resources.
 * All further usages of this key will fail.
 *
 * \param [in] appskey: Identifier of key to destroy.
 *
 * \return [wsm_result_t](@ref wsm_result_t) value:
 * \li WSM_SUCCESS - successful execution
 * \li WSM_ERR_INVALID_INPUT - given key is incorrect or unknown.
 * \li WSM_ERR_RECONNECT_REQUIRED - required to reconnect (call at first WSM_Disconnect() and after that WSM_Connect) because of error related to TrustZone
 * \li WSM_ERR_SYSTEM_ERROR
 *
 * \sa WSM_CreateAppsKey()
 */
wsm_result_t __attribute__((visibility("default")))
WSM_DestroyAppsKey(const WSM_APPSKEY_ID appskey);


/*!
 * \brief WSM_Disconnect() closes secure channel between two already connected
 * devices and frees all acquired resources if any.
 *
 * \details This API call destroys all secure data (i.e. AppsKey's), frees all resources
 * and closes transport connection between 2 devices according to input argument *id*.
 * All further usages of *id* with WSM API will fail.
 *
 * \param [in] [id](@ref SESSION_ID) is a identifier returned by WSM_Connect().
 *
 * \return [wsm_result_t](@ref wsm_result_t) value:
 * \li WSM_SUCCESS - successful execution
 * \li WSM_ERR_DISCONNECT - Unable to disconnect
 * \li WSM_ERR_RECONNECT_REQUIRED - required to reconnect (call at first WSM_Disconnect() and after that WSM_Connect) because of error related to TrustZone
 *
 * \sa WSM_Connect
 */
wsm_result_t __attribute__((visibility("default")))
WSM_Disconnect(const WSM_SESSION_ID id);

//!< WSM Extensions API. It's optional and Client Application is able not use it at all.

/*!
 * \brief WSM_DelegatedWrap() wraps data to another TA.
 *
 * \details This API call generates confirm message for attestation TA using attestation TA nonce.
 * \since_tizen 2.3.1.5
 *
 * \note This method is optional and may be used in Client Application in SWd implementation only.
 * Only allow listed service can use this API.
 *
 * \param [in] [id](@ref SESSION_ID) - identifier of WSM Client Application
 * \param [in,out] [args](@ref wsm_wrap_args) points to object with all arguments required for wrapping.
 * Fields nonce, nonce_len, ta_name, ta_name_len, plain and plain_len must be initialized.
 * Fields with suffix len must contain actual length of data in appropriate array.
 *
 * \return [wsm_result_t](@ref wsm_result_t) value:
 * \li WSM_SUCCESS - successful execution
 * \li WSM_ERR_INVALID_INPUT - one of input arguments is wrong.
 */
wsm_result_t __attribute__((visibility("default")))
WSM_DelegatedWrap(const WSM_SESSION_ID id, wsm_wrap_args_t *args);

/*!
 * \brief WSM_Query() used for querying information about WSM.
 *
 * \details This API replaces next API from version 1 and 2:
 * \li is_WSM_connected() - check if WSM Library connected to WSM daemon.
 *
 * \li WSM_get_current_protocol_version() - get WSM protocol version.
 *   Please be aware that starting from version 3 WSM uses next versioning system: X.Y.Z.
 *   Where X is major version, Y is minor version, Z is patch version.
 *   For example initial version is 3.0.0.
 *
 * \li WSM_getESAPKey()
 * \li WSM_generateConfirmMessage()
 * \li WSM_getWSMEncKey()
 * \li WSM_getWSMConfirmKey()
 * \li WSM_generateNonce()
 *
 * Please see [enumeration](@ref wsm_request_type) for all requests.
 *
 * \param [in] [request](@ref wsm_request_type_t) denotes required information.
 * \param [in] [option](@ref wsm_query_option_t) include value to make requested data.
 * \param [out] [response](@ref wsm_response_t) contains requested data.
 * Returned answer depends on type of requested information.
 * Please see definition of [wsm_request_type_t](@ref wsm_request_type_t) to find out what field contains answer.
 * If answer is byte array, then notice that memory allocated by WSM. Callee is responsible to free it.
 *
 * \return [wsm_result_t](@ref wsm_result_t) value:
 * \li WSM_SUCCESS - successful execution
 * \li WSM_ERR_NOT_SUPPORTED - requested information is not supported by WSM version in use.
 */
wsm_result_t __attribute__((visibility("default")))
WSM_Query(const wsm_query_t type, const wsm_query_option_t *option, wsm_response_t *response);

/*!
 * \brief Encrypts input "plaintext" data
 *
 * \details This API call encrypt "plaintext" data according to mode using
 * key associated with "AppsKey"
 *
 * \note the WSM_Query with WSM_QUERY_GET_ENCRYPT_SIZE parameter can be used to get size of encrypted data.
 *
 * \param [in] appskey: is an identifier of key created by "WSM_CreateAppsKey";
 * \param [in] mode: specifies which encipherment should be used to encrypt
 * plaintext.
 * \param [in] plaintext: data to encrypt;
 * \param [in] plaintext_len: is amount of data in "plaintext" buffer in bytes.
 * \param [out] ciphertext: encrypted data; if it's set to NULL then function will return amount of data
 *                          required for encryption in ciphertext_len
 * \param [out] ciphertext_len: is amount of data in "ciphertext" buffer in bytes.
 *
 * \return WSM_SUCCESS when operations complete successfully, otherwise
 * appropriate error code:
 * \li WSM_ERR_NOT_SUPPORTED - operation not supported. (if incorrect crypto more was specified).
 * \li WSM_ERR_INVALID_INPUT - if encryption can't be performed using provided parameters.
 * \li WSM_ERR_RECONNECT_REQUIRED - required to reconnect (call at first WSM_Disconnect() and after that WSM_Connect) because of error related to TrustZone
 *
 * \sa WSM_CreateAppsKey()
 * \sa WSM_Decrypt()
 */
wsm_result_t __attribute__((visibility("default")))
WSM_Encrypt(const WSM_APPSKEY_ID appskey_id, const wsm_crypto_mode_t mode, const uint8_t *plaintext,
            const uint32_t plaintext_len, uint8_t *ciphertext, uint32_t *ciphertext_len);

/*!
 * \brief Decrypt specified ciphertext using key associated with specified key ID
 *
 * \details Result of the decrypted data according to [mode](@ref wsm_crypto_mode) will be stored to *plaintext*.
 * Actual decrypted data length will be stored in *plaintext_len*.
 *
 * \note Output value with mode WSM_DECRYPT_AND_WRAP will be wrapped after decryption.
 * It's mandatory to bind TA name to Appskey by WSM_Query(WSM_QUERY_SET_TA_NAME, ...)
 * before WSM_Decrypt() with mode WSM_DECRYPT_AND_WRAP.
 *
 * \param [in] appskey: is an identifier of key created by WSM_CreateAppsKey()
 * \param [in] mode: specifies which crypto function use to encrypt input plaintext.
 * \param [in] ciphertext: is a pointer to buffer will be encrypted.
 * \param [in] ciphertext_len: is actual length of buff.
 * \param [out] plaintext: is a pointer to buffer where output result will be stored in. If it's set to NULL
 *                         then function will return amount of data required for decrypted text in plaintext_len
 * \param [out] plaintext_len: is actual length of output data in buffer.
 *
 * \return WSM_SUCCESS when operation completed successfully, otherwise appropriate error code:
 * \li WSM_ERR_NOT_SUPPORTED - operation not supported. (if incorrect crypto mode was specified).
 * \li WSM_ERR_INVALID_INPUT - if decryption can't be performed using provided parameters.
 * \li WSM_ERR_RECONNECT_REQUIRED - required to reconnect (call at first WSM_Disconnect() and after that WSM_Connect) because of error related to TrustZone
 *
 * \sa WSM_CreateAppsKey()
 * \sa WSM_Encrypt()
 */
wsm_result_t __attribute__((visibility("default")))
WSM_Decrypt(const WSM_APPSKEY_ID appskey, const wsm_crypto_mode_t mode, uint8_t *ciphertext,
            const uint32_t ciphertext_len, uint8_t *plaintext, uint32_t *plaintext_len);

#ifdef __cplusplus
}
#endif // ifdef __cplusplus

#endif /* __WSM_H__ */
