2019-02-07 03:55:40

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 0/5 v2] mesh: Save/restore network keys

Rev.2: addressed Brina's comments.

This set of patches fixes the network key add/update processing.
Network keys need to be saved to a local node configuration file
when:
- a new node is provisioned
- new network key are added by a configuration client
- existing network key is updated by a configuration client
during key refresh procedure.

Also, each saved network key is accompanied by a proper key
refresh phase setting.

Inga Stotland (5):
mesh: Separate functions for net key add and update
mesh: Add function to restore net key state from storage
mesh: Declare internal functions as static
mesh: Save key refresh phase state to node config file
mesh: Save newly added or updated net key to config file

mesh/cfgmod-server.c | 8 +-
mesh/mesh-db.c | 178 +++++++++++++++++-----------
mesh/mesh-db.h | 6 +-
mesh/net.c | 268 +++++++++++++++++++++++++++----------------
mesh/net.h | 12 +-
mesh/node.c | 19 ++-
mesh/storage.c | 22 ++--
mesh/storage.h | 7 +-
8 files changed, 326 insertions(+), 194 deletions(-)

--
2.17.2



2019-02-07 03:55:41

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 1/5 v2] mesh: Separate functions for net key add and update

This splits mesh_net_key_add() into two separate functions:
mesh_net_key_add() and mesh_net_key_update().
mesh_net_key_update() essentially replaces mesh_net_kr_phase_one()
since switching to Key Refresh phase one can only be triggered
by successful network key update.
---
mesh/cfgmod-server.c | 8 ++++++--
mesh/net.c | 27 +++++++++++----------------
mesh/net.h | 8 ++++----
mesh/node.c | 4 ++--
mesh/storage.c | 2 +-
5 files changed, 24 insertions(+), 25 deletions(-)

diff --git a/mesh/cfgmod-server.c b/mesh/cfgmod-server.c
index 062bdaaf2..899bdde2e 100644
--- a/mesh/cfgmod-server.c
+++ b/mesh/cfgmod-server.c
@@ -981,8 +981,12 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
if (size != 18)
return true;

- b_res = mesh_net_add_key(net, opcode == OP_NETKEY_UPDATE,
- l_get_le16(pkt), pkt + 2);
+ net_idx = l_get_le16(pkt);
+
+ if (opcode == OP_NETKEY_ADD)
+ b_res = mesh_net_add_key(net, net_idx, pkt + 2);
+ else
+ b_res = mesh_net_update_key(net, net_idx, pkt + 2);

l_debug("NetKey Add/Update %s",
(b_res == MESH_STATUS_SUCCESS) ? "success" : "fail");
diff --git a/mesh/net.c b/mesh/net.c
index 9e509a8ea..91823c724 100644
--- a/mesh/net.c
+++ b/mesh/net.c
@@ -970,27 +970,13 @@ int mesh_net_del_key(struct mesh_net *net, uint16_t idx)
return MESH_STATUS_SUCCESS;
}

-int mesh_net_add_key(struct mesh_net *net, bool update, uint16_t idx,
- const void *value)
+int mesh_net_add_key(struct mesh_net *net, uint16_t idx, const uint8_t *value)
{
- int status;
struct mesh_subnet *subnet;

subnet = l_queue_find(net->subnets, match_key_index,
L_UINT_TO_PTR(idx));

- if (update) {
- if (subnet && subnet->kr_phase == KEY_REFRESH_PHASE_NONE) {
- l_info("Start key refresh");
- status = mesh_net_kr_phase_one(net, idx, value);
- if (status == MESH_STATUS_SUCCESS &&
- !storage_net_key_add(net, idx,
- value, KEY_REFRESH_PHASE_ONE))
- return MESH_STATUS_STORAGE_FAIL;
- } else
- return MESH_STATUS_CANNOT_UPDATE;
- }
-
if (subnet) {
if (net_key_confirm(subnet->net_key_cur, value))
return MESH_STATUS_SUCCESS;
@@ -3570,7 +3556,7 @@ uint8_t mesh_net_key_refresh_phase_get(struct mesh_net *net, uint16_t idx,
return MESH_STATUS_SUCCESS;
}

-int mesh_net_kr_phase_one(struct mesh_net *net, uint16_t idx,
+int mesh_net_update_key(struct mesh_net *net, uint16_t idx,
const uint8_t *value)
{
struct mesh_subnet *subnet;
@@ -3580,9 +3566,15 @@ int mesh_net_kr_phase_one(struct mesh_net *net, uint16_t idx,

subnet = l_queue_find(net->subnets, match_key_index,
L_UINT_TO_PTR(idx));
+
if (!subnet)
return MESH_STATUS_CANNOT_UPDATE;

+ /* Check if the key has been already successfully updated */
+ if (subnet->kr_phase == KEY_REFRESH_PHASE_ONE &&
+ net_key_confirm(subnet->net_key_upd, value))
+ return MESH_STATUS_SUCCESS;
+
if (subnet->net_key_upd) {
net_key_unref(subnet->net_key_upd);
l_info("Warning: overwriting new keys");
@@ -3606,6 +3598,9 @@ int mesh_net_kr_phase_one(struct mesh_net *net, uint16_t idx,

l_info("key refresh phase 1: Key ID %d", subnet->net_key_upd);

+ if (!storage_net_key_add(net, idx, value, KEY_REFRESH_PHASE_ONE))
+ return MESH_STATUS_STORAGE_FAIL;
+
subnet->kr_phase = KEY_REFRESH_PHASE_ONE;

return MESH_STATUS_SUCCESS;
diff --git a/mesh/net.h b/mesh/net.h
index 0ef01b63e..b27a4e614 100644
--- a/mesh/net.h
+++ b/mesh/net.h
@@ -280,8 +280,10 @@ bool mesh_net_set_relay_mode(struct mesh_net *net, bool enable, uint8_t cnt,
uint8_t interval);
bool mesh_net_set_friend_mode(struct mesh_net *net, bool enable);
int mesh_net_del_key(struct mesh_net *net, uint16_t net_idx);
-int mesh_net_add_key(struct mesh_net *net, bool update,
- uint16_t net_idx, const void *key);
+int mesh_net_add_key(struct mesh_net *net, uint16_t net_idx,
+ const uint8_t *key);
+int mesh_net_update_key(struct mesh_net *net, uint16_t net_idx,
+ const uint8_t *key);
uint32_t mesh_net_get_iv_index(struct mesh_net *net);
void mesh_net_get_snb_state(struct mesh_net *net,
uint8_t *flags, uint32_t *iv_index);
@@ -335,8 +337,6 @@ uint8_t mesh_net_key_refresh_phase_set(struct mesh_net *net, uint16_t net_idx,
uint8_t transition);
uint8_t mesh_net_key_refresh_phase_get(struct mesh_net *net, uint16_t net_idx,
uint8_t *phase);
-int mesh_net_kr_phase_one(struct mesh_net *net, uint16_t net_idx,
- const uint8_t *key);
int mesh_net_key_refresh_phase_two(struct mesh_net *net, uint16_t net_idx);
int mesh_net_key_refresh_finish(struct mesh_net *net, uint16_t net_idx);
void mesh_net_send_seg(struct mesh_net *net, uint32_t key_id,
diff --git a/mesh/node.c b/mesh/node.c
index e921b72b7..1845f9a32 100644
--- a/mesh/node.c
+++ b/mesh/node.c
@@ -1726,8 +1726,8 @@ bool node_add_pending_local(struct mesh_node *node, void *prov_node_info,
if (!mesh_db_write_device_key(node->jconfig, info->device_key))
return false;

- if (mesh_net_add_key(node->net, kr, info->net_index,
- info->net_key) != MESH_STATUS_SUCCESS)
+ if (mesh_net_add_key(node->net, info->net_index, info->net_key) !=
+ MESH_STATUS_SUCCESS)
return false;

if (!storage_net_key_add(node->net, info->net_index, info->net_key,
diff --git a/mesh/storage.c b/mesh/storage.c
index 3a6614eb2..1b52000b0 100644
--- a/mesh/storage.c
+++ b/mesh/storage.c
@@ -120,7 +120,7 @@ static bool read_net_keys_cb(uint16_t idx, uint8_t *key, uint8_t *new_key,
if (!net)
return false;

- if (mesh_net_add_key(net, false, idx, key) != MESH_STATUS_SUCCESS)
+ if (mesh_net_add_key(net, idx, key) != MESH_STATUS_SUCCESS)
return false;
/* TODO: handle restoring key refresh phase and new keys */

--
2.17.2


2019-02-07 03:55:43

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 2/5 v2] mesh: Add function to restore net key state from storage

This creates subnet state based on saved network key state:
current keys and, if present, updated keys.
Secure network beacon is generated according to key refresh phase.
---
mesh/net.c | 90 ++++++++++++++++++++++++++++++++++++++++++++------
mesh/net.h | 2 ++
mesh/storage.c | 6 +---
3 files changed, 82 insertions(+), 16 deletions(-)

diff --git a/mesh/net.c b/mesh/net.c
index 91823c724..8cd547663 100644
--- a/mesh/net.c
+++ b/mesh/net.c
@@ -970,20 +970,10 @@ int mesh_net_del_key(struct mesh_net *net, uint16_t idx)
return MESH_STATUS_SUCCESS;
}

-int mesh_net_add_key(struct mesh_net *net, uint16_t idx, const uint8_t *value)
+static int add_key(struct mesh_net *net, uint16_t idx, const uint8_t *value)
{
struct mesh_subnet *subnet;

- subnet = l_queue_find(net->subnets, match_key_index,
- L_UINT_TO_PTR(idx));
-
- if (subnet) {
- if (net_key_confirm(subnet->net_key_cur, value))
- return MESH_STATUS_SUCCESS;
- else
- return MESH_STATUS_IDX_ALREADY_STORED;
- }
-
subnet = subnet_new(net, idx);
if (!subnet)
return MESH_STATUS_INSUFF_RESOURCES;
@@ -1000,6 +990,32 @@ int mesh_net_add_key(struct mesh_net *net, uint16_t idx, const uint8_t *value)
return MESH_STATUS_INSUFF_RESOURCES;
}

+ return MESH_STATUS_SUCCESS;
+}
+
+/*
+ * This function is called when Configuration Server Model receives
+ * a NETKEY_ADD command
+ */
+int mesh_net_add_key(struct mesh_net *net, uint16_t idx, const uint8_t *value)
+{
+ struct mesh_subnet *subnet;
+ int status;
+
+ subnet = l_queue_find(net->subnets, match_key_index,
+ L_UINT_TO_PTR(idx));
+
+ if (subnet) {
+ if (net_key_confirm(subnet->net_key_cur, value))
+ return MESH_STATUS_SUCCESS;
+ else
+ return MESH_STATUS_IDX_ALREADY_STORED;
+ }
+
+ status = add_key(net, idx, value);
+ if (status != MESH_STATUS_SUCCESS)
+ return status;
+
if (!storage_net_key_add(net, idx, value,
KEY_REFRESH_PHASE_NONE)) {
l_queue_remove(net->subnets, subnet);
@@ -2923,6 +2939,54 @@ bool mesh_net_set_beacon_mode(struct mesh_net *net, bool enable)
return true;
}

+/* This function is called when network keys are restored from storage. */
+bool mesh_net_set_key(struct mesh_net *net, uint16_t idx, const uint8_t *key,
+ const uint8_t *new_key, uint8_t phase)
+{
+ struct mesh_subnet *subnet;
+ int status;
+
+ subnet = l_queue_find(net->subnets, match_key_index,
+ L_UINT_TO_PTR(idx));
+ if (subnet)
+ return false;
+
+ /* Current key must be always present */
+ if (!key)
+ return false;
+
+ /* If key refresh is in progress, a new key must be present */
+ if (phase != KEY_REFRESH_PHASE_NONE && !new_key)
+ return false;
+
+ status = add_key(net, idx, key);
+ if (status != MESH_STATUS_SUCCESS)
+ return false;
+
+ subnet = l_queue_find(net->subnets, match_key_index,
+ L_UINT_TO_PTR(idx));
+ if (!subnet)
+ return false;
+
+ if (new_key)
+ subnet->net_key_upd = net_key_add(new_key);
+
+ /* Preserve key refresh state to generate secure beacon flags*/
+ if (phase == KEY_REFRESH_PHASE_TWO) {
+ subnet->key_refresh = 1;
+ subnet->net_key_tx = subnet->net_key_upd;
+ }
+
+ subnet->kr_phase = phase;
+
+ set_network_beacon(subnet, net);
+
+ if (net->io)
+ start_network_beacon(subnet, net);
+
+ return true;
+}
+
static bool is_this_net(const void *a, const void *b)
{
return a == b;
@@ -3556,6 +3620,10 @@ uint8_t mesh_net_key_refresh_phase_get(struct mesh_net *net, uint16_t idx,
return MESH_STATUS_SUCCESS;
}

+/*
+ * This function is called when Configuration Server Model receives
+ * a NETKEY_UPDATE command
+ */
int mesh_net_update_key(struct mesh_net *net, uint16_t idx,
const uint8_t *value)
{
diff --git a/mesh/net.h b/mesh/net.h
index b27a4e614..591a6898e 100644
--- a/mesh/net.h
+++ b/mesh/net.h
@@ -284,6 +284,8 @@ int mesh_net_add_key(struct mesh_net *net, uint16_t net_idx,
const uint8_t *key);
int mesh_net_update_key(struct mesh_net *net, uint16_t net_idx,
const uint8_t *key);
+bool mesh_net_set_key(struct mesh_net *net, uint16_t idx, const uint8_t *key,
+ const uint8_t *new_key, uint8_t phase);
uint32_t mesh_net_get_iv_index(struct mesh_net *net);
void mesh_net_get_snb_state(struct mesh_net *net,
uint8_t *flags, uint32_t *iv_index);
diff --git a/mesh/storage.c b/mesh/storage.c
index 1b52000b0..84f7c6161 100644
--- a/mesh/storage.c
+++ b/mesh/storage.c
@@ -120,11 +120,7 @@ static bool read_net_keys_cb(uint16_t idx, uint8_t *key, uint8_t *new_key,
if (!net)
return false;

- if (mesh_net_add_key(net, idx, key) != MESH_STATUS_SUCCESS)
- return false;
- /* TODO: handle restoring key refresh phase and new keys */
-
- return true;
+ return mesh_net_set_key(net, idx, key, new_key, phase);
}

static bool read_app_keys_cb(uint16_t net_idx, uint16_t app_idx, uint8_t *key,
--
2.17.2


2019-02-07 03:55:47

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 3/5 v2] mesh: Declare internal functions as static

This renames mesh_net_key_refresh_finish() to key_refresh_finish() and
mesh_net_key_phase_two() to key_refresh_phase_wo() and changes the
function declaration to static since they are called only within net.c
---
mesh/net.c | 146 ++++++++++++++++++++++++++---------------------------
mesh/net.h | 2 -
2 files changed, 73 insertions(+), 75 deletions(-)

diff --git a/mesh/net.c b/mesh/net.c
index 8cd547663..1be722181 100644
--- a/mesh/net.c
+++ b/mesh/net.c
@@ -1016,8 +1016,7 @@ int mesh_net_add_key(struct mesh_net *net, uint16_t idx, const uint8_t *value)
if (status != MESH_STATUS_SUCCESS)
return status;

- if (!storage_net_key_add(net, idx, value,
- KEY_REFRESH_PHASE_NONE)) {
+ if (!storage_net_key_add(net, idx, value, KEY_REFRESH_PHASE_NONE)) {
l_queue_remove(net->subnets, subnet);
subnet_free(subnet);
return MESH_STATUS_STORAGE_FAIL;
@@ -2629,6 +2628,70 @@ static void iv_upd_to(struct l_timeout *upd_timeout, void *user_data)
}
}

+
+static int key_refresh_phase_two(struct mesh_net *net, uint16_t idx)
+{
+ struct mesh_subnet *subnet;
+
+ if (!net)
+ return MESH_STATUS_UNSPECIFIED_ERROR;
+
+ subnet = l_queue_find(net->subnets, match_key_index,
+ L_UINT_TO_PTR(idx));
+
+ if (!subnet || !subnet->net_key_upd)
+ return MESH_STATUS_INVALID_NETKEY;
+
+ l_info("Key refresh procedure phase 2: start using new net TX keys");
+ subnet->key_refresh = 1;
+ subnet->net_key_tx = subnet->net_key_upd;
+ /* TODO: Provisioner may need to stay in phase three until
+ * it hears beacons from all the nodes
+ */
+ subnet->kr_phase = KEY_REFRESH_PHASE_TWO;
+ set_network_beacon(subnet, net);
+
+ if (net->friend_addr)
+ frnd_key_refresh(net, 2);
+ else
+ l_queue_foreach(net->friends, frnd_kr_phase2, net);
+
+ return MESH_STATUS_SUCCESS;
+}
+
+static int key_refresh_finish(struct mesh_net *net, uint16_t idx)
+{
+ struct mesh_subnet *subnet;
+
+ if (!net)
+ return MESH_STATUS_UNSPECIFIED_ERROR;
+
+ subnet = l_queue_find(net->subnets, match_key_index,
+ L_UINT_TO_PTR(idx));
+ if (!subnet || !subnet->net_key_upd)
+ return MESH_STATUS_INVALID_NETKEY;
+
+ if (subnet->kr_phase == KEY_REFRESH_PHASE_NONE)
+ return MESH_STATUS_SUCCESS;
+
+ l_info("Key refresh phase 3: use new keys only, discard old ones");
+
+ /* Switch to using new keys, discard old ones */
+ net_key_unref(subnet->net_key_cur);
+ subnet->net_key_tx = subnet->net_key_cur = subnet->net_key_upd;
+ subnet->net_key_upd = 0;
+ subnet->key_refresh = 0;
+ subnet->kr_phase = KEY_REFRESH_PHASE_NONE;
+ set_network_beacon(subnet, net);
+
+ if (net->friend_addr)
+ frnd_key_refresh(net, 3);
+ else
+ l_queue_foreach(net->friends, frnd_kr_phase3, net);
+
+ 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)
@@ -2680,11 +2743,11 @@ static void update_iv_kr_state(struct mesh_subnet *subnet, uint32_t iv_index,

/* Figure out the key refresh phase */
if (kr_transition) {
+ l_debug("Beacon based KR phase change");
if (rxed_key_refresh)
- mesh_net_key_refresh_phase_two(net,
- subnet->idx);
+ key_refresh_phase_two(net, subnet->idx);
else
- mesh_net_key_refresh_finish(net, subnet->idx);
+ key_refresh_finish(net, subnet->idx);
}

if (!lpn)
@@ -2717,9 +2780,9 @@ static void update_iv_kr_state(struct mesh_subnet *subnet, uint32_t iv_index,
/* Figure out the key refresh phase */
if (kr_transition) {
if (rxed_key_refresh)
- mesh_net_key_refresh_phase_two(net, subnet->idx);
+ key_refresh_phase_two(net, subnet->idx);
else
- mesh_net_key_refresh_finish(net, subnet->idx);
+ key_refresh_finish(net, subnet->idx);
}

if (!lpn)
@@ -3588,18 +3651,19 @@ uint8_t mesh_net_key_refresh_phase_set(struct mesh_net *net, uint16_t idx,

switch (transition) {
case 2:
- if (mesh_net_key_refresh_phase_two(net, idx)
+ if (key_refresh_phase_two(net, idx)
!= MESH_STATUS_SUCCESS)
return MESH_STATUS_CANNOT_SET;
break;
case 3:
- if (mesh_net_key_refresh_finish(net, idx)
+ if (key_refresh_finish(net, idx)
!= MESH_STATUS_SUCCESS)
return MESH_STATUS_CANNOT_SET;
break;
default:
return MESH_STATUS_CANNOT_SET;
}
+
return MESH_STATUS_SUCCESS;
}

@@ -3674,70 +3738,6 @@ int mesh_net_update_key(struct mesh_net *net, uint16_t idx,
return MESH_STATUS_SUCCESS;
}

-int mesh_net_key_refresh_phase_two(struct mesh_net *net, uint16_t idx)
-{
- struct mesh_subnet *subnet;
-
- if (!net)
- return MESH_STATUS_UNSPECIFIED_ERROR;
-
- subnet = l_queue_find(net->subnets, match_key_index,
- L_UINT_TO_PTR(idx));
-
- if (!subnet || !subnet->net_key_upd)
- return MESH_STATUS_INVALID_NETKEY;
-
- l_info("Key refresh procedure phase 2: start using new net TX keys");
- subnet->key_refresh = 1;
- subnet->net_key_tx = subnet->net_key_upd;
- /* TODO: Provisioner may need to stay in phase three until
- * it hears beacons from all the nodes
- */
- subnet->kr_phase = KEY_REFRESH_PHASE_TWO;
- set_network_beacon(subnet, net);
-
- if (net->friend_addr)
- frnd_key_refresh(net, 2);
- else
- l_queue_foreach(net->friends, frnd_kr_phase2, net);
-
- return MESH_STATUS_SUCCESS;
-}
-
-int mesh_net_key_refresh_finish(struct mesh_net *net, uint16_t idx)
-{
- struct mesh_subnet *subnet;
-
- if (!net)
- return MESH_STATUS_UNSPECIFIED_ERROR;
-
- subnet = l_queue_find(net->subnets, match_key_index,
- L_UINT_TO_PTR(idx));
-
- if (!subnet || !subnet->net_key_upd)
- return MESH_STATUS_INVALID_NETKEY;
-
- if (subnet->kr_phase == KEY_REFRESH_PHASE_NONE)
- return MESH_STATUS_SUCCESS;
-
- l_info("Key refresh phase 3: use new keys only, discard old ones");
-
- /* Switch to using new keys, discard old ones */
- net_key_unref(subnet->net_key_cur);
- subnet->net_key_tx = subnet->net_key_cur = subnet->net_key_upd;
- subnet->net_key_upd = 0;
- subnet->key_refresh = 0;
- subnet->kr_phase = KEY_REFRESH_PHASE_NONE;
- set_network_beacon(subnet, net);
-
- if (net->friend_addr)
- frnd_key_refresh(net, 3);
- else
- l_queue_foreach(net->friends, frnd_kr_phase3, net);
-
- return MESH_STATUS_SUCCESS;
-}
-
uint16_t mesh_net_get_features(struct mesh_net *net)
{
uint16_t features = 0;
diff --git a/mesh/net.h b/mesh/net.h
index 591a6898e..e040e19fa 100644
--- a/mesh/net.h
+++ b/mesh/net.h
@@ -339,8 +339,6 @@ uint8_t mesh_net_key_refresh_phase_set(struct mesh_net *net, uint16_t net_idx,
uint8_t transition);
uint8_t mesh_net_key_refresh_phase_get(struct mesh_net *net, uint16_t net_idx,
uint8_t *phase);
-int mesh_net_key_refresh_phase_two(struct mesh_net *net, uint16_t net_idx);
-int mesh_net_key_refresh_finish(struct mesh_net *net, uint16_t net_idx);
void mesh_net_send_seg(struct mesh_net *net, uint32_t key_id,
uint32_t iv_index, uint8_t ttl, uint32_t seq,
uint16_t src, uint16_t dst, uint32_t hdr,
--
2.17.2


2019-02-07 03:55:49

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 4/5 v2] mesh: Save key refresh phase state to node config file

This adds implementation for saving the key refresh phase to
a node configuration file in JSON format. When the key refresh
procedure is finished, the old network keys are remove from the
configuration file.
---
mesh/mesh-db.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++
mesh/mesh-db.h | 2 +-
mesh/net.c | 4 ++++
mesh/storage.c | 9 ++++++++
mesh/storage.h | 2 ++
5 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/mesh/mesh-db.c b/mesh/mesh-db.c
index 5c0b72551..b9bbef912 100644
--- a/mesh/mesh-db.c
+++ b/mesh/mesh-db.c
@@ -1491,3 +1491,59 @@ bool mesh_db_add_node(json_object *jnode, struct mesh_db_node *node) {

return true;
}
+
+static void finish_key_refresh(json_object *jobj, uint16_t net_idx)
+{
+ json_object *jarray;
+ int i, len;
+
+ /* Clean up all the bound appkeys */
+ json_object_object_get_ex(jobj, "appKeys", &jarray);
+ if (!jarray)
+ return;
+
+ len = json_object_array_length(jarray);
+
+ for (i = 0; i < len; ++i) {
+ json_object *jentry;
+ uint16_t idx;
+
+ jentry = json_object_array_get_idx(jarray, i);
+
+ if (!get_key_index(jentry, "boundNetKey", &idx))
+ continue;
+
+ if (idx != net_idx)
+ continue;
+
+ json_object_object_del(jentry, "oldKey");
+
+ if (!get_key_index(jentry, "index", &idx))
+ continue;
+ }
+
+}
+
+bool mesh_db_net_key_set_phase(json_object *jobj, uint16_t idx, uint8_t phase)
+{
+ json_object *jarray, *jentry = NULL;
+
+ json_object_object_get_ex(jobj, "netKeys", &jarray);
+
+ if (jarray)
+ jentry = get_key_object(jarray, idx);
+
+ if (!jentry)
+ return false;
+
+ json_object_object_del(jentry, "keyRefresh");
+ json_object_object_add(jentry, "keyRefresh",
+ json_object_new_int(phase));
+
+ if (phase == KEY_REFRESH_PHASE_NONE) {
+ json_object_object_del(jentry, "oldKey");
+ finish_key_refresh(jobj, idx);
+ }
+
+ return true;
+}
diff --git a/mesh/mesh-db.h b/mesh/mesh-db.h
index 40e60f72d..db7ea6045 100644
--- a/mesh/mesh-db.h
+++ b/mesh/mesh-db.h
@@ -135,7 +135,7 @@ bool mesh_db_app_key_del(json_object *jobj, uint16_t net_idx, uint16_t idx);
bool mesh_db_net_key_add(json_object *jobj, uint16_t net_idx,
const uint8_t key[16], int phase);
bool mesh_db_net_key_del(json_object *jobj, uint16_t net_idx);
-bool mesh_db_write_kr_phase(json_object *jobj, uint16_t net_idx, int phase);
+bool mesh_db_net_key_set_phase(json_object *jobj, uint16_t idx, uint8_t phase);
bool mesh_db_write_address(json_object *jobj, uint16_t address);
bool mesh_db_write_iv_index(json_object *jobj, uint32_t idx, bool update);
void mesh_db_remove_property(json_object *jobj, const char *desc);
diff --git a/mesh/net.c b/mesh/net.c
index 1be722181..3229d20d4 100644
--- a/mesh/net.c
+++ b/mesh/net.c
@@ -2656,6 +2656,8 @@ static int key_refresh_phase_two(struct mesh_net *net, uint16_t idx)
else
l_queue_foreach(net->friends, frnd_kr_phase2, net);

+ storage_set_key_refresh_phase(net, idx, KEY_REFRESH_PHASE_TWO);
+
return MESH_STATUS_SUCCESS;
}

@@ -2689,6 +2691,8 @@ static int key_refresh_finish(struct mesh_net *net, uint16_t idx)
else
l_queue_foreach(net->friends, frnd_kr_phase3, net);

+ storage_set_key_refresh_phase(net, idx, KEY_REFRESH_PHASE_NONE);
+
return MESH_STATUS_SUCCESS;
}

diff --git a/mesh/storage.c b/mesh/storage.c
index 84f7c6161..e1d86960a 100644
--- a/mesh/storage.c
+++ b/mesh/storage.c
@@ -321,6 +321,15 @@ bool storage_set_iv_index(struct mesh_net *net, uint32_t iv_index,
return mesh_db_write_iv_index(jnode, iv_index, update);
}

+bool storage_set_key_refresh_phase(struct mesh_net *net, uint16_t net_idx,
+ uint8_t phase)
+{
+ struct mesh_node *node = mesh_net_node_get(net);
+ json_object *jnode = node_jconfig_get(node);
+
+ return mesh_db_net_key_set_phase(jnode, net_idx, phase);
+}
+
bool storage_write_sequence_number(struct mesh_net *net, uint32_t seq)
{
struct mesh_node *node = mesh_net_node_get(net);
diff --git a/mesh/storage.h b/mesh/storage.h
index 91299f0a8..7dad2762e 100644
--- a/mesh/storage.h
+++ b/mesh/storage.h
@@ -47,3 +47,5 @@ bool storage_set_iv_index(struct mesh_net *net, uint32_t iv_index,
bool update);
bool storage_set_device_key(struct mesh_node *node, uint8_t dev_key[16]);
bool storage_set_unicast(struct mesh_node *node, uint16_t unicast);
+bool storage_set_key_refresh_phase(struct mesh_net *net, uint16_t net_idx,
+ uint8_t phase);
--
2.17.2


2019-02-07 04:01:53

by Stotland, Inga

[permalink] [raw]
Subject: [PATCH BlueZ 5/5 v2] mesh: Save newly added or updated net key to config file

This separates mesh_db_net_key_add() into distinct functions:
mesh_db_net_key_add() and mesh_db_net_key_update() which will be called
based on whether a network key was newly added or updated.
---
mesh/mesh-db.c | 122 +++++++++++++++++++++----------------------------
mesh/mesh-db.h | 4 +-
mesh/net.c | 9 ++--
mesh/node.c | 15 ++++--
mesh/storage.c | 7 ++-
mesh/storage.h | 5 +-
6 files changed, 80 insertions(+), 82 deletions(-)

diff --git a/mesh/mesh-db.c b/mesh/mesh-db.c
index b9bbef912..6486f7cff 100644
--- a/mesh/mesh-db.c
+++ b/mesh/mesh-db.c
@@ -51,7 +51,7 @@ static bool get_int(json_object *jobj, const char *keyword, int *value)
return true;
}

-static bool add_key(json_object *jobject, const char *desc,
+static bool add_key_value(json_object *jobject, const char *desc,
const uint8_t key[16])
{
json_object *jstring;
@@ -382,7 +382,7 @@ bool mesh_db_read_net_keys(json_object *jobj, mesh_db_net_key_cb cb,
}

bool mesh_db_net_key_add(json_object *jobj, uint16_t idx,
- const uint8_t key[16], int phase)
+ const uint8_t key[16])
{
json_object *jarray, *jentry = NULL, *jstring;
char buf[5];
@@ -392,91 +392,75 @@ bool mesh_db_net_key_add(json_object *jobj, uint16_t idx,
if (jarray)
jentry = get_key_object(jarray, idx);

- if (jentry) {
- uint8_t buf[16];
- json_object *jvalue;
- char *str;
-
- json_object_object_get_ex(jentry, "key", &jvalue);
- if (!jvalue)
- return false;
-
- str = (char *)json_object_get_string(jvalue);
- if (!str2hex(str, strlen(str), buf, sizeof(buf)))
- return false;
-
- /* If the same key, return success */
- if (memcmp(key, buf, 16) == 0)
- return true;
+ /* Do not allow direct overwrite */
+ if (jentry)
+ return false;

+ jentry = json_object_new_object();
+ if (!jentry)
return false;
- }

- if (!jentry) {
- jentry = json_object_new_object();
- if (!jentry)
- goto fail;
+ snprintf(buf, 5, "%4.4x", idx);
+ jstring = json_object_new_string(buf);
+ if (!jstring)
+ goto fail;

- snprintf(buf, 5, "%4.4x", idx);
- jstring = json_object_new_string(buf);
- if (!jstring)
- goto fail;
+ json_object_object_add(jentry, "index", jstring);

- json_object_object_add(jentry, "index", jstring);
+ if (!add_key_value(jentry, "key", key))
+ goto fail;

- snprintf(buf, 5, "%4.4x", idx);
- jstring = json_object_new_string(buf);
- if (!jstring)
- goto fail;
+ json_object_object_add(jentry, "keyRefresh",
+ json_object_new_int(KEY_REFRESH_PHASE_NONE));

- if (!add_key(jentry, "key", key))
+ if (!jarray) {
+ jarray = json_object_new_array();
+ if (!jarray)
goto fail;
+ json_object_object_add(jobj, "netKeys", jarray);
+ }

- /* If Key Refresh underway, add placeholder for "Old Key" */
- if (phase != KEY_REFRESH_PHASE_NONE) {
- uint8_t buf[16];
- uint8_t i;
+ json_object_array_add(jarray, jentry);

- /* Flip Bits to differentiate */
- for (i = 0; i < sizeof(buf); i++)
- buf[i] = key[i] ^ 0xff;
+ return true;
+fail:
+ if (jentry)
+ json_object_put(jentry);

- if (!add_key(jentry, "oldKey", buf))
- goto fail;
- }
+ return false;
+}

- if (!jarray) {
- jarray = json_object_new_array();
- if (!jarray)
- goto fail;
- json_object_object_add(jobj, "netKeys", jarray);
- }
+bool mesh_db_net_key_update(json_object *jobj, uint16_t idx,
+ const uint8_t key[16])
+{
+ json_object *jarray, *jentry, *jstring;
+ const char *str;

- json_object_array_add(jarray, jentry);
+ json_object_object_get_ex(jobj, "netKeys", &jarray);

- } else {
+ if (!jarray)
+ return false;

- if (!json_object_object_get_ex(jentry, "key", &jstring))
- return false;
+ jentry = get_key_object(jarray, idx);
+ /* Net key must be already recorded */
+ if (!jentry)
+ return false;

- json_object_object_add(jentry, "oldKey", jstring);
- json_object_object_del(jentry, "key");
+ if (!json_object_object_get_ex(jentry, "key", &jstring))
+ return false;

- if (!add_key(jentry, "key", key))
- return false;
- }
+ str = json_object_get_string(jstring);
+ jstring = json_object_new_string(str);
+ json_object_object_add(jentry, "oldKey", jstring);
+ json_object_object_del(jentry, "key");

+ if (!add_key_value(jentry, "key", key))
+ return false;

json_object_object_add(jentry, "keyRefresh",
- json_object_new_int(phase));
+ json_object_new_int(KEY_REFRESH_PHASE_ONE));

return true;
-fail:
-
- if (jentry)
- json_object_put(jentry);
-
- return false;
}

bool mesh_db_net_key_del(json_object *jobj, uint16_t idx)
@@ -513,7 +497,7 @@ bool mesh_db_net_key_del(json_object *jobj, uint16_t idx)

bool mesh_db_write_device_key(json_object *jnode, uint8_t *key)
{
- return add_key(jnode, "deviceKey", key);
+ return add_key_value(jnode, "deviceKey", key);
}

bool mesh_db_app_key_add(json_object *jobj, uint16_t net_idx, uint16_t app_idx,
@@ -572,7 +556,7 @@ bool mesh_db_app_key_add(json_object *jobj, uint16_t net_idx, uint16_t app_idx,

json_object_object_add(jentry, "boundNetKey", jstring);

- if (!add_key(jentry, "key", key))
+ if (!add_key_value(jentry, "key", key))
goto fail;

if (!jarray) {
@@ -592,7 +576,7 @@ bool mesh_db_app_key_add(json_object *jobj, uint16_t net_idx, uint16_t app_idx,
json_object_object_add(jentry, "oldKey", jstring);
json_object_object_del(jentry, "key");

- if (!add_key(jentry, "key", key))
+ if (!add_key_value(jentry, "key", key))
return false;
}

@@ -1421,7 +1405,7 @@ bool mesh_db_add_node(json_object *jnode, struct mesh_db_node *node) {
return false;

/* Device UUID */
- if (!add_key(jnode, "UUID", node->uuid))
+ if (!add_key_value(jnode, "UUID", node->uuid))
return false;

/* Features: relay, LPN, friend, proxy*/
diff --git a/mesh/mesh-db.h b/mesh/mesh-db.h
index db7ea6045..513ad3861 100644
--- a/mesh/mesh-db.h
+++ b/mesh/mesh-db.h
@@ -133,7 +133,9 @@ bool mesh_db_app_key_add(json_object *jnode, uint16_t net_idx, uint16_t app_idx,
const uint8_t key[16], bool update);
bool mesh_db_app_key_del(json_object *jobj, uint16_t net_idx, uint16_t idx);
bool mesh_db_net_key_add(json_object *jobj, uint16_t net_idx,
- const uint8_t key[16], int phase);
+ const uint8_t key[16]);
+bool mesh_db_net_key_update(json_object *jobj, uint16_t idx,
+ const uint8_t key[16]);
bool mesh_db_net_key_del(json_object *jobj, uint16_t net_idx);
bool mesh_db_net_key_set_phase(json_object *jobj, uint16_t idx, uint8_t phase);
bool mesh_db_write_address(json_object *jobj, uint16_t address);
diff --git a/mesh/net.c b/mesh/net.c
index 3229d20d4..f00ef7df7 100644
--- a/mesh/net.c
+++ b/mesh/net.c
@@ -1016,7 +1016,7 @@ int mesh_net_add_key(struct mesh_net *net, uint16_t idx, const uint8_t *value)
if (status != MESH_STATUS_SUCCESS)
return status;

- if (!storage_net_key_add(net, idx, value, KEY_REFRESH_PHASE_NONE)) {
+ if (!storage_net_key_add(net, idx, value, false)) {
l_queue_remove(net->subnets, subnet);
subnet_free(subnet);
return MESH_STATUS_STORAGE_FAIL;
@@ -3704,13 +3704,16 @@ int mesh_net_update_key(struct mesh_net *net, uint16_t idx,
L_UINT_TO_PTR(idx));

if (!subnet)
- return MESH_STATUS_CANNOT_UPDATE;
+ return MESH_STATUS_INVALID_NETKEY;

/* Check if the key has been already successfully updated */
if (subnet->kr_phase == KEY_REFRESH_PHASE_ONE &&
net_key_confirm(subnet->net_key_upd, value))
return MESH_STATUS_SUCCESS;

+ if (subnet->kr_phase != KEY_REFRESH_PHASE_NONE)
+ return MESH_STATUS_CANNOT_UPDATE;
+
if (subnet->net_key_upd) {
net_key_unref(subnet->net_key_upd);
l_info("Warning: overwriting new keys");
@@ -3734,7 +3737,7 @@ int mesh_net_update_key(struct mesh_net *net, uint16_t idx,

l_info("key refresh phase 1: Key ID %d", subnet->net_key_upd);

- if (!storage_net_key_add(net, idx, value, KEY_REFRESH_PHASE_ONE))
+ if (!storage_net_key_add(net, idx, value, true))
return MESH_STATUS_STORAGE_FAIL;

subnet->kr_phase = KEY_REFRESH_PHASE_ONE;
diff --git a/mesh/node.c b/mesh/node.c
index 1845f9a32..c815acf2e 100644
--- a/mesh/node.c
+++ b/mesh/node.c
@@ -1730,9 +1730,16 @@ bool node_add_pending_local(struct mesh_node *node, void *prov_node_info,
MESH_STATUS_SUCCESS)
return false;

- if (!storage_net_key_add(node->net, info->net_index, info->net_key,
- kr ? KEY_REFRESH_PHASE_TWO : KEY_REFRESH_PHASE_NONE))
- return false;
+ if (kr) {
+ /* Duplicate net key, if the key refresh is on */
+ if (mesh_net_update_key(node->net, info->net_index,
+ info->net_key) != MESH_STATUS_SUCCESS)
+ return false;
+
+ if (!mesh_db_net_key_set_phase(node->jconfig, info->net_index,
+ KEY_REFRESH_PHASE_TWO))
+ return false;
+ }

if (!storage_save_config(node, true, NULL, NULL))
return false;
@@ -1752,7 +1759,7 @@ void node_jconfig_set(struct mesh_node *node, void *jconfig)

void *node_jconfig_get(struct mesh_node *node)
{
- return node->jconfig;
+ return node->jconfig;
}

void node_cfg_file_set(struct mesh_node *node, char *cfg)
diff --git a/mesh/storage.c b/mesh/storage.c
index e1d86960a..d6b566a80 100644
--- a/mesh/storage.c
+++ b/mesh/storage.c
@@ -296,12 +296,15 @@ bool storage_app_key_del(struct mesh_net *net, uint16_t net_idx,
}

bool storage_net_key_add(struct mesh_net *net, uint16_t net_idx,
- const uint8_t key[16], int phase)
+ const uint8_t key[16], bool update)
{
struct mesh_node *node = mesh_net_node_get(net);
json_object *jnode = node_jconfig_get(node);

- return mesh_db_net_key_add(jnode, net_idx, key, phase);
+ if (!update)
+ return mesh_db_net_key_add(jnode, net_idx, key);
+ else
+ return mesh_db_net_key_update(jnode, net_idx, key);
}

bool storage_net_key_del(struct mesh_net *net, uint16_t net_idx)
diff --git a/mesh/storage.h b/mesh/storage.h
index 7dad2762e..85f7899bc 100644
--- a/mesh/storage.h
+++ b/mesh/storage.h
@@ -33,10 +33,9 @@ bool storage_set_relay(json_object *jnode, bool enable, uint8_t count,
uint8_t interval);
bool storage_set_transmit_params(json_object *jnode, uint8_t count,
uint8_t interval);
-bool storage_set_mode(json_object *jnode, uint8_t mode,
- const char *mode_name);
+bool storage_set_mode(json_object *jnode, uint8_t mode, const char *mode_name);
bool storage_net_key_add(struct mesh_net *net, uint16_t net_idx,
- const uint8_t key[16], int phase);
+ const uint8_t key[16], bool update);
bool storage_net_key_del(struct mesh_net *net, uint16_t net_idx);
bool storage_app_key_add(struct mesh_net *net, uint16_t net_idx,
uint16_t app_idx, const uint8_t key[16], bool update);
--
2.17.2


2019-02-12 23:42:24

by Gix, Brian

[permalink] [raw]
Subject: Re: [PATCH BlueZ 0/5 v2] mesh: Save/restore network keys

Patch set applied


On Wed, 2019-02-06 at 19:55 -0800, Inga Stotland wrote:
> Rev.2: addressed Brina's comments.
>
> This set of patches fixes the network key add/update processing.
> Network keys need to be saved to a local node configuration file
> when:
> - a new node is provisioned
> - new network key are added by a configuration client
> - existing network key is updated by a configuration client
> during key refresh procedure.
>
> Also, each saved network key is accompanied by a proper key
> refresh phase setting.
>
> Inga Stotland (5):
> mesh: Separate functions for net key add and update
> mesh: Add function to restore net key state from storage
> mesh: Declare internal functions as static
> mesh: Save key refresh phase state to node config file
> mesh: Save newly added or updated net key to config file
>
> mesh/cfgmod-server.c | 8 +-
> mesh/mesh-db.c | 178 +++++++++++++++++-----------
> mesh/mesh-db.h | 6 +-
> mesh/net.c | 268 +++++++++++++++++++++++++++----------------
> mesh/net.h | 12 +-
> mesh/node.c | 19 ++-
> mesh/storage.c | 22 ++--
> mesh/storage.h | 7 +-
> 8 files changed, 326 insertions(+), 194 deletions(-)
>