Bluetooth: Mesh: Fix network credential selection

The only messages that should be encrypted using the friendship
credentials are those coming through the Friend Queue on the Friend
node, most request-response pairs between LPN & Friend (exceptions are
Friend Request - Friend Offer, and Friend Clear - Friend Clear
Confirm), as well as Model Publication messages when the Friendship
Credentials Flag has been enabled in the model publication.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
Johan Hedberg 2017-11-09 20:35:19 +02:00 committed by Johan Hedberg
commit eb23d688f2
6 changed files with 36 additions and 65 deletions

View file

@ -172,10 +172,7 @@ struct bt_mesh_msg_ctx {
u16_t addr;
/** Received TTL value. Not used for sending. */
u8_t recv_ttl:7;
/** Whether friend credentials are used. */
u8_t friend_cred:1;
u8_t recv_ttl;
/** TTL, or BT_MESH_TTL_DEFAULT for default TTL. */
u8_t send_ttl;

View file

@ -437,23 +437,19 @@ void bt_mesh_model_msg_init(struct net_buf_simple *msg, u32_t opcode)
net_buf_simple_add_le16(msg, opcode & 0xffff);
}
int bt_mesh_model_send(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *msg, bt_mesh_cb_t cb,
void *cb_data)
static int model_send(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
bool friend_cred, struct net_buf_simple *msg,
bt_mesh_cb_t cb, void *cb_data)
{
struct bt_mesh_net_tx tx = {
.sub = bt_mesh_subnet_get(ctx->net_idx),
.ctx = ctx,
.src = model->elem->addr,
.xmit = bt_mesh_net_transmit_get(),
.friend_cred = friend_cred,
};
if (ctx->friend_cred && !bt_mesh_lpn_established()) {
BT_ERR("Friendship Credentials requested without a Friend");
return -EINVAL;
}
BT_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", ctx->net_idx,
ctx->app_idx, ctx->addr);
BT_DBG("len %u: %s", msg->len, bt_hex(msg->data, msg->len));
@ -476,12 +472,22 @@ int bt_mesh_model_send(struct bt_mesh_model *model,
return bt_mesh_trans_send(&tx, msg, cb, cb_data);
}
int bt_mesh_model_send(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *msg, bt_mesh_cb_t cb,
void *cb_data)
{
return model_send(model, ctx, false, msg, cb, cb_data);
}
int bt_mesh_model_publish(struct bt_mesh_model *model,
struct net_buf_simple *msg)
{
struct bt_mesh_app_key *key;
struct bt_mesh_msg_ctx ctx;
BT_DBG("");
if (!model->pub) {
return -ENOTSUP;
}
@ -499,10 +505,9 @@ int bt_mesh_model_publish(struct bt_mesh_model *model,
ctx.net_idx = key->net_idx;
ctx.app_idx = key->app_idx;
ctx.addr = model->pub->addr;
ctx.friend_cred = model->pub->cred;
ctx.send_ttl = model->pub->ttl;
return bt_mesh_model_send(model, &ctx, msg, NULL, NULL);
return model_send(model, &ctx, model->pub->cred, msg, NULL, NULL);
}
struct bt_mesh_model *bt_mesh_model_find_vnd(struct bt_mesh_elem *elem,

View file

@ -327,13 +327,13 @@ static int send_friend_poll(void)
.app_idx = BT_MESH_KEY_UNUSED,
.addr = bt_mesh.lpn.frnd,
.send_ttl = 0,
.friend_cred = 1,
};
struct bt_mesh_net_tx tx = {
.sub = &bt_mesh.sub[0],
.ctx = &ctx,
.src = bt_mesh_primary_addr(),
.xmit = POLL_XMIT,
.friend_cred = true,
};
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
u8_t fsn = lpn->fsn;
@ -619,13 +619,13 @@ static bool sub_update(u8_t op)
.app_idx = BT_MESH_KEY_UNUSED,
.addr = lpn->frnd,
.send_ttl = 0,
.friend_cred = 1,
};
struct bt_mesh_net_tx tx = {
.sub = &bt_mesh.sub[0],
.ctx = &ctx,
.src = bt_mesh_primary_addr(),
.xmit = POLL_XMIT,
.friend_cred = true,
};
struct bt_mesh_ctl_friend_sub req;
size_t i, g;
@ -928,7 +928,7 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx,
* credentials so we need to ensure the right ones (Friend
* Credentials) were used for this message.
*/
if (!rx->ctx.friend_cred) {
if (!rx->friend_cred) {
BT_WARN("Friend Update with wrong credentials");
return -EINVAL;
}

View file

@ -670,25 +670,16 @@ do_update:
}
int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct net_buf *buf,
bool new_key, bool friend_cred, bt_mesh_adv_func_t cb)
bool new_key, bt_mesh_adv_func_t cb)
{
const u8_t *enc, *priv;
int err;
BT_DBG("net_idx 0x%04x new_key %u friend_cred %u len %u",
sub->net_idx, new_key, friend_cred, buf->len);
BT_DBG("net_idx 0x%04x new_key %u len %u", sub->net_idx, new_key,
buf->len);
if (friend_cred) {
err = bt_mesh_friend_cred_get(sub->net_idx,
BT_MESH_ADDR_UNASSIGNED,
new_key, NULL, &enc, &priv);
if (err) {
return err;
}
} else {
enc = sub->keys[new_key].enc;
priv = sub->keys[new_key].privacy;
}
enc = sub->keys[new_key].enc;
priv = sub->keys[new_key].privacy;
err = bt_mesh_net_obfuscate(buf->data, BT_MESH_NET_IVI_TX, priv);
if (err) {
@ -778,20 +769,20 @@ int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf,
net_buf_simple_push_u8(buf, tx->ctx->send_ttl);
}
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && tx->ctx->friend_cred) {
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && tx->friend_cred) {
if (bt_mesh_friend_cred_get(tx->sub->net_idx,
BT_MESH_ADDR_UNASSIGNED,
idx, &nid, &enc, &priv)) {
BT_WARN("Falling back to master credentials");
tx->ctx->friend_cred = 0;
tx->friend_cred = false;
nid = tx->sub->keys[idx].nid;
enc = tx->sub->keys[idx].enc;
priv = tx->sub->keys[idx].privacy;
}
} else {
tx->ctx->friend_cred = 0;
tx->friend_cred = false;
nid = tx->sub->keys[idx].nid;
enc = tx->sub->keys[idx].enc;
priv = tx->sub->keys[idx].privacy;
@ -1002,7 +993,7 @@ static bool net_find_and_decrypt(const u8_t *data, size_t data_len,
#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;
rx->friend_cred = 1;
rx->ctx.net_idx = sub->net_idx;
rx->sub = sub;
return true;
@ -1083,7 +1074,7 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf,
BT_DBG("Relaying packet. TTL is now %u", TTL(buf->data));
/* Update NID if RX or RX was with friend credentials */
if (rx->ctx.friend_cred) {
if (rx->friend_cred) {
buf->data[0] &= 0x80; /* Clear everything except IVI */
buf->data[0] |= nid;
}

View file

@ -234,6 +234,7 @@ struct bt_mesh_net_rx {
u16_t dst; /* Destination address */
u8_t old_iv:1, /* iv_index - 1 was used */
new_key:1, /* Data was encrypted with updated key */
friend_cred:1, /* Data was encrypted with friend cred */
ctl:1, /* Network Control */
net_if:2, /* Network interface */
local_match:1, /* Matched a local element */
@ -247,6 +248,7 @@ struct bt_mesh_net_tx {
struct bt_mesh_msg_ctx *ctx;
u16_t src;
u8_t xmit;
bool friend_cred;
};
extern struct bt_mesh_net bt_mesh;
@ -302,7 +304,7 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf,
bt_mesh_adv_func_t cb);
int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct net_buf *buf,
bool new_key, bool friend_cred, bt_mesh_adv_func_t cb);
bool new_key, bt_mesh_adv_func_t cb);
int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if,
struct bt_mesh_net_rx *rx, struct net_buf_simple *buf);

View file

@ -62,7 +62,6 @@ static struct seg_tx {
u64_t seq_auth;
u16_t dst;
u8_t seg_n:5, /* Last segment index */
friend_cred:1, /* Use Friendship creds */
new_key:1; /* New/old key */
u8_t nack_count; /* Number of unacked segs */
bt_mesh_cb_t cb;
@ -230,8 +229,7 @@ static void seg_tx_send_unacked(struct seg_tx *tx)
BT_DBG("resending %u/%u", i, tx->seg_n);
err = bt_mesh_net_resend(tx->sub, seg, tx->new_key,
tx->friend_cred, seg_sent);
err = bt_mesh_net_resend(tx->sub, seg, tx->new_key, seg_sent);
if (err) {
BT_ERR("Sending segment failed");
seg_tx_complete(tx, -EIO);
@ -295,7 +293,6 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, u8_t aid,
tx->seq_auth = SEQ_AUTH(BT_MESH_NET_IVI_TX, bt_mesh.seq);
tx->sub = net_tx->sub;
tx->new_key = net_tx->sub->kr_flag;
tx->friend_cred = net_tx->ctx->friend_cred;
seq_zero = tx->seq_auth & 0x1fff;
@ -364,11 +361,6 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, u8_t aid,
}
}
/* bt_mesh_net_send() may have modified this if the needed
* Friendship credentials were not found.
*/
tx->friend_cred = net_tx->ctx->friend_cred;
if (bt_mesh_lpn_established()) {
bt_mesh_lpn_friend_poll();
}
@ -448,14 +440,6 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg,
return err;
}
/* Communication between LPN & Friend should always be using
* the Friendship Credentials. Any other destination should
* use the Master Credentials.
*/
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
tx->ctx->friend_cred = bt_mesh_lpn_match(tx->ctx->addr);
}
if (seg) {
return send_seg(tx, aid, mic_len, msg, cb, cb_data);
}
@ -763,7 +747,7 @@ static int ctl_recv(struct bt_mesh_net_rx *rx, u8_t hdr,
return bt_mesh_lpn_friend_clear_cfm(rx, buf);
}
if (!rx->ctx.friend_cred) {
if (!rx->friend_cred) {
BT_WARN("Message from friend with wrong credentials");
return -EINVAL;
}
@ -866,14 +850,6 @@ int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, u8_t ctl_op, void *data,
}
}
/* Communication between LPN & Friend should always be using
* the Friendship Credentials. Any other destination should
* use the Master Credentials.
*/
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
tx->ctx->friend_cred = bt_mesh_lpn_match(tx->ctx->addr);
}
return bt_mesh_net_send(tx, buf, cb);
}
@ -1257,7 +1233,7 @@ int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx)
*/
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) &&
bt_mesh_lpn_established() &&
(!bt_mesh_lpn_waiting_update() || !rx->ctx.friend_cred)) {
(!bt_mesh_lpn_waiting_update() || !rx->friend_cred)) {
BT_WARN("Ignoring unexpected message in Low Power mode");
return -EAGAIN;
}