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