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>
This commit is contained in:
Johan Hedberg 2017-11-06 13:18:14 +02:00 committed by Johan Hedberg
commit 2a74be43ea

View file

@ -906,35 +906,12 @@ struct bt_mesh_subnet *bt_mesh_subnet_find(const u8_t net_id[8], u8_t flags,
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 @@ static int net_decrypt(struct bt_mesh_subnet *sub, u8_t idx, const u8_t *data,
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;
}