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