Bluetooth: Fix error returns for Read Local OOB Extended Data commands
[firefly-linux-kernel-4.4.55.git] / net / bluetooth / smp.c
index c8382f4fcd5c28168b83966453d6730f4908cb9d..1ec3f66b5a74ec1027efa078409cfbcf88e18c73 100644 (file)
@@ -78,7 +78,7 @@ struct smp_dev {
        /* Secure Connections OOB data */
        u8                      local_pk[64];
        u8                      local_sk[32];
-       u8                      local_rr[16];
+       u8                      local_rand[16];
        bool                    debug_key;
 
        struct crypto_blkcipher *tfm_aes;
@@ -569,14 +569,14 @@ int smp_generate_oob(struct hci_dev *hdev, u8 hash[16], u8 rand[16])
        SMP_DBG("OOB Public Key Y: %32phN", smp->local_pk + 32);
        SMP_DBG("OOB Private Key:  %32phN", smp->local_sk);
 
-       get_random_bytes(smp->local_rr, 16);
+       get_random_bytes(smp->local_rand, 16);
 
        err = smp_f4(smp->tfm_cmac, smp->local_pk, smp->local_pk,
-                    smp->local_rr, 0, hash);
+                    smp->local_rand, 0, hash);
        if (err < 0)
                return err;
 
-       memcpy(rand, smp->local_rr, 16);
+       memcpy(rand, smp->local_rand, 16);
 
        return 0;
 }
@@ -685,6 +685,8 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
                        oob_flag = SMP_OOB_PRESENT;
                        memcpy(smp->rr, oob_data->rand256, 16);
                        memcpy(smp->pcnf, oob_data->hash256, 16);
+                       SMP_DBG("OOB Remote Confirmation: %16phN", smp->pcnf);
+                       SMP_DBG("OOB Remote Random: %16phN", smp->rr);
                }
 
        } else {
@@ -878,6 +880,12 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
                return 0;
        }
 
+       /* If this function is used for SC -> legacy fallback we
+        * can only recover the just-works case.
+        */
+       if (test_bit(SMP_FLAG_SC, &smp->flags))
+               return -EINVAL;
+
        /* Not Just Works/Confirm results in MITM Authentication */
        if (smp->method != JUST_CFM) {
                set_bit(SMP_FLAG_MITM_AUTH, &smp->flags);
@@ -1735,6 +1743,13 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
        memcpy(&smp->preq[1], req, sizeof(*req));
        skb_pull(skb, sizeof(*req));
 
+       /* If the remote side's OOB flag is set it means it has
+        * successfully received our local OOB data - therefore set the
+        * flag to indicate that local OOB is in use.
+        */
+       if (req->oob_flag == SMP_OOB_PRESENT)
+               set_bit(SMP_FLAG_LOCAL_OOB, &smp->flags);
+
        /* SMP over BR/EDR requires special treatment */
        if (conn->hcon->type == ACL_LINK) {
                /* We must have a BR/EDR SC link */
@@ -1797,6 +1812,13 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 
        clear_bit(SMP_FLAG_INITIATOR, &smp->flags);
 
+       /* Strictly speaking we shouldn't allow Pairing Confirm for the
+        * SC case, however some implementations incorrectly copy RFU auth
+        * req bits from our security request, which may create a false
+        * positive SC enablement.
+        */
+       SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
+
        if (test_bit(SMP_FLAG_SC, &smp->flags)) {
                SMP_ALLOW_CMD(smp, SMP_CMD_PUBLIC_KEY);
                /* Clear bits which are generated but not distributed */
@@ -1805,8 +1827,6 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
                return 0;
        }
 
-       SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
-
        /* Request setup of TK */
        ret = tk_request(conn, 0, auth, rsp.io_capability, req->io_capability);
        if (ret)
@@ -1832,7 +1852,7 @@ static u8 sc_send_public_key(struct smp_chan *smp)
 
                memcpy(smp->local_pk, smp_dev->local_pk, 64);
                memcpy(smp->local_sk, smp_dev->local_sk, 32);
-               memcpy(smp->lr, smp_dev->local_rr, 16);
+               memcpy(smp->lr, smp_dev->local_rand, 16);
 
                if (smp_dev->debug_key)
                        set_bit(SMP_FLAG_DEBUG_KEY, &smp->flags);
@@ -1899,6 +1919,13 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
        if (hci_dev_test_flag(hdev, HCI_SC_ONLY) && !(auth & SMP_AUTH_SC))
                return SMP_AUTH_REQUIREMENTS;
 
+       /* If the remote side's OOB flag is set it means it has
+        * successfully received our local OOB data - therefore set the
+        * flag to indicate that local OOB is in use.
+        */
+       if (rsp->oob_flag == SMP_OOB_PRESENT)
+               set_bit(SMP_FLAG_LOCAL_OOB, &smp->flags);
+
        smp->prsp[0] = SMP_CMD_PAIRING_RSP;
        memcpy(&smp->prsp[1], rsp, sizeof(*rsp));
 
@@ -1965,10 +1992,6 @@ static u8 sc_check_confirm(struct smp_chan *smp)
 
        BT_DBG("");
 
-       /* Public Key exchange must happen before any other steps */
-       if (!test_bit(SMP_FLAG_REMOTE_PK, &smp->flags))
-               return SMP_UNSPECIFIED;
-
        if (smp->method == REQ_PASSKEY || smp->method == DSP_PASSKEY)
                return sc_passkey_round(smp, SMP_CMD_PAIRING_CONFIRM);
 
@@ -1981,6 +2004,47 @@ static u8 sc_check_confirm(struct smp_chan *smp)
        return 0;
 }
 
+/* Work-around for some implementations that incorrectly copy RFU bits
+ * from our security request and thereby create the impression that
+ * we're doing SC when in fact the remote doesn't support it.
+ */
+static int fixup_sc_false_positive(struct smp_chan *smp)
+{
+       struct l2cap_conn *conn = smp->conn;
+       struct hci_conn *hcon = conn->hcon;
+       struct hci_dev *hdev = hcon->hdev;
+       struct smp_cmd_pairing *req, *rsp;
+       u8 auth;
+
+       /* The issue is only observed when we're in slave role */
+       if (hcon->out)
+               return SMP_UNSPECIFIED;
+
+       if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
+               BT_ERR("Refusing SMP SC -> legacy fallback in SC-only mode");
+               return SMP_UNSPECIFIED;
+       }
+
+       BT_ERR("Trying to fall back to legacy SMP");
+
+       req = (void *) &smp->preq[1];
+       rsp = (void *) &smp->prsp[1];
+
+       /* Rebuild key dist flags which may have been cleared for SC */
+       smp->remote_key_dist = (req->init_key_dist & rsp->resp_key_dist);
+
+       auth = req->auth_req & AUTH_REQ_MASK(hdev);
+
+       if (tk_request(conn, 0, auth, rsp->io_capability, req->io_capability)) {
+               BT_ERR("Failed to fall back to legacy SMP");
+               return SMP_UNSPECIFIED;
+       }
+
+       clear_bit(SMP_FLAG_SC, &smp->flags);
+
+       return 0;
+}
+
 static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct l2cap_chan *chan = conn->smp;
@@ -1994,8 +2058,19 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
        memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf));
        skb_pull(skb, sizeof(smp->pcnf));
 
-       if (test_bit(SMP_FLAG_SC, &smp->flags))
-               return sc_check_confirm(smp);
+       if (test_bit(SMP_FLAG_SC, &smp->flags)) {
+               int ret;
+
+               /* Public Key exchange must happen before any other steps */
+               if (test_bit(SMP_FLAG_REMOTE_PK, &smp->flags))
+                       return sc_check_confirm(smp);
+
+               BT_ERR("Unexpected SMP Pairing Confirm");
+
+               ret = fixup_sc_false_positive(smp);
+               if (ret)
+                       return ret;
+       }
 
        if (conn->hcon->out) {
                smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
@@ -2509,6 +2584,16 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
 
        memcpy(smp->remote_pk, key, 64);
 
+       if (test_bit(SMP_FLAG_REMOTE_OOB, &smp->flags)) {
+               err = smp_f4(smp->tfm_cmac, smp->remote_pk, smp->remote_pk,
+                            smp->rr, 0, cfm.confirm_val);
+               if (err)
+                       return SMP_UNSPECIFIED;
+
+               if (memcmp(cfm.confirm_val, smp->pcnf, 16))
+                       return SMP_CONFIRM_FAILED;
+       }
+
        /* Non-initiating device sends its public key after receiving
         * the key from the initiating device.
         */
@@ -2519,7 +2604,7 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
        }
 
        SMP_DBG("Remote Public Key X: %32phN", smp->remote_pk);
-       SMP_DBG("Remote Public Key Y: %32phN", &smp->remote_pk[32]);
+       SMP_DBG("Remote Public Key Y: %32phN", smp->remote_pk + 32);
 
        if (!ecdh_shared_secret(smp->remote_pk, smp->local_sk, smp->dhkey))
                return SMP_UNSPECIFIED;
@@ -2557,14 +2642,6 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
        }
 
        if (smp->method == REQ_OOB) {
-               err = smp_f4(smp->tfm_cmac, smp->remote_pk, smp->remote_pk,
-                            smp->rr, 0, cfm.confirm_val);
-               if (err)
-                       return SMP_UNSPECIFIED;
-
-               if (memcmp(cfm.confirm_val, smp->pcnf, 16))
-                       return SMP_CONFIRM_FAILED;
-
                if (hcon->out)
                        smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM,
                                     sizeof(smp->prnd), smp->prnd);
@@ -3047,9 +3124,11 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)
 create_chan:
        chan = l2cap_chan_create();
        if (!chan) {
-               crypto_free_blkcipher(smp->tfm_aes);
-               crypto_free_hash(smp->tfm_cmac);
-               kzfree(smp);
+               if (smp) {
+                       crypto_free_blkcipher(smp->tfm_aes);
+                       crypto_free_hash(smp->tfm_cmac);
+                       kzfree(smp);
+               }
                return ERR_PTR(-ENOMEM);
        }