aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/nRF5_SDK_15.0.0_a53641a/external/nrf_tls/mbedtls/tls_interface.c
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/external/nrf_tls/mbedtls/tls_interface.c')
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/external/nrf_tls/mbedtls/tls_interface.c1103
1 files changed, 1103 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/external/nrf_tls/mbedtls/tls_interface.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/external/nrf_tls/mbedtls/tls_interface.c
new file mode 100644
index 0000000..8319e99
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/external/nrf_tls/mbedtls/tls_interface.c
@@ -0,0 +1,1103 @@
+/**
+ * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ * Semiconductor ASA integrated circuit in a product or a software update for
+ * such product, must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <stdint.h>
+#include <stdbool.h>
+#include "nrf_error.h"
+#include "nrf_drv_rng.h"
+#include "app_fifo.h"
+#include "mem_manager.h"
+#include "mbedtls/ssl.h"
+#include "mbedtls/platform.h"
+#include "mbedtls/sha256.h"
+#include "mbedtls/debug.h"
+#include "nrf_tls.h"
+#include "nrf_assert.h"
+#include "iot_timer.h"
+#include "iot_errors.h"
+
+#if TLS_CONFIG_LOG_ENABLED
+
+#define NRF_LOG_MODULE_NAME TLS
+
+#define NRF_LOG_LEVEL TLS_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR TLS_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR TLS_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define TLS_LOG NRF_LOG_INFO /**< Used for getting trace of execution in the module. */
+#define TLS_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
+#define TLS_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
+
+#define TLS_ENTRY() TLS_TRC(">> %s", __func__)
+#define TLS_EXIT() TLS_TRC("<< %s", __func__)
+
+#else // TLS_CONFIG_LOG_ENABLED
+
+#define TLS_LOG(...) /**< Disables traces. */
+#define TLS_DUMP(...) /**< Disables dumping of octet streams. */
+#define TLS_ERR(...) /**< Disables error logs. */
+
+#define TLS_ENTRY(...)
+#define TLS_EXIT(...)
+
+#endif // TLS_CONFIG_LOG_ENABLED
+
+#define TIME_PERIOD_INVALID 0xFFFFFFFF /**< Identifier for invalid time period. Used for timer functions. */
+
+#define TLS_MUTEX_LOCK() SDK_MUTEX_LOCK(m_tls_mutex) /**< Lock module using mutex */
+#define TLS_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_tls_mutex) /**< Unlock module using mutex */
+
+/**
+ * @brief This macro is used for developer debugging.
+ *
+ * @note Not enabled nromally as too many logs result and this level of detail is needed
+ * less frequently.
+ */
+#define TLS_TRC(...)
+
+/**@brief TLS interface. */
+typedef struct
+{
+ uint32_t transport_id; /**< Transport identifier provided by the application to map the TLS instance with associated transport. Set by the application on allocation. */
+ nrf_tls_output_t output_fn; /**< Output function registered by the application to write TLS data on the transport. */
+ app_fifo_t input_fifo; /**< Input FIFO used for queueing up data received from the transport. Data on the transport us*/
+ app_fifo_t output_fifo; /**< Output FIFO used for queueing up decrypted data received on the TLS interface. */
+ mbedtls_ssl_context context; /**< SSL context used by mBedTLS for managing the TLS instance. */
+ mbedtls_ssl_config conf; /**< Pointer to the configuration paramaters used for the instance. Memory is allocated on nrf_tls_alloc. */
+#ifdef MBEDTLS_X509_CRT_PARSE_C
+ mbedtls_pk_context pkey; /**< Private key information. Used only when own certificate is provided. */
+ mbedtls_x509_crt * p_owncert; /**< Own parsed certificate. */
+ mbedtls_x509_crt * p_cacert; /**< CA's parsed certificate. */
+#endif // MBEDTLS_X509_CRT_PARSE_C
+ /**@brief Timer management used to provide timeouts to the TLS library. */
+ uint32_t start_tick; /**< Indicator (in milliseconds) of when the timeout was requested. */
+ uint32_t intrmediate_delay; /**< Period indicating intermediate timeout period in milliseconds. */
+ uint32_t final_delay; /**< Final timeout period in milliseconds. */
+} interface_t;
+
+
+#ifdef MBEDTLS_X509_CRT_PARSE_C
+
+/**@brief Input buffer size used for the input FIFO.
+ *
+ * @note For ECDHE-RSA, though the context length is set to a value smaller than 3072, a buffer size
+ * of 4k is needed for the cloud sends a certificate that does not fit the size.
+ * Also configuration of input FIFO is possible in powers of 2 therefore tuning this value to
+ * a smaller FIFO size to exactly the size of certificate size is not possible.
+ */
+#define INPUT_BUFFER_SIZE 4096
+
+#endif // MBEDTLS_X509_CRT_PARSE_C
+
+/**@brief Input buffer size when certificates are not used. */
+#ifndef INPUT_BUFFER_SIZE
+#define INPUT_BUFFER_SIZE MBEDTLS_SSL_MAX_CONTENT_LEN
+#endif // INPUT_BUFFER_SIZE
+
+/**@brief Output buffer size.
+ *
+ * @note Limiting to 1024 instead of MBEDTLS_SSL_MAX_CONTENT_LEN due to RAM constraints.
+ */
+#define OUTPUT_BUFFER_SIZE 1024
+
+
+static interface_t * m_interface[NRF_TLS_MAX_INSTANCE_COUNT]; /**< Interface table to manage the interfaces. */
+static uint8_t m_input_buffer[INPUT_BUFFER_SIZE * NRF_TLS_MAX_INSTANCE_COUNT]; /**< Input buffer that is statically reserved. */
+SDK_MUTEX_DEFINE(m_tls_mutex) /**< Mutex variable. Currently unused, this declaration does not occupy any space in RAM. */
+
+/**@brief Initializes the interface.
+ *
+ * @param[in] index Identifies instance in m_interface table to be initialized.
+ */
+static __INLINE void interface_init(uint32_t index)
+{
+ m_interface[index] = NULL;
+}
+
+
+/**@brief Wrapper function to avoid GCC errors with incompatible parameters.
+ *
+ * @param[in] n Number of blocks to be allocated.
+ * @param[in] s Size of each block to be assigned.
+ *
+ * @retval Pointer to memory block if procedure succeeded.
+ * @retval NULL if procedure failed.
+ */
+static __INLINE void * wrapper_calloc(size_t n, size_t s)
+{
+ return nrf_calloc(n,s);
+}
+
+
+/**@brief Frees and allocated interface instance.
+ *
+ *@param[in] p_instance Identifies the interface instance to be freed.
+ */
+static void interface_free(uint32_t index)
+{
+ interface_t * const p_interface = m_interface[index];
+
+ if (p_interface != NULL)
+ {
+ nrf_free(p_interface->input_fifo.p_buf);
+ nrf_free(p_interface->output_fifo.p_buf);
+#ifdef MBEDTLS_X509_CRT_PARSE_C
+ nrf_free(p_interface->p_cacert);
+ nrf_free(p_interface->p_owncert);
+#endif // MBEDTLS_X509_CRT_PARSE_C
+
+ mbedtls_ssl_config_free(&p_interface->conf);
+ mbedtls_ssl_config_init(&p_interface->conf);
+
+ mbedtls_ssl_free(&p_interface->context);
+
+ nrf_free(p_interface);
+ }
+ interface_init(index);
+}
+
+/**@brief Allocates an interface instance.
+ *
+ * @param[inout] p_instance Provides transport identifier for the TLS instance.
+ * And if procedure was successful, will conatin allocated TLS instance identifier.
+ * @param[in] TLS options to be used for the instamce.
+ *
+ * @retval NRF_SUCCESS if the procedure was successful, else an error code indicating reason
+ ( for failure.
+ */
+static uint32_t interface_alloc(nrf_tls_instance_t * p_instance,
+ nrf_tls_options_t const * p_options)
+{
+ uint32_t index = 0;
+ uint32_t err_code = NRF_TLS_NO_FREE_INSTANCE;
+ interface_t * p_interface = NULL;
+
+ TLS_ENTRY();
+
+ // allocate meory for the TLS instance.
+ for (index = 0; index < NRF_TLS_MAX_INSTANCE_COUNT; index++)
+ {
+ if (m_interface[index] == NULL)
+ {
+ err_code = (NRF_ERROR_NO_MEM | IOT_TLS_ERR_BASE);
+
+ // Check if we have space to book keep the instance information.
+ p_interface = nrf_malloc(sizeof(interface_t));
+
+ m_interface[index] = p_interface;
+ break;
+ }
+ }
+
+ if ((index < NRF_TLS_MAX_INSTANCE_COUNT)&& (p_interface != NULL))
+ {
+ // Initialize the memory holding the sturcture.
+ memset(p_interface, 0, sizeof(interface_t));
+
+ p_interface->output_fn = p_options->output_fn;
+
+ // Found free instance. Allocate memory for input and output queues.
+ uint8_t * p_input_memory = &m_input_buffer[INPUT_BUFFER_SIZE * index];
+ uint8_t * p_output_memory = (uint8_t *)nrf_malloc(OUTPUT_BUFFER_SIZE);
+
+ TLS_LOG("Input memory address %p", p_input_memory);
+ TLS_LOG("Output memory address %p", p_output_memory);
+
+ if (p_output_memory != NULL)
+ {
+ // Initialize the instance.
+ err_code = app_fifo_init(&p_interface->input_fifo,
+ p_input_memory,
+ INPUT_BUFFER_SIZE);
+
+ TLS_LOG("Input FIFO init result %08lx", err_code);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = app_fifo_init(&p_interface->output_fifo,
+ p_output_memory,
+ OUTPUT_BUFFER_SIZE);
+
+ TLS_LOG("Output FIFO init result %08lx", err_code);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ // All pre-requisites for using the instance met.
+ // Procedure was successful.
+ TLS_LOG("Ind");
+
+ p_interface->transport_id = p_instance->transport_id;
+ p_instance->instance_id = index;
+ }
+ }
+
+ if (err_code != NRF_SUCCESS)
+ {
+ err_code = (NRF_ERROR_INTERNAL | IOT_TLS_ERR_BASE);
+ }
+ }
+
+ if (err_code != NRF_SUCCESS)
+ {
+ TLS_ERR("Allocation failed - Initialization procedures.");
+ interface_free(index);
+ }
+ }
+ else
+ {
+ TLS_ERR("Allocation failed - Inadequate memory.");
+ }
+
+ return err_code;
+}
+
+
+/**@brief Transport read function registered with the TLS library.
+ *
+ * @details Data read on the transport is fed to the interface using the nrf_tls_input function.
+ * The TLS library requests the data based on state of SSL connection.
+ *
+ * @param[in] p_ctx Context registered with the library on creation of the TLS instance.
+ * @param[out] p_buffer Buffer where read data is fetched.
+ * @param[in] size Size to be read.
+ *
+ * @retval size of data read if procedure was successful.
+ * @retval MBEDTLS_ERR_SSL_CONN_EOF indicating there is not enough data received on the transport.
+ */
+static int interface_transport_read(void * p_ctx, unsigned char * p_buffer, size_t buffer_size)
+{
+ uint32_t err;
+ uint32_t length = buffer_size;
+ interface_t * const p_interface = m_interface[(uint32_t)p_ctx];
+ uint32_t available_size = 0;
+
+ TLS_MUTEX_LOCK();
+
+ TLS_TRC("[%p]: interface_transport_read requested %08x",
+ p_interface,
+ buffer_size);
+
+ // Verify how much data is available in the queue.
+ err = app_fifo_read(&p_interface->input_fifo, NULL, &available_size);
+
+ TLS_TRC("[%p]: interface_transport_read, app_fifo_read result %ld",
+ p_interface,
+ err);
+
+ // For datagram connection, read all that is available.
+ // For stream sockets, read only if available data is at least as much as requested.
+ if (( (p_interface->conf.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) &&
+ (available_size > 0) )||
+ ( (p_interface->conf.transport == MBEDTLS_SSL_TRANSPORT_STREAM) &&
+ (available_size >= buffer_size)) )
+ {
+ TLS_TRC("[%p]: interface_transport_read requested 0x%08x, available %08lx.",
+ p_interface,
+ buffer_size,
+ available_size);
+
+ err = app_fifo_read(&p_interface->input_fifo, p_buffer, &length);
+
+ if (err == NRF_SUCCESS)
+ {
+ TLS_TRC("[%p]: interface_transport_read success, length 0x%08lx.",
+ p_interface,
+ length);
+
+ TLS_TRC("[NRF TLS]: ---------------- SSL Read data --------------");
+ TLS_DUMP(p_buffer, length);
+ TLS_TRC("[NRF TLS]: -------------------- End ------------------");
+
+ return length;
+ }
+ }
+ else
+ {
+ TLS_TRC("[%p]: interface_transport_read requested size 0x%08x, "
+ "available 0x%08lx.",
+ p_interface,
+ buffer_size,
+ available_size);
+ }
+
+ TLS_MUTEX_UNLOCK();
+
+ return MBEDTLS_ERR_SSL_CONN_EOF;
+}
+
+
+/**@brief Write function that the TLS library calls to write on the transport.
+ *
+ * @param[in] p_ctx Context registered with the library on creation of the TLS instance.
+ * @param[in] p_buf Buffer containing data to be written on the transport.
+ * @param[in] len Length of data to be written.
+ *
+ * @retval length of data written on the transport if the procedure was successful.
+ * @retval MBEDTLS_ERR_SSL_CONN_EOF in case the procedure failed.
+ */
+static int interface_transport_write(void * p_ctx, const unsigned char * p_buf, size_t len)
+{
+ int op_len = len;
+ interface_t * const p_interface = m_interface[(uint32_t)p_ctx];
+
+ TLS_MUTEX_LOCK();
+
+ const nrf_tls_instance_t handle = {
+ .transport_id = p_interface->transport_id,
+ .instance_id = (uint32_t)p_ctx
+ };
+
+ TLS_LOG("[%p]: interface_transport_write requested 0x%08x",
+ p_interface, len);
+
+ TLS_MUTEX_UNLOCK();
+
+ uint32_t err_code = p_interface->output_fn(&handle, (uint8_t *)p_buf, len);
+
+ TLS_MUTEX_LOCK();
+
+ if (err_code != NRF_SUCCESS)
+ {
+ op_len = MBEDTLS_ERR_SSL_CONN_EOF;
+ }
+
+ TLS_MUTEX_UNLOCK();
+
+ return op_len;
+}
+
+
+/**
+ * @brief Random number generator registered with the TLS library to create random numbers
+ * when needed.
+ *
+ * @param[in] p_ctx Context registered with the library on creation of the TLS instance.
+ * @param[out] p_buffer Buffer where generated random vector is to be fetched.
+ * @param[in] size Requested size of the random vector.
+ *
+ * @retval 0 when procedure is successful.
+ *
+ * @note This loop is time critical when available is less than requested size.
+ */
+static int random_vector_generate(void * p_ctx, unsigned char * p_buffer, size_t size)
+{
+ uint8_t available = 0;
+
+ ASSERT(size <= RNG_CONFIG_POOL_SIZE);
+
+ while (available < size)
+ {
+ nrf_drv_rng_bytes_available(&available);
+
+ TLS_TRC(">> random_vector_generate, requested 0x%08lx, available 0x%08x",
+ size,
+ available);
+ }
+
+ UNUSED_RETURN_VALUE(nrf_drv_rng_rand(p_buffer, size));
+
+ return 0;
+}
+
+
+/**@brief Routine called periodically to adavnce the SSL context state.
+ *
+ * @param[in] index Identifies the instance in m_interface to be serviced.
+ */
+static void interface_continue(interface_t * p_interface)
+{
+ uint8_t * data = nrf_malloc(OUTPUT_BUFFER_SIZE);
+
+ if (data != NULL)
+ {
+ int len;
+
+ TLS_MUTEX_UNLOCK();
+
+ len = mbedtls_ssl_read(&p_interface->context, &data[0], OUTPUT_BUFFER_SIZE);
+
+ TLS_MUTEX_LOCK();
+
+ TLS_TRC("[%p]:[0x%08lx]mbedtls_ssl_read result(len) 0x%08lx",
+ p_interface,
+ index,
+ len);
+
+ if (len > 0)
+ {
+ uint32_t write_len = len;
+
+ uint32_t err_code = app_fifo_write(&p_interface->output_fifo, data, &write_len);
+ if (err_code != NRF_SUCCESS)
+ {
+ TLS_LOG("Failed to write decrypted data.");
+ }
+ }
+
+ nrf_free(data);
+ }
+}
+
+/**@brief Debug log funciton registered with the TLS library.
+ *
+ * @param[in] p_ctx Context registered with the library on creation of the TLS instance.
+ * @param[in] level Debug level of the log.
+ * @param[in] p_file File requesting the log.
+ * @param[in] line Line number in the file requesting the log.
+ * @param[in] p_str String containing the log message.
+ */
+static void mbedtls_log(void * p_ctx,
+ int level,
+ const char * p_file,
+ int line,
+ const char * p_str)
+{
+ TLS_LOG("[%s]:[%d]: %s", &p_file[strlen(p_file)-12], line, p_str);
+}
+
+
+/**@brief Function registered with TLS library to set (start/stop) timer.
+ *
+ * @param[in] p_ctx Context registered with the library on creation of the TLS instance.
+ * @param[in] int_ms Intermediate timeout period in milliseconds.
+ * @param[in] fin_ms Finaly timout period in milliseconds.
+ * Value of zero indicates a request to stop the timer.
+ */
+static void tls_set_timer (void * p_ctx, uint32_t int_ms, uint32_t fin_ms)
+{
+ TLS_MUTEX_LOCK();
+
+ interface_t * const p_interface = m_interface[(uint32_t)p_ctx];
+
+ if (fin_ms > 0)
+ {
+ TLS_TRC("[%p]: set_timer, start %d, final %d, intermediate %d",
+ p_interface,
+ p_interface->start_tick,
+ p_interface->final_delay,
+ p_interface->intrmediate_delay);
+
+ uint32_t err_code = iot_timer_wall_clock_get(&p_interface->start_tick);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ p_interface->final_delay = fin_ms;
+ p_interface->intrmediate_delay = int_ms;
+ }
+ }
+ else
+ {
+ p_interface->start_tick = TIME_PERIOD_INVALID;
+ p_interface->final_delay = TIME_PERIOD_INVALID;
+ p_interface->intrmediate_delay = 0;
+ }
+
+ TLS_MUTEX_UNLOCK();
+}
+
+
+/**@brief Function registered with TLS library to get the status of the timer.
+ *
+ * @param[in] p_ctx Context registered with the library on creation of the TLS instance.
+ *
+ * @retval -1 if timer is cancelled
+ * @retval 0 if none of the delays is expired
+ * @retval 1 if the intermediate delay only is expired
+ * @retval 2 if the final delay is expired
+ */
+static int tls_get_timer (void * p_ctx)
+{
+ TLS_MUTEX_LOCK();
+
+ iot_timer_time_in_ms_t elapsed_time;
+ interface_t * const p_interface = m_interface[(uint32_t)p_ctx];
+
+ uint32_t err_code = iot_timer_wall_clock_delta_get(&p_interface->start_tick, &elapsed_time);
+
+ TLS_TRC("[%p]:get_timer, start %d, final %d, intermediate %d, elapsed %d",
+ p_interface,
+ p_interface->start_tick,
+ p_interface->final_delay,
+ p_interface->intrmediate_delay,
+ elapsed_time);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ if (p_interface->final_delay <= elapsed_time)
+ {
+ return 2;
+ }
+ else if (p_interface->intrmediate_delay <= elapsed_time)
+ {
+ return 1;
+ }
+ else
+ {
+ if ((p_interface->intrmediate_delay == TIME_PERIOD_INVALID) &&
+ (p_interface->final_delay == TIME_PERIOD_INVALID))
+ {
+ return -1;
+ }
+ }
+ }
+
+ TLS_MUTEX_UNLOCK();
+
+ return 0;
+}
+
+
+/**@brief Prints/displays the configuration of the interface. Used for debugging purposes.
+ *
+ * @param[in] p_interface Identifies the instance whose ssl configuration is to be printed.
+ */
+static void interface_conf_debug_print(interface_t * p_interface)
+{
+
+ TLS_TRC("[%p] SSL Conf", p_interface);
+
+ for (int i = 0; i < 4; i++)
+ {
+ TLS_TRC("\t Cipger Suites : %02d", i);
+ TLS_TRC("\t\t\tCiphersuite[0] = %02d", p_interface->conf.ciphersuite_list[i][0]);
+ TLS_TRC("\t\t\tCiphersuite[1] = %02d", p_interface->conf.ciphersuite_list[i][1]);
+ TLS_TRC("\t\t\tCiphersuite[2] = %02d", p_interface->conf.ciphersuite_list[i][2]);
+ TLS_TRC("\t\t\tCiphersuite[3] = %02d", p_interface->conf.ciphersuite_list[i][3]);
+ }
+
+ TLS_TRC("\t\tf_dbg = %p", p_interface->conf.f_dbg);
+ TLS_TRC("\t\tp_dbg = %p", p_interface->conf.p_dbg);
+
+ TLS_TRC("\t\tf_rng = %p", p_interface->conf.f_rng);
+ TLS_TRC("\t\tp_rng = %p", p_interface->conf.p_rng);
+
+ TLS_TRC("\t\tf_get_cache = %p", p_interface->conf.f_get_cache);
+ TLS_TRC("\t\tf_set_cache = %p", p_interface->conf.f_set_cache);
+ TLS_TRC("\t\tf_set_cache = %p", p_interface->conf.p_cache);
+
+ TLS_TRC("\t\tf_vrfy = %p", p_interface->conf.f_vrfy);
+ TLS_TRC("\t\tp_vrfy = %p", p_interface->conf.p_vrfy);
+
+ TLS_TRC("\t\tcert_profile = %p", p_interface->conf.cert_profile);
+ TLS_TRC("\t\tkey_cert = %p", p_interface->conf.key_cert);
+ TLS_TRC("\t\tca_chain = %p", p_interface->conf.ca_chain);
+ TLS_TRC("\t\tca_crl = %p", p_interface->conf.ca_crl);
+
+ TLS_TRC("\t\tmax_major_ver = %2d", p_interface->conf.max_major_ver);
+ TLS_TRC("\t\tmax_minor_ver = %2d", p_interface->conf.max_minor_ver);
+ TLS_TRC("\t\tmin_major_ver = %2d", p_interface->conf.min_major_ver);
+ TLS_TRC("\t\tmax_major_ver = %2d", p_interface->conf.max_major_ver);
+}
+
+
+/**@brief Sets up own certificate on the interface instance.
+ *
+ * @param[in] p_interface TLS interface instance for which the procedure is requested.
+ * @param[in] p_own Supplies own certifcate setup information.
+ *
+ * @retval NRF_SUCCESS if the procedure was successful, else an error code indicating reason for
+ * failure.
+ */
+static uint32_t own_certificate_set(interface_t * const p_interface,
+ nrf_tls_certificate_t const * p_own)
+{
+#ifdef MBEDTLS_X509_CRT_PARSE_C
+ uint32_t error_code = (NRF_ERROR_NO_MEM | IOT_TLS_ERR_BASE);
+
+ int result;
+
+ p_interface->p_owncert = nrf_malloc(sizeof(mbedtls_x509_crt));
+
+ if (p_interface->p_owncert)
+ {
+ mbedtls_x509_crt_init(p_interface->p_owncert);
+
+ result = mbedtls_x509_crt_parse(p_interface->p_owncert,
+ p_own->p_certificate,
+ p_own->certificate_len);
+
+ if ( result == 0 )
+ {
+ mbedtls_pk_init( &p_interface->pkey );
+
+ result = mbedtls_pk_parse_key(&p_interface->pkey,
+ p_own->p_private_key,
+ p_own->private_key_len,
+ NULL,
+ 0 );
+
+ result = mbedtls_ssl_conf_own_cert(&p_interface->conf,
+ p_interface->p_owncert,
+ &p_interface->pkey);
+ if (result != 0)
+ {
+ error_code = NRF_TLS_OWN_CERT_SETUP_FAILED;
+ }
+ else
+ {
+ error_code = NRF_SUCCESS;
+ }
+ }
+ else
+ {
+ error_code = NRF_TLS_OWN_CERT_SETUP_FAILED;
+ }
+ }
+
+ return error_code;
+#else
+ return NRF_SUCCESS;
+#endif // MBEDTLS_X509_CRT_PARSE_C
+}
+
+
+/**@brief Sets up verification option for the interfce,
+ *
+ * @param[in] p_interface TLS interface instance for which the procedure is requested.
+ * @param[in] p_settings Key setting supplying CA PEM file.
+ *
+ * @retval NRF_SUCCESS if the procedure was successful, else an error code indicating reason for
+ * failure.
+ */
+static uint32_t verify_options_set(interface_t * const p_interface,
+ nrf_tls_key_settings_t const * p_settings)
+{
+ uint32_t err_code = NRF_SUCCESS;
+
+#ifdef MBEDTLS_X509_CRT_PARSE_C
+ if ((p_settings != NULL) && (p_settings->p_ca_cert_pem != NULL))
+ {
+ mbedtls_ssl_conf_authmode(&p_interface->conf, MBEDTLS_SSL_VERIFY_REQUIRED );
+
+ p_interface->p_cacert = nrf_malloc(sizeof(mbedtls_x509_crt));
+
+ if (p_interface->p_cacert != NULL)
+ {
+ // Initialize ca certificate.
+ mbedtls_x509_crt_init(p_interface->p_cacert);
+
+ int result = mbedtls_x509_crt_parse(p_interface->p_cacert,
+ p_settings->p_ca_cert_pem,
+ p_settings->ca_cert_pem_len);
+ if ( result < 0 )
+ {
+ err_code = NRF_TLS_INVALID_CA_CERTIFICATE;
+ }
+ else
+ {
+ mbedtls_ssl_conf_ca_chain(&p_interface->conf, p_interface->p_cacert, NULL);
+ }
+ }
+ else
+ {
+ err_code = (NRF_ERROR_NO_MEM | IOT_TLS_ERR_BASE);
+ }
+ }
+ else
+#endif // MBEDTLS_X509_CRT_PARSE_C
+ {
+ mbedtls_ssl_conf_authmode(&p_interface->conf, MBEDTLS_SSL_VERIFY_NONE);
+ }
+
+ return err_code;
+}
+
+
+/**@brief Sets up the configuration for SSL context according to the options specificed.
+ *
+ * @param[in] instance_id Identifies the TLS instance for which the procedure is requested.
+ * @param[in] p_options Supplies options to be used for the configuration.
+ *
+ * @retval NRF_SUCCESS if the procedure was successful, else an error indicating reason
+ * for failure.
+ */
+static uint32_t interface_conf_setup(uint32_t instance_id, nrf_tls_options_t const * p_options)
+{
+ int result = 0;
+ interface_t * p_interface = m_interface[instance_id];
+ uint32_t err_code = NRF_TLS_CONFIGURATION_FAILED;
+
+ mbedtls_ssl_config_init(&p_interface->conf);
+
+ result = mbedtls_ssl_config_defaults(&p_interface->conf,
+ p_options->role,
+ p_options->transport_type,
+ MBEDTLS_SSL_PRESET_DEFAULT);
+
+ mbedtls_ssl_conf_rng(&p_interface->conf, random_vector_generate, NULL);
+ mbedtls_ssl_conf_dbg(&p_interface->conf, mbedtls_log, NULL);
+
+ TLS_TRC("[%p]: mbedtls_ssl_config_defaults result %08lx", p_conf, result);
+
+#ifdef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
+ if (result == 0)
+ {
+ if ((p_options->p_key_settings != NULL) && (p_options->p_key_settings->p_psk != NULL))
+ {
+ result = mbedtls_ssl_conf_psk(&p_interface->conf,
+ p_options->p_key_settings->p_psk->p_secret_key,
+ p_options->p_key_settings->p_psk->secret_key_len,
+ p_options->p_key_settings->p_psk->p_identity,
+ p_options->p_key_settings->p_psk->identity_len);
+ }
+ }
+#endif // MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
+
+ if (result == 0)
+ {
+ if (p_options->p_key_settings->p_own_certificate != NULL)
+ {
+ err_code = own_certificate_set(p_interface,
+ p_options->p_key_settings->p_own_certificate);
+ }
+ else
+ {
+ err_code = NRF_SUCCESS;
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = verify_options_set(p_interface, p_options->p_key_settings);
+ }
+
+#ifdef MBEDTLS_SSL_PROTO_DTLS
+ if (err_code == NRF_SUCCESS)
+ {
+ if (p_interface->conf.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM)
+ {
+ mbedtls_ssl_conf_min_version(&p_interface->conf,
+ MBEDTLS_SSL_MAJOR_VERSION_3,
+ MBEDTLS_SSL_MINOR_VERSION_3);
+
+ mbedtls_ssl_conf_max_version(&p_interface->conf,
+ MBEDTLS_SSL_MAJOR_VERSION_3,
+ MBEDTLS_SSL_MINOR_VERSION_3);
+
+ if (p_options->transport_type == MBEDTLS_SSL_TRANSPORT_DATAGRAM)
+ {
+ mbedtls_ssl_conf_handshake_timeout(&p_interface->conf,
+ (MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MIN * 2),
+ (MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MIN * 2));
+ }
+ }
+ }
+#endif // MBEDTLS_SSL_PROTO_DTLS
+
+ interface_conf_debug_print(p_interface);
+
+ return err_code;
+}
+
+
+/**@brief Sets up the SSL context according to the options specificed.
+ *
+ * @param[in] instance_id Identifies the TLS instance for which the procedure is requested.
+ *
+ * @retval NRF_SUCCESS if the procedure was successful, else an error indicating reason for
+ * failure.
+ *
+ * @note For client roles, handshake prcoedure is initiated here.
+ */
+static uint32_t interface_ssl_context_setup(uint32_t instance_id)
+{
+ int result = 0;
+ interface_t * p_interface = m_interface[instance_id];
+
+ TLS_TRC("[%p]: Major number: 0x%08lx Minor number: 0x%08lx",
+ p_conf,
+ p_conf->min_major_ver,
+ p_conf->min_minor_ver);
+
+ mbedtls_ssl_init(&p_interface->context);
+
+ result = mbedtls_ssl_setup(&p_interface->context, &p_interface->conf);
+
+ TLS_LOG("mbedtls_ssl_setup result %d",result);
+
+ if (result == 0)
+ {
+ //ssl_set_ciphersuites(&p_interface->context, default_ciphers);
+ mbedtls_ssl_set_bio(&p_interface->context,
+ (void *)instance_id,
+ interface_transport_write,
+ interface_transport_read,
+ NULL);
+
+ if (p_interface->conf.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM)
+ {
+ mbedtls_ssl_set_timer_cb(&p_interface->context,
+ (void *)instance_id,
+ tls_set_timer,
+ tls_get_timer);
+ }
+
+ TLS_MUTEX_UNLOCK();
+
+ result = mbedtls_ssl_handshake(&p_interface->context);
+
+ TLS_MUTEX_LOCK();
+
+ TLS_LOG("mbedtls_ssl_handshake result %d", result);
+
+ if (result == MBEDTLS_ERR_SSL_CONN_EOF)
+ {
+ result = 0;
+ }
+ }
+
+ return (result ? (NRF_ERROR_INTERNAL | IOT_TLS_ERR_BASE) : NRF_SUCCESS);
+}
+
+
+uint32_t nrf_tls_init(void)
+{
+ uint32_t index = 0;
+
+ SDK_MUTEX_INIT(m_tls_mutex);
+
+ do
+ {
+ interface_init(index);
+ index++;
+ } while (index < NRF_TLS_MAX_INSTANCE_COUNT);
+
+ UNUSED_RETURN_VALUE(mbedtls_platform_set_calloc_free(wrapper_calloc, nrf_free));
+
+#ifdef MBEDTLS_DEBUG_C
+ mbedtls_debug_set_threshold(2);
+#endif // MBEDTLS_DEBUG_C
+
+ UNUSED_RETURN_VALUE(nrf_drv_rng_init(NULL));
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t nrf_tls_alloc(nrf_tls_instance_t * p_instance,
+ nrf_tls_options_t const * p_options)
+{
+ uint32_t err_code = (NRF_ERROR_NO_MEM | IOT_TLS_ERR_BASE);
+
+ TLS_MUTEX_LOCK();
+
+ err_code = interface_alloc(p_instance, p_options);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = interface_conf_setup(p_instance->instance_id, p_options);
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = interface_ssl_context_setup(p_instance->instance_id);
+ }
+
+ if (err_code != NRF_SUCCESS)
+ {
+ interface_free(p_instance->instance_id);
+ }
+
+ TLS_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t nrf_tls_input(nrf_tls_instance_t const * p_instance,
+ uint8_t const * p_data,
+ uint32_t datalen)
+{
+
+ uint32_t actual_size = 0;
+ uint32_t err_code = (NRF_ERROR_NOT_FOUND | IOT_TLS_ERR_BASE);
+
+ TLS_MUTEX_LOCK();
+
+ if ((p_instance->instance_id < NRF_TLS_MAX_INSTANCE_COUNT) &&
+ (m_interface[p_instance->instance_id] != NULL))
+ {
+ interface_t * const p_interface = m_interface[p_instance->instance_id];
+
+ // Verify all data can be queued in the FIFO.
+ err_code = app_fifo_write(&p_interface->input_fifo, NULL, &actual_size);
+ if (err_code == NRF_SUCCESS)
+ {
+ // Avoid partial write.
+ if (datalen <= actual_size)
+ {
+ actual_size = datalen;
+
+ err_code = app_fifo_write(&p_interface->input_fifo, p_data, &actual_size);
+
+ TLS_TRC("[%p]: >> nrf_tls_input datalen 0x%08lx result 0x%08lx",
+ p_interface,
+ datalen,
+ retval);
+ }
+ else
+ {
+ TLS_LOG("[%p]: Failed to queue input. "
+ "Available 0x%08lx, requested 0x%08lx",
+ p_interface,
+ actual_size,
+ datalen);
+ }
+
+ interface_continue(p_interface);
+ }
+ else
+ {
+ // Not enough room in the FIFO, indicate error.
+ return (NRF_ERROR_NO_MEM | IOT_TLS_ERR_BASE);
+ }
+ }
+
+ TLS_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t nrf_tls_read(nrf_tls_instance_t const * p_instance,
+ uint8_t * p_data,
+ uint32_t * p_datalen)
+{
+ uint32_t err_code = (NRF_ERROR_NOT_FOUND | IOT_TLS_ERR_BASE);
+
+ TLS_MUTEX_LOCK();
+
+ if ((p_instance->instance_id < NRF_TLS_MAX_INSTANCE_COUNT) &&
+ (m_interface[p_instance->instance_id] != NULL))
+ {
+ interface_t * const p_interface = m_interface[p_instance->instance_id];
+
+ err_code = app_fifo_read(&p_interface->output_fifo, p_data, p_datalen);
+ }
+
+ TLS_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t nrf_tls_write(nrf_tls_instance_t const * p_instance,
+ uint8_t const * p_data,
+ uint32_t * p_datalen)
+{
+ uint32_t err_code = (NRF_ERROR_NOT_FOUND | IOT_TLS_ERR_BASE);
+
+ TLS_MUTEX_LOCK();
+
+ if ((p_instance->instance_id < NRF_TLS_MAX_INSTANCE_COUNT) &&
+ (m_interface[p_instance->instance_id] != NULL))
+ {
+ interface_t * const p_interface = m_interface[p_instance->instance_id];
+
+ int actual_len = (*p_datalen);
+
+ TLS_MUTEX_UNLOCK();
+
+ actual_len = mbedtls_ssl_write(&p_interface->context, p_data, actual_len);
+
+ TLS_MUTEX_LOCK();
+
+ if (actual_len < 0)
+ {
+ err_code = (NRF_ERROR_INTERNAL | IOT_TLS_ERR_BASE);
+
+ if (actual_len == MBEDTLS_ERR_SSL_CONN_EOF)
+ {
+ if (p_interface->context.state < MBEDTLS_SSL_HANDSHAKE_OVER)
+ {
+ err_code = NRF_TLS_HANDSHAKE_IN_PROGRESS;
+ }
+ }
+ }
+ else
+ {
+ (* p_datalen) = actual_len;
+ err_code = NRF_SUCCESS;
+ }
+ }
+
+ TLS_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+uint32_t nrf_tls_free(nrf_tls_instance_t const * p_instance)
+{
+ uint32_t err_code = (NRF_ERROR_NOT_FOUND | IOT_TLS_ERR_BASE);
+
+ TLS_MUTEX_LOCK();
+
+ if ((p_instance->instance_id < NRF_TLS_MAX_INSTANCE_COUNT) &&
+ (m_interface[p_instance->instance_id] != NULL))
+ {
+ interface_free(p_instance->instance_id);
+ err_code = NRF_SUCCESS;
+ }
+
+ TLS_MUTEX_UNLOCK();
+
+ return err_code;
+}
+
+
+void nrf_tls_process(void)
+{
+ uint32_t index;
+
+ TLS_MUTEX_LOCK();
+
+ for (index = 0; index < NRF_TLS_MAX_INSTANCE_COUNT; index++)
+ {
+ if (m_interface[index] != NULL)
+ {
+ interface_continue(m_interface[index]);
+ }
+ }
+
+ TLS_MUTEX_UNLOCK();
+}