diff --git a/nanostack/dhcp_service_api.h b/nanostack/dhcp_service_api.h index 27315a5540..e4759a5951 100644 --- a/nanostack/dhcp_service_api.h +++ b/nanostack/dhcp_service_api.h @@ -217,6 +217,16 @@ void dhcp_service_update_server_address(uint32_t msg_tr_id, uint8_t *server_addr */ void dhcp_service_req_remove(uint32_t msg_tr_id); +/** + * \brief Stops transactions for a messages (retransmissions). + * + * Clears off sending retransmissions for a particular message transaction by finding it via its message class pointer. + * + * \param msg_class_ptr The message class pointer. + * + */ +void dhcp_service_req_remove_all(void *msg_class_ptr); + /** * \brief Timer tick function for retransmissions. * diff --git a/nanostack/sw_mac.h b/nanostack/sw_mac.h index 6bdfc7eeb7..e4a018fc4e 100644 --- a/nanostack/sw_mac.h +++ b/nanostack/sw_mac.h @@ -97,6 +97,14 @@ extern int ns_sw_mac_phy_statistics_start(struct mac_api_s *mac_api, struct phy_ */ extern uint32_t ns_sw_mac_read_current_timestamp(struct mac_api_s *mac_api); +/** + * @brief Enable or disable Frame counter per security key. SW MAC must be create before enable this feature! + * @param mac_api MAC instance. + * @param enable_feature True will allocate frame counter table for devices / key False will clear mode and free counter table. + * @return 0 on success, -1 on fail. + */ +extern int8_t ns_sw_mac_enable_frame_counter_per_key(struct mac_api_s *mac_api, bool enable_feature); + #ifdef __cplusplus } #endif diff --git a/nanostack/ws_bbr_api.h b/nanostack/ws_bbr_api.h index dbfb20b25a..a4d4d460e8 100644 --- a/nanostack/ws_bbr_api.h +++ b/nanostack/ws_bbr_api.h @@ -140,4 +140,26 @@ int ws_bbr_node_access_revoke_start(int8_t interface_id); */ int ws_bbr_eapol_node_limit_set(int8_t interface_id, uint16_t limit); +/** + * Extended certificate validation + */ +#define BBR_CRT_EXT_VALID_NONE 0x00 /**< Do not make extended validations */ +#define BBR_CRT_EXT_VALID_WISUN 0x01 /**< Validate Wi-SUN specific fields */ + +/** + * Sets extended certificate validation setting + * + * Sets extended certificate validation setting on border router. Function can be used + * to set which fields on client certificate are validated. + * + * \param interface_id Network interface ID + * \param validation Extended Certificate validation setting + * BBR_CRT_EXT_VALID_NONE Do not make extended validations + * BBR_CRT_EXT_VALID_WISUN Validate Wi-SUN specific fields + * + * \return 0 Validation setting was set + * \return <0 Setting set failed + */ +int ws_bbr_ext_certificate_validation_set(int8_t interface_id, uint8_t validation); + #endif /* WS_BBR_API_H_ */ diff --git a/source/6LoWPAN/MAC/mac_helper.c b/source/6LoWPAN/MAC/mac_helper.c index 177113f46e..f6bc6626f6 100644 --- a/source/6LoWPAN/MAC/mac_helper.c +++ b/source/6LoWPAN/MAC/mac_helper.c @@ -349,12 +349,12 @@ int8_t mac_helper_security_default_recv_key_set(protocol_interface_info_entry_t return 0; } -int8_t mac_helper_security_auto_request_key_index_set(protocol_interface_info_entry_t *interface, uint8_t id) +int8_t mac_helper_security_auto_request_key_index_set(protocol_interface_info_entry_t *interface, uint8_t key_attibute_index, uint8_t id) { if (id == 0) { return -1; } - + interface->mac_parameters->mac_default_key_attribute_id = key_attibute_index; mac_helper_pib_8bit_set(interface, macAutoRequestKeyIndex, id); return 0; } @@ -442,13 +442,11 @@ void mac_helper_security_key_swap_next_to_default(protocol_interface_info_entry_ interface->mac_parameters->mac_prev_key_index = interface->mac_parameters->mac_default_key_index; interface->mac_parameters->mac_prev_key_attribute_id = interface->mac_parameters->mac_default_key_attribute_id; - interface->mac_parameters->mac_default_key_index = interface->mac_parameters->mac_next_key_index; - interface->mac_parameters->mac_default_key_attribute_id = interface->mac_parameters->mac_next_key_attribute_id; + mac_helper_security_auto_request_key_index_set(interface, interface->mac_parameters->mac_next_key_attribute_id, interface->mac_parameters->mac_next_key_index); + interface->mac_parameters->mac_next_key_index = 0; interface->mac_parameters->mac_next_key_attribute_id = prev_attribute; - mac_helper_pib_8bit_set(interface, macAutoRequestKeyIndex, interface->mac_parameters->mac_default_key_index); - } void mac_helper_security_key_clean(protocol_interface_info_entry_t *interface) @@ -841,7 +839,7 @@ int8_t mac_helper_link_frame_counter_read(int8_t interface_id, uint32_t *seq_ptr } mlme_get_t get_req; get_req.attr = macFrameCounter; - get_req.attr_index = 0; + get_req.attr_index = cur->mac_parameters->mac_default_key_attribute_id; cur->mac_api->mlme_req(cur->mac_api, MLME_GET, &get_req); *seq_ptr = cur->mac_parameters->security_frame_counter; @@ -858,7 +856,7 @@ int8_t mac_helper_link_frame_counter_set(int8_t interface_id, uint32_t seq_ptr) } mlme_set_t set_req; set_req.attr = macFrameCounter; - set_req.attr_index = 0; + set_req.attr_index = cur->mac_parameters->mac_default_key_attribute_id; set_req.value_pointer = &seq_ptr; set_req.value_size = 4; cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); diff --git a/source/6LoWPAN/MAC/mac_helper.h b/source/6LoWPAN/MAC/mac_helper.h index 025df0313b..3cee017539 100644 --- a/source/6LoWPAN/MAC/mac_helper.h +++ b/source/6LoWPAN/MAC/mac_helper.h @@ -69,7 +69,7 @@ int8_t mac_helper_security_default_key_set(struct protocol_interface_info_entry int8_t mac_helper_security_default_recv_key_set(struct protocol_interface_info_entry *interface, const uint8_t *key, uint8_t id, uint8_t keyid_mode); -int8_t mac_helper_security_auto_request_key_index_set(struct protocol_interface_info_entry *interface, uint8_t id); +int8_t mac_helper_security_auto_request_key_index_set(struct protocol_interface_info_entry *interface, uint8_t key_attibute_index, uint8_t id); int8_t mac_helper_security_next_key_set(struct protocol_interface_info_entry *interface, uint8_t *key, uint8_t id, uint8_t keyid_mode); diff --git a/source/6LoWPAN/ws/ws_bbr_api.c b/source/6LoWPAN/ws/ws_bbr_api.c index 317ab8ac78..f01c07b110 100644 --- a/source/6LoWPAN/ws/ws_bbr_api.c +++ b/source/6LoWPAN/ws/ws_bbr_api.c @@ -636,3 +636,18 @@ int ws_bbr_eapol_node_limit_set(int8_t interface_id, uint16_t limit) return -1; #endif } + +int ws_bbr_ext_certificate_validation_set(int8_t interface_id, uint8_t validation) +{ + (void) interface_id; +#ifdef HAVE_WS_BORDER_ROUTER + bool enabled = false; + if (validation & BBR_CRT_EXT_VALID_WISUN) { + enabled = true; + } + return ws_pae_controller_ext_certificate_validation_set(interface_id, enabled); +#else + (void) validation; + return -1; +#endif +} diff --git a/source/6LoWPAN/ws/ws_bootstrap.c b/source/6LoWPAN/ws/ws_bootstrap.c index 8483b7de8e..cc651f1033 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.c +++ b/source/6LoWPAN/ws/ws_bootstrap.c @@ -1371,7 +1371,7 @@ static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_ent //Read current timestamp uint32_t time_from_last_unicast_shedule = ws_time_from_last_unicast_traffic(current_time_stamp, ws_neighbor); - if (time_from_last_unicast_shedule > WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT || !ws_neighbor->unicast_data_rx) { + if (time_from_last_unicast_shedule > WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT) { //Accept only Enough Old Device if (!neighbor_entry_ptr) { //Accept first compare @@ -1581,6 +1581,10 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode) return -2; } + if (ns_sw_mac_enable_frame_counter_per_key(cur->mac_api, true)) { + return -1; + } + if (!etx_storage_list_allocate(cur->id, buffer.device_decription_table_size)) { return -1; } @@ -1940,6 +1944,9 @@ static void ws_dhcp_client_global_adress_cb(int8_t interface, uint8_t dhcp_addr[ if (cur) { rpl_control_register_address(cur, prefix); } + } else { + //Delete dhcpv6 client + dhcp_client_global_address_delete(interface, dhcp_addr, prefix); } } @@ -2055,6 +2062,9 @@ static void ws_bootstrap_rpl_activate(protocol_interface_info_entry_t *cur) // If i am router I Do this rpl_control_force_leaf(protocol_6lowpan_rpl_domain, leaf); rpl_control_request_parent_link_confirmation(true); + rpl_control_set_dio_multicast_min_config_advertisment_count(WS_MIN_DIO_MULTICAST_CONFIG_ADVERTISMENT_COUNT); + rpl_control_set_dao_retry_count(WS_MAX_DAO_RETRIES); + rpl_control_set_initial_dao_ack_wait(WS_MAX_DAO_INITIAL_TIMEOUT); cur->ws_info->rpl_state = 0xff; // Set invalid state and learn from event } @@ -2107,7 +2117,9 @@ static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur) ws_bootstrap_neighbor_list_clean(cur); // Clear RPL information - rpl_control_remove_domain_from_interface(cur); + rpl_control_free_domain_instances_from_interface(cur); + // Clear EAPOL relay address + ws_eapol_relay_delete(cur); // Clear ip stack from old information ws_bootstrap_ip_stack_reset(cur); @@ -2169,7 +2181,7 @@ static void ws_bootstrap_nw_key_clear(protocol_interface_info_entry_t *cur, uint static void ws_bootstrap_nw_key_index_set(protocol_interface_info_entry_t *cur, uint8_t index) { // Set send key - mac_helper_security_auto_request_key_index_set(cur, index + 1); + mac_helper_security_auto_request_key_index_set(cur, index, index + 1); } static void ws_bootstrap_nw_frame_counter_set(protocol_interface_info_entry_t *cur, uint32_t counter) diff --git a/source/6LoWPAN/ws/ws_common.c b/source/6LoWPAN/ws/ws_common.c index e9a8e025c1..cb2970ec1b 100644 --- a/source/6LoWPAN/ws/ws_common.c +++ b/source/6LoWPAN/ws/ws_common.c @@ -31,6 +31,8 @@ #include "Service_Libs/etx/etx.h" #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" #include "Service_Libs/blacklist/blacklist.h" +#include "RPL/rpl_protocol.h" +#include "RPL/rpl_control.h" #include "ws_management_api.h" #include "mac_api.h" @@ -404,6 +406,13 @@ bool ws_common_allow_child_registration(protocol_interface_info_entry_t *interfa return true; } + //Verify that we have Selected Parent + if (interface->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER && !rpl_control_parent_candidate_list_size(interface, true)) { + tr_info("Do not accept new ARO child: no selected parent"); + return false; + } + + ns_list_foreach_safe(mac_neighbor_table_entry_t, cur, &mac_neighbor_info(interface)->neighbour_list) { if (ipv6_neighbour_has_registered_by_eui64(&interface->ipv6_neighbour_cache, cur->mac64)) { diff --git a/source/6LoWPAN/ws/ws_config.h b/source/6LoWPAN/ws/ws_config.h index 0d63c67c6b..ee05b7fb44 100644 --- a/source/6LoWPAN/ws/ws_config.h +++ b/source/6LoWPAN/ws/ws_config.h @@ -133,4 +133,12 @@ extern uint8_t DEVICE_MIN_SENS; #define FRAME_COUNTER_INCREMENT 1000 // How much frame counter is incremented on start up #define FRAME_COUNTER_STORE_THRESHOLD 800 // How much frame counter must increment before it is stored + +/* + * RPL Configuration parameters + */ +#define WS_MAX_DAO_RETRIES 3 // With 40s, 80s, 160s, 320s, 640s +#define WS_MAX_DAO_INITIAL_TIMEOUT 400 // With 40s initial value exponentially increasing +#define WS_MIN_DIO_MULTICAST_CONFIG_ADVERTISMENT_COUNT 10 // Define 10 multicast advertisment when learn config or learn config update + #endif /* WS_CONFIG_H_ */ diff --git a/source/6LoWPAN/ws/ws_pae_auth.c b/source/6LoWPAN/ws/ws_pae_auth.c index 8e20e856fb..e4ec775a39 100644 --- a/source/6LoWPAN/ws/ws_pae_auth.c +++ b/source/6LoWPAN/ws/ws_pae_auth.c @@ -919,12 +919,12 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup kmp_api_t *api = ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, next_type); if (api != NULL) { + /* For other types than GTK, only one ongoing negotiation at the same time, + for GTK there can be previous terminating and the new one for next key index */ if (next_type != IEEE_802_11_GKH) { tr_info("KMP already ongoing; ignored, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8)); return; } - // Delete KMP - ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, api); } } diff --git a/source/6LoWPAN/ws/ws_pae_controller.c b/source/6LoWPAN/ws/ws_pae_controller.c index 086ec06393..11e2c455cb 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.c +++ b/source/6LoWPAN/ws/ws_pae_controller.c @@ -100,6 +100,7 @@ typedef struct { typedef struct { uint16_t node_limit; /**< Max number of stored supplicants */ bool node_limit_set : 1; /**< Node limit set */ + bool ext_cert_valid_enabled : 1; /**< Extended certificate validation enabled */ } pae_controller_config_t; static pae_controller_t *ws_pae_controller_get(protocol_interface_info_entry_t *interface_ptr); @@ -126,7 +127,8 @@ static NS_LIST_DEFINE(pae_controller_list, pae_controller_t, link); pae_controller_config_t pae_controller_config = { .node_limit = 0, - .node_limit_set = false + .node_limit_set = false, + .ext_cert_valid_enabled = false }; #if !defined(HAVE_PAE_SUPP) && !defined(HAVE_PAE_AUTH) @@ -482,9 +484,12 @@ static void ws_pae_controller_nw_key_index_check_and_set(protocol_interface_info controller->gtk_index = index; uint32_t frame_counter = ws_pae_controller_frame_counter_get(&controller->stored_frame_counter, index, controller->nw_key[index].hash); - controller->nw_frame_counter_set(interface_ptr, frame_counter); + if (frame_counter) { + controller->nw_frame_counter_set(interface_ptr, frame_counter); + } tr_info("NW frame counter set: %"PRIu32"", frame_counter); ws_pae_controller_frame_counter_write(controller, index, controller->nw_key[index].hash, frame_counter); + } // Do not update PAN version for initial key index set @@ -511,9 +516,12 @@ static void ws_pae_controller_active_nw_key_set(protocol_interface_info_entry_t // If index has changed and the key for the index is fresh get frame counter if (controller->gtk_index != index && controller->nw_key[index].fresh) { uint32_t frame_counter = ws_pae_controller_frame_counter_get(&controller->stored_frame_counter, index, controller->nw_key[index].hash); - controller->nw_frame_counter_set(cur, frame_counter); + if (frame_counter) { + controller->nw_frame_counter_set(cur, frame_counter); + } tr_info("NW frame counter set: %"PRIu32"", frame_counter); ws_pae_controller_frame_counter_write(controller, index, controller->nw_key[index].hash, frame_counter); + } controller->gtk_index = index; @@ -586,6 +594,7 @@ static void ws_pae_controller_data_init(pae_controller_t *controller) sec_prot_keys_gtks_init(&controller->gtks); sec_prot_keys_gtks_init(&controller->next_gtks); sec_prot_certs_init(&controller->certs); + sec_prot_certs_ext_certificate_validation_set(&controller->certs, pae_controller_config.ext_cert_valid_enabled); ws_pae_timers_settings_init(&controller->timer_settings); } @@ -695,6 +704,9 @@ int8_t ws_pae_controller_stop(protocol_interface_info_entry_t *interface_ptr) // Stores frame counter ws_pae_controller_frame_counter_store(controller); + // Removes network keys from PAE controller and MAC + ws_pae_controller_nw_keys_remove(interface_ptr); + // If PAE has been initialized, deletes it if (controller->pae_delete) { controller->pae_delete(interface_ptr); @@ -764,6 +776,46 @@ int8_t ws_pae_controller_certificate_chain_set(const arm_certificate_chain_entry } } } + + // Updates the length of own certificates + entry->certs.own_cert_chain_len = sec_prot_certs_cert_chain_entry_len_get(&entry->certs.own_cert_chain); + } + + return 0; +} + +int8_t ws_pae_controller_own_certificate_add(const arm_certificate_entry_s *cert) +{ + if (!cert) { + return -1; + } + + int8_t ret = -1; + + ns_list_foreach(pae_controller_t, entry, &pae_controller_list) { + for (uint8_t i = 0; i < SEC_PROT_CERT_CHAIN_DEPTH; i++) { + if (entry->certs.own_cert_chain.cert[i] == NULL) { + sec_prot_certs_cert_set(&entry->certs.own_cert_chain, i, (uint8_t *) cert->cert, cert->cert_len); + // Set private key if set for the certificate that is added + if (cert->key && cert->key_len > 0) { + sec_prot_certs_priv_key_set(&entry->certs.own_cert_chain, (uint8_t *) cert->key, cert->key_len); + } + ret = 0; + break; + } + } + // Updates the length of own certificates + entry->certs.own_cert_chain_len = sec_prot_certs_cert_chain_entry_len_get(&entry->certs.own_cert_chain); + } + + return ret; +} + +int8_t ws_pae_controller_own_certificates_remove(void) +{ + ns_list_foreach(pae_controller_t, entry, &pae_controller_list) { + sec_prot_certs_chain_entry_init(&entry->certs.own_cert_chain); + entry->certs.own_cert_chain_len = 0; } return 0; @@ -816,6 +868,15 @@ int8_t ws_pae_controller_trusted_certificate_remove(const arm_certificate_entry_ return ret; } +int8_t ws_pae_controller_trusted_certificates_remove(void) +{ + ns_list_foreach(pae_controller_t, entry, &pae_controller_list) { + sec_prot_certs_chain_list_delete(&entry->certs.trusted_cert_chain_list); + } + + return 0; +} + int8_t ws_pae_controller_certificate_revocation_list_add(const arm_cert_revocation_list_entry_s *crl) { if (!crl) { @@ -1051,6 +1112,26 @@ int8_t ws_pae_controller_node_limit_set(int8_t interface_id, uint16_t limit) #endif } +int8_t ws_pae_controller_ext_certificate_validation_set(int8_t interface_id, bool enabled) +{ +#ifdef HAVE_PAE_AUTH + pae_controller_config.ext_cert_valid_enabled = enabled; + + pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id); + if (!controller) { + return -1; + } + + sec_prot_certs_ext_certificate_validation_set(&controller->certs, enabled); + + return 0; +#else + (void) interface_id; + (void) enabled; + return -1; +#endif +} + void ws_pae_controller_forced_gc(bool full_gc) { /* Purge only when on critical limit since node limit should handle limiting diff --git a/source/6LoWPAN/ws/ws_pae_controller.h b/source/6LoWPAN/ws/ws_pae_controller.h index b34a61ae37..717ca11258 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.h +++ b/source/6LoWPAN/ws/ws_pae_controller.h @@ -158,6 +158,26 @@ int8_t ws_pae_controller_timing_adjust(uint8_t timing); */ int8_t ws_pae_controller_certificate_chain_set(const arm_certificate_chain_entry_s *chain); +/** + * ws_pae_controller_own_certificate_add add own certificate to certificate chain + * + * \param cert own certificate + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_own_certificate_add(const arm_certificate_entry_s *cert); + +/** + * ws_pae_controller_own_certificates_remove removes own certificates + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_own_certificates_remove(void); + /** * ws_pae_controller_trusted_certificate_add add trusted certificate * @@ -180,6 +200,15 @@ int8_t ws_pae_controller_trusted_certificate_add(const arm_certificate_entry_s * */ int8_t ws_pae_controller_trusted_certificate_remove(const arm_certificate_entry_s *cert); +/** + * ws_pae_controller_trusted_certificates_remove removes trusted certificates + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_trusted_certificates_remove(void); + /** * ws_pae_controller_certificate_revocation_list_add add certification revocation list * @@ -338,6 +367,18 @@ int8_t ws_pae_controller_node_access_revoke_start(int8_t interface_id); */ int8_t ws_pae_controller_node_limit_set(int8_t interface_id, uint16_t limit); +/** + * ws_pae_controller_ext_certificate_validation_set enable or disable extended certificate validation + * + * \param interface_ptr interface + * \param enabled true to enable extended validation, false to disable + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_ext_certificate_validation_set(int8_t interface_id, bool enabled); + /** * ws_pae_controller_active_key_update update active key (test interface) * diff --git a/source/6LoWPAN/ws/ws_pae_lib.c b/source/6LoWPAN/ws/ws_pae_lib.c index d01917d955..d27c63b055 100644 --- a/source/6LoWPAN/ws/ws_pae_lib.c +++ b/source/6LoWPAN/ws/ws_pae_lib.c @@ -76,13 +76,21 @@ int8_t ws_pae_lib_kmp_list_delete(kmp_list_t *kmp_list, kmp_api_t *kmp) kmp_api_t *ws_pae_lib_kmp_list_type_get(kmp_list_t *kmp_list, kmp_type_e type) { + kmp_api_t *kmp = NULL; + ns_list_foreach(kmp_entry_t, cur, kmp_list) { + // If kmp type matches if (kmp_api_type_get(cur->kmp) == type) { - return cur->kmp; + /* If receiving of messages has not been disabled for the kmp (kmp is not + in terminating phase) prioritizes that kmp */ + if (!kmp_api_receive_disable(cur->kmp)) { + return cur->kmp; + } + // Otherwise returns any kmp that matches + kmp = cur->kmp; } } - - return 0; + return kmp; } void ws_pae_lib_kmp_list_free(kmp_list_t *kmp_list) diff --git a/source/6LoWPAN/ws/ws_pae_supp.c b/source/6LoWPAN/ws/ws_pae_supp.c index ae7abe7a0d..6d22e3e9a8 100644 --- a/source/6LoWPAN/ws/ws_pae_supp.c +++ b/source/6LoWPAN/ws/ws_pae_supp.c @@ -588,6 +588,7 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se pae_supp->timer_running = false; pae_supp->new_br_eui_64_set = false; pae_supp->new_br_eui_64_fresh = false; + pae_supp->entry_address_active = false; ws_pae_lib_supp_init(&pae_supp->entry); @@ -1010,7 +1011,13 @@ static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, kmp_type_ // Check if ongoing kmp_api_t *kmp = ws_pae_lib_kmp_list_type_get(&pae_supp->entry.kmp_list, type); - if (kmp) { + /* If kmp receiving is enabled or it is not GKH, routes message to existing KMP. + + For GKH creates an instance to handle message. If message is not valid (e.g. repeated + message counter), GKH ignores message and waits for timeout. All further messages + are routed to that instance. If valid message arrives, GKH instance handles the + message, replies to authenticator and terminates. */ + if (kmp && (!kmp_api_receive_disable(kmp) || type != IEEE_802_11_GKH)) { return kmp; } diff --git a/source/Common_Protocols/icmpv6.c b/source/Common_Protocols/icmpv6.c index a1cb4042e8..d842055a9f 100644 --- a/source/Common_Protocols/icmpv6.c +++ b/source/Common_Protocols/icmpv6.c @@ -1388,6 +1388,9 @@ static void icmpv6_aro_cb(buffer_t *buf, uint8_t status) ll_address[8] ^= 2; } rpl_control_address_register_done(buf->interface, ll_address, status); + if (status != SOCKET_TX_DONE) { + ws_common_aro_failure(buf->interface, ll_address); + } } buffer_t *icmpv6_build_ns(protocol_interface_info_entry_t *cur, const uint8_t target_addr[16], const uint8_t *prompting_src_addr, bool unicast, bool unspecified_source, const aro_t *aro) @@ -1603,8 +1606,6 @@ buffer_t *icmpv6_build_na(protocol_interface_info_entry_t *cur, bool solicited, uint8_t *ptr; uint8_t flags; - tr_debug("Build NA"); - /* Check if ARO response and status == success, then sending can be omitted with flag */ if (aro && cur->ipv6_neighbour_cache.omit_na_aro_success && aro->status == ARO_SUCCESS) { tr_debug("Omit NA ARO success"); @@ -1712,6 +1713,8 @@ buffer_t *icmpv6_build_na(protocol_interface_info_entry_t *cur, bool solicited, buf->info = (buffer_info_t)(B_DIR_DOWN | B_FROM_ICMP | B_TO_ICMP); buf->interface = cur; + tr_debug("Build NA"); + return (buf); } diff --git a/source/Common_Protocols/udp.c b/source/Common_Protocols/udp.c index a232e6762c..0159f450d1 100644 --- a/source/Common_Protocols/udp.c +++ b/source/Common_Protocols/udp.c @@ -146,12 +146,7 @@ buffer_t *udp_up(buffer_t *buf) if (buf->dst_sa.port == UDP_PORT_ECHO && buf->src_sa.port != UDP_PORT_ECHO) { protocol_interface_info_entry_t *cur; - tr_debug("UDP echo msg [%"PRIi16"]: %s%s", - buffer_data_length(buf), - trace_array( - buffer_data_pointer(buf), - (buffer_data_length(buf) > 64 ? 64 : buffer_data_length(buf))), - (buffer_data_length(buf) > 64 ? "..." : "")); + tr_debug("UDP echo msg from %s", trace_ipv6(buf->src_sa.address)); cur = buf->interface; diff --git a/source/DHCPv6_client/dhcpv6_client_service.c b/source/DHCPv6_client/dhcpv6_client_service.c index ed5ffede38..af57e49c5c 100644 --- a/source/DHCPv6_client/dhcpv6_client_service.c +++ b/source/DHCPv6_client/dhcpv6_client_service.c @@ -111,7 +111,7 @@ void dhcp_client_delete(int8_t interface) if (srv_data_ptr != NULL) { tr_debug("Free DHCPv6 Client\n"); memcpy(temporary_address, srv_data_ptr->iaNontemporalAddress.addressPrefix, 16); - dhcp_service_req_remove(srv_data_ptr->transActionId);// remove all pending retransmissions + dhcp_service_req_remove_all(srv_data_ptr);// remove all pending retransmissions libdhcvp6_nontemporalAddress_server_data_free(srv_data_ptr); addr_delete(cur, temporary_address); @@ -144,13 +144,18 @@ int dhcp_solicit_resp_cb(uint16_t instance_id, void *ptr, uint8_t msg_name, uin dhcpv6_client_server_data_t *srv_data_ptr = NULL; (void)instance_id; - srv_data_ptr = ptr; + //Validate that started TR ID class is still at list + srv_data_ptr = libdhcpv6_nonTemporal_validate_class_pointer(ptr); + if (srv_data_ptr == NULL) { tr_error("server data not found"); goto error_exit; } + //Clear Active Transaction state + srv_data_ptr->transActionId = 0; + // Validate message if (msg_name != DHCPV6_REPLY_TYPE) { tr_error("invalid response"); @@ -158,7 +163,7 @@ int dhcp_solicit_resp_cb(uint16_t instance_id, void *ptr, uint8_t msg_name, uin } if (libdhcpv6_reply_message_option_validate(&clientId, &serverId, &dhcp_ia_non_temporal_params, msg_ptr, msg_len) != 0) { - tr_error("Sol Not include all Options"); + tr_error("Reply Not include all Options"); goto error_exit; } @@ -330,7 +335,7 @@ int dhcp_client_server_address_update(int8_t interface, uint8_t *prefix, uint8_t } memcpy(srv_data_ptr->server_address, server_address, 16); - if (!srv_data_ptr->iaNonTemporalStructValid) { + if (srv_data_ptr->transActionId) { dhcp_service_update_server_address(srv_data_ptr->transActionId, server_address); } return 0; @@ -357,7 +362,7 @@ void dhcp_client_global_address_delete(int8_t interface, uint8_t *dhcp_addr, uin return; } - dhcp_service_req_remove(srv_data_ptr->transActionId);// remove all pending retransmissions + dhcp_service_req_remove_all(srv_data_ptr);// remove all pending retransmissions if (dhcp_client.one_instance_interface) { addr_deprecate(cur, srv_data_ptr->iaNontemporalAddress.addressPrefix); } else { @@ -384,7 +389,7 @@ void dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t return; } if (reason == ADDR_CALLBACK_INVALIDATED) { - dhcp_service_req_remove(srv_data_ptr->transActionId);//stop retransmissions of renew + dhcp_service_req_remove_all(srv_data_ptr);// remove all pending retransmissions libdhcvp6_nontemporalAddress_server_data_free(srv_data_ptr); tr_warn("Dhcp address lost"); return; @@ -394,6 +399,12 @@ void dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t return; } + if (srv_data_ptr->transActionId) { + //Do not trig new Renew process + tr_warn("Do not trig new pending renew request"); + return; + } + payload_len = libdhcpv6_address_request_message_len(srv_data_ptr->clientLinkIdType, srv_data_ptr->serverLinkType, 0, !dhcp_client.no_address_hint); payload_ptr = ns_dyn_mem_temporary_alloc(payload_len); if (payload_ptr == NULL) { diff --git a/source/MAC/IEEE802_15_4/mac_defines.h b/source/MAC/IEEE802_15_4/mac_defines.h index 25a18844a4..119c2c2efa 100644 --- a/source/MAC/IEEE802_15_4/mac_defines.h +++ b/source/MAC/IEEE802_15_4/mac_defines.h @@ -148,24 +148,19 @@ typedef struct mac_mcps_data_conf_fail_s { typedef struct protocol_interface_rf_mac_setup { int8_t mac_interface_id; - bool macUpState; + bool macUpState: 1; bool shortAdressValid: 1; //Define Dynamic src address to mac16 when it is true bool beaconSrcAddressModeLong: 1; //This force beacon src to mac64 otherwise shortAdressValid will define type + bool secFrameCounterPerKey: 1; bool mac_extension_enabled: 1; bool mac_ack_tx_active: 1; bool mac_frame_pending: 1; - uint16_t mac_short_address; - uint16_t pan_id; - uint8_t mac64[8]; - uint16_t coord_short_address; - uint8_t coord_long_address[8]; /* MAC Capability Information */ bool macCapRxOnIdle: 1; bool macCapCordinator: 1; bool macCapAssocationPermit: 1; bool macCapBatteryPowered: 1; bool macCapSecrutityCapability: 1; - bool macProminousMode: 1; bool macGTSPermit: 1; bool mac_security_enabled: 1; @@ -173,7 +168,6 @@ typedef struct protocol_interface_rf_mac_setup { bool mac_security_bypass_unknow_device: 1; /* Load balancing need this feature */ bool macAcceptAnyBeacon: 1; - /* TX process Flag */ bool macTxProcessActive: 1; bool macTxRequestAck: 1; @@ -188,6 +182,12 @@ typedef struct protocol_interface_rf_mac_setup { bool scan_active: 1; bool rf_csma_extension_supported: 1; bool ack_tx_possible: 1; + uint16_t mac_short_address; + uint16_t pan_id; + uint8_t mac64[8]; + uint16_t coord_short_address; + uint8_t coord_long_address[8]; + /* CSMA Params */ unsigned macMinBE: 4; unsigned macMaxBE: 4; @@ -200,7 +200,6 @@ typedef struct protocol_interface_rf_mac_setup { uint8_t scan_duration; //Needed??? mac_scan_type_t scan_type; - uint8_t mac_channel; //uint8_t cca_failure; @@ -253,6 +252,7 @@ typedef struct protocol_interface_rf_mac_setup { struct mlme_device_descriptor_s *device_description_table; uint8_t device_description_table_size; struct mlme_key_descriptor_s *key_description_table; + void *key_device_frame_counter_list_buffer; uint8_t key_description_table_size; uint8_t key_lookup_list_size; uint8_t key_usage_list_size; diff --git a/source/MAC/IEEE802_15_4/mac_mcps_sap.c b/source/MAC/IEEE802_15_4/mac_mcps_sap.c index 687325955a..74c30b16b3 100644 --- a/source/MAC/IEEE802_15_4/mac_mcps_sap.c +++ b/source/MAC/IEEE802_15_4/mac_mcps_sap.c @@ -90,6 +90,14 @@ uint32_t mac_mcps_sap_get_phy_timestamp(protocol_interface_rf_mac_setup_s *rf_ma return timestamp; } +static bool mac_data_counter_too_small(uint32_t current_counter, uint32_t packet_counter) +{ + if ((current_counter - packet_counter) >= 2) { + return true; + } + return false; +} + static bool mac_data_request_confirmation_finnish(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_pre_build_frame_t *buffer) { if (!buffer->asynch_request) { @@ -583,10 +591,14 @@ static uint8_t mac_data_interface_decrypt_packet(mac_pre_parsed_frame_t *b, mlme return MLME_UNAVAILABLE_KEY; } - if (b->neigh_info && neighbour_validation.frameCounter < b->neigh_info->FrameCounter) { - tr_debug("MLME_COUNTER_ERROR"); - return MLME_COUNTER_ERROR; + if (b->neigh_info) { + uint32_t min_accepted_frame_counter = mac_mib_key_device_frame_counter_get(key_description, b->neigh_info, device_descriptor_handle); + if (neighbour_validation.frameCounter < min_accepted_frame_counter) { + tr_debug("MLME_COUNTER_ERROR"); + return MLME_COUNTER_ERROR; + } } + } key = key_description->Key; @@ -620,10 +632,15 @@ static uint8_t mac_data_interface_decrypt_packet(mac_pre_parsed_frame_t *b, mlme //Update key device and key description tables if (!security_by_pass) { - b->neigh_info->FrameCounter = neighbour_validation.frameCounter + 1; + + mac_sec_mib_key_device_frame_counter_set(key_description, b->neigh_info, neighbour_validation.frameCounter + 1, device_descriptor_handle); + if (!key_device_description) { - // Black list old used keys by this device - mac_sec_mib_device_description_blacklist(rf_mac_setup, device_descriptor_handle); + if (!rf_mac_setup->secFrameCounterPerKey) { + // Black list old used keys by this device + mac_sec_mib_device_description_blacklist(rf_mac_setup, device_descriptor_handle); + } + key_device_description = mac_sec_mib_key_device_description_list_update(key_description); if (key_device_description) { tr_debug("Set new device user %u for key", device_descriptor_handle); @@ -1199,6 +1216,7 @@ mac_pre_build_frame_t *mcps_sap_prebuild_frame_buffer_get(uint16_t payload_size) return NULL; } memset(buffer, 0, sizeof(mac_pre_build_frame_t)); + buffer->aux_header.frameCounter = 0xffffffff; if (payload_size) { //Mac interlnal payload allocate buffer->mac_payload = ns_dyn_mem_temporary_alloc(payload_size); @@ -1229,7 +1247,7 @@ void mcps_sap_prebuild_frame_buffer_free(mac_pre_build_frame_t *buffer) } -static bool mac_frame_security_parameters_init(ccm_globals_t *ccm_ptr, protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer) +static mlme_key_descriptor_t *mac_frame_security_key_get(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer) { /* Encrypt the packet payload if AES encyption bit is set */ mlme_security_t key_source; @@ -1237,13 +1255,13 @@ static bool mac_frame_security_parameters_init(ccm_globals_t *ccm_ptr, protocol_ key_source.KeyIndex = buffer->aux_header.KeyIndex; key_source.SecurityLevel = buffer->aux_header.securityLevel; memcpy(key_source.Keysource, buffer->aux_header.Keysource, 8); - mlme_key_descriptor_t *key_description = mac_sec_key_description_get(rf_ptr, &key_source, buffer->fcf_dsn.DstAddrMode, buffer->DstAddr, buffer->DstPANId); + return mac_sec_key_description_get(rf_ptr, &key_source, buffer->fcf_dsn.DstAddrMode, buffer->DstAddr, buffer->DstPANId); +} - if (!key_description) { - buffer->status = MLME_UNAVAILABLE_KEY; - return false; - } +static bool mac_frame_security_parameters_init(ccm_globals_t *ccm_ptr, protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer, mlme_key_descriptor_t *key_description) +{ + /* Encrypt the packet payload if AES encyption bit is set */ mlme_device_descriptor_t *device_description; uint8_t *nonce_ext_64_ptr; @@ -1298,6 +1316,7 @@ static void mac_common_data_confirmation_handle(protocol_interface_rf_mac_setup_ timer_mac_stop(rf_mac_setup); if (m_event == MAC_CCA_FAIL) { sw_mac_stats_update(rf_mac_setup, STAT_MAC_TX_CCA_FAIL, 0); + tr_debug("MAC CCA fail"); /* CCA fail */ //rf_mac_setup->cca_failure++; buf->status = MLME_BUSY_CHAN; @@ -1305,7 +1324,7 @@ static void mac_common_data_confirmation_handle(protocol_interface_rf_mac_setup_ sw_mac_stats_update(rf_mac_setup, STAT_MAC_TX_COUNT, buf->mac_payload_length); if (m_event == MAC_TX_FAIL) { sw_mac_stats_update(rf_mac_setup, STAT_MAC_TX_FAIL, 0); - tr_error("MAC tx fail"); + tr_debug("MAC tx fail"); buf->status = MLME_TX_NO_ACK; } else if (m_event == MAC_TX_DONE) { if (mac_is_ack_request_set(buf) == false) { @@ -1517,16 +1536,31 @@ static int8_t mcps_generic_packet_build(protocol_interface_rf_mac_setup_s *rf_pt mac_header_information_elements_preparation(buffer); mcps_generic_sequence_number_allocate(rf_ptr, buffer); - + mlme_key_descriptor_t *key_desc; if (buffer->fcf_dsn.securityEnabled) { + bool increment_framecounter = false; //Remember to update security counter here! - buffer->aux_header.frameCounter = mac_mlme_framecounter_get(rf_ptr); - if (!mac_frame_security_parameters_init(&ccm_ptr, rf_ptr, buffer)) { + key_desc = mac_frame_security_key_get(rf_ptr, buffer); + if (!key_desc) { + buffer->status = MLME_UNAVAILABLE_KEY; + return -2; + } + + //GET Counter + uint32_t new_frameCounter = mac_sec_mib_key_outgoing_frame_counter_get(rf_ptr, key_desc); + // If buffer frame counter is set, this is FHSS channel retry, update frame counter only if something was sent after failure + if ((buffer->aux_header.frameCounter == 0xffffffff) || buffer->asynch_request || mac_data_counter_too_small(new_frameCounter, buffer->aux_header.frameCounter)) { + buffer->aux_header.frameCounter = new_frameCounter; + increment_framecounter = true; + } + + if (!mac_frame_security_parameters_init(&ccm_ptr, rf_ptr, buffer, key_desc)) { return -2; } //Increment security counter - mac_mlme_framecounter_increment(rf_ptr); - + if (increment_framecounter) { + mac_sec_mib_key_outgoing_frame_counter_increment(rf_ptr, key_desc); + } } //Calculate Payload length here with IE extension @@ -1559,7 +1593,9 @@ static int8_t mcps_generic_packet_build(protocol_interface_rf_mac_setup_s *rf_pt tr_debug("Too Long %u, %u pa %u header %u mic %u", frame_length, mac_payload_length, buffer->mac_header_length_with_security, buffer->security_mic_len, dev_driver->phy_MTU); buffer->status = MLME_FRAME_TOO_LONG; //decrement security counter - mac_mlme_framecounter_decrement(rf_ptr); + if (buffer->fcf_dsn.securityEnabled) { + mac_sec_mib_key_outgoing_frame_counter_decrement(rf_ptr, key_desc); + } return -1; } @@ -1673,19 +1709,24 @@ int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, bool in ccm_globals_t ccm_ptr; mac_pre_build_frame_t *buffer = &rf_ptr->enhanced_ack_buffer; - + mlme_key_descriptor_t *key_desc; if (buffer->fcf_dsn.securityEnabled) { //Remember to update security counter here! - if (init_build) { - buffer->aux_header.frameCounter = mac_mlme_framecounter_get(rf_ptr); + key_desc = mac_frame_security_key_get(rf_ptr, buffer); + if (!key_desc) { + buffer->status = MLME_UNAVAILABLE_KEY; + return -2; } - if (!mac_frame_security_parameters_init(&ccm_ptr, rf_ptr, buffer)) { + if (init_build) { + buffer->aux_header.frameCounter = mac_sec_mib_key_outgoing_frame_counter_get(rf_ptr, key_desc); + } + if (!mac_frame_security_parameters_init(&ccm_ptr, rf_ptr, buffer, key_desc)) { return -2; } if (init_build) { //Increment security counter - mac_mlme_framecounter_increment(rf_ptr); + mac_sec_mib_key_outgoing_frame_counter_increment(rf_ptr, key_desc); } } @@ -1709,7 +1750,7 @@ int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, bool in if (buffer->fcf_dsn.securityEnabled) { //decrement security counter - mac_mlme_framecounter_decrement(rf_ptr); + mac_sec_mib_key_outgoing_frame_counter_decrement(rf_ptr, key_desc); ccm_free(&ccm_ptr); } return -1; @@ -1770,7 +1811,14 @@ static int8_t mcps_generic_packet_rebuild(protocol_interface_rf_mac_setup_s *rf_ } if (buffer->fcf_dsn.securityEnabled) { - if (!mac_frame_security_parameters_init(&ccm_ptr, rf_ptr, buffer)) { + + mlme_key_descriptor_t *key_desc = mac_frame_security_key_get(rf_ptr, buffer); + if (!key_desc) { + buffer->status = MLME_UNAVAILABLE_KEY; + return -2; + } + + if (!mac_frame_security_parameters_init(&ccm_ptr, rf_ptr, buffer, key_desc)) { return -2; } } @@ -2318,3 +2366,17 @@ int mcps_packet_ingress_rate_limit_by_memory(uint8_t free_heap_percentage) return -1; } + +void mcps_pending_packet_counter_update_check(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_pre_build_frame_t *buffer) +{ + if (buffer->fcf_dsn.securityEnabled) { + mlme_key_descriptor_t *key_desc = mac_frame_security_key_get(rf_mac_setup, buffer); + if (key_desc) { + uint32_t current_counter = mac_sec_mib_key_outgoing_frame_counter_get(rf_mac_setup, key_desc); + if (mac_data_counter_too_small(current_counter, buffer->aux_header.frameCounter)) { + buffer->aux_header.frameCounter = current_counter; + mac_sec_mib_key_outgoing_frame_counter_increment(rf_mac_setup, key_desc); + } + } + } +} diff --git a/source/MAC/IEEE802_15_4/mac_mcps_sap.h b/source/MAC/IEEE802_15_4/mac_mcps_sap.h index 90a0cbf738..de61fe8b91 100644 --- a/source/MAC/IEEE802_15_4/mac_mcps_sap.h +++ b/source/MAC/IEEE802_15_4/mac_mcps_sap.h @@ -140,4 +140,6 @@ int mcps_packet_ingress_rate_limit_by_memory(uint8_t free_heap_percentage); uint32_t mac_mcps_sap_get_phy_timestamp(struct protocol_interface_rf_mac_setup *rf_mac_setup); +void mcps_pending_packet_counter_update_check(struct protocol_interface_rf_mac_setup *rf_mac_setup, mac_pre_build_frame_t *buffer); + #endif /* MAC_IEEE802_15_4_MAC_MCPS_SAP_H_ */ diff --git a/source/MAC/IEEE802_15_4/mac_mlme.c b/source/MAC/IEEE802_15_4/mac_mlme.c index 70dc179df5..d0925f97f8 100644 --- a/source/MAC/IEEE802_15_4/mac_mlme.c +++ b/source/MAC/IEEE802_15_4/mac_mlme.c @@ -606,15 +606,21 @@ static int8_t mac_mlme_8bit_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, return 0; } -static int8_t mac_mlme_32bit_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, mlme_attr_t attribute, uint32_t value) +static int8_t mac_mlme_32bit_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, mlme_attr_t attribute, uint8_t index, uint32_t value) { - (void)rf_mac_setup; - (void) value; + switch (attribute) { case macFrameCounter: - platform_enter_critical(); - rf_mac_setup->security_frame_counter = value; - platform_exit_critical(); + if (rf_mac_setup->secFrameCounterPerKey) { + mlme_key_descriptor_t *key_desc = mac_sec_key_description_get_by_attribute(rf_mac_setup, index); + if (!key_desc) { + return -1; + } + mac_sec_mib_key_outgoing_frame_counter_set(rf_mac_setup, key_desc, value); + } else { + mac_sec_mib_key_outgoing_frame_counter_set(rf_mac_setup, NULL, value); + } + break; default: @@ -718,7 +724,7 @@ static int8_t mac_mlme_handle_set_values(protocol_interface_rf_mac_setup_s *rf_m return mac_mlme_16bit_set(rf_mac_setup, set_req->attr, *pu16); } else if (set_req->value_size == 4) { const uint32_t *pu32 = set_req->value_pointer; - return mac_mlme_32bit_set(rf_mac_setup, set_req->attr, *pu32); + return mac_mlme_32bit_set(rf_mac_setup, set_req->attr, set_req->attr_index, *pu32); } return -1; } @@ -787,30 +793,6 @@ int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const m } } -uint32_t mac_mlme_framecounter_get(struct protocol_interface_rf_mac_setup *rf_mac_setup) -{ - uint32_t value; - platform_enter_critical(); - value = rf_mac_setup->security_frame_counter; - platform_exit_critical(); - return value; -} - -void mac_mlme_framecounter_increment(struct protocol_interface_rf_mac_setup *rf_mac_setup) -{ - platform_enter_critical(); - rf_mac_setup->security_frame_counter++; - platform_exit_critical(); -} - -void mac_mlme_framecounter_decrement(struct protocol_interface_rf_mac_setup *rf_mac_setup) -{ - platform_enter_critical(); - rf_mac_setup->security_frame_counter--; - platform_exit_critical(); -} - - int8_t mac_mlme_get_req(struct protocol_interface_rf_mac_setup *rf_mac_setup, mlme_get_conf_t *get_req) { if (!get_req || !rf_mac_setup) { @@ -833,9 +815,16 @@ int8_t mac_mlme_get_req(struct protocol_interface_rf_mac_setup *rf_mac_setup, ml break; case macFrameCounter: - platform_enter_critical(); - get_req->value_pointer = &rf_mac_setup->security_frame_counter; - platform_exit_critical(); + if (rf_mac_setup->secFrameCounterPerKey) { + mlme_key_descriptor_t *key_desc = mac_sec_key_description_get_by_attribute(rf_mac_setup, get_req->attr_index); + if (!key_desc) { + return -1; + } + get_req->value_pointer = &key_desc->KeyFrameCounter; + } else { + get_req->value_pointer = &rf_mac_setup->security_frame_counter; + } + get_req->value_size = 4; break; @@ -1344,8 +1333,6 @@ int mac_mlme_beacon_notify(protocol_interface_rf_mac_setup_s *rf_mac_setup, mlme mac->mlme_ind_cb(mac, MLME_BEACON_NOTIFY, data); } - tr_debug("Beacon Notify: %s", trace_array(data->beacon_data, data->beacon_data_length)); - if (rf_mac_setup->mac_mlme_scan_resp) { mlme_scan_conf_t *conf = rf_mac_setup->mac_mlme_scan_resp; update_beacon = add_or_update_beacon(conf, data, rf_mac_setup->fhss_api); diff --git a/source/MAC/IEEE802_15_4/mac_mlme.h b/source/MAC/IEEE802_15_4/mac_mlme.h index 76e0c0c3f5..fb251c8000 100644 --- a/source/MAC/IEEE802_15_4/mac_mlme.h +++ b/source/MAC/IEEE802_15_4/mac_mlme.h @@ -65,11 +65,6 @@ int8_t mac_mlme_get_req(struct protocol_interface_rf_mac_setup *rf_mac_setup, st void mac_extended_mac_set(struct protocol_interface_rf_mac_setup *rf_mac_setup, const uint8_t *mac64); -uint32_t mac_mlme_framecounter_get(struct protocol_interface_rf_mac_setup *rf_mac_setup); - -void mac_mlme_framecounter_increment(struct protocol_interface_rf_mac_setup *rf_mac_setup); -void mac_mlme_framecounter_decrement(struct protocol_interface_rf_mac_setup *rf_mac_setup); - /** * MLME Poll Request * diff --git a/source/MAC/IEEE802_15_4/mac_pd_sap.c b/source/MAC/IEEE802_15_4/mac_pd_sap.c index d938de1a43..1e0a09865f 100644 --- a/source/MAC/IEEE802_15_4/mac_pd_sap.c +++ b/source/MAC/IEEE802_15_4/mac_pd_sap.c @@ -387,14 +387,6 @@ static void mac_sap_no_ack_cb(protocol_interface_rf_mac_setup_s *rf_ptr) } } -static bool mac_data_counter_too_small(uint32_t current_counter, uint32_t packet_counter) -{ - if ((current_counter - packet_counter) >= 2) { - return true; - } - return false; -} - static bool mac_data_asynch_channel_switch(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *active_buf) { @@ -420,13 +412,7 @@ static void mac_data_ack_tx_finish(protocol_interface_rf_mac_setup_s *rf_ptr) } if (rf_ptr->active_pd_data_request) { - if (rf_ptr->active_pd_data_request->fcf_dsn.securityEnabled) { - uint32_t current_counter = mac_mlme_framecounter_get(rf_ptr); - if (mac_data_counter_too_small(current_counter, rf_ptr->active_pd_data_request->aux_header.frameCounter)) { - rf_ptr->active_pd_data_request->aux_header.frameCounter = current_counter; - mac_mlme_framecounter_increment(rf_ptr); - } - } + mcps_pending_packet_counter_update_check(rf_ptr, rf_ptr->active_pd_data_request); //GEN TX failure mac_sap_cca_fail_cb(rf_ptr); } diff --git a/source/MAC/IEEE802_15_4/mac_security_mib.c b/source/MAC/IEEE802_15_4/mac_security_mib.c index e009d04256..b023c32cdf 100644 --- a/source/MAC/IEEE802_15_4/mac_security_mib.c +++ b/source/MAC/IEEE802_15_4/mac_security_mib.c @@ -19,6 +19,7 @@ #include "ns_types.h" #include "ns_trace.h" #include "nsdynmemLIB.h" +#include "platform/arm_hal_interrupt.h" #include "mac_api.h" #include "sw_mac.h" #include "mac_common_defines.h" @@ -78,6 +79,42 @@ static mlme_key_id_lookup_descriptor_t *mac_sec_mib_key_lookup_table_allocate(ui return table_ptr; } +static int mac_sec_mib_frame_counter_key_buffer_allocate(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint16_t list_size, uint16_t device_count) +{ + rf_mac_setup->key_device_frame_counter_list_buffer = ns_dyn_mem_alloc(sizeof(uint32_t) * list_size * device_count); + if (!rf_mac_setup->key_device_frame_counter_list_buffer) { + return -1; + } + memset(rf_mac_setup->key_device_frame_counter_list_buffer, 0, (sizeof(uint32_t) * list_size * device_count)); + rf_mac_setup->secFrameCounterPerKey = true; + mlme_key_descriptor_t *key_descriptor_list = rf_mac_setup->key_description_table; + uint32_t *frame_counter_pointer = rf_mac_setup->key_device_frame_counter_list_buffer; + for (uint8_t i = 0; i < rf_mac_setup->key_description_table_size; i++) { + key_descriptor_list->KeyDeviceFrameCouterList = frame_counter_pointer; + key_descriptor_list->KeyFrameCounterPerKey = true; + key_descriptor_list->KeyFrameCounter = 0; + //Update Pointers + key_descriptor_list++; + frame_counter_pointer += device_count; + } + + return 0; +} + +static void mac_sec_mib_frame_counter_key_buffer_free(protocol_interface_rf_mac_setup_s *rf_mac_setup) +{ + mlme_key_descriptor_t *key_descriptor_list = rf_mac_setup->key_description_table; + for (uint8_t i = 0; i < rf_mac_setup->key_description_table_size; i++) { + key_descriptor_list->KeyDeviceFrameCouterList = NULL; + key_descriptor_list->KeyFrameCounterPerKey = false; + //Update Pointers + key_descriptor_list++; + } + ns_dyn_mem_free(rf_mac_setup->key_device_frame_counter_list_buffer); + rf_mac_setup->key_device_frame_counter_list_buffer = NULL; + rf_mac_setup->secFrameCounterPerKey = false; +} + static mlme_device_descriptor_t *mac_sec_mib_device_description_get_by_mac16(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint16_t mac16) { @@ -134,6 +171,11 @@ static void mac_sec_mib_key_device_description_remove_from_list(mlme_key_descrip if (removed_entry) { key_descpription_table->KeyDeviceListEntries--; + //Clear Also frame counter per key if it its enabled + if (key_descpription_table->KeyFrameCounterPerKey) { + //SET frame counter to 0 + mac_sec_mib_key_device_frame_counter_set(key_descpription_table, NULL, 0, device_descriptor_handle); + } } } @@ -234,7 +276,6 @@ int8_t mac_sec_mib_device_description_set(uint8_t atribute_index, mlme_device_de //validate index to list size if (!rf_mac_setup || !device_descriptor || atribute_index >= rf_mac_setup->device_description_table_size) { - tr_debug("Too many Devices"); return -1; } @@ -302,6 +343,17 @@ int8_t mac_sec_mib_key_description_set(uint8_t atribute_index, mlme_key_descript memcpy(key_ptr->KeyUsageList, key_descriptor->KeyUsageList, sizeof(mlme_key_usage_descriptor_t) * key_ptr->KeyUsageListEntries); } + if (key_ptr->KeyFrameCounterPerKey) { + key_ptr->KeyFrameCounter = 0; + if (key_ptr->KeyDeviceListEntries == 0) { + //Clear all frame counters from old possible user's + uint32_t *counter_ptr = key_ptr->KeyDeviceFrameCouterList; + for (int i = 0; i < rf_mac_setup->device_description_table_size; i++) { + *counter_ptr++ = 0; + } + } + } + return 0; } @@ -414,6 +466,17 @@ mlme_key_descriptor_t *mac_sec_key_description_get(protocol_interface_rf_mac_set return NULL; } +mlme_key_descriptor_t *mac_sec_key_description_get_by_attribute(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t atribute_index) +{ + //validate index to list size + if (atribute_index >= rf_mac_setup->key_description_table_size) { + return NULL; + } + + + return rf_mac_setup->key_description_table + atribute_index; +} + int8_t mac_sec_mib_init(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_description_storage_size_t *storage_sizes) { @@ -434,16 +497,102 @@ int8_t mac_sec_mib_init(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_des return 0; } + +int8_t mac_sec_mib_frame_counter_per_key_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, bool enabled) +{ + if (enabled) { + if (rf_mac_setup->key_device_frame_counter_list_buffer) { + return 0; + } + return mac_sec_mib_frame_counter_key_buffer_allocate(rf_mac_setup, rf_mac_setup->key_description_table_size, rf_mac_setup->device_description_table_size); + } + + //Clear Key Descriptors + + //Free current list + mac_sec_mib_frame_counter_key_buffer_free(rf_mac_setup); + return 0; +} + + void mac_sec_mib_deinit(protocol_interface_rf_mac_setup_s *rf_mac_setup) { if (!rf_mac_setup) { return; } + mac_sec_mib_frame_counter_key_buffer_free(rf_mac_setup); mac_sec_mib_device_description_table_deinit(rf_mac_setup); mac_sec_mib_key_description_table_deinit(rf_mac_setup); } +uint32_t mac_sec_mib_key_outgoing_frame_counter_get(protocol_interface_rf_mac_setup_s *rf_mac_setup, mlme_key_descriptor_t *key_descpription) +{ + uint32_t value; + platform_enter_critical(); + if (key_descpription && key_descpription->KeyFrameCounterPerKey) { + value = key_descpription->KeyFrameCounter; + } else { + value = rf_mac_setup->security_frame_counter; + } + platform_exit_critical(); + return value; +} + +void mac_sec_mib_key_outgoing_frame_counter_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, mlme_key_descriptor_t *key_descpription, uint32_t value) +{ + platform_enter_critical(); + if (key_descpription && key_descpription->KeyFrameCounterPerKey) { + key_descpription->KeyFrameCounter = value; + } else { + rf_mac_setup->security_frame_counter = value; + } + platform_exit_critical(); +} + +void mac_sec_mib_key_outgoing_frame_counter_increment(struct protocol_interface_rf_mac_setup *rf_mac_setup, mlme_key_descriptor_t *key_descpription) +{ + platform_enter_critical(); + if (key_descpription && key_descpription->KeyFrameCounterPerKey) { + key_descpription->KeyFrameCounter++; + } else { + rf_mac_setup->security_frame_counter++; + } + platform_exit_critical(); +} + +void mac_sec_mib_key_outgoing_frame_counter_decrement(struct protocol_interface_rf_mac_setup *rf_mac_setup, mlme_key_descriptor_t *key_descpription) +{ + platform_enter_critical(); + if (key_descpription && key_descpription->KeyFrameCounterPerKey) { + key_descpription->KeyFrameCounter--; + } else { + rf_mac_setup->security_frame_counter--; + } + platform_exit_critical(); +} + + +void mac_sec_mib_key_device_frame_counter_set(mlme_key_descriptor_t *key_descpription_table, mlme_device_descriptor_t *device_info, uint32_t frame_counter, uint8_t attribute_index) +{ + if (key_descpription_table->KeyFrameCounterPerKey) { + uint32_t *counter_ptr = key_descpription_table->KeyDeviceFrameCouterList + attribute_index; + *counter_ptr = frame_counter; + } else { + device_info->FrameCounter = frame_counter; + } +} + +uint32_t mac_mib_key_device_frame_counter_get(mlme_key_descriptor_t *key_descpription_table, mlme_device_descriptor_t *device_info, uint8_t attribute_index) +{ + if (key_descpription_table->KeyFrameCounterPerKey) { + uint32_t *counter_ptr = key_descpription_table->KeyDeviceFrameCouterList + attribute_index; + return *counter_ptr; + } + return device_info->FrameCounter; +} + + //allocate new entry and update entries size mlme_key_device_descriptor_t *mac_sec_mib_key_device_description_list_update(mlme_key_descriptor_t *key_descpription_table) { @@ -477,7 +626,6 @@ mlme_key_device_descriptor_t *mac_sec_mib_key_device_description_discover_from_l void mac_sec_mib_device_description_blacklist(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t device_handle) { - if (!rf_mac_setup) { return; } @@ -485,7 +633,6 @@ void mac_sec_mib_device_description_blacklist(protocol_interface_rf_mac_setup_s for (uint8_t i = 0; i < rf_mac_setup->key_description_table_size; i++) { descriptor = mac_sec_mib_key_device_description_discover_from_list(&rf_mac_setup->key_description_table[i], device_handle); if (descriptor) { - tr_debug("Black listed device %u", device_handle); descriptor->Blacklisted = true; } diff --git a/source/MAC/IEEE802_15_4/mac_security_mib.h b/source/MAC/IEEE802_15_4/mac_security_mib.h index 05be16d572..9ca75cd5b8 100644 --- a/source/MAC/IEEE802_15_4/mac_security_mib.h +++ b/source/MAC/IEEE802_15_4/mac_security_mib.h @@ -25,21 +25,26 @@ struct mac_description_storage_size_s; typedef struct mlme_key_descriptor_s { mlme_key_id_lookup_descriptor_t *KeyIdLookupList; - uint8_t KeyIdLookupListEntries; mlme_key_device_descriptor_t *KeyDeviceList; + mlme_key_usage_descriptor_t *KeyUsageList; + uint32_t *KeyDeviceFrameCouterList; + uint32_t KeyFrameCounter; + uint8_t Key[16]; uint8_t KeyDeviceListSize; uint8_t KeyDeviceListEntries; - mlme_key_usage_descriptor_t *KeyUsageList; + uint8_t KeyIdLookupListEntries; uint8_t KeyUsageListEntries; uint8_t KeyUsageListSize; - uint8_t Key[16]; - bool unique_key_descriptor; + bool unique_key_descriptor: 1; + bool KeyFrameCounterPerKey: 1; } mlme_key_descriptor_t; int8_t mac_sec_mib_init(struct protocol_interface_rf_mac_setup *rf_mac_setup, struct mac_description_storage_size_s *storage_sizes); void mac_sec_mib_deinit(struct protocol_interface_rf_mac_setup *rf_mac_setup); +int8_t mac_sec_mib_frame_counter_per_key_set(struct protocol_interface_rf_mac_setup *rf_mac_setup, bool enabled); + int8_t mac_sec_mib_device_description_set(uint8_t atribute_index, mlme_device_descriptor_t *device_descriptor, struct protocol_interface_rf_mac_setup *rf_mac_setup); int8_t mac_sec_mib_key_description_set(uint8_t atribute_index, mlme_key_descriptor_entry_t *key_descriptor, struct protocol_interface_rf_mac_setup *rf_mac_setup); @@ -52,10 +57,24 @@ uint8_t mac_mib_device_descption_attribute_get_by_descriptor(struct protocol_int mlme_key_descriptor_t *mac_sec_key_description_get(struct protocol_interface_rf_mac_setup *rf_mac_setup, mlme_security_t *key_source, uint8_t address_mode, uint8_t *address_ptr, uint16_t pan_id); +mlme_key_descriptor_t *mac_sec_key_description_get_by_attribute(struct protocol_interface_rf_mac_setup *rf_mac_setup, uint8_t atribute_index); + mlme_key_device_descriptor_t *mac_sec_mib_key_device_description_list_update(mlme_key_descriptor_t *key_descpription_table); mlme_key_device_descriptor_t *mac_sec_mib_key_device_description_discover_from_list(mlme_key_descriptor_t *key_descpription_table, uint8_t device_descriptor_handle); void mac_sec_mib_device_description_blacklist(struct protocol_interface_rf_mac_setup *rf_mac_setup, uint8_t device_handle); +void mac_sec_mib_key_device_frame_counter_set(mlme_key_descriptor_t *key_descpription_table, mlme_device_descriptor_t *device_info, uint32_t frame_counter, uint8_t attribute_index); + +uint32_t mac_mib_key_device_frame_counter_get(mlme_key_descriptor_t *key_descpription_table, mlme_device_descriptor_t *device_info, uint8_t attribute_index); + +uint32_t mac_sec_mib_key_outgoing_frame_counter_get(struct protocol_interface_rf_mac_setup *rf_mac_setup, mlme_key_descriptor_t *key_descpription); + +void mac_sec_mib_key_outgoing_frame_counter_set(struct protocol_interface_rf_mac_setup *rf_mac_setup, mlme_key_descriptor_t *key_descpription, uint32_t value); + +void mac_sec_mib_key_outgoing_frame_counter_increment(struct protocol_interface_rf_mac_setup *rf_mac_setup, mlme_key_descriptor_t *key_descpription); + +void mac_sec_mib_key_outgoing_frame_counter_decrement(struct protocol_interface_rf_mac_setup *rf_mac_setup, mlme_key_descriptor_t *key_descpription); + #endif /* MAC_SECURITY_MIB_H_ */ diff --git a/source/MAC/IEEE802_15_4/sw_mac.c b/source/MAC/IEEE802_15_4/sw_mac.c index 7c40766f93..ca52231bac 100644 --- a/source/MAC/IEEE802_15_4/sw_mac.c +++ b/source/MAC/IEEE802_15_4/sw_mac.c @@ -25,6 +25,7 @@ #include "MAC/IEEE802_15_4/mac_defines.h" #include "MAC/IEEE802_15_4/mac_mcps_sap.h" #include "MAC/IEEE802_15_4/mac_pd_sap.h" +#include "MAC/IEEE802_15_4/mac_security_mib.h" #include "MAC/rf_driver_storage.h" #include "MAC/virtual_rf/virtual_rf_defines.h" #include "mac_fhss_callbacks.h" @@ -123,6 +124,14 @@ mac_api_t *ns_sw_mac_create(int8_t rf_driver_id, mac_description_storage_size_t return this; } +int8_t ns_sw_mac_enable_frame_counter_per_key(struct mac_api_s *mac_api_s, bool enable_feature) +{ + if (!mac_api_s || mac_api_s != mac_store.mac_api) { + return -1; + } + return mac_sec_mib_frame_counter_per_key_set(mac_store.setup, enable_feature); +} + int8_t ns_sw_mac_virtual_client_register(mac_api_t *api, int8_t virtual_driver_id) { if (!api || api != mac_store.mac_api) { diff --git a/source/RPL/rpl_control.c b/source/RPL/rpl_control.c index f176350b9e..c6854e3f4e 100644 --- a/source/RPL/rpl_control.c +++ b/source/RPL/rpl_control.c @@ -176,6 +176,21 @@ void rpl_control_request_parent_link_confirmation(bool requested) rpl_policy_set_parent_confirmation_request(requested); } +void rpl_control_set_dio_multicast_min_config_advertisment_count(uint8_t min_count) +{ + rpl_policy_set_dio_multicast_config_advertisment_min_count(min_count); +} + +void rpl_control_set_dao_retry_count(uint8_t count) +{ + rpl_policy_set_dao_retry_count(count); +} + +void rpl_control_set_initial_dao_ack_wait(uint16_t timeout_in_ms) +{ + rpl_policy_set_initial_dao_ack_wait(timeout_in_ms); +} + /* Send address registration to either specified address, or to non-registered address */ void rpl_control_register_address(protocol_interface_info_entry_t *interface, const uint8_t addr[16]) { @@ -340,16 +355,24 @@ void rpl_control_delete_domain(rpl_domain_t *domain) rpl_free(domain, sizeof * domain); } -static void rpl_control_remove_interface_from_domain(protocol_interface_info_entry_t *cur, rpl_domain_t *domain) +static void rpl_control_remove_interface_from_domain(protocol_interface_info_entry_t *cur, rpl_domain_t *domain, bool free_instances) { ns_list_foreach(rpl_instance_t, instance, &domain->instances) { rpl_instance_remove_interface(instance, cur->id); } + ns_list_foreach(if_address_entry_t, addr, &cur->ip_addresses) { if (!addr_is_ipv6_link_local(addr->address)) { rpl_control_unpublish_address(domain, addr->address); } } + + if (free_instances) { + ns_list_foreach_safe(rpl_instance_t, instance, &domain->instances) { + rpl_delete_instance(instance); + } + } + if (domain->non_storing_downstream_interface == cur->id) { domain->non_storing_downstream_interface = -1; } @@ -374,7 +397,16 @@ void rpl_control_set_domain_on_interface(protocol_interface_info_entry_t *cur, r void rpl_control_remove_domain_from_interface(protocol_interface_info_entry_t *cur) { if (cur->rpl_domain) { - rpl_control_remove_interface_from_domain(cur, cur->rpl_domain); + rpl_control_remove_interface_from_domain(cur, cur->rpl_domain, false); + addr_delete_group(cur, ADDR_LINK_LOCAL_ALL_RPL_NODES); + cur->rpl_domain = NULL; + } +} + +void rpl_control_free_domain_instances_from_interface(protocol_interface_info_entry_t *cur) +{ + if (cur->rpl_domain) { + rpl_control_remove_interface_from_domain(cur, cur->rpl_domain, true); addr_delete_group(cur, ADDR_LINK_LOCAL_ALL_RPL_NODES); cur->rpl_domain = NULL; } @@ -1368,6 +1400,7 @@ void rpl_control_transmit_dis(rpl_domain_t *domain, protocol_interface_info_entr buffer_data_end_set(buf, ptr); rpl_control_transmit(domain, cur, ICMPV6_CODE_RPL_DIS, buf, dst); + tr_info("Transmit DIS"); } #ifdef HAVE_RPL_DAO_HANDLING diff --git a/source/RPL/rpl_control.h b/source/RPL/rpl_control.h index c9c1d7f176..17290fddc0 100644 --- a/source/RPL/rpl_control.h +++ b/source/RPL/rpl_control.h @@ -145,6 +145,7 @@ rpl_domain_t *rpl_control_create_domain(void); void rpl_control_delete_domain(rpl_domain_t *domain); void rpl_control_set_domain_on_interface(struct protocol_interface_info_entry *cur, rpl_domain_t *domain, bool downstream); void rpl_control_remove_domain_from_interface(struct protocol_interface_info_entry *cur); +void rpl_control_free_domain_instances_from_interface(struct protocol_interface_info_entry *cur); void rpl_control_set_callback(rpl_domain_t *domain, rpl_domain_callback_t callback, rpl_prefix_callback_t prefix_learn_cb, rpl_new_parent_callback_t new_parent_add, void *cb_handle); /* Target publishing */ @@ -156,6 +157,9 @@ uint16_t rpl_control_parent_candidate_list_size(struct protocol_interface_info_e void rpl_control_neighbor_delete(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16]); /* Parent link confirmation API extension */ void rpl_control_request_parent_link_confirmation(bool requested); +void rpl_control_set_dio_multicast_min_config_advertisment_count(uint8_t min_count); +void rpl_control_set_dao_retry_count(uint8_t count); +void rpl_control_set_initial_dao_ack_wait(uint16_t timeout_in_ms); void rpl_control_register_address(struct protocol_interface_info_entry *interface, const uint8_t addr[16]); void rpl_control_address_register_done(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16], uint8_t status); @@ -178,6 +182,7 @@ uint16_t rpl_control_current_rank(const struct rpl_instance *instance); #define rpl_control_fast_timer(ticks) ((void) 0) #define rpl_control_slow_timer(seconds) ((void) 0) #define rpl_control_remove_domain_from_interface(cur) ((void) 0) +#define rpl_control_free_domain_instances_from_interface(cur) ((void) 0) #define rpl_control_register_address(interface, addr) ((void) 0) #define rpl_control_address_register_done(interface, ll_addr, status) ((void) 0) diff --git a/source/RPL/rpl_downward.c b/source/RPL/rpl_downward.c index ad9cde193c..188f144a45 100644 --- a/source/RPL/rpl_downward.c +++ b/source/RPL/rpl_downward.c @@ -712,6 +712,21 @@ void rpl_instance_send_dao_update(rpl_instance_t *instance) return; } + if (rpl_policy_dao_retry_count() > 0 && instance->dao_attempt >= rpl_policy_dao_retry_count()) { + // Check if recovery logic is started + // after half the retries are done we remove the primary parent + tr_info("DAO remove primary parent"); + rpl_neighbour_t *neighbour = ns_list_get_first(&instance->candidate_neighbours); + if (neighbour) { + rpl_delete_neighbour(instance, neighbour); + } + // Set parameters to restart + instance->dao_in_transit = false; + instance->dao_attempt = 0; + instance->dao_retry_timer = 0; + instance->delay_dao_timer = 0; + return; + } /* Which parent this DAO will be for if storing */ rpl_neighbour_t *parent = NULL; @@ -847,6 +862,15 @@ void rpl_instance_send_dao_update(rpl_instance_t *instance) cur = NULL; } + if (instance->dao_attempt > 0) { + // Start informing problem in routing. This will cause us to select secondary routes when sending the DAO + tr_info("DAO reachability problem"); + protocol_interface_info_entry_t *interface = protocol_stack_interface_info_get_by_rpl_domain(instance->domain, -1); + if (interface) { + ipv6_neighbour_reachability_problem(dst, interface->id); + } + } + bool need_ack = rpl_control_transmit_dao(instance->domain, cur, instance, instance->id, instance->dao_sequence, dodag->id, opts, ptr - opts, dst); ns_dyn_mem_free(opts); @@ -1859,7 +1883,7 @@ void rpl_instance_address_registration_done(protocol_interface_info_entry_t *int if (status == SOCKET_TX_DONE) { /* State_timer is 1/10 s. Set renewal to 75-85% of lifetime */ if_address_entry_t *address = rpl_interface_addr_get(interface, dao_target->prefix); - if (address) { + if (address && address->source != ADDR_SOURCE_DHCP) { address->state_timer = (address->preferred_lifetime * randLIB_get_random_in_range(75, 85) / 10); } neighbour->confirmed = true; diff --git a/source/RPL/rpl_policy.c b/source/RPL/rpl_policy.c index 3048898333..ec581c8bb4 100644 --- a/source/RPL/rpl_policy.c +++ b/source/RPL/rpl_policy.c @@ -35,6 +35,11 @@ #define TRACE_GROUP "RPLy" static bool rpl_policy_parent_confirmation_req = false; +static int8_t rpl_policy_dao_retry_count_conf = 0; +static int16_t rpl_policy_dao_initial_timeout_conf = 20; // Default is 2 seconds 100ms ticks +static uint16_t rpl_policy_dio_validity_period_hysteresis = 0x0180; //Fixed Point 1.5 +static uint8_t rpl_policy_multicast_config_min_advertisment_count = 0; + /* TODO - application API to control when to join new instances / DODAGs * @@ -105,6 +110,11 @@ bool rpl_policy_request_dao_acks(const rpl_domain_t *domain, uint8_t mop) return true; } +void rpl_policy_set_initial_dao_ack_wait(uint16_t timeout_in_ms) +{ + rpl_policy_dao_initial_timeout_conf = timeout_in_ms; +} + uint16_t rpl_policy_initial_dao_ack_wait(const rpl_domain_t *domain, uint8_t mop) { (void)mop; @@ -120,7 +130,18 @@ uint16_t rpl_policy_initial_dao_ack_wait(const rpl_domain_t *domain, uint8_t mop } } - return 20; /* *100ms ticks = 2s */ + return rpl_policy_dao_initial_timeout_conf; +} + + +void rpl_policy_set_dao_retry_count(uint8_t count) +{ + rpl_policy_dao_retry_count_conf = count; +} + +int8_t rpl_policy_dao_retry_count() +{ + return rpl_policy_dao_retry_count_conf; } /* Given the next-hop address from a source routing header, which interface, @@ -192,6 +213,20 @@ uint16_t rpl_policy_etx_hysteresis(rpl_domain_t *domain) return 0x0080; /* 8.8 fixed-point, so 0.5 */ } +uint16_t rpl_policy_dio_validity_period(rpl_domain_t *domain) +{ + (void)domain; + + return rpl_policy_dio_validity_period_hysteresis; /* Fixed Point */ +} + +void rpl_policy_set_dio_validity_period(rpl_domain_t *domain, uint16_t fixed_point) +{ + (void)domain; + + rpl_policy_dio_validity_period_hysteresis = fixed_point; /* Fixed Point */ +} + uint16_t rpl_policy_etx_change_parent_selection_delay(rpl_domain_t *domain) { (void)domain; @@ -331,6 +366,16 @@ bool rpl_policy_parent_confirmation_requested(void) return rpl_policy_parent_confirmation_req; } +uint8_t rpl_policy_dio_multicast_config_advertisment_min_count(void) +{ + return rpl_policy_multicast_config_min_advertisment_count; +} + +void rpl_policy_set_dio_multicast_config_advertisment_min_count(uint8_t min_count) +{ + rpl_policy_multicast_config_min_advertisment_count = min_count; +} + #ifdef RPL_STRUCTURES_H_ #error "rpl_structures.h should not be included by rpl_policy.c" diff --git a/source/RPL/rpl_policy.h b/source/RPL/rpl_policy.h index dc1094e5cd..c51adc81cd 100644 --- a/source/RPL/rpl_policy.h +++ b/source/RPL/rpl_policy.h @@ -27,11 +27,20 @@ bool rpl_policy_join_config(rpl_domain_t *domain, const rpl_dodag_conf_t *conf, bool rpl_policy_request_dao_acks(const rpl_domain_t *domain, uint8_t mop); uint16_t rpl_policy_initial_dao_ack_wait(const rpl_domain_t *domain, uint8_t mop); +void rpl_policy_set_initial_dao_ack_wait(uint16_t timeout_in_ms); + +void rpl_policy_set_dao_retry_count(uint8_t count); +int8_t rpl_policy_dao_retry_count(); + int8_t rpl_policy_srh_next_hop_interface(rpl_domain_t *domain, int8_t if_id, const uint8_t *next_hop); uint16_t rpl_policy_modify_downward_cost_to_root_neighbour(rpl_domain_t *domain, int8_t if_id, const uint8_t *next_hop, uint16_t cost); uint16_t rpl_policy_parent_selection_period(rpl_domain_t *domain); uint16_t rpl_policy_etx_hysteresis(rpl_domain_t *domain); +//Return Fixed point multiple which base 1.0 is 0x0100 +uint16_t rpl_policy_dio_validity_period(rpl_domain_t *domain); +//Fixed point must 1.0 is 0x0100 +void rpl_policy_set_dio_validity_period(rpl_domain_t *domain, uint16_t fixed_point); uint16_t rpl_policy_etx_change_parent_selection_delay(rpl_domain_t *domain); uint16_t rpl_policy_dio_parent_selection_delay(rpl_domain_t *domain); @@ -56,5 +65,7 @@ uint16_t rpl_policy_mrhof_parent_switch_threshold(const rpl_domain_t *domain); uint16_t rpl_policy_mrhof_max_rank_stretch_for_extra_parents(const rpl_domain_t *domain); bool rpl_policy_parent_confirmation_requested(void); void rpl_policy_set_parent_confirmation_request(bool confirmation_requested); +uint8_t rpl_policy_dio_multicast_config_advertisment_min_count(void); +void rpl_policy_set_dio_multicast_config_advertisment_min_count(uint8_t min_count); #endif /* RPL_POLICY_H_ */ diff --git a/source/RPL/rpl_structures.h b/source/RPL/rpl_structures.h index 107ff9b6eb..1d4dcc0c37 100644 --- a/source/RPL/rpl_structures.h +++ b/source/RPL/rpl_structures.h @@ -90,6 +90,7 @@ struct rpl_dodag { bool leaf: 1; /* We are a leaf in this DODAG (by policy) */ bool have_config: 1; /* We have the config */ bool used: 1; /* We have ever been a member of this DODAG? */ + uint8_t new_config_advertisment_count; /* We have advertiment new config at multicasti DIO */ NS_LIST_HEAD(rpl_dodag_version_t, link) versions; /* List of DODAG versions (newest first) */ prefix_list_t prefixes; /* Prefixes advertised in DIO PIOs */ rpl_dio_route_list_t routes; /* Routes advertised in DIO RIOs*/ diff --git a/source/RPL/rpl_upward.c b/source/RPL/rpl_upward.c index cdee6bec90..4bd186d369 100644 --- a/source/RPL/rpl_upward.c +++ b/source/RPL/rpl_upward.c @@ -635,6 +635,7 @@ rpl_dodag_t *rpl_create_dodag(rpl_instance_t *instance, const uint8_t *dodagid, dodag->have_config = false; dodag->used = false; dodag->g_mop_prf = g_mop_prf; + dodag->new_config_advertisment_count = 0; // Default timer parameters and trickle start should never normally // be used - we would set the parameters from the DODAG Config and start // as we join a version. But initialising here catches odd cases where @@ -728,6 +729,7 @@ bool rpl_dodag_update_config(rpl_dodag_t *dodag, const rpl_dodag_conf_t *conf, c /* They've changed the timing parameters for our currently-in-use trickle timer! */ tr_warn("Trickle parameters changed"); trickle_start(&dodag->instance->dio_timer, &dodag->dio_timer_params); + dodag->new_config_advertisment_count = 0; } dodag->instance->of = rpl_objective_lookup(conf->objective_code_point); /* We could be a leaf of an unknown OCP. Still need an OF to choose parents */ @@ -1355,6 +1357,11 @@ static void trace_info_print(const char *fmt, ...) va_end(ap); } +static uint32_t rpl_dio_imax_time_calculate(uint16_t Imax, uint16_t fixed_point) +{ + return (((uint32_t)Imax * fixed_point) / 0x0100); +} + void rpl_instance_run_parent_selection(rpl_instance_t *instance) { @@ -1438,6 +1445,15 @@ void rpl_instance_run_parent_selection(rpl_instance_t *instance) if (preferred_parent) { // Always stop repair if we find a parent rpl_instance_set_local_repair(instance, false); + //Validate time from last DIO + + uint32_t time_between_parent = protocol_core_monotonic_time - preferred_parent->dio_timestamp; + uint32_t accepted_time = rpl_dio_imax_time_calculate(instance->current_dodag_version->dodag->dio_timer_params.Imax, rpl_policy_dio_validity_period(instance->domain)); + + if (accepted_time < time_between_parent) { + rpl_control_transmit_dis(instance->domain, NULL, RPL_SOLINFO_PRED_INSTANCEID, instance->id, NULL, 0, preferred_parent->ll_address); + } + } else if (original_preferred) { // Only start repair if we just lost a parent rpl_instance_set_local_repair(instance, true); @@ -1533,7 +1549,15 @@ void rpl_instance_dio_trigger(rpl_instance_t *instance, protocol_interface_info_ } // Always send config in unicasts (as required), never in multicasts (optional) - rpl_dodag_conf_t *conf = addr ? &dodag->config : NULL; + rpl_dodag_conf_t *conf; + if (addr) { + conf = &dodag->config; + } else if (dodag->new_config_advertisment_count < rpl_policy_dio_multicast_config_advertisment_min_count()) { + conf = &dodag->config; + dodag->new_config_advertisment_count++; + } else { + conf = NULL; + } rpl_control_transmit_dio(instance->domain, cur, instance->id, dodag_version->number, rank, dodag->g_mop_prf, instance->dtsn, dodag, dodag->id, conf, addr); @@ -1921,7 +1945,7 @@ bool rpl_upward_accept_prefix_update(const rpl_dodag_t *dodag_info, const rpl_ne //Calculate Time between from last dio from parent and this neighbour //neighbour dio_timestamp >= pref_parent's, because it's a newly-received message uint32_t time_between_parent = neighbour->dio_timestamp - pref_parent->dio_timestamp; - uint32_t accepted_time = (uint32_t)dodag_info->dio_timer_params.Imax * 2; + uint32_t accepted_time = rpl_dio_imax_time_calculate(dodag_info->dio_timer_params.Imax, 0x0200); //Accept prefix Update If Time from last DIO is more than 2 x Max if (accepted_time < time_between_parent) { return true; diff --git a/source/Security/kmp/kmp_api.c b/source/Security/kmp/kmp_api.c index 35d541f156..3ca8bc2e6a 100644 --- a/source/Security/kmp/kmp_api.c +++ b/source/Security/kmp/kmp_api.c @@ -314,6 +314,11 @@ kmp_type_e kmp_api_type_get(kmp_api_t *kmp) return kmp->type; } +bool kmp_api_receive_disable(kmp_api_t *kmp) +{ + return kmp->receive_disable; +} + kmp_type_e kmp_api_type_from_id_get(uint8_t kmp_id) { switch (kmp_id) { diff --git a/source/Security/kmp/kmp_api.h b/source/Security/kmp/kmp_api.h index cb19ec168d..c690aa9ec9 100644 --- a/source/Security/kmp/kmp_api.h +++ b/source/Security/kmp/kmp_api.h @@ -152,6 +152,16 @@ void kmp_api_delete(kmp_api_t *kmp); */ kmp_type_e kmp_api_type_get(kmp_api_t *kmp); +/** + * kmp_api_type_get get receive disabled status + * + * \param kmp instance + * + * \return true/false true when receiving has been disabled + * + */ +bool kmp_api_receive_disable(kmp_api_t *kmp); + /** * kmp_api_type_from_id_get get KMP type from KMP id * diff --git a/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c b/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c index 3e1c1c7fb6..40a5c2eccd 100644 --- a/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c +++ b/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c @@ -98,7 +98,7 @@ static int8_t auth_eap_tls_sec_prot_message_handle(sec_prot_t *prot); static int8_t auth_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type, uint8_t tls_state); static void auth_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); -static void auth_eap_tls_sec_prot_init_tls(sec_prot_t *prot); +static int8_t auth_eap_tls_sec_prot_init_tls(sec_prot_t *prot); static void auth_eap_tls_sec_prot_delete_tls(sec_prot_t *prot); static void auth_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot); @@ -348,16 +348,16 @@ static int8_t auth_eap_tls_sec_prot_tls_send(sec_prot_t *tls_prot, void *pdu, ui return 0; } -static void auth_eap_tls_sec_prot_init_tls(sec_prot_t *prot) +static int8_t auth_eap_tls_sec_prot_init_tls(sec_prot_t *prot) { eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); if (data->tls_prot) { - return; + return 0; } data->tls_prot = prot->type_get(prot, SEC_PROT_TYPE_TLS); if (!data->tls_prot) { - return; + return -1; } data->tls_prot->header_size = TLS_HEAD_LEN; @@ -369,6 +369,8 @@ static void auth_eap_tls_sec_prot_init_tls(sec_prot_t *prot) data->tls_prot->send = auth_eap_tls_sec_prot_tls_send; data->tls_ongoing = true; + + return 0; } static void auth_eap_tls_sec_prot_delete_tls(sec_prot_t *prot) @@ -388,14 +390,17 @@ static void auth_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"); 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)); - prot->timer_start(prot); + // Set default timeout for the total maximum length of the negotiation + sec_prot_default_timeout_set(&data->common); // KMP-CREATE.confirm prot->create_conf(prot, SEC_RESULT_OK); @@ -469,8 +474,11 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot) // All fragments received for a message if (result == EAP_TLS_MSG_RECEIVE_DONE) { - auth_eap_tls_sec_prot_init_tls(prot); - + // Initialize TLS protocol + if (auth_eap_tls_sec_prot_init_tls(prot) < 0) { + tr_error("TLS init failed"); + return; + } if (data->tls_ongoing) { // Call TLS data->tls_prot->receive(data->tls_prot, data->tls_recv.data, data->tls_recv.total_len); @@ -538,12 +546,14 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot) sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_FINISHED); break; - case EAP_TLS_STATE_FINISHED: + 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"); auth_eap_tls_sec_prot_delete_tls(prot); prot->timer_stop(prot); prot->finished(prot); break; - + } default: break; } 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 b3d4e87008..40e4b9ea0a 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 @@ -59,6 +59,23 @@ int8_t eap_tls_sec_prot_lib_message_allocate(tls_data_t *data, uint8_t head_len, return 0; } +int8_t eap_tls_sec_prot_lib_message_realloc(tls_data_t *data, uint8_t head_len, uint16_t new_len) +{ + tls_data_t new_tls_send; + + eap_tls_sec_prot_lib_message_init(&new_tls_send); + if (eap_tls_sec_prot_lib_message_allocate(&new_tls_send, head_len, new_len) < 0) { + return -1; + } + memcpy(new_tls_send.data + head_len, data->data + head_len, data->handled_len); + new_tls_send.handled_len = data->handled_len; + eap_tls_sec_prot_lib_message_free(data); + + *data = new_tls_send; + + return 0; +} + void eap_tls_sec_prot_lib_message_free(tls_data_t *data) { ns_dyn_mem_free(data->data); diff --git a/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.h b/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.h index 0de960bb05..285e617d64 100644 --- a/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.h +++ b/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.h @@ -72,6 +72,19 @@ extern const uint8_t eap_msg_trace[4][10]; */ int8_t eap_tls_sec_prot_lib_message_allocate(tls_data_t *data, uint8_t head_len, uint16_t len); +/** + * eap_tls_sec_prot_lib_message_realloc allocates larger message buffer and copies existing data to it + * + * \param data data buffer which length is increased + * \param head_len header length + * \param new_len new length for the buffer + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t eap_tls_sec_prot_lib_message_realloc(tls_data_t *data, uint8_t head_len, uint16_t new_len); + /** * eap_tls_sec_prot_lib_message_free free message buffer * diff --git a/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c b/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c index dadbdc17d3..8d73f22f38 100644 --- a/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c +++ b/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c @@ -90,7 +90,7 @@ static int8_t supp_eap_tls_sec_prot_message_handle(sec_prot_t *prot); static int8_t supp_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type, uint8_t tls_state); static void supp_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); -static void supp_eap_tls_sec_prot_init_tls(sec_prot_t *prot); +static int8_t supp_eap_tls_sec_prot_init_tls(sec_prot_t *prot); static void supp_eap_tls_sec_prot_delete_tls(sec_prot_t *prot); static void supp_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot); @@ -360,16 +360,16 @@ static int8_t supp_eap_tls_sec_prot_tls_send(sec_prot_t *tls_prot, void *pdu, ui return 0; } -static void supp_eap_tls_sec_prot_init_tls(sec_prot_t *prot) +static int8_t supp_eap_tls_sec_prot_init_tls(sec_prot_t *prot) { eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); if (data->tls_prot) { - return; + return 0; } data->tls_prot = prot->type_get(prot, SEC_PROT_TYPE_TLS); if (!data->tls_prot) { - return; + return -1; } data->tls_prot->header_size = TLS_HEAD_LEN; @@ -381,6 +381,8 @@ static void supp_eap_tls_sec_prot_init_tls(sec_prot_t *prot) data->tls_prot->send = supp_eap_tls_sec_prot_tls_send; data->tls_ongoing = true; + + return 0; } static void supp_eap_tls_sec_prot_delete_tls(sec_prot_t *prot) @@ -400,7 +402,9 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot) // EAP-TLS supplicant state machine switch (sec_prot_state_get(&data->common)) { case EAP_TLS_STATE_INIT: + tr_info("EAP-TLS init"); sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_REQUEST_ID); + prot->timer_start(prot); break; // Wait EAP request, Identity (starts handshake on supplicant) @@ -411,13 +415,14 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot) return; } + // Set default timeout for the total maximum length of the negotiation + sec_prot_default_timeout_set(&data->common); + // Store sequence ID supp_eap_tls_sec_prot_seq_id_update(prot); tr_info("EAP-TLS start"); - prot->timer_start(prot); - // Send KMP-CREATE.indication prot->create_ind(prot); sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_CREATE_RESP); @@ -459,7 +464,10 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot) data->common.ticks = retry_timeout; // Initialize TLS protocol - supp_eap_tls_sec_prot_init_tls(prot); + if (supp_eap_tls_sec_prot_init_tls(prot) < 0) { + tr_error("TLS init failed"); + return; + } // Request TLS to start (send client hello) data->tls_prot->create_req(data->tls_prot, prot->sec_keys); break; @@ -523,6 +531,7 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot) break; case EAP_TLS_STATE_FINISHED: + tr_info("EAP-TLS finished"); supp_eap_tls_sec_prot_delete_tls(prot); prot->timer_stop(prot); prot->finished(prot); diff --git a/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c b/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c index ed91c306d6..5c0a48393d 100644 --- a/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c +++ b/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c @@ -341,6 +341,7 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) // 4WH authenticator state machine switch (sec_prot_state_get(&data->common)) { case FWH_STATE_INIT: + tr_info("4WH: init"); prot->timer_start(prot); sec_prot_state_set(prot, &data->common, FWH_STATE_CREATE_REQ); break; @@ -349,6 +350,9 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) case FWH_STATE_CREATE_REQ: tr_info("4WH: 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); + uint8_t *pmk = sec_prot_keys_pmk_get(prot->sec_keys); if (!pmk) { // If PMK is not set fails prot->create_conf(prot, SEC_RESULT_ERROR); @@ -429,10 +433,13 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) sec_prot_state_set(prot, &data->common, FWH_STATE_FINISHED); break; - case FWH_STATE_FINISHED: + case FWH_STATE_FINISHED: { + uint8_t *remote_eui_64 = sec_prot_remote_eui_64_addr_get(prot); + tr_info("4WH: finished, eui-64: %s", remote_eui_64 ? trace_array(sec_prot_remote_eui_64_addr_get(prot), 8) : "not set"); prot->timer_stop(prot); prot->finished(prot); break; + } default: break; diff --git a/source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.c b/source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.c index 7faa7e7f43..ee44df03cf 100644 --- a/source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.c +++ b/source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.c @@ -310,6 +310,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot) // 4WH supplicant state machine switch (sec_prot_state_get(&data->common)) { case FWH_STATE_INIT: + tr_info("4WH: init"); prot->timer_start(prot); sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_1); break; @@ -325,6 +326,9 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot) return; } + // Set default timeout for the total maximum length of the negotiation + sec_prot_default_timeout_set(&data->common); + tr_info("4WH: start"); // Store authenticator nonce for check when 4WH Message 3 is received @@ -467,6 +471,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot) break; case FWH_STATE_FINISHED: + tr_info("4WH: finished"); prot->timer_stop(prot); prot->finished(prot); break; diff --git a/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c b/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c index ac95f91783..50a9691b33 100644 --- a/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c +++ b/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c @@ -293,14 +293,17 @@ static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot) // GKH authenticator state machine switch (sec_prot_state_get(&data->common)) { case GKH_STATE_INIT: + tr_info("GKH init"); sec_prot_state_set(prot, &data->common, GKH_STATE_CREATE_REQ); + prot->timer_start(prot); break; // Wait KMP-CREATE.request case GKH_STATE_CREATE_REQ: tr_info("GKH start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); - prot->timer_start(prot); + // Set default timeout for the total maximum length of the negotiation + sec_prot_default_timeout_set(&data->common); // KMP-CREATE.confirm prot->create_conf(prot, SEC_RESULT_OK); @@ -340,10 +343,13 @@ static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot) sec_prot_state_set(prot, &data->common, GKH_STATE_FINISHED); break; - case GKH_STATE_FINISHED: + case GKH_STATE_FINISHED: { + uint8_t *remote_eui_64 = sec_prot_remote_eui_64_addr_get(prot); + tr_info("GKH finished, eui-64: %s", remote_eui_64 ? trace_array(sec_prot_remote_eui_64_addr_get(prot), 8) : "not set"); prot->timer_stop(prot); prot->finished(prot); break; + } default: break; diff --git a/source/Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.c b/source/Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.c index 15b8dcce2c..ccd2890ec9 100644 --- a/source/Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.c +++ b/source/Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.c @@ -230,7 +230,9 @@ static void supp_gkh_sec_prot_state_machine(sec_prot_t *prot) // GKH supplicant state machine switch (sec_prot_state_get(&data->common)) { case GKH_STATE_INIT: + tr_info("GKH init"); sec_prot_state_set(prot, &data->common, GKH_STATE_MESSAGE_1); + prot->timer_start(prot); break; // Wait GKH message 1 (starts handshake on supplicant) @@ -243,11 +245,12 @@ static void supp_gkh_sec_prot_state_machine(sec_prot_t *prot) return; } + // Set default timeout for the total maximum length of the negotiation + sec_prot_default_timeout_set(&data->common); + supp_gkh_sec_prot_security_replay_counter_update(prot); - tr_debug("GKH start"); - - prot->timer_start(prot); + tr_info("GKH start"); // Send KMP-CREATE.indication prot->create_ind(prot); @@ -267,7 +270,7 @@ static void supp_gkh_sec_prot_state_machine(sec_prot_t *prot) break; case GKH_STATE_FINISH: - tr_debug("GKH finish"); + tr_info("GKH finish"); // KMP-FINISHED.indication, prot->finished_ind(prot, sec_prot_result_get(&data->common), prot->sec_keys); @@ -275,6 +278,7 @@ static void supp_gkh_sec_prot_state_machine(sec_prot_t *prot) break; case GKH_STATE_FINISHED: + tr_info("GKH finished"); prot->timer_stop(prot); prot->finished(prot); break; diff --git a/source/Security/protocols/sec_prot_certs.c b/source/Security/protocols/sec_prot_certs.c index cc779a1149..dc76a22ba9 100644 --- a/source/Security/protocols/sec_prot_certs.c +++ b/source/Security/protocols/sec_prot_certs.c @@ -32,6 +32,10 @@ #define TRACE_GROUP "spce" +// Length for PEM coded certificate's begin and end certificate text strings +#define SEC_PROT_CERT_PEM_HEADER_FOOTER_LEN 52 +#define SEC_PROT_CERT_PEM_HEADER_STR "-----BEGIN CERTIFICATE-----" + int8_t sec_prot_certs_init(sec_prot_certs_t *certs) { if (!certs) { @@ -41,6 +45,8 @@ int8_t sec_prot_certs_init(sec_prot_certs_t *certs) sec_prot_certs_chain_entry_init(&certs->own_cert_chain); ns_list_init(&certs->trusted_cert_chain_list); ns_list_init(&certs->cert_revocat_lists); + certs->own_cert_chain_len = 0; + certs->ext_cert_valid_enabled = false; return 0; } @@ -56,6 +62,27 @@ void sec_prot_certs_delete(sec_prot_certs_t *certs) sec_prot_certs_revocat_lists_delete(&certs->cert_revocat_lists); } +int8_t sec_prot_certs_ext_certificate_validation_set(sec_prot_certs_t *certs, bool enabled) +{ + if (!certs) { + return -1; + } + + certs->ext_cert_valid_enabled = enabled; + + return 0; +} + +bool sec_prot_certs_ext_certificate_validation_get(const sec_prot_certs_t *certs) +{ + return certs->ext_cert_valid_enabled; +} + +uint16_t sec_prot_certs_own_cert_chain_len_get(const sec_prot_certs_t *certs) +{ + return certs->own_cert_chain_len; +} + cert_chain_entry_t *sec_prot_certs_chain_entry_create(void) { cert_chain_entry_t *entry = ns_dyn_mem_alloc(sizeof(cert_chain_entry_t)); @@ -98,6 +125,28 @@ uint8_t *sec_prot_certs_cert_get(const cert_chain_entry_t *entry, uint8_t index, return entry->cert[index]; } +uint16_t sec_prot_certs_cert_chain_entry_len_get(const cert_chain_entry_t *entry) +{ + uint16_t chain_length = 0; + for (uint8_t index = 0; index < SEC_PROT_CERT_CHAIN_DEPTH; index++) { + if (entry->cert[index]) { + uint16_t cert_length = entry->cert_len[index]; + // Checks if certificate is in PEM base64 format + if (cert_length > SEC_PROT_CERT_PEM_HEADER_FOOTER_LEN && + entry->cert[index][cert_length - 1] == '\0' && + strstr((const char *)entry->cert[index], SEC_PROT_CERT_PEM_HEADER_STR) != NULL) { + cert_length -= SEC_PROT_CERT_PEM_HEADER_FOOTER_LEN; + /* 4 base64 chars encode 3 bytes (ignores line endings and possible paddings in the + calculation i.e they are counted to length) */ + chain_length += (cert_length / 4) * 3; + } else { + chain_length += cert_length; + } + } + } + return chain_length; +} + int8_t sec_prot_certs_priv_key_set(cert_chain_entry_t *entry, uint8_t *key, uint8_t key_len) { if (!entry) { diff --git a/source/Security/protocols/sec_prot_certs.h b/source/Security/protocols/sec_prot_certs.h index 3c2ce3d1a9..e9a25ece84 100644 --- a/source/Security/protocols/sec_prot_certs.h +++ b/source/Security/protocols/sec_prot_certs.h @@ -58,6 +58,8 @@ typedef struct { cert_chain_entry_t own_cert_chain; /**< Own certificate chain */ cert_chain_list_t trusted_cert_chain_list; /**< Trusted certificate chain lists */ cert_revocat_lists_t cert_revocat_lists; /**< Certificate Revocation Lists */ + uint16_t own_cert_chain_len; /**< Own certificate chain certificates length */ + bool ext_cert_valid_enabled : 1; /**< Extended certificate validation enabled */ } sec_prot_certs_t; /** @@ -78,6 +80,37 @@ int8_t sec_prot_certs_init(sec_prot_certs_t *certs); */ void sec_prot_certs_delete(sec_prot_certs_t *certs); +/** + * sec_prot_certs_ext_certificate_validation_set enable or disable extended certificate validation + * + * \param certs certificate information + * \param enabled true to enable extended validation, false to disable + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t sec_prot_certs_ext_certificate_validation_set(sec_prot_certs_t *certs, bool enabled); + +/** + * sec_prot_certs_ext_certificate_validation_get get extended certificate validation setting + * + * \param certs certificate information + * + * \return true/false enabled or not + * + */ +bool sec_prot_certs_ext_certificate_validation_get(const sec_prot_certs_t *certs); + +/** + * sec_prot_certs_own_cert_chain_len_get get length of own certificate chain + * + * \param certs certificate information + * + * \return length of all the certificates in the own certificate chain + */ +uint16_t sec_prot_certs_own_cert_chain_len_get(const sec_prot_certs_t *certs); + /** * sec_prot_certs_chain_entry_create allocate memory for certificate chain entry * @@ -123,6 +156,15 @@ int8_t sec_prot_certs_cert_set(cert_chain_entry_t *entry, uint8_t index, uint8_t */ uint8_t *sec_prot_certs_cert_get(const cert_chain_entry_t *entry, uint8_t index, uint16_t *cert_len); +/** + * sec_prot_certs_cert_chain_entry_len_get get length of certificate chain on cert chain entry + * + * \param entry certificate chain entry + * + * \return total length of all the certificates in the entry + */ +uint16_t sec_prot_certs_cert_chain_entry_len_get(const cert_chain_entry_t *entry); + /** * sec_prot_certs_priv_key_set set certificate (chain) private key * diff --git a/source/Security/protocols/sec_prot_lib.c b/source/Security/protocols/sec_prot_lib.c index 470d854639..29268529d3 100644 --- a/source/Security/protocols/sec_prot_lib.c +++ b/source/Security/protocols/sec_prot_lib.c @@ -48,7 +48,7 @@ void sec_prot_init(sec_prot_common_t *data) { data->state = SEC_STATE_INIT; data->result = SEC_RESULT_OK; - data->ticks = SEC_TOTAL_TIMEOUT; + data->ticks = SEC_INIT_TIMEOUT; data->trickle_running = false; } @@ -73,10 +73,14 @@ void sec_prot_timer_timeout_handle(sec_prot_t *prot, sec_prot_common_t *data, co if (data->ticks > ticks) { data->ticks -= ticks; } else { - tr_debug("prot timeout"); + tr_debug("prot timeout, state: %i", data->state); data->ticks = 0; sec_prot_result_set(data, SEC_RESULT_TIMEOUT); - sec_prot_state_set(prot, data, SEC_STATE_FINISH); + if (data->state == SEC_STATE_INIT) { + sec_prot_state_set(prot, data, SEC_STATE_FINISHED); + } else { + sec_prot_state_set(prot, data, SEC_STATE_FINISH); + } } } @@ -167,6 +171,11 @@ bool sec_prot_result_ok_check(sec_prot_common_t *data) return false; } +void sec_prot_default_timeout_set(sec_prot_common_t *data) +{ + data->ticks = SEC_TOTAL_TIMEOUT; +} + void sec_prot_lib_nonce_generate(uint8_t *nonce) { // Use randlib diff --git a/source/Security/protocols/sec_prot_lib.h b/source/Security/protocols/sec_prot_lib.h index 4786e49cd4..1ade05bd44 100644 --- a/source/Security/protocols/sec_prot_lib.h +++ b/source/Security/protocols/sec_prot_lib.h @@ -32,6 +32,7 @@ #define FWH_NONCE_LENGTH 32 #define EUI64_LEN 8 #define SEC_TOTAL_TIMEOUT 30 * 60 * 10 // 30 minutes +#define SEC_INIT_TIMEOUT 60 * 10 // 60 seconds #define SEC_FINISHED_TIMEOUT 5 * 10 // 5 seconds @@ -295,4 +296,12 @@ bool sec_prot_result_timeout_check(sec_prot_common_t *data); */ bool sec_prot_result_ok_check(sec_prot_common_t *data); +/** + * sec_prot_default_timeout_set sets default timeout for protocol + * + * \param data common data + * + */ +void sec_prot_default_timeout_set(sec_prot_common_t *data); + #endif /* SEC_PROT_LIB_H_ */ diff --git a/source/Security/protocols/tls_sec_prot/tls_sec_prot.c b/source/Security/protocols/tls_sec_prot/tls_sec_prot.c index 7d443073c6..beff5f5bae 100644 --- a/source/Security/protocols/tls_sec_prot/tls_sec_prot.c +++ b/source/Security/protocols/tls_sec_prot/tls_sec_prot.c @@ -104,6 +104,8 @@ 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); +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 static NS_LIST_DEFINE(tls_sec_prot_queue, tls_sec_prot_queue_t, link); @@ -292,15 +294,17 @@ static void client_tls_sec_prot_state_machine(sec_prot_t *prot) 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->timer_start(prot); - prot->create_conf(prot, SEC_RESULT_OK); sec_prot_state_set(prot, &data->common, TLS_STATE_CONFIGURE); @@ -383,15 +387,17 @@ static void server_tls_sec_prot_state_machine(sec_prot_t *prot) 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)); - prot->timer_start(prot); client_hello = true; sec_prot_state_set(prot, &data->common, TLS_STATE_CREATE_RESP); @@ -494,12 +500,23 @@ static int16_t tls_sec_prot_tls_send(void *handle, const void *buf, size_t len) tls_sec_prot_int_t *data = tls_sec_prot_get(prot); if (!data->tls_send.data) { - eap_tls_sec_prot_lib_message_allocate(&data->tls_send, prot->header_size, TLS_SEC_PROT_BUFFER_SIZE); + 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; @@ -685,4 +702,9 @@ static void tls_sec_prot_queue_remove(sec_prot_t *prot) } } +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 */ diff --git a/source/Security/protocols/tls_sec_prot/tls_sec_prot.h b/source/Security/protocols/tls_sec_prot/tls_sec_prot.h index 5ed9621ea7..129648e1cc 100644 --- a/source/Security/protocols/tls_sec_prot/tls_sec_prot.h +++ b/source/Security/protocols/tls_sec_prot/tls_sec_prot.h @@ -23,7 +23,13 @@ * */ -#define TLS_SEC_PROT_BUFFER_SIZE 1200 // Send buffer size (maximum size for a TLS data for a flight) +/* 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 diff --git a/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c b/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c index b6cec1412d..03e2f5cf72 100644 --- a/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c +++ b/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c @@ -49,6 +49,7 @@ #include "mbedtls/ctr_drbg.h" #include "mbedtls/ssl_ciphersuites.h" #include "mbedtls/debug.h" +#include "mbedtls/oid.h" #include "mbedtls/ssl_internal.h" @@ -57,7 +58,9 @@ #define TLS_HANDSHAKE_TIMEOUT_MIN 25000 #define TLS_HANDSHAKE_TIMEOUT_MAX 201000 -//#define TLS_SEC_PROT_LIB_TLS_DEBUG // Enable mbed TLS debug traces +//#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 */ @@ -71,6 +74,8 @@ struct tls_security_s { 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 */ @@ -85,23 +90,42 @@ static int tls_sec_prot_lib_ssl_send(void *ctx, const unsigned char *buf, size_t 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, unsigned char client_random[32], - unsigned char server_random[32], + 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"; @@ -110,7 +134,6 @@ int8_t tls_sec_prot_lib_init(tls_security_t *sec) 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); @@ -269,21 +292,37 @@ static int tls_sec_prot_lib_configure_certificates(tls_security_t *sec, const se // 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; } - int endpoint = MBEDTLS_SSL_IS_CLIENT; - if (is_server) { - endpoint = MBEDTLS_SSL_IS_SERVER; +#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, endpoint, MBEDTLS_SSL_TRANSPORT_STREAM, 0)) != 0) { + + 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; } @@ -331,8 +370,11 @@ int8_t tls_sec_prot_lib_connect(tls_security_t *sec, bool is_server, const sec_p mbedtls_ssl_conf_min_version(&sec->conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MAJOR_VERSION_3); mbedtls_ssl_conf_max_version(&sec->conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MAJOR_VERSION_3); + // Set certificate verify callback + mbedtls_ssl_set_verify(&sec->ssl, tls_sec_prot_lib_x509_crt_verify, sec); + #ifdef MBEDTLS_ECP_RESTARTABLE - if (endpoint == MBEDTLS_SSL_IS_SERVER) { + if (is_server_is_set) { // Temporary to enable non blocking ECC */ sec->ssl.handshake->ecrs_enabled = 1; } @@ -405,8 +447,8 @@ 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, unsigned char client_random[32], - unsigned char server_random[32], + size_t ivlen, const unsigned char client_random[32], + const unsigned char server_random[32], mbedtls_tls_prf_types tls_prf_type) { (void) kb; @@ -433,6 +475,109 @@ static int tls_sec_prot_lib_ssl_export_keys(void *p_expkey, const unsigned char 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"); + } + + // 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..) + 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_error("invalid 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_error("invalid 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; @@ -518,4 +663,3 @@ uint16_t tls_sec_prot_lib_size(void) } #endif /* WS_MBEDTLS_SECURITY_ENABLED */ #endif /* HAVE_WS */ - diff --git a/source/libDHCPv6/dhcp_service_api.c b/source/libDHCPv6/dhcp_service_api.c index 5eb4164485..8e321a9468 100644 --- a/source/libDHCPv6/dhcp_service_api.c +++ b/source/libDHCPv6/dhcp_service_api.c @@ -679,6 +679,7 @@ void dhcp_service_delete(uint16_t instance) int dhcp_service_send_resp(uint32_t msg_tr_id, uint8_t options, uint8_t *msg_ptr, uint16_t msg_len) { + tr_debug("Send DHCPv6 response"); msg_tr_t *msg_tr_ptr; server_instance_t *srv_instance; msg_tr_ptr = dhcp_tr_find(msg_tr_id); @@ -706,6 +707,7 @@ int dhcp_service_send_resp(uint32_t msg_tr_id, uint8_t options, uint8_t *msg_ptr } uint32_t dhcp_service_send_req(uint16_t instance_id, uint8_t options, void *ptr, const uint8_t addr[static 16], uint8_t *msg_ptr, uint16_t msg_len, dhcp_service_receive_resp_cb *receive_resp_cb) { + tr_debug("Send DHCPv6 request"); msg_tr_t *msg_tr_ptr; server_instance_t *srv_ptr; srv_ptr = dhcp_service_client_find(instance_id); @@ -767,6 +769,17 @@ void dhcp_service_req_remove(uint32_t msg_tr_id) return; } +void dhcp_service_req_remove_all(void *msg_class_ptr) +{ + if (dhcp_service) { + ns_list_foreach_safe(msg_tr_t, cur_ptr, &dhcp_service->tr_list) { + if (cur_ptr->client_obj_ptr == msg_class_ptr) { + dhcp_tr_delete(cur_ptr); + } + } + } +} + void dhcp_service_send_message(msg_tr_t *msg_tr_ptr) { int8_t retval; @@ -930,4 +943,9 @@ bool dhcp_service_timer_tick(uint16_t ticks) return false; } +void dhcp_service_req_remove_all(void *msg_class_ptr) +{ + (void)msg_class_ptr; +} + #endif diff --git a/source/libDHCPv6/libDHCPv6.c b/source/libDHCPv6/libDHCPv6.c index 5b7b3ffb8b..86fa88345c 100644 --- a/source/libDHCPv6/libDHCPv6.c +++ b/source/libDHCPv6/libDHCPv6.c @@ -217,6 +217,17 @@ dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_entry_get_by_prefix(int8_t in return NULL; } +dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_validate_class_pointer(void *class_ptr) +{ + ns_list_foreach(dhcpv6_client_server_data_t, cur, &dhcpv6_client_nonTemporal_list) { + if (cur == class_ptr) { + return cur; + } + } + return NULL; +} + + uint16_t libdhcpv6_duid_option_size(uint16_t linkType) { uint16_t length = 8; // Type & Length header part *2 diff --git a/source/libDHCPv6/libDHCPv6.h b/source/libDHCPv6/libDHCPv6.h index 7cbf1cdd7e..e3cb612826 100644 --- a/source/libDHCPv6/libDHCPv6.h +++ b/source/libDHCPv6/libDHCPv6.h @@ -235,6 +235,7 @@ dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_entry_get_by_iaid(uint32_t ia dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_entry_get_by_transactionId(uint32_t txId); dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_entry_get_by_prefix(int8_t interfaceId, uint8_t *prefix); dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_entry_get_by_instance(uint8_t instanceId); +dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_validate_class_pointer(void *class_ptr); uint8_t libdhcpv6_nonTemporal_entry_get_unique_instance_id(void); diff --git a/source/libNET/src/ns_net.c b/source/libNET/src/ns_net.c index da7e31b98e..5ee8a60dc6 100644 --- a/source/libNET/src/ns_net.c +++ b/source/libNET/src/ns_net.c @@ -988,18 +988,30 @@ int8_t arm_network_trusted_certificate_remove(const arm_certificate_entry_s *cer int8_t arm_network_trusted_certificates_remove(void) { +#ifdef HAVE_WS + return ws_pae_controller_trusted_certificates_remove(); +#else return -1; +#endif } int8_t arm_network_own_certificate_add(const arm_certificate_entry_s *cert) { +#ifdef HAVE_WS + return ws_pae_controller_own_certificate_add(cert); +#else (void) cert; return -1; +#endif } extern int8_t arm_network_own_certificates_remove(void) { +#ifdef HAVE_WS + return ws_pae_controller_own_certificates_remove(); +#else return -1; +#endif } int8_t arm_network_certificate_revocation_list_add(const arm_cert_revocation_list_entry_s *crl)