Re: [PATCH BlueZ v4] mesh: Secure Beacon - IV_Index/Key Refresh re-write

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Applied

On Thu, 2019-10-10 at 15:58 -0700, Brian Gix wrote:
> This is a major rewrite of Secure Network Beacon (SNB) handling
> that includes:
> 
> * Seperating Key Refresh from IV_Index handling
> 
>   This is a clearer handling of the two features. Although both features
>   are represented in SNB's, they run independantly.
> 
> * Creating a Seperate IV_Index initialization and updating state
>   distinct from the current values sent and received in SNBs.
> 
>   If a restart occured during an IV Update procedure (96 hours long)
>   the IVU bit got lost, and Sequence number resetting was not done
>   correctly.
> 
> * Assuring that all Nodes handled by daemon receive each incoming
>   beacon. SNB handling previously stopped after the first node
>   successfuly handled it, although the SNB may be valid for many local
>   nodes.
> ---
>  mesh/mesh-config-json.c |   3 +-
>  mesh/net.c              | 350 +++++++++++++++-------------------------
>  2 files changed, 131 insertions(+), 222 deletions(-)
> 
> diff --git a/mesh/mesh-config-json.c b/mesh/mesh-config-json.c
> index 198fef518..df58cbd7d 100644
> --- a/mesh/mesh-config-json.c
> +++ b/mesh/mesh-config-json.c
> @@ -2057,7 +2057,8 @@ bool mesh_config_write_seq_number(struct mesh_config *cfg, uint32_t seq,
>  		return mesh_config_save(cfg, true, NULL, NULL);
>  	}
>  
> -	if (get_int(cfg->jnode, "sequenceNumber", &value))
> +	/* If resetting seq to Zero, make sure cached value reset as well */
> +	if (seq && get_int(cfg->jnode, "sequenceNumber", &value))
>  		cached = (uint32_t)value;
>  
>  	/*
> diff --git a/mesh/net.c b/mesh/net.c
> index 2785039db..f07de4d8a 100644
> --- a/mesh/net.c
> +++ b/mesh/net.c
> @@ -41,7 +41,7 @@
>  
>  #define IV_IDX_DIFF_RANGE	42
>  
> -/* #define IV_IDX_UPD_MIN	(60)		1 minute for Testing */
> +/*#define IV_IDX_UPD_MIN	(5 * 60)	* 5 minute for Testing */
>  #define IV_IDX_UPD_MIN	(60 * 60 * 96)	/* 96 Hours - per Spec */
>  #define IV_IDX_UPD_HOLD	(IV_IDX_UPD_MIN/2)
>  #define IV_IDX_UPD_MAX	(IV_IDX_UPD_MIN + IV_IDX_UPD_HOLD)
> @@ -257,6 +257,11 @@ struct net_queue_data {
>  	uint16_t len;
>  };
>  
> +struct net_beacon_data {
> +	const uint8_t *data;
> +	uint16_t len;
> +};
> +
>  #define FAST_CACHE_SIZE 8
>  static struct l_queue *fast_cache;
>  static struct l_queue *nets;
> @@ -503,6 +508,7 @@ void mesh_friend_sub_del(struct mesh_net *net, uint16_t lpn,
>  uint32_t mesh_net_next_seq_num(struct mesh_net *net)
>  {
>  	uint32_t seq = net->seq_num++;
> +
>  	node_set_sequence_number(net->node, net->seq_num);
>  	return seq;
>  }
> @@ -568,9 +574,10 @@ static bool create_secure_beacon(struct mesh_net *net,
>  					struct mesh_subnet *subnet,
>  					uint8_t *beacon_data)
>  {
> +	bool kr = (subnet->kr_phase == KEY_REFRESH_PHASE_TWO);
> +
>  	return net_key_snb_compose(subnet->net_key_tx, net->iv_index,
> -				!!subnet->key_refresh, iv_is_updating(net),
> -								beacon_data);
> +					kr, net->iv_update, beacon_data);
>  }
>  
>  static void send_network_beacon(struct mesh_subnet *subnet,
> @@ -718,6 +725,7 @@ bool mesh_net_set_seq_num(struct mesh_net *net, uint32_t seq)
>  		return false;
>  
>  	net->seq_num = seq;
> +	node_set_sequence_number(net->node, net->seq_num);
>  
>  	return true;
>  }
> @@ -1034,7 +1042,7 @@ uint32_t mesh_net_get_iv_index(struct mesh_net *net)
>  	if (!net)
>  		return 0xffffffff;
>  
> -	return net->iv_index - (iv_is_updating(net) ? 1 : 0);
> +	return net->iv_index - net->iv_update;
>  }
>  
>  /* TODO: net key index? */
> @@ -2616,10 +2624,15 @@ static void iv_upd_to(struct l_timeout *upd_timeout, void *user_data)
>  			break;
>  		}
>  
> -		l_info("iv_upd_state = IV_UPD_NORMAL_HOLD");
> +		l_debug("iv_upd_state = IV_UPD_NORMAL_HOLD");
>  		net->iv_upd_state = IV_UPD_NORMAL_HOLD;
>  		l_timeout_modify(net->iv_update_timeout, IV_IDX_UPD_MIN);
> -		mesh_net_set_seq_num(net, 0);
> +		if (net->iv_update)
> +			mesh_net_set_seq_num(net, 0);
> +
> +		net->iv_update = false;
> +		mesh_config_write_iv_index(node_config_get(net->node),
> +							net->iv_index, false);
>  		l_queue_foreach(net->subnets, set_network_beacon, net);
>  		mesh_net_flush_msg_queues(net);
>  		break;
> @@ -2629,8 +2642,12 @@ static void iv_upd_to(struct l_timeout *upd_timeout, void *user_data)
>  	case IV_UPD_NORMAL:
>  		l_timeout_remove(upd_timeout);
>  		net->iv_update_timeout = NULL;
> -		l_info("iv_upd_state = IV_UPD_NORMAL");
> +		l_debug("iv_upd_state = IV_UPD_NORMAL");
>  		net->iv_upd_state = IV_UPD_NORMAL;
> +		if (net->iv_update)
> +			mesh_net_set_seq_num(net, 0);
> +
> +		net->iv_update = false;
>  		if (net->seq_num > IV_UPDATE_SEQ_TRIGGER)
>  			mesh_net_iv_index_update(net);
>  		break;
> @@ -2707,39 +2724,41 @@ static int key_refresh_finish(struct mesh_net *net, uint16_t idx)
>  	return MESH_STATUS_SUCCESS;
>  }
>  
> -static void update_iv_kr_state(struct mesh_subnet *subnet, uint32_t iv_index,
> -				bool iv_update, bool kr_transition,
> -				bool rxed_key_refresh, bool lpn)
> +static void update_kr_state(struct mesh_subnet *subnet, bool kr, uint32_t id)
> +{
> +	/* Figure out the key refresh phase */
> +	if (kr) {
> +		if (id == subnet->net_key_upd) {
> +			l_debug("Beacon based KR phase 2 change");
> +			key_refresh_phase_two(subnet->net, subnet->idx);
> +		}
> +	} else {
> +		if (id == subnet->net_key_upd) {
> +			l_debug("Beacon based KR phase 3 change");
> +			key_refresh_finish(subnet->net, subnet->idx);
> +		}
> +	}
> +}
> +
> +static void update_iv_ivu_state(struct mesh_net *net, uint32_t iv_index,
> +								bool ivu)
>  {
> -	struct mesh_net *net = subnet->net;
> -	uint8_t local_kr;
>  	uint32_t local_iv_index;
> -	bool local_iv_update;
> +	bool local_ivu;
>  
> -	/* Save original settings to avoid resetting same values,
> -	 * and secure beacon timer
> -	 */
> +	/* Save original settings to differentiate what has changed */
>  	local_iv_index = net->iv_index;
> -	local_kr = subnet->key_refresh;
> -	local_iv_update = iv_is_updating(net);
> -
> -	if (iv_index != local_iv_index || kr_transition)
> -		l_info("SNB-RX: %8.8x - Key Refresh: %d IV Update: %d",
> -					iv_index, rxed_key_refresh, iv_update);
> +	local_ivu = net->iv_update;
>  
> -	if (iv_update && (net->iv_upd_state > IV_UPD_UPDATING)) {
> -		if (iv_index != net->iv_index)
> -			l_error("Update attempted to0 soon (Normal < MIN)");
> -
> -		return;
> +	if ((iv_index - ivu) > (local_iv_index - local_ivu)) {
> +		/* Don't accept IV_Index changes when performing SAR Out */
> +		if (l_queue_length(net->sar_out))
> +			return;
>  	}
>  
> +	/* If first beacon seen, accept without judgement */
>  	if (net->iv_upd_state == IV_UPD_INIT) {
> -		if (iv_index > net->iv_index)
> -			mesh_net_set_seq_num(net, 0);
> -		net->iv_index = iv_index;
> -
> -		if (iv_update) {
> +		if (ivu) {
>  			/* Other devices will be accepting old or new iv_index,
>  			 * but we don't know how far through update they are.
>  			 * Starting permissive state will allow us maximum
> @@ -2753,164 +2772,89 @@ static void update_iv_kr_state(struct mesh_subnet *subnet, uint32_t iv_index,
>  			l_info("iv_upd_state = IV_UPD_NORMAL");
>  			net->iv_upd_state = IV_UPD_NORMAL;
>  		}
> -
> -		mesh_config_write_iv_index(node_config_get(net->node), iv_index,
> -							net->iv_upd_state);
> -
> -		/* Figure out the key refresh phase */
> -		if (kr_transition) {
> -			l_debug("Beacon based KR phase change");
> -			if (rxed_key_refresh)
> -				key_refresh_phase_two(net, subnet->idx);
> -			else
> -				key_refresh_finish(net, subnet->idx);
> +	} else if (ivu) {
> +		/* Ignore beacons with IVU if they come too soon */
> +		if (!local_ivu && net->iv_upd_state == IV_UPD_NORMAL_HOLD) {
> +			l_error("Update attempted too soon");
> +			return;
>  		}
>  
> -		if (!lpn)
> -			set_network_beacon(subnet, net);
> -
> -		return;
> -	}
> -
> -	if (iv_update && !iv_is_updating(net)) {
> -		l_info("iv_upd_state = IV_UPD_UPDATING");
> -		net->iv_upd_state = IV_UPD_UPDATING;
> -		net->iv_update_timeout = l_timeout_create(IV_IDX_UPD_MIN,
> -							iv_upd_to, net, NULL);
> -		mesh_config_write_iv_index(node_config_get(net->node), iv_index,
> -							net->iv_upd_state);
> -	} else if (iv_update && iv_index != net->iv_index) {
> -		l_error("Update attempted too soon (iv idx already updated)");
> +		if (!local_ivu) {
> +			l_info("iv_upd_state = IV_UPD_UPDATING");
> +			net->iv_upd_state = IV_UPD_UPDATING;
> +			net->iv_update_timeout = l_timeout_create(
> +					IV_IDX_UPD_MIN, iv_upd_to, net, NULL);
> +		}
> +	} else if (local_ivu) {
> +		l_error("IVU clear attempted too soon");
>  		return;
>  	}
>  
> -	if (iv_index != local_iv_index || kr_transition)
> -		l_info("IVindex 0x%8.8x / Key Refresh update received",
> -								iv_index);
> +	if ((iv_index - ivu) > (local_iv_index - local_ivu))
> +		mesh_net_set_seq_num(net, 0);
>  
> -	if (iv_index > net->iv_index) {
> -		l_queue_clear(net->msg_cache, mesh_msg_free);
> -		net->iv_index = iv_index;
> -		mesh_config_write_iv_index(node_config_get(net->node), iv_index,
> -							net->iv_upd_state);
> -	}
> +	if (ivu != net->iv_update || local_iv_index != net->iv_index) {
> +		struct mesh_config *cfg = node_config_get(net->node);
>  
> -	/* Figure out the key refresh phase */
> -	if (kr_transition) {
> -		if (rxed_key_refresh)
> -			key_refresh_phase_two(net, subnet->idx);
> -		else
> -			key_refresh_finish(net, subnet->idx);
> +		mesh_config_write_iv_index(cfg, iv_index, ivu);
>  	}
>  
> -	if (!lpn)
> -		return;
> -
> -	if (local_kr != subnet->key_refresh ||
> -					local_iv_index != net->iv_index ||
> -					local_iv_update != iv_is_updating(net))
> -		set_network_beacon(subnet, net);
> +	net->iv_index = iv_index;
> +	net->iv_update = ivu;
>  }
>  
> -static void process_beacon(void *user_data, const void *data,
> -						uint8_t size, int8_t rssi)
> +static void process_beacon(void *net_ptr, void *user_data)
>  {
> -	struct mesh_net *net = user_data;
> -	const uint8_t *buf = data;
> -	uint32_t iv_index;
> -	bool iv_update, rxed_iv_update, rxed_key_refresh;
> +	struct mesh_net *net = net_ptr;
> +	const uint8_t *buf = *(uint8_t **)user_data;
> +	uint32_t ivi;
> +	bool ivu, kr, local_kr;
>  	struct mesh_subnet *subnet;
>  	uint32_t key_id;
> -	bool kr_transition = false;
> -
> -	if (size != 22 || buf[0] != 0x01)
> -		return;
> -
> -	/* print_packet("Secure Net Beacon RXed", data, size); */
> -	rxed_key_refresh = (buf[1] & 0x01) == 0x01;
> -	rxed_iv_update = iv_update = (buf[1] & 0x02) == 0x02;
> -	iv_index = l_get_be32(buf + 10);
> -
> -	l_debug("KR: %d -- IVU: %d -- IV: %8.8x",
> -				rxed_key_refresh, rxed_iv_update, iv_index);
>  
> -	/* Inhibit recognizing iv_update true-->false
> -	 * if we have outbound SAR messages in flight
> -	 */
> -	if (l_queue_length(net->sar_out)) {
> -		if (!iv_update && iv_update != iv_is_updating(net))
> -			iv_update = true;
> -	}
> +	ivi = l_get_be32(buf + 10);
>  
> -	key_id = net_key_network_id(buf + 2);
> -	subnet = l_queue_find(net->subnets, match_key_id,
> -						L_UINT_TO_PTR(key_id));
> -	if (!subnet || !key_id)
> +	/* Ignore out-of-range IV_Index for this network */
> +	if ((net->iv_index + IV_IDX_DIFF_RANGE < ivi) || (ivi < net->iv_index))
>  		return;
>  
> -	/* Check if Key Refresh flag value is different from
> -	 * the locally stored one
> -	 */
> -	if (rxed_key_refresh != subnet->key_refresh)
> -		kr_transition = true;
> -
> -	/* If the local node is a provisioner or there are no new keys,
> -	 * ignore KR beacon setting
> -	 */
> -	if (net->provisioner)
> -		kr_transition = false;
> -	else if (!subnet->net_key_upd)
> -		kr_transition = false;
> -	/* If beacon's key refresh bit is not set and the beacon is encoded
> -	 * with the "new" network key, this signals transition from
> -	 * key refresh procedure to normal operation
> -	 */
> -	else if (!rxed_key_refresh && subnet->net_key_upd == key_id)
> -		kr_transition = true;
> -
> -	if ((net->iv_index + IV_IDX_DIFF_RANGE < iv_index) ||
> -						(iv_index < net->iv_index)) {
> -		l_info("iv index outside range");
> -		return;
> -	}
> -
> -	/* Don't bother going further if nothing has changed */
> -	if (!memcmp(&subnet->snb.beacon[1], buf, size)) {
> -		subnet->snb.observed++;
> +	/* Ignore Network IDs unknown to this mesh universe */
> +	key_id = net_key_network_id(buf + 2);
> +	if (!key_id)
>  		return;
> -	}
>  
> -	if (!rxed_key_refresh && !subnet->key_refresh && !kr_transition)
> -		key_id = subnet->net_key_cur;
> -	else if (subnet->net_key_upd)
> -		key_id = subnet->net_key_upd;
> -	else
> +	subnet = l_queue_find(net->subnets, match_key_id,
> +							L_UINT_TO_PTR(key_id));
> +	if (!subnet)
>  		return;
>  
> -	if (!net_key_snb_check(key_id, iv_index, rxed_key_refresh,
> -						rxed_iv_update,
> -						l_get_be64(buf + 14))) {
> -		l_error("mesh_crypto_beacon verify failed");
> -		return;
> -	}
> +	/* Get IVU and KR boolean bits from beacon */
> +	ivu = !!(buf[1] & 0x02);
> +	kr = !!(buf[1] & 0x01);
> +	local_kr = !!(subnet->kr_phase != KEY_REFRESH_PHASE_TWO);
>  
> -	if (iv_index == net->iv_index &&
> -			iv_is_updating(net) == iv_update && !kr_transition) {
> -		l_info("No change: IV index %4.4x, rxed KR = %d ",
> -						iv_index, rxed_key_refresh);
> -		if (net->iv_upd_state == IV_UPD_INIT) {
> -			l_info("iv_upd_state = IV_UPD_NORMAL");
> -			net->iv_upd_state = IV_UPD_NORMAL;
> +	if (net->iv_upd_state != IV_UPD_INIT) {
> +		/* Ignore beacons that indicate *no change* */
> +		if (!memcmp(&subnet->snb.beacon[1], buf, 22)) {
> +			subnet->snb.observed++;
> +			return;
>  		}
> +	}
>  
> -		subnet->snb.observed++;
> +	/* Validate beacon before accepting */
> +	if (!net_key_snb_check(key_id, ivi, kr, ivu, l_get_be64(buf + 14))) {
> +		l_error("mesh_crypto_beacon verify failed");
>  		return;
>  	}
>  
> +	/* We have officially *seen* this beacon now */
>  	subnet->snb.observed++;
>  
> -	update_iv_kr_state(subnet, iv_index, iv_update, kr_transition,
> -						rxed_key_refresh, false);
> +	update_iv_ivu_state(net, ivi, ivu);
> +	update_kr_state(subnet, kr, key_id);
> +
> +	if (ivi != net->iv_index || ivu != net->iv_update || kr != local_kr)
> +		set_network_beacon(subnet, net);
>  }
>  
>  static void lpn_process_beacon(void *user_data, const void *data,
> @@ -2918,87 +2862,50 @@ static void lpn_process_beacon(void *user_data, const void *data,
>  {
>  	struct mesh_net *net = user_data;
>  	const uint8_t *buf = data;
> -	uint32_t iv_index;
> -	bool iv_update, rxed_key_refresh;
> +	uint32_t ivi;
> +	bool ivu, kr, local_kr;
>  	struct mesh_subnet *subnet;
>  	bool kr_transition = false;
>  
>  	/* print_packet("lpn: Secure Net Beacon RXed", data, size); */
> -	rxed_key_refresh = (buf[0] & 0x01) == 0x01;
> -	iv_update = (buf[0] & 0x02) == 0x02;
> -	iv_index = l_get_be32(buf + 1);
> +	kr = !!(buf[0] & 0x01);
> +	ivu = !!(buf[0] & 0x02);
> +	ivi = l_get_be32(buf + 1);
>  
> -	/* Inhibit recognizing iv_update true-->false if we have outbound
> -	 * SAR messages in flight
> -	 */
> -	if (l_queue_length(net->sar_out)) {
> -		if (!iv_update && iv_update != iv_is_updating(net))
> -			iv_update = true;
> -	}
> -
> -	l_debug("KR: %d -- IVU: %d -- IV: %8.8x",
> -				rxed_key_refresh, iv_update, iv_index);
> +	l_debug("KR: %d -- IVU: %d -- IVI: %8.8x", kr, ivu, ivi);
>  
>  	/* TODO: figure out actual network index (i.e., friendship subnet) */
>  	subnet = get_primary_subnet(net);
>  	if (!subnet)
>  		return;
>  
> -	/* Check if Key Refresh flag value is different from
> -	 * the locally stored one
> -	 */
> -	if (rxed_key_refresh != subnet->key_refresh)
> -		kr_transition = true;
> -
> -	/* If the local node is a provisioner or there are no new keys,
> -	 * ignore KR beacon setting
> -	 */
> -	if (!subnet->net_key_upd)
> -		kr_transition = false;
> -
> -	if ((net->iv_index + IV_IDX_DIFF_RANGE < iv_index) ||
> -					(iv_index < net->iv_index)) {
> -		l_info("iv index outside range");
> -		return;
> -	}
> +	local_kr = (subnet->kr_phase == KEY_REFRESH_PHASE_TWO);
>  
>  	/* Don't bother going further if nothing has changed */
> -	if (!kr_transition && iv_index == net->iv_index &&
> -			iv_update == iv_is_updating(net) &&
> -			net->iv_upd_state != IV_UPD_INIT)
> +	if (local_kr == kr && ivi == net->iv_index && ivu == net->iv_update &&
> +					net->iv_upd_state != IV_UPD_INIT)
>  		return;
>  
> -	if (iv_index == net->iv_index &&
> -			iv_is_updating(net) == iv_update && !kr_transition) {
> -		l_info("No change: IV index %4.4x, rxed KR = %d ",
> -						iv_index, rxed_key_refresh);
> -		if (net->iv_upd_state == IV_UPD_INIT) {
> -			l_info("iv_upd_state = IV_UPD_NORMAL");
> -			net->iv_upd_state = IV_UPD_NORMAL;
> -		}
> -		return;
> -	}
> +	update_iv_ivu_state(net, ivi, ivu);
>  
> -	update_iv_kr_state(subnet, iv_index, iv_update, kr_transition,
> -						rxed_key_refresh, true);
> +	if (kr)
> +		update_kr_state(subnet, kr_transition, subnet->net_key_upd);
> +	else
> +		update_kr_state(subnet, kr_transition, subnet->net_key_cur);
>  }
>  
>  static void beacon_recv(void *user_data, struct mesh_io_recv_info *info,
>  					const uint8_t *data, uint16_t len)
>  {
> -	struct mesh_net *net = user_data;
> -	int8_t rssi = 0;
> +	const uint8_t *ptr = data + 1;
>  
> -	if (len <= 2 || !net)
> +	if (len != 23 || data[1] != 0x01)
>  		return;
>  
> -	if (info) {
> -		net->instant = info->instant;
> -		net->chan = info->chan;
> -		rssi = info->rssi;
> -	}
> +	l_debug("KR: %d -- IVU: %d -- IV: %8.8x",
> +			data[2] & 1, !!(data[2] & 2), l_get_be32(data + 11));
>  
> -	process_beacon(user_data, data + 1, len - 1, rssi);
> +	l_queue_foreach(nets, process_beacon, &ptr);
>  }
>  
>  bool mesh_net_set_beacon_mode(struct mesh_net *net, bool enable)
> @@ -3044,7 +2951,7 @@ bool mesh_net_set_key(struct mesh_net *net, uint16_t idx, const uint8_t *key,
>  	if (!subnet)
>  		return false;
>  
> -	if (new_key)
> +	if (new_key && phase)
>  		subnet->net_key_upd = net_key_add(new_key);
>  
>  	/* Preserve key refresh state to generate secure beacon flags*/
> @@ -3085,7 +2992,7 @@ bool mesh_net_attach(struct mesh_net *net, struct mesh_io *io)
>  
>  		l_info("Register io cb");
>  		mesh_io_register_recv_cb(io, MESH_IO_FILTER_BEACON,
> -							beacon_recv, net);
> +							beacon_recv, NULL);
>  		mesh_io_register_recv_cb(io, MESH_IO_FILTER_NET,
>  							net_msg_recv, NULL);
>  		l_queue_foreach(net->subnets, start_network_beacon, net);
> @@ -3128,12 +3035,13 @@ bool mesh_net_iv_index_update(struct mesh_net *net)
>  
>  	l_info("iv_upd_state = IV_UPD_UPDATING");
>  	mesh_net_flush_msg_queues(net);
> -	net->iv_upd_state = IV_UPD_UPDATING;
> -	net->iv_index++;
>  	if (!mesh_config_write_iv_index(node_config_get(net->node),
> -					net->iv_index, IV_UPD_UPDATING))
> +						net->iv_index + 1, true))
>  		return false;
>  
> +	net->iv_upd_state = IV_UPD_UPDATING;
> +	net->iv_index++;
> +	net->iv_update = true;
>  	l_queue_foreach(net->subnets, set_network_beacon, net);
>  	net->iv_update_timeout = l_timeout_create(
>  			IV_IDX_UPD_MIN,




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux