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 * L2CAP Security Manager (channel ID = 6).
22 *
23 * Design overview:
24 *
25 * L2CAP sm procedures are initiated by the application via function calls.
26 * Such functions return when either of the following happens:
27 *
28 * (1) The procedure completes (success or failure).
29 * (2) The procedure cannot proceed until a BLE peer responds.
30 *
31 * For (1), the result of the procedure if fully indicated by the function
32 * return code.
33 * For (2), the procedure result is indicated by an application-configured
34 * callback. The callback is executed when the procedure completes.
35 *
36 * Notes on thread-safety:
37 * 1. The ble_hs mutex must never be locked when an application callback is
38 * executed. A callback is free to initiate additional host procedures.
39 * 2. Keep the host mutex locked whenever:
40 * o A proc entry is read from or written to.
41 * o The proc list is read or modified.
42 */
43
44 #include <string.h>
45 #include <errno.h>
46 #include "securec.h"
47 #include "nimble/ble.h"
48 #include "nimble/nimble_opt.h"
49 #include "ble_hs_priv.h"
50 #include "host/ble_sm.h"
51
52 #if NIMBLE_BLE_SM
53
54 /** Procedure timeout; 30 seconds. */
55 #define BLE_SM_TIMEOUT_MS (30000)
56
57 STAILQ_HEAD(ble_sm_proc_list, ble_sm_proc);
58
59 typedef void ble_sm_rx_fn(uint16_t conn_handle, struct os_mbuf **om,
60 struct ble_sm_result *res);
61
62 static ble_sm_rx_fn ble_sm_rx_noop;
63 static ble_sm_rx_fn ble_sm_pair_req_rx;
64 static ble_sm_rx_fn ble_sm_pair_rsp_rx;
65 static ble_sm_rx_fn ble_sm_confirm_rx;
66 static ble_sm_rx_fn ble_sm_random_rx;
67 static ble_sm_rx_fn ble_sm_fail_rx;
68 static ble_sm_rx_fn ble_sm_enc_info_rx;
69 static ble_sm_rx_fn ble_sm_master_id_rx;
70 static ble_sm_rx_fn ble_sm_id_info_rx;
71 static ble_sm_rx_fn ble_sm_id_addr_info_rx;
72 static ble_sm_rx_fn ble_sm_sign_info_rx;
73 static ble_sm_rx_fn ble_sm_sec_req_rx;
74
75 static ble_sm_rx_fn *const ble_sm_dispatch[] = {
76 [BLE_SM_OP_PAIR_REQ] = ble_sm_pair_req_rx,
77 [BLE_SM_OP_PAIR_RSP] = ble_sm_pair_rsp_rx,
78 [BLE_SM_OP_PAIR_CONFIRM] = ble_sm_confirm_rx,
79 [BLE_SM_OP_PAIR_RANDOM] = ble_sm_random_rx,
80 [BLE_SM_OP_PAIR_FAIL] = ble_sm_fail_rx,
81 [BLE_SM_OP_ENC_INFO] = ble_sm_enc_info_rx,
82 [BLE_SM_OP_MASTER_ID] = ble_sm_master_id_rx,
83 [BLE_SM_OP_IDENTITY_INFO] = ble_sm_id_info_rx,
84 [BLE_SM_OP_IDENTITY_ADDR_INFO] = ble_sm_id_addr_info_rx,
85 [BLE_SM_OP_SIGN_INFO] = ble_sm_sign_info_rx,
86 [BLE_SM_OP_SEC_REQ] = ble_sm_sec_req_rx,
87 [BLE_SM_OP_PAIR_KEYPRESS_NOTIFY] = ble_sm_rx_noop,
88 #if MYNEWT_VAL(BLE_SM_SC)
89 [BLE_SM_OP_PAIR_PUBLIC_KEY] = ble_sm_sc_public_key_rx,
90 [BLE_SM_OP_PAIR_DHKEY_CHECK] = ble_sm_sc_dhkey_check_rx,
91 #else
92 [BLE_SM_OP_PAIR_PUBLIC_KEY] = ble_sm_rx_noop,
93 [BLE_SM_OP_PAIR_DHKEY_CHECK] = ble_sm_rx_noop,
94 #endif
95 };
96
97 struct hci_start_encrypt {
98 uint16_t connection_handle;
99 uint16_t encrypted_diversifier;
100 uint64_t random_number;
101 uint8_t long_term_key[16];
102 };
103
104 typedef void ble_sm_state_fn(struct ble_sm_proc *proc,
105 struct ble_sm_result *res, void *arg);
106
107 static ble_sm_state_fn ble_sm_pair_exec;
108 static ble_sm_state_fn ble_sm_confirm_exec;
109 static ble_sm_state_fn ble_sm_random_exec;
110 static ble_sm_state_fn ble_sm_ltk_start_exec;
111 static ble_sm_state_fn ble_sm_ltk_restore_exec;
112 static ble_sm_state_fn ble_sm_enc_start_exec;
113 static ble_sm_state_fn ble_sm_enc_restore_exec;
114 static ble_sm_state_fn ble_sm_key_exch_exec;
115 static ble_sm_state_fn ble_sm_sec_req_exec;
116
117 static ble_sm_state_fn *const
118 ble_sm_state_dispatch[BLE_SM_PROC_STATE_CNT] = {
119 [BLE_SM_PROC_STATE_PAIR] = ble_sm_pair_exec,
120 [BLE_SM_PROC_STATE_CONFIRM] = ble_sm_confirm_exec,
121 [BLE_SM_PROC_STATE_RANDOM] = ble_sm_random_exec,
122 [BLE_SM_PROC_STATE_LTK_START] = ble_sm_ltk_start_exec,
123 [BLE_SM_PROC_STATE_LTK_RESTORE] = ble_sm_ltk_restore_exec,
124 [BLE_SM_PROC_STATE_ENC_START] = ble_sm_enc_start_exec,
125 [BLE_SM_PROC_STATE_ENC_RESTORE] = ble_sm_enc_restore_exec,
126 [BLE_SM_PROC_STATE_KEY_EXCH] = ble_sm_key_exch_exec,
127 [BLE_SM_PROC_STATE_SEC_REQ] = ble_sm_sec_req_exec,
128 #if MYNEWT_VAL(BLE_SM_SC)
129 [BLE_SM_PROC_STATE_PUBLIC_KEY] = ble_sm_sc_public_key_exec,
130 [BLE_SM_PROC_STATE_DHKEY_CHECK] = ble_sm_sc_dhkey_check_exec,
131 #else
132 [BLE_SM_PROC_STATE_PUBLIC_KEY] = NULL,
133 [BLE_SM_PROC_STATE_DHKEY_CHECK] = NULL,
134 #endif
135 };
136
137 static os_membuf_t ble_sm_proc_mem[
138 OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_SM_MAX_PROCS),
139 sizeof(struct ble_sm_proc))
140 ];
141
142 static struct os_mempool ble_sm_proc_pool;
143
144 /* Maintains the list of active security manager procedures. */
145 static struct ble_sm_proc_list ble_sm_procs;
146
147 static void ble_sm_pair_cfg(struct ble_sm_proc *proc);
148
149 /*****************************************************************************
150 * $debug *
151 *****************************************************************************/
152
153 #if MYNEWT_VAL(BLE_HS_DEBUG)
154
155 static uint8_t ble_sm_dbg_next_pair_rand[16];
156 static uint8_t ble_sm_dbg_next_pair_rand_set;
157 static uint16_t ble_sm_dbg_next_ediv;
158 static uint8_t ble_sm_dbg_next_ediv_set;
159 static uint64_t ble_sm_dbg_next_master_id_rand;
160 static uint8_t ble_sm_dbg_next_master_id_rand_set;
161 static uint8_t ble_sm_dbg_next_ltk[16];
162 static uint8_t ble_sm_dbg_next_ltk_set;
163 static uint8_t ble_sm_dbg_next_csrk[16];
164 static uint8_t ble_sm_dbg_next_csrk_set;
165
ble_sm_dbg_set_next_pair_rand(uint8_t * next_pair_rand)166 void ble_sm_dbg_set_next_pair_rand(uint8_t *next_pair_rand)
167 {
168 memcpy_s(ble_sm_dbg_next_pair_rand, sizeof(ble_sm_dbg_next_pair_rand), next_pair_rand,
169 sizeof ble_sm_dbg_next_pair_rand);
170 ble_sm_dbg_next_pair_rand_set = 1;
171 }
172
ble_sm_dbg_set_next_ediv(uint16_t next_ediv)173 void ble_sm_dbg_set_next_ediv(uint16_t next_ediv)
174 {
175 ble_sm_dbg_next_ediv = next_ediv;
176 ble_sm_dbg_next_ediv_set = 1;
177 }
178
ble_sm_dbg_set_next_master_id_rand(uint64_t next_master_id_rand)179 void ble_sm_dbg_set_next_master_id_rand(uint64_t next_master_id_rand)
180 {
181 ble_sm_dbg_next_master_id_rand = next_master_id_rand;
182 ble_sm_dbg_next_master_id_rand_set = 1;
183 }
184
ble_sm_dbg_set_next_ltk(uint8_t * next_ltk)185 void ble_sm_dbg_set_next_ltk(uint8_t *next_ltk)
186 {
187 memcpy_s(ble_sm_dbg_next_ltk, sizeof(ble_sm_dbg_next_ltk), next_ltk,
188 sizeof ble_sm_dbg_next_ltk);
189 ble_sm_dbg_next_ltk_set = 1;
190 }
191
ble_sm_dbg_set_next_csrk(uint8_t * next_csrk)192 void ble_sm_dbg_set_next_csrk(uint8_t *next_csrk)
193 {
194 memcpy_s(ble_sm_dbg_next_csrk, sizeof(ble_sm_dbg_next_csrk), next_csrk,
195 sizeof ble_sm_dbg_next_csrk);
196 ble_sm_dbg_next_csrk_set = 1;
197 }
198
199 #endif
200
ble_sm_dbg_assert_no_cycles(void)201 static void ble_sm_dbg_assert_no_cycles(void)
202 {
203 #if MYNEWT_VAL(BLE_HS_DEBUG)
204 ble_sm_num_procs();
205 #endif
206 }
207
ble_sm_dbg_assert_not_inserted(struct ble_sm_proc * proc)208 static void ble_sm_dbg_assert_not_inserted(struct ble_sm_proc *proc)
209 {
210 #if MYNEWT_VAL(BLE_HS_DEBUG)
211 struct ble_sm_proc *cur;
212 STAILQ_FOREACH(cur, &ble_sm_procs, next) {
213 BLE_HS_DBG_ASSERT(cur != proc);
214 }
215 #endif
216 }
217
218 /*****************************************************************************
219 * $misc *
220 *****************************************************************************/
221
222 /**
223 * Calculates the number of active SM procedures.
224 */
ble_sm_num_procs(void)225 int ble_sm_num_procs(void)
226 {
227 struct ble_sm_proc *proc;
228 int cnt;
229 cnt = 0;
230 STAILQ_FOREACH(proc, &ble_sm_procs, next) {
231 BLE_HS_DBG_ASSERT(cnt < MYNEWT_VAL(BLE_SM_MAX_PROCS));
232 cnt++;
233 }
234 return cnt;
235 }
236
ble_sm_gen_pair_rand(uint8_t * pair_rand)237 int ble_sm_gen_pair_rand(uint8_t *pair_rand)
238 {
239 int rc;
240 #if MYNEWT_VAL(BLE_HS_DEBUG)
241
242 if (ble_sm_dbg_next_pair_rand_set) {
243 ble_sm_dbg_next_pair_rand_set = 0;
244 memcpy_s(pair_rand, sizeof(*pair_rand), ble_sm_dbg_next_pair_rand,
245 sizeof ble_sm_dbg_next_pair_rand);
246 return 0;
247 }
248
249 #endif
250 rc = ble_hs_hci_util_rand(pair_rand, 16); // 16:len
251 if (rc != 0) {
252 return rc;
253 }
254
255 return 0;
256 }
257
ble_sm_gen_ediv(struct ble_sm_master_id * master_id)258 static int ble_sm_gen_ediv(struct ble_sm_master_id *master_id)
259 {
260 int rc;
261 #if MYNEWT_VAL(BLE_HS_DEBUG)
262
263 if (ble_sm_dbg_next_ediv_set) {
264 ble_sm_dbg_next_ediv_set = 0;
265 master_id->ediv = ble_sm_dbg_next_ediv;
266 return 0;
267 }
268
269 #endif
270 rc = ble_hs_hci_util_rand(&master_id->ediv, sizeof master_id->ediv);
271 if (rc != 0) {
272 return rc;
273 }
274
275 return 0;
276 }
277
ble_sm_gen_master_id_rand(struct ble_sm_master_id * master_id)278 static int ble_sm_gen_master_id_rand(struct ble_sm_master_id *master_id)
279 {
280 int rc;
281 #if MYNEWT_VAL(BLE_HS_DEBUG)
282
283 if (ble_sm_dbg_next_master_id_rand_set) {
284 ble_sm_dbg_next_master_id_rand_set = 0;
285 master_id->rand_val = ble_sm_dbg_next_master_id_rand;
286 return 0;
287 }
288
289 #endif
290 rc = ble_hs_hci_util_rand(&master_id->rand_val, sizeof master_id->rand_val);
291 if (rc != 0) {
292 return rc;
293 }
294
295 return 0;
296 }
297
ble_sm_gen_ltk(struct ble_sm_proc * proc,uint8_t * ltk)298 static int ble_sm_gen_ltk(struct ble_sm_proc *proc, uint8_t *ltk)
299 {
300 int rc;
301 #if MYNEWT_VAL(BLE_HS_DEBUG)
302
303 if (ble_sm_dbg_next_ltk_set) {
304 ble_sm_dbg_next_ltk_set = 0;
305 memcpy_s(ltk, sizeof(*ltk), ble_sm_dbg_next_ltk,
306 sizeof ble_sm_dbg_next_ltk);
307 return 0;
308 }
309
310 #endif
311 rc = ble_hs_hci_util_rand(ltk, proc->key_size);
312 if (rc != 0) {
313 return rc;
314 }
315
316 /* Ensure proper key size */
317 memset_s(ltk + proc->key_size, sizeof(ltk + proc->key_size), 0, sizeof proc->ltk - proc->key_size);
318 return 0;
319 }
320
ble_sm_gen_csrk(struct ble_sm_proc * proc,uint8_t * csrk)321 static int ble_sm_gen_csrk(struct ble_sm_proc *proc, uint8_t *csrk)
322 {
323 int rc;
324 #if MYNEWT_VAL(BLE_HS_DEBUG)
325
326 if (ble_sm_dbg_next_csrk_set) {
327 ble_sm_dbg_next_csrk_set = 0;
328 memcpy_s(csrk, sizeof(*csrk), ble_sm_dbg_next_csrk,
329 sizeof ble_sm_dbg_next_csrk);
330 return 0;
331 }
332
333 #endif
334 rc = ble_hs_hci_util_rand(csrk, 16); // 16:len
335 if (rc != 0) {
336 return rc;
337 }
338
339 return 0;
340 }
341
ble_sm_proc_set_timer(struct ble_sm_proc * proc)342 static void ble_sm_proc_set_timer(struct ble_sm_proc *proc)
343 {
344 proc->exp_os_ticks = ble_npl_time_get() +
345 ble_npl_time_ms_to_ticks32(BLE_SM_TIMEOUT_MS);
346 ble_hs_timer_resched();
347 }
348
ble_sm_dispatch_get(uint8_t op)349 static ble_sm_rx_fn *ble_sm_dispatch_get(uint8_t op)
350 {
351 if (op >= sizeof ble_sm_dispatch / sizeof ble_sm_dispatch[0]) {
352 return NULL;
353 }
354
355 return ble_sm_dispatch[op];
356 }
357
358 /**
359 * Allocates a proc entry.
360 *
361 * @return An entry on success; null on failure.
362 */
ble_sm_proc_alloc(void)363 static struct ble_sm_proc *ble_sm_proc_alloc(void)
364 {
365 struct ble_sm_proc *proc;
366 proc = os_memblock_get(&ble_sm_proc_pool);
367 if (proc != NULL) {
368 memset_s(proc, sizeof * proc, 0, sizeof * proc);
369 }
370
371 return proc;
372 }
373
374 /**
375 * Frees the specified proc entry. No-state if passed a null pointer.
376 */
ble_sm_proc_free(struct ble_sm_proc * proc)377 static void ble_sm_proc_free(struct ble_sm_proc *proc)
378 {
379 if (proc != NULL) {
380 ble_sm_dbg_assert_not_inserted(proc);
381 #if MYNEWT_VAL(BLE_HS_DEBUG)
382 memset_s(proc, sizeof * proc, 0xff, sizeof * proc);
383 #endif
384 int rc = os_memblock_put(&ble_sm_proc_pool, proc);
385 BLE_HS_DBG_ASSERT_EVAL(rc == 0);
386 }
387 }
388
ble_sm_proc_remove(struct ble_sm_proc * proc,struct ble_sm_proc * prev)389 static void ble_sm_proc_remove(struct ble_sm_proc *proc, struct ble_sm_proc *prev)
390 {
391 if (prev == NULL) {
392 BLE_HS_DBG_ASSERT(STAILQ_FIRST(&ble_sm_procs) == proc);
393 STAILQ_REMOVE_HEAD(&ble_sm_procs, next);
394 } else {
395 BLE_HS_DBG_ASSERT(STAILQ_NEXT(prev, next) == proc);
396 STAILQ_REMOVE_AFTER(&ble_sm_procs, prev, next);
397 }
398
399 ble_sm_dbg_assert_no_cycles();
400 }
401
ble_sm_update_sec_state(uint16_t conn_handle,int encrypted,int authenticated,int bonded,int key_size)402 static void ble_sm_update_sec_state(uint16_t conn_handle, int encrypted,
403 int authenticated, int bonded, int key_size)
404 {
405 struct ble_hs_conn *conn;
406 conn = ble_hs_conn_find(conn_handle);
407 if (conn != NULL) {
408 conn->bhc_sec_state.encrypted = encrypted;
409
410 /* Authentication and bonding are never revoked from a secure link */
411 if (authenticated) {
412 conn->bhc_sec_state.authenticated = 1;
413 }
414
415 if (bonded) {
416 conn->bhc_sec_state.bonded = 1;
417 }
418
419 if (key_size) {
420 conn->bhc_sec_state.key_size = key_size;
421 }
422 }
423 }
424
ble_sm_fill_store_value(const ble_addr_t * peer_addr,int authenticated,int sc,struct ble_sm_keys * keys,struct ble_store_value_sec * value_sec)425 static void ble_sm_fill_store_value(const ble_addr_t *peer_addr,
426 int authenticated,
427 int sc,
428 struct ble_sm_keys *keys,
429 struct ble_store_value_sec *value_sec)
430 {
431 memset_s(value_sec, sizeof * value_sec, 0, sizeof * value_sec);
432 value_sec->peer_addr = *peer_addr;
433
434 if (keys->ediv_rand_valid && keys->ltk_valid) {
435 value_sec->key_size = keys->key_size;
436 value_sec->ediv = keys->ediv;
437 value_sec->rand_num = keys->rand_val;
438 memcpy_s(value_sec->ltk, sizeof(value_sec->ltk), keys->ltk, sizeof value_sec->ltk);
439 value_sec->ltk_present = 1;
440 value_sec->authenticated = !!authenticated;
441 value_sec->sc = !!sc;
442 }
443
444 if (keys->irk_valid) {
445 memcpy_s(value_sec->irk, sizeof(value_sec->irk), keys->irk, sizeof value_sec->irk);
446 value_sec->irk_present = 1;
447 }
448
449 if (keys->csrk_valid) {
450 memcpy_s(value_sec->csrk, sizeof(value_sec->csrk), keys->csrk, sizeof value_sec->csrk);
451 value_sec->csrk_present = 1;
452 }
453 }
454
ble_sm_ia_ra(struct ble_sm_proc * proc,uint8_t * out_iat,uint8_t * out_ia,uint8_t * out_rat,uint8_t * out_ra)455 void ble_sm_ia_ra(struct ble_sm_proc *proc,
456 uint8_t *out_iat, uint8_t *out_ia,
457 uint8_t *out_rat, uint8_t *out_ra)
458 {
459 struct ble_hs_conn_addrs addrs;
460 struct ble_hs_conn *conn;
461 conn = ble_hs_conn_find_assert(proc->conn_handle);
462 ble_hs_conn_addrs(conn, &addrs);
463
464 if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
465 *out_iat = addrs.our_ota_addr.type;
466 memcpy_s(out_ia, sizeof(*out_ia), addrs.our_ota_addr.val, 6); // 6:size
467 *out_rat = addrs.peer_ota_addr.type;
468 memcpy_s(out_ra, sizeof(*out_ra), addrs.peer_ota_addr.val, 6); // 6:size
469 } else {
470 *out_iat = addrs.peer_ota_addr.type;
471 memcpy_s(out_ia, sizeof(*out_ia), addrs.peer_ota_addr.val, 6); // 6:size
472 *out_rat = addrs.our_ota_addr.type;
473 memcpy_s(out_ra, sizeof(*out_ra), addrs.our_ota_addr.val, 6); // 6:size
474 }
475 }
476
ble_sm_persist_keys(struct ble_sm_proc * proc)477 static void ble_sm_persist_keys(struct ble_sm_proc *proc)
478 {
479 struct ble_store_value_sec value_sec;
480 struct ble_hs_conn *conn;
481 ble_addr_t peer_addr;
482 int authenticated;
483 int identity_ev = 0;
484 int sc;
485 ble_hs_lock();
486 conn = ble_hs_conn_find(proc->conn_handle);
487 BLE_HS_DBG_ASSERT(conn != NULL);
488
489 /* If we got an identity address, use that for key storage. */
490 if (proc->peer_keys.addr_valid) {
491 peer_addr.type = proc->peer_keys.addr_type;
492 memcpy_s(peer_addr.val, sizeof(peer_addr.val), proc->peer_keys.addr, sizeof peer_addr.val);
493 conn->bhc_peer_addr = peer_addr;
494
495 /* Update identity address in conn.
496 * If peer's rpa address is set then it means that the peer's address
497 * is an identity address. The peer's address type has to be
498 * set as 'ID' to allow resolve 'id' and 'ota' addresses properly in
499 * conn info.
500 */
501 if (memcmp(BLE_ADDR_ANY->val, &conn->bhc_peer_rpa_addr.val, 6) != 0) { // 6:size
502 switch (peer_addr.type) {
503 case BLE_ADDR_PUBLIC:
504 case BLE_ADDR_PUBLIC_ID:
505 conn->bhc_peer_addr.type = BLE_ADDR_PUBLIC_ID;
506 break;
507
508 case BLE_ADDR_RANDOM:
509 case BLE_ADDR_RANDOM_ID:
510 conn->bhc_peer_addr.type = BLE_ADDR_RANDOM_ID;
511 break;
512 }
513
514 identity_ev = 1;
515 }
516 } else {
517 peer_addr = conn->bhc_peer_addr;
518 peer_addr.type = ble_hs_misc_peer_addr_type_to_id(conn->bhc_peer_addr.type);
519 }
520
521 ble_hs_unlock();
522
523 if (identity_ev) {
524 ble_gap_identity_event(proc->conn_handle);
525 }
526
527 authenticated = proc->flags & BLE_SM_PROC_F_AUTHENTICATED;
528 sc = proc->flags & BLE_SM_PROC_F_SC;
529 ble_sm_fill_store_value(&peer_addr, authenticated, sc, &proc->our_keys,
530 &value_sec);
531 ble_store_write_our_sec(&value_sec);
532 ble_sm_fill_store_value(&peer_addr, authenticated, sc, &proc->peer_keys,
533 &value_sec);
534 ble_store_write_peer_sec(&value_sec);
535 }
536
ble_sm_proc_matches(struct ble_sm_proc * proc,uint16_t conn_handle,uint8_t state,int is_initiator)537 static int ble_sm_proc_matches(struct ble_sm_proc *proc, uint16_t conn_handle,
538 uint8_t state, int is_initiator)
539 {
540 int proc_is_initiator;
541
542 if (conn_handle != proc->conn_handle) {
543 return 0;
544 }
545
546 if (state != BLE_SM_PROC_STATE_NONE && state != proc->state) {
547 return 0;
548 }
549
550 proc_is_initiator = !!(proc->flags & BLE_SM_PROC_F_INITIATOR);
551
552 if (is_initiator != -1 && is_initiator != proc_is_initiator) {
553 return 0;
554 }
555
556 return 1;
557 }
558
559 /**
560 * Searches the main proc list for an entry whose connection handle and state
561 * code match those specified.
562 *
563 * @param conn_handle The connection handle to match against.
564 * @param state The state code to match against.
565 * @param is_initiator Matches on the proc's initiator flag:
566 * 0=non-initiator only
567 * 1=initiator only
568 * -1=don't care
569 * @param out_prev On success, the entry previous to the result is
570 * written here.
571 *
572 * @return The matching proc entry on success;
573 * null on failure.
574 */
ble_sm_proc_find(uint16_t conn_handle,uint8_t state,int is_initiator,struct ble_sm_proc ** out_prev)575 struct ble_sm_proc *ble_sm_proc_find(uint16_t conn_handle, uint8_t state, int is_initiator,
576 struct ble_sm_proc **out_prev)
577 {
578 struct ble_sm_proc *proc;
579 struct ble_sm_proc *prev;
580 BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
581 prev = NULL;
582 STAILQ_FOREACH(proc, &ble_sm_procs, next) {
583 if (ble_sm_proc_matches(proc, conn_handle, state, is_initiator)) {
584 if (out_prev != NULL) {
585 *out_prev = prev;
586 }
587
588 break;
589 }
590
591 prev = proc;
592 }
593 return proc;
594 }
595
ble_sm_insert(struct ble_sm_proc * proc)596 static void ble_sm_insert(struct ble_sm_proc *proc)
597 {
598 #if MYNEWT_VAL(BLE_HS_DEBUG)
599 struct ble_sm_proc *cur;
600 STAILQ_FOREACH(cur, &ble_sm_procs, next) {
601 BLE_HS_DBG_ASSERT(cur != proc);
602 }
603 #endif
604 STAILQ_INSERT_HEAD(&ble_sm_procs, proc, next);
605 }
606
ble_sm_extract_expired(struct ble_sm_proc_list * dst_list)607 static int32_t ble_sm_extract_expired(struct ble_sm_proc_list *dst_list)
608 {
609 struct ble_sm_proc *proc;
610 struct ble_sm_proc *prev;
611 struct ble_sm_proc *next;
612 ble_npl_time_t now;
613 ble_npl_stime_t next_exp_in;
614 ble_npl_stime_t time_diff;
615 now = ble_npl_time_get();
616 STAILQ_INIT(dst_list);
617 /* Assume each event is either expired or has infinite duration. */
618 next_exp_in = BLE_HS_FOREVER;
619 ble_hs_lock();
620 prev = NULL;
621 proc = STAILQ_FIRST(&ble_sm_procs);
622 while (proc != NULL) {
623 next = STAILQ_NEXT(proc, next);
624 time_diff = proc->exp_os_ticks - now;
625 if (time_diff <= 0) {
626 /* Procedure has expired; move it to the destination list. */
627 if (prev == NULL) {
628 STAILQ_REMOVE_HEAD(&ble_sm_procs, next);
629 } else {
630 STAILQ_REMOVE_AFTER(&ble_sm_procs, prev, next);
631 }
632
633 STAILQ_INSERT_HEAD(dst_list, proc, next);
634 } else {
635 if (time_diff < next_exp_in) {
636 next_exp_in = time_diff;
637 }
638 }
639
640 prev = proc;
641 proc = next;
642 }
643
644 ble_sm_dbg_assert_no_cycles();
645 ble_hs_unlock();
646 return next_exp_in;
647 }
648
ble_sm_rx_noop(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)649 static void ble_sm_rx_noop(uint16_t conn_handle, struct os_mbuf **om,
650 struct ble_sm_result *res)
651 {
652 res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP);
653 res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP;
654 }
655
ble_sm_build_authreq(void)656 static uint8_t ble_sm_build_authreq(void)
657 {
658 return (ble_hs_cfg.sm_bonding << 0) |
659 (ble_hs_cfg.sm_mitm << 2) | // 2:byte alignment
660 (ble_hs_cfg.sm_sc << 3) | // 3:byte alignment
661 (ble_hs_cfg.sm_keypress << 4); // 4:byte alignment
662 }
663
ble_sm_io_action(struct ble_sm_proc * proc,uint8_t * action)664 static int ble_sm_io_action(struct ble_sm_proc *proc, uint8_t *action)
665 {
666 if (proc->flags & BLE_SM_PROC_F_SC) {
667 return ble_sm_sc_io_action(proc, action);
668 } else {
669 return ble_sm_lgcy_io_action(proc, action);
670 }
671 }
672
ble_sm_ioact_state(uint8_t action)673 int ble_sm_ioact_state(uint8_t action)
674 {
675 switch (action) {
676 case BLE_SM_IOACT_NONE:
677 return BLE_SM_PROC_STATE_NONE;
678
679 case BLE_SM_IOACT_NUMCMP:
680 return BLE_SM_PROC_STATE_DHKEY_CHECK;
681
682 case BLE_SM_IOACT_OOB_SC:
683 return BLE_SM_PROC_STATE_RANDOM;
684
685 case BLE_SM_IOACT_OOB:
686 case BLE_SM_IOACT_INPUT:
687 case BLE_SM_IOACT_DISP:
688 return BLE_SM_PROC_STATE_CONFIRM;
689
690 default:
691 BLE_HS_DBG_ASSERT(0);
692 return BLE_SM_PROC_STATE_NONE;
693 }
694 }
695
ble_sm_proc_can_advance(struct ble_sm_proc * proc)696 int ble_sm_proc_can_advance(struct ble_sm_proc *proc)
697 {
698 uint8_t ioact;
699 int rc;
700 rc = ble_sm_io_action(proc, &ioact);
701 if (rc != 0) {
702 BLE_HS_DBG_ASSERT(0);
703 }
704
705 if (ble_sm_ioact_state(ioact) != proc->state) {
706 return 1;
707 }
708
709 if ((proc->flags & BLE_SM_PROC_F_IO_INJECTED) &&
710 (proc->flags & BLE_SM_PROC_F_ADVANCE_ON_IO)) {
711 return 1;
712 }
713
714 return 0;
715 }
716
ble_sm_exec(struct ble_sm_proc * proc,struct ble_sm_result * res,void * arg)717 static void ble_sm_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, void *arg)
718 {
719 memset_s(res, sizeof * res, 0, sizeof * res);
720
721 if (!ble_hs_conn_exists(proc->conn_handle)) {
722 res->app_status = BLE_HS_ENOTCONN;
723 } else {
724 BLE_HS_DBG_ASSERT(proc->state < BLE_SM_PROC_STATE_CNT);
725 ble_sm_state_fn *cb = ble_sm_state_dispatch[proc->state];
726 BLE_HS_DBG_ASSERT(cb != NULL);
727 cb(proc, res, arg);
728 }
729 }
730
ble_sm_pair_fail_tx(uint16_t conn_handle,uint8_t reason)731 static void ble_sm_pair_fail_tx(uint16_t conn_handle, uint8_t reason)
732 {
733 struct ble_sm_pair_fail *cmd;
734 struct os_mbuf *txom;
735 BLE_HS_DBG_ASSERT(reason > 0 && reason < BLE_SM_ERR_MAX_PLUS_1);
736 cmd = ble_sm_cmd_get(BLE_SM_OP_PAIR_FAIL, sizeof(*cmd), &txom);
737 if (cmd) {
738 cmd->reason = reason;
739 int rc = ble_sm_tx(conn_handle, txom);
740 if (rc) {
741 BLE_HS_LOG(ERROR, "ble_sm_pair_fail_tx failed, rc = %d\n", rc);
742 }
743 }
744 }
745
746 /**
747 * Reads a bond from storage.
748 */
ble_sm_read_bond(uint16_t conn_handle,struct ble_store_value_sec * out_bond)749 static int ble_sm_read_bond(uint16_t conn_handle, struct ble_store_value_sec *out_bond)
750 {
751 struct ble_store_key_sec key_sec;
752 struct ble_gap_conn_desc desc;
753 int rc;
754 rc = ble_gap_conn_find(conn_handle, &desc);
755 if (rc != 0) {
756 return rc;
757 }
758
759 memset_s(&key_sec, sizeof key_sec, 0, sizeof key_sec);
760 key_sec.peer_addr = desc.peer_id_addr;
761 rc = ble_store_read_peer_sec(&key_sec, out_bond);
762 return rc;
763 }
764
765 /**
766 * Checks if the specified peer is already bonded. If it is, the application
767 * is queried about how to proceed: retry or ignore. The application should
768 * only indicate a retry if it deleted the old bond.
769 *
770 * @param conn_handle The handle of the connection over which the
771 * pairing request was received.
772 * @param proc_flags The security flags associated with the
773 * conflicting SM procedure.
774 * @param key_size The key size of the conflicting SM procedure.
775 *
776 * @return 0 if the procedure should continue;
777 * nonzero if the request should be ignored.
778 */
ble_sm_chk_repeat_pairing(uint16_t conn_handle,ble_sm_proc_flags proc_flags,uint8_t key_size)779 static int ble_sm_chk_repeat_pairing(uint16_t conn_handle,
780 ble_sm_proc_flags proc_flags,
781 uint8_t key_size)
782 {
783 struct ble_gap_repeat_pairing rp;
784 struct ble_store_value_sec bond;
785 int rc;
786 do {
787 /* If the peer isn't bonded, indicate that the pairing procedure should
788 * continue.
789 */
790 rc = ble_sm_read_bond(conn_handle, &bond);
791 switch (rc) {
792 case 0:
793 break;
794
795 case BLE_HS_ENOENT:
796 return 0;
797
798 default:
799 return rc;
800 }
801
802 /* Peer is already bonded. Ask the application what to do about it. */
803 rp.conn_handle = conn_handle;
804 rp.cur_key_size = bond.key_size;
805 rp.cur_authenticated = bond.authenticated;
806 rp.cur_sc = bond.sc;
807 rp.new_key_size = key_size;
808 rp.new_authenticated = !!(proc_flags & BLE_SM_PROC_F_AUTHENTICATED);
809 rp.new_sc = !!(proc_flags & BLE_SM_PROC_F_SC);
810 rp.new_bonding = !!(proc_flags & BLE_SM_PROC_F_BONDING);
811 rc = ble_gap_repeat_pairing_event(&rp);
812 } while (rc == BLE_GAP_REPEAT_PAIRING_RETRY);
813
814 BLE_HS_LOG(DEBUG, "silently ignoring pair request from bonded peer");
815 return BLE_HS_EALREADY;
816 }
817
ble_sm_process_result(uint16_t conn_handle,struct ble_sm_result * res)818 void ble_sm_process_result(uint16_t conn_handle, struct ble_sm_result *res)
819 {
820 struct ble_sm_proc *prev;
821 int rm;
822 rm = 0;
823
824 while (1) {
825 ble_hs_lock();
826 struct ble_sm_proc *proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, &prev);
827 if (proc != NULL) {
828 if (res->execute) {
829 ble_sm_exec(proc, res, res->state_arg);
830 }
831
832 if (res->app_status != 0) {
833 rm = 1;
834 }
835
836 if (proc->state == BLE_SM_PROC_STATE_NONE) {
837 rm = 1;
838 }
839
840 if (rm) {
841 ble_sm_proc_remove(proc, prev);
842 } else {
843 ble_sm_proc_set_timer(proc);
844 }
845 }
846
847 if (res->sm_err != 0) {
848 ble_sm_pair_fail_tx(conn_handle, res->sm_err);
849 }
850
851 ble_hs_unlock();
852
853 if (proc == NULL) {
854 break;
855 }
856
857 if (res->enc_cb) {
858 BLE_HS_DBG_ASSERT(proc == NULL || rm);
859 ble_gap_enc_event(conn_handle, res->app_status, res->restore);
860 }
861
862 if (res->app_status == 0 &&
863 res->passkey_params.action != BLE_SM_IOACT_NONE) {
864 ble_gap_passkey_event(conn_handle, &res->passkey_params);
865 }
866
867 /* Persist keys if bonding has successfully completed. */
868 if ((res->app_status == 0) &&
869 rm &&
870 (proc->flags & BLE_SM_PROC_F_BONDING)) {
871 ble_sm_persist_keys(proc);
872 }
873
874 if (rm) {
875 ble_sm_proc_free(proc);
876 break;
877 }
878
879 if (!res->execute) {
880 break;
881 }
882
883 memset_s(res, sizeof * res, 0, sizeof * res);
884 res->execute = 1;
885 }
886 }
887
ble_sm_key_dist(struct ble_sm_proc * proc,uint8_t * out_init_key_dist,uint8_t * out_resp_key_dist)888 static void ble_sm_key_dist(struct ble_sm_proc *proc, uint8_t *out_init_key_dist, uint8_t *out_resp_key_dist)
889 {
890 struct ble_sm_pair_cmd *pair_rsp;
891 pair_rsp = (struct ble_sm_pair_cmd *) &proc->pair_rsp[1];
892 *out_init_key_dist = pair_rsp->init_key_dist;
893 *out_resp_key_dist = pair_rsp->resp_key_dist;
894
895 /* Encryption info and master ID are only sent in legacy pairing. */
896 if (proc->flags & BLE_SM_PROC_F_SC) {
897 *out_init_key_dist &= ~BLE_SM_PAIR_KEY_DIST_ENC;
898 *out_resp_key_dist &= ~BLE_SM_PAIR_KEY_DIST_ENC;
899 }
900 }
901
ble_sm_chk_store_overflow_by_type(int obj_type,uint16_t conn_handle)902 static int ble_sm_chk_store_overflow_by_type(int obj_type, uint16_t conn_handle)
903 {
904 #if !MYNEWT_VAL(BLE_SM_BONDING)
905 return 0;
906 #endif
907 int count;
908 int rc;
909 rc = ble_store_util_count(obj_type, &count);
910 if (rc != 0) {
911 return rc;
912 }
913
914 /* Pessimistically assume all active procs will persist bonds. */
915 ble_hs_lock();
916 count += ble_sm_num_procs();
917 ble_hs_unlock();
918
919 if (count < MYNEWT_VAL(BLE_STORE_MAX_BONDS)) {
920 /* There is sufficient capacity for another bond. */
921 return 0;
922 }
923
924 /* No capacity for an additional bond. Tell the application to make
925 * room.
926 */
927 rc = ble_store_full_event(obj_type, conn_handle);
928 if (rc != 0) {
929 return rc;
930 }
931
932 return 0;
933 }
934
ble_sm_chk_store_overflow(uint16_t conn_handle)935 static int ble_sm_chk_store_overflow(uint16_t conn_handle)
936 {
937 int rc;
938 rc = ble_sm_chk_store_overflow_by_type(BLE_STORE_OBJ_TYPE_PEER_SEC,
939 conn_handle);
940 if (rc != 0) {
941 return rc;
942 }
943
944 rc = ble_sm_chk_store_overflow_by_type(BLE_STORE_OBJ_TYPE_OUR_SEC,
945 conn_handle);
946 if (rc != 0) {
947 return rc;
948 }
949
950 return 0;
951 }
952
953 /*****************************************************************************
954 * $enc *
955 *****************************************************************************/
956
ble_sm_start_encrypt_tx(struct hci_start_encrypt * params)957 static int ble_sm_start_encrypt_tx(struct hci_start_encrypt *params)
958 {
959 struct ble_hci_le_start_encrypt_cp cmd;
960 cmd.conn_handle = htole16(params->connection_handle);
961 cmd.div = htole16(params->encrypted_diversifier);
962 cmd.rand = htole64(params->random_number);
963 memcpy_s(cmd.ltk, sizeof(cmd.ltk), params->long_term_key, sizeof(cmd.ltk));
964 return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
965 BLE_HCI_OCF_LE_START_ENCRYPT),
966 &cmd, sizeof(cmd), NULL, 0);
967 }
968
ble_sm_enc_start_exec(struct ble_sm_proc * proc,struct ble_sm_result * res,void * arg)969 static void ble_sm_enc_start_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, void *arg)
970 {
971 struct hci_start_encrypt cmd;
972 int rc;
973 BLE_HS_DBG_ASSERT(proc->flags & BLE_SM_PROC_F_INITIATOR);
974 cmd.connection_handle = proc->conn_handle;
975 cmd.encrypted_diversifier = 0;
976 cmd.random_number = 0;
977 memcpy_s(cmd.long_term_key, sizeof(cmd.long_term_key), proc->ltk, sizeof cmd.long_term_key);
978 rc = ble_sm_start_encrypt_tx(&cmd);
979 if (rc != 0) {
980 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
981 res->app_status = rc;
982 res->enc_cb = 1;
983 }
984 }
985
ble_sm_enc_restore_exec(struct ble_sm_proc * proc,struct ble_sm_result * res,void * arg)986 static void ble_sm_enc_restore_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, void *arg)
987 {
988 struct hci_start_encrypt *cmd;
989 BLE_HS_DBG_ASSERT(proc->flags & BLE_SM_PROC_F_INITIATOR);
990 cmd = arg;
991 BLE_HS_DBG_ASSERT(cmd != NULL);
992 res->app_status = ble_sm_start_encrypt_tx(cmd);
993 }
994
ble_sm_enc_event_rx(uint16_t conn_handle,uint8_t evt_status,int encrypted)995 static void ble_sm_enc_event_rx(uint16_t conn_handle, uint8_t evt_status, int encrypted)
996 {
997 struct ble_sm_result res;
998 struct ble_sm_proc *proc;
999 int authenticated;
1000 int bonded;
1001 int key_size;
1002 memset_s(&res, sizeof res, 0, sizeof res);
1003 /* Assume no change in authenticated and bonded statuses. */
1004 authenticated = 0;
1005 bonded = 0;
1006 key_size = 0;
1007 ble_hs_lock();
1008 proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, NULL);
1009 if (proc != NULL) {
1010 switch (proc->state) {
1011 case BLE_SM_PROC_STATE_ENC_START:
1012
1013 /* We are completing a pairing procedure; keys may need to be
1014 * exchanged.
1015 */
1016 if (evt_status == 0) {
1017 /* If the responder has any keys to send, it sends them
1018 * first.
1019 */
1020 proc->state = BLE_SM_PROC_STATE_KEY_EXCH;
1021 if (!(proc->flags & BLE_SM_PROC_F_INITIATOR) ||
1022 proc->rx_key_flags == 0) {
1023 res.execute = 1;
1024 }
1025
1026 key_size = proc->key_size;
1027 } else {
1028 /* Failure or no keys to exchange; procedure is complete. */
1029 proc->state = BLE_SM_PROC_STATE_NONE;
1030 }
1031
1032 if (proc->flags & BLE_SM_PROC_F_AUTHENTICATED) {
1033 authenticated = 1;
1034 }
1035
1036 break;
1037
1038 case BLE_SM_PROC_STATE_ENC_RESTORE:
1039 /* A secure link is being restored via the encryption
1040 * procedure. Keys were exchanged during pairing; they don't
1041 * get exchanged again now. Procedure is complete.
1042 */
1043 BLE_HS_DBG_ASSERT(proc->rx_key_flags == 0);
1044 proc->state = BLE_SM_PROC_STATE_NONE;
1045 if (proc->flags & BLE_SM_PROC_F_AUTHENTICATED) {
1046 authenticated = 1;
1047 }
1048
1049 bonded = 1;
1050 res.restore = 1;
1051 key_size = proc->key_size;
1052 break;
1053
1054 default:
1055 /* The encryption change event is unexpected. We take the
1056 * controller at its word that the state has changed and we
1057 * terminate the procedure.
1058 */
1059 proc->state = BLE_SM_PROC_STATE_NONE;
1060 res.sm_err = BLE_SM_ERR_UNSPECIFIED;
1061 break;
1062 }
1063 }
1064
1065 if (evt_status == 0) {
1066 /* Set the encrypted state of the connection as indicated in the
1067 * event.
1068 */
1069 ble_sm_update_sec_state(conn_handle, encrypted, authenticated, bonded,
1070 key_size);
1071 }
1072
1073 /* Unless keys need to be exchanged, notify the application of the security
1074 * change. If key exchange is pending, the application callback is
1075 * triggered after exchange completes.
1076 */
1077 if (proc == NULL || proc->state == BLE_SM_PROC_STATE_NONE) {
1078 res.enc_cb = 1;
1079 res.app_status = BLE_HS_HCI_ERR(evt_status);
1080 }
1081
1082 ble_hs_unlock();
1083 ble_sm_process_result(conn_handle, &res);
1084 }
1085
ble_sm_enc_change_rx(const struct ble_hci_ev_enrypt_chg * ev)1086 void ble_sm_enc_change_rx(const struct ble_hci_ev_enrypt_chg *ev)
1087 {
1088 /* For encrypted state: read LE-encryption bit; ignore BR/EDR and reserved
1089 * bits.
1090 */
1091 ble_sm_enc_event_rx(le16toh(ev->connection_handle), ev->status,
1092 ev->enabled & 0x01);
1093 }
1094
ble_sm_enc_key_refresh_rx(const struct ble_hci_ev_enc_key_refresh * ev)1095 void ble_sm_enc_key_refresh_rx(const struct ble_hci_ev_enc_key_refresh *ev)
1096 {
1097 ble_sm_enc_event_rx(le16toh(ev->conn_handle), ev->status, 1);
1098 }
1099
1100 /*****************************************************************************
1101 * $ltk *
1102 *****************************************************************************/
1103
ble_sm_retrieve_ltk(uint16_t ediv,uint64_t rand,uint8_t peer_addr_type,uint8_t * peer_addr,struct ble_store_value_sec * value_sec)1104 static int ble_sm_retrieve_ltk(uint16_t ediv, uint64_t rand, uint8_t peer_addr_type,
1105 uint8_t *peer_addr, struct ble_store_value_sec *value_sec)
1106 {
1107 struct ble_store_key_sec key_sec;
1108 int rc;
1109 /* Tell applicaiton to look up LTK by peer address and ediv/rand pair. */
1110 memset_s(&key_sec, sizeof key_sec, 0, sizeof key_sec);
1111 key_sec.peer_addr.type = peer_addr_type;
1112 memcpy_s(key_sec.peer_addr.val, sizeof(key_sec.peer_addr.val), peer_addr, 6); // 6:size
1113 key_sec.ediv = ediv;
1114 key_sec.rand_num = rand;
1115 key_sec.ediv_rand_present = 1;
1116 rc = ble_store_read_our_sec(&key_sec, value_sec);
1117 return rc;
1118 }
1119
ble_sm_ltk_req_reply_tx(uint16_t conn_handle,const uint8_t * ltk)1120 static int ble_sm_ltk_req_reply_tx(uint16_t conn_handle, const uint8_t *ltk)
1121 {
1122 struct ble_hci_le_lt_key_req_reply_cp cmd;
1123 struct ble_hci_le_lt_key_req_reply_rp rsp;
1124 int rc;
1125 cmd.conn_handle = htole16(conn_handle);
1126 memcpy_s(cmd.ltk, sizeof(cmd.ltk), ltk, 16); // 16:size
1127 rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
1128 BLE_HCI_OCF_LE_LT_KEY_REQ_REPLY),
1129 &cmd, sizeof(cmd), &rsp, sizeof(rsp));
1130 if (rc != 0) {
1131 return rc;
1132 }
1133
1134 if (le16toh(rsp.conn_handle) != conn_handle) {
1135 return BLE_HS_ECONTROLLER;
1136 }
1137
1138 return 0;
1139 }
1140
ble_sm_ltk_req_neg_reply_tx(uint16_t conn_handle)1141 static int ble_sm_ltk_req_neg_reply_tx(uint16_t conn_handle)
1142 {
1143 struct ble_hci_le_lt_key_req_neg_reply_cp cmd;
1144 struct ble_hci_le_lt_key_req_neg_reply_cp rsp;
1145 int rc;
1146 cmd.conn_handle = htole16(conn_handle);
1147 rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
1148 BLE_HCI_OCF_LE_LT_KEY_REQ_NEG_REPLY),
1149 &cmd, sizeof(cmd), &rsp, sizeof(rsp));
1150 if (rc != 0) {
1151 return rc;
1152 }
1153
1154 if (le16toh(rsp.conn_handle) != conn_handle) {
1155 return BLE_HS_ECONTROLLER;
1156 }
1157
1158 return 0;
1159 }
1160
ble_sm_ltk_start_exec(struct ble_sm_proc * proc,struct ble_sm_result * res,void * arg)1161 static void ble_sm_ltk_start_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, void *arg)
1162 {
1163 BLE_HS_DBG_ASSERT(!(proc->flags & BLE_SM_PROC_F_INITIATOR));
1164 res->app_status = ble_sm_ltk_req_reply_tx(proc->conn_handle, proc->ltk);
1165
1166 if (res->app_status == 0) {
1167 proc->state = BLE_SM_PROC_STATE_ENC_START;
1168 } else {
1169 res->enc_cb = 1;
1170 }
1171 }
1172
ble_sm_ltk_restore_exec(struct ble_sm_proc * proc,struct ble_sm_result * res,void * arg)1173 static void ble_sm_ltk_restore_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, void *arg)
1174 {
1175 struct ble_store_value_sec *value_sec;
1176 BLE_HS_DBG_ASSERT(!(proc->flags & BLE_SM_PROC_F_INITIATOR));
1177 value_sec = arg;
1178
1179 if (value_sec != NULL) {
1180 /* Store provided a key; send it to the controller. */
1181 res->app_status = ble_sm_ltk_req_reply_tx(proc->conn_handle, value_sec->ltk);
1182 if (res->app_status == 0) {
1183 proc->key_size = value_sec->key_size;
1184
1185 if (value_sec->authenticated) {
1186 proc->flags |= BLE_SM_PROC_F_AUTHENTICATED;
1187 }
1188 } else {
1189 /* Notify the app if it provided a key and the procedure failed. */
1190 res->enc_cb = 1;
1191 }
1192 } else {
1193 /* Application does not have the requested key in its database. Send a
1194 * negative reply to the controller.
1195 */
1196 ble_sm_ltk_req_neg_reply_tx(proc->conn_handle);
1197 res->app_status = BLE_HS_ENOENT;
1198 }
1199
1200 if (res->app_status == 0) {
1201 proc->state = BLE_SM_PROC_STATE_ENC_RESTORE;
1202 }
1203 }
1204
ble_sm_ltk_req_rx(const struct ble_hci_ev_le_subev_lt_key_req * ev)1205 int ble_sm_ltk_req_rx(const struct ble_hci_ev_le_subev_lt_key_req *ev)
1206 {
1207 struct ble_store_value_sec value_sec;
1208 struct ble_hs_conn_addrs addrs;
1209 struct ble_sm_result res;
1210 struct ble_sm_proc *proc;
1211 uint8_t peer_id_addr[6];
1212 int restore;
1213 uint16_t conn_handle = le16toh(ev->conn_handle);
1214 memset_s(&res, sizeof res, 0, sizeof res);
1215 ble_hs_lock();
1216 proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, 0, NULL);
1217 if (proc == NULL) {
1218 /* The peer is attempting to restore a encrypted connection via the
1219 * encryption procedure. Create a proc entry to indicate that security
1220 * establishment is in progress and execute the procedure after the
1221 * mutex gets unlocked.
1222 */
1223 restore = 1;
1224 proc = ble_sm_proc_alloc();
1225 if (proc == NULL) {
1226 res.app_status = BLE_HS_ENOMEM;
1227 } else {
1228 proc->conn_handle = conn_handle;
1229 proc->state = BLE_SM_PROC_STATE_LTK_RESTORE;
1230 ble_sm_insert(proc);
1231 res.execute = 1;
1232 }
1233 } else if (proc->state == BLE_SM_PROC_STATE_SEC_REQ) {
1234 /* Same as above, except we solicited the encryption procedure by
1235 * sending a security request.
1236 */
1237 restore = 1;
1238 proc->state = BLE_SM_PROC_STATE_LTK_RESTORE;
1239 res.execute = 1;
1240 } else if (proc->state == BLE_SM_PROC_STATE_LTK_START) {
1241 /* Legacy pairing just completed. Send the short term key to the
1242 * controller.
1243 */
1244 restore = 0;
1245 res.execute = 1;
1246 } else {
1247 /* The request is unexpected; nack and forget. */
1248 restore = 0;
1249 ble_sm_ltk_req_neg_reply_tx(conn_handle);
1250 proc = NULL;
1251 }
1252
1253 if (restore) {
1254 struct ble_hs_conn *conn = ble_hs_conn_find_assert(conn_handle);
1255 ble_hs_conn_addrs(conn, &addrs);
1256 memcpy_s(peer_id_addr, sizeof(peer_id_addr), addrs.peer_id_addr.val, 6); // 6:size
1257 }
1258
1259 ble_hs_unlock();
1260
1261 if (proc == NULL) {
1262 return res.app_status;
1263 }
1264
1265 if (res.app_status == 0) {
1266 if (restore) {
1267 int store_rc = ble_sm_retrieve_ltk(le16toh(ev->div), le64toh(ev->rand),
1268 addrs.peer_id_addr.type,
1269 peer_id_addr, &value_sec);
1270 if (store_rc == 0) {
1271 /* Send the key to the controller. */
1272 res.state_arg = &value_sec;
1273 } else {
1274 /* Send a nack to the controller. */
1275 res.state_arg = NULL;
1276 }
1277 }
1278 }
1279
1280 ble_sm_process_result(conn_handle, &res);
1281 return 0;
1282 }
1283
1284 /*****************************************************************************
1285 * $random *
1286 *****************************************************************************/
1287
ble_sm_our_pair_rand(struct ble_sm_proc * proc)1288 uint8_t *ble_sm_our_pair_rand(struct ble_sm_proc *proc)
1289 {
1290 if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
1291 return proc->randm;
1292 } else {
1293 return proc->rands;
1294 }
1295 }
1296
ble_sm_peer_pair_rand(struct ble_sm_proc * proc)1297 uint8_t *ble_sm_peer_pair_rand(struct ble_sm_proc *proc)
1298 {
1299 if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
1300 return proc->rands;
1301 } else {
1302 return proc->randm;
1303 }
1304 }
1305
ble_sm_random_exec(struct ble_sm_proc * proc,struct ble_sm_result * res,void * arg)1306 static void ble_sm_random_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, void *arg)
1307 {
1308 if (proc->flags & BLE_SM_PROC_F_SC) {
1309 ble_sm_sc_random_exec(proc, res);
1310 } else {
1311 ble_sm_lgcy_random_exec(proc, res);
1312 }
1313 }
1314
ble_sm_random_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)1315 static void ble_sm_random_rx(uint16_t conn_handle, struct os_mbuf **om, struct ble_sm_result *res)
1316 {
1317 struct ble_sm_pair_random *cmd;
1318 struct ble_sm_proc *proc;
1319 res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*cmd));
1320 if (res->app_status != 0) {
1321 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
1322 res->enc_cb = 1;
1323 return;
1324 }
1325
1326 cmd = (struct ble_sm_pair_random *)(*om)->om_data;
1327 ble_hs_lock();
1328 proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_RANDOM, -1, NULL);
1329 if (proc == NULL) {
1330 res->app_status = BLE_HS_ENOENT;
1331 } else {
1332 memcpy_s(ble_sm_peer_pair_rand(proc), sizeof(*ble_sm_peer_pair_rand(proc)), cmd->value, 16); // 16:size
1333
1334 if (proc->flags & BLE_SM_PROC_F_SC) {
1335 ble_sm_sc_random_rx(proc, res);
1336 } else {
1337 ble_sm_lgcy_random_rx(proc, res);
1338 }
1339 }
1340
1341 ble_hs_unlock();
1342 }
1343
1344 /*****************************************************************************
1345 * $confirm *
1346 *****************************************************************************/
1347
ble_sm_confirm_exec(struct ble_sm_proc * proc,struct ble_sm_result * res,void * arg)1348 static void ble_sm_confirm_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, void *arg)
1349 {
1350 if (!(proc->flags & BLE_SM_PROC_F_SC)) {
1351 ble_sm_lgcy_confirm_exec(proc, res);
1352 } else {
1353 ble_sm_sc_confirm_exec(proc, res);
1354 }
1355 }
1356
ble_sm_confirm_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)1357 static void ble_sm_confirm_rx(uint16_t conn_handle, struct os_mbuf **om, struct ble_sm_result *res)
1358 {
1359 struct ble_sm_pair_confirm *cmd;
1360 struct ble_sm_proc *proc;
1361 uint8_t ioact;
1362 res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*cmd));
1363 if (res->app_status != 0) {
1364 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
1365 res->enc_cb = 1;
1366 return;
1367 }
1368
1369 cmd = (struct ble_sm_pair_confirm *)(*om)->om_data;
1370 ble_hs_lock();
1371 proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_CONFIRM, -1, NULL);
1372 if (proc == NULL) {
1373 res->app_status = BLE_HS_ENOENT;
1374 } else {
1375 memcpy_s(proc->confirm_peer, sizeof(proc->confirm_peer), cmd->value, 16); // 16:size
1376
1377 if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
1378 proc->state = BLE_SM_PROC_STATE_RANDOM;
1379 res->execute = 1;
1380 } else {
1381 int rc;
1382 rc = ble_sm_io_action(proc, &ioact);
1383 if (rc != 0) {
1384 BLE_HS_DBG_ASSERT(0);
1385 }
1386
1387 if (ble_sm_ioact_state(ioact) == proc->state) {
1388 proc->flags |= BLE_SM_PROC_F_ADVANCE_ON_IO;
1389 }
1390
1391 if (ble_sm_proc_can_advance(proc)) {
1392 res->execute = 1;
1393 }
1394 }
1395 }
1396
1397 ble_hs_unlock();
1398 }
1399
1400 /*****************************************************************************
1401 * $pair *
1402 *****************************************************************************/
1403
ble_sm_state_after_pair(struct ble_sm_proc * proc)1404 static uint8_t ble_sm_state_after_pair(struct ble_sm_proc *proc)
1405 {
1406 if (proc->flags & BLE_SM_PROC_F_SC) {
1407 return BLE_SM_PROC_STATE_PUBLIC_KEY;
1408 } else {
1409 return BLE_SM_PROC_STATE_CONFIRM;
1410 }
1411 }
1412
ble_sm_pair_cfg(struct ble_sm_proc * proc)1413 static void ble_sm_pair_cfg(struct ble_sm_proc *proc)
1414 {
1415 struct ble_sm_pair_cmd *pair_req, *pair_rsp;
1416 uint8_t init_key_dist;
1417 uint8_t resp_key_dist;
1418 uint8_t rx_key_dist;
1419 uint8_t ioact;
1420 int rc;
1421 pair_req = (struct ble_sm_pair_cmd *) &proc->pair_req[1];
1422 pair_rsp = (struct ble_sm_pair_cmd *) &proc->pair_rsp[1];
1423
1424 if ((pair_req->authreq & BLE_SM_PAIR_AUTHREQ_SC) &&
1425 (pair_rsp->authreq & BLE_SM_PAIR_AUTHREQ_SC)) {
1426 proc->flags |= BLE_SM_PROC_F_SC;
1427 }
1428
1429 ble_sm_key_dist(proc, &init_key_dist, &resp_key_dist);
1430
1431 if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
1432 rx_key_dist = resp_key_dist;
1433 } else {
1434 rx_key_dist = init_key_dist;
1435 }
1436
1437 if ((pair_req->authreq & BLE_SM_PAIR_AUTHREQ_BOND) &&
1438 (pair_rsp->authreq & BLE_SM_PAIR_AUTHREQ_BOND)) {
1439 proc->flags |= BLE_SM_PROC_F_BONDING;
1440 }
1441
1442 /* In legacy mode, bonding requires the exchange of keys
1443 * at least from one side. If no key exchange was specified,
1444 * pretend bonding is not enabled.
1445 */
1446 if (!(proc->flags & BLE_SM_PROC_F_SC) &&
1447 (init_key_dist == 0 && resp_key_dist == 0)) {
1448 proc->flags &= ~BLE_SM_PROC_F_BONDING;
1449 }
1450
1451 proc->rx_key_flags = 0;
1452
1453 if (rx_key_dist & BLE_SM_PAIR_KEY_DIST_ENC) {
1454 proc->rx_key_flags |= BLE_SM_KE_F_ENC_INFO |
1455 BLE_SM_KE_F_MASTER_ID;
1456 }
1457
1458 if (rx_key_dist & BLE_SM_PAIR_KEY_DIST_ID) {
1459 proc->rx_key_flags |= BLE_SM_KE_F_ID_INFO |
1460 BLE_SM_KE_F_ADDR_INFO;
1461 }
1462
1463 if (rx_key_dist & BLE_SM_PAIR_KEY_DIST_SIGN) {
1464 proc->rx_key_flags |= BLE_SM_KE_F_SIGN_INFO;
1465 }
1466
1467 proc->key_size = min(pair_req->max_enc_key_size,
1468 pair_rsp->max_enc_key_size);
1469 rc = ble_sm_io_action(proc, &ioact);
1470 BLE_HS_DBG_ASSERT_EVAL(rc == 0);
1471 }
1472
ble_sm_pair_base_fill(struct ble_sm_pair_cmd * cmd)1473 static void ble_sm_pair_base_fill(struct ble_sm_pair_cmd *cmd)
1474 {
1475 cmd->io_cap = ble_hs_cfg.sm_io_cap;
1476 cmd->oob_data_flag = ble_hs_cfg.sm_oob_data_flag;
1477 cmd->authreq = ble_sm_build_authreq();
1478 cmd->max_enc_key_size = BLE_SM_PAIR_KEY_SZ_MAX;
1479 }
1480
ble_sm_pair_req_fill(struct ble_sm_proc * proc)1481 static void ble_sm_pair_req_fill(struct ble_sm_proc *proc)
1482 {
1483 struct ble_sm_pair_cmd *req;
1484 req = (void *)(proc->pair_req + 1);
1485 proc->pair_req[0] = BLE_SM_OP_PAIR_REQ;
1486 ble_sm_pair_base_fill(req);
1487 req->init_key_dist = ble_hs_cfg.sm_our_key_dist;
1488 req->resp_key_dist = ble_hs_cfg.sm_their_key_dist;
1489 }
1490
ble_sm_pair_rsp_fill(struct ble_sm_proc * proc)1491 static void ble_sm_pair_rsp_fill(struct ble_sm_proc *proc)
1492 {
1493 const struct ble_sm_pair_cmd *req;
1494 struct ble_sm_pair_cmd *rsp;
1495 req = (void *)(proc->pair_req + 1);
1496 rsp = (void *)(proc->pair_rsp + 1);
1497 proc->pair_rsp[0] = BLE_SM_OP_PAIR_RSP;
1498 ble_sm_pair_base_fill(rsp);
1499 /* The response's key distribution flags field is the intersection of
1500 * the peer's preferences and our capabilities.
1501 */
1502 rsp->init_key_dist = req->init_key_dist &
1503 ble_hs_cfg.sm_their_key_dist;
1504 rsp->resp_key_dist = req->resp_key_dist &
1505 ble_hs_cfg.sm_our_key_dist;
1506 }
1507
ble_sm_pair_exec(struct ble_sm_proc * proc,struct ble_sm_result * res,void * arg)1508 static void ble_sm_pair_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, void *arg)
1509 {
1510 struct ble_sm_pair_cmd *cmd;
1511 struct os_mbuf *txom;
1512 uint8_t ioact;
1513 int is_req;
1514 int rc;
1515 is_req = proc->flags & BLE_SM_PROC_F_INITIATOR;
1516 cmd = ble_sm_cmd_get(is_req ? BLE_SM_OP_PAIR_REQ : BLE_SM_OP_PAIR_RSP,
1517 sizeof(*cmd), &txom);
1518 if (cmd == NULL) {
1519 rc = BLE_HS_ENOMEM;
1520 goto err;
1521 }
1522
1523 if (is_req) {
1524 ble_sm_pair_req_fill(proc);
1525 memcpy_s(cmd, sizeof(*cmd), proc->pair_req + 1, sizeof(*cmd));
1526 } else {
1527 /* The response was already generated when we processed the incoming
1528 * request.
1529 */
1530 memcpy_s(cmd, sizeof(*cmd), proc->pair_rsp + 1, sizeof(*cmd));
1531 proc->state = ble_sm_state_after_pair(proc);
1532 rc = ble_sm_io_action(proc, &ioact);
1533 BLE_HS_DBG_ASSERT(rc == 0);
1534
1535 if (ble_sm_ioact_state(ioact) == proc->state) {
1536 res->passkey_params.action = ioact;
1537 }
1538 }
1539
1540 rc = ble_sm_tx(proc->conn_handle, txom);
1541 if (rc != 0) {
1542 goto err;
1543 }
1544
1545 res->app_status = ble_sm_gen_pair_rand(ble_sm_our_pair_rand(proc));
1546 if (res->app_status != 0) {
1547 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
1548 res->enc_cb = 1;
1549 return;
1550 }
1551
1552 return;
1553 err:
1554 res->app_status = rc;
1555
1556 if (!is_req) {
1557 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
1558 }
1559 }
1560
ble_sm_verify_auth_requirements(uint8_t authreq)1561 static bool ble_sm_verify_auth_requirements(uint8_t authreq)
1562 {
1563 /* For now we check only SC only mode. I.e.: when remote indicates
1564 * to not support SC pairing, let us make sure legacy pairing is supported
1565 * on our side. If not, we can fail right away.
1566 */
1567 if (!(authreq & BLE_SM_PAIR_AUTHREQ_SC)) {
1568 if (MYNEWT_VAL(BLE_SM_LEGACY) == 0) {
1569 return false;
1570 }
1571 }
1572
1573 return true;
1574 }
1575
ble_sm_pair_req_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)1576 static void ble_sm_pair_req_rx(uint16_t conn_handle, struct os_mbuf **om,
1577 struct ble_sm_result *res)
1578 {
1579 struct ble_sm_pair_cmd *req;
1580 struct ble_sm_proc *proc;
1581 struct ble_sm_proc *prev;
1582 ble_sm_proc_flags proc_flags;
1583 uint8_t key_size;
1584 int rc;
1585 /* Silence spurious unused-variable warnings. */
1586 proc_flags = 0;
1587 key_size = 0;
1588 res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*req));
1589 if (res->app_status != 0) {
1590 return;
1591 }
1592
1593 req = (struct ble_sm_pair_cmd *)(*om)->om_data;
1594 ble_hs_lock();
1595 /* XXX: Check connection state; reject if not appropriate. */
1596 /* XXX: Ensure enough time has passed since the previous failed pairing
1597 * attempt.
1598 */
1599 proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, &prev);
1600 if (proc != NULL) {
1601 /* Fail if procedure is in progress unless we sent a slave security
1602 * request to peer.
1603 */
1604 if (proc->state != BLE_SM_PROC_STATE_SEC_REQ) {
1605 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
1606 res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_UNSPECIFIED);
1607 ble_hs_unlock();
1608 return;
1609 }
1610
1611 /* Remove the procedure because it was allocated when
1612 * sending the Slave Security Request and it will be allocated
1613 * again later in this method. We should probably refactor this
1614 * in the future.
1615 */
1616 ble_sm_proc_remove(proc, prev);
1617 ble_sm_proc_free(proc);
1618 }
1619
1620 ble_hs_unlock();
1621 /* Check if there is storage capacity for a new bond. If there isn't, ask
1622 * the application to make room.
1623 */
1624 rc = ble_sm_chk_store_overflow(conn_handle);
1625 if (rc != 0) {
1626 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
1627 res->app_status = rc;
1628 return;
1629 }
1630
1631 ble_hs_lock();
1632 proc = ble_sm_proc_alloc();
1633 if (proc != NULL) {
1634 proc->conn_handle = conn_handle;
1635 proc->state = BLE_SM_PROC_STATE_PAIR;
1636 ble_sm_insert(proc);
1637 proc->pair_req[0] = BLE_SM_OP_PAIR_REQ;
1638 memcpy_s(proc->pair_req + 1, sizeof(proc->pair_req + 1), req, sizeof(*req));
1639 struct ble_hs_conn *conn = ble_hs_conn_find_assert(proc->conn_handle);
1640 if (conn->bhc_flags & BLE_HS_CONN_F_MASTER) {
1641 res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP;
1642 res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP);
1643 } else if (req->max_enc_key_size < BLE_SM_PAIR_KEY_SZ_MIN) {
1644 res->sm_err = BLE_SM_ERR_ENC_KEY_SZ;
1645 res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_ENC_KEY_SZ);
1646 } else if (req->max_enc_key_size > BLE_SM_PAIR_KEY_SZ_MAX) {
1647 res->sm_err = BLE_SM_ERR_INVAL;
1648 res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_INVAL);
1649 } else if (!ble_sm_verify_auth_requirements(req->authreq)) {
1650 res->sm_err = BLE_SM_ERR_AUTHREQ;
1651 res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_AUTHREQ);
1652 } else {
1653 /* The request looks good. Precalculate our pairing response and
1654 * determine some properties of the imminent link. We need this
1655 * information in case this is a repeated pairing attempt (i.e., we
1656 * are already bonded to this peer). In that case, we include the
1657 * information in a notification to the app.
1658 */
1659 ble_sm_pair_rsp_fill(proc);
1660 ble_sm_pair_cfg(proc);
1661 proc_flags = proc->flags;
1662 key_size = proc->key_size;
1663 res->execute = 1;
1664 }
1665 }
1666
1667 ble_hs_unlock();
1668
1669 /* Check if we are already bonded to this peer. If so, give the
1670 * application an opportunity to delete the old bond.
1671 */
1672 if (res->app_status == 0) {
1673 rc = ble_sm_chk_repeat_pairing(conn_handle, proc_flags, key_size);
1674 if (rc != 0) {
1675 /* The app indicated that the pairing request should be ignored. */
1676 res->app_status = rc;
1677 res->execute = 0;
1678 }
1679 }
1680 }
1681
ble_sm_pair_rsp_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)1682 static void ble_sm_pair_rsp_rx(uint16_t conn_handle, struct os_mbuf **om, struct ble_sm_result *res)
1683 {
1684 struct ble_sm_pair_cmd *rsp;
1685 struct ble_sm_proc *proc;
1686 uint8_t ioact;
1687 res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*rsp));
1688 if (res->app_status != 0) {
1689 res->enc_cb = 1;
1690 return;
1691 }
1692
1693 rsp = (struct ble_sm_pair_cmd *)(*om)->om_data;
1694 ble_hs_lock();
1695 proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_PAIR, 1, NULL);
1696 if (proc != NULL) {
1697 proc->pair_rsp[0] = BLE_SM_OP_PAIR_RSP;
1698 memcpy_s(proc->pair_rsp + 1, sizeof(proc->pair_rsp + 1), rsp, sizeof(*rsp));
1699
1700 if (rsp->max_enc_key_size < BLE_SM_PAIR_KEY_SZ_MIN) {
1701 res->sm_err = BLE_SM_ERR_ENC_KEY_SZ;
1702 res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_ENC_KEY_SZ);
1703 } else if (rsp->max_enc_key_size > BLE_SM_PAIR_KEY_SZ_MAX) {
1704 res->sm_err = BLE_SM_ERR_INVAL;
1705 res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_INVAL);
1706 } else {
1707 ble_sm_pair_cfg(proc);
1708 int rc = ble_sm_io_action(proc, &ioact);
1709 if (rc != 0) {
1710 res->sm_err = BLE_SM_ERR_AUTHREQ;
1711 res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_AUTHREQ);
1712 res->enc_cb = 1;
1713 } else {
1714 proc->state = ble_sm_state_after_pair(proc);
1715
1716 if (ble_sm_ioact_state(ioact) == proc->state) {
1717 res->passkey_params.action = ioact;
1718 }
1719
1720 if (ble_sm_proc_can_advance(proc)) {
1721 res->execute = 1;
1722 }
1723 }
1724 }
1725 }
1726
1727 ble_hs_unlock();
1728 }
1729
1730 /*****************************************************************************
1731 * $security request *
1732 *****************************************************************************/
1733
ble_sm_sec_req_exec(struct ble_sm_proc * proc,struct ble_sm_result * res,void * arg)1734 static void ble_sm_sec_req_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, void *arg)
1735 {
1736 struct ble_sm_sec_req *cmd;
1737 struct os_mbuf *txom;
1738 int rc;
1739 cmd = ble_sm_cmd_get(BLE_SM_OP_SEC_REQ, sizeof(*cmd), &txom);
1740 if (!cmd) {
1741 res->app_status = BLE_HS_ENOMEM;
1742 return;
1743 }
1744
1745 cmd->authreq = ble_sm_build_authreq();
1746 rc = ble_sm_tx(proc->conn_handle, txom);
1747 if (rc != 0) {
1748 res->app_status = rc;
1749 return;
1750 }
1751 }
1752
ble_sm_sec_req_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)1753 static void ble_sm_sec_req_rx(uint16_t conn_handle, struct os_mbuf **om, struct ble_sm_result *res)
1754 {
1755 struct ble_store_value_sec value_sec;
1756 struct ble_store_key_sec key_sec;
1757 struct ble_hs_conn_addrs addrs;
1758 struct ble_sm_sec_req *cmd;
1759 struct ble_hs_conn *conn;
1760 res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*cmd));
1761 if (res->app_status != 0) {
1762 return;
1763 }
1764
1765 cmd = (struct ble_sm_sec_req *)(*om)->om_data;
1766 /* XXX: Reject if:
1767 * o authreq-reserved flags set?
1768 */
1769 ble_hs_lock();
1770 conn = ble_hs_conn_find_assert(conn_handle);
1771 if (!(conn->bhc_flags & BLE_HS_CONN_F_MASTER)) {
1772 res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP);
1773 res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP;
1774 } else {
1775 /* We will be querying the SM database for a key corresponding to the
1776 * sender; remember the sender's address while the connection list is
1777 * locked.
1778 */
1779 ble_hs_conn_addrs(conn, &addrs);
1780 memset_s(&key_sec, sizeof key_sec, 0, sizeof key_sec);
1781 key_sec.peer_addr = addrs.peer_id_addr;
1782 }
1783
1784 ble_hs_unlock();
1785
1786 if (res->app_status == 0) {
1787 /* If the peer is requesting a bonded connection, query database for an
1788 * LTK corresponding to the sender.
1789 */
1790 if (cmd->authreq & BLE_SM_PAIR_AUTHREQ_BOND) {
1791 res->app_status = ble_store_read_peer_sec(&key_sec, &value_sec);
1792 } else {
1793 res->app_status = BLE_HS_ENOENT;
1794 }
1795
1796 if (res->app_status == 0) {
1797 /* Found a key corresponding to this peer. Make sure it meets the
1798 * requested minimum authreq.
1799 */
1800 int authreq_mitm = cmd->authreq & BLE_SM_PAIR_AUTHREQ_MITM;
1801 if (authreq_mitm && !value_sec.authenticated) {
1802 res->app_status = BLE_HS_EREJECT;
1803 }
1804 }
1805
1806 if (res->app_status == 0) {
1807 res->app_status = ble_sm_enc_initiate(conn_handle,
1808 value_sec.key_size,
1809 value_sec.ltk,
1810 value_sec.ediv,
1811 value_sec.rand_num,
1812 value_sec.authenticated);
1813 } else {
1814 res->app_status = ble_sm_pair_initiate(conn_handle);
1815 }
1816 }
1817 }
1818
1819 /*****************************************************************************
1820 * $key exchange *
1821 *****************************************************************************/
1822
ble_sm_key_exch_success(struct ble_sm_proc * proc,struct ble_sm_result * res)1823 static void ble_sm_key_exch_success(struct ble_sm_proc *proc, struct ble_sm_result *res)
1824 {
1825 /* The procedure is now complete. Update connection bonded state and
1826 * terminate procedure.
1827 */
1828 ble_sm_update_sec_state(proc->conn_handle, 1,
1829 !!(proc->flags & BLE_SM_PROC_F_AUTHENTICATED),
1830 !!(proc->flags & BLE_SM_PROC_F_BONDING),
1831 proc->key_size);
1832 proc->state = BLE_SM_PROC_STATE_NONE;
1833 res->app_status = 0;
1834 res->enc_cb = 1;
1835 }
1836
ble_sm_key_exch_exec(struct ble_sm_proc * proc,struct ble_sm_result * res,void * arg)1837 static void ble_sm_key_exch_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, void *arg)
1838 {
1839 struct ble_sm_id_addr_info *addr_info;
1840 struct ble_hs_conn_addrs addrs;
1841 struct ble_sm_sign_info *sign_info;
1842 struct ble_sm_master_id *master_id;
1843 struct ble_sm_enc_info *enc_info;
1844 struct ble_sm_id_info *id_info;
1845 struct ble_hs_conn *conn;
1846 uint8_t init_key_dist;
1847 uint8_t resp_key_dist;
1848 uint8_t our_key_dist;
1849 struct os_mbuf *txom;
1850 const uint8_t *irk;
1851 int rc;
1852 ble_sm_key_dist(proc, &init_key_dist, &resp_key_dist);
1853
1854 if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
1855 our_key_dist = init_key_dist;
1856 } else {
1857 our_key_dist = resp_key_dist;
1858 }
1859
1860 if (our_key_dist & BLE_SM_PAIR_KEY_DIST_ENC) {
1861 /* Send encryption information. */
1862 enc_info = ble_sm_cmd_get(BLE_SM_OP_ENC_INFO, sizeof(*enc_info), &txom);
1863 if (!enc_info) {
1864 rc = BLE_HS_ENOMEM;
1865 goto err;
1866 }
1867
1868 rc = ble_sm_gen_ltk(proc, enc_info->ltk);
1869 if (rc != 0) {
1870 os_mbuf_free_chain(txom);
1871 goto err;
1872 }
1873
1874 /* store LTK before sending since ble_sm_tx consumes tx mbuf */
1875 memcpy_s(proc->our_keys.ltk, sizeof(proc->our_keys.ltk), enc_info->ltk, 16); // 16:size
1876 proc->our_keys.key_size = proc->key_size;
1877 proc->our_keys.ltk_valid = 1;
1878 rc = ble_sm_tx(proc->conn_handle, txom);
1879 if (rc != 0) {
1880 goto err;
1881 }
1882
1883 /* Send master identification. */
1884 master_id = ble_sm_cmd_get(BLE_SM_OP_MASTER_ID, sizeof(*master_id),
1885 &txom);
1886 if (!master_id) {
1887 rc = BLE_HS_ENOMEM;
1888 goto err;
1889 }
1890
1891 rc = ble_sm_gen_ediv(master_id);
1892 if (rc != 0) {
1893 os_mbuf_free_chain(txom);
1894 goto err;
1895 }
1896
1897 rc = ble_sm_gen_master_id_rand(master_id);
1898 if (rc != 0) {
1899 os_mbuf_free_chain(txom);
1900 goto err;
1901 }
1902
1903 proc->our_keys.ediv_rand_valid = 1;
1904 proc->our_keys.rand_val = master_id->rand_val;
1905 proc->our_keys.ediv = master_id->ediv;
1906 rc = ble_sm_tx(proc->conn_handle, txom);
1907 if (rc != 0) {
1908 goto err;
1909 }
1910 }
1911
1912 if (our_key_dist & BLE_SM_PAIR_KEY_DIST_ID) {
1913 /* Send identity information. */
1914 id_info = ble_sm_cmd_get(BLE_SM_OP_IDENTITY_INFO, sizeof(*id_info),
1915 &txom);
1916 if (!id_info) {
1917 rc = BLE_HS_ENOMEM;
1918 goto err;
1919 }
1920
1921 rc = ble_hs_pvcy_our_irk(&irk);
1922 if (rc != 0) {
1923 os_mbuf_free_chain(txom);
1924 goto err;
1925 }
1926
1927 memcpy_s(id_info->irk, sizeof(id_info->irk), irk, 16); // 16:size
1928 proc->our_keys.irk_valid = 1;
1929 rc = ble_sm_tx(proc->conn_handle, txom);
1930 if (rc != 0) {
1931 goto err;
1932 }
1933
1934 /* Send identity address information. */
1935 addr_info = ble_sm_cmd_get(BLE_SM_OP_IDENTITY_ADDR_INFO,
1936 sizeof(*addr_info), &txom);
1937 if (!addr_info) {
1938 rc = BLE_HS_ENOMEM;
1939 goto err;
1940 }
1941
1942 conn = ble_hs_conn_find_assert(proc->conn_handle);
1943 ble_hs_conn_addrs(conn, &addrs);
1944 addr_info->addr_type = addrs.our_id_addr.type;
1945 memcpy_s(addr_info->bd_addr, sizeof(addr_info->bd_addr), addrs.our_id_addr.val, 6); // 6:size
1946 proc->our_keys.addr_valid = 1;
1947 memcpy_s(proc->our_keys.irk, sizeof(proc->our_keys.irk), irk, 16); // 16:size
1948 proc->our_keys.addr_type = addr_info->addr_type;
1949 memcpy_s(proc->our_keys.addr, sizeof(proc->our_keys.addr), addr_info->bd_addr, 6); // 6:size
1950 rc = ble_sm_tx(proc->conn_handle, txom);
1951 if (rc != 0) {
1952 goto err;
1953 }
1954 }
1955
1956 if (our_key_dist & BLE_SM_PAIR_KEY_DIST_SIGN) {
1957 /* Send signing information. */
1958 sign_info = ble_sm_cmd_get(BLE_SM_OP_SIGN_INFO, sizeof(*sign_info),
1959 &txom);
1960 if (!sign_info) {
1961 rc = BLE_HS_ENOMEM;
1962 goto err;
1963 }
1964
1965 rc = ble_sm_gen_csrk(proc, sign_info->sig_key);
1966 if (rc != 0) {
1967 os_mbuf_free_chain(txom);
1968 goto err;
1969 }
1970
1971 proc->our_keys.csrk_valid = 1;
1972 memcpy_s(proc->our_keys.csrk, sizeof(proc->our_keys.csrk), sign_info->sig_key, 16); // 16:size
1973 rc = ble_sm_tx(proc->conn_handle, txom);
1974 if (rc != 0) {
1975 goto err;
1976 }
1977 }
1978
1979 if ((proc->flags & BLE_SM_PROC_F_INITIATOR) || (proc->rx_key_flags == 0)) {
1980 /* The procedure is now complete. */
1981 ble_sm_key_exch_success(proc, res);
1982 }
1983
1984 return;
1985 err:
1986 res->app_status = rc;
1987 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
1988 res->enc_cb = 1;
1989 }
1990
ble_sm_key_rxed(struct ble_sm_proc * proc,struct ble_sm_result * res)1991 static void ble_sm_key_rxed(struct ble_sm_proc *proc, struct ble_sm_result *res)
1992 {
1993 BLE_HS_LOG(DEBUG, "rx_key_flags=0x%02x\n", proc->rx_key_flags);
1994
1995 if (proc->rx_key_flags == 0) {
1996 /* The peer is done sending keys. If we are the initiator, we need to
1997 * send ours. If we are the responder, the procedure is complete.
1998 */
1999 if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
2000 res->execute = 1;
2001 } else {
2002 ble_sm_key_exch_success(proc, res);
2003 }
2004 }
2005 }
2006
ble_sm_enc_info_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)2007 static void ble_sm_enc_info_rx(uint16_t conn_handle, struct os_mbuf **om, struct ble_sm_result *res)
2008 {
2009 struct ble_sm_enc_info *cmd;
2010 struct ble_sm_proc *proc;
2011 res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*cmd));
2012 if (res->app_status != 0) {
2013 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
2014 res->enc_cb = 1;
2015 return;
2016 }
2017
2018 cmd = (struct ble_sm_enc_info *)(*om)->om_data;
2019 ble_hs_lock();
2020 proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_KEY_EXCH, -1, NULL);
2021 if (proc == NULL) {
2022 res->app_status = BLE_HS_ENOENT;
2023 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
2024 } else {
2025 proc->rx_key_flags &= ~BLE_SM_KE_F_ENC_INFO;
2026 proc->peer_keys.ltk_valid = 1;
2027 memcpy_s(proc->peer_keys.ltk, sizeof(proc->peer_keys.ltk), cmd->ltk, 16); // 16:size
2028 proc->peer_keys.key_size = proc->key_size;
2029 ble_sm_key_rxed(proc, res);
2030 }
2031
2032 ble_hs_unlock();
2033 }
2034
ble_sm_master_id_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)2035 static void ble_sm_master_id_rx(uint16_t conn_handle, struct os_mbuf **om, struct ble_sm_result *res)
2036 {
2037 struct ble_sm_master_id *cmd;
2038 struct ble_sm_proc *proc;
2039 res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*cmd));
2040 if (res->app_status != 0) {
2041 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
2042 res->enc_cb = 1;
2043 return;
2044 }
2045
2046 cmd = (struct ble_sm_master_id *)(*om)->om_data;
2047 ble_hs_lock();
2048 proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_KEY_EXCH, -1, NULL);
2049 if (proc == NULL) {
2050 res->app_status = BLE_HS_ENOENT;
2051 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
2052 } else {
2053 proc->rx_key_flags &= ~BLE_SM_KE_F_MASTER_ID;
2054 proc->peer_keys.ediv_rand_valid = 1;
2055 proc->peer_keys.ediv = le16toh(cmd->ediv);
2056 proc->peer_keys.rand_val = le64toh(cmd->rand_val);
2057 ble_sm_key_rxed(proc, res);
2058 }
2059
2060 ble_hs_unlock();
2061 }
2062
ble_sm_id_info_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)2063 static void ble_sm_id_info_rx(uint16_t conn_handle, struct os_mbuf **om, struct ble_sm_result *res)
2064 {
2065 struct ble_sm_id_info *cmd;
2066 struct ble_sm_proc *proc;
2067 res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*cmd));
2068 if (res->app_status != 0) {
2069 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
2070 res->enc_cb = 1;
2071 return;
2072 }
2073
2074 cmd = (struct ble_sm_id_info *)(*om)->om_data;
2075 ble_hs_lock();
2076 proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_KEY_EXCH, -1, NULL);
2077 if (proc == NULL) {
2078 res->app_status = BLE_HS_ENOENT;
2079 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
2080 } else {
2081 proc->rx_key_flags &= ~BLE_SM_KE_F_ID_INFO;
2082 memcpy_s(proc->peer_keys.irk, sizeof(proc->peer_keys.irk), cmd->irk, 16); // 16:size
2083 proc->peer_keys.irk_valid = 1;
2084 ble_sm_key_rxed(proc, res);
2085 }
2086
2087 ble_hs_unlock();
2088 }
2089
ble_sm_id_addr_info_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)2090 static void ble_sm_id_addr_info_rx(uint16_t conn_handle, struct os_mbuf **om, struct ble_sm_result *res)
2091 {
2092 struct ble_sm_id_addr_info *cmd;
2093 struct ble_sm_proc *proc;
2094 res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*cmd));
2095 if (res->app_status != 0) {
2096 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
2097 res->enc_cb = 1;
2098 return;
2099 }
2100
2101 cmd = (struct ble_sm_id_addr_info *)(*om)->om_data;
2102 ble_hs_lock();
2103 proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_KEY_EXCH, -1, NULL);
2104 if (proc == NULL) {
2105 res->app_status = BLE_HS_ENOENT;
2106 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
2107 } else {
2108 proc->rx_key_flags &= ~BLE_SM_KE_F_ADDR_INFO;
2109 proc->peer_keys.addr_valid = 1;
2110 proc->peer_keys.addr_type = cmd->addr_type;
2111 memcpy_s(proc->peer_keys.addr, sizeof(proc->peer_keys.addr), cmd->bd_addr, 6); // 6:size
2112 ble_sm_key_rxed(proc, res);
2113 }
2114
2115 ble_hs_unlock();
2116 }
2117
ble_sm_sign_info_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)2118 static void ble_sm_sign_info_rx(uint16_t conn_handle, struct os_mbuf **om, struct ble_sm_result *res)
2119 {
2120 struct ble_sm_sign_info *cmd;
2121 struct ble_sm_proc *proc;
2122 res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*cmd));
2123 if (res->app_status != 0) {
2124 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
2125 res->enc_cb = 1;
2126 return;
2127 }
2128
2129 cmd = (struct ble_sm_sign_info *)(*om)->om_data;
2130 ble_hs_lock();
2131 proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_KEY_EXCH, -1, NULL);
2132 if (proc == NULL) {
2133 res->app_status = BLE_HS_ENOENT;
2134 res->sm_err = BLE_SM_ERR_UNSPECIFIED;
2135 } else {
2136 proc->rx_key_flags &= ~BLE_SM_KE_F_SIGN_INFO;
2137 memcpy_s(proc->peer_keys.csrk, sizeof(proc->peer_keys.csrk), cmd->sig_key, 16); // 16:size
2138 proc->peer_keys.csrk_valid = 1;
2139 ble_sm_key_rxed(proc, res);
2140 }
2141
2142 ble_hs_unlock();
2143 }
2144
2145 /*****************************************************************************
2146 * $fail *
2147 *****************************************************************************/
2148
ble_sm_fail_rx(uint16_t conn_handle,struct os_mbuf ** om,struct ble_sm_result * res)2149 static void ble_sm_fail_rx(uint16_t conn_handle, struct os_mbuf **om, struct ble_sm_result *res)
2150 {
2151 struct ble_sm_pair_fail *cmd;
2152 res->enc_cb = 1;
2153 res->app_status = ble_hs_mbuf_pullup_base(om, sizeof(*cmd));
2154 if (res->app_status == 0) {
2155 cmd = (struct ble_sm_pair_fail *)(*om)->om_data;
2156 res->app_status = BLE_HS_SM_PEER_ERR(cmd->reason);
2157 }
2158 }
2159
2160 /*****************************************************************************
2161 * $api *
2162 *****************************************************************************/
2163
2164 /**
2165 * Times out expired SM procedures.
2166 *
2167 * @return The number of ticks until this function should
2168 * be called again.
2169 */
ble_sm_timer(void)2170 int32_t ble_sm_timer(void)
2171 {
2172 struct ble_sm_proc_list exp_list;
2173 struct ble_sm_proc *proc;
2174 int32_t ticks_until_exp;
2175 /* Remove timed-out procedures from the main list and insert them into a
2176 * temporary list. This function also calculates the number of ticks until
2177 * the next expiration will occur.
2178 */
2179 ticks_until_exp = ble_sm_extract_expired(&exp_list);
2180
2181 /* Notify application of each failure and free the corresponding procedure
2182 * object.
2183 * XXX: Mark connection as tainted; don't allow any subsequent SMP
2184 * procedures without reconnect.
2185 */
2186 while ((proc = STAILQ_FIRST(&exp_list)) != NULL) {
2187 ble_gap_enc_event(proc->conn_handle, BLE_HS_ETIMEOUT, 0);
2188 STAILQ_REMOVE_HEAD(&exp_list, next);
2189 ble_sm_proc_free(proc);
2190 }
2191
2192 return ticks_until_exp;
2193 }
2194
2195 /**
2196 * Initiates the pairing procedure for the specified connection.
2197 */
ble_sm_pair_initiate(uint16_t conn_handle)2198 int ble_sm_pair_initiate(uint16_t conn_handle)
2199 {
2200 struct ble_sm_result res;
2201 struct ble_sm_proc *proc;
2202 int rc;
2203 memset_s(&res, sizeof(res), 0, sizeof(res));
2204 /* Make sure a procedure isn't already in progress for this connection. */
2205 ble_hs_lock();
2206 proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, NULL);
2207 ble_hs_unlock();
2208
2209 if (proc != NULL) {
2210 res.app_status = BLE_HS_EALREADY;
2211 return BLE_HS_EALREADY;
2212 }
2213
2214 /* Check if there is storage capacity for a new bond. If there isn't, ask
2215 * the application to make room.
2216 */
2217 rc = ble_sm_chk_store_overflow(conn_handle);
2218 if (rc != 0) {
2219 return rc;
2220 }
2221
2222 proc = ble_sm_proc_alloc();
2223 if (proc == NULL) {
2224 res.app_status = BLE_HS_ENOMEM;
2225 } else {
2226 proc->conn_handle = conn_handle;
2227 proc->state = BLE_SM_PROC_STATE_PAIR;
2228 proc->flags |= BLE_SM_PROC_F_INITIATOR;
2229 ble_hs_lock();
2230 ble_sm_insert(proc);
2231 ble_hs_unlock();
2232 res.execute = 1;
2233 }
2234
2235 if (proc != NULL) {
2236 ble_sm_process_result(conn_handle, &res);
2237 }
2238
2239 return res.app_status;
2240 }
2241
ble_sm_slave_initiate(uint16_t conn_handle)2242 int ble_sm_slave_initiate(uint16_t conn_handle)
2243 {
2244 struct ble_sm_result res;
2245 struct ble_sm_proc *proc;
2246 memset_s(&res, sizeof(res), 0, sizeof(res));
2247 ble_hs_lock();
2248 /* Make sure a procedure isn't already in progress for this connection. */
2249 proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, NULL);
2250 if (proc != NULL) {
2251 res.app_status = BLE_HS_EALREADY;
2252 /* Set pointer to null so that existing entry doesn't get freed. */
2253 proc = NULL;
2254 } else {
2255 proc = ble_sm_proc_alloc();
2256 if (proc == NULL) {
2257 res.app_status = BLE_HS_ENOMEM;
2258 } else {
2259 proc->conn_handle = conn_handle;
2260 proc->state = BLE_SM_PROC_STATE_SEC_REQ;
2261 ble_sm_insert(proc);
2262 res.execute = 1;
2263 }
2264 }
2265
2266 ble_hs_unlock();
2267
2268 if (proc != NULL) {
2269 ble_sm_process_result(conn_handle, &res);
2270 }
2271
2272 return res.app_status;
2273 }
2274
2275 /**
2276 * Initiates the encryption procedure for the specified connection.
2277 */
ble_sm_enc_initiate(uint16_t conn_handle,uint8_t key_size,const uint8_t * ltk,uint16_t ediv,uint64_t rand_val,int auth)2278 int ble_sm_enc_initiate(uint16_t conn_handle, uint8_t key_size,
2279 const uint8_t *ltk, uint16_t ediv,
2280 uint64_t rand_val, int auth)
2281 {
2282 struct ble_sm_result res;
2283 struct ble_sm_proc *proc;
2284 struct hci_start_encrypt cmd;
2285 memset_s(&res, sizeof res, 0, sizeof res);
2286 /* Make sure a procedure isn't already in progress for this connection. */
2287 ble_hs_lock();
2288 proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, NULL);
2289 if (proc != NULL) {
2290 res.app_status = BLE_HS_EALREADY;
2291 /* Set pointer to null so that existing entry doesn't get freed. */
2292 proc = NULL;
2293 } else {
2294 proc = ble_sm_proc_alloc();
2295 if (proc == NULL) {
2296 res.app_status = BLE_HS_ENOMEM;
2297 } else {
2298 proc->conn_handle = conn_handle;
2299 proc->key_size = key_size;
2300 proc->state = BLE_SM_PROC_STATE_ENC_RESTORE;
2301 proc->flags |= BLE_SM_PROC_F_INITIATOR;
2302
2303 if (auth) {
2304 proc->flags |= BLE_SM_PROC_F_AUTHENTICATED;
2305 }
2306
2307 ble_sm_insert(proc);
2308 cmd.connection_handle = conn_handle;
2309 cmd.encrypted_diversifier = ediv;
2310 cmd.random_number = rand_val;
2311 memcpy_s(cmd.long_term_key, sizeof(cmd.long_term_key), ltk, sizeof cmd.long_term_key);
2312 res.execute = 1;
2313 res.state_arg = &cmd;
2314 }
2315 }
2316
2317 ble_hs_unlock();
2318 ble_sm_process_result(conn_handle, &res);
2319 return res.app_status;
2320 }
2321
ble_sm_rx(struct ble_l2cap_chan * chan)2322 static int ble_sm_rx(struct ble_l2cap_chan *chan)
2323 {
2324 struct ble_sm_result res;
2325 ble_sm_rx_fn *rx_cb;
2326 uint8_t op;
2327 uint16_t conn_handle;
2328 struct os_mbuf **om;
2329 int rc;
2330 STATS_INC(ble_l2cap_stats, sm_rx);
2331 conn_handle = ble_l2cap_get_conn_handle(chan);
2332 if (conn_handle == BLE_HS_CONN_HANDLE_NONE) {
2333 return BLE_HS_ENOTCONN;
2334 }
2335
2336 om = &chan->rx_buf;
2337 BLE_HS_DBG_ASSERT(*om != NULL);
2338 rc = os_mbuf_copydata(*om, 0, 1, &op);
2339 if (rc != 0) {
2340 return BLE_HS_EBADDATA;
2341 }
2342
2343 /* Strip L2CAP SM header from the front of the mbuf. */
2344 os_mbuf_adj(*om, 1);
2345 rx_cb = ble_sm_dispatch_get(op);
2346 if (rx_cb != NULL) {
2347 memset_s(&res, sizeof res, 0, sizeof res);
2348 rx_cb(conn_handle, om, &res);
2349 ble_sm_process_result(conn_handle, &res);
2350 rc = res.app_status;
2351 } else {
2352 rc = BLE_HS_ENOTSUP;
2353 }
2354
2355 return rc;
2356 }
2357
ble_sm_inject_io(uint16_t conn_handle,struct ble_sm_io * pkey)2358 int ble_sm_inject_io(uint16_t conn_handle, struct ble_sm_io *pkey)
2359 {
2360 struct ble_sm_result res;
2361 struct ble_sm_proc *proc;
2362 int rc;
2363 uint8_t action;
2364 memset_s(&res, sizeof res, 0, sizeof res);
2365 ble_hs_lock();
2366 proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, NULL);
2367 if (proc == NULL) {
2368 rc = BLE_HS_ENOENT;
2369 } else if (proc->flags & BLE_SM_PROC_F_IO_INJECTED) {
2370 rc = BLE_HS_EALREADY;
2371 } else if ((ble_sm_io_action(proc, &action) == 0) && pkey->action != action) {
2372 /* Application provided incorrect IO type. */
2373 rc = BLE_HS_EINVAL;
2374 } else if (ble_sm_ioact_state(pkey->action) != proc->state) {
2375 /* Procedure is not ready for user input. */
2376 rc = BLE_HS_EINVAL;
2377 } else {
2378 /* Assume valid input. */
2379 rc = 0;
2380
2381 switch (pkey->action) {
2382 case BLE_SM_IOACT_OOB:
2383 proc->flags |= BLE_SM_PROC_F_IO_INJECTED;
2384 memcpy_s(proc->tk, sizeof(proc->tk), pkey->oob, 16); // 16:size
2385
2386 if ((proc->flags & BLE_SM_PROC_F_INITIATOR) ||
2387 (proc->flags & BLE_SM_PROC_F_ADVANCE_ON_IO)) {
2388 res.execute = 1;
2389 }
2390
2391 break;
2392
2393 case BLE_SM_IOACT_INPUT:
2394 case BLE_SM_IOACT_DISP:
2395 if (pkey->passkey > 999999) { // 99999:Analyzing conditions
2396 rc = BLE_HS_EINVAL;
2397 } else {
2398 proc->flags |= BLE_SM_PROC_F_IO_INJECTED;
2399 memset_s(proc->tk, 16, 0, 16); // 16:size
2400 proc->tk[0] = (pkey->passkey >> 0) & 0xff;
2401 proc->tk[1] = (pkey->passkey >> 8) & 0xff; // 8:byte alignment
2402 proc->tk[2] = (pkey->passkey >> 16) & 0xff; // 16:byte alignment, 2:array element
2403 proc->tk[3] = (pkey->passkey >> 24) & 0xff; // 24:byte alignment, 3:array element
2404
2405 if ((proc->flags & BLE_SM_PROC_F_INITIATOR) ||
2406 (proc->flags & BLE_SM_PROC_F_ADVANCE_ON_IO)) {
2407 res.execute = 1;
2408 }
2409 }
2410
2411 break;
2412
2413 case BLE_SM_IOACT_NUMCMP:
2414 if (!pkey->numcmp_accept) {
2415 res.app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_NUMCMP);
2416 res.sm_err = BLE_SM_ERR_NUMCMP;
2417 } else {
2418 proc->flags |= BLE_SM_PROC_F_IO_INJECTED;
2419
2420 if ((proc->flags & BLE_SM_PROC_F_INITIATOR) ||
2421 (proc->flags & BLE_SM_PROC_F_ADVANCE_ON_IO)) {
2422 res.execute = 1;
2423 }
2424 }
2425
2426 break;
2427 #if MYNEWT_VAL(BLE_SM_SC)
2428
2429 case BLE_SM_IOACT_OOB_SC:
2430 if (!ble_sm_sc_oob_data_check(proc,
2431 (pkey->oob_sc_data.local != NULL),
2432 (pkey->oob_sc_data.remote != NULL))) {
2433 res.app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_OOB);
2434 res.sm_err = BLE_SM_ERR_OOB;
2435 } else {
2436 proc->flags |= BLE_SM_PROC_F_IO_INJECTED;
2437 proc->oob_data_local = pkey->oob_sc_data.local;
2438 proc->oob_data_remote = pkey->oob_sc_data.remote;
2439 /* Execute Confirm step */
2440 ble_sm_sc_oob_confirm(proc, &res);
2441 }
2442
2443 break;
2444 #endif
2445
2446 default:
2447 BLE_HS_DBG_ASSERT(0);
2448 rc = BLE_HS_EINVAL;
2449 break;
2450 }
2451 }
2452
2453 ble_hs_unlock();
2454
2455 /* If application provided invalid input, return error without modifying
2456 * SMP state.
2457 */
2458 if (rc != 0) {
2459 return rc;
2460 }
2461
2462 ble_sm_process_result(conn_handle, &res);
2463 return res.app_status;
2464 }
2465
ble_sm_connection_broken(uint16_t conn_handle)2466 void ble_sm_connection_broken(uint16_t conn_handle)
2467 {
2468 struct ble_sm_result res;
2469 memset_s(&res, sizeof(res), 0, sizeof(res));
2470 res.app_status = BLE_HS_ENOTCONN;
2471 res.enc_cb = 1;
2472 ble_sm_process_result(conn_handle, &res);
2473 }
2474
ble_sm_init(void)2475 int ble_sm_init(void)
2476 {
2477 int rc;
2478 STAILQ_INIT(&ble_sm_procs);
2479 rc = os_mempool_init(&ble_sm_proc_pool,
2480 MYNEWT_VAL(BLE_SM_MAX_PROCS),
2481 sizeof(struct ble_sm_proc),
2482 ble_sm_proc_mem,
2483 "ble_sm_proc_pool");
2484 if (rc != 0) {
2485 return rc;
2486 }
2487
2488 ble_sm_sc_init();
2489 return 0;
2490 }
2491 #else
2492 /* if pairing is not supported it is only needed to reply with Pairing
2493 * Failed with 'Pairing not Supported' reason so this function can be very
2494 * simple
2495 */
ble_sm_rx(struct ble_l2cap_chan * chan)2496 static int ble_sm_rx(struct ble_l2cap_chan *chan)
2497 {
2498 struct ble_sm_pair_fail *cmd;
2499 struct os_mbuf *txom;
2500 uint16_t handle;
2501 int rc;
2502 handle = ble_l2cap_get_conn_handle(chan);
2503 if (!handle) {
2504 return BLE_HS_ENOTCONN;
2505 }
2506
2507 cmd = ble_sm_cmd_get(BLE_SM_OP_PAIR_FAIL, sizeof(*cmd), &txom);
2508 if (cmd == NULL) {
2509 return BLE_HS_ENOMEM;
2510 }
2511
2512 cmd->reason = BLE_SM_ERR_PAIR_NOT_SUPP;
2513 ble_hs_lock();
2514 rc = ble_sm_tx(handle, txom);
2515 ble_hs_unlock();
2516 return rc;
2517 }
2518 #endif
2519
ble_sm_create_chan(uint16_t conn_handle)2520 struct ble_l2cap_chan *ble_sm_create_chan(uint16_t conn_handle)
2521 {
2522 struct ble_l2cap_chan *chan;
2523 chan = ble_l2cap_chan_alloc(conn_handle);
2524 if (chan == NULL) {
2525 return NULL;
2526 }
2527
2528 chan->scid = BLE_L2CAP_CID_SM;
2529 chan->dcid = BLE_L2CAP_CID_SM;
2530 chan->my_mtu = BLE_SM_MTU;
2531 chan->rx_fn = ble_sm_rx;
2532 return chan;
2533 }