Import Mbed OS hard-float snapshot

This commit is contained in:
Beslan
2026-06-01 20:15:04 +03:00
commit d3738e2f89
16278 changed files with 10628036 additions and 0 deletions

View File

@@ -0,0 +1,740 @@
/*
* Copyright (c) 2019, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "nsconfig.h"
#include <string.h>
#include "ns_types.h"
#include "ns_list.h"
#include "ns_trace.h"
#include "nsdynmemLIB.h"
#include "fhss_config.h"
#include "Service_Libs/Trickle/trickle.h"
#include "NWK_INTERFACE/Include/protocol.h"
#include "6LoWPAN/ws/ws_config.h"
#include "Security/protocols/sec_prot_cfg.h"
#include "Security/kmp/kmp_addr.h"
#include "Security/kmp/kmp_api.h"
#include "Security/PANA/pana_eap_header.h"
#include "Security/eapol/eapol_helper.h"
#include "Security/protocols/sec_prot_certs.h"
#include "Security/protocols/sec_prot_keys.h"
#include "Security/protocols/sec_prot.h"
#include "Security/protocols/sec_prot_lib.h"
#include "Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.h"
#include "Security/protocols/tls_sec_prot/tls_sec_prot.h"
#include "Security/protocols/tls_sec_prot/tls_sec_prot_lib.h"
#ifdef HAVE_WS
#define TRACE_GROUP "tlsp"
typedef enum {
TLS_STATE_INIT = SEC_STATE_INIT,
TLS_STATE_CREATE_REQ = SEC_STATE_CREATE_REQ,
TLS_STATE_CREATE_RESP = SEC_STATE_CREATE_RESP,
TLS_STATE_CREATE_IND = SEC_STATE_CREATE_IND,
TLS_STATE_CLIENT_HELLO = SEC_STATE_FIRST,
TLS_STATE_CONFIGURE,
TLS_STATE_PROCESS,
TLS_STATE_FINISH = SEC_STATE_FINISH,
TLS_STATE_FINISHED = SEC_STATE_FINISHED
} eap_tls_sec_prot_state_e;
typedef struct tls_sec_prot_lib_int_s tls_sec_prot_lib_int_t;
typedef struct {
sec_prot_common_t common; /**< Common data */
uint8_t new_pmk[PMK_LEN]; /**< New Pair Wise Master Key */
tls_data_t tls_send; /**< TLS send buffer */
tls_data_t tls_recv; /**< TLS receive buffer */
uint32_t int_timer; /**< TLS intermediate timer timeout */
uint32_t fin_timer; /**< TLS final timer timeout */
bool fin_timer_timeout; /**< TLS final timer has timeouted */
bool timer_running : 1; /**< TLS timer running */
bool finished : 1; /**< TLS finished */
bool calculating : 1; /**< TLS is calculating */
#ifdef SERVER_TLS_EC_CALC_QUEUE
bool queued : 1; /**< TLS is queued */
#endif
bool library_init : 1; /**< TLS library has been initialized */
tls_sec_prot_lib_int_t *tls_sec_inst; /**< TLS security library storage, SHALL BE THE LAST FIELD */
} tls_sec_prot_int_t;
// TLS server EC queue is currently disabled, since EC calculation is made on server in one go
#ifdef SERVER_TLS_EC_CALC_QUEUE
typedef struct {
ns_list_link_t link; /**< Link */
sec_prot_t *prot; /**< Protocol instance */
} tls_sec_prot_queue_t;
#endif
static uint16_t tls_sec_prot_size(void);
static int8_t client_tls_sec_prot_init(sec_prot_t *prot);
static int8_t server_tls_sec_prot_init(sec_prot_t *prot);
static void tls_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys);
static void tls_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result);
static void tls_sec_prot_delete(sec_prot_t *prot);
static int8_t tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size);
static void tls_sec_prot_finished_send(sec_prot_t *prot);
static void client_tls_sec_prot_state_machine(sec_prot_t *prot);
static void server_tls_sec_prot_state_machine(sec_prot_t *prot);
static void tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks);
static int16_t tls_sec_prot_tls_send(void *handle, const void *buf, size_t len);
static int16_t tls_sec_prot_tls_receive(void *handle, unsigned char *buf, size_t len);
static void tls_sec_prot_tls_export_keys(void *handle, const uint8_t *master_secret, const uint8_t *eap_tls_key_material);
static void tls_sec_prot_tls_set_timer(void *handle, uint32_t inter, uint32_t fin);
static int8_t tls_sec_prot_tls_get_timer(void *handle);
static int8_t tls_sec_prot_tls_configure_and_connect(sec_prot_t *prot, bool is_server);
#ifdef SERVER_TLS_EC_CALC_QUEUE
static bool tls_sec_prot_queue_check(sec_prot_t *prot);
static bool tls_sec_prot_queue_process(sec_prot_t *prot);
static void tls_sec_prot_queue_remove(sec_prot_t *prot);
#else
#define tls_sec_prot_queue_process(prot) true
#define tls_sec_prot_queue_remove(prot)
#endif /* SERVER_TLS_EC_CALC_QUEUE */
static uint16_t tls_sec_prot_send_buffer_size_get(sec_prot_t *prot);
#define tls_sec_prot_get(prot) (tls_sec_prot_int_t *) &prot->data
#ifdef SERVER_TLS_EC_CALC_QUEUE
static NS_LIST_DEFINE(tls_sec_prot_queue, tls_sec_prot_queue_t, link);
#endif
int8_t client_tls_sec_prot_register(kmp_service_t *service)
{
if (!service) {
return -1;
}
if (kmp_service_sec_protocol_register(service, TLS_PROT, tls_sec_prot_size, client_tls_sec_prot_init) < 0) {
return -1;
}
return 0;
}
int8_t server_tls_sec_prot_register(kmp_service_t *service)
{
if (!service) {
return -1;
}
if (kmp_service_sec_protocol_register(service, TLS_PROT, tls_sec_prot_size, server_tls_sec_prot_init) < 0) {
return -1;
}
return 0;
}
static uint16_t tls_sec_prot_size(void)
{
return sizeof(tls_sec_prot_int_t) + tls_sec_prot_lib_size();
}
static int8_t client_tls_sec_prot_init(sec_prot_t *prot)
{
prot->create_req = tls_sec_prot_create_request;
prot->create_resp = NULL;
prot->receive = tls_sec_prot_receive;
prot->delete = tls_sec_prot_delete;
prot->state_machine = client_tls_sec_prot_state_machine;
prot->timer_timeout = tls_sec_prot_timer_timeout;
prot->finished_send = tls_sec_prot_finished_send;
tls_sec_prot_int_t *data = tls_sec_prot_get(prot);
sec_prot_init(&data->common);
sec_prot_state_set(prot, &data->common, TLS_STATE_INIT);
memset(data->new_pmk, 0, PMK_LEN);
data->finished = false;
// Set from security parameters
eap_tls_sec_prot_lib_message_init(&data->tls_recv);
eap_tls_sec_prot_lib_message_init(&data->tls_send);
data->int_timer = 0;
data->fin_timer = 0;
data->fin_timer_timeout = false;
data->timer_running = false;
data->calculating = false;
#ifdef SERVER_TLS_EC_CALC_QUEUE
data->queued = false;
#endif
data->library_init = false;
return 0;
}
static int8_t server_tls_sec_prot_init(sec_prot_t *prot)
{
prot->create_req = NULL;
prot->create_resp = tls_sec_prot_create_response;
prot->receive = tls_sec_prot_receive;
prot->delete = tls_sec_prot_delete;
prot->state_machine = server_tls_sec_prot_state_machine;
prot->timer_timeout = tls_sec_prot_timer_timeout;
prot->finished_send = tls_sec_prot_finished_send;
tls_sec_prot_int_t *data = tls_sec_prot_get(prot);
sec_prot_init(&data->common);
sec_prot_state_set(prot, &data->common, TLS_STATE_INIT);
memset(data->new_pmk, 0, PMK_LEN);
data->finished = false;
// Set from security parameters
eap_tls_sec_prot_lib_message_init(&data->tls_recv);
eap_tls_sec_prot_lib_message_init(&data->tls_send);
data->int_timer = 0;
data->fin_timer = 0;
data->fin_timer_timeout = false;
data->timer_running = false;
data->calculating = false;
#ifdef SERVER_TLS_EC_CALC_QUEUE
data->queued = false;
#endif
data->library_init = false;
return 0;
}
static void tls_sec_prot_delete(sec_prot_t *prot)
{
tls_sec_prot_int_t *data = tls_sec_prot_get(prot);
eap_tls_sec_prot_lib_message_free(&data->tls_send);
eap_tls_sec_prot_lib_message_free(&data->tls_recv);
if (data->library_init) {
tr_info("TLS: free library");
tls_sec_prot_lib_free((tls_security_t *) &data->tls_sec_inst);
}
tls_sec_prot_queue_remove(prot);
}
static void tls_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys)
{
prot->sec_keys = sec_keys;
// Call state machine
prot->state_machine_call(prot);
}
static void tls_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result)
{
tls_sec_prot_int_t *data = tls_sec_prot_get(prot);
// Call state machine
sec_prot_result_set(&data->common, result);
prot->state_machine_call(prot);
}
static int8_t tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size)
{
tls_sec_prot_int_t *data = tls_sec_prot_get(prot);
// Discards old data
eap_tls_sec_prot_lib_message_free(&data->tls_recv);
data->tls_recv.data = pdu;
data->tls_recv.total_len = size;
prot->state_machine(prot);
return 0;
}
static void tls_sec_prot_finished_send(sec_prot_t *prot)
{
tls_sec_prot_int_t *data = tls_sec_prot_get(prot);
prot->timer_start(prot);
sec_prot_state_set(prot, &data->common, TLS_STATE_FINISHED);
}
static void tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks)
{
tls_sec_prot_int_t *data = tls_sec_prot_get(prot);
if (data->timer_running) {
if (data->int_timer > ticks) {
data->int_timer -= ticks;
} else {
data->int_timer = 0;
}
if (data->fin_timer > ticks) {
data->fin_timer -= ticks;
} else {
if (data->fin_timer > 0) {
data->fin_timer_timeout = true;
data->fin_timer = 0;
}
}
}
/* Checks if TLS sessions queue is enabled, and if queue is enabled whether the
session is first in the queue i.e. allowed to process */
if (tls_sec_prot_queue_process(prot)) {
if (data->fin_timer_timeout) {
data->fin_timer_timeout = false;
prot->state_machine(prot);
} else if (data->calculating
#ifdef SERVER_TLS_EC_CALC_QUEUE
|| data->queued
#endif
) {
prot->state_machine(prot);
}
}
sec_prot_timer_timeout_handle(prot, &data->common, NULL, ticks);
}
static void client_tls_sec_prot_state_machine(sec_prot_t *prot)
{
tls_sec_prot_int_t *data = tls_sec_prot_get(prot);
int8_t result;
switch (sec_prot_state_get(&data->common)) {
case TLS_STATE_INIT:
tr_debug("TLS: init");
sec_prot_state_set(prot, &data->common, TLS_STATE_CREATE_REQ);
prot->timer_start(prot);
// Set default timeout for the total maximum length of the negotiation
sec_prot_default_timeout_set(&data->common);
break;
// Wait KMP-CREATE.request
case TLS_STATE_CREATE_REQ:
tr_debug("TLS: start");
prot->create_conf(prot, SEC_RESULT_OK);
sec_prot_state_set(prot, &data->common, TLS_STATE_CONFIGURE);
prot->state_machine_call(prot);
break;
case TLS_STATE_CONFIGURE:
if (tls_sec_prot_tls_configure_and_connect(prot, false) < 0) {
sec_prot_result_set(&data->common, SEC_RESULT_CONF_ERROR);
sec_prot_state_set(prot, &data->common, TLS_STATE_FINISH);
return;
}
sec_prot_state_set(prot, &data->common, TLS_STATE_PROCESS);
prot->state_machine(prot);
break;
case TLS_STATE_PROCESS:
result = tls_sec_prot_lib_process((tls_security_t *) &data->tls_sec_inst);
if (result == TLS_SEC_PROT_LIB_CALCULATING) {
data->calculating = true;
prot->state_machine_call(prot);
return;
} else {
data->calculating = false;
}
if (data->tls_send.data) {
prot->send(prot, data->tls_send.data, data->tls_send.handled_len);
eap_tls_sec_prot_lib_message_init(&data->tls_send);
}
if (result != TLS_SEC_PROT_LIB_CONTINUE) {
if (result == TLS_SEC_PROT_LIB_ERROR) {
tr_error("TLS: error");
sec_prot_result_set(&data->common, SEC_RESULT_ERROR);
}
sec_prot_state_set(prot, &data->common, TLS_STATE_FINISH);
}
break;
case TLS_STATE_FINISH:
tr_debug("TLS: finish");
data->calculating = false;
if (sec_prot_result_ok_check(&data->common)) {
sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk, prot->timer_cfg->pmk_lifetime);
}
// KMP-FINISHED.indication,
prot->finished_ind(prot, sec_prot_result_get(&data->common), prot->sec_keys);
sec_prot_state_set(prot, &data->common, TLS_STATE_FINISHED);
tls_sec_prot_lib_free((tls_security_t *) &data->tls_sec_inst);
data->library_init = false;
break;
case TLS_STATE_FINISHED:
tr_debug("TLS: finished, free %s", data->library_init ? "T" : "F");
if (data->library_init) {
tls_sec_prot_lib_free((tls_security_t *) &data->tls_sec_inst);
data->library_init = false;
}
prot->timer_stop(prot);
prot->finished(prot);
break;
default:
break;
}
}
static void server_tls_sec_prot_state_machine(sec_prot_t *prot)
{
tls_sec_prot_int_t *data = tls_sec_prot_get(prot);
int8_t result;
#ifdef SERVER_TLS_EC_CALC_QUEUE
bool client_hello = false;
#endif
switch (sec_prot_state_get(&data->common)) {
case TLS_STATE_INIT:
tr_debug("TLS: init");
sec_prot_state_set(prot, &data->common, TLS_STATE_CLIENT_HELLO);
prot->timer_start(prot);
// Set default timeout for the total maximum length of the negotiation
sec_prot_default_timeout_set(&data->common);
break;
// Wait EAP request, Identity (starts handshake on supplicant)
case TLS_STATE_CLIENT_HELLO:
tr_debug("TLS: start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
#ifdef SERVER_TLS_EC_CALC_QUEUE
client_hello = true;
#endif
sec_prot_state_set(prot, &data->common, TLS_STATE_CREATE_RESP);
// Send KMP-CREATE.indication
prot->create_ind(prot);
break;
// Wait KMP-CREATE.response
case TLS_STATE_CREATE_RESP:
if (sec_prot_result_ok_check(&data->common)) {
sec_prot_state_set(prot, &data->common, TLS_STATE_CONFIGURE);
prot->state_machine_call(prot);
} else {
// Ready to be deleted
sec_prot_state_set(prot, &data->common, TLS_STATE_FINISHED);
}
break;
case TLS_STATE_CONFIGURE:
if (tls_sec_prot_tls_configure_and_connect(prot, true) < 0) {
sec_prot_result_set(&data->common, SEC_RESULT_CONF_ERROR);
sec_prot_state_set(prot, &data->common, TLS_STATE_FINISH);
return;
}
sec_prot_state_set(prot, &data->common, TLS_STATE_PROCESS);
prot->state_machine(prot);
break;
case TLS_STATE_PROCESS:
#ifdef SERVER_TLS_EC_CALC_QUEUE
// If not client hello, reserves slot on TLS queue
if (!client_hello && !tls_sec_prot_queue_check(prot)) {
data->queued = true;
return;
} else {
data->queued = false;
}
#endif
result = tls_sec_prot_lib_process((tls_security_t *) &data->tls_sec_inst);
if (result == TLS_SEC_PROT_LIB_CALCULATING) {
data->calculating = true;
prot->state_machine_call(prot);
return;
} else {
data->calculating = false;
}
if (data->tls_send.data) {
prot->send(prot, data->tls_send.data, data->tls_send.handled_len);
eap_tls_sec_prot_lib_message_init(&data->tls_send);
}
if (result != TLS_SEC_PROT_LIB_CONTINUE) {
if (result == TLS_SEC_PROT_LIB_ERROR) {
tr_error("TLS: error, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
sec_prot_result_set(&data->common, SEC_RESULT_ERROR);
}
sec_prot_state_set(prot, &data->common, TLS_STATE_FINISH);
}
break;
case TLS_STATE_FINISH:
tr_debug("TLS: finish, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
data->calculating = false;
if (sec_prot_result_ok_check(&data->common)) {
sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk, prot->timer_cfg->pmk_lifetime);
}
// KMP-FINISHED.indication,
prot->finished_ind(prot, sec_prot_result_get(&data->common), prot->sec_keys);
sec_prot_state_set(prot, &data->common, TLS_STATE_FINISHED);
tls_sec_prot_queue_remove(prot);
tls_sec_prot_lib_free((tls_security_t *) &data->tls_sec_inst);
data->library_init = false;
break;
case TLS_STATE_FINISHED: {
uint8_t *remote_eui_64 = sec_prot_remote_eui_64_addr_get(prot);
tr_debug("TLS: finished, eui-64: %s free %s", remote_eui_64 ? trace_array(sec_prot_remote_eui_64_addr_get(prot), 8) : "not set", data->library_init ? "T" : "F");
if (data->library_init) {
tls_sec_prot_lib_free((tls_security_t *) &data->tls_sec_inst);
data->library_init = false;
}
prot->timer_stop(prot);
prot->finished(prot);
break;
}
default:
break;
}
}
static int16_t tls_sec_prot_tls_send(void *handle, const void *buf, size_t len)
{
sec_prot_t *prot = handle;
tls_sec_prot_int_t *data = tls_sec_prot_get(prot);
if (!data->tls_send.data) {
uint16_t buffer_len = tls_sec_prot_send_buffer_size_get(prot);
eap_tls_sec_prot_lib_message_allocate(&data->tls_send, prot->header_size, buffer_len);
}
if (!data->tls_send.data) {
return -1;
}
/* If send buffer is too small for the TLS payload, re-allocates */
uint16_t new_len = prot->header_size + data->tls_send.handled_len + len;
if (new_len > data->tls_send.total_len) {
tr_error("TLS send buffer size too small: %i < %i, allocating new: %i", data->tls_send.total_len, new_len, data->tls_send.total_len + TLS_SEC_PROT_SEND_BUFFER_SIZE_INCREMENT);
if (eap_tls_sec_prot_lib_message_realloc(&data->tls_send, prot->header_size,
data->tls_send.total_len + TLS_SEC_PROT_SEND_BUFFER_SIZE_INCREMENT) < 0) {
return -1;
}
}
memcpy(data->tls_send.data + prot->header_size + data->tls_send.handled_len, buf, len);
data->tls_send.handled_len += len;
return len;
}
static int16_t tls_sec_prot_tls_receive(void *handle, unsigned char *buf, size_t len)
{
sec_prot_t *prot = handle;
tls_sec_prot_int_t *data = tls_sec_prot_get(prot);
if (data->tls_recv.data && len > 0) {
uint16_t copy_len = len;
bool all_copied = false;
if ((uint16_t) copy_len >= data->tls_recv.total_len - data->tls_recv.handled_len) {
copy_len = data->tls_recv.total_len - data->tls_recv.handled_len;
all_copied = true;
}
memcpy(buf, data->tls_recv.data + data->tls_recv.handled_len, copy_len);
data->tls_recv.handled_len += copy_len;
if (all_copied) {
eap_tls_sec_prot_lib_message_free(&data->tls_recv);
}
return copy_len;
}
return TLS_SEC_PROT_LIB_NO_DATA;
}
static void tls_sec_prot_tls_export_keys(void *handle, const uint8_t *master_secret, const uint8_t *eap_tls_key_material)
{
(void) master_secret;
sec_prot_t *prot = handle;
tls_sec_prot_int_t *data = tls_sec_prot_get(prot);
if (eap_tls_key_material) {
memcpy(data->new_pmk, eap_tls_key_material, PMK_LEN);
}
#ifdef EXTRA_DEBUG_INFO
const uint8_t *print_data = eap_tls_key_material;
uint16_t print_data_len = 128;
while (true) {
tr_debug("EAP-TLS key material %s\n", trace_array(print_data, print_data_len > 32 ? 32 : print_data_len));
if (print_data_len > 32) {
print_data_len -= 32;
print_data += 32;
} else {
break;
}
}
#endif
}
static void tls_sec_prot_tls_set_timer(void *handle, uint32_t inter, uint32_t fin)
{
sec_prot_t *prot = handle;
tls_sec_prot_int_t *data = tls_sec_prot_get(prot);
if (fin == 0) {
data->timer_running = false;
data->int_timer = 0;
data->fin_timer = 0;
return;
}
data->timer_running = true;
data->int_timer = inter / 100;
data->fin_timer = fin / 100;
}
static int8_t tls_sec_prot_tls_get_timer(void *handle)
{
sec_prot_t *prot = handle;
tls_sec_prot_int_t *data = tls_sec_prot_get(prot);
if (!data->timer_running) {
return TLS_SEC_PROT_LIB_TIMER_CANCELLED;
} else if (data->fin_timer == 0) {
return TLS_SEC_PROT_LIB_TIMER_FIN_EXPIRY;
} else if (data->int_timer == 0) {
return TLS_SEC_PROT_LIB_TIMER_INT_EXPIRY;
}
return TLS_SEC_PROT_LIB_TIMER_NO_EXPIRY;
}
static int8_t tls_sec_prot_tls_configure_and_connect(sec_prot_t *prot, bool is_server)
{
tls_sec_prot_int_t *data = tls_sec_prot_get(prot);
// Must be free if library initialize is done
data->library_init = true;
if (tls_sec_prot_lib_init((tls_security_t *)&data->tls_sec_inst) < 0) {
tr_error("TLS: library init fail");
return -1;
}
tls_sec_prot_lib_set_cb_register((tls_security_t *)&data->tls_sec_inst, prot,
tls_sec_prot_tls_send, tls_sec_prot_tls_receive, tls_sec_prot_tls_export_keys,
tls_sec_prot_tls_set_timer, tls_sec_prot_tls_get_timer);
if (tls_sec_prot_lib_connect((tls_security_t *)&data->tls_sec_inst, is_server, prot->sec_keys->certs) < 0) {
tr_error("TLS: library connect fail");
return -1;
}
return 0;
}
#ifdef SERVER_TLS_EC_CALC_QUEUE
static bool tls_sec_prot_queue_check(sec_prot_t *prot)
{
bool queue_add = true;
bool queue_continue = false;
uint8_t entry_index = 0;
// Checks if TLS queue is empty or this instance is the first entry
if (ns_list_is_empty(&tls_sec_prot_queue)) {
queue_continue = true;
} else {
ns_list_foreach(tls_sec_prot_queue_t, entry, &tls_sec_prot_queue) {
if (entry->prot == prot) {
queue_add = false;
if (entry_index < 3) {
queue_continue = true;
break;
} else {
queue_continue = false;
}
}
entry_index++;
}
}
// Adds entry to queue if not there already
if (queue_add) {
tr_debug("TLS QUEUE add index: %i, eui-64: %s", entry_index, trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
tls_sec_prot_queue_t *entry = ns_dyn_mem_temporary_alloc(sizeof(tls_sec_prot_queue_t));
if (entry) {
entry->prot = prot;
ns_list_add_to_end(&tls_sec_prot_queue, entry);
}
}
return queue_continue;
}
static bool tls_sec_prot_queue_process(sec_prot_t *prot)
{
if (ns_list_is_empty(&tls_sec_prot_queue)) {
return true;
}
uint8_t entry_index = 0;
ns_list_foreach(tls_sec_prot_queue_t, entry, &tls_sec_prot_queue) {
if (entry->prot == prot) {
return true;
}
if (entry_index > 2) {
return false;
}
entry_index++;
}
return false;
}
static void tls_sec_prot_queue_remove(sec_prot_t *prot)
{
ns_list_foreach_safe(tls_sec_prot_queue_t, entry, &tls_sec_prot_queue) {
if (entry->prot == prot) {
ns_list_remove(&tls_sec_prot_queue, entry);
ns_dyn_mem_free(entry);
tr_debug("TLS QUEUE remove%s, eui-64: %s", ns_list_is_empty(&tls_sec_prot_queue) ? " last" : "", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
}
}
}
#endif
static uint16_t tls_sec_prot_send_buffer_size_get(sec_prot_t *prot)
{
return TLS_SEC_PROT_SEND_BUFFER_SIZE + sec_prot_certs_own_cert_chain_len_get(prot->sec_keys->certs);
}
#endif /* HAVE_WS */

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2019, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TLS_SEC_PROT_H_
#define TLS_SEC_PROT_H_
/*
* TLS security protocol
*
*/
/* TLS send buffer size not including certificates. This should include e.g. on
* server: server hello, server key exchange, certificate request and server
* hello done. */
#define TLS_SEC_PROT_SEND_BUFFER_SIZE 500
/* TLS send buffer size increment if it is detected that buffer is too small */
#define TLS_SEC_PROT_SEND_BUFFER_SIZE_INCREMENT 1000
/**
* client_tls_sec_prot_register register client TLS protocol to KMP service
*
* \param service KMP service
*
* \return < 0 failure
* \return >= 0 success
*/
int8_t client_tls_sec_prot_register(kmp_service_t *service);
/**
* server_tls_sec_prot_register register server TLS protocol to KMP service
*
* \param service KMP service
*
* \return < 0 failure
* \return >= 0 success
*/
int8_t server_tls_sec_prot_register(kmp_service_t *service);
#endif /* TLS_SEC_PROT_H_ */

View File

@@ -0,0 +1,692 @@
/*
* Copyright (c) 2019, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "nsconfig.h"
#ifdef HAVE_WS
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_SSL_TLS_C) && defined(MBEDTLS_X509_CRT_PARSE_C) && defined(MBEDTLS_SSL_EXPORT_KEYS) /* EXPORT_KEYS not supported by mbedtls baremetal yet */
#define WS_MBEDTLS_SECURITY_ENABLED
#endif
#include <string.h>
#include <randLIB.h>
#include "ns_types.h"
#include "ns_list.h"
#include "ns_trace.h"
#include "nsdynmemLIB.h"
#include "common_functions.h"
#include "Service_Libs/Trickle/trickle.h"
#include "Security/protocols/sec_prot_cfg.h"
#include "Security/protocols/sec_prot_certs.h"
#include "Security/protocols/tls_sec_prot/tls_sec_prot_lib.h"
#if defined(MBEDTLS_SSL_TLS_C) && defined(MBEDTLS_X509_CRT_PARSE_C) && defined(MBEDTLS_SSL_EXPORT_KEYS) /* EXPORT_KEYS not supported by mbedtls baremetal yet */
#ifdef WS_MBEDTLS_SECURITY_ENABLED
#endif
#include "mbedtls/sha256.h"
#include "mbedtls/error.h"
#include "mbedtls/platform.h"
#include "mbedtls/ssl_cookie.h"
#include "mbedtls/entropy.h"
#include "mbedtls/entropy_poll.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/ssl_ciphersuites.h"
#include "mbedtls/debug.h"
#include "mbedtls/oid.h"
#define TRACE_GROUP "tlsl"
#define TLS_HANDSHAKE_TIMEOUT_MIN 25000
#define TLS_HANDSHAKE_TIMEOUT_MAX 201000
//#define TLS_SEC_PROT_LIB_TLS_DEBUG // Enable mbed TLS debug traces
typedef int tls_sec_prot_lib_crt_verify_cb(tls_security_t *sec, mbedtls_x509_crt *crt, uint32_t *flags);
struct tls_security_s {
mbedtls_ssl_config conf; /**< mbed TLS SSL configuration */
mbedtls_ssl_context ssl; /**< mbed TLS SSL context */
mbedtls_ctr_drbg_context ctr_drbg; /**< mbed TLS pseudo random number generator context */
mbedtls_entropy_context entropy; /**< mbed TLS entropy context */
mbedtls_x509_crt cacert; /**< CA certificate(s) */
mbedtls_x509_crl *crl; /**< Certificate Revocation List */
mbedtls_x509_crt owncert; /**< Own certificate(s) */
mbedtls_pk_context pkey; /**< Private key for own certificate */
void *handle; /**< Handle provided in callbacks (defined by library user) */
bool ext_cert_valid : 1; /**< Extended certificate validation enabled */
tls_sec_prot_lib_crt_verify_cb *crt_verify; /**< Verify function for client/server certificate */
tls_sec_prot_lib_send *send; /**< Send callback */
tls_sec_prot_lib_receive *receive; /**< Receive callback */
tls_sec_prot_lib_export_keys *export_keys; /**< Export keys callback */
tls_sec_prot_lib_set_timer *set_timer; /**< Set timer callback */
tls_sec_prot_lib_get_timer *get_timer; /**< Get timer callback */
};
static void tls_sec_prot_lib_ssl_set_timer(void *ctx, uint32_t int_ms, uint32_t fin_ms);
static int tls_sec_prot_lib_ssl_get_timer(void *ctx);
static int tls_sec_lib_entropy_poll(void *data, unsigned char *output, size_t len, size_t *olen);
static int tls_sec_prot_lib_ssl_send(void *ctx, const unsigned char *buf, size_t len);
static int tls_sec_prot_lib_ssl_recv(void *ctx, unsigned char *buf, size_t len);
static int tls_sec_prot_lib_ssl_export_keys(void *p_expkey, const unsigned char *ms,
const unsigned char *kb, size_t maclen, size_t keylen,
size_t ivlen, const unsigned char client_random[32],
const unsigned char server_random[32],
mbedtls_tls_prf_types tls_prf_type);
static int tls_sec_prot_lib_x509_crt_verify(void *ctx, mbedtls_x509_crt *crt, int certificate_depth, uint32_t *flags);
static int8_t tls_sec_prot_lib_subject_alternative_name_validate(mbedtls_x509_crt *crt);
static int8_t tls_sec_prot_lib_extended_key_usage_validate(mbedtls_x509_crt *crt);
#ifdef HAVE_PAE_AUTH
static int tls_sec_prot_lib_x509_crt_idevid_ldevid_verify(tls_security_t *sec, mbedtls_x509_crt *crt, uint32_t *flags);
#endif
#ifdef HAVE_PAE_SUPP
static int tls_sec_prot_lib_x509_crt_server_verify(tls_security_t *sec, mbedtls_x509_crt *crt, uint32_t *flags);
#endif
#ifdef TLS_SEC_PROT_LIB_TLS_DEBUG
static void tls_sec_prot_lib_debug(void *ctx, int level, const char *file, int line, const char *string);
#endif
#ifdef MBEDTLS_PLATFORM_MEMORY
// Disable for now
//#define TLS_SEC_PROT_LIB_USE_MBEDTLS_PLATFORM_MEMORY
#endif
#ifdef TLS_SEC_PROT_LIB_USE_MBEDTLS_PLATFORM_MEMORY
static void *tls_sec_prot_lib_mem_calloc(size_t count, size_t size);
static void tls_sec_prot_lib_mem_free(void *ptr);
#endif
#if defined(HAVE_PAE_AUTH) && defined(HAVE_PAE_SUPP)
#define is_server_is_set (is_server == true)
#define is_server_is_not_set (is_server == false)
#elif defined(HAVE_PAE_AUTH)
#define is_server_is_set true
#define is_server_is_not_set false
#elif defined(HAVE_PAE_SUPP)
#define is_server_is_set false
#define is_server_is_not_set true
#endif
int8_t tls_sec_prot_lib_init(tls_security_t *sec)
{
const char *pers = "ws_tls";
#ifdef TLS_SEC_PROT_LIB_USE_MBEDTLS_PLATFORM_MEMORY
mbedtls_platform_set_calloc_free(tls_sec_prot_lib_mem_calloc, tls_sec_prot_lib_mem_free);
#endif
mbedtls_ssl_init(&sec->ssl);
mbedtls_ssl_config_init(&sec->conf);
mbedtls_ctr_drbg_init(&sec->ctr_drbg);
mbedtls_entropy_init(&sec->entropy);
mbedtls_x509_crt_init(&sec->cacert);
mbedtls_x509_crt_init(&sec->owncert);
mbedtls_pk_init(&sec->pkey);
sec->crl = NULL;
if (mbedtls_entropy_add_source(&sec->entropy, tls_sec_lib_entropy_poll, NULL,
128, MBEDTLS_ENTROPY_SOURCE_WEAK) < 0) {
tr_error("Entropy add fail");
return -1;
}
if ((mbedtls_ctr_drbg_seed(&sec->ctr_drbg, mbedtls_entropy_func, &sec->entropy,
(const unsigned char *) pers, strlen(pers))) != 0) {
tr_error("drbg seed fail");
return -1;
}
return 0;
}
uint16_t tls_sec_prot_lib_size(void)
{
return sizeof(tls_security_t);
}
void tls_sec_prot_lib_set_cb_register(tls_security_t *sec, void *handle,
tls_sec_prot_lib_send *send, tls_sec_prot_lib_receive *receive,
tls_sec_prot_lib_export_keys *export_keys, tls_sec_prot_lib_set_timer *set_timer,
tls_sec_prot_lib_get_timer *get_timer)
{
if (!sec) {
return;
}
sec->handle = handle;
sec->send = send;
sec->receive = receive;
sec->export_keys = export_keys;
sec->set_timer = set_timer;
sec->get_timer = get_timer;
}
void tls_sec_prot_lib_free(tls_security_t *sec)
{
mbedtls_x509_crt_free(&sec->cacert);
if (sec->crl) {
mbedtls_x509_crl_free(sec->crl);
ns_dyn_mem_free(sec->crl);
}
mbedtls_x509_crt_free(&sec->owncert);
mbedtls_pk_free(&sec->pkey);
mbedtls_entropy_free(&sec->entropy);
mbedtls_ctr_drbg_free(&sec->ctr_drbg);
mbedtls_ssl_config_free(&sec->conf);
mbedtls_ssl_free(&sec->ssl);
}
static int tls_sec_prot_lib_configure_certificates(tls_security_t *sec, const sec_prot_certs_t *certs)
{
if (!certs->own_cert_chain.cert[0]) {
tr_error("no own cert");
return -1;
}
// Parse own certificate chain
uint8_t index = 0;
while (true) {
uint16_t cert_len;
uint8_t *cert = sec_prot_certs_cert_get(&certs->own_cert_chain, index, &cert_len);
if (!cert) {
if (index == 0) {
tr_error("No own cert");
return -1;
}
break;
}
if (mbedtls_x509_crt_parse(&sec->owncert, cert, cert_len) < 0) {
tr_error("Own cert parse eror");
return -1;
}
index++;
}
// Parse private key
uint8_t key_len;
uint8_t *key = sec_prot_certs_priv_key_get(&certs->own_cert_chain, &key_len);
if (!key) {
tr_error("No private key");
return -1;
}
if (mbedtls_pk_parse_key(&sec->pkey, key, key_len, NULL, 0) < 0) {
tr_error("Private key parse error");
return -1;
}
// Configure own certificate chain and private key
if (mbedtls_ssl_conf_own_cert(&sec->conf, &sec->owncert, &sec->pkey) != 0) {
tr_error("Own cert and private key conf error");
return -1;
}
// Parse trusted certificate chains
ns_list_foreach(cert_chain_entry_t, entry, &certs->trusted_cert_chain_list) {
index = 0;
while (true) {
uint16_t cert_len;
uint8_t *cert = sec_prot_certs_cert_get(entry, index, &cert_len);
if (!cert) {
if (index == 0) {
tr_error("No trusted cert");
return -1;
}
break;
}
if (mbedtls_x509_crt_parse(&sec->cacert, cert, cert_len) < 0) {
tr_error("Trusted cert parse error");
return -1;
}
index++;
}
}
// Parse certificate revocation lists
ns_list_foreach(cert_revocat_list_entry_t, entry, &certs->cert_revocat_lists) {
uint16_t crl_len;
const uint8_t *crl = sec_prot_certs_revocat_list_get(entry, &crl_len);
if (!crl) {
break;
}
if (!sec->crl) {
sec->crl = ns_dyn_mem_temporary_alloc(sizeof(mbedtls_x509_crl));
if (!sec->crl) {
tr_error("No memory for CRL");
return -1;
}
mbedtls_x509_crl_init(sec->crl);
}
if (mbedtls_x509_crl_parse(sec->crl, crl, crl_len) < 0) {
tr_error("CRL parse error");
return -1;
}
}
// Configure trusted certificates and certificate revocation lists
mbedtls_ssl_conf_ca_chain(&sec->conf, &sec->cacert, sec->crl);
// Certificate verify required on both client and server
mbedtls_ssl_conf_authmode(&sec->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
// Get extended certificate validation setting
sec->ext_cert_valid = sec_prot_certs_ext_certificate_validation_get(certs);
return 0;
}
int8_t tls_sec_prot_lib_connect(tls_security_t *sec, bool is_server, const sec_prot_certs_t *certs)
{
#if !defined(HAVE_PAE_SUPP) || !defined(HAVE_PAE_AUTH)
(void) is_server;
#endif
if (!sec) {
return -1;
}
#ifdef HAVE_PAE_SUPP
if (is_server_is_not_set) {
sec->crt_verify = tls_sec_prot_lib_x509_crt_server_verify;
}
#endif
#ifdef HAVE_PAE_AUTH
if (is_server_is_set) {
sec->crt_verify = tls_sec_prot_lib_x509_crt_idevid_ldevid_verify;
}
#endif
if ((mbedtls_ssl_config_defaults(&sec->conf,
is_server_is_set ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM, 0)) != 0) {
tr_error("config defaults fail");
return -1;
}
#if !defined(MBEDTLS_SSL_CONF_RNG)
// Configure random number generator
mbedtls_ssl_conf_rng(&sec->conf, mbedtls_ctr_drbg_random, &sec->ctr_drbg);
#endif
#ifdef MBEDTLS_ECP_RESTARTABLE
// Set ECC calculation maximum operations (affects only client)
mbedtls_ecp_set_max_ops(ECC_CALCULATION_MAX_OPS);
#endif
if ((mbedtls_ssl_setup(&sec->ssl, &sec->conf)) != 0) {
tr_error("ssl setup fail");
return -1;
}
// Defines MBEDTLS_SSL_CONF_RECV/SEND/RECV_TIMEOUT define global functions which should be the same for all
// callers of mbedtls_ssl_set_bio_ctx and there should be only one ssl context. If these rules don't apply,
// these defines can't be used.
#if !defined(MBEDTLS_SSL_CONF_RECV) && !defined(MBEDTLS_SSL_CONF_SEND) && !defined(MBEDTLS_SSL_CONF_RECV_TIMEOUT)
// Set calbacks
mbedtls_ssl_set_bio(&sec->ssl, sec, tls_sec_prot_lib_ssl_send, tls_sec_prot_lib_ssl_recv, NULL);
#else
mbedtls_ssl_set_bio_ctx(&sec->ssl, sec);
#endif /* !defined(MBEDTLS_SSL_CONF_RECV) && !defined(MBEDTLS_SSL_CONF_SEND) && !defined(MBEDTLS_SSL_CONF_RECV_TIMEOUT) */
// Defines MBEDTLS_SSL_CONF_SET_TIMER/GET_TIMER define global functions which should be the same for all
// callers of mbedtls_ssl_set_timer_cb and there should be only one ssl context. If these rules don't apply,
// these defines can't be used.
#if !defined(MBEDTLS_SSL_CONF_SET_TIMER) && !defined(MBEDTLS_SSL_CONF_GET_TIMER)
mbedtls_ssl_set_timer_cb(&sec->ssl, sec, tls_sec_prot_lib_ssl_set_timer, tls_sec_prot_lib_ssl_get_timer);
#endif /* !defined(MBEDTLS_SSL_CONF_SET_TIMER) && !defined(MBEDTLS_SSL_CONF_GET_TIMER) */
// Configure certificates, keys and certificate revocation list
if (tls_sec_prot_lib_configure_certificates(sec, certs) != 0) {
tr_error("cert conf fail");
return -1;
}
#if !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE)
// Configure ciphersuites
static const int sec_suites[] = {
MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,
0,
0,
0
};
mbedtls_ssl_conf_ciphersuites(&sec->conf, sec_suites);
#endif /* !defined(MBEDTLS_SSL_CONF_SINGLE_CIPHERSUITE) */
#ifdef TLS_SEC_PROT_LIB_TLS_DEBUG
mbedtls_ssl_conf_dbg(&sec->conf, tls_sec_prot_lib_debug, sec);
mbedtls_debug_set_threshold(5);
#endif
// Export keys callback
mbedtls_ssl_conf_export_keys_ext_cb(&sec->conf, tls_sec_prot_lib_ssl_export_keys, sec);
#if !defined(MBEDTLS_SSL_CONF_MIN_MINOR_VER) || !defined(MBEDTLS_SSL_CONF_MIN_MAJOR_VER)
mbedtls_ssl_conf_min_version(&sec->conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MAJOR_VERSION_3);
#endif /* !defined(MBEDTLS_SSL_CONF_MIN_MINOR_VER) || !defined(MBEDTLS_SSL_CONF_MIN_MAJOR_VER) */
#if !defined(MBEDTLS_SSL_CONF_MAX_MINOR_VER) || !defined(MBEDTLS_SSL_CONF_MAX_MAJOR_VER)
mbedtls_ssl_conf_max_version(&sec->conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MAJOR_VERSION_3);
#endif /* !defined(MBEDTLS_SSL_CONF_MAX_MINOR_VER) || !defined(MBEDTLS_SSL_CONF_MAX_MAJOR_VER) */
// Set certificate verify callback
mbedtls_ssl_set_verify(&sec->ssl, tls_sec_prot_lib_x509_crt_verify, sec);
/* Currently assuming we are running fast enough HW that ECC calculations are not blocking any normal operation.
*
* If there is a problem with ECC calculations and those are taking too long in border router
* MBEDTLS_ECP_RESTARTABLE feature needs to be enabled and public API is needed to allow it in border router
* enabling should be done here.
*/
return 0;
}
#ifdef TLS_SEC_PROT_LIB_TLS_DEBUG
static void tls_sec_prot_lib_debug(void *ctx, int level, const char *file, int line, const char *string)
{
(void) ctx;
tr_debug("%i %s %i %s", level, file, line, string);
}
#endif
int8_t tls_sec_prot_lib_process(tls_security_t *sec)
{
int ret = -1;
while (ret != MBEDTLS_ERR_SSL_WANT_READ) {
ret = mbedtls_ssl_handshake_step(&sec->ssl);
#if defined(MBEDTLS_ECP_RESTARTABLE) && defined(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS)
if (ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS /* || ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS */) {
return TLS_SEC_PROT_LIB_CALCULATING;
}
#endif
if (ret && (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)) {
return TLS_SEC_PROT_LIB_ERROR;
}
if (sec->ssl.state == MBEDTLS_SSL_HANDSHAKE_OVER) {
return TLS_SEC_PROT_LIB_HANDSHAKE_OVER;
}
}
return TLS_SEC_PROT_LIB_CONTINUE;
}
static void tls_sec_prot_lib_ssl_set_timer(void *ctx, uint32_t int_ms, uint32_t fin_ms)
{
tls_security_t *sec = (tls_security_t *)ctx;
sec->set_timer(sec->handle, int_ms, fin_ms);
}
static int tls_sec_prot_lib_ssl_get_timer(void *ctx)
{
tls_security_t *sec = (tls_security_t *)ctx;
return sec->get_timer(sec->handle);
}
static int tls_sec_prot_lib_ssl_send(void *ctx, const unsigned char *buf, size_t len)
{
tls_security_t *sec = (tls_security_t *)ctx;
return sec->send(sec->handle, buf, len);
}
static int tls_sec_prot_lib_ssl_recv(void *ctx, unsigned char *buf, size_t len)
{
tls_security_t *sec = (tls_security_t *)ctx;
int16_t ret = sec->receive(sec->handle, buf, len);
if (ret == TLS_SEC_PROT_LIB_NO_DATA) {
return MBEDTLS_ERR_SSL_WANT_READ;
}
return ret;
}
static int tls_sec_prot_lib_ssl_export_keys(void *p_expkey, const unsigned char *ms,
const unsigned char *kb, size_t maclen, size_t keylen,
size_t ivlen, const unsigned char client_random[32],
const unsigned char server_random[32],
mbedtls_tls_prf_types tls_prf_type)
{
(void) kb;
(void) maclen;
(void) keylen;
(void) ivlen;
tls_security_t *sec = (tls_security_t *)p_expkey;
uint8_t eap_tls_key_material[128];
uint8_t random[64];
memcpy(random, client_random, 32);
memcpy(&random[32], server_random, 32);
int ret = mbedtls_ssl_tls_prf(tls_prf_type, ms, 48, "client EAP encryption",
random, 64, eap_tls_key_material, 128);
if (ret != 0) {
tr_error("key material PRF error");
return 0;
}
sec->export_keys(sec->handle, ms, eap_tls_key_material);
return 0;
}
static int tls_sec_prot_lib_x509_crt_verify(void *ctx, mbedtls_x509_crt *crt, int certificate_depth, uint32_t *flags)
{
tls_security_t *sec = (tls_security_t *) ctx;
/* MD/PK forced by configuration flags and dynamic settings but traced also here
to prevent invalid configurations/certificates */
if (crt->sig_md != MBEDTLS_MD_SHA256) {
tr_error("Invalid signature md algorithm");
}
if (crt->sig_pk != MBEDTLS_PK_ECDSA) {
tr_error("Invalid signature pk algorithm");
}
if (*flags & MBEDTLS_X509_BADCERT_FUTURE) {
tr_info("Certificate time future");
*flags &= ~MBEDTLS_X509_BADCERT_FUTURE;
}
// Verify client/server certificate of the chain
if (certificate_depth == 0) {
return sec->crt_verify(sec, crt, flags);
}
// No further checks for intermediate and root certificates at the moment
return 0;
}
static int8_t tls_sec_prot_lib_subject_alternative_name_validate(mbedtls_x509_crt *crt)
{
mbedtls_asn1_sequence *seq = &crt->subject_alt_names;
int8_t result = -1;
while (seq) {
mbedtls_x509_subject_alternative_name san;
int ret_value = mbedtls_x509_parse_subject_alt_name((mbedtls_x509_buf *)&seq->buf, &san);
if (ret_value == 0 && san.type == MBEDTLS_X509_SAN_OTHER_NAME) {
// id-on-hardwareModuleName must be present (1.3.6.1.5.5.7.8.4)
if (MBEDTLS_OID_CMP(MBEDTLS_OID_ON_HW_MODULE_NAME, &san.san.other_name.value.hardware_module_name.oid)) {
// Traces hardwareModuleName (1.3.6.1.4.1.<enteprise number>.<model,version,etc.>)
char buffer[30];
ret_value = mbedtls_oid_get_numeric_string(buffer, sizeof(buffer), &san.san.other_name.value.hardware_module_name.oid);
if (ret_value != MBEDTLS_ERR_OID_BUF_TOO_SMALL) {
tr_info("id-on-hardwareModuleName %s", buffer);
}
// Traces serial number as hex string
mbedtls_x509_buf *val = &san.san.other_name.value.hardware_module_name.val;
if (val->p) {
tr_info("id-on-hardwareModuleName hwSerialNum %s", trace_array(val->p, val->len));
}
result = 0;
}
} else {
tr_debug("Ignored subject alt name: %i", san.type);
}
seq = seq->next;
}
return result;
}
static int8_t tls_sec_prot_lib_extended_key_usage_validate(mbedtls_x509_crt *crt)
{
#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE)
// Extended key usage must be present
if (mbedtls_x509_crt_check_extended_key_usage(crt, MBEDTLS_OID_WISUN_FAN, sizeof(MBEDTLS_OID_WISUN_FAN) - 1) != 0) {
tr_error("invalid extended key usage");
return -1; // FAIL
}
#endif
return 0;
}
#ifdef HAVE_PAE_AUTH
static int tls_sec_prot_lib_x509_crt_idevid_ldevid_verify(tls_security_t *sec, mbedtls_x509_crt *crt, uint32_t *flags)
{
// For both IDevID and LDevId both subject alternative name or extended key usage must be valid
if (tls_sec_prot_lib_subject_alternative_name_validate(crt) < 0 ||
tls_sec_prot_lib_extended_key_usage_validate(crt) < 0) {
tr_info("no wisun fields on cert");
if (sec->ext_cert_valid) {
*flags |= MBEDTLS_X509_BADCERT_OTHER;
return MBEDTLS_ERR_X509_CERT_VERIFY_FAILED;
}
}
return 0;
}
#endif
#ifdef HAVE_PAE_SUPP
static int tls_sec_prot_lib_x509_crt_server_verify(tls_security_t *sec, mbedtls_x509_crt *crt, uint32_t *flags)
{
int8_t sane_res = tls_sec_prot_lib_subject_alternative_name_validate(crt);
int8_t ext_key_res = tls_sec_prot_lib_extended_key_usage_validate(crt);
// If either subject alternative name or extended key usage is present
if (sane_res >= 0 || ext_key_res >= 0) {
// Then both subject alternative name and extended key usage must be valid
if (sane_res < 0 || ext_key_res < 0) {
tr_info("no wisun fields on cert");
if (sec->ext_cert_valid) {
*flags |= MBEDTLS_X509_BADCERT_OTHER;
return MBEDTLS_ERR_X509_CERT_VERIFY_FAILED;
}
}
}
return 0;
}
#endif
static int tls_sec_lib_entropy_poll(void *ctx, unsigned char *output, size_t len, size_t *olen)
{
(void)ctx;
char *c = (char *)ns_dyn_mem_temporary_alloc(len);
if (!c) {
tr_error("entropy alloca fail");
return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
}
memset(c, 0, len);
for (uint16_t i = 0; i < len; i++) {
*(c + i) = (char)randLIB_get_8bit();
}
memmove(output, c, len);
*olen = len;
ns_dyn_mem_free(c);
return (0);
}
#ifdef TLS_SEC_PROT_LIB_USE_MBEDTLS_PLATFORM_MEMORY
static void *tls_sec_prot_lib_mem_calloc(size_t count, size_t size)
{
void *mem_ptr = ns_dyn_mem_temporary_alloc(count * size);
if (mem_ptr) {
// Calloc should initialize with zero
memset(mem_ptr, 0, count * size);
}
return mem_ptr;
}
static void tls_sec_prot_lib_mem_free(void *ptr)
{
ns_dyn_mem_free(ptr);
}
#endif
#else /* WS_MBEDTLS_SECURITY_ENABLED */
int8_t tls_sec_prot_lib_connect(tls_security_t *sec, bool is_server, const sec_prot_certs_t *certs)
{
(void)sec;
(void)is_server;
(void)certs;
return 0;
}
void tls_sec_prot_lib_free(tls_security_t *sec)
{
(void)sec;
}
int8_t tls_sec_prot_lib_init(tls_security_t *sec)
{
(void)sec;
return 0;
}
int8_t tls_sec_prot_lib_process(tls_security_t *sec)
{
(void)sec;
return 0;
}
void tls_sec_prot_lib_set_cb_register(tls_security_t *sec, void *handle,
tls_sec_prot_lib_send *send, tls_sec_prot_lib_receive *receive,
tls_sec_prot_lib_export_keys *export_keys, tls_sec_prot_lib_set_timer *set_timer,
tls_sec_prot_lib_get_timer *get_timer)
{
(void)sec;
(void)handle;
(void)send;
(void)receive;
(void)export_keys;
(void)set_timer;
(void)get_timer;
}
uint16_t tls_sec_prot_lib_size(void)
{
return 0;
}
#endif /* WS_MBEDTLS_SECURITY_ENABLED */
#endif /* HAVE_WS */

View File

@@ -0,0 +1,169 @@
/*
* Copyright (c) 2019, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TLS_SEC_PROT_LIB_H_
#define TLS_SEC_PROT_LIB_H_
/*
* TLS security protocol library to connect to mbed TLS
*
*/
typedef struct tls_security_s tls_security_t;
typedef enum {
TLS_SEC_PROT_LIB_ERROR = -2,
TLS_SEC_PROT_LIB_NO_DATA = -1,
TLS_SEC_PROT_LIB_CONTINUE = 0,
TLS_SEC_PROT_LIB_CALCULATING,
TLS_SEC_PROT_LIB_HANDSHAKE_OVER,
} tls_sec_prot_lib_ret_e;
typedef enum {
TLS_SEC_PROT_LIB_TIMER_CANCELLED = -1,
TLS_SEC_PROT_LIB_TIMER_NO_EXPIRY = 0,
TLS_SEC_PROT_LIB_TIMER_INT_EXPIRY = 1,
TLS_SEC_PROT_LIB_TIMER_FIN_EXPIRY = 2,
} tls_sec_prot_lib_timer_e;
// Maximum operations made on one round of ECC calculation
#define ECC_CALCULATION_MAX_OPS 200
/**
* tls_sec_prot_lib_init initialize security library
*
* \param sec security library instance
*
* \return < 0 failure
* \return >= 0 success
*/
int8_t tls_sec_prot_lib_init(tls_security_t *sec);
/**
* tls_sec_prot_lib_size get security library instance size
*
* \return size
*/
uint16_t tls_sec_prot_lib_size(void);
/**
* tls_sec_prot_lib_send send data callback
*
* \param handle caller defined handle
* \param buf buffer to be send
* \param len length of the buffer
*
* \return length of the send data
*/
typedef int16_t tls_sec_prot_lib_send(void *handle, const void *buf, size_t len);
/**
* tls_sec_prot_lib_receive receive data callback
*
* \param handle caller defined handle
* \param buf receive buffer
* \param len receive buffer length
*
* \return length of the received data written to receive buffer
* \return TLS_SEC_PROT_LIB_NO_DATA no more data received
*/
typedef int16_t tls_sec_prot_lib_receive(void *handle, unsigned char *buf, size_t len);
/**
* tls_sec_prot_lib_set_timer set timer callback
*
* \param handle caller defined handle
* \param inter intermediate timeout
* \param fin final timeout
*
*/
typedef void tls_sec_prot_lib_set_timer(void *handle, uint32_t inter, uint32_t fin);
/**
* tls_sec_prot_lib_get_timer get timer callback
*
* \param handle caller defined handle
*
* \return TLS_SEC_PROT_LIB_TIMER_CANCELLED timer cancelled
* \return TLS_SEC_PROT_LIB_TIMER_FIN_EXPIRY final timeout has expired
* \return TLS_SEC_PROT_LIB_TIMER_INT_EXPIRY intermediate timeout has expired
* \retunt TLS_SEC_PROT_LIB_TIMER_NO_EXPIRY timer has not expired
*
*/
typedef int8_t tls_sec_prot_lib_get_timer(void *handle);
/**
* tls_sec_prot_lib_export_keys export key material after handshake is completed
*
* \param handle caller defined handle
* \param master_secret TLS master secret, 48 bytes
* \param eap_tls_key_material EAP TLS key material, 128 bytes
*
*/
typedef void tls_sec_prot_lib_export_keys(void *handle, const uint8_t *master_secret, const uint8_t *eap_tls_key_material);
/**
* tls_sec_prot_lib_set_cb_register register callbacks to library
*
* \param sec security library instance
* \param handle caller defined handle
* \param send send data callback
* \param receive receive data callback
* \param export_keys export keys callback
* \param set_timer set timer callback
* \param get_timer get timer callback
*
*/
void tls_sec_prot_lib_set_cb_register(tls_security_t *sec, void *handle,
tls_sec_prot_lib_send *send, tls_sec_prot_lib_receive *receive,
tls_sec_prot_lib_export_keys *export_keys, tls_sec_prot_lib_set_timer *set_timer,
tls_sec_prot_lib_get_timer *get_timer);
/**
* tls_sec_prot_lib_free free security library internal data (e.g. TLS data)
*
* \param sec security library instance
*
*/
void tls_sec_prot_lib_free(tls_security_t *sec);
/**
* tls_sec_prot_lib_connect start TLS handshake
*
* \param sec security library instance
* \param is_server TRUE if TLS server, FALSE for TLS client
* \param certs certificates
*
* \return < 0 failure
* \return >= 0 success
*/
int8_t tls_sec_prot_lib_connect(tls_security_t *sec, bool is_server, const sec_prot_certs_t *certs);
/**
* tls_sec_prot_lib_process process TLS (call e.g. after incoming message)
*
* \param sec Security library instance
*
* \return TLS_SEC_PROT_LIB_ERROR failure, failure, stop TLS negotiation
* \return TLS_SEC_PROT_LIB_CONTINUE continue processing (send output message)
* \return TLS_SEC_PROT_LIB_CALCULATING calculation ongoing, call process again
* \return TLS_SEC_PROT_LIB_HANDSHAKE_OVER handshake completed successfully
*
*/
int8_t tls_sec_prot_lib_process(tls_security_t *sec);
#endif /* TLS_SEC_PROT_LIB_H_ */