Skip to content

Commit

Permalink
Added checks for Border Router frame counter space exhaustion (ARMmbe…
Browse files Browse the repository at this point in the history
…d#2660)

* Added checks for Border Router frame counter space exhaustion

Added three checks for Border Router frame counter space exhaustion:
1) Compares GTK lifetime left to frame counter space left (as percent)
and decrements GTK lifetime if frame counter space is exhausting faster
than GTK lifetime.
2) Calculates an estimate for how much free frame counter space is
needed for the GTK update and initiates it faster if needed.
3) Calculates an estimate for how much free frame counter space is
needed for the GTK activation and initiates it faster if needed.
  • Loading branch information
Mika Leppänen authored Aug 17, 2021
1 parent f1a65ec commit 7415bc7
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 18 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Features
* Added support for triggering test procedures (e.g. for manually sending DIS, DIO, DAO, PAS, PS, PCS and PC).
* Added automatic test procedure triggering during bootstrap (PAS, EAPOL target selection, PCS, DIS, RPL parent selection).
* Added checks for Border Router frame counter space exhaustion.

### Changes
* PAN_TIMEOUT for medium sized network changed to 30 minutes.
Expand Down
123 changes: 119 additions & 4 deletions source/6LoWPAN/ws/ws_pae_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@
// Short GTK lifetime value, for GTK install check
#define SHORT_GTK_LIFETIME 10 * 3600 // 10 hours

// Frame counter exhaust check timer
#define FRAME_CNT_TIMER 3600

#define SECONDS_IN_DAY (3600 * 24)

typedef struct {
ns_list_link_t link; /**< Link */
uint16_t pan_id; /**< PAN ID */
Expand All @@ -93,6 +98,7 @@ typedef struct {
ws_pae_auth_nw_info_updated *nw_info_updated; /**< Security keys network info updated callback */
ws_pae_auth_ip_addr_get *ip_addr_get; /**< IP address get callback */
ws_pae_auth_congestion_get *congestion_get; /**< Congestion get callback */
ws_pae_auth_nw_frame_counter_read *nw_frame_cnt_read; /**< Network frame counter read callback */
supp_list_t active_supp_list; /**< List of active supplicants */
supp_list_t waiting_supp_list; /**< List of waiting supplicants */
shared_comp_list_t shared_comp_list; /**< Shared component list */
Expand All @@ -101,13 +107,17 @@ typedef struct {
const sec_prot_certs_t *certs; /**< Certificates */
sec_prot_keys_nw_info_t *sec_keys_nw_info; /**< Security keys network information */
sec_cfg_t *sec_cfg; /**< Security configuration */
frame_counters_t *frame_counters; /**< Frame counters */
uint32_t prev_frame_cnt; /**< Previous frame counter */
uint16_t prev_frame_cnt_timer; /**< Previous frame counter timer */
uint16_t supp_max_number; /**< Max number of stored supplicants */
uint16_t waiting_supp_list_size; /**< Waiting supplicants list size */
uint8_t relay_socked_msg_if_instance_id; /**< Relay socket message interface instance identifier */
uint8_t radius_socked_msg_if_instance_id; /**< Radius socket message interface instance identifier */
bool timer_running : 1; /**< Timer is running */
bool gtk_new_inst_req_exp : 1; /**< GTK new install required timer expired */
bool gtk_new_act_time_exp: 1; /**< GTK new activation time expired */
bool prev_frame_cnt_set : 1; /**< Previous frame counter set */
} pae_auth_t;

static int8_t ws_pae_auth_network_keys_from_gtks_set(pae_auth_t *pae_auth, bool force_install);
Expand All @@ -118,6 +128,7 @@ static pae_auth_t *ws_pae_auth_get(protocol_interface_info_entry_t *interface_pt
static pae_auth_t *ws_pae_auth_by_kmp_service_get(kmp_service_t *service);
static int8_t ws_pae_auth_event_send(kmp_service_t *service, void *data);
static void ws_pae_auth_tasklet_handler(arm_event_s *event);
static uint32_t ws_pae_auth_lifetime_key_frame_cnt_check(pae_auth_t *pae_auth, uint8_t gtk_index, uint16_t seconds);
static void ws_pae_auth_gtk_key_insert(pae_auth_t *pae_auth);
static int8_t ws_pae_auth_new_gtk_activate(pae_auth_t *pae_auth);
static int8_t ws_pae_auth_timer_if_start(kmp_service_t *service, kmp_api_t *kmp);
Expand Down Expand Up @@ -145,9 +156,9 @@ static void ws_pae_auth_waiting_supp_deleted(void *pae_auth);
static int8_t tasklet_id = -1;
static NS_LIST_DEFINE(pae_auth_list, pae_auth_t, link);

int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_cfg_t *sec_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info)
int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_cfg_t *sec_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info, frame_counters_t *frame_counters)
{
if (!interface_ptr || !next_gtks || !certs || !sec_cfg || !sec_keys_nw_info) {
if (!interface_ptr || !next_gtks || !certs || !sec_cfg || !sec_keys_nw_info || !frame_counters) {
return -1;
}

Expand Down Expand Up @@ -175,16 +186,21 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot
pae_auth->nw_info_updated = NULL;
pae_auth->ip_addr_get = NULL;
pae_auth->congestion_get = NULL;
pae_auth->nw_frame_cnt_read = NULL;

pae_auth->next_gtks = next_gtks;
pae_auth->certs = certs;
pae_auth->sec_keys_nw_info = sec_keys_nw_info;
pae_auth->sec_cfg = sec_cfg;
pae_auth->frame_counters = frame_counters;
pae_auth->prev_frame_cnt = 0;
pae_auth->prev_frame_cnt_timer = FRAME_CNT_TIMER;
pae_auth->supp_max_number = SUPPLICANT_MAX_NUMBER;
pae_auth->waiting_supp_list_size = 0;

pae_auth->gtk_new_inst_req_exp = false;
pae_auth->gtk_new_act_time_exp = false;
pae_auth->prev_frame_cnt_set = false;

pae_auth->relay_socked_msg_if_instance_id = 0;
pae_auth->radius_socked_msg_if_instance_id = 0;
Expand Down Expand Up @@ -316,7 +332,7 @@ int8_t ws_pae_auth_delete(protocol_interface_info_entry_t *interface_ptr)
return 0;
}

void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated, ws_pae_auth_ip_addr_get *ip_addr_get, ws_pae_auth_congestion_get *congestion_get)
void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated, ws_pae_auth_ip_addr_get *ip_addr_get, ws_pae_auth_congestion_get *congestion_get, ws_pae_auth_nw_frame_counter_read *nw_frame_cnt_read)
{
if (!interface_ptr) {
return;
Expand All @@ -333,6 +349,7 @@ void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_
pae_auth->nw_info_updated = nw_info_updated;
pae_auth->ip_addr_get = ip_addr_get;
pae_auth->congestion_get = congestion_get;
pae_auth->nw_frame_cnt_read = nw_frame_cnt_read;
}

void ws_pae_auth_start(protocol_interface_info_entry_t *interface_ptr)
Expand Down Expand Up @@ -734,7 +751,11 @@ void ws_pae_auth_slow_timer(uint16_t seconds)
if (!sec_prot_keys_gtk_is_set(pae_auth->sec_keys_nw_info->gtks, i)) {
continue;
}
uint32_t timer_seconds = sec_prot_keys_gtk_lifetime_decrement(pae_auth->sec_keys_nw_info->gtks, i, current_time, seconds, true);
uint32_t gtk_lifetime_dec_extra_seconds = 0;
if (active_index == i) {
gtk_lifetime_dec_extra_seconds = ws_pae_auth_lifetime_key_frame_cnt_check(pae_auth, i, seconds);
}
uint32_t timer_seconds = sec_prot_keys_gtk_lifetime_decrement(pae_auth->sec_keys_nw_info->gtks, i, current_time, seconds + gtk_lifetime_dec_extra_seconds, true);
if (active_index == i) {
if (!pae_auth->gtk_new_inst_req_exp) {
pae_auth->gtk_new_inst_req_exp = ws_pae_timers_gtk_new_install_required(pae_auth->sec_cfg, timer_seconds);
Expand Down Expand Up @@ -786,6 +807,100 @@ void ws_pae_auth_slow_timer(uint16_t seconds)
ws_pae_key_storage_timer(seconds);
}

static uint32_t ws_pae_auth_lifetime_key_frame_cnt_check(pae_auth_t *pae_auth, uint8_t gtk_index, uint16_t seconds)
{
uint32_t decrement_seconds = 0;

if (pae_auth->prev_frame_cnt_timer > seconds) {
pae_auth->prev_frame_cnt_timer -= seconds;
return 0;
}
pae_auth->prev_frame_cnt_timer = FRAME_CNT_TIMER;

uint32_t frame_cnt = 0;
if (pae_auth->nw_frame_cnt_read(pae_auth->interface_ptr, &frame_cnt, gtk_index) < 0) {
return 0;
}

sec_timer_cfg_t *timer_cfg = &pae_auth->sec_cfg->timer_cfg;

// For GTK lifetime and frame counter space calculate the percent that has been used
uint32_t gtk_lifetime_left = sec_prot_keys_gtk_lifetime_get(pae_auth->sec_keys_nw_info->gtks, gtk_index);
uint32_t gtk_lifetime = timer_cfg->gtk_expire_offset;
uint32_t gtk_lifetime_left_percent = gtk_lifetime_left * 100 / gtk_lifetime;

uint32_t frame_cnt_left_percent = ((uint64_t)((UINT32_MAX - frame_cnt))) * 100 / UINT32_MAX;

tr_info("Active GTK lifetime %"PRIu32", frame counter %"PRIu32" percent, counter %"PRIu32, gtk_lifetime_left_percent, frame_cnt_left_percent, frame_cnt);

/* If frame counter space has been exhausted faster than should be based on GTK lifetime
* decrements GTK lifetime. Do not check until 20% of the frame counter space has been used
* so that we have data from longer time period. As sanity check, validate that GTK lifetime
* is not more than 105% of the GTK lifetime.
*/
uint32_t gtk_new_install_req_seconds = timer_cfg->gtk_expire_offset - timer_cfg->gtk_new_install_req * timer_cfg->gtk_expire_offset / 100;
if ((frame_cnt_left_percent < gtk_lifetime_left_percent && frame_cnt_left_percent < 80) ||
gtk_lifetime_left_percent > 105) {
// If not yet on GTK update period
if (gtk_lifetime_left > (gtk_new_install_req_seconds + SECONDS_IN_DAY)) {
uint32_t diff = gtk_lifetime_left_percent - frame_cnt_left_percent;
decrement_seconds = gtk_lifetime * diff / 100 + SECONDS_IN_DAY;
if (decrement_seconds > gtk_lifetime_left - gtk_new_install_req_seconds) {
decrement_seconds = gtk_lifetime_left - gtk_new_install_req_seconds;
}
tr_info("Decrement GTK lifetime percent, seconds %"PRIu32, decrement_seconds);
}
}

// Calculate how much frame counters have changed and store maximum if larger than previous maximum
uint32_t frame_cnt_diff = 0;
if (pae_auth->prev_frame_cnt_set && frame_cnt > pae_auth->prev_frame_cnt) {
frame_cnt_diff = frame_cnt - pae_auth->prev_frame_cnt;
if (frame_cnt_diff > pae_auth->frame_counters->counter[gtk_index].max_frame_counter_chg) {
pae_auth->frame_counters->counter[gtk_index].max_frame_counter_chg = frame_cnt_diff;
}
}

tr_info("Frame counter change %"PRIu32", max %"PRIu32, frame_cnt_diff, pae_auth->frame_counters->counter[gtk_index].max_frame_counter_chg);

/* Calculates an estimate for how much free frame counter space is needed for the GTK update and
* initiates it faster if needed (default length of GTK update is 6 days).
*/
uint32_t max_needed_frame_counters =
pae_auth->frame_counters->counter[gtk_index].max_frame_counter_chg * gtk_new_install_req_seconds / 3600;
// Adds 20% to calculated value
max_needed_frame_counters = max_needed_frame_counters * 120 / 100;
// If estimated value is more than is left starts GTK update right away (if not already started)
if (max_needed_frame_counters >= (UINT32_MAX - frame_cnt)) {
if (gtk_lifetime_left > gtk_new_install_req_seconds) {
decrement_seconds = gtk_lifetime_left - gtk_new_install_req_seconds;
tr_info("Decrement GTK lifetime update, seconds %"PRIu32, decrement_seconds);
}
}

/* Calculates an estimate for how much free frame counter space is needed for the GTK activation and
* initiates it faster if needed (default length of GTK activation is 60 minutes).
*/
uint32_t gtk_new_activation_time_seconds = timer_cfg->gtk_expire_offset / timer_cfg->gtk_new_act_time;
// Calculates the estimated maximum value for frame counter during GTK update
max_needed_frame_counters =
pae_auth->frame_counters->counter[gtk_index].max_frame_counter_chg * gtk_new_activation_time_seconds / 3600;
// Adds 200% to calculated value
max_needed_frame_counters = max_needed_frame_counters * 300 / 100;
// If estimated value is more than is left starts GTK update right away (if not already started)
if (max_needed_frame_counters >= (UINT32_MAX - frame_cnt)) {
if (gtk_lifetime_left > gtk_new_activation_time_seconds) {
decrement_seconds = gtk_lifetime_left - gtk_new_activation_time_seconds;
tr_info("Decrement GTK lifetime activation, seconds %"PRIu32, decrement_seconds);
}
}

pae_auth->prev_frame_cnt = frame_cnt;
pae_auth->prev_frame_cnt_set = true;

return decrement_seconds;
}

static void ws_pae_auth_gtk_key_insert(pae_auth_t *pae_auth)
{
// Gets index to install the key
Expand Down
23 changes: 19 additions & 4 deletions source/6LoWPAN/ws/ws_pae_auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,13 @@
* \param timer_settings timer settings
* \param sec_cfg security configuration
* \param sec_keys_nw_info security keys network information
* \param frame_counters frame counters
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_cfg_t *sec_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info);
int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_cfg_t *sec_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info, frame_counters_t *frame_counters);

/**
* ws_pae_auth_addresses_set set relay addresses
Expand Down Expand Up @@ -260,6 +261,19 @@ typedef void ws_pae_auth_ip_addr_get(protocol_interface_info_entry_t *interface_
*/
typedef bool ws_pae_auth_congestion_get(protocol_interface_info_entry_t *interface_ptr, uint16_t active_supp);

/**
* ws_pae_auth_nw_frame_counter_read network frame counter read callback
*
* \param interface_ptr interface
* \param counter frame counter
* \param gtk_index GTK index
*
* \return < 0 failure
* \return >= 0 success
*
*/
typedef int8_t ws_pae_auth_nw_frame_counter_read(protocol_interface_info_entry_t *interface_ptr, uint32_t *counter, uint8_t gtk_index);

/**
* ws_pae_auth_cb_register register PAE authenticator callbacks
*
Expand All @@ -270,17 +284,18 @@ typedef bool ws_pae_auth_congestion_get(protocol_interface_info_entry_t *interfa
* \param nw_info_updated network keys updated callback
* \param ip_addr_get IP addressing information callback
* \param congestion_get congestion get callback
* \param nw_frame_cnt_read network frame counter read callback
*
*/
void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated, ws_pae_auth_ip_addr_get *ip_addr_get, ws_pae_auth_congestion_get *congestion_get);
void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated, ws_pae_auth_ip_addr_get *ip_addr_get, ws_pae_auth_congestion_get *congestion_get, ws_pae_auth_nw_frame_counter_read *nw_frame_cnt_read);

#else

#define ws_pae_auth_init(interface_ptr, next_gtks, certs, sec_cfg, sec_keys_nw_info) 1
#define ws_pae_auth_init(interface_ptr, next_gtks, certs, sec_cfg, sec_keys_nw_info, frame_counters) 1
#define ws_pae_auth_timing_adjust(timing)
#define ws_pae_auth_addresses_set(interface_ptr, local_port, remote_addr, remote_port) 1
#define ws_pae_auth_delete NULL
#define ws_pae_auth_cb_register(interface_ptr, hash_set, nw_key_insert, nw_key_index_set, nw_info_updated, ip_addr_get, congestion_get) {(void) hash_set;}
#define ws_pae_auth_cb_register(interface_ptr, hash_set, nw_key_insert, nw_key_index_set, nw_info_updated, ip_addr_get, congestion_get, nw_frame_cnt_read) {(void) hash_set;}
#define ws_pae_auth_start(interface_ptr)
#define ws_pae_auth_gtks_updated NULL
#define ws_pae_auth_nw_key_index_update NULL
Expand Down
21 changes: 19 additions & 2 deletions source/6LoWPAN/ws/ws_pae_controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ static void ws_pae_controller_nw_info_updated_check(protocol_interface_info_entr
#ifdef HAVE_PAE_AUTH
static void ws_pae_controller_auth_ip_addr_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *address);
static bool ws_pae_controller_auth_congestion_get(protocol_interface_info_entry_t *interface_ptr, uint16_t active_supp);
static int8_t ws_pae_controller_auth_nw_frame_counter_read(protocol_interface_info_entry_t *interface_ptr, uint32_t *counter, uint8_t gtk_index);
#endif
static pae_controller_t *ws_pae_controller_get(protocol_interface_info_entry_t *interface_ptr);
static void ws_pae_controller_frame_counter_timer(uint16_t seconds, pae_controller_t *entry);
Expand Down Expand Up @@ -239,7 +240,7 @@ int8_t ws_pae_controller_authenticator_start(protocol_interface_info_entry_t *in
ws_pae_auth_node_limit_set(controller->interface_ptr, pae_controller_config.node_limit);
}

ws_pae_auth_cb_register(interface_ptr, ws_pae_controller_gtk_hash_set, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_nw_key_index_check_and_set, ws_pae_controller_nw_info_updated_check, ws_pae_controller_auth_ip_addr_get, ws_pae_controller_auth_congestion_get);
ws_pae_auth_cb_register(interface_ptr, ws_pae_controller_gtk_hash_set, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_nw_key_index_check_and_set, ws_pae_controller_nw_info_updated_check, ws_pae_controller_auth_ip_addr_get, ws_pae_controller_auth_congestion_get, ws_pae_controller_auth_nw_frame_counter_read);

controller->auth_started = true;

Expand Down Expand Up @@ -410,6 +411,21 @@ static bool ws_pae_controller_auth_congestion_get(protocol_interface_info_entry_

return controller->congestion_get(interface_ptr, active_supp);
}

static int8_t ws_pae_controller_auth_nw_frame_counter_read(protocol_interface_info_entry_t *interface_ptr, uint32_t *counter, uint8_t gtk_index)
{
if (!interface_ptr) {
return -1;
}

pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
if (!controller) {
return -1;
}

controller->nw_frame_counter_read(interface_ptr, counter, gtk_index);
return 0;
}
#endif

int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface_ptr, uint8_t *br_iid)
Expand Down Expand Up @@ -849,6 +865,7 @@ static void ws_pae_controller_frame_counter_index_reset(frame_counters_t *frame_
memset(frame_counters->counter[index].gtk, 0, GTK_LEN);
frame_counters->counter[index].frame_counter = 0;
frame_counters->counter[index].stored_frame_counter = 0;
frame_counters->counter[index].max_frame_counter_chg = 0;
frame_counters->counter[index].set = false;
}

Expand Down Expand Up @@ -951,7 +968,7 @@ int8_t ws_pae_controller_auth_init(protocol_interface_info_entry_t *interface_pt
return -1;
}

if (ws_pae_auth_init(controller->interface_ptr, &controller->next_gtks, &controller->certs, &controller->sec_cfg, &controller->sec_keys_nw_info) < 0) {
if (ws_pae_auth_init(controller->interface_ptr, &controller->next_gtks, &controller->certs, &controller->sec_cfg, &controller->sec_keys_nw_info, &controller->frame_counters) < 0) {
return -1;
}

Expand Down
Loading

0 comments on commit 7415bc7

Please sign in to comment.