From 684b7144155778b52d33f2727fbbfc244ddd0170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=20Lepp=C3=A4nen?= Date: Tue, 1 Sep 2020 11:11:02 +0300 Subject: [PATCH] Added support for retries and multiple sockets to RADIUS client (#2426) * Added support for retries and multiple sockets to RADIUS client - RADIUS EAP-TLS and client now supports retries - RADIUS client now allocates message identifiers from a poll - Message identifiers on the poll are freed for re-use based in timer - If message identifier space runs out (255) a new socket is created - Maximum number of sockets is 3 - Added shared component support to security protocols to allow creation of message identifier pools - Improved peer message deletion by adding peer delete callback to security protocols --- source/6LoWPAN/ws/ws_pae_auth.c | 32 +++ source/6LoWPAN/ws/ws_pae_lib.c | 60 +++++ source/6LoWPAN/ws/ws_pae_lib.h | 65 +++++ source/Security/kmp/kmp_api.c | 90 +++++-- source/Security/kmp/kmp_api.h | 76 +++++- source/Security/kmp/kmp_eapol_pdu_if.c | 14 +- source/Security/kmp/kmp_socket_if.c | 89 +++++-- .../eap_tls_sec_prot/eap_tls_sec_prot_lib.c | 2 +- .../radius_eap_tls_sec_prot.c | 154 ++++++++---- .../radius_sec_prot/radius_client_sec_prot.c | 222 ++++++++++++++++-- source/Security/protocols/sec_prot.h | 97 ++++++++ 11 files changed, 788 insertions(+), 113 deletions(-) diff --git a/source/6LoWPAN/ws/ws_pae_auth.c b/source/6LoWPAN/ws/ws_pae_auth.c index b435270c7714..e63938dde3f0 100644 --- a/source/6LoWPAN/ws/ws_pae_auth.c +++ b/source/6LoWPAN/ws/ws_pae_auth.c @@ -94,6 +94,7 @@ typedef struct { ws_pae_auth_nw_info_updated *nw_info_updated; /**< Security keys network info updated callback */ ws_pae_auth_ip_addr_get *ip_addr_get; /**< IP address get callback */ supp_list_t active_supp_list; /**< List of active supplicants */ + shared_comp_list_t shared_comp_list; /**< Shared component list */ arm_event_storage_t *timer; /**< Timer */ sec_prot_gtk_keys_t *next_gtks; /**< Next GTKs */ const sec_prot_certs_t *certs; /**< Certificates */ @@ -121,6 +122,8 @@ static int8_t ws_pae_auth_timer_if_start(kmp_service_t *service, kmp_api_t *kmp) static int8_t ws_pae_auth_timer_if_stop(kmp_service_t *service, kmp_api_t *kmp); static int8_t ws_pae_auth_timer_start(pae_auth_t *pae_auth); static int8_t ws_pae_auth_timer_stop(pae_auth_t *pae_auth); +static int8_t ws_pae_auth_shared_comp_add(kmp_service_t *service, kmp_shared_comp_t *data); +static int8_t ws_pae_auth_shared_comp_remove(kmp_service_t *service, kmp_shared_comp_t *data); static bool ws_pae_auth_timer_running(pae_auth_t *pae_auth); static void ws_pae_auth_kmp_service_addr_get(kmp_service_t *service, kmp_api_t *kmp, kmp_addr_t *local_addr, kmp_addr_t *remote_addr); static void ws_pae_auth_kmp_service_ip_addr_get(kmp_service_t *service, kmp_api_t *kmp, uint8_t *address); @@ -156,6 +159,7 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot pae_auth->pan_id = 0xffff; pae_auth->interface_ptr = interface_ptr; ws_pae_lib_supp_list_init(&pae_auth->active_supp_list); + ws_pae_lib_shared_comp_list_init(&pae_auth->shared_comp_list); pae_auth->timer = NULL; pae_auth->hash_set = NULL; @@ -192,6 +196,10 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot goto error; } + if (kmp_service_shared_comp_if_register(pae_auth->kmp_service, ws_pae_auth_shared_comp_add, ws_pae_auth_shared_comp_remove)) { + goto error; + } + if (auth_key_sec_prot_register(pae_auth->kmp_service) < 0) { goto error; } @@ -594,6 +602,8 @@ static void ws_pae_auth_free(pae_auth_t *pae_auth) return; } + ws_pae_lib_shared_comp_list_free(&pae_auth->shared_comp_list); + ws_pae_lib_supp_list_delete(&pae_auth->active_supp_list); kmp_socket_if_unregister(pae_auth->kmp_service); @@ -741,6 +751,8 @@ void ws_pae_auth_slow_timer(uint16_t seconds) } ws_pae_lib_supp_list_slow_timer_update(&pae_auth->active_supp_list, seconds); + + ws_pae_lib_shared_comp_list_timeout(&pae_auth->shared_comp_list, seconds); } // Update key storage timer @@ -837,6 +849,26 @@ static int8_t ws_pae_auth_timer_if_stop(kmp_service_t *service, kmp_api_t *kmp) return 0; } +static int8_t ws_pae_auth_shared_comp_add(kmp_service_t *service, kmp_shared_comp_t *data) +{ + pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service); + if (!pae_auth) { + return -1; + } + + return ws_pae_lib_shared_comp_list_add(&pae_auth->shared_comp_list, data); +} + +static int8_t ws_pae_auth_shared_comp_remove(kmp_service_t *service, kmp_shared_comp_t *data) +{ + pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service); + if (!pae_auth) { + return -1; + } + + return ws_pae_lib_shared_comp_list_remove(&pae_auth->shared_comp_list, data); +} + static int8_t ws_pae_auth_timer_start(pae_auth_t *pae_auth) { pae_auth->timer_running = true; diff --git a/source/6LoWPAN/ws/ws_pae_lib.c b/source/6LoWPAN/ws/ws_pae_lib.c index 52ceaaba6a2a..3f9ab10b37fe 100644 --- a/source/6LoWPAN/ws/ws_pae_lib.c +++ b/source/6LoWPAN/ws/ws_pae_lib.c @@ -448,4 +448,64 @@ supp_entry_t *ws_pae_lib_supp_list_entry_retry_timer_get(supp_list_t *supp_list) return retry_supp; } +int8_t ws_pae_lib_shared_comp_list_init(shared_comp_list_t *comp_list) +{ + ns_list_init(comp_list); + return 0; +} + +int8_t ws_pae_lib_shared_comp_list_free(shared_comp_list_t *comp_list) +{ + ns_list_foreach_safe(shared_comp_entry_t, entry, comp_list) { + if (entry->data->delete) { + entry->data->delete (); + } + ns_list_remove(comp_list, entry); + ns_dyn_mem_free(entry); + } + return 0; +} + +int8_t ws_pae_lib_shared_comp_list_add(shared_comp_list_t *comp_list, kmp_shared_comp_t *data) +{ + ns_list_foreach(shared_comp_entry_t, entry, comp_list) { + if (entry->data == data) { + return -1; + } + } + + shared_comp_entry_t *entry = ns_dyn_mem_alloc(sizeof(shared_comp_entry_t)); + if (!entry) { + return -1; + } + entry->data = data; + ns_list_add_to_end(comp_list, entry); + + return 0; +} + +int8_t ws_pae_lib_shared_comp_list_remove(shared_comp_list_t *comp_list, kmp_shared_comp_t *data) +{ + ns_list_foreach(shared_comp_entry_t, entry, comp_list) { + if (entry->data == data) { + ns_list_remove(comp_list, entry); + ns_dyn_mem_free(entry); + return 0; + } + } + + return 0; +} + +int8_t ws_pae_lib_shared_comp_list_timeout(shared_comp_list_t *comp_list, uint16_t ticks) +{ + ns_list_foreach(shared_comp_entry_t, entry, comp_list) { + if (entry->data->timeout) { + entry->data->timeout(ticks); + } + } + + return 0; +} + #endif /* HAVE_WS */ diff --git a/source/6LoWPAN/ws/ws_pae_lib.h b/source/6LoWPAN/ws/ws_pae_lib.h index 5058e3e36401..dc9a0b67b564 100644 --- a/source/6LoWPAN/ws/ws_pae_lib.h +++ b/source/6LoWPAN/ws/ws_pae_lib.h @@ -45,6 +45,13 @@ typedef struct supp_entry_s { typedef NS_LIST_HEAD(supp_entry_t, link) supp_list_t; +typedef struct { + kmp_shared_comp_t *data; /**< KMP shared component data */ + ns_list_link_t link; /**< Link */ +} shared_comp_entry_t; + +typedef NS_LIST_HEAD(shared_comp_entry_t, link) shared_comp_list_t; + /** * ws_pae_lib_kmp_list_init initializes KMP list * @@ -388,4 +395,62 @@ kmp_api_t *ws_pae_lib_supp_list_kmp_receive_check(supp_list_t *supp_list, const */ supp_entry_t *ws_pae_lib_supp_list_entry_retry_timer_get(supp_list_t *supp_list); +/** + * ws_pae_lib_shared_comp_list_init init shared component list + * + * \param comp_list component list + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_lib_shared_comp_list_init(shared_comp_list_t *comp_list); + +/** + * ws_pae_lib_shared_comp_list_free free shared component list + * + * \param comp_list component list + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_lib_shared_comp_list_free(shared_comp_list_t *comp_list); + +/** + * ws_pae_lib_shared_comp_list_add add to shared component list + * + * \param comp_list component list + * \param data shared component + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_lib_shared_comp_list_add(shared_comp_list_t *comp_list, kmp_shared_comp_t *data); + +/** + * ws_pae_lib_shared_comp_list_remove remove from shared component list + * + * \param comp_list component list + * \param data shared component + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_lib_shared_comp_list_remove(shared_comp_list_t *comp_list, kmp_shared_comp_t *data); + +/** + * ws_pae_lib_shared_comp_list_timeout timeout to shared component list + * + * \param comp_list component list + * \param ticks elapsed time in seconds + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_lib_shared_comp_list_timeout(shared_comp_list_t *comp_list, uint16_t ticks); + #endif /* WS_PAE_AUTH_H_ */ diff --git a/source/Security/kmp/kmp_api.c b/source/Security/kmp/kmp_api.c index e175d9a851ff..19be4a7f7a33 100644 --- a/source/Security/kmp/kmp_api.c +++ b/source/Security/kmp/kmp_api.c @@ -64,6 +64,7 @@ typedef NS_LIST_HEAD(kmp_sec_prot_entry_t, link) kmp_sec_prot_list_t; typedef struct { uint8_t instance_id; /**< Message interface instance identifier */ uint8_t header_size; /**< Message interface header size */ + uint8_t number_of_conn; /**< Message interface number of connections */ kmp_service_msg_if_send *send; /**< Message interface callback to send KMP frames */ ns_list_link_t link; /**< Link */ } kmp_msg_if_entry_t; @@ -71,17 +72,19 @@ typedef struct { typedef NS_LIST_HEAD(kmp_msg_if_entry_t, link) kmp_msg_if_list_t; struct kmp_service_s { - kmp_sec_prot_list_t sec_prot_list; /**< Security protocols list */ - kmp_msg_if_list_t msg_if_list; /**< Message interface list */ - kmp_service_incoming_ind *incoming_ind; /**< Callback to application to indicate incoming KMP frame */ - kmp_service_tx_status_ind *tx_status_ind; /**< Callback to application to indicate TX status */ - kmp_service_addr_get *addr_get; /**< Callback to get addresses related to KMP */ - kmp_service_ip_addr_get *ip_addr_get; /**< Callback to get IP addresses related to KMP */ - kmp_service_api_get *api_get; /**< Callback to get KMP API from a service */ - kmp_service_timer_if_start *timer_start; /**< Callback to start timer */ - kmp_service_timer_if_stop *timer_stop; /**< Callback to stop timer */ - kmp_service_event_if_event_send *event_send; /**< Callback to send event */ - ns_list_link_t link; /**< Link */ + kmp_sec_prot_list_t sec_prot_list; /**< Security protocols list */ + kmp_msg_if_list_t msg_if_list; /**< Message interface list */ + kmp_service_incoming_ind *incoming_ind; /**< Callback to application to indicate incoming KMP frame */ + kmp_service_tx_status_ind *tx_status_ind; /**< Callback to application to indicate TX status */ + kmp_service_addr_get *addr_get; /**< Callback to get addresses related to KMP */ + kmp_service_ip_addr_get *ip_addr_get; /**< Callback to get IP addresses related to KMP */ + kmp_service_api_get *api_get; /**< Callback to get KMP API from a service */ + kmp_service_timer_if_start *timer_start; /**< Callback to start timer */ + kmp_service_timer_if_stop *timer_stop; /**< Callback to stop timer */ + kmp_service_event_if_event_send *event_send; /**< Callback to send event */ + kmp_service_shared_comp_add *shared_comp_add; /**< Callback to shared component add */ + kmp_service_shared_comp_remove *shared_comp_remove; /**< Callback to shared component remove */ + ns_list_link_t link; /**< Link */ }; typedef struct { @@ -100,8 +103,11 @@ static void kmp_api_sec_prot_create_indication(sec_prot_t *prot); static void kmp_api_sec_prot_finished_indication(sec_prot_t *prot, sec_prot_result_e result, sec_prot_keys_t *sec_keys); static void kmp_api_sec_prot_finished(sec_prot_t *prot); static int8_t kmp_sec_prot_send(sec_prot_t *prot, void *pdu, uint16_t size); +static int8_t kmp_sec_prot_conn_send(sec_prot_t *prot, void *pdu, uint16_t size, uint8_t conn_number, uint8_t flags); static void kmp_sec_prot_timer_start(sec_prot_t *prot); static void kmp_sec_prot_timer_stop(sec_prot_t *prot); +static int8_t kmp_sec_prot_shared_comp_add(sec_prot_t *prot, shared_comp_data_t *data); +static int8_t kmp_sec_prot_shared_comp_remove(sec_prot_t *prot, shared_comp_data_t *data); static void kmp_sec_prot_state_machine_call(sec_prot_t *prot); static void kmp_sec_prot_eui64_addr_get(sec_prot_t *prot, uint8_t *local_eui64, uint8_t *remote_eui64); static void kmp_sec_prot_ip_addr_get(sec_prot_t *prot, uint8_t *address); @@ -157,13 +163,17 @@ kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, uint8_t msg_i kmp->sec_prot.header_size = msg_if_entry->header_size; kmp->sec_prot.receive_peer_hdr_size = msg_if_entry->header_size; + kmp->sec_prot.number_of_conn = msg_if_entry->number_of_conn; kmp->sec_prot.create_conf = kmp_api_sec_prot_create_confirm; kmp->sec_prot.create_ind = kmp_api_sec_prot_create_indication; kmp->sec_prot.finished_ind = kmp_api_sec_prot_finished_indication; kmp->sec_prot.finished = kmp_api_sec_prot_finished; kmp->sec_prot.send = kmp_sec_prot_send; + kmp->sec_prot.conn_send = kmp_sec_prot_conn_send; kmp->sec_prot.timer_start = kmp_sec_prot_timer_start; kmp->sec_prot.timer_stop = kmp_sec_prot_timer_stop; + kmp->sec_prot.shared_comp_add = kmp_sec_prot_shared_comp_add; + kmp->sec_prot.shared_comp_remove = kmp_sec_prot_shared_comp_remove; kmp->sec_prot.state_machine_call = kmp_sec_prot_state_machine_call; kmp->sec_prot.addr_get = kmp_sec_prot_eui64_addr_get; kmp->sec_prot.ip_addr_get = kmp_sec_prot_ip_addr_get; @@ -237,6 +247,11 @@ static void kmp_api_sec_prot_finished(sec_prot_t *prot) } static int8_t kmp_sec_prot_send(sec_prot_t *prot, void *pdu, uint16_t size) +{ + return kmp_sec_prot_conn_send(prot, pdu, size, 0, 0); +} + +static int8_t kmp_sec_prot_conn_send(sec_prot_t *prot, void *pdu, uint16_t size, uint8_t conn_number, uint8_t flags) { kmp_api_t *kmp = kmp_api_get_from_prot(prot); @@ -256,7 +271,7 @@ static int8_t kmp_sec_prot_send(sec_prot_t *prot, void *pdu, uint16_t size) int8_t result = -1; if (msg_if_entry->send) { - result = msg_if_entry->send(kmp->service, prot->msg_if_instance_id, kmp_id, kmp->addr, pdu, size, kmp->instance_identifier); + result = msg_if_entry->send(kmp->service, prot->msg_if_instance_id, kmp_id, kmp->addr, pdu, size, kmp->instance_identifier, conn_number, flags); } if (result < 0) { @@ -269,6 +284,7 @@ static int8_t kmp_sec_prot_send(sec_prot_t *prot, void *pdu, uint16_t size) static void kmp_sec_prot_timer_start(sec_prot_t *prot) { kmp_api_t *kmp = kmp_api_get_from_prot(prot); + kmp->timer_start_pending = false; if (kmp->service->timer_start(kmp->service, kmp) < 0) { kmp->timer_start_pending = true; @@ -278,10 +294,33 @@ static void kmp_sec_prot_timer_start(sec_prot_t *prot) static void kmp_sec_prot_timer_stop(sec_prot_t *prot) { kmp_api_t *kmp = kmp_api_get_from_prot(prot); + kmp->service->timer_stop(kmp->service, kmp); kmp->timer_start_pending = false; } +static int8_t kmp_sec_prot_shared_comp_add(sec_prot_t *prot, shared_comp_data_t *data) +{ + kmp_api_t *kmp = kmp_api_get_from_prot(prot); + + if (kmp->service->shared_comp_add == NULL) { + return -1; + } + kmp->service->shared_comp_add(kmp->service, (kmp_shared_comp_t *) data); + return 0; +} + +static int8_t kmp_sec_prot_shared_comp_remove(sec_prot_t *prot, shared_comp_data_t *data) +{ + kmp_api_t *kmp = kmp_api_get_from_prot(prot); + + if (kmp->service->shared_comp_add == NULL) { + return -1; + } + kmp->service->shared_comp_remove(kmp->service, (kmp_shared_comp_t *) data); + return 0; +} + static void kmp_sec_prot_eui64_addr_get(sec_prot_t *prot, uint8_t *local_eui64, uint8_t *remote_eui64) { kmp_api_t *kmp = kmp_api_get_from_prot(prot); @@ -444,6 +483,8 @@ kmp_service_t *kmp_service_create(void) service->tx_status_ind = 0; service->addr_get = 0; service->api_get = 0; + service->shared_comp_add = NULL; + service->shared_comp_remove = NULL; ns_list_add_to_start(&kmp_service_list, service); @@ -496,7 +537,7 @@ int8_t kmp_service_cb_register(kmp_service_t *service, kmp_service_incoming_ind return 0; } -int8_t kmp_service_msg_if_register(kmp_service_t *service, uint8_t instance_id, kmp_service_msg_if_send *send, uint8_t header_size) +int8_t kmp_service_msg_if_register(kmp_service_t *service, uint8_t instance_id, kmp_service_msg_if_send *send, uint8_t header_size, uint8_t number_of_conn) { if (!service) { return -1; @@ -533,11 +574,12 @@ int8_t kmp_service_msg_if_register(kmp_service_t *service, uint8_t instance_id, entry->instance_id = instance_id; entry->send = send; entry->header_size = header_size; + entry->number_of_conn = number_of_conn; return 0; } -int8_t kmp_service_msg_if_receive(kmp_service_t *service, uint8_t instance_id, kmp_type_e type, const kmp_addr_t *addr, void *pdu, uint16_t size) +int8_t kmp_service_msg_if_receive(kmp_service_t *service, uint8_t instance_id, kmp_type_e type, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t connection_num) { if (!service) { return -1; @@ -553,7 +595,14 @@ int8_t kmp_service_msg_if_receive(kmp_service_t *service, uint8_t instance_id, k return -1; } - int8_t ret = kmp->sec_prot.receive(&kmp->sec_prot, pdu, size); + int8_t ret = -1; + if (kmp->sec_prot.receive != NULL) { + ret = kmp->sec_prot.receive(&kmp->sec_prot, pdu, size); + } + if (kmp->sec_prot.conn_receive != NULL) { + ret = kmp->sec_prot.conn_receive(&kmp->sec_prot, pdu, size, connection_num); + } + return ret; } @@ -642,6 +691,17 @@ int8_t kmp_service_timer_if_register(kmp_service_t *service, kmp_service_timer_i return 0; } +int8_t kmp_service_shared_comp_if_register(kmp_service_t *service, kmp_service_shared_comp_add add, kmp_service_shared_comp_remove remove) +{ + if (!service) { + return -1; + } + + service->shared_comp_add = add; + service->shared_comp_remove = remove; + return 0; +} + void kmp_service_event_if_event(kmp_service_t *service, void *data) { (void) service; diff --git a/source/Security/kmp/kmp_api.h b/source/Security/kmp/kmp_api.h index f51a14058869..fa945eb48051 100644 --- a/source/Security/kmp/kmp_api.h +++ b/source/Security/kmp/kmp_api.h @@ -59,6 +59,9 @@ typedef enum { KMP_TX_ERR_UNSPEC = -2, // Other reason } kmp_tx_status_e; +// On message interface send, do not deallocate pdu buffer +#define MSG_IF_SEND_FLAG_NO_DEALLOC 0x01 + typedef void kmp_sec_keys_t; typedef struct sec_prot_s sec_prot_t; typedef struct kmp_api_s kmp_api_t; @@ -367,12 +370,13 @@ int8_t kmp_service_cb_register(kmp_service_t *service, kmp_service_incoming_ind * \param addr address * \param pdu pdu * \param size pdu size + * \param conn_number connection number (0 for default) * * \return < 0 failure * \return >= 0 success * */ -int8_t kmp_service_msg_if_receive(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size); +int8_t kmp_service_msg_if_receive(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t conn_number); /** * kmp_service_msg_if_send send a message @@ -384,12 +388,14 @@ int8_t kmp_service_msg_if_receive(kmp_service_t *service, uint8_t instance_id, k * \param pdu pdu * \param size pdu size * \param tx_identifier TX identifier + * \param conn_number connection number (0 for default) + * \param flags flags * * \return < 0 failure * \return >= 0 success * */ -typedef int8_t kmp_service_msg_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e type, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier); +typedef int8_t kmp_service_msg_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e type, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier, uint8_t conn_number, uint8_t flags); /** * kmp_service_msg_if_register registers message interface @@ -398,12 +404,13 @@ typedef int8_t kmp_service_msg_if_send(kmp_service_t *service, uint8_t instance_ * \param instance_id message interface instance identifier * \param send KMP PDU send callback * \param header_size header size + * \param number_of_conn number of connections * * \return < 0 failure * \return >= 0 success * */ -int8_t kmp_service_msg_if_register(kmp_service_t *service, uint8_t instance_id, kmp_service_msg_if_send *send, uint8_t header_size); +int8_t kmp_service_msg_if_register(kmp_service_t *service, uint8_t instance_id, kmp_service_msg_if_send *send, uint8_t header_size, uint8_t number_of_conn); /** * kmp_service_tx_status tx status indication @@ -467,6 +474,7 @@ int8_t kmp_service_sec_protocol_unregister(kmp_service_t *service, kmp_type_e ty * kmp_service_timer_if_timeout timer timeout * * \param service KMP instance + * \param ticks Ticks * */ void kmp_service_timer_if_timeout(kmp_api_t *kmp, uint16_t ticks); @@ -508,6 +516,68 @@ typedef int8_t kmp_service_timer_if_stop(kmp_service_t *service, kmp_api_t *kmp) */ int8_t kmp_service_timer_if_register(kmp_service_t *service, kmp_service_timer_if_start start, kmp_service_timer_if_stop stop); +/** + * kmp_service_shared_comp_timer_timeout shared component timer timeout + * + * \param ticks timer ticks + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t kmp_service_shared_comp_timer_timeout(uint16_t ticks); + +/** + * kmp_service_shared_comp_delete shared component delete + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t kmp_service_shared_comp_delete(void); + +typedef struct { + kmp_service_shared_comp_timer_timeout *timeout; + kmp_service_shared_comp_delete *delete; +} kmp_shared_comp_t; + +/** + * kmp_service_shared_comp_add add shared component + * + * \param service KMP service + * \param data shared component data + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t kmp_service_shared_comp_add(kmp_service_t *service, kmp_shared_comp_t *data); + +/** + * kmp_service_shared_comp_remove remove shared component + * + * \param service KMP service + * \param data shared component data + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t kmp_service_shared_comp_remove(kmp_service_t *service, kmp_shared_comp_t *data); + +/** + * kmp_service_shared_comp_if_register register a continuous timer interface to KMP service + * + * \param service KMP service + * \param add shared component + * \param remove remove shared component + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kmp_service_shared_comp_if_register(kmp_service_t *service, kmp_service_shared_comp_add add, kmp_service_shared_comp_remove remove); + /** * kmp_service_event_if_event event callback * diff --git a/source/Security/kmp/kmp_eapol_pdu_if.c b/source/Security/kmp/kmp_eapol_pdu_if.c index f12bc517b979..afcae84571b5 100644 --- a/source/Security/kmp/kmp_eapol_pdu_if.c +++ b/source/Security/kmp/kmp_eapol_pdu_if.c @@ -49,7 +49,7 @@ typedef struct { static NS_LIST_DEFINE(kmp_eapol_pdu_if_list, kmp_eapol_pdu_if_t, link); -static int8_t kmp_eapol_pdu_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier); +static int8_t kmp_eapol_pdu_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier, uint8_t conn_number, uint8_t flags); static int8_t kmp_eapol_pdu_if_tx_status(protocol_interface_info_entry_t *interface_ptr, eapol_pdu_tx_status_e tx_status, uint8_t tx_identifier); int8_t kmp_eapol_pdu_if_register(kmp_service_t *service, protocol_interface_info_entry_t *interface_ptr) @@ -72,7 +72,7 @@ int8_t kmp_eapol_pdu_if_register(kmp_service_t *service, protocol_interface_info eapol_pdu_if->kmp_service = service; eapol_pdu_if->interface_ptr = interface_ptr; - if (kmp_service_msg_if_register(service, 0, kmp_eapol_pdu_if_send, EAPOL_PDU_IF_HEADER_SIZE) < 0) { + if (kmp_service_msg_if_register(service, 0, kmp_eapol_pdu_if_send, EAPOL_PDU_IF_HEADER_SIZE, 0) < 0) { ns_dyn_mem_free(eapol_pdu_if); return -1; } @@ -92,17 +92,19 @@ int8_t kmp_eapol_pdu_if_unregister(kmp_service_t *service) if (entry->kmp_service == service) { ns_list_remove(&kmp_eapol_pdu_if_list, entry); ns_dyn_mem_free(entry); - kmp_service_msg_if_register(service, 0, NULL, 0); + kmp_service_msg_if_register(service, 0, NULL, 0, 0); } } return 0; } -static int8_t kmp_eapol_pdu_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier) +static int8_t kmp_eapol_pdu_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier, uint8_t conn_number, uint8_t flags) { (void) instance_id; // Only one instance of eapol interface possible + (void) conn_number; // Only one connection of eapol interface possible - if (!service || !addr || !pdu) { + // No flags supported + if (!service || !addr || !pdu || flags) { return -1; } @@ -159,7 +161,7 @@ int8_t kmp_eapol_pdu_if_receive(protocol_interface_info_entry_t *interface_ptr, return -1; } - int8_t ret = kmp_service_msg_if_receive(service, 0, type, &addr, data_pdu, data_pdu_size); + int8_t ret = kmp_service_msg_if_receive(service, 0, type, &addr, data_pdu, data_pdu_size, 0); return ret; } diff --git a/source/Security/kmp/kmp_socket_if.c b/source/Security/kmp/kmp_socket_if.c index 66c78b10392f..cfecba64d893 100644 --- a/source/Security/kmp/kmp_socket_if.c +++ b/source/Security/kmp/kmp_socket_if.c @@ -39,19 +39,20 @@ #define TRACE_GROUP "kmsi" -#define SOCKET_IF_HEADER_SIZE 27 +#define SOCKET_IF_HEADER_SIZE 27 +#define INSTANCE_SOCKETS_NUMBER 3 typedef struct { kmp_service_t *kmp_service; /**< KMP service */ uint8_t instance_id; /**< Instance identifier */ bool relay; /**< Interface is relay interface */ ns_address_t remote_addr; /**< Remote address */ - int8_t socket_id; /**< Socket ID */ - bool socket_id_set; /**< Socket ID is set */ + int8_t socket_id[INSTANCE_SOCKETS_NUMBER]; /**< Socket ID */ + unsigned socket_id_in_use : 4; /**< Socket ID is in use */ ns_list_link_t link; /**< Link */ } kmp_socket_if_t; -static int8_t kmp_socket_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier); +static int8_t kmp_socket_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier, uint8_t connection_num, uint8_t flags); static void kmp_socket_if_socket_cb(void *ptr); static NS_LIST_DEFINE(kmp_socket_if_list, kmp_socket_if_t, link); @@ -78,7 +79,10 @@ int8_t kmp_socket_if_register(kmp_service_t *service, uint8_t *instance_id, bool return -1; } memset(socket_if, 0, sizeof(kmp_socket_if_t)); - socket_if->socket_id = -1; + for (uint8_t socket_num = 0; socket_num < INSTANCE_SOCKETS_NUMBER; socket_num++) { + socket_if->socket_id[socket_num] = -1; + } + socket_if->socket_id_in_use = 1; new_socket_if_allocated = true; } @@ -104,14 +108,19 @@ int8_t kmp_socket_if_register(kmp_service_t *service, uint8_t *instance_id, bool memcpy(&socket_if->remote_addr.address, remote_addr, 16); socket_if->remote_addr.identifier = remote_port; - if (socket_if->socket_id < 0 || address_changed) { - if (socket_if->socket_id >= 0) { - socket_close(socket_if->socket_id); - } - socket_if->socket_id = socket_open(IPV6_NH_UDP, local_port, &kmp_socket_if_socket_cb); - if (socket_if->socket_id < 0) { - ns_dyn_mem_free(socket_if); - return -1; + for (uint8_t socket_num = 0; socket_num < INSTANCE_SOCKETS_NUMBER; socket_num++) { + if (socket_if->socket_id_in_use & (1 << socket_num)) { + + if ((socket_if->socket_id[socket_num] < 1) || address_changed) { + if (socket_if->socket_id[socket_num] >= 0) { + socket_close(socket_if->socket_id[socket_num]); + } + socket_if->socket_id[socket_num] = socket_open(IPV6_NH_UDP, local_port, &kmp_socket_if_socket_cb); + if (socket_if->socket_id[socket_num] < 0) { + ns_dyn_mem_free(socket_if); + return -1; + } + } } } @@ -120,7 +129,12 @@ int8_t kmp_socket_if_register(kmp_service_t *service, uint8_t *instance_id, bool header_size = SOCKET_IF_HEADER_SIZE; } - if (kmp_service_msg_if_register(service, *instance_id, kmp_socket_if_send, header_size) < 0) { + if (kmp_service_msg_if_register(service, *instance_id, kmp_socket_if_send, header_size, INSTANCE_SOCKETS_NUMBER) < 0) { + for (uint8_t socket_num = 0; socket_num < INSTANCE_SOCKETS_NUMBER; socket_num++) { + if (socket_if->socket_id[socket_num] >= 0) { + socket_close(socket_if->socket_id[socket_num]); + } + } ns_dyn_mem_free(socket_if); return -1; } @@ -141,15 +155,19 @@ int8_t kmp_socket_if_unregister(kmp_service_t *service) ns_list_foreach_safe(kmp_socket_if_t, entry, &kmp_socket_if_list) { if (entry->kmp_service == service) { ns_list_remove(&kmp_socket_if_list, entry); - socket_close(entry->socket_id); - kmp_service_msg_if_register(service, entry->instance_id, NULL, 0); + for (uint8_t socket_num = 0; socket_num < INSTANCE_SOCKETS_NUMBER; socket_num++) { + if (entry->socket_id[socket_num] >= 0) { + socket_close(entry->socket_id[socket_num]); + } + } + kmp_service_msg_if_register(service, entry->instance_id, NULL, 0, 0); ns_dyn_mem_free(entry); } } return 0; } -static int8_t kmp_socket_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier) +static int8_t kmp_socket_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier, uint8_t connection_num, uint8_t flags) { (void) tx_identifier; @@ -157,6 +175,10 @@ static int8_t kmp_socket_if_send(kmp_service_t *service, uint8_t instance_id, km return -1; } + if (connection_num >= INSTANCE_SOCKETS_NUMBER) { + return -1; + } + kmp_socket_if_t *socket_if = NULL; ns_list_foreach(kmp_socket_if_t, entry, &kmp_socket_if_list) { @@ -181,7 +203,26 @@ static int8_t kmp_socket_if_send(kmp_service_t *service, uint8_t instance_id, km *ptr = kmp_id; } - socket_sendto(socket_if->socket_id, &socket_if->remote_addr, pdu, size); + int8_t socket_id = -1; + if ((socket_if->socket_id_in_use & (1 << connection_num)) && socket_if->socket_id[connection_num] >= 0) { + socket_id = socket_if->socket_id[connection_num]; + } else { + if (socket_if->socket_id[connection_num] < 0) { + socket_if->socket_id[connection_num] = socket_open(IPV6_NH_UDP, 0, &kmp_socket_if_socket_cb); + } + if (socket_if->socket_id[connection_num] < 0) { + return -1; + } + socket_if->socket_id_in_use |= (1 << connection_num); + } + + socket_sendto(socket_id, &socket_if->remote_addr, pdu, size); + + // Deallocate unless flags deny it + if (flags & MSG_IF_SEND_FLAG_NO_DEALLOC) { + return 0; + } + ns_dyn_mem_free(pdu); return 0; @@ -196,11 +237,15 @@ static void kmp_socket_if_socket_cb(void *ptr) } kmp_socket_if_t *socket_if = NULL; + uint8_t connection_num = 0; ns_list_foreach(kmp_socket_if_t, entry, &kmp_socket_if_list) { - if (entry->socket_id == cb_data->socket_id) { - socket_if = entry; - break; + for (uint8_t socket_num = 0; socket_num < INSTANCE_SOCKETS_NUMBER; socket_num++) { + if (entry->socket_id[socket_num] == cb_data->socket_id) { + socket_if = entry; + connection_num = socket_num; + break; + } } } @@ -237,7 +282,7 @@ static void kmp_socket_if_socket_cb(void *ptr) cb_data->d_len -= SOCKET_IF_HEADER_SIZE; } - kmp_service_msg_if_receive(socket_if->kmp_service, socket_if->instance_id, type, &addr, data_ptr, cb_data->d_len); + kmp_service_msg_if_receive(socket_if->kmp_service, socket_if->instance_id, type, &addr, data_ptr, cb_data->d_len, connection_num); ns_dyn_mem_free(pdu); } diff --git a/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c b/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c index 1513f99cb0f3..5c2f5ee0e498 100644 --- a/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c +++ b/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c @@ -177,7 +177,7 @@ uint8_t *eap_tls_sec_prot_lib_message_build(uint8_t eap_code, uint8_t eap_type, uint8_t *data_ptr = NULL; // Write EAP-TLS data (from EAP-TLS flags field onward) - if (tls_send->data) { + if (tls_send != NULL && tls_send->data) { data_ptr = eap_tls_sec_prot_lib_fragment_write(tls_send->data + TLS_HEAD_LEN, tls_send->total_len, tls_send->handled_len, &eap_len, flags); } diff --git a/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c b/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c index 2c85d85378dd..33c46eb8ae1b 100644 --- a/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c +++ b/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c @@ -65,20 +65,23 @@ typedef enum { // How many times initial EAPOL-key is accepted on wait for identity response state #define INITIAL_EAPOL_KEY_MAX_COUNT 2 +// How long to wait RADIUS client to proceed with handshake (RADIUS server to answer) +#define RADIUS_EAP_TLS_CLIENT_TIMEOUT 60 * 10 // 60 seconds + typedef struct { - sec_prot_common_t common; /**< Common data */ - sec_prot_t *radius_client_prot; /**< RADIUS client security protocol */ - sec_prot_receive *radius_client_send; /**< RADIUS client security protocol send (receive from peer) */ - eapol_pdu_t recv_eapol_pdu; /**< Received EAPOL PDU */ - tls_data_t tls_send; /**< EAP-TLS send buffer */ - uint16_t recv_eap_msg_len; /**< Received EAP message length */ - uint8_t *recv_eap_msg; /**< Received EAP message */ - uint16_t burst_filt_timer; /**< Burst filter timer */ - uint8_t eap_id_seq; /**< EAP sequence */ - uint8_t recv_eap_id_seq; /**< Last received EAP sequence */ - uint8_t eap_code; /**< Received EAP code */ - uint8_t eap_type; /**< Received EAP type */ - uint8_t init_key_cnt; /**< How many time initial EAPOL-key has been received */ + sec_prot_common_t common; /**< Common data */ + sec_prot_t *radius_client_prot; /**< RADIUS client security protocol */ + sec_prot_receive *radius_client_send; /**< RADIUS client security protocol send (receive from peer) */ + sec_prot_delete *radius_client_deleted; /**< RADIUS client security protocol peer deleted (notify to peer that radius EAP-TLS deleted) */ + eapol_pdu_t recv_eapol_pdu; /**< Received EAPOL PDU */ + uint16_t recv_eap_msg_len; /**< Received EAP message length */ + uint8_t *recv_eap_msg; /**< Received EAP message */ + uint16_t burst_filt_timer; /**< Burst filter timer */ + uint8_t eap_id_seq; /**< EAP sequence */ + uint8_t recv_eap_id_seq; /**< Last received EAP sequence */ + uint8_t eap_code; /**< Received EAP code */ + uint8_t eap_type; /**< Received EAP type */ + uint8_t init_key_cnt; /**< How many time initial EAPOL-key has been received */ } radius_eap_tls_sec_prot_int_t; static uint16_t radius_eap_tls_sec_prot_size(void); @@ -88,15 +91,18 @@ static void radius_eap_tls_sec_prot_create_request(sec_prot_t *prot, sec_prot_ke static void radius_eap_tls_sec_prot_delete(sec_prot_t *prot); static int8_t radius_eap_tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size); static int8_t radius_eap_tls_sec_prot_radius_client_receive(sec_prot_t *radius_client, void *pdu, uint16_t size); +static void radius_eap_tls_sec_prot_eap_tls_msg_free(sec_prot_t *prot); static int8_t radius_eap_tls_sec_prot_radius_eap_message_forward(sec_prot_t *prot, uint8_t *eap_code); +static int8_t radius_eap_tls_sec_prot_radius_eap_message_retry(sec_prot_t *prot); static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot); static int8_t radius_eap_tls_sec_prot_message_handle(sec_prot_t *prot, uint8_t *data_ptr, uint16_t *length); -static int8_t radius_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type, uint8_t tls_state); +static int8_t radius_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type); static void radius_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); static int8_t radius_eap_tls_sec_prot_init_radius_client(sec_prot_t *prot); +static void radius_eap_tls_sec_prot_radius_client_deleted(sec_prot_t *prot); static void radius_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot); @@ -126,6 +132,7 @@ static int8_t radius_eap_tls_sec_prot_init(sec_prot_t *prot) prot->create_resp = 0; prot->receive = radius_eap_tls_sec_prot_receive; prot->receive_peer = radius_eap_tls_sec_prot_radius_client_receive; + prot->peer_deleted = radius_eap_tls_sec_prot_radius_client_deleted; prot->delete = radius_eap_tls_sec_prot_delete; prot->state_machine = radius_eap_tls_sec_prot_state_machine; prot->timer_timeout = radius_eap_tls_sec_prot_timer_timeout; @@ -142,7 +149,6 @@ static int8_t radius_eap_tls_sec_prot_init(sec_prot_t *prot) data->recv_eap_id_seq = 0; data->eap_code = 0; data->eap_type = 0; - eap_tls_sec_prot_lib_message_init(&data->tls_send); data->init_key_cnt = 0; return 0; } @@ -150,7 +156,10 @@ static int8_t radius_eap_tls_sec_prot_init(sec_prot_t *prot) static void radius_eap_tls_sec_prot_delete(sec_prot_t *prot) { radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); - eap_tls_sec_prot_lib_message_free(&data->tls_send); + + if (data->recv_eap_msg != NULL) { + ns_dyn_mem_free(data->recv_eap_msg); + } } static void radius_eap_tls_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys) @@ -242,30 +251,13 @@ static int8_t radius_eap_tls_sec_prot_message_handle(sec_prot_t *prot, uint8_t * return EAP_TLS_MSG_CONTINUE; } -static int8_t radius_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type, uint8_t tls_state) +static int8_t radius_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type) { radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); uint8_t flags = 0xff; - // EAP-TLS flags field is always present during TLS exchange - if (tls_state == EAP_TLS_EXCHANGE_ONGOING) { - flags = 0x00; - } - - if (eap_code == EAP_REQ) { - if (eap_type == EAP_TLS && tls_state == EAP_TLS_EXCHANGE_START) { - eap_tls_sec_prot_lib_message_allocate(&data->tls_send, TLS_HEAD_LEN, 0); - flags = EAP_TLS_START; - } - } else if (eap_code == EAP_SUCCESS || eap_code == EAP_FAILURE) { - // Send Success and Failure with same identifier as received in EAP Response - data->eap_id_seq = data->recv_eap_id_seq; - } else { - return -1; - } - uint16_t eapol_pdu_size; - uint8_t *eapol_decoded_data = eap_tls_sec_prot_lib_message_build(eap_code, eap_type, &flags, data->eap_id_seq, prot->header_size, &data->tls_send, &eapol_pdu_size); + uint8_t *eapol_decoded_data = eap_tls_sec_prot_lib_message_build(eap_code, eap_type, &flags, data->eap_id_seq, prot->header_size, NULL, &eapol_pdu_size); if (!eapol_decoded_data) { return -1; } @@ -327,7 +319,23 @@ static int8_t radius_eap_tls_sec_prot_radius_eap_message_forward(sec_prot_t *pro eap_type == EAP_IDENTITY ? "IDENTITY" : "TLS", data->eap_id_seq, flags, eapol_pdu_size, trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); - if (prot->send(prot, data->recv_eap_msg, eapol_pdu_size + prot->header_size) < 0) { + if (prot->conn_send(prot, data->recv_eap_msg, eapol_pdu_size + prot->header_size, 0, SEC_PROT_SEND_FLAG_NO_DEALLOC) < 0) { + return -1; + } + data->recv_eap_msg_len = eapol_pdu_size + prot->header_size; + + return 0; +} + +static int8_t radius_eap_tls_sec_prot_radius_eap_message_retry(sec_prot_t *prot) +{ + radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + + if (data->recv_eap_msg == NULL || data->recv_eap_msg_len == 0) { + return -1; + } + + if (prot->conn_send(prot, data->recv_eap_msg, data->recv_eap_msg_len, 0, SEC_PROT_SEND_FLAG_NO_DEALLOC) < 0) { return -1; } @@ -357,6 +365,10 @@ static int8_t radius_eap_tls_sec_prot_radius_client_receive(sec_prot_t *radius_c radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + if (data->recv_eap_msg != NULL) { + ns_dyn_mem_free(data->recv_eap_msg); + } + data->recv_eap_msg_len = size; data->recv_eap_msg = pdu; @@ -365,6 +377,18 @@ static int8_t radius_eap_tls_sec_prot_radius_client_receive(sec_prot_t *radius_c return 0; } +static void radius_eap_tls_sec_prot_eap_tls_msg_free(sec_prot_t *prot) +{ + radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + + if (data->recv_eap_msg != NULL) { + ns_dyn_mem_free(data->recv_eap_msg); + } + + data->recv_eap_msg = NULL; + data->recv_eap_msg_len = 0; +} + static int8_t radius_eap_tls_sec_prot_init_radius_client(sec_prot_t *prot) { radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); @@ -377,10 +401,22 @@ static int8_t radius_eap_tls_sec_prot_init_radius_client(sec_prot_t *prot) return -1; } data->radius_client_send = data->radius_client_prot->receive_peer; + data->radius_client_deleted = data->radius_client_prot->peer_deleted; return 0; } +static void radius_eap_tls_sec_prot_radius_client_deleted(sec_prot_t *prot) +{ + radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + + tr_debug("EAP-TLS: client deleted"); + + data->radius_client_prot = NULL; + data->radius_client_send = NULL; + data->radius_client_deleted = NULL; +} + static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) { radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); @@ -390,14 +426,14 @@ static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) // EAP-TLS authenticator state machine switch (sec_prot_state_get(&data->common)) { case EAP_TLS_STATE_INIT: - tr_info("EAP-TLS init"); + tr_info("EAP-TLS: init"); sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_CREATE_REQ); prot->timer_start(prot); break; // Wait KMP-CREATE.request case EAP_TLS_STATE_CREATE_REQ: - tr_info("EAP-TLS start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + tr_info("EAP-TLS: start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); // Set default timeout for the total maximum length of the negotiation sec_prot_default_timeout_set(&data->common); @@ -409,7 +445,7 @@ static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) radius_eap_tls_sec_prot_seq_id_update(prot); // Sends EAP request, Identity - radius_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_IDENTITY, EAP_TLS_EXCHANGE_NONE); + radius_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_IDENTITY); // Start trickle timer to re-send if no response sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params); @@ -423,7 +459,7 @@ static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) // On timeout if (sec_prot_result_timeout_check(&data->common)) { // Re-sends EAP request, Identity - radius_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_IDENTITY, EAP_TLS_EXCHANGE_NONE); + radius_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_IDENTITY); return; } @@ -432,13 +468,22 @@ static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) return; } - tr_info("EAP-TLS EAP response id, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + tr_info("EAP-TLS: EAP response id, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); if (radius_eap_tls_sec_prot_init_radius_client(prot) < 0) { tr_error("EAP-TLS: radius client init failed"); return; } + // Free EAP request buffer since answer received and retries not needed + radius_eap_tls_sec_prot_eap_tls_msg_free(prot); + + // Stop trickle timer, radius client will continue + sec_prot_timer_trickle_stop(&data->common); + + // Set timeout to wait for RADIUS client to continue + data->common.ticks = RADIUS_EAP_TLS_CLIENT_TIMEOUT; + // Send to radius client data->radius_client_send(data->radius_client_prot, (void *) &data->recv_eapol_pdu, length); @@ -454,7 +499,7 @@ static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) return; } - tr_info("EAP-TLS EAP request, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + tr_info("EAP-TLS: EAP request, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); uint8_t eap_code; if (radius_eap_tls_sec_prot_radius_eap_message_forward(prot, &eap_code) < 0) { @@ -470,6 +515,9 @@ static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_FINISH); } + // Start trickle timer to re-send if no response + sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params); + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_EAP_RESPONSE); break; @@ -478,17 +526,29 @@ static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) // On timeout if (sec_prot_result_timeout_check(&data->common)) { - // Do nothing for now + tr_debug("EAP-TLS: retry EAP request, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + if (radius_eap_tls_sec_prot_radius_eap_message_retry(prot) < 0) { + tr_error("EAP-TLS: retry msg send error"); + } return; } - tr_info("EAP-TLS EAP response, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + tr_info("EAP-TLS: EAP response, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); // Handle EAP response if (radius_eap_tls_sec_prot_message_handle(prot, data_ptr, &length) != EAP_TLS_MSG_CONTINUE) { return; } + // Free EAP request buffer since answer received and retries not needed + radius_eap_tls_sec_prot_eap_tls_msg_free(prot); + + // Stop trickle timer, radius client will continue + sec_prot_timer_trickle_stop(&data->common); + + // Set timeout to wait for RADIUS client to continue + data->common.ticks = RADIUS_EAP_TLS_CLIENT_TIMEOUT; + // Send to radius client data->radius_client_send(data->radius_client_prot, (void *) &data->recv_eapol_pdu, length); @@ -507,6 +567,12 @@ static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) case EAP_TLS_STATE_FINISHED: { uint8_t *remote_eui_64 = sec_prot_remote_eui_64_addr_get(prot); tr_info("EAP-TLS finished, eui-64: %s", remote_eui_64 ? trace_array(sec_prot_remote_eui_64_addr_get(prot), 8) : "not set"); + + // Indicate to radius client peer protocol that radius EAP-TLS has been deleted + if (data->radius_client_deleted) { + data->radius_client_deleted(data->radius_client_prot); + } + prot->timer_stop(prot); prot->finished(prot); break; diff --git a/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c b/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c index a181cf0dd3cc..08072a726d3d 100644 --- a/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c +++ b/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c @@ -75,12 +75,17 @@ typedef enum { #define MS_MPPE_RECV_KEY_SALT_LEN 2 #define MS_MPPE_RECV_KEY_BLOCK_LEN 16 +#define RADIUS_CONN_NUMBER 3 +#define RADIUS_ID_RANGE_SIZE 10 +#define RADIUS_ID_RANGE_NUM (255 / RADIUS_ID_RANGE_SIZE) - 1 + typedef struct radius_client_sec_prot_lib_int_s radius_client_sec_prot_lib_int_t; typedef struct { sec_prot_common_t common; /**< Common data */ sec_prot_t *radius_eap_tls_prot; /**< Radius EAP-TLS security protocol */ sec_prot_receive *radius_eap_tls_send; /**< Radius EAP-TLS security protocol send (receive from peer) */ + sec_prot_delete *radius_eap_tls_deleted; /**< Radius EAP-TLS security protocol peer deleted (notify to peer that radius client deleted) */ uint8_t radius_eap_tls_header_size; /**< Radius EAP-TLS header size */ uint8_t new_pmk[PMK_LEN]; /**< New Pair Wise Master Key */ uint16_t recv_eap_msg_len; /**< Received EAP message length */ @@ -91,34 +96,46 @@ typedef struct { uint8_t *identity; /**< Supplicant EAP identity */ uint8_t radius_code; /**< Radius code that was received */ uint8_t radius_identifier; /**< Radius identifier that was last sent */ + uint8_t radius_id_conn_num; /**< Radius identifier connection number (socket instance) */ + uint8_t radius_id_range; /**< Radius identifier range */ uint8_t request_authenticator[16]; /**< Radius request authenticator that was last sent */ uint8_t state_len; /**< Radius state length that was last received */ uint8_t *state; /**< Radius state that was last received */ uint8_t remote_eui_64_hash[8]; /**< Remote EUI-64 hash used for calling station id */ bool remote_eui_64_hash_set : 1; /**< Remote EUI-64 hash used for calling station id set */ bool new_pmk_set : 1; /**< New Pair Wise Master Key set */ + bool radius_id_range_set : 1; /**< Radius identifier start value set */ } radius_client_sec_prot_int_t; typedef struct { - uint8_t radius_client_identifier; /**< Radius client identifier */ + uint8_t radius_identifier_timer[RADIUS_CONN_NUMBER][RADIUS_ID_RANGE_NUM]; + shared_comp_data_t comp_data; /**< Shared component data (timer, delete) */ uint8_t local_eui64_hash[8]; /**< Local EUI-64 hash used for called stations id */ uint8_t hash_random[16]; /**< Random used to generate local and remote EUI-64 hashes */ bool local_eui64_hash_set : 1; /**< Local EUI-64 hash used for called stations id set */ bool hash_random_set : 1; /**< Random used to generate local and remote EUI-64 hashes set */ + bool radius_id_timer_running : 1; /**> Radius identifier timer running */ } radius_client_sec_prot_shared_t; static uint16_t radius_client_sec_prot_size(void); static int8_t radius_client_sec_prot_init(sec_prot_t *prot); +static int8_t radius_client_sec_prot_shared_data_timeout(uint16_t ticks); +static void radius_identifier_timer_value_set(uint8_t conn_num, uint8_t id_range, uint8_t value); +static int8_t radius_client_sec_prot_shared_data_delete(void); +static void radius_identifier_timer_value_set(uint8_t conn_num, uint8_t id_range, uint8_t value); static void radius_client_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result); static void radius_client_sec_prot_delete(sec_prot_t *prot); static int8_t radius_client_sec_prot_receive_check(sec_prot_t *prot, const void *pdu, uint16_t size); static int8_t radius_client_sec_prot_init_radius_eap_tls(sec_prot_t *prot); +static void radius_client_sec_prot_radius_eap_tls_deleted(sec_prot_t *prot); static uint16_t radius_client_sec_prot_eap_avps_handle(uint16_t avp_length, uint8_t *avp_ptr, uint8_t *copy_to_ptr); -static int8_t radius_client_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size); +static int8_t radius_client_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size, uint8_t conn_number); static int8_t radius_client_sec_prot_radius_eap_receive(sec_prot_t *prot, void *pdu, uint16_t size); static void radius_client_sec_prot_allocate_and_create_radius_message(sec_prot_t *prot); static int8_t radius_client_sec_prot_radius_msg_send(sec_prot_t *prot); -static uint8_t radius_client_sec_prot_identifier_allocate(void); +static void radius_client_sec_prot_radius_msg_free(sec_prot_t *prot); +static uint8_t radius_client_sec_prot_identifier_allocate(sec_prot_t *prot, uint8_t value); +static void radius_client_sec_prot_identifier_free(sec_prot_t *prot); static uint8_t radius_client_sec_prot_hex_to_ascii(uint8_t value); static int8_t radius_client_sec_prot_eui_64_hash_generate(uint8_t *eui_64, uint8_t *hashed_eui_64); static void radius_client_sec_prot_station_id_generate(uint8_t *eui_64, uint8_t *station_id_ptr); @@ -131,6 +148,17 @@ static void radius_client_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t tick #define radius_client_sec_prot_get(prot) (radius_client_sec_prot_int_t *) &prot->data +#define RADIUS_CLIENT_RETRY_IMIN 100 // Retries done in 10 seconds +#define RADIUS_CLIENT_RETRY_IMAX 200 // Largest value 20 seconds +#define RADIUS_CLIENT_TIMER_EXPIRATIONS 2 // Number of retries + +const trickle_params_t radius_client_trickle_params = { + .Imin = RADIUS_CLIENT_RETRY_IMIN, + .Imax = RADIUS_CLIENT_RETRY_IMAX, + .k = 0, + .TimerExpirations = RADIUS_CLIENT_TIMER_EXPIRATIONS +}; + // Data shared between radius client instances static radius_client_sec_prot_shared_t *shared_data = NULL; @@ -152,12 +180,55 @@ static uint16_t radius_client_sec_prot_size(void) return sizeof(radius_client_sec_prot_int_t); } +static int8_t radius_client_sec_prot_shared_data_timeout(uint16_t ticks) +{ + if (shared_data == NULL || !shared_data->radius_id_timer_running) { + return -1; + } + + bool timer_running = false; + + for (uint8_t conn_num = 0; conn_num < RADIUS_CONN_NUMBER; conn_num++) { + for (uint8_t id_range = 0; id_range < RADIUS_ID_RANGE_NUM; id_range++) { + if (shared_data->radius_identifier_timer[conn_num][id_range] > ticks) { + shared_data->radius_identifier_timer[conn_num][id_range] -= ticks; + timer_running = true; + } else { + shared_data->radius_identifier_timer[conn_num][id_range] = 0; + } + } + } + + if (!timer_running) { + shared_data->radius_id_timer_running = false; + } + + return 0; +} + +static void radius_identifier_timer_value_set(uint8_t conn_num, uint8_t id_range, uint8_t value) +{ + shared_data->radius_identifier_timer[conn_num][id_range] = value; + shared_data->radius_id_timer_running = true; +} + +static int8_t radius_client_sec_prot_shared_data_delete(void) +{ + if (shared_data == NULL) { + return -1; + } + ns_dyn_mem_free(shared_data); + shared_data = NULL; + return 0; +} + static int8_t radius_client_sec_prot_init(sec_prot_t *prot) { prot->create_req = NULL; prot->create_resp = radius_client_sec_prot_create_response; - prot->receive = radius_client_sec_prot_receive; + prot->conn_receive = radius_client_sec_prot_receive; prot->receive_peer = radius_client_sec_prot_radius_eap_receive; + prot->peer_deleted = radius_client_sec_prot_radius_eap_tls_deleted; prot->delete = radius_client_sec_prot_delete; prot->state_machine = radius_client_sec_prot_state_machine; prot->timer_timeout = radius_client_sec_prot_timer_timeout; @@ -192,11 +263,14 @@ static int8_t radius_client_sec_prot_init(sec_prot_t *prot) if (!shared_data) { return -1; } - shared_data->radius_client_identifier = 0; - memset(shared_data->local_eui64_hash, 0, 8); - memset(shared_data->hash_random, 0, 16); + memset(shared_data, 0, sizeof(radius_client_sec_prot_shared_t)); shared_data->local_eui64_hash_set = false; shared_data->hash_random_set = false; + shared_data->radius_id_timer_running = false; + // Add as shared component to enable timers and delete + shared_data->comp_data.timeout = radius_client_sec_prot_shared_data_timeout; + shared_data->comp_data.delete = radius_client_sec_prot_shared_data_delete; + prot->shared_comp_add(prot, &shared_data->comp_data); } return 0; @@ -256,10 +330,22 @@ static int8_t radius_client_sec_prot_init_radius_eap_tls(sec_prot_t *prot) } data->radius_eap_tls_header_size = data->radius_eap_tls_prot->receive_peer_hdr_size; data->radius_eap_tls_send = data->radius_eap_tls_prot->receive_peer; + data->radius_eap_tls_deleted = data->radius_eap_tls_prot->peer_deleted; return 0; } +static void radius_client_sec_prot_radius_eap_tls_deleted(sec_prot_t *prot) +{ + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); + + tr_debug("Radius: EAP-TLS deleted"); + + data->radius_eap_tls_prot = NULL; + data->radius_eap_tls_send = NULL; + data->radius_eap_tls_deleted = NULL; +} + static uint16_t radius_client_sec_prot_eap_avps_handle(uint16_t avp_length, uint8_t *avp_ptr, uint8_t *copy_to_ptr) { // Calculate EAP AVPs length and copy EAP AVPs to continuous buffer if buffer is give @@ -290,8 +376,10 @@ static uint16_t radius_client_sec_prot_eap_avps_handle(uint16_t avp_length, uint return eap_len; } -static int8_t radius_client_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size) +static int8_t radius_client_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size, uint8_t conn_number) { + (void) conn_number; + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); if (size < RADIUS_MSG_FIXED_LENGTH) { @@ -312,6 +400,10 @@ static int8_t radius_client_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16 uint16_t length = common_read_16_bit(radius_msg_ptr); radius_msg_ptr += 2; + if (length < RADIUS_MSG_FIXED_LENGTH) { + return -1; + } + // Store response authenticator uint8_t recv_response_authenticator[16]; memcpy(recv_response_authenticator, radius_msg_ptr, 16); @@ -333,11 +425,23 @@ static int8_t radius_client_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16 return -1; } - uint16_t avp_length = length - RADIUS_MSG_FIXED_LENGTH; + // Response authenticator matches, start validating radius EAP-TLS specific fields + data->recv_eap_msg = NULL; + data->recv_eap_msg_len = 0; + + uint16_t avp_length = 0; + if (length >= RADIUS_MSG_FIXED_LENGTH) { + avp_length = length - RADIUS_MSG_FIXED_LENGTH; + } uint8_t *message_authenticator = avp_message_authenticator_read(radius_msg_ptr, avp_length); - if (message_authenticator == NULL) { + if (message_authenticator == NULL || avp_length == 0) { tr_error("No message authenticator"); + // Message does not have radius EAP-TLS specific fields + data->radius_code = code; + prot->state_machine(prot); + + return 0; } // Store message authenticator @@ -442,9 +546,43 @@ static int8_t radius_client_sec_prot_radius_eap_receive(sec_prot_t *prot, void * return 0; } -static uint8_t radius_client_sec_prot_identifier_allocate(void) +static uint8_t radius_client_sec_prot_identifier_allocate(sec_prot_t *prot, uint8_t value) +{ + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); + + if (!data->radius_id_range_set || value >= (data->radius_id_range * RADIUS_ID_RANGE_SIZE) + RADIUS_ID_RANGE_SIZE) { + for (uint8_t conn_num = 0; conn_num < RADIUS_CONN_NUMBER; conn_num++) { + for (uint8_t id_range = 0; id_range < RADIUS_ID_RANGE_NUM; id_range++) { + if (shared_data->radius_identifier_timer[conn_num][id_range] == 0) { + // If range has been already reserved + if (data->radius_id_range_set) { + // Set previous range to timeout in 5 seconds + radius_identifier_timer_value_set(data->radius_id_conn_num, data->radius_id_range, 5); + } + // Set timeout for new range to 60 seconds + radius_identifier_timer_value_set(conn_num, id_range, 60); + data->radius_id_conn_num = conn_num; + data->radius_id_range = id_range; + data->radius_id_range_set = true; + return id_range * RADIUS_ID_RANGE_SIZE; + } + } + } + } else { + radius_identifier_timer_value_set(data->radius_id_conn_num, data->radius_id_range, 60); + return value + 1; + } + + return 0; +} + +static void radius_client_sec_prot_identifier_free(sec_prot_t *prot) { - return shared_data->radius_client_identifier++; + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); + + if (data->radius_id_range_set) { + radius_identifier_timer_value_set(data->radius_id_conn_num, data->radius_id_range, 5); + } } static uint8_t radius_client_sec_prot_eui_64_hash_get(sec_prot_t *prot, uint8_t *local_eui_64_hash, uint8_t *remote_eui_64_hash, bool remote_eui_64_hash_set) @@ -524,7 +662,7 @@ static void radius_client_sec_prot_allocate_and_create_radius_message(sec_prot_t uint8_t *radius_msg_start_ptr = radius_msg_ptr; *radius_msg_ptr++ = RADIUS_ACCESS_REQUEST; // code - data->radius_identifier = radius_client_sec_prot_identifier_allocate(); + data->radius_identifier = radius_client_sec_prot_identifier_allocate(prot, data->radius_identifier); *radius_msg_ptr++ = data->radius_identifier; // identifier radius_msg_ptr = common_write_16_bit(radius_msg_length, radius_msg_ptr); // length @@ -604,15 +742,25 @@ static int8_t radius_client_sec_prot_radius_msg_send(sec_prot_t *prot) return -1; } - if (prot->send(prot, data->send_radius_msg, data->send_radius_msg_len) < 0) { + if (prot->conn_send(prot, data->send_radius_msg, data->send_radius_msg_len, data->radius_id_conn_num, SEC_PROT_SEND_FLAG_NO_DEALLOC) < 0) { return -1; } - data->send_radius_msg = NULL; - data->send_radius_msg_len = 0; return 0; } +static void radius_client_sec_prot_radius_msg_free(sec_prot_t *prot) +{ + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); + + if (data->send_radius_msg != NULL) { + ns_dyn_mem_free(data->send_radius_msg); + } + + data->send_radius_msg = NULL; + data->send_radius_msg_len = 0; +} + static int8_t radius_client_sec_prot_eui_64_hash_generate(uint8_t *eui_64, uint8_t *hashed_eui_64) { int8_t ret_val = 0; @@ -852,8 +1000,7 @@ static void radius_client_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t tick { radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); - sec_prot_timer_timeout_handle(prot, &data->common, - &prot->sec_cfg->prot_cfg.sec_prot_trickle_params, ticks); + sec_prot_timer_timeout_handle(prot, &data->common, &radius_client_trickle_params, ticks); } static void radius_client_sec_prot_state_machine(sec_prot_t *prot) @@ -906,7 +1053,7 @@ static void radius_client_sec_prot_state_machine(sec_prot_t *prot) } // Start trickle timer to re-send if no response - sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &radius_client_trickle_params); sec_prot_state_set(prot, &data->common, RADIUS_STATE_ACCESS_ACCEPT_REJECT_CHALLENGE); break; @@ -915,14 +1062,32 @@ static void radius_client_sec_prot_state_machine(sec_prot_t *prot) // On timeout if (sec_prot_result_timeout_check(&data->common)) { - // Do nothing for now + tr_debug("Radius: retry access request, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + if (radius_client_sec_prot_radius_msg_send(prot) < 0) { + tr_error("Radius: retry msg send error"); + } return; } tr_debug("Radius: received access accept/reject/challenge, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + // Free radius access-request buffer since answer received and retries not needed + radius_client_sec_prot_radius_msg_free(prot); + + // Stop trickle timer, EAP-TLS will continue and on reject/accept negotiation will end + sec_prot_timer_trickle_stop(&data->common); + + // Set timeout to wait for EAP-TLS to continue + data->common.ticks = prot->sec_cfg->prot_cfg.sec_prot_retry_timeout; + // Send to radius EAP-TLS - data->radius_eap_tls_send(data->radius_eap_tls_prot, (void *) data->recv_eap_msg, data->recv_eap_msg_len); + if (data->radius_eap_tls_send && data->radius_eap_tls_prot && data->recv_eap_msg && data->recv_eap_msg_len > 0) { + data->radius_eap_tls_send(data->radius_eap_tls_prot, (void *) data->recv_eap_msg, data->recv_eap_msg_len); + } else { + if (data->recv_eap_msg) { + ns_dyn_mem_free(data->recv_eap_msg); + } + } data->recv_eap_msg = NULL; data->recv_eap_msg_len = 0; @@ -945,7 +1110,10 @@ static void radius_client_sec_prot_state_machine(sec_prot_t *prot) // On timeout if (sec_prot_result_timeout_check(&data->common)) { - // Do nothing for now + tr_debug("Radius: retry access request, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + if (radius_client_sec_prot_radius_msg_send(prot) < 0) { + tr_error("Radius: retry msg send error"); + } return; } @@ -957,6 +1125,9 @@ static void radius_client_sec_prot_state_machine(sec_prot_t *prot) tr_error("Radius: msg send error"); } + // Start trickle timer to re-send if no response + sec_prot_timer_trickle_start(&data->common, &radius_client_trickle_params); + sec_prot_state_set(prot, &data->common, RADIUS_STATE_ACCESS_ACCEPT_REJECT_CHALLENGE); break; @@ -982,6 +1153,13 @@ static void radius_client_sec_prot_state_machine(sec_prot_t *prot) uint8_t *remote_eui_64 = sec_prot_remote_eui_64_addr_get(prot); tr_debug("Radius: finished, eui-64: %s", remote_eui_64 ? trace_array(remote_eui_64, 8) : "not set"); + radius_client_sec_prot_identifier_free(prot); + + // Indicate to radius EAP-TLS peer protocol that radius client has been deleted + if (data->radius_eap_tls_deleted) { + data->radius_eap_tls_deleted(data->radius_eap_tls_prot); + } + prot->timer_stop(prot); prot->finished(prot); break; diff --git a/source/Security/protocols/sec_prot.h b/source/Security/protocols/sec_prot.h index 3c7724124eed..565ad5148a51 100644 --- a/source/Security/protocols/sec_prot.h +++ b/source/Security/protocols/sec_prot.h @@ -61,6 +61,9 @@ typedef enum { SEC_PROT_TX_ERR_UNSPEC = -2, // Other reason } sec_prot_tx_status_e; +// On security protocol send, do not deallocate pdu buffer +#define SEC_PROT_SEND_FLAG_NO_DEALLOC 0x01 + /** * sec_prot_create_request KMP-CREATE.request to security protocol * @@ -128,6 +131,7 @@ typedef void sec_prot_finished_send(sec_prot_t *prot); * \param prot protocol * \param pdu pdu * \param size pdu size + * \param conn_number connection number * * \return < 0 failure * \return >= 0 success @@ -148,6 +152,35 @@ typedef int8_t sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size); */ typedef int8_t sec_prot_send(sec_prot_t *prot, void *pdu, uint16_t size); +/** + * sec_prot_conn_receive receive a message for a connection number + * + * \param prot protocol + * \param pdu pdu + * \param size pdu size + * \param conn_number connection number + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t sec_prot_conn_receive(sec_prot_t *prot, void *pdu, uint16_t size, uint8_t conn_number); + +/** + * sec_prot_conn_send send a message for a connection number and/or with flags + * + * \param prot protocol + * \param pdu pdu + * \param size pdu size + * \param conn_number connection number + * \param flags flags + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t sec_prot_conn_send(sec_prot_t *prot, void *pdu, uint16_t size, uint8_t conn_number, uint8_t flags); + /** * sec_prot_tx_status_ind tx status indication * @@ -184,6 +217,14 @@ typedef void sec_prot_state_machine(sec_prot_t *prot); */ typedef void sec_prot_state_machine_call(sec_prot_t *prot); +/** + * sec_prot_cont_timer_timeout cont timer timeout + * + * \param ticks timer ticks + * + */ +typedef void sec_prot_cont_timer_timeout(uint16_t ticks); + /** * sec_prot_timer_start start timer * @@ -209,6 +250,55 @@ typedef void sec_prot_timer_stop(sec_prot_t *prot); */ typedef void sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); +/** + * sec_prot_shared_comp_timer_timeout shared component timer timeout + * + * \param ticks timer ticks + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t sec_prot_shared_comp_timer_timeout(uint16_t ticks); + +/** + * sec_prot_shared_comp_delete shared component delete + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t sec_prot_shared_comp_delete(void); + +typedef struct { + sec_prot_shared_comp_timer_timeout *timeout; + sec_prot_shared_comp_delete *delete; +} shared_comp_data_t; + +/** + * sec_prot_shared_comp_add add shared component + * + * \param prot protocol + * \param data shared component data + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t sec_prot_shared_comp_add(sec_prot_t *prot, shared_comp_data_t *data); + +/** + * sec_prot_shared_comp_remove remove shared component + * + * \param prot protocol + * \param data shared component data + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t sec_prot_shared_comp_remove(sec_prot_t *prot, shared_comp_data_t *data); + /** * sec_prot_eui64_addr_get gets EUI-64 addresses * @@ -277,7 +367,10 @@ struct sec_prot_s { sec_prot_send *send; /**< Protocol send */ sec_prot_receive *receive; /**< Protocol receive */ + sec_prot_conn_send *conn_send; /**< Protocol connection send */ + sec_prot_conn_receive *conn_receive; /**< Protocol connection receive */ sec_prot_receive *receive_peer; /**< Protocol receive from peer (used by peer protocol for send) */ + sec_prot_delete *peer_deleted; /**< Protocol peer has been deleted (notifies that peer no longer exists */ sec_prot_tx_status_ind *tx_status_ind; /**< TX status indication */ @@ -290,6 +383,9 @@ struct sec_prot_s { sec_prot_timer_stop *timer_stop; /**< Stop timer */ sec_prot_timer_timeout *timer_timeout; /**< Timer timeout */ + sec_prot_shared_comp_add *shared_comp_add; /**< Shared component add */ + sec_prot_shared_comp_remove *shared_comp_remove; /**< Shared component remove */ + sec_prot_eui64_addr_get *addr_get; /**< Gets EUI-64 addresses */ sec_prot_ip_addr_get *ip_addr_get; /**< Gets IP address */ sec_prot_by_type_get *type_get; /**< Gets security protocol by type */ @@ -300,6 +396,7 @@ struct sec_prot_s { sec_cfg_t *sec_cfg; /**< Security configuration configuration pointer */ uint8_t header_size; /**< Header size */ uint8_t receive_peer_hdr_size; /**< Receive from peer header size */ + uint8_t number_of_conn; /**< Number of connections */ uint8_t msg_if_instance_id; /**< Message interface instance identifier */ sec_prot_int_data_t *data; /**< Protocol internal data */ };