Import Mbed OS hard-float snapshot
This commit is contained in:
@@ -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 */
|
||||
@@ -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_ */
|
||||
@@ -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 */
|
||||
@@ -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_ */
|
||||
Reference in New Issue
Block a user