BLE Host - Add peer address to ltk store.
Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/7b6fcb93 Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/7b6fcb93 Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/7b6fcb93 Branch: refs/heads/develop Commit: 7b6fcb93922587c40480eb492a15d9421d830958 Parents: 23fda23 Author: Christopher Collins <[email protected]> Authored: Wed May 25 09:36:17 2016 -0700 Committer: Christopher Collins <[email protected]> Committed: Wed May 25 12:16:46 2016 -0700 ---------------------------------------------------------------------- net/nimble/host/include/host/ble_store.h | 20 +++++ net/nimble/host/src/ble_att_svr.c | 23 ++--- net/nimble/host/src/ble_l2cap_sm.c | 90 +++++++++++++------- net/nimble/host/src/ble_store.c | 20 +++++ .../host/src/test/ble_hs_test_util_store.c | 37 +++++--- net/nimble/host/src/test/ble_l2cap_sm_test.c | 1 + 6 files changed, 139 insertions(+), 52 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7b6fcb93/net/nimble/host/include/host/ble_store.h ---------------------------------------------------------------------- diff --git a/net/nimble/host/include/host/ble_store.h b/net/nimble/host/include/host/ble_store.h index 5d54ce9..08bcb9e 100644 --- a/net/nimble/host/include/host/ble_store.h +++ b/net/nimble/host/include/host/ble_store.h @@ -27,17 +27,35 @@ #define BLE_STORE_OBJ_TYPE_CCCD 3 #define BLE_STORE_PEER_ADDR_TYPE_NONE 0xff +#define BLE_STORE_AUTHREQ_NONE 0xff struct ble_store_key_ltk { + /** + * Key by peer identity address; + * peer_addr_type=BLE_STORE_PEER_ADDR_TYPE_NONE means don't key off peer. + */ + uint8_t addr[6]; + uint8_t addr_type; + + /** Key by ediv; ediv_present=0 means don't key off ediv. */ uint16_t ediv; + unsigned ediv_present:1; + + /** Key by rand_num; rand_num_present=0 means don't key off rand_num. */ uint64_t rand_num; + unsigned rand_num_present:1; }; struct ble_store_value_ltk { + uint8_t addr[6]; + uint8_t addr_type; uint16_t ediv; uint64_t rand_num; uint8_t key[16]; + unsigned authenticated:1; + unsigned sc:1; + }; struct ble_store_key_cccd { @@ -88,6 +106,8 @@ int ble_store_read(int obj_type, union ble_store_key *key, int ble_store_write(int obj_type, union ble_store_value *val); int ble_store_delete(int obj_type, union ble_store_key *key); +int ble_store_read_peer_ltk(struct ble_store_key_ltk *key_ltk, + struct ble_store_value_ltk *value_ltk); int ble_store_read_cccd(struct ble_store_key_cccd *key, struct ble_store_value_cccd *out_value); int ble_store_write_cccd(struct ble_store_value_cccd *value); http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7b6fcb93/net/nimble/host/src/ble_att_svr.c ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/ble_att_svr.c b/net/nimble/host/src/ble_att_svr.c index 47e4418..49238ac 100644 --- a/net/nimble/host/src/ble_att_svr.c +++ b/net/nimble/host/src/ble_att_svr.c @@ -357,17 +357,20 @@ ble_att_svr_write(uint16_t conn_handle, struct ble_att_svr_entry *entry, BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task()); - if (conn_handle != BLE_HS_CONN_HANDLE_NONE && - !(entry->ha_flags & BLE_ATT_F_WRITE)) { - - att_err = BLE_ATT_ERR_WRITE_NOT_PERMITTED; - rc = BLE_HS_ENOTSUP; - goto err; - } + /* Bypass permissions and security checks if we are writing our own + * attribute. + */ + if (conn_handle != BLE_HS_CONN_HANDLE_NONE) { + if (!(entry->ha_flags & BLE_ATT_F_WRITE)) { + att_err = BLE_ATT_ERR_WRITE_NOT_PERMITTED; + rc = BLE_HS_ENOTSUP; + goto err; + } - rc = ble_att_svr_check_security(conn_handle, 0, entry, &att_err); - if (rc != 0) { - goto err; + rc = ble_att_svr_check_security(conn_handle, 0, entry, &att_err); + if (rc != 0) { + goto err; + } } BLE_HS_DBG_ASSERT(entry->ha_cb != NULL); http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7b6fcb93/net/nimble/host/src/ble_l2cap_sm.c ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/ble_l2cap_sm.c b/net/nimble/host/src/ble_l2cap_sm.c index 5f20c18..e9d5230 100644 --- a/net/nimble/host/src/ble_l2cap_sm.c +++ b/net/nimble/host/src/ble_l2cap_sm.c @@ -490,6 +490,7 @@ ble_l2cap_sm_key_exchange_events(struct ble_l2cap_sm_proc *proc) sizeof store_value.ltk.key); store_value.ltk.authenticated = !!(proc->flags & BLE_L2CAP_SM_PROC_F_AUTHENTICATED); + store_value.ltk.sc = 0; ble_store_write(BLE_STORE_OBJ_TYPE_OUR_LTK, &store_value); } @@ -500,6 +501,7 @@ ble_l2cap_sm_key_exchange_events(struct ble_l2cap_sm_proc *proc) sizeof store_value.ltk.key); store_value.ltk.authenticated = !!(proc->flags & BLE_L2CAP_SM_PROC_F_AUTHENTICATED); + store_value.ltk.sc = 0; ble_store_write(BLE_STORE_OBJ_TYPE_PEER_LTK, &store_value); } @@ -1763,16 +1765,20 @@ ble_l2cap_sm_lt_key_req_ltk_handle(struct hci_le_lt_key_req *evt) union ble_store_key store_key; struct ble_l2cap_sm_proc *proc; struct ble_l2cap_sm_proc *prev; - int app_rc; + int store_rc; int rc; /* Tell applicaiton to look up LTK by ediv/rand pair. */ + /* XXX: Also filter by peer address? */ + memset(&store_key, 0, sizeof store_key); store_key.ltk.ediv = evt->encrypted_diversifier; + store_key.ltk.ediv_present = 1; store_key.ltk.rand_num = evt->random_number; - app_rc = ble_store_read(BLE_STORE_OBJ_TYPE_OUR_LTK, &store_key, - &store_value); - if (app_rc == 0) { - /* App provided a key; send it to the controller. */ + store_key.ltk.rand_num_present = 1; + store_rc = ble_store_read(BLE_STORE_OBJ_TYPE_OUR_LTK, &store_key, + &store_value); + if (store_rc == 0) { + /* Store provided a key; send it to the controller. */ rc = ble_l2cap_sm_lt_key_req_reply_tx(evt->connection_handle, store_value.ltk.key); } else { @@ -1788,7 +1794,7 @@ ble_l2cap_sm_lt_key_req_ltk_handle(struct hci_le_lt_key_req *evt) &prev); if (proc == NULL) { rc = BLE_HS_EUNKNOWN; - } else if (app_rc == 0 && rc == 0) { + } else if (store_rc == 0 && rc == 0) { proc->state = BLE_L2CAP_SM_PROC_STATE_ENC_CHANGE; if (store_value.ltk.authenticated) { proc->flags |= BLE_L2CAP_SM_PROC_F_AUTHENTICATED; @@ -1799,14 +1805,14 @@ ble_l2cap_sm_lt_key_req_ltk_handle(struct hci_le_lt_key_req *evt) ble_hs_unlock(); /* Notify the app if it provided a key and the procedure failed. */ - if (app_rc == 0 && rc != 0) { + if (store_rc == 0 && rc != 0) { ble_l2cap_sm_gap_event(proc, rc, 0); } /* The procedure is aborted if the app didn't provide a key or if there was * a failure. */ - if (app_rc != 0 || rc != 0) { + if (store_rc != 0 || rc != 0) { ble_l2cap_sm_proc_free(proc); } @@ -1928,8 +1934,10 @@ static int ble_l2cap_sm_rx_sec_req(uint16_t conn_handle, uint8_t op, struct os_mbuf **om) { struct ble_l2cap_sm_sec_req cmd; - struct ble_l2cap_sm_proc *proc; + struct ble_store_value_ltk value_ltk; + struct ble_store_key_ltk key_ltk; struct ble_hs_conn *conn; + int authreq_mitm; int rc; rc = ble_hs_misc_pullup_base(om, BLE_L2CAP_SM_SEC_REQ_SZ); @@ -1939,39 +1947,57 @@ ble_l2cap_sm_rx_sec_req(uint16_t conn_handle, uint8_t op, struct os_mbuf **om) ble_l2cap_sm_sec_req_parse((*om)->om_data, (*om)->om_len, &cmd); + /* XXX: Reject if: + * o authreq-bonded flag not set? + * o authreq-reserved flags set? + */ + BLE_HS_LOG(DEBUG, "rxed sm sec req; authreq=%d\n", cmd.authreq); ble_hs_lock(); - /* Only handle the security request if a procedure isn't already in - * progress for this connection. - */ - proc = ble_l2cap_sm_proc_find(conn_handle, BLE_L2CAP_SM_PROC_STATE_NONE, - -1, NULL); - if (proc != NULL) { - rc = BLE_HS_EALREADY; + conn = ble_hs_conn_find(conn_handle); + if (conn == NULL) { + rc = BLE_HS_ENOTCONN; + } else if (!(conn->bhc_flags & BLE_HS_CONN_F_MASTER)) { + rc = BLE_HS_SM_US_ERR(BLE_L2CAP_SM_ERR_CMD_NOT_SUPP); + ble_l2cap_sm_pair_fail_tx(conn_handle, BLE_L2CAP_SM_ERR_CMD_NOT_SUPP); } else { - conn = ble_hs_conn_find(conn_handle); - if (conn == NULL) { - rc = BLE_HS_ENOTCONN; - } else if (!(conn->bhc_flags & BLE_HS_CONN_F_MASTER)) { - rc = BLE_HS_SM_US_ERR(BLE_L2CAP_SM_ERR_CMD_NOT_SUPP); - ble_l2cap_sm_pair_fail_tx(conn_handle, - BLE_L2CAP_SM_ERR_CMD_NOT_SUPP); - } else { - rc = 0; - } + rc = 0; + + /* We will be querying the SM database for a key corresponding to the + * sender; remember the sender's address while the connection list is + * locked. + */ + memset(&key_ltk, 0, sizeof key_ltk); + key_ltk.addr_type = conn->bhc_addr_type; + memcpy(key_ltk.addr, conn->bhc_addr, 6); } ble_hs_unlock(); if (rc == 0) { - /* XXX: Ask app / someone if there is a persisted LTK such that: - * o It corresponds to this peer. - * o It meets the specified authreq criteria. - * For now, assume we don't have an appropriate LTK; initiate pairing. - */ - rc = ble_l2cap_sm_pair_initiate(conn_handle); + /* Query database for an LTK corresonding to the sender. */ + rc = ble_store_read_peer_ltk(&key_ltk, &value_ltk); + if (rc == 0) { + /* Found a key corresponding to this peer. Make sure it meets the + * requested minimum authreq. + */ + authreq_mitm = cmd.authreq & BLE_L2CAP_SM_PAIR_AUTHREQ_MITM; + if ((!authreq_mitm && value_ltk.authenticated) || + (authreq_mitm && !value_ltk.authenticated)) { + + rc = BLE_HS_EREJECT; + } + } + + if (rc == 0) { + rc = ble_l2cap_sm_enc_initiate(conn_handle, value_ltk.key, + value_ltk.ediv, value_ltk.rand_num, + value_ltk.authenticated); + } else { + rc = ble_l2cap_sm_pair_initiate(conn_handle); + } } return rc; http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7b6fcb93/net/nimble/host/src/ble_store.c ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/ble_store.c b/net/nimble/host/src/ble_store.c index 267e8d3..580f145 100644 --- a/net/nimble/host/src/ble_store.c +++ b/net/nimble/host/src/ble_store.c @@ -66,6 +66,20 @@ ble_store_delete(int obj_type, union ble_store_key *key) } int +ble_store_read_peer_ltk(struct ble_store_key_ltk *key_ltk, + struct ble_store_value_ltk *value_ltk) +{ + union ble_store_value *store_value; + union ble_store_key *store_key; + int rc; + + store_key = (void *)key_ltk; + store_value = (void *)value_ltk; + rc = ble_store_read(BLE_STORE_OBJ_TYPE_PEER_LTK, store_key, store_value); + return rc; +} + +int ble_store_read_cccd(struct ble_store_key_cccd *key, struct ble_store_value_cccd *out_value) { @@ -115,6 +129,12 @@ void ble_store_key_from_value_ltk(struct ble_store_key_ltk *out_key, struct ble_store_value_ltk *value) { + out_key->addr_type = value->addr_type; + memcpy(out_key->addr, value->addr, sizeof out_key->addr); + out_key->ediv = value->ediv; + out_key->ediv_present = 1; + out_key->rand_num = value->rand_num; + out_key->rand_num_present = 1; } http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7b6fcb93/net/nimble/host/src/test/ble_hs_test_util_store.c ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/test/ble_hs_test_util_store.c b/net/nimble/host/src/test/ble_hs_test_util_store.c index 51f6dde..2172ebb 100644 --- a/net/nimble/host/src/test/ble_hs_test_util_store.c +++ b/net/nimble/host/src/test/ble_hs_test_util_store.c @@ -86,15 +86,32 @@ ble_hs_test_util_store_read_ltk(struct ble_store_value_ltk *store, struct ble_store_key_ltk *key, struct ble_store_value_ltk *value) { - struct ble_store_value_ltk *ltk; + struct ble_store_value_ltk *cur; int i; for (i = 0; i < num_values; i++) { - ltk = store + i; - if (ltk->ediv == key->ediv && ltk->rand_num == key->rand_num) { - *value = *ltk; - return 0; + cur = store + i; + + if (key->addr_type != BLE_STORE_PEER_ADDR_TYPE_NONE) { + if (cur->addr_type != key->addr_type) { + continue; + } + + if (memcmp(cur->addr, key->addr, sizeof cur->addr) != 0) { + continue; + } } + + if (key->ediv_present && cur->ediv != key->ediv) { + continue; + } + + if (key->rand_num_present && cur->rand_num != key->rand_num) { + continue; + } + + *value = *cur; + return 0; } return BLE_HS_ENOENT; @@ -103,26 +120,26 @@ ble_hs_test_util_store_read_ltk(struct ble_store_value_ltk *store, static int ble_hs_test_util_store_find_cccd(struct ble_store_key_cccd *key) { - struct ble_store_value_cccd *cccd; + struct ble_store_value_cccd *cur; int skipped; int i; skipped = 0; for (i = 0; i < ble_hs_test_util_store_num_cccds; i++) { - cccd = ble_hs_test_util_store_cccds + i; + cur = ble_hs_test_util_store_cccds + i; if (key->peer_addr_type != BLE_STORE_PEER_ADDR_TYPE_NONE) { - if (cccd->peer_addr_type != key->peer_addr_type) { + if (cur->peer_addr_type != key->peer_addr_type) { continue; } - if (memcmp(cccd->peer_addr, key->peer_addr, 6) != 0) { + if (memcmp(cur->peer_addr, key->peer_addr, 6) != 0) { continue; } } if (key->chr_val_handle != 0) { - if (cccd->chr_val_handle != key->chr_val_handle) { + if (cur->chr_val_handle != key->chr_val_handle) { continue; } } http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7b6fcb93/net/nimble/host/src/test/ble_l2cap_sm_test.c ---------------------------------------------------------------------- diff --git a/net/nimble/host/src/test/ble_l2cap_sm_test.c b/net/nimble/host/src/test/ble_l2cap_sm_test.c index c58396d..d955132 100644 --- a/net/nimble/host/src/test/ble_l2cap_sm_test.c +++ b/net/nimble/host/src/test/ble_l2cap_sm_test.c @@ -1780,6 +1780,7 @@ TEST_CASE(ble_l2cap_sm_test_case_peer_sec_req_inval) ble_l2cap_sm_test_util_verify_tx_pair_fail(&fail); /*** Pairing already in progress; ignore security request. */ + ble_hs_atomic_conn_set_flags(2, BLE_HS_CONN_F_MASTER, 1); rc = ble_l2cap_sm_pair_initiate(2); TEST_ASSERT_FATAL(rc == 0); ble_hs_test_util_tx_all();
