2019-11-15 23:17:59

by Gix, Brian

[permalink] [raw]
Subject: [PATCH BlueZ v2 0/2] mesh: Fix inOOB and outOOB issues

This patchset includes modification to both the Daemon and the
mesh-cfgclient. All of the inOOB and outOOB scenarios have been tested,
and are working according to the Bluetooth Profile specification, for
the Provisioner "Initiator" role.

Brian Gix (1):
mesh: Fix inOOB and outOOB agent handling on prov initiate

Inga Stotland (1):
tools/mesh-cfgclient: Add full support inOOB and outOOB

mesh/agent.c | 12 +--
mesh/prov-initiator.c | 69 +++++++++++++---
tools/mesh-cfgclient.c | 178 ++++++++++++++++++++++++++++++++++-------
tools/mesh-gatt/prov.c | 9 ++-
tools/mesh/agent.c | 21 +++--
tools/mesh/agent.h | 4 +-
6 files changed, 233 insertions(+), 60 deletions(-)

--
2.21.0


2019-11-15 23:17:59

by Gix, Brian

[permalink] [raw]
Subject: [PATCH BlueZ v2 1/2] mesh: Fix inOOB and outOOB agent handling on prov initiate

This code fixes the Provisioner Initiator role so that the following
Out-of-Band agent calls are made correctly, and their results handled
properly:

"push", "twist", "blink", "beep", "vibrate", "in-numeric",
"out-numeric", "in-alpha", "out-alpha"
---
mesh/agent.c | 12 ++++----
mesh/prov-initiator.c | 69 ++++++++++++++++++++++++++++++++++++-------
2 files changed, 65 insertions(+), 16 deletions(-)

diff --git a/mesh/agent.c b/mesh/agent.c
index 4f99bad7b..623f2faf0 100644
--- a/mesh/agent.c
+++ b/mesh/agent.c
@@ -363,7 +363,7 @@ static void key_reply(struct l_dbus_message *reply, void *user_data)
mesh_agent_key_cb_t cb;
struct l_dbus_message_iter iter_array;
uint32_t n = 0, expected_len = 0;
- uint8_t buf[64];
+ uint8_t *buf;
int err;

if (!l_queue_find(agents, simple_match, agent) || !agent->req)
@@ -376,13 +376,13 @@ static void key_reply(struct l_dbus_message *reply, void *user_data)
if (err != MESH_ERROR_NONE)
goto done;

- if (!l_dbus_message_get_arguments(reply, "au", &iter_array)) {
+ if (!l_dbus_message_get_arguments(reply, "ay", &iter_array)) {
l_error("Failed to retrieve key input");
err = MESH_ERROR_FAILED;
goto done;
}

- if (!l_dbus_message_iter_get_fixed_array(&iter_array, buf, &n)) {
+ if (!l_dbus_message_iter_get_fixed_array(&iter_array, &buf, &n)) {
l_error("Failed to retrieve key input");
err = MESH_ERROR_FAILED;
goto done;
@@ -390,7 +390,7 @@ static void key_reply(struct l_dbus_message *reply, void *user_data)

if (req->type == MESH_AGENT_REQUEST_PRIVATE_KEY)
expected_len = 32;
- else if (MESH_AGENT_REQUEST_PUBLIC_KEY)
+ else if (req->type == MESH_AGENT_REQUEST_PUBLIC_KEY)
expected_len = 64;
else
expected_len = 16;
@@ -402,13 +402,13 @@ static void key_reply(struct l_dbus_message *reply, void *user_data)
}

done:
- l_dbus_message_unref(req->msg);
-
if (req->cb) {
cb = req->cb;
cb(req->user_data, err, buf, n);
}

+ l_dbus_message_unref(req->msg);
+
l_free(req);
agent->req = NULL;
}
diff --git a/mesh/prov-initiator.c b/mesh/prov-initiator.c
index 5e45d6813..96be00cdc 100644
--- a/mesh/prov-initiator.c
+++ b/mesh/prov-initiator.c
@@ -433,6 +433,54 @@ failure:
/* TODO: Call Complete Callback (Fail)*/
}

+static void get_random_key(struct mesh_prov_initiator *prov, uint8_t action,
+ uint8_t size)
+{
+ uint32_t oob_key;
+ int i;
+
+ if (action >= PROV_ACTION_IN_ALPHA) {
+ uint8_t alpha;
+ char tmp[17];
+
+ memset(tmp, 0, sizeof(tmp));
+
+ if (size > 16)
+ size = 16;
+
+ /* Create random alphanumeric string made of 0-9, a-z, A-Z */
+ for (i = 0; i < size; i++) {
+ l_getrandom(&alpha, sizeof(alpha));
+ alpha %= (10 + 26 + 26);
+
+ if (alpha < 10)
+ alpha += '0';
+ else if (alpha < 10 + 26)
+ alpha += 'a' - 10;
+ else
+ alpha += 'A' - 10 - 26;
+
+ tmp[i] = (char) alpha;
+ }
+ memcpy(prov->rand_auth_workspace + 16, tmp, size);
+ memcpy(prov->rand_auth_workspace + 32, tmp, size);
+ return;
+ }
+
+ l_getrandom(&oob_key, sizeof(oob_key));
+
+ if (action <= PROV_ACTION_TWIST)
+ oob_key %= size;
+ else
+ oob_key %= digit_mod(size);
+
+ if (!oob_key)
+ oob_key = size;
+
+ /* Save two copies, for two confirmation values */
+ l_put_be32(oob_key, prov->rand_auth_workspace + 28);
+ l_put_be32(oob_key, prov->rand_auth_workspace + 44);
+}

static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
{
@@ -591,22 +639,22 @@ static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len)

case 3:
/* Auth Type 3b - input OOB */
- l_getrandom(&oob_key, sizeof(oob_key));
- oob_key %= digit_mod(prov->conf_inputs.start.auth_size);
+ get_random_key(prov,
+ prov->conf_inputs.start.auth_action,
+ prov->conf_inputs.start.auth_size);
+ oob_key = l_get_be32(prov->rand_auth_workspace + 28);

- /* Save two copies, for two confirmation values */
- l_put_be32(oob_key, prov->rand_auth_workspace + 28);
- l_put_be32(oob_key, prov->rand_auth_workspace + 44);
- prov->material |= MAT_RAND_AUTH;
- /* Ask Agent to Display U32 */
+ /* Ask Agent to Display random key */
if (prov->conf_inputs.start.auth_action ==
PROV_ACTION_IN_ALPHA) {
- /* TODO: Construst NUL-term string to pass */
+
fail_code[1] = mesh_agent_display_string(
- prov->agent, NULL, NULL, prov);
+ prov->agent,
+ (char *) prov->rand_auth_workspace + 16,
+ NULL, prov);
} else {
fail_code[1] = mesh_agent_display_number(
- prov->agent, false,
+ prov->agent, true,
prov->conf_inputs.start.auth_action,
oob_key, NULL, prov);
}
@@ -625,6 +673,7 @@ static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len)

case PROV_INP_CMPLT: /* Provisioning Input Complete */
/* TODO: Cancel Agent prompt */
+ prov->material |= MAT_RAND_AUTH;
send_confirm(prov);
break;

--
2.21.0

2019-11-15 23:18:16

by Gix, Brian

[permalink] [raw]
Subject: [PATCH BlueZ v2 2/2] tools/mesh-cfgclient: Add full support inOOB and outOOB

From: Inga Stotland <[email protected]>

Add support for all the forms of inOOB and outOOB prompt and display
requests from the Provisioner for a remote device:
"push", "twist", "blink", "beep", "vibrate", "in-numeric",
"out-numeric", "in-alpha", and "out-alpha"
---
tools/mesh-cfgclient.c | 178 ++++++++++++++++++++++++++++++++++-------
tools/mesh-gatt/prov.c | 9 ++-
tools/mesh/agent.c | 21 +++--
tools/mesh/agent.h | 4 +-
4 files changed, 168 insertions(+), 44 deletions(-)

diff --git a/tools/mesh-cfgclient.c b/tools/mesh-cfgclient.c
index 444b9e5aa..1c617a37b 100644
--- a/tools/mesh-cfgclient.c
+++ b/tools/mesh-cfgclient.c
@@ -353,53 +353,141 @@ static bool caps_getter(struct l_dbus *dbus,
return true;
}

+static void agent_input_done(oob_type_t type, void *buf, uint16_t len,
+ void *user_data)
+{
+ struct l_dbus_message *msg = user_data;
+ struct l_dbus_message *reply = NULL;
+ struct l_dbus_message_builder *builder;
+ uint32_t val_u32;
+ uint8_t ascii[16];
+
+ switch (type) {
+ case NONE:
+ case OUTPUT:
+ case HEXADECIMAL:
+ default:
+ break;
+
+ case ASCII:
+ if (len > 8) {
+ bt_shell_printf("Bad input length\n");
+ break;
+ }
+
+ memset(ascii, 0, 16);
+ memcpy(ascii, buf, len);
+ reply = l_dbus_message_new_method_return(msg);
+ builder = l_dbus_message_builder_new(reply);
+ append_byte_array(builder, ascii, 16);
+ l_dbus_message_builder_finalize(builder);
+ l_dbus_message_builder_destroy(builder);
+ break;
+
+ case DECIMAL:
+ if (len > 8) {
+ bt_shell_printf("Bad input length\n");
+ break;
+ }
+
+ val_u32 = l_get_be32(buf);
+ reply = l_dbus_message_new_method_return(msg);
+ l_dbus_message_set_arguments(reply, "u", val_u32);
+ break;
+ }
+
+ if (!reply)
+ reply = l_dbus_message_new_error(msg, dbus_err_fail, NULL);
+
+ l_dbus_send(dbus, reply);
+}
+
+struct requested_action {
+ const char *action;
+ const char *description;
+};
+
+static struct requested_action display_numeric_table[] = {
+ { "push", "Push remote button %d times"},
+ { "twist", "Twist remote nob %d times"},
+ { "in-numeric", "Enter %d on remote device"},
+ { "out-numeric", "Enter %d on remote device"}
+};
+
+static struct requested_action prompt_numeric_table[] = {
+ { "blink", "Enter the number of times remote LED blinked"},
+ { "beep", "Enter the number of times remote device beeped"},
+ { "vibrate", "Enter the number of times remote device vibrated"},
+ { "in-numeric", "Enter the number displayed on remote device"},
+ { "out-numeric", "Enter the number displayed on remote device"}
+};
+
+static int get_action(char *str, bool prompt)
+{
+ struct requested_action *action_table;
+ size_t len;
+ int i, sz;
+
+ if (!str)
+ return -1;
+
+ if (prompt) {
+ len = strlen(str);
+ sz = L_ARRAY_SIZE(prompt_numeric_table);
+ action_table = prompt_numeric_table;
+ } else {
+ len = strlen(str);
+ sz = L_ARRAY_SIZE(display_numeric_table);
+ action_table = display_numeric_table;
+ }
+
+ for (i = 0; i < sz; ++i)
+ if (len == strlen(action_table[i].action) &&
+ !strcmp(str, action_table[i].action))
+ return i;
+
+ return -1;
+}
+
static struct l_dbus_message *disp_numeric_call(struct l_dbus *dbus,
struct l_dbus_message *msg,
void *user_data)
{
char *str;
uint32_t n;
+ int action_index;

if (!l_dbus_message_get_arguments(msg, "su", &str, &n)) {
l_error("Cannot parse \"DisplayNumeric\" arguments");
return l_dbus_message_new_error(msg, dbus_err_fail, NULL);
}

- if (!str || strlen(str) != strlen("in-numeric") ||
- strncmp(str, "in-numeric", strlen("in-numeric")))
+ action_index = get_action(str, false);
+ if (action_index < 0)
return l_dbus_message_new_error(msg, dbus_err_support, NULL);

- bt_shell_printf(COLOR_YELLOW "Enter %u on remote device" COLOR_OFF, n);
+ str = l_strdup_printf(display_numeric_table[action_index].description,
+ n);
+ bt_shell_printf(COLOR_YELLOW "%s\n" COLOR_OFF, str);
+ l_free(str);

return l_dbus_message_new_method_return(msg);
}

-static void agent_input_done(oob_type_t type, void *buf, uint16_t len,
- void *user_data)
+static struct l_dbus_message *disp_string_call(struct l_dbus *dbus,
+ struct l_dbus_message *msg,
+ void *user_data)
{
- struct l_dbus_message *msg = user_data;
- struct l_dbus_message *reply;
- uint32_t val_u32;
-
- switch (type) {
- case NONE:
- case OUTPUT:
- case ASCII:
- case HEXADECIMAL:
- default:
- return;
- case DECIMAL:
- if (len >= 8) {
- bt_shell_printf("Bad input length");
- return;
- }
+ char *str;

- val_u32 = l_get_be32(buf);
- reply = l_dbus_message_new_method_return(msg);
- l_dbus_message_set_arguments(reply, "u", val_u32);
- l_dbus_send(dbus, reply);
- break;
+ if (!l_dbus_message_get_arguments(msg, "s", &str)) {
+ l_error("Cannot parse \"DisplayString\" arguments");
+ return l_dbus_message_new_error(msg, dbus_err_fail, NULL);
}
+
+ bt_shell_printf(COLOR_YELLOW "Enter AlphaNumeric code on remote device: %s\n" COLOR_OFF, str);
+
+ return l_dbus_message_new_method_return(msg);
}

static struct l_dbus_message *prompt_numeric_call(struct l_dbus *dbus,
@@ -407,18 +495,43 @@ static struct l_dbus_message *prompt_numeric_call(struct l_dbus *dbus,
void *user_data)
{
char *str;
+ int action_index;
+ const char *desc;

if (!l_dbus_message_get_arguments(msg, "s", &str)) {
l_error("Cannot parse \"PromptNumeric\" arguments");
return l_dbus_message_new_error(msg, dbus_err_fail, NULL);
}

- if (!str || strlen(str) != strlen("out-numeric") ||
- strncmp(str, "out-numeric", strlen("out-numeric")))
+ action_index = get_action(str, true);
+ if (action_index < 0)
return l_dbus_message_new_error(msg, dbus_err_support, NULL);

+ desc = prompt_numeric_table[action_index].description;
+
l_dbus_message_ref(msg);
- agent_input_request(DECIMAL, 8, agent_input_done, msg);
+ agent_input_request(DECIMAL, 8, desc, agent_input_done, msg);
+
+ return NULL;
+}
+
+static struct l_dbus_message *prompt_static_call(struct l_dbus *dbus,
+ struct l_dbus_message *msg,
+ void *user_data)
+{
+ char *str;
+
+ if (!l_dbus_message_get_arguments(msg, "s", &str) || !str) {
+ l_error("Cannot parse \"PromptStatic\" arguments");
+ return l_dbus_message_new_error(msg, dbus_err_fail, NULL);
+ }
+
+ if (!strcmp(str, "in-alpha") && !strcmp(str, "out-alpha"))
+ return l_dbus_message_new_error(msg, dbus_err_support, NULL);
+
+ l_dbus_message_ref(msg);
+ agent_input_request(ASCII, 8, "Enter displayed Ascii code",
+ agent_input_done, msg);

return NULL;
}
@@ -428,11 +541,14 @@ static void setup_agent_iface(struct l_dbus_interface *iface)
l_dbus_interface_property(iface, "Capabilities", 0, "as", caps_getter,
NULL);
/* TODO: Other properties */
+ l_dbus_interface_method(iface, "DisplayString", 0, disp_string_call,
+ "", "s", "value");
l_dbus_interface_method(iface, "DisplayNumeric", 0, disp_numeric_call,
"", "su", "type", "number");
l_dbus_interface_method(iface, "PromptNumeric", 0, prompt_numeric_call,
- "u", "s", "number", "type");
-
+ "u", "s", "type");
+ l_dbus_interface_method(iface, "PromptStatic", 0, prompt_static_call,
+ "ay", "s", "type");
}

static bool register_agent(void)
diff --git a/tools/mesh-gatt/prov.c b/tools/mesh-gatt/prov.c
index 0f9d85d01..598c94ebf 100644
--- a/tools/mesh-gatt/prov.c
+++ b/tools/mesh-gatt/prov.c
@@ -333,18 +333,18 @@ static void prov_calc_ecdh(DBusMessage *message, void *node)

case 1: /* Static OOB */
agent_input_request(HEXADECIMAL,
- 16,
+ 16, NULL,
prov_out_oob_done, node);
break;

case 2: /* Output OOB */
if (action <= 3)
agent_input_request(DECIMAL,
- size,
+ size, NULL,
prov_out_oob_done, node);
else
agent_input_request(ASCII,
- size,
+ size, NULL,
prov_out_oob_done, node);
break;

@@ -421,7 +421,8 @@ static void prov_start_cmplt(DBusMessage *message, void *node)
if (prov == NULL) return;

if (prov->conf_in.start.pub_key)
- agent_input_request(HEXADECIMAL, 64, prov_oob_pub_key, node);
+ agent_input_request(HEXADECIMAL, 64, NULL, prov_oob_pub_key,
+ node);
else
prov_send_pub_key(node);
}
diff --git a/tools/mesh/agent.c b/tools/mesh/agent.c
index 0ec76f3b7..1f83347bf 100644
--- a/tools/mesh/agent.c
+++ b/tools/mesh/agent.c
@@ -35,6 +35,8 @@
#include "src/shared/shell.h"
#include "tools/mesh/agent.h"

+#define AGENT_PROMPT COLOR_BLUE "[mesh-agent]" COLOR_OFF "# "
+
struct input_request {
oob_type_t type;
uint16_t len;
@@ -124,7 +126,7 @@ static bool request_hexadecimal(uint16_t len)
return false;

bt_shell_printf("Request hexadecimal key (hex %d octets)\n", len);
- bt_shell_prompt_input("mesh", "Enter key (hex number):",
+ bt_shell_prompt_input(AGENT_PROMPT, "Enter key (hex number):",
response_hexadecimal, NULL);

return true;
@@ -140,10 +142,15 @@ static uint32_t power_ten(uint8_t power)
return ret;
}

-static bool request_decimal(uint16_t len)
+static bool request_decimal(const char *desc, uint16_t len)
{
- bt_shell_printf("Request decimal key (0 - %d)\n", power_ten(len) - 1);
- bt_shell_prompt_input("mesh-agent", "Enter Numeric key:",
+ if (!desc)
+ bt_shell_printf("Request decimal key (0 - %d)\n",
+ power_ten(len) - 1);
+ else
+ bt_shell_printf("%s (0 - %d)\n", desc, power_ten(len) - 1);
+
+ bt_shell_prompt_input(AGENT_PROMPT, "Enter decimal number:",
response_decimal, NULL);

return true;
@@ -161,8 +168,8 @@ static bool request_ascii(uint16_t len)
return true;
}

-bool agent_input_request(oob_type_t type, uint16_t max_len, agent_input_cb cb,
- void *user_data)
+bool agent_input_request(oob_type_t type, uint16_t max_len, const char *desc,
+ agent_input_cb cb, void *user_data)
{
bool result;

@@ -174,7 +181,7 @@ bool agent_input_request(oob_type_t type, uint16_t max_len, agent_input_cb cb,
result = request_hexadecimal(max_len);
break;
case DECIMAL:
- result = request_decimal(max_len);
+ result = request_decimal(desc, max_len);
break;
case ASCII:
result = request_ascii(max_len);
diff --git a/tools/mesh/agent.h b/tools/mesh/agent.h
index 9db4321fc..7f95798f1 100644
--- a/tools/mesh/agent.h
+++ b/tools/mesh/agent.h
@@ -35,8 +35,8 @@ typedef enum {

typedef void (*agent_input_cb)(oob_type_t type, void *input, uint16_t len,
void *user_data);
-bool agent_input_request(oob_type_t type, uint16_t max_len, agent_input_cb cb,
- void *user_data);
+bool agent_input_request(oob_type_t type, uint16_t max_len, const char *desc,
+ agent_input_cb cb, void *user_data);

bool agent_output_request(const char* str);
void agent_output_request_cancel(void);
--
2.21.0

2019-11-16 12:10:45

by Aurelien Jarno

[permalink] [raw]
Subject: Re: [PATCH BlueZ v2 0/2] mesh: Fix inOOB and outOOB issues

On 2019-11-15 15:17, Brian Gix wrote:
> This patchset includes modification to both the Daemon and the
> mesh-cfgclient. All of the inOOB and outOOB scenarios have been tested,
> and are working according to the Bluetooth Profile specification, for
> the Provisioner "Initiator" role.
>
> Brian Gix (1):
> mesh: Fix inOOB and outOOB agent handling on prov initiate
>
> Inga Stotland (1):
> tools/mesh-cfgclient: Add full support inOOB and outOOB
>
> mesh/agent.c | 12 +--
> mesh/prov-initiator.c | 69 +++++++++++++---
> tools/mesh-cfgclient.c | 178 ++++++++++++++++++++++++++++++++++-------
> tools/mesh-gatt/prov.c | 9 ++-
> tools/mesh/agent.c | 21 +++--
> tools/mesh/agent.h | 4 +-
> 6 files changed, 233 insertions(+), 60 deletions(-)

Thanks for the patches. I have just tried them and I confirm it fixes
output OOB with number. Output OOB with string still doesn't work. I
came up with this patch to fix it:

diff --git a/mesh/agent.c b/mesh/agent.c
index 623f2faf0..e5545d7f3 100644
--- a/mesh/agent.c
+++ b/mesh/agent.c
@@ -604,7 +604,7 @@ int mesh_agent_prompt_number(struct mesh_agent *agent, bool initiator,
int mesh_agent_prompt_alpha(struct mesh_agent *agent, mesh_agent_key_cb_t cb,
void *user_data)
{
- return prompt_input(agent, "in-alpha", MESH_AGENT_REQUEST_IN_ALPHA,
+ return prompt_input(agent, "out-alpha", MESH_AGENT_REQUEST_OUT_ALPHA,
false, cb, user_data);
}

Aurelien

--
Aurelien Jarno GPG: 4096R/1DDD8C9B
[email protected] http://www.aurel32.net