1 /*
2 * Copyright (c) 2017 Intel Corporation
3 * Copyright (c) 2020 Lingao Meng
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/kernel.h>
9 #include <errno.h>
10 #include <zephyr/sys/atomic.h>
11 #include <zephyr/sys/util.h>
12 #include <zephyr/sys/byteorder.h>
13
14 #include <zephyr/net/buf.h>
15 #include <zephyr/bluetooth/bluetooth.h>
16 #include <zephyr/bluetooth/conn.h>
17 #include <zephyr/bluetooth/mesh.h>
18 #include <zephyr/bluetooth/uuid.h>
19
20 #include "crypto.h"
21 #include "mesh.h"
22 #include "net.h"
23 #include "access.h"
24 #include "foundation.h"
25 #include "prov.h"
26
27 #define LOG_LEVEL CONFIG_BT_MESH_PROV_LOG_LEVEL
28 #include <zephyr/logging/log.h>
29 LOG_MODULE_REGISTER(bt_mesh_prov);
30
31 struct bt_mesh_prov_link bt_mesh_prov_link;
32 const struct bt_mesh_prov *bt_mesh_prov;
33
34 /* Verify specification defined length: */
35 BUILD_ASSERT(sizeof(bt_mesh_prov_link.conf_inputs) == 145,
36 "Confirmation inputs shall be 145 bytes");
37
bt_mesh_prov_reset_state(void)38 int bt_mesh_prov_reset_state(void)
39 {
40 int err;
41 const size_t offset = offsetof(struct bt_mesh_prov_link, addr);
42
43 atomic_clear(bt_mesh_prov_link.flags);
44 (void)memset((uint8_t *)&bt_mesh_prov_link + offset, 0,
45 sizeof(bt_mesh_prov_link) - offset);
46
47 err = bt_mesh_pub_key_gen();
48 if (err) {
49 LOG_ERR("Failed to generate public key (%d)", err);
50 return err;
51 }
52 return 0;
53 }
54
output_action(uint8_t action)55 static bt_mesh_output_action_t output_action(uint8_t action)
56 {
57 switch (action) {
58 case OUTPUT_OOB_BLINK:
59 return BT_MESH_BLINK;
60 case OUTPUT_OOB_BEEP:
61 return BT_MESH_BEEP;
62 case OUTPUT_OOB_VIBRATE:
63 return BT_MESH_VIBRATE;
64 case OUTPUT_OOB_NUMBER:
65 return BT_MESH_DISPLAY_NUMBER;
66 case OUTPUT_OOB_STRING:
67 return BT_MESH_DISPLAY_STRING;
68 default:
69 return BT_MESH_NO_OUTPUT;
70 }
71 }
72
input_action(uint8_t action)73 static bt_mesh_input_action_t input_action(uint8_t action)
74 {
75 switch (action) {
76 case INPUT_OOB_PUSH:
77 return BT_MESH_PUSH;
78 case INPUT_OOB_TWIST:
79 return BT_MESH_TWIST;
80 case INPUT_OOB_NUMBER:
81 return BT_MESH_ENTER_NUMBER;
82 case INPUT_OOB_STRING:
83 return BT_MESH_ENTER_STRING;
84 default:
85 return BT_MESH_NO_INPUT;
86 }
87 }
88
check_output_auth(bt_mesh_output_action_t output,uint8_t size)89 static int check_output_auth(bt_mesh_output_action_t output, uint8_t size)
90 {
91 if (!output) {
92 return -EINVAL;
93 }
94
95 if (!(bt_mesh_prov->output_actions & output)) {
96 return -EINVAL;
97 }
98
99 if (size > bt_mesh_prov->output_size) {
100 return -EINVAL;
101 }
102
103 return 0;
104 }
105
check_input_auth(bt_mesh_input_action_t input,uint8_t size)106 static int check_input_auth(bt_mesh_input_action_t input, uint8_t size)
107 {
108 if (!input) {
109 return -EINVAL;
110 }
111
112 if (!(bt_mesh_prov->input_actions & input)) {
113 return -EINVAL;
114 }
115
116 if (size > bt_mesh_prov->input_size) {
117 return -EINVAL;
118 }
119
120 return 0;
121 }
122
get_auth_string(char * str,uint8_t size)123 static void get_auth_string(char *str, uint8_t size)
124 {
125 uint64_t value;
126
127 bt_rand(&value, sizeof(value));
128
129 static const char characters[36] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
130
131 for (int i = 0; i < size; i++) {
132 /* pull base-36 digits: */
133 int idx = value % 36;
134
135 value = value / 36;
136 str[i] = characters[idx];
137 }
138
139 str[size] = '\0';
140
141 memcpy(bt_mesh_prov_link.auth, str, size);
142 memset(bt_mesh_prov_link.auth + size, 0,
143 sizeof(bt_mesh_prov_link.auth) - size);
144 }
145
get_auth_number(bt_mesh_output_action_t output,bt_mesh_input_action_t input,uint8_t size)146 static uint32_t get_auth_number(bt_mesh_output_action_t output,
147 bt_mesh_input_action_t input, uint8_t size)
148 {
149 const uint32_t divider[PROV_IO_OOB_SIZE_MAX] = { 10, 100, 1000, 10000,
150 100000, 1000000, 10000000, 100000000 };
151 uint8_t auth_size = bt_mesh_prov_auth_size_get();
152 uint32_t num = 0;
153
154 bt_rand(&num, sizeof(num));
155
156 if (output == BT_MESH_BLINK || output == BT_MESH_BEEP || output == BT_MESH_VIBRATE ||
157 input == BT_MESH_PUSH || input == BT_MESH_TWIST) {
158 /* According to MshPRTv1.1: 5.4.2.4, blink, beep vibrate, push and twist should be
159 * a random integer between 0 and 10^size, *exclusive*:
160 */
161 num = (num % (divider[size - 1] - 1)) + 1;
162 } else {
163 num %= divider[size - 1];
164 }
165
166 sys_put_be32(num, &bt_mesh_prov_link.auth[auth_size - sizeof(num)]);
167 memset(bt_mesh_prov_link.auth, 0, auth_size - sizeof(num));
168
169 return num;
170 }
171
bt_mesh_prov_auth(bool is_provisioner,uint8_t method,uint8_t action,uint8_t size)172 int bt_mesh_prov_auth(bool is_provisioner, uint8_t method, uint8_t action, uint8_t size)
173 {
174 bt_mesh_output_action_t output;
175 bt_mesh_input_action_t input;
176 uint8_t auth_size = bt_mesh_prov_auth_size_get();
177 int err;
178
179 switch (method) {
180 case AUTH_METHOD_NO_OOB:
181 if (action || size) {
182 return -EINVAL;
183 }
184
185 (void)memset(bt_mesh_prov_link.auth, 0, auth_size);
186 return 0;
187 case AUTH_METHOD_STATIC:
188 if (action || size) {
189 return -EINVAL;
190 }
191
192 atomic_set_bit(bt_mesh_prov_link.flags, OOB_STATIC_KEY);
193
194 return 0;
195
196 case AUTH_METHOD_OUTPUT:
197 output = output_action(action);
198
199 if (is_provisioner) {
200 if (output == BT_MESH_DISPLAY_STRING) {
201 input = BT_MESH_ENTER_STRING;
202 atomic_set_bit(bt_mesh_prov_link.flags, WAIT_STRING);
203 } else {
204 input = BT_MESH_ENTER_NUMBER;
205 atomic_set_bit(bt_mesh_prov_link.flags, WAIT_NUMBER);
206 }
207
208 return bt_mesh_prov->input(input, size);
209 }
210
211 err = check_output_auth(output, size);
212 if (err) {
213 return err;
214 }
215
216 if (output == BT_MESH_DISPLAY_STRING) {
217 char str[9];
218
219 atomic_set_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE);
220 get_auth_string(str, size);
221 return bt_mesh_prov->output_string(str);
222 }
223
224 atomic_set_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE);
225 return bt_mesh_prov->output_number(output,
226 get_auth_number(output, BT_MESH_NO_INPUT, size));
227
228 case AUTH_METHOD_INPUT:
229 input = input_action(action);
230
231 if (!is_provisioner) {
232 err = check_input_auth(input, size);
233 if (err) {
234 return err;
235 }
236
237 if (input == BT_MESH_ENTER_STRING) {
238 atomic_set_bit(bt_mesh_prov_link.flags, WAIT_STRING);
239 } else {
240 atomic_set_bit(bt_mesh_prov_link.flags, WAIT_NUMBER);
241 }
242
243 return bt_mesh_prov->input(input, size);
244 }
245
246 if (input == BT_MESH_ENTER_STRING) {
247 char str[9];
248
249 atomic_set_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE);
250 get_auth_string(str, size);
251 return bt_mesh_prov->output_string(str);
252 }
253
254 atomic_set_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE);
255 output = BT_MESH_DISPLAY_NUMBER;
256 return bt_mesh_prov->output_number(output,
257 get_auth_number(BT_MESH_NO_OUTPUT, input, size));
258
259 default:
260 return -EINVAL;
261 }
262 }
263
bt_mesh_input_number(uint32_t num)264 int bt_mesh_input_number(uint32_t num)
265 {
266 uint8_t auth_size = bt_mesh_prov_auth_size_get();
267
268 LOG_DBG("%u", num);
269
270 if (!atomic_test_and_clear_bit(bt_mesh_prov_link.flags, WAIT_NUMBER)) {
271 return -EINVAL;
272 }
273
274 sys_put_be32(num, &bt_mesh_prov_link.auth[auth_size - sizeof(num)]);
275
276 bt_mesh_prov_link.role->input_complete();
277
278 return 0;
279 }
280
bt_mesh_input_string(const char * str)281 int bt_mesh_input_string(const char *str)
282 {
283 LOG_DBG("%s", str);
284
285 if (strlen(str) > PROV_IO_OOB_SIZE_MAX ||
286 strlen(str) > bt_mesh_prov_link.oob_size) {
287 return -ENOTSUP;
288 }
289
290 if (!atomic_test_and_clear_bit(bt_mesh_prov_link.flags, WAIT_STRING)) {
291 return -EINVAL;
292 }
293
294 memcpy(bt_mesh_prov_link.auth, str, strlen(str));
295
296 bt_mesh_prov_link.role->input_complete();
297
298 return 0;
299 }
300
bt_mesh_prov_get(void)301 const struct bt_mesh_prov *bt_mesh_prov_get(void)
302 {
303 return bt_mesh_prov;
304 }
305
bt_mesh_prov_active(void)306 bool bt_mesh_prov_active(void)
307 {
308 return atomic_test_bit(bt_mesh_prov_link.flags, LINK_ACTIVE);
309 }
310
prov_recv(const struct prov_bearer * bearer,void * cb_data,struct net_buf_simple * buf)311 static void prov_recv(const struct prov_bearer *bearer, void *cb_data,
312 struct net_buf_simple *buf)
313 {
314 static const uint8_t op_len[10] = {
315 [PROV_INVITE] = PDU_LEN_INVITE,
316 [PROV_CAPABILITIES] = PDU_LEN_CAPABILITIES,
317 [PROV_START] = PDU_LEN_START,
318 [PROV_PUB_KEY] = PDU_LEN_PUB_KEY,
319 [PROV_INPUT_COMPLETE] = PDU_LEN_INPUT_COMPLETE,
320 [PROV_CONFIRM] = PDU_LEN_CONFIRM,
321 [PROV_RANDOM] = PDU_LEN_RANDOM,
322 [PROV_DATA] = PDU_LEN_DATA,
323 [PROV_COMPLETE] = PDU_LEN_COMPLETE,
324 [PROV_FAILED] = PDU_LEN_FAILED,
325 };
326
327 uint8_t type = buf->data[0];
328
329 LOG_DBG("type 0x%02x len %u", type, buf->len);
330
331 if (type >= ARRAY_SIZE(bt_mesh_prov_link.role->op)) {
332 LOG_ERR("Unknown provisioning PDU type 0x%02x", type);
333 bt_mesh_prov_link.role->error(PROV_ERR_NVAL_PDU);
334 return;
335 }
336
337 if ((type != PROV_FAILED && type != bt_mesh_prov_link.expect) ||
338 !bt_mesh_prov_link.role->op[type]) {
339 LOG_WRN("Unexpected msg 0x%02x != 0x%02x", type, bt_mesh_prov_link.expect);
340 bt_mesh_prov_link.role->error(PROV_ERR_UNEXP_PDU);
341 return;
342 }
343
344 uint8_t expected = 1 + op_len[type];
345
346 if (type == PROV_CONFIRM || type == PROV_RANDOM) {
347 /* Expected length depends on Auth size */
348 expected = 1 + bt_mesh_prov_auth_size_get();
349 }
350
351 if (buf->len != expected) {
352 LOG_ERR("Invalid length %u for type 0x%02x", buf->len, type);
353 bt_mesh_prov_link.role->error(PROV_ERR_NVAL_FMT);
354 return;
355 }
356
357 bt_mesh_prov_link.role->op[type](&buf->data[1]);
358 }
359
prov_link_opened(const struct prov_bearer * bearer,void * cb_data)360 static void prov_link_opened(const struct prov_bearer *bearer, void *cb_data)
361 {
362 atomic_set_bit(bt_mesh_prov_link.flags, LINK_ACTIVE);
363
364 if (bt_mesh_prov->link_open) {
365 bt_mesh_prov->link_open(bearer->type);
366 }
367
368 bt_mesh_prov_link.bearer = bearer;
369
370 if (bt_mesh_prov_link.role->link_opened) {
371 bt_mesh_prov_link.role->link_opened();
372 }
373 }
374
prov_link_closed(const struct prov_bearer * bearer,void * cb_data,enum prov_bearer_link_status reason)375 static void prov_link_closed(const struct prov_bearer *bearer, void *cb_data,
376 enum prov_bearer_link_status reason)
377 {
378 LOG_DBG("%u", reason);
379
380 if (bt_mesh_prov_link.role->link_closed) {
381 bt_mesh_prov_link.role->link_closed(reason);
382 }
383
384 if (bt_mesh_prov->link_close) {
385 bt_mesh_prov->link_close(bearer->type);
386 }
387 }
388
prov_bearer_error(const struct prov_bearer * bearer,void * cb_data,uint8_t err)389 static void prov_bearer_error(const struct prov_bearer *bearer, void *cb_data,
390 uint8_t err)
391 {
392 if (bt_mesh_prov_link.role->error) {
393 bt_mesh_prov_link.role->error(err);
394 }
395 }
396
397 static const struct prov_bearer_cb prov_bearer_cb = {
398 .link_opened = prov_link_opened,
399 .link_closed = prov_link_closed,
400 .error = prov_bearer_error,
401 .recv = prov_recv,
402 };
403
bt_mesh_prov_bearer_cb_get(void)404 const struct prov_bearer_cb *bt_mesh_prov_bearer_cb_get(void)
405 {
406 return &prov_bearer_cb;
407 }
408
bt_mesh_prov_complete(uint16_t net_idx,uint16_t addr)409 void bt_mesh_prov_complete(uint16_t net_idx, uint16_t addr)
410 {
411 if (bt_mesh_prov->complete) {
412 bt_mesh_prov->complete(net_idx, addr);
413 }
414 }
415
bt_mesh_prov_reset(void)416 void bt_mesh_prov_reset(void)
417 {
418 if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV)) {
419 bt_mesh_pb_adv_reset();
420 }
421
422 if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) {
423 bt_mesh_pb_gatt_reset();
424 }
425
426 bt_mesh_prov_reset_state();
427
428 if (bt_mesh_prov->reset) {
429 bt_mesh_prov->reset();
430 }
431 }
432
bt_mesh_prov_init(const struct bt_mesh_prov * prov_info)433 int bt_mesh_prov_init(const struct bt_mesh_prov *prov_info)
434 {
435 if (!prov_info) {
436 LOG_ERR("No provisioning context provided");
437 return -EINVAL;
438 }
439
440 bt_mesh_prov = prov_info;
441
442 if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV)) {
443 bt_mesh_pb_adv_init();
444 }
445
446 if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) {
447 bt_mesh_pb_gatt_init();
448 }
449
450 return bt_mesh_prov_reset_state();
451 }
452