You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by na...@apache.org on 2019/12/09 14:37:30 UTC

[mynewt-nimble] 02/03: nimble/host: Add support for OOB Secure Connections

This is an automated email from the ASF dual-hosted git repository.

naraj pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git

commit b552ba370920614b027f106388b17c573a12246a
Author: MichaƂ Narajowski <mi...@codecoup.pl>
AuthorDate: Tue Dec 3 11:52:10 2019 +0100

    nimble/host: Add support for OOB Secure Connections
    
    Previously we supported only Legacy OOB pairing procedure.
    Secure connections version uses a very different Authentication stage
    which required some changes to the SM code.
    
    SC OOB uses two 128-bit values as OOB data. OOB communication
    is possible in one or both directions. Due to the difference in
    OOB Data compared to the Legacy version, we had to introduce additional
    IO Action that is used in ble_sm_inject_io() API. Also the CONFIRM
    state is omitted as there is no confirmation data sent in-band. The
    confirmation is done when application is passing OOB data to the host
    using ble_sm_inject_io(). The application should call
    ble_sm_sc_oob_generate_data() to generate local OOB data for later use.
---
 nimble/host/include/host/ble_sm.h |  17 ++++-
 nimble/host/src/ble_sm.c          |  21 ++++++
 nimble/host/src/ble_sm_priv.h     |   6 ++
 nimble/host/src/ble_sm_sc.c       | 146 ++++++++++++++++++++++++++++++++++----
 4 files changed, 176 insertions(+), 14 deletions(-)

diff --git a/nimble/host/include/host/ble_sm.h b/nimble/host/include/host/ble_sm.h
index 9bd25ad..ceebb85 100644
--- a/nimble/host/include/host/ble_sm.h
+++ b/nimble/host/include/host/ble_sm.h
@@ -84,7 +84,16 @@ extern "C" {
 #define BLE_SM_IOACT_INPUT                      2
 #define BLE_SM_IOACT_DISP                       3
 #define BLE_SM_IOACT_NUMCMP                     4
-#define BLE_SM_IOACT_MAX_PLUS_ONE               5
+#define BLE_SM_IOACT_OOB_SC                     5
+#define BLE_SM_IOACT_MAX_PLUS_ONE               6
+
+struct ble_sm_sc_oob_data {
+    /** Random Number. */
+    uint8_t r[16];
+
+    /** Confirm Value. */
+    uint8_t c[16];
+};
 
 struct ble_sm_io {
     uint8_t action;
@@ -92,9 +101,15 @@ struct ble_sm_io {
         uint32_t passkey;
         uint8_t  oob[16];
         uint8_t  numcmp_accept;
+        struct {
+            struct ble_sm_sc_oob_data *local;
+            struct ble_sm_sc_oob_data *remote;
+        } oob_sc_data;
     };
 };
 
+int ble_sm_sc_oob_generate_data(struct ble_sm_sc_oob_data *oob_data);
+
 #if NIMBLE_BLE_SM
 int ble_sm_inject_io(uint16_t conn_handle, struct ble_sm_io *pkey);
 #else
diff --git a/nimble/host/src/ble_sm.c b/nimble/host/src/ble_sm.c
index 8ce5c9f..c83426d 100644
--- a/nimble/host/src/ble_sm.c
+++ b/nimble/host/src/ble_sm.c
@@ -740,6 +740,9 @@ ble_sm_ioact_state(uint8_t action)
     case BLE_SM_IOACT_NUMCMP:
         return BLE_SM_PROC_STATE_DHKEY_CHECK;
 
+    case BLE_SM_IOACT_OOB_SC:
+        return BLE_SM_PROC_STATE_RANDOM;
+
     case BLE_SM_IOACT_OOB:
     case BLE_SM_IOACT_INPUT:
     case BLE_SM_IOACT_DISP:
@@ -2668,6 +2671,24 @@ ble_sm_inject_io(uint16_t conn_handle, struct ble_sm_io *pkey)
             }
             break;
 
+#if MYNEWT_VAL(BLE_SM_SC)
+        case BLE_SM_IOACT_OOB_SC:
+            if (!ble_sm_sc_oob_data_check(proc,
+                                          (pkey->oob_sc_data.local != NULL),
+                                          (pkey->oob_sc_data.remote != NULL))) {
+                res.app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_OOB);
+                res.sm_err = BLE_SM_ERR_OOB;
+            } else {
+                proc->flags |= BLE_SM_PROC_F_IO_INJECTED;
+                proc->oob_data_local = pkey->oob_sc_data.local;
+                proc->oob_data_remote = pkey->oob_sc_data.remote;
+
+                /* Execute Confirm step */
+                ble_sm_sc_oob_confirm(proc, &res);
+            }
+            break;
+#endif
+
         default:
             BLE_HS_DBG_ASSERT(0);
             rc = BLE_HS_EINVAL;
diff --git a/nimble/host/src/ble_sm_priv.h b/nimble/host/src/ble_sm_priv.h
index 5c770ca..6d5601b 100644
--- a/nimble/host/src/ble_sm_priv.h
+++ b/nimble/host/src/ble_sm_priv.h
@@ -269,6 +269,8 @@ struct ble_sm_proc {
     struct ble_sm_public_key pub_key_peer;
     uint8_t mackey[16];
     uint8_t dhkey[32];
+    const struct ble_sm_sc_oob_data *oob_data_local;
+    const struct ble_sm_sc_oob_data *oob_data_remote;
 #endif
 };
 
@@ -353,6 +355,10 @@ void ble_sm_sc_dhkey_check_exec(struct ble_sm_proc *proc,
                                 struct ble_sm_result *res, void *arg);
 void ble_sm_sc_dhkey_check_rx(uint16_t conn_handle, struct os_mbuf **rxom,
                               struct ble_sm_result *res);
+bool ble_sm_sc_oob_data_check(struct ble_sm_proc *proc,
+                              bool oob_data_local_present,
+                              bool oob_data_remote_present);
+void ble_sm_sc_oob_confirm(struct ble_sm_proc *proc, struct ble_sm_result *res);
 void ble_sm_sc_init(void);
 #else
 #define ble_sm_sc_io_action(proc, action) (BLE_HS_ENOTSUP)
diff --git a/nimble/host/src/ble_sm_sc.c b/nimble/host/src/ble_sm_sc.c
index 1e705c0..562f33b 100644
--- a/nimble/host/src/ble_sm_sc.c
+++ b/nimble/host/src/ble_sm_sc.c
@@ -106,7 +106,7 @@ ble_sm_sc_io_action(struct ble_sm_proc *proc, uint8_t *action)
 
     if (pair_req->oob_data_flag == BLE_SM_PAIR_OOB_YES ||
         pair_rsp->oob_data_flag == BLE_SM_PAIR_OOB_YES) {
-        *action = BLE_SM_IOACT_OOB;
+        *action = BLE_SM_IOACT_OOB_SC;
     } else if (!(pair_req->authreq & BLE_SM_PAIR_AUTHREQ_MITM) &&
                !(pair_rsp->authreq & BLE_SM_PAIR_AUTHREQ_MITM)) {
 
@@ -125,7 +125,7 @@ ble_sm_sc_io_action(struct ble_sm_proc *proc, uint8_t *action)
         proc->pair_alg = BLE_SM_PAIR_ALG_JW;
         break;
 
-    case BLE_SM_IOACT_OOB:
+    case BLE_SM_IOACT_OOB_SC:
         proc->pair_alg = BLE_SM_PAIR_ALG_OOB;
         proc->flags |= BLE_SM_PROC_F_AUTHENTICATED;
         break;
@@ -233,11 +233,11 @@ ble_sm_sc_gen_ri(struct ble_sm_proc *proc)
 {
     int byte;
     int bit;
-    int rc;
 
     switch (proc->pair_alg) {
     case BLE_SM_PAIR_ALG_JW:
     case BLE_SM_PAIR_ALG_NUMCMP:
+    case BLE_SM_PAIR_ALG_OOB:
         proc->ri = 0;
         return 0;
 
@@ -253,10 +253,6 @@ ble_sm_sc_gen_ri(struct ble_sm_proc *proc)
 
         return 0;
 
-    case BLE_SM_PAIR_ALG_OOB:
-        rc = ble_hs_hci_util_rand(&proc->ri, 1);
-        return rc;
-
     default:
         BLE_HS_DBG_ASSERT(0);
         return BLE_HS_EUNKNOWN;
@@ -264,6 +260,43 @@ ble_sm_sc_gen_ri(struct ble_sm_proc *proc)
 }
 
 void
+ble_sm_sc_oob_confirm(struct ble_sm_proc *proc, struct ble_sm_result *res)
+{
+    int err;
+    bool match;
+    uint8_t c[16];
+
+    /* Authentication stage 1: Step 5 */
+    if (proc->oob_data_remote) {
+        err = ble_sm_alg_f4(proc->pub_key_peer.x, proc->pub_key_peer.x,
+                            proc->oob_data_remote->r, 0, c);
+        if (err) {
+            res->sm_err = BLE_SM_ERR_UNSPECIFIED;
+            res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_UNSPECIFIED);
+            res->enc_cb = 1;
+            return;
+        }
+
+        match = (memcmp(c, proc->oob_data_remote->c, sizeof(c)) == 0);
+        if (!match) {
+            /* Random number mismatch. */
+            res->sm_err = BLE_SM_ERR_CONFIRM_MISMATCH;
+            res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CONFIRM_MISMATCH);
+            res->enc_cb = 1;
+            return;
+        }
+    }
+
+    if ((proc->flags & BLE_SM_PROC_F_INITIATOR) ||
+        (proc->flags & BLE_SM_PROC_F_ADVANCE_ON_IO)) {
+        /* If is initiator or was waiting on
+         * IO then execute step 6: send Random
+         */
+        res->execute = 1;
+    }
+}
+
+void
 ble_sm_sc_confirm_exec(struct ble_sm_proc *proc, struct ble_sm_result *res)
 {
     struct ble_sm_pair_confirm *cmd;
@@ -414,8 +447,9 @@ ble_sm_sc_random_rx(struct ble_sm_proc *proc, struct ble_sm_result *res)
     uint8_t rat;
     int rc;
 
-    if (proc->flags & BLE_SM_PROC_F_INITIATOR ||
-        ble_sm_sc_responder_verifies_random(proc)) {
+    if (proc->pair_alg != BLE_SM_PAIR_ALG_OOB && (
+        proc->flags & BLE_SM_PROC_F_INITIATOR ||
+        ble_sm_sc_responder_verifies_random(proc))) {
 
         BLE_HS_LOG(DEBUG, "tk=");
         ble_hs_log_flat_buf(proc->tk, 16);
@@ -487,7 +521,12 @@ ble_sm_sc_random_rx(struct ble_sm_proc *proc, struct ble_sm_result *res)
             res->execute = 1;
         }
     } else {
-        res->execute = 1;
+        if (proc->pair_alg == BLE_SM_PAIR_ALG_OOB &&
+            !(proc->flags & BLE_SM_PROC_F_IO_INJECTED)) {
+            proc->flags |= BLE_SM_PROC_F_ADVANCE_ON_IO;
+        } else {
+            res->execute = 1;
+        }
     }
 }
 
@@ -526,7 +565,11 @@ ble_sm_sc_public_key_exec(struct ble_sm_proc *proc, struct ble_sm_result *res,
     }
 
     if (!(proc->flags & BLE_SM_PROC_F_INITIATOR)) {
-        proc->state = BLE_SM_PROC_STATE_CONFIRM;
+        if (proc->pair_alg == BLE_SM_PAIR_ALG_OOB) {
+            proc->state = BLE_SM_PROC_STATE_RANDOM;
+        } else {
+            proc->state = BLE_SM_PROC_STATE_CONFIRM;
+        }
 
         rc = ble_sm_sc_io_action(proc, &ioact);
         if (rc != 0) {
@@ -587,8 +630,11 @@ ble_sm_sc_public_key_rx(uint16_t conn_handle, struct os_mbuf **om,
             res->enc_cb = 1;
         } else {
             if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
-
-                proc->state = BLE_SM_PROC_STATE_CONFIRM;
+                if (proc->pair_alg == BLE_SM_PAIR_ALG_OOB) {
+                    proc->state = BLE_SM_PROC_STATE_RANDOM;
+                } else {
+                    proc->state = BLE_SM_PROC_STATE_CONFIRM;
+                }
 
                 rc = ble_sm_sc_io_action(proc, &ioact);
                 if (rc != 0) {
@@ -650,6 +696,14 @@ ble_sm_sc_dhkey_check_exec(struct ble_sm_proc *proc, struct ble_sm_result *res,
         iocap = &pair_rsp->io_cap;
     }
 
+    if (proc->pair_alg == BLE_SM_PAIR_ALG_OOB) {
+        if (proc->oob_data_remote) {
+            memcpy(proc->tk, proc->oob_data_remote->r, 16);
+        } else {
+            memset(proc->tk, 0, 16);
+        }
+    }
+
     ble_sm_sc_dhkey_addrs(proc, &our_addr, &peer_addr);
 
     cmd = ble_sm_cmd_get(BLE_SM_OP_PAIR_DHKEY_CHECK, sizeof(*cmd), &txom);
@@ -701,11 +755,27 @@ ble_sm_dhkey_check_process(struct ble_sm_proc *proc,
 
         pair_rsp  = (struct ble_sm_pair_cmd *) &proc->pair_rsp[1];
         iocap = &pair_rsp->io_cap;
+
+        if (proc->pair_alg == BLE_SM_PAIR_ALG_OOB) {
+            if (pair_rsp->oob_data_flag) {
+                memcpy(proc->tk, proc->oob_data_local->r, 16);
+            } else {
+                memset(proc->tk, 0, 16);
+            }
+        }
     } else {
         struct ble_sm_pair_cmd *pair_req;
 
         pair_req  = (struct ble_sm_pair_cmd *) &proc->pair_req[1];
         iocap = &pair_req->io_cap;
+
+        if (proc->pair_alg == BLE_SM_PAIR_ALG_OOB) {
+            if (pair_req->oob_data_flag) {
+                memcpy(proc->tk, proc->oob_data_local->r, 16);
+            } else {
+                memset(proc->tk, 0, 16);
+            }
+        }
     }
 
     ble_sm_sc_dhkey_addrs(proc, &our_addr, &peer_addr);
@@ -779,6 +849,56 @@ ble_sm_sc_dhkey_check_rx(uint16_t conn_handle, struct os_mbuf **om,
     ble_hs_unlock();
 }
 
+bool
+ble_sm_sc_oob_data_check(struct ble_sm_proc *proc,
+                         bool oob_data_local_present,
+                         bool oob_data_remote_present)
+{
+    struct ble_sm_pair_cmd *pair_req;
+    struct ble_sm_pair_cmd *pair_rsp;
+    bool req_oob_present;
+    bool rsp_oob_present;
+
+    pair_req = (struct ble_sm_pair_cmd *) &proc->pair_req[1];
+    pair_rsp = (struct ble_sm_pair_cmd *) &proc->pair_rsp[1];
+    req_oob_present = pair_req->oob_data_flag == BLE_SM_PAIR_OOB_YES;
+    rsp_oob_present = pair_rsp->oob_data_flag == BLE_SM_PAIR_OOB_YES;
+
+    if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
+        return req_oob_present == oob_data_remote_present;
+    } else {
+        return rsp_oob_present == oob_data_remote_present;
+    }
+}
+
+int
+ble_sm_sc_oob_generate_data(struct ble_sm_sc_oob_data *oob_data)
+{
+    int rc;
+
+#if !MYNEWT_VAL(BLE_SM_SC)
+    return BLE_HS_ENOTSUP;
+#endif
+
+    rc = ble_sm_sc_ensure_keys_generated();
+    if (rc) {
+        return rc;
+    }
+
+    rc = ble_hs_hci_util_rand(oob_data->r, 16);
+    if (rc) {
+        return rc;
+    }
+
+    rc = ble_sm_alg_f4(ble_sm_sc_pub_key, ble_sm_sc_pub_key, oob_data->r, 0,
+                       oob_data->c);
+    if (rc) {
+        return rc;
+    }
+
+    return 0;
+}
+
 void
 ble_sm_sc_init(void)
 {