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 }