2019-07-03 07:17:53

by Michał Lowas-Rzechonek

[permalink] [raw]
Subject: [PATCH BlueZ v3 0/3] Add possibility to use remote device keys

+Fixed build/checkpatch errors
+Removed unused APP_IDX_NET and APP_IDX_ANY


This patchset adds support for sending and receiving messages encrypted
with remote device keys.

This plugs a 'leak' in the API where it was possible to exchange such
messages using Send()/MessageReceived() API by using 0x7fff app key
index.

In order to allow the application to receive responses from a local
Config Server model, messages originating from a local node and
encrypted using local device key are also forwarded to the application
via D-Bus (assuming they were not handled by one of internal models).

Michał Lowas-Rzechonek (3):
mesh: Split APP_IDX_DEV into APP_IDX_DEV_LOCAL and APP_IDX_DEV_REMOTE
mesh: Implement DevKeySend() method on Node interface
mesh: Handle messages encrypted with a remote device key

mesh/cfgmod-server.c | 15 +++----
mesh/model.c | 96 +++++++++++++++++++++++++++++++++++++-------
mesh/net.h | 8 ++--
mesh/node.c | 59 ++++++++++++++++++++++++++-
4 files changed, 151 insertions(+), 27 deletions(-)

--
2.19.1


2019-07-03 07:17:56

by Michał Lowas-Rzechonek

[permalink] [raw]
Subject: [PATCH BlueZ v3 1/3] mesh: Split APP_IDX_DEV into APP_IDX_DEV_LOCAL and APP_IDX_DEV_REMOTE

This is needed to distinguish incoming messages encrypted using a device
key: if the key is local, the message can be forwarded to internal
models. If the key is a known remote one, it will be forwarded to the
application via DevKeyMessageReceived() API.
---
mesh/cfgmod-server.c | 15 ++++++++-------
mesh/model.c | 22 +++++++++++++---------
mesh/net.h | 8 ++++----
3 files changed, 25 insertions(+), 20 deletions(-)

diff --git a/mesh/cfgmod-server.c b/mesh/cfgmod-server.c
index 634ac006b..a849b5e99 100644
--- a/mesh/cfgmod-server.c
+++ b/mesh/cfgmod-server.c
@@ -69,7 +69,8 @@ static void send_pub_status(struct mesh_node *node, uint16_t src, uint16_t dst,
n += 2;
}

- mesh_model_send(node, dst, src, APP_IDX_DEV, DEFAULT_TTL, msg, n);
+ mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, DEFAULT_TTL,
+ msg, n);
}

static bool config_pub_get(struct mesh_node *node, uint16_t src, uint16_t dst,
@@ -254,7 +255,7 @@ static void send_sub_status(struct mesh_node *node, uint16_t src, uint16_t dst,
n += 2;
}

- mesh_model_send(node, dst, src, APP_IDX_DEV, DEFAULT_TTL, msg, n);
+ mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, DEFAULT_TTL, msg, n);
}

static bool config_sub_get(struct mesh_node *node, uint16_t src, uint16_t dst,
@@ -312,7 +313,7 @@ static bool config_sub_get(struct mesh_node *node, uint16_t src, uint16_t dst,

*msg_status = (uint8_t) status;

- mesh_model_send(node, dst, src, APP_IDX_DEV, DEFAULT_TTL, msg, n);
+ mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, DEFAULT_TTL, msg, n);
return true;
}

@@ -487,7 +488,7 @@ static void send_model_app_status(struct mesh_node *node, uint16_t src,
l_put_le16(id, msg + n);
n += 2;

- mesh_model_send(node, dst, src, APP_IDX_DEV, DEFAULT_TTL, msg, n);
+ mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, DEFAULT_TTL, msg, n);
}

static void model_app_list(struct mesh_node *node, uint16_t src, uint16_t dst,
@@ -540,7 +541,7 @@ static void model_app_list(struct mesh_node *node, uint16_t src, uint16_t dst,

if (result >= 0) {
*status = result;
- mesh_model_send(node, dst, src, APP_IDX_DEV, DEFAULT_TTL,
+ mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, DEFAULT_TTL,
msg, n);
}

@@ -758,7 +759,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
uint16_t interval;
uint16_t n;

- if (idx != APP_IDX_DEV)
+ if (idx != APP_IDX_DEV_LOCAL)
return false;

if (mesh_model_opcode_get(pkt, size, &opcode, &n)) {
@@ -1259,7 +1260,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
if (n) {
/* print_packet("App Tx", long_msg ? long_msg : msg, n); */
mesh_model_send(node, unicast, src,
- APP_IDX_DEV, DEFAULT_TTL,
+ APP_IDX_DEV_LOCAL, DEFAULT_TTL,
long_msg ? long_msg : msg, n);
}
l_free(long_msg);
diff --git a/mesh/model.c b/mesh/model.c
index 7401dcecb..598615c5e 100644
--- a/mesh/model.c
+++ b/mesh/model.c
@@ -306,7 +306,9 @@ static void forward_model(void *a, void *b)
bool result;

l_debug("model %8.8x with idx %3.3x", mod->id, fwd->idx);
- if (fwd->idx != APP_IDX_DEV && !has_binding(mod->bindings, fwd->idx))
+
+ if (fwd->idx != APP_IDX_DEV_LOCAL &&
+ !has_binding(mod->bindings, fwd->idx))
return;

dst = fwd->dst;
@@ -356,15 +358,15 @@ static int dev_packet_decrypt(struct mesh_node *node, const uint8_t *data,
uint16_t dst, uint8_t key_id, uint32_t seq,
uint32_t iv_idx, uint8_t *out)
{
- const uint8_t *dev_key;
+ const uint8_t *key;

- dev_key = node_get_device_key(node);
- if (!dev_key)
+ key = node_get_device_key(node);
+ if (!key)
return false;

if (mesh_crypto_payload_decrypt(NULL, 0, data, size, szmict, src,
- dst, key_id, seq, iv_idx, out, dev_key))
- return APP_IDX_DEV;
+ dst, key_id, seq, iv_idx, out, key))
+ return APP_IDX_DEV_LOCAL;

return -1;
}
@@ -952,7 +954,7 @@ bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t target,
if (IS_UNASSIGNED(target))
return false;

- if (app_idx == APP_IDX_DEV) {
+ if (app_idx == APP_IDX_DEV_LOCAL) {
key = node_get_device_key(node);
if (!key)
return false;
@@ -1381,12 +1383,14 @@ struct mesh_model *mesh_model_setup(struct mesh_node *node, uint8_t ele_idx,
if (ele_idx != PRIMARY_ELE_IDX)
return NULL;

- l_queue_push_head(mod->bindings, L_UINT_TO_PTR(APP_IDX_DEV));
+ l_queue_push_head(mod->bindings,
+ L_UINT_TO_PTR(APP_IDX_DEV_LOCAL));
return mod;
}

if (db_mod->id == CONFIG_CLI_MODEL) {
- l_queue_push_head(mod->bindings, L_UINT_TO_PTR(APP_IDX_DEV));
+ l_queue_push_head(mod->bindings,
+ L_UINT_TO_PTR(APP_IDX_DEV_LOCAL));
return mod;
}

diff --git a/mesh/net.h b/mesh/net.h
index f19024766..8848e6df0 100644
--- a/mesh/net.h
+++ b/mesh/net.h
@@ -37,10 +37,10 @@ struct mesh_node;
#define SEQ_MASK 0xffffff

#define CREDFLAG_MASK 0x1000
-#define APP_IDX_MASK 0x0fff
-#define APP_IDX_DEV 0x7fff
-#define APP_IDX_ANY 0x8000
-#define APP_IDX_NET 0xffff
+
+#define APP_IDX_MASK 0x0fff
+#define APP_IDX_DEV_REMOTE 0x6fff
+#define APP_IDX_DEV_LOCAL 0x7fff

#define NET_IDX_INVALID 0xffff
#define NET_NID_INVALID 0xff
--
2.19.1

2019-07-03 07:18:59

by Michał Lowas-Rzechonek

[permalink] [raw]
Subject: [PATCH BlueZ v3 3/3] mesh: Handle messages encrypted with a remote device key

This adds ability to receive messages encrypted using known remote
device key. Such a key must be added to the node's keyring using
ImportRemoteNode() method of org.bluez.mesh.Management1 interface.

Decrypted messages are then forwarded to the application using
DevKeyMessageReceived() D-Bus API.

Also, messages originating from a local node and encrypted using local
device key are forwarde to the application as well, if they weren't
handled by internal model. This allows e.g. receiving status messages
from a local Config Server in the application.
---
mesh/model.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 61 insertions(+), 4 deletions(-)

diff --git a/mesh/model.c b/mesh/model.c
index aae913d92..404f5b64b 100644
--- a/mesh/model.c
+++ b/mesh/model.c
@@ -359,6 +359,7 @@ static int dev_packet_decrypt(struct mesh_node *node, const uint8_t *data,
uint16_t dst, uint8_t key_id, uint32_t seq,
uint32_t iv_idx, uint8_t *out)
{
+ uint8_t dev_key[16];
const uint8_t *key;

key = node_get_device_key(node);
@@ -369,6 +370,14 @@ static int dev_packet_decrypt(struct mesh_node *node, const uint8_t *data,
dst, key_id, seq, iv_idx, out, key))
return APP_IDX_DEV_LOCAL;

+ if (!keyring_get_remote_dev_key(node, src, dev_key))
+ return -1;
+
+ key = dev_key;
+ if (mesh_crypto_payload_decrypt(NULL, 0, data, size, szmict, src,
+ dst, key_id, seq, iv_idx, out, key))
+ return APP_IDX_DEV_REMOTE;
+
return -1;
}

@@ -695,6 +704,47 @@ static int add_sub(struct mesh_net *net, struct mesh_model *mod,
return MESH_STATUS_SUCCESS;
}

+static void send_dev_key_msg_rcvd(struct mesh_node *node, uint8_t ele_idx,
+ uint16_t src, uint16_t net_idx,
+ uint16_t size, const uint8_t *data)
+{
+ struct l_dbus *dbus = dbus_get_bus();
+ struct l_dbus_message *msg;
+ struct l_dbus_message_builder *builder;
+ const char *owner;
+ const char *path;
+
+ owner = node_get_owner(node);
+ path = node_get_element_path(node, ele_idx);
+ if (!path || !owner)
+ return;
+
+ l_debug("Send \"DevKeyMessageReceived\"");
+
+ msg = l_dbus_message_new_method_call(dbus, owner, path,
+ MESH_ELEMENT_INTERFACE,
+ "DevKeyMessageReceived");
+
+ builder = l_dbus_message_builder_new(msg);
+
+ if (!l_dbus_message_builder_append_basic(builder, 'q', &src))
+ goto error;
+
+ if (!l_dbus_message_builder_append_basic(builder, 'q', &net_idx))
+ goto error;
+
+ if (!dbus_append_byte_array(builder, data, size))
+ goto error;
+
+ if (!l_dbus_message_builder_finalize(builder))
+ goto error;
+
+ l_dbus_send(dbus, msg);
+
+error:
+ l_dbus_message_builder_destroy(builder);
+}
+
static void send_msg_rcvd(struct mesh_node *node, uint8_t ele_idx, bool is_sub,
uint16_t src, uint16_t key_idx,
uint16_t size, const uint8_t *data)
@@ -843,10 +893,17 @@ bool mesh_model_rx(struct mesh_node *node, bool szmict, uint32_t seq0,
* Cycle through external models if the message has not been
* handled by internal models
*/
- if (forward.has_dst && !forward.done)
- send_msg_rcvd(node, i, is_subscription, src,
- forward.idx, forward.size,
- forward.data);
+ if (forward.has_dst && !forward.done) {
+ if ((decrypt_idx & APP_IDX_MASK) == decrypt_idx)
+ send_msg_rcvd(node, i, is_subscription, src,
+ forward.idx, forward.size,
+ forward.data);
+ else if (decrypt_idx == APP_IDX_DEV_REMOTE ||
+ (decrypt_idx == APP_IDX_DEV_LOCAL &&
+ mesh_net_is_local_address(net, src)))
+ send_dev_key_msg_rcvd(node, i, src, 0,
+ forward.size, forward.data);
+ }

/*
* Either the message has been processed internally or
--
2.19.1