Bluetooth: Mesh: Fix network decryption in case of multiple LPNs
If we are a Friend node with multiple LPNs, we need to iterate through
all available Friendship credentials to find the right keys.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
diff --git a/subsys/bluetooth/host/mesh/net.c b/subsys/bluetooth/host/mesh/net.c
index 9cec0de..b72482e 100644
--- a/subsys/bluetooth/host/mesh/net.c
+++ b/subsys/bluetooth/host/mesh/net.c
@@ -906,35 +906,12 @@
return NULL;
}
-static int net_decrypt(struct bt_mesh_subnet *sub, u8_t idx, const u8_t *data,
+static int net_decrypt(struct bt_mesh_subnet *sub, const u8_t *enc,
+ const u8_t *priv, const u8_t *data,
size_t data_len, struct bt_mesh_net_rx *rx,
struct net_buf_simple *buf)
{
- const u8_t *enc, *priv;
-
- BT_DBG("NID 0x%02x, PDU NID 0x%02x net_idx 0x%04x idx %u",
- sub->keys[idx].nid, NID(data), sub->net_idx, idx);
-
- if (NID(data) == sub->keys[idx].nid) {
- enc = sub->keys[idx].enc;
- priv = sub->keys[idx].privacy;
- rx->ctx.friend_cred = 0;
- } else {
- u8_t nid;
-
- if (bt_mesh_friend_cred_get(sub->net_idx,
- BT_MESH_ADDR_UNASSIGNED, idx,
- &nid, &enc, &priv)) {
- return -ENOENT;
- }
-
- if (nid != NID(data)) {
- return -ENOENT;
- }
-
- rx->ctx.friend_cred = 1;
- }
-
+ BT_DBG("NID 0x%02x net_idx 0x%04x", NID(data), sub->net_idx);
BT_DBG("IVI %u net->iv_index 0x%08x", IVI(data), bt_mesh.iv_index);
rx->old_iv = (IVI(data) != (bt_mesh.iv_index & 0x01));
@@ -968,42 +945,92 @@
return bt_mesh_net_decrypt(enc, buf, BT_MESH_NET_IVI_RX(rx), false);
}
-static int net_find_and_decrypt(const u8_t *data, size_t data_len,
- struct bt_mesh_net_rx *rx,
- struct net_buf_simple *buf)
+#if (defined(CONFIG_BT_MESH_LOW_POWER) || \
+ defined(CONFIG_BT_MESH_FRIEND))
+static int friend_decrypt(struct bt_mesh_subnet *sub, const u8_t *data,
+ size_t data_len, struct bt_mesh_net_rx *rx,
+ struct net_buf_simple *buf)
{
int i;
- BT_DBG("");
+ BT_DBG("NID 0x%02x net_idx 0x%04x", NID(data), sub->net_idx);
- for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
- struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
- int err;
+ for (i = 0; i < ARRAY_SIZE(friend_cred); i++) {
+ struct bt_mesh_friend_cred *cred = &friend_cred[i];
- if (sub->net_idx == BT_MESH_KEY_UNUSED) {
+ if (cred->net_idx != sub->net_idx) {
continue;
}
- err = net_decrypt(sub, 0, data, data_len, rx, buf);
- if (!err) {
- rx->ctx.net_idx = sub->net_idx;
- rx->sub = sub;
- return true;
+ if (NID(data) == cred->cred[0].nid &&
+ !net_decrypt(sub, cred->cred[0].enc, cred->cred[0].privacy,
+ data, data_len, rx, buf)) {
+ return 0;
}
if (sub->kr_phase == BT_MESH_KR_NORMAL) {
continue;
}
- err = net_decrypt(sub, 1, data, data_len, rx, buf);
- if (!err) {
- rx->ctx.net_idx = sub->net_idx;
- rx->sub = sub;
+ if (NID(data) == cred->cred[1].nid &&
+ !net_decrypt(sub, cred->cred[1].enc, cred->cred[1].privacy,
+ data, data_len, rx, buf)) {
rx->new_key = 1;
- return true;
+ return 0;
}
}
+ return -ENOENT;
+}
+#endif
+
+static int net_find_and_decrypt(const u8_t *data, size_t data_len,
+ struct bt_mesh_net_rx *rx,
+ struct net_buf_simple *buf)
+{
+ struct bt_mesh_subnet *sub;
+ int i;
+
+ BT_DBG("");
+
+ for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
+ sub = &bt_mesh.sub[i];
+ if (sub->net_idx == BT_MESH_KEY_UNUSED) {
+ continue;
+ }
+
+#if (defined(CONFIG_BT_MESH_LOW_POWER) || \
+ defined(CONFIG_BT_MESH_FRIEND))
+ if (!friend_decrypt(sub, data, data_len, rx, buf)) {
+ rx->ctx.friend_cred = 1;
+ break;
+ }
+#endif
+
+ if (NID(data) == sub->keys[0].nid &&
+ !net_decrypt(sub, sub->keys[0].enc, sub->keys[0].privacy,
+ data, data_len, rx, buf)) {
+ break;
+ }
+
+ if (sub->kr_phase == BT_MESH_KR_NORMAL) {
+ continue;
+ }
+
+ if (NID(data) == sub->keys[1].nid &&
+ !net_decrypt(sub, sub->keys[1].enc, sub->keys[1].privacy,
+ data, data_len, rx, buf)) {
+ rx->new_key = 1;
+ break;
+ }
+ }
+
+ if (i < ARRAY_SIZE(bt_mesh.sub)) {
+ rx->ctx.net_idx = sub->net_idx;
+ rx->sub = sub;
+ return true;
+ }
+
return false;
}