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