diff --git a/subsys/bluetooth/mesh/prov.c b/subsys/bluetooth/mesh/prov.c index 0b0a27268c9..0cbb360cbc4 100644 --- a/subsys/bluetooth/mesh/prov.c +++ b/subsys/bluetooth/mesh/prov.c @@ -107,10 +107,98 @@ static bt_mesh_input_action_t input_action(uint8_t action) } } -int bt_mesh_prov_auth(uint8_t method, uint8_t action, uint8_t size) +static int check_output_auth(bt_mesh_output_action_t output, uint8_t size) +{ + if (!output) { + return -EINVAL; + } + + if (!(bt_mesh_prov->output_actions & output)) { + return -EINVAL; + } + + if (size > bt_mesh_prov->output_size) { + return -EINVAL; + } + + return 0; +} + +static int check_input_auth(bt_mesh_input_action_t input, uint8_t size) +{ + if (!input) { + return -EINVAL; + } + + if (!(bt_mesh_prov->input_actions & input)) { + return -EINVAL; + } + + if (size > bt_mesh_prov->input_size) { + return -EINVAL; + } + + return 0; +} + +static void get_auth_string(char *str, uint8_t size) +{ + uint64_t value; + + bt_rand(&value, sizeof(value)); + + static const char characters[36] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + for (int i = 0; i < size; i++) { + /* pull base-36 digits: */ + int idx = value % 36; + + value = value / 36; + str[i] = characters[idx]; + } + + str[size] = '\0'; + + memcpy(bt_mesh_prov_link.auth, str, size); + memset(bt_mesh_prov_link.auth + size, 0, + sizeof(bt_mesh_prov_link.auth) - size); +} + +static uint32_t get_auth_number(bt_mesh_output_action_t output, + bt_mesh_input_action_t input, uint8_t size) +{ + const uint32_t divider[PROV_IO_OOB_SIZE_MAX] = { 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000 }; + uint32_t num = 0; + + bt_rand(&num, sizeof(num)); + + if (output == BT_MESH_BLINK || + output == BT_MESH_BEEP || + output == BT_MESH_VIBRATE || + input == BT_MESH_PUSH || + input == BT_MESH_TWIST) { + /* According to the Bluetooth Mesh Profile + * Specification Section 5.4.2.4, blink, beep + * vibrate, push and twist should be a random integer + * between 0 and 10^size, *exclusive*: + */ + num = (num % (divider[size - 1] - 1)) + 1; + } else { + num %= divider[size - 1]; + } + + sys_put_be32(num, &bt_mesh_prov_link.auth[12]); + memset(bt_mesh_prov_link.auth, 0, 12); + + return num; +} + +int bt_mesh_prov_auth(bool is_provisioner, uint8_t method, uint8_t action, uint8_t size) { bt_mesh_output_action_t output; bt_mesh_input_action_t input; + int err; switch (method) { case AUTH_METHOD_NO_OOB: @@ -131,89 +219,66 @@ int bt_mesh_prov_auth(uint8_t method, uint8_t action, uint8_t size) case AUTH_METHOD_OUTPUT: output = output_action(action); - if (!output) { - return -EINVAL; + + if (is_provisioner) { + if (output == BT_MESH_DISPLAY_STRING) { + input = BT_MESH_ENTER_STRING; + atomic_set_bit(bt_mesh_prov_link.flags, WAIT_STRING); + } else { + input = BT_MESH_ENTER_NUMBER; + atomic_set_bit(bt_mesh_prov_link.flags, WAIT_NUMBER); + } + + return bt_mesh_prov->input(input, size); } - if (!(bt_mesh_prov->output_actions & output)) { - return -EINVAL; + err = check_output_auth(output, size); + if (err) { + return err; } - if (size > bt_mesh_prov->output_size) { - return -EINVAL; + if (output == BT_MESH_DISPLAY_STRING) { + char str[9]; + + atomic_set_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE); + get_auth_string(str, size); + return bt_mesh_prov->output_string(str); } atomic_set_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE); - - if (output == BT_MESH_DISPLAY_STRING) { - unsigned char str[9]; - uint8_t i; - - bt_rand(str, size); - - /* Normalize to '0' .. '9' & 'A' .. 'Z' */ - for (i = 0U; i < size; i++) { - str[i] %= 36; - if (str[i] < 10) { - str[i] += '0'; - } else { - str[i] += 'A' - 10; - } - } - str[size] = '\0'; - - memcpy(bt_mesh_prov_link.auth, str, size); - (void)memset(bt_mesh_prov_link.auth + size, 0, - sizeof(bt_mesh_prov_link.auth) - size); - - return bt_mesh_prov->output_string((char *)str); - } else { - uint32_t div[8] = { 10, 100, 1000, 10000, 100000, - 1000000, 10000000, 100000000 }; - uint32_t num; - - bt_rand(&num, sizeof(num)); - - if (output == BT_MESH_BLINK || - output == BT_MESH_BEEP || - output == BT_MESH_VIBRATE) { - /* According to the Bluetooth Mesh Profile - * Specification Section 5.4.2.4, blink, beep - * and vibrate should be a random integer - * between 0 and 10^size, *exclusive*: - */ - num = (num % (div[size - 1] - 1)) + 1; - } else { - num %= div[size - 1]; - } - - sys_put_be32(num, &bt_mesh_prov_link.auth[12]); - (void)memset(bt_mesh_prov_link.auth, 0, 12); - - return bt_mesh_prov->output_number(output, num); - } + return bt_mesh_prov->output_number(output, + get_auth_number(output, BT_MESH_NO_INPUT, size)); case AUTH_METHOD_INPUT: input = input_action(action); - if (!input) { - return -EINVAL; - } - if (!(bt_mesh_prov->input_actions & input)) { - return -EINVAL; - } + if (!is_provisioner) { + err = check_input_auth(input, size); + if (err) { + return err; + } - if (size > bt_mesh_prov->input_size) { - return -EINVAL; + if (input == BT_MESH_ENTER_STRING) { + atomic_set_bit(bt_mesh_prov_link.flags, WAIT_STRING); + } else { + atomic_set_bit(bt_mesh_prov_link.flags, WAIT_NUMBER); + } + + return bt_mesh_prov->input(input, size); } if (input == BT_MESH_ENTER_STRING) { - atomic_set_bit(bt_mesh_prov_link.flags, WAIT_STRING); - } else { - atomic_set_bit(bt_mesh_prov_link.flags, WAIT_NUMBER); + char str[9]; + + atomic_set_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE); + get_auth_string(str, size); + return bt_mesh_prov->output_string(str); } - return bt_mesh_prov->input(input, size); + atomic_set_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE); + output = BT_MESH_DISPLAY_NUMBER; + return bt_mesh_prov->output_number(output, + get_auth_number(BT_MESH_NO_OUTPUT, input, size)); default: return -EINVAL; @@ -239,11 +304,16 @@ int bt_mesh_input_string(const char *str) { BT_DBG("%s", log_strdup(str)); + if (strlen(str) > PROV_IO_OOB_SIZE_MAX || + strlen(str) > bt_mesh_prov_link.oob_size) { + return -ENOTSUP; + } + if (!atomic_test_and_clear_bit(bt_mesh_prov_link.flags, WAIT_STRING)) { return -EINVAL; } - strncpy((char *)bt_mesh_prov_link.auth, str, bt_mesh_prov->input_size); + strcpy((char *)bt_mesh_prov_link.auth, str); bt_mesh_prov_link.role->input_complete(); diff --git a/subsys/bluetooth/mesh/prov.h b/subsys/bluetooth/mesh/prov.h index 4de7dba84d1..733da1062dc 100644 --- a/subsys/bluetooth/mesh/prov.h +++ b/subsys/bluetooth/mesh/prov.h @@ -67,6 +67,8 @@ #define PROV_ALG_P256 0x00 +#define PROV_IO_OOB_SIZE_MAX 8 /* in bytes */ + #define PROV_BUF(name, len) \ NET_BUF_SIMPLE_DEFINE(name, PROV_BEARER_BUF_HEADROOM + PDU_OP_LEN + len) @@ -151,7 +153,7 @@ int bt_mesh_prov_reset_state(void (*func)(const uint8_t key[BT_PUB_KEY_LEN])); bool bt_mesh_prov_active(void); -int bt_mesh_prov_auth(uint8_t method, uint8_t action, uint8_t size); +int bt_mesh_prov_auth(bool is_provisioner, uint8_t method, uint8_t action, uint8_t size); int bt_mesh_pb_gatt_open(struct bt_conn *conn); int bt_mesh_pb_gatt_close(struct bt_conn *conn); diff --git a/subsys/bluetooth/mesh/prov_device.c b/subsys/bluetooth/mesh/prov_device.c index 2bba13aa646..b6c38ab6174 100644 --- a/subsys/bluetooth/mesh/prov_device.c +++ b/subsys/bluetooth/mesh/prov_device.c @@ -150,8 +150,11 @@ static void prov_start(const uint8_t *data) memcpy(bt_mesh_prov_link.conf_inputs.start, data, PDU_LEN_START); bt_mesh_prov_link.expect = PROV_PUB_KEY; + bt_mesh_prov_link.oob_method = data[2]; + bt_mesh_prov_link.oob_action = data[3]; + bt_mesh_prov_link.oob_size = data[4]; - if (bt_mesh_prov_auth(data[2], data[3], data[4]) < 0) { + if (bt_mesh_prov_auth(false, data[2], data[3], data[4]) < 0) { BT_ERR("Invalid authentication method: 0x%02x; " "action: 0x%02x; size: 0x%02x", data[2], data[3], data[4]); diff --git a/subsys/bluetooth/mesh/provisioner.c b/subsys/bluetooth/mesh/provisioner.c index 7913b05d34c..dcc07f3cbd7 100644 --- a/subsys/bluetooth/mesh/provisioner.c +++ b/subsys/bluetooth/mesh/provisioner.c @@ -109,7 +109,6 @@ static void start_sent(int err, void *cb_data) static void send_start(void) { BT_DBG(""); - uint8_t method, action; PROV_BUF(start, PDU_LEN_START); @@ -125,26 +124,6 @@ static void send_start(void) net_buf_simple_add_u8(&start, PUB_KEY_NO_OOB); } - if (bt_mesh_prov_link.oob_method == AUTH_METHOD_INPUT) { - method = AUTH_METHOD_OUTPUT; - if (bt_mesh_prov_link.oob_action == INPUT_OOB_STRING) { - action = OUTPUT_OOB_STRING; - } else { - action = OUTPUT_OOB_NUMBER; - } - - } else if (bt_mesh_prov_link.oob_method == AUTH_METHOD_OUTPUT) { - method = AUTH_METHOD_INPUT; - if (bt_mesh_prov_link.oob_action == OUTPUT_OOB_STRING) { - action = INPUT_OOB_STRING; - } else { - action = INPUT_OOB_NUMBER; - } - } else { - method = bt_mesh_prov_link.oob_method; - action = 0x00; - } - net_buf_simple_add_u8(&start, bt_mesh_prov_link.oob_method); net_buf_simple_add_u8(&start, bt_mesh_prov_link.oob_action); @@ -153,10 +132,11 @@ static void send_start(void) memcpy(bt_mesh_prov_link.conf_inputs.start, &start.data[1], PDU_LEN_START); - if (bt_mesh_prov_auth(method, action, bt_mesh_prov_link.oob_size) < 0) { + if (bt_mesh_prov_auth(true, bt_mesh_prov_link.oob_method, + bt_mesh_prov_link.oob_action, bt_mesh_prov_link.oob_size) < 0) { BT_ERR("Invalid authentication method: 0x%02x; " - "action: 0x%02x; size: 0x%02x", method, - action, bt_mesh_prov_link.oob_size); + "action: 0x%02x; size: 0x%02x", bt_mesh_prov_link.oob_method, + bt_mesh_prov_link.oob_action, bt_mesh_prov_link.oob_size); return; } @@ -691,7 +671,7 @@ static void prov_set_method(uint8_t method, uint8_t action, uint8_t size) int bt_mesh_auth_method_set_input(bt_mesh_input_action_t action, uint8_t size) { - if (!action || !size || size > 8) { + if (!action || !size || size > PROV_IO_OOB_SIZE_MAX) { return -EINVAL; } @@ -701,7 +681,7 @@ int bt_mesh_auth_method_set_input(bt_mesh_input_action_t action, uint8_t size) int bt_mesh_auth_method_set_output(bt_mesh_output_action_t action, uint8_t size) { - if (!action || !size || size > 8) { + if (!action || !size || size > PROV_IO_OOB_SIZE_MAX) { return -EINVAL; }