diff options
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.c | 1103 |
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(); +} |