1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include <stdint.h>
21 #include <string.h>
22 #include "securec.h"
23 #include "sysinit/sysinit.h"
24 #include "syscfg/syscfg.h"
25 #include "host/ble_hs.h"
26 #include "ble_store_config_priv.h"
27 #include "store/config/ble_store_config.h"
28
29 struct ble_store_value_sec ble_store_config_our_secs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
30 int ble_store_config_num_our_secs;
31
32 struct ble_store_value_sec ble_store_config_peer_secs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
33 int ble_store_config_num_peer_secs;
34
35 struct ble_store_value_cccd ble_store_config_cccds[MYNEWT_VAL(BLE_STORE_MAX_CCCDS)*MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
36 int ble_store_config_num_cccds;
37
38 /*****************************************************************************
39 * $sec *
40 *****************************************************************************/
41
ble_store_config_print_value_sec(const struct ble_store_value_sec * sec)42 static void ble_store_config_print_value_sec(const struct ble_store_value_sec *sec)
43 {
44 BLE_HS_LOG(DEBUG, "addr=");
45 ble_hs_log_flat_buf(sec->peer_addr.val, 6); // 6:len
46 BLE_HS_LOG(DEBUG, "peer_addr_type=%d ", sec->peer_addr.type);
47
48 if (sec->ltk_present) {
49 BLE_HS_LOG(DEBUG, "ediv=%u rand=%llu authenticated=%d ltk=",
50 sec->ediv, sec->rand_num, sec->authenticated);
51 ble_hs_log_flat_buf(sec->ltk, 16); // 16:len
52 BLE_HS_LOG(DEBUG, " ");
53 }
54
55 if (sec->irk_present) {
56 BLE_HS_LOG(DEBUG, "irk=");
57 ble_hs_log_flat_buf(sec->irk, 16); // 16:len
58 BLE_HS_LOG(DEBUG, " ");
59 }
60
61 if (sec->csrk_present) {
62 BLE_HS_LOG(DEBUG, "csrk=");
63 ble_hs_log_flat_buf(sec->csrk, 16); // 16:len
64 BLE_HS_LOG(DEBUG, " ");
65 }
66
67 BLE_HS_LOG(DEBUG, "\n");
68 }
69
ble_store_config_print_key_sec(const struct ble_store_key_sec * key_sec)70 static void ble_store_config_print_key_sec(const struct ble_store_key_sec *key_sec)
71 {
72 if (ble_addr_cmp(&key_sec->peer_addr, BLE_ADDR_ANY)) {
73 BLE_HS_LOG(DEBUG, "peer_addr_type=%d peer_addr=",
74 key_sec->peer_addr.type);
75 ble_hs_log_flat_buf(key_sec->peer_addr.val, 6); // 6:len
76 BLE_HS_LOG(DEBUG, " ");
77 }
78
79 if (key_sec->ediv_rand_present) {
80 BLE_HS_LOG(DEBUG, "ediv=0x%02x rand=0x%llx ",
81 key_sec->ediv, key_sec->rand_num);
82 }
83 }
ble_store_config_print_key_cccd(const struct ble_store_key_cccd * key_ccd)84 static void ble_store_config_print_key_cccd(const struct ble_store_key_cccd *key_ccd)
85 {
86 if (ble_addr_cmp(&key_ccd->peer_addr, BLE_ADDR_ANY)) {
87 BLE_HS_LOG(DEBUG, "peer_addr_type=%d peer_addr=",
88 key_ccd->peer_addr.type);
89 ble_hs_log_flat_buf(key_ccd->peer_addr.val, 6); // 6:len
90 BLE_HS_LOG(DEBUG, " ");
91 }
92
93 BLE_HS_LOG(DEBUG, "%d(0x%04x) %d(0x%04x)\r\n",
94 key_ccd->chr_val_handle, key_ccd->chr_val_handle, key_ccd->idx, key_ccd->idx);
95 }
96
ble_store_config_find_sec(const struct ble_store_key_sec * key_sec,const struct ble_store_value_sec * value_secs,int num_value_secs)97 static int ble_store_config_find_sec(const struct ble_store_key_sec *key_sec,
98 const struct ble_store_value_sec *value_secs,
99 int num_value_secs)
100 {
101 const struct ble_store_value_sec *cur;
102 int skipped;
103 int i;
104 skipped = 0;
105
106 for (i = 0; i < num_value_secs; i++) {
107 cur = value_secs + i;
108
109 if (ble_addr_cmp(&key_sec->peer_addr, BLE_ADDR_ANY)) {
110 if (ble_addr_cmp(&cur->peer_addr, &key_sec->peer_addr)) {
111 continue;
112 }
113 }
114
115 if (key_sec->ediv_rand_present) {
116 if (cur->ediv != key_sec->ediv) {
117 continue;
118 }
119
120 if (cur->rand_num != key_sec->rand_num) {
121 continue;
122 }
123 }
124
125 if (key_sec->idx > skipped) {
126 skipped++;
127 continue;
128 }
129
130 return i;
131 }
132
133 return -1;
134 }
135
ble_store_config_read_our_sec(const struct ble_store_key_sec * key_sec,struct ble_store_value_sec * value_sec)136 static int ble_store_config_read_our_sec(const struct ble_store_key_sec *key_sec,
137 struct ble_store_value_sec *value_sec)
138 {
139 int idx;
140 idx = ble_store_config_find_sec(key_sec, ble_store_config_our_secs,
141 ble_store_config_num_our_secs);
142 if (idx == -1) {
143 return BLE_HS_ENOENT;
144 }
145
146 *value_sec = ble_store_config_our_secs[idx];
147 return 0;
148 }
149
ble_store_config_write_our_sec(const struct ble_store_value_sec * value_sec)150 static int ble_store_config_write_our_sec(const struct ble_store_value_sec *value_sec)
151 {
152 struct ble_store_key_sec key_sec;
153 int idx;
154 int rc;
155 BLE_HS_LOG(DEBUG, "persisting our sec; ");
156 ble_store_config_print_value_sec(value_sec);
157 ble_store_key_from_value_sec(&key_sec, value_sec);
158 idx = ble_store_config_find_sec(&key_sec, ble_store_config_our_secs,
159 ble_store_config_num_our_secs);
160 if (idx == -1) {
161 if (ble_store_config_num_our_secs >= MYNEWT_VAL(BLE_STORE_MAX_BONDS)) {
162 BLE_HS_LOG(DEBUG, "error persisting our sec; too many entries "
163 "(%d)\n", ble_store_config_num_our_secs);
164 return BLE_HS_ESTORE_CAP;
165 }
166
167 idx = ble_store_config_num_our_secs;
168 ble_store_config_num_our_secs++;
169 }
170
171 ble_store_config_our_secs[idx] = *value_sec;
172 rc = ble_store_config_persist_our_secs(true);
173 if (rc != 0) {
174 return rc;
175 }
176
177 return 0;
178 }
179
ble_store_config_delete_obj(void * values,int value_size,int idx,int * num_values)180 static int ble_store_config_delete_obj(void *values, int value_size, int idx, int *num_values)
181 {
182 uint8_t *dst;
183
184 (*num_values)--;
185
186 if (idx < *num_values) {
187 dst = values;
188 dst += idx * value_size;
189 uint8_t *src = dst + value_size;
190 int move_count = *num_values - idx;
191 memmove_s(dst, sizeof(*dst), src, move_count * value_size);
192 }
193
194 return 0;
195 }
196
ble_store_config_delete_sec(const struct ble_store_key_sec * key_sec,struct ble_store_value_sec * value_secs,int * num_value_secs)197 static int ble_store_config_delete_sec(const struct ble_store_key_sec *key_sec,
198 struct ble_store_value_sec *value_secs,
199 int *num_value_secs)
200 {
201 int idx;
202 int rc;
203 idx = ble_store_config_find_sec(key_sec, value_secs, *num_value_secs);
204 if (idx == -1) {
205 return BLE_HS_ENOENT;
206 }
207
208 rc = ble_store_config_delete_obj(value_secs, sizeof * value_secs, idx,
209 num_value_secs);
210 if (rc != 0) {
211 return rc;
212 }
213
214 return 0;
215 }
216
ble_store_config_delete_our_sec(const struct ble_store_key_sec * key_sec)217 static int ble_store_config_delete_our_sec(const struct ble_store_key_sec *key_sec)
218 {
219 int rc;
220 rc = ble_store_config_delete_sec(key_sec, ble_store_config_our_secs,
221 &ble_store_config_num_our_secs);
222 if (rc != 0) {
223 return rc;
224 }
225
226 return 0;
227 }
228
ble_store_config_delete_peer_sec(const struct ble_store_key_sec * key_sec)229 static int ble_store_config_delete_peer_sec(const struct ble_store_key_sec *key_sec)
230 {
231 int rc;
232 rc = ble_store_config_delete_sec(key_sec, ble_store_config_peer_secs,
233 &ble_store_config_num_peer_secs);
234 if (rc != 0) {
235 return rc;
236 }
237
238 return 0;
239 }
240
ble_store_config_read_peer_sec(const struct ble_store_key_sec * key_sec,struct ble_store_value_sec * value_sec)241 static int ble_store_config_read_peer_sec(const struct ble_store_key_sec *key_sec,
242 struct ble_store_value_sec *value_sec)
243 {
244 int idx;
245 idx = ble_store_config_find_sec(key_sec, ble_store_config_peer_secs,
246 ble_store_config_num_peer_secs);
247 if (idx == -1) {
248 return BLE_HS_ENOENT;
249 }
250
251 *value_sec = ble_store_config_peer_secs[idx];
252 return 0;
253 }
254
ble_store_config_write_peer_sec(const struct ble_store_value_sec * value_sec)255 static int ble_store_config_write_peer_sec(const struct ble_store_value_sec *value_sec)
256 {
257 struct ble_store_key_sec key_sec;
258 int idx;
259 int rc;
260 BLE_HS_LOG(DEBUG, "persisting peer sec; ");
261 ble_store_config_print_value_sec(value_sec);
262 ble_store_key_from_value_sec(&key_sec, value_sec);
263 idx = ble_store_config_find_sec(&key_sec, ble_store_config_peer_secs,
264 ble_store_config_num_peer_secs);
265 if (idx == -1) {
266 if (ble_store_config_num_peer_secs >= MYNEWT_VAL(BLE_STORE_MAX_BONDS)) {
267 BLE_HS_LOG(DEBUG, "error persisting peer sec; too many entries "
268 "(%d)\n", ble_store_config_num_peer_secs);
269 return BLE_HS_ESTORE_CAP;
270 }
271
272 idx = ble_store_config_num_peer_secs;
273 ble_store_config_num_peer_secs++;
274 }
275
276 ble_store_config_peer_secs[idx] = *value_sec;
277 rc = ble_store_config_persist_peer_secs(true);
278 if (rc != 0) {
279 return rc;
280 }
281
282 return 0;
283 }
284
285 /*****************************************************************************
286 * $cccd *
287 *****************************************************************************/
288
ble_store_config_find_cccd(const struct ble_store_key_cccd * key)289 static int ble_store_config_find_cccd(const struct ble_store_key_cccd *key)
290 {
291 struct ble_store_value_cccd *cccd;
292 int skipped;
293 int i;
294 skipped = 0;
295
296 for (i = 0; i < ble_store_config_num_cccds; i++) {
297 cccd = ble_store_config_cccds + i;
298
299 if (ble_addr_cmp(&key->peer_addr, BLE_ADDR_ANY)) {
300 if (ble_addr_cmp(&cccd->peer_addr, &key->peer_addr)) {
301 continue;
302 }
303 }
304
305 if (key->chr_val_handle != 0) {
306 if (cccd->chr_val_handle != key->chr_val_handle) {
307 continue;
308 }
309 }
310
311 if (key->idx > skipped) {
312 skipped++;
313 continue;
314 }
315
316 return i;
317 }
318
319 return -1;
320 }
321
ble_store_config_delete_cccd(const struct ble_store_key_cccd * key_cccd)322 static int ble_store_config_delete_cccd(const struct ble_store_key_cccd *key_cccd)
323 {
324 int idx;
325 int rc;
326 idx = ble_store_config_find_cccd(key_cccd);
327 if (idx == -1) {
328 return BLE_HS_ENOENT;
329 }
330
331 rc = ble_store_config_delete_obj(ble_store_config_cccds,
332 sizeof * ble_store_config_cccds,
333 idx,
334 &ble_store_config_num_cccds);
335 if (rc != 0) {
336 return rc;
337 }
338
339 return 0;
340 }
341
ble_store_config_read_cccd(const struct ble_store_key_cccd * key_cccd,struct ble_store_value_cccd * value_cccd)342 static int ble_store_config_read_cccd(const struct ble_store_key_cccd *key_cccd,
343 struct ble_store_value_cccd *value_cccd)
344 {
345 int idx;
346 idx = ble_store_config_find_cccd(key_cccd);
347 if (idx == -1) {
348 return BLE_HS_ENOENT;
349 }
350
351 *value_cccd = ble_store_config_cccds[idx];
352 return 0;
353 }
354
ble_store_config_write_cccd(const struct ble_store_value_cccd * value_cccd)355 static int ble_store_config_write_cccd(const struct ble_store_value_cccd *value_cccd)
356 {
357 return 0;
358 }
359
360 /*****************************************************************************
361 * $api *
362 *****************************************************************************/
363
364 /**
365 * Searches the database for an object matching the specified criteria.
366 *
367 * @return 0 if a key was found; else BLE_HS_ENOENT.
368 */
ble_store_config_read(int obj_type,const union ble_store_key * key,union ble_store_value * value)369 int ble_store_config_read(int obj_type, const union ble_store_key *key,
370 union ble_store_value *value)
371 {
372 int rc;
373
374 switch (obj_type) {
375 case BLE_STORE_OBJ_TYPE_PEER_SEC:
376 /* An encryption procedure (bonding) is being attempted. The nimble
377 * stack is asking us to look in our key database for a long-term key
378 * corresponding to the specified ediv and random number.
379 *
380 * Perform a key lookup and populate the context object with the
381 * result. The nimble stack will use this key if this function returns
382 * success.
383 */
384 BLE_HS_LOG(DEBUG, "looking up peer sec; ");
385 ble_store_config_print_key_sec(&key->sec);
386 BLE_HS_LOG(DEBUG, "\n");
387 rc = ble_store_config_read_peer_sec(&key->sec, &value->sec);
388 return rc;
389
390 case BLE_STORE_OBJ_TYPE_OUR_SEC:
391 BLE_HS_LOG(DEBUG, "looking up our sec; ");
392 ble_store_config_print_key_sec(&key->sec);
393 BLE_HS_LOG(DEBUG, "\n");
394 rc = ble_store_config_read_our_sec(&key->sec, &value->sec);
395 return rc;
396
397 case BLE_STORE_OBJ_TYPE_CCCD:
398 BLE_HS_LOG(DEBUG, "looking up xxxx ccd; ");
399 ble_store_config_print_key_cccd(&key->cccd);
400 BLE_HS_LOG(DEBUG, "\n");
401 rc = ble_store_config_read_cccd(&key->cccd, &value->cccd);
402 return rc;
403
404 default:
405 return BLE_HS_ENOTSUP;
406 }
407 }
408
409 /**
410 * Adds the specified object to the database.
411 *
412 * @return 0 on success;
413 * BLE_HS_ESTORE_CAP if the database is full.
414 */
ble_store_config_write(int obj_type,const union ble_store_value * val)415 int ble_store_config_write(int obj_type, const union ble_store_value *val)
416 {
417 int rc;
418
419 switch (obj_type) {
420 case BLE_STORE_OBJ_TYPE_PEER_SEC:
421 rc = ble_store_config_write_peer_sec(&val->sec);
422 return rc;
423
424 case BLE_STORE_OBJ_TYPE_OUR_SEC:
425 rc = ble_store_config_write_our_sec(&val->sec);
426 return rc;
427
428 case BLE_STORE_OBJ_TYPE_CCCD:
429 rc = ble_store_config_write_cccd(&val->cccd);
430 return rc;
431
432 default:
433 return BLE_HS_ENOTSUP;
434 }
435 }
436
ble_store_config_delete(int obj_type,const union ble_store_key * key)437 int ble_store_config_delete(int obj_type, const union ble_store_key *key)
438 {
439 int rc;
440
441 switch (obj_type) {
442 case BLE_STORE_OBJ_TYPE_PEER_SEC:
443 rc = ble_store_config_delete_peer_sec(&key->sec);
444 return rc;
445
446 case BLE_STORE_OBJ_TYPE_OUR_SEC:
447 rc = ble_store_config_delete_our_sec(&key->sec);
448 return rc;
449
450 case BLE_STORE_OBJ_TYPE_CCCD:
451 rc = ble_store_config_delete_cccd(&key->cccd);
452 return rc;
453
454 default:
455 return BLE_HS_ENOTSUP;
456 }
457 }
458
ble_store_config_flush(void)459 int ble_store_config_flush(void)
460 {
461 int rc;
462
463 /* Erase all saved in nvram */
464 rc = ble_store_config_delete_all();
465 if (rc != 0) {
466 return rc;
467 }
468 rc = ble_store_config_persist_peer_secs(false);
469 if (rc != 0) {
470 return rc;
471 }
472
473 rc = ble_store_config_persist_our_secs(false);
474 if (rc != 0) {
475 return rc;
476 }
477
478 rc = ble_store_config_persist_cccds(false);
479 if (rc != 0) {
480 return rc;
481 }
482
483 ble_store_config_persist_flush();
484
485 return 0;
486 }
487
ble_store_config_init(void)488 void ble_store_config_init(void)
489 {
490 /* Ensure this function only gets called by sysinit. */
491 SYSINIT_ASSERT_ACTIVE();
492 ble_hs_cfg.store_read_cb = ble_store_config_read;
493 ble_hs_cfg.store_write_cb = ble_store_config_write;
494 ble_hs_cfg.store_delete_cb = ble_store_config_delete;
495 ble_hs_cfg.store_flush_cb = ble_store_config_flush;
496 /* Re-initialize BSS values in case of unit tests. */
497 ble_store_config_num_our_secs = 0;
498 ble_store_config_num_peer_secs = 0;
499 ble_store_config_num_cccds = 0;
500 ble_store_config_conf_init();
501 }
ble_store_config_deinit(void)502 void ble_store_config_deinit(void)
503 {
504 ble_store_config_conf_deinit();
505 }