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