All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/9] Bluetooth: Fix missing PDU length checks for SMP
@ 2014-02-18  8:19 johan.hedberg
  2014-02-18  8:19 ` [PATCH 2/9] Bluetooth: Fix minor whitespace issues in SMP code johan.hedberg
                   ` (7 more replies)
  0 siblings, 8 replies; 11+ messages in thread
From: johan.hedberg @ 2014-02-18  8:19 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@intel.com>

For each received SMP PDU we need to check that we have enough data to
fit the specified size of the PDU. This patch adds the necessary checks
for each SMP PDU handler and ensures that buffer overflows do not occur
if to little data has been received.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/smp.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index efe51ccdc615..1730bb2b6259 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -565,6 +565,9 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	BT_DBG("conn %p", conn);
 
+	if (skb->len < sizeof(*req))
+		return SMP_UNSPECIFIED;
+
 	if (conn->hcon->link_mode & HCI_LM_MASTER)
 		return SMP_CMD_NOTSUPP;
 
@@ -617,6 +620,9 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	BT_DBG("conn %p", conn);
 
+	if (skb->len < sizeof(*rsp))
+		return SMP_UNSPECIFIED;
+
 	if (!(conn->hcon->link_mode & HCI_LM_MASTER))
 		return SMP_CMD_NOTSUPP;
 
@@ -661,6 +667,9 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
 
+	if (skb->len < sizeof(smp->pcnf))
+		return SMP_UNSPECIFIED;
+
 	memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf));
 	skb_pull(skb, sizeof(smp->pcnf));
 
@@ -686,6 +695,9 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	BT_DBG("conn %p", conn);
 
+	if (skb->len < sizeof(smp->rrnd))
+		return SMP_UNSPECIFIED;
+
 	swap128(skb->data, smp->rrnd);
 	skb_pull(skb, sizeof(smp->rrnd));
 
@@ -725,6 +737,9 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	BT_DBG("conn %p", conn);
 
+	if (skb->len < sizeof(*rp))
+		return SMP_UNSPECIFIED;
+
 	if (!(conn->hcon->link_mode & HCI_LM_MASTER))
 		return SMP_CMD_NOTSUPP;
 
@@ -814,6 +829,11 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
 	struct smp_cmd_encrypt_info *rp = (void *) skb->data;
 	struct smp_chan *smp = conn->smp_chan;
 
+	BT_DBG("conn %p", conn);
+
+	if (skb->len < sizeof(*rp))
+		return SMP_UNSPECIFIED;
+
 	skb_pull(skb, sizeof(*rp));
 
 	memcpy(smp->tk, rp->ltk, sizeof(smp->tk));
@@ -829,6 +849,11 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
 	struct hci_conn *hcon = conn->hcon;
 	u8 authenticated;
 
+	BT_DBG("conn %p", conn);
+
+	if (skb->len < sizeof(*rp))
+		return SMP_UNSPECIFIED;
+
 	skb_pull(skb, sizeof(*rp));
 
 	hci_dev_lock(hdev);
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/9] Bluetooth: Fix minor whitespace issues in SMP code
  2014-02-18  8:19 [PATCH 1/9] Bluetooth: Fix missing PDU length checks for SMP johan.hedberg
@ 2014-02-18  8:19 ` johan.hedberg
  2014-02-18  8:19 ` [PATCH 3/9] Bluetooth: Add smp_irk_matches helper function johan.hedberg
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: johan.hedberg @ 2014-02-18  8:19 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@intel.com>

This patch fixes a couple of unnecessary empty lines in the SMP code.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/smp.c | 1 -
 net/bluetooth/smp.h | 1 -
 2 files changed, 2 deletions(-)

diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 1730bb2b6259..ae487e17380e 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -990,7 +990,6 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
 		*keydist &= req->resp_key_dist;
 	}
 
-
 	BT_DBG("keydist 0x%x", *keydist);
 
 	if (*keydist & SMP_DIST_ENC_KEY) {
diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h
index a700bcb490d7..777ee93a6c9b 100644
--- a/net/bluetooth/smp.h
+++ b/net/bluetooth/smp.h
@@ -132,7 +132,6 @@ struct smp_chan {
 	struct crypto_blkcipher	*tfm;
 	struct work_struct confirm;
 	struct work_struct random;
-
 };
 
 /* SMP Commands */
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 3/9] Bluetooth: Add smp_irk_matches helper function
  2014-02-18  8:19 [PATCH 1/9] Bluetooth: Fix missing PDU length checks for SMP johan.hedberg
  2014-02-18  8:19 ` [PATCH 2/9] Bluetooth: Fix minor whitespace issues in SMP code johan.hedberg
@ 2014-02-18  8:19 ` johan.hedberg
  2014-02-18  8:19 ` [PATCH 4/9] Bluetooth: Add AES crypto context for each HCI device johan.hedberg
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: johan.hedberg @ 2014-02-18  8:19 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@intel.com>

This patch adds a helper function to check whether a given IRK matches a
given Resolvable Private Address (RPA). The function will be needed for
implementing the rest of address resolving support.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/smp.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 net/bluetooth/smp.h |  3 +++
 2 files changed, 49 insertions(+)

diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index ae487e17380e..5f500b479f45 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -78,6 +78,52 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
 	return err;
 }
 
+static int smp_ah(struct crypto_blkcipher *tfm, u8 irk[16], u8 r[3], u8 res[3])
+{
+	u8 _res[16], k[16];
+	int err;
+
+	/* r' = padding || r */
+	memset(_res, 0, 13);
+	_res[13] = r[2];
+	_res[14] = r[1];
+	_res[15] = r[0];
+
+	swap128(irk, k);
+	err = smp_e(tfm, k, _res);
+	if (err) {
+		BT_ERR("Encrypt error");
+		return err;
+	}
+
+	/* The output of the random address function ah is:
+	 *	ah(h, r) = e(k, r') mod 2^24
+	 * The output of the security function e is then truncated to 24 bits
+	 * by taking the least significant 24 bits of the output of e as the
+	 * result of ah.
+	 */
+	res[0] = _res[15];
+	res[1] = _res[14];
+	res[2] = _res[13];
+
+	return 0;
+}
+
+bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16],
+		     bdaddr_t *bdaddr)
+{
+	u8 hash[3];
+	int err;
+
+	BT_DBG("RPA %pMR IRK %*phN", bdaddr, 16, irk);
+
+	err = smp_ah(tfm, irk, &bdaddr->b[3], hash);
+	if (err)
+		return false;
+
+	return !memcmp(bdaddr->b, hash, 3);
+}
+
 static int smp_c1(struct crypto_blkcipher *tfm, u8 k[16], u8 r[16],
 		  u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia,
 		  u8 _rat, bdaddr_t *ra, u8 res[16])
diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h
index 777ee93a6c9b..950d039c2ea2 100644
--- a/net/bluetooth/smp.h
+++ b/net/bluetooth/smp.h
@@ -143,4 +143,7 @@ int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey);
 
 void smp_chan_destroy(struct l2cap_conn *conn);
 
+bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16],
+		     bdaddr_t *bdaddr);
+
 #endif /* __SMP_H */
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 4/9] Bluetooth: Add AES crypto context for each HCI device
  2014-02-18  8:19 [PATCH 1/9] Bluetooth: Fix missing PDU length checks for SMP johan.hedberg
  2014-02-18  8:19 ` [PATCH 2/9] Bluetooth: Fix minor whitespace issues in SMP code johan.hedberg
  2014-02-18  8:19 ` [PATCH 3/9] Bluetooth: Add smp_irk_matches helper function johan.hedberg
@ 2014-02-18  8:19 ` johan.hedberg
  2014-02-18  8:40   ` [PATCH v2] " johan.hedberg
  2014-02-18  8:19 ` [PATCH 5/9] Bluetooth: Add basic IRK management support johan.hedberg
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 11+ messages in thread
From: johan.hedberg @ 2014-02-18  8:19 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@intel.com>

Previously the crypto context has only been available for LE SMP
sessions, but now that we'll need to perform operations also during
discovery it makes sense to have this context part of the hci_dev
struct. Later, the context can be removed from the SMP context.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 include/net/bluetooth/hci_core.h |  1 +
 net/bluetooth/hci_core.c         | 15 ++++++++++++++-
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 92fa75fce29d..b344890b18f5 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -259,6 +259,7 @@ struct hci_dev {
 	__u32			req_status;
 	__u32			req_result;
 
+	struct crypto_blkcipher	*tfm_aes;
 
 	struct discovery_state	discovery;
 	struct hci_conn_hash	conn_hash;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index b40d52446f8f..cd1cd7da3235 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -29,6 +29,7 @@
 #include <linux/idr.h>
 #include <linux/rfkill.h>
 #include <linux/debugfs.h>
+#include <linux/crypto.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -3205,9 +3206,16 @@ int hci_register_dev(struct hci_dev *hdev)
 
 	dev_set_name(&hdev->dev, "%s", hdev->name);
 
+	hdev->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0,
+					       CRYPTO_ALG_ASYNC);
+	if (IS_ERR(hdev->tfm_aes)) {
+		BT_ERR("Unable to create crypto context");
+		goto err_wqueue;
+	}
+
 	error = device_add(&hdev->dev);
 	if (error < 0)
-		goto err_wqueue;
+		goto err_tfm;
 
 	hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
 				    RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops,
@@ -3243,6 +3251,8 @@ int hci_register_dev(struct hci_dev *hdev)
 
 	return id;
 
+err_tfm:
+	crypto_free_blkcipher(hdev->tfm_aes);
 err_wqueue:
 	destroy_workqueue(hdev->workqueue);
 	destroy_workqueue(hdev->req_workqueue);
@@ -3293,6 +3303,9 @@ void hci_unregister_dev(struct hci_dev *hdev)
 		rfkill_destroy(hdev->rfkill);
 	}
 
+	if (hdev->tfm_aes)
+		crypto_free_blkcipher(hdev->tfm_aes);
+
 	device_del(&hdev->dev);
 
 	debugfs_remove_recursive(hdev->debugfs);
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 5/9] Bluetooth: Add basic IRK management support
  2014-02-18  8:19 [PATCH 1/9] Bluetooth: Fix missing PDU length checks for SMP johan.hedberg
                   ` (2 preceding siblings ...)
  2014-02-18  8:19 ` [PATCH 4/9] Bluetooth: Add AES crypto context for each HCI device johan.hedberg
@ 2014-02-18  8:19 ` johan.hedberg
  2014-02-18  8:19 ` [PATCH 6/9] Bluetooth: Add hci_bdaddr_is_rpa convenience function johan.hedberg
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: johan.hedberg @ 2014-02-18  8:19 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@intel.com>

This patch adds the initial IRK storage and management functions to the
HCI core. This includes storing a list of IRKs per HCI device and the
ability to add, remove and lookup entries in that list.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 include/net/bluetooth/hci_core.h | 16 +++++++++
 net/bluetooth/hci_core.c         | 70 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 86 insertions(+)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index b344890b18f5..eac422337582 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -103,6 +103,14 @@ struct smp_ltk {
 	u8 val[16];
 };
 
+struct smp_irk {
+	struct list_head list;
+	bdaddr_t rpa;
+	bdaddr_t bdaddr;
+	u8 addr_type;
+	u8 val[16];
+};
+
 struct link_key {
 	struct list_head list;
 	bdaddr_t bdaddr;
@@ -269,6 +277,7 @@ struct hci_dev {
 	struct list_head	uuids;
 	struct list_head	link_keys;
 	struct list_head	long_term_keys;
+	struct list_head	identity_resolving_keys;
 	struct list_head	remote_oob_data;
 	struct list_head	le_conn_params;
 
@@ -787,6 +796,13 @@ int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr);
 int hci_smp_ltks_clear(struct hci_dev *hdev);
 int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
 
+struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa);
+struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
+				     u8 addr_type);
+int hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type,
+		u8 val[16], bdaddr_t *rpa);
+void hci_smp_irks_clear(struct hci_dev *hdev);
+
 int hci_remote_oob_data_clear(struct hci_dev *hdev);
 struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
 					  bdaddr_t *bdaddr);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index cd1cd7da3235..2e1819bed2b4 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -35,6 +35,8 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
+#include "smp.h"
+
 static void hci_rx_work(struct work_struct *work);
 static void hci_cmd_work(struct work_struct *work);
 static void hci_tx_work(struct work_struct *work);
@@ -2544,6 +2546,16 @@ int hci_smp_ltks_clear(struct hci_dev *hdev)
 	return 0;
 }
 
+void hci_smp_irks_clear(struct hci_dev *hdev)
+{
+	struct smp_irk *k, *tmp;
+
+	list_for_each_entry_safe(k, tmp, &hdev->identity_resolving_keys, list) {
+		list_del(&k->list);
+		kfree(k);
+	}
+}
+
 struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
 	struct link_key *k;
@@ -2632,6 +2644,39 @@ struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
 	return NULL;
 }
 
+struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa)
+{
+	struct smp_irk *irk;
+
+	list_for_each_entry(irk, &hdev->identity_resolving_keys, list) {
+		if (!bacmp(&irk->rpa, rpa))
+			return irk;
+	}
+
+	list_for_each_entry(irk, &hdev->identity_resolving_keys, list) {
+		if (smp_irk_matches(hdev->tfm_aes, irk->val, rpa)) {
+			bacpy(&irk->rpa, rpa);
+			return irk;
+		}
+	}
+
+	return NULL;
+}
+
+struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
+				     u8 addr_type)
+{
+	struct smp_irk *irk;
+
+	list_for_each_entry(irk, &hdev->identity_resolving_keys, list) {
+		if (addr_type == irk->addr_type &&
+		    bacmp(bdaddr, &irk->bdaddr) == 0)
+			return irk;
+	}
+
+	return NULL;
+}
+
 int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
 		     bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len)
 {
@@ -2726,6 +2771,29 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type,
 	return 0;
 }
 
+int hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type,
+		u8 val[16], bdaddr_t *rpa)
+{
+	struct smp_irk *irk;
+
+	irk = hci_find_irk_by_addr(hdev, bdaddr, addr_type);
+	if (!irk) {
+		irk = kzalloc(sizeof(*irk), GFP_KERNEL);
+		if (!irk)
+			return -ENOMEM;
+
+		bacpy(&irk->bdaddr, bdaddr);
+		irk->addr_type = addr_type;
+
+		list_add(&irk->list, &hdev->identity_resolving_keys);
+	}
+
+	memcpy(irk->val, val, 16);
+	bacpy(&irk->rpa, rpa);
+
+	return 0;
+}
+
 int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
 	struct link_key *key;
@@ -3120,6 +3188,7 @@ struct hci_dev *hci_alloc_dev(void)
 	INIT_LIST_HEAD(&hdev->uuids);
 	INIT_LIST_HEAD(&hdev->link_keys);
 	INIT_LIST_HEAD(&hdev->long_term_keys);
+	INIT_LIST_HEAD(&hdev->identity_resolving_keys);
 	INIT_LIST_HEAD(&hdev->remote_oob_data);
 	INIT_LIST_HEAD(&hdev->le_conn_params);
 	INIT_LIST_HEAD(&hdev->conn_hash.list);
@@ -3318,6 +3387,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
 	hci_uuids_clear(hdev);
 	hci_link_keys_clear(hdev);
 	hci_smp_ltks_clear(hdev);
+	hci_smp_irks_clear(hdev);
 	hci_remote_oob_data_clear(hdev);
 	hci_conn_params_clear(hdev);
 	hci_dev_unlock(hdev);
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 6/9] Bluetooth: Add hci_bdaddr_is_rpa convenience function
  2014-02-18  8:19 [PATCH 1/9] Bluetooth: Fix missing PDU length checks for SMP johan.hedberg
                   ` (3 preceding siblings ...)
  2014-02-18  8:19 ` [PATCH 5/9] Bluetooth: Add basic IRK management support johan.hedberg
@ 2014-02-18  8:19 ` johan.hedberg
  2014-02-18  8:19 ` [PATCH 7/9] Bluetooth: Implement mgmt_load_irks command johan.hedberg
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: johan.hedberg @ 2014-02-18  8:19 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@intel.com>

When implementing support for Resolvable Private Addresses (RPAs) we'll
need to in several places be able to identify such addresses. This patch
adds a simple convenience function to do the identification of the
address type.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 include/net/bluetooth/hci_core.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index eac422337582..86ea4bab9e77 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1071,6 +1071,17 @@ static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type)
 	return false;
 }
 
+static inline bool hci_bdaddr_is_rpa(bdaddr_t *bdaddr, u8 addr_type)
+{
+	if (addr_type != 0x01)
+		return false;
+
+	if ((bdaddr->b[5] & 0xc0) == 0x40)
+	       return true;
+
+	return false;
+}
+
 int hci_register_cb(struct hci_cb *hcb);
 int hci_unregister_cb(struct hci_cb *hcb);
 
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 7/9] Bluetooth: Implement mgmt_load_irks command
  2014-02-18  8:19 [PATCH 1/9] Bluetooth: Fix missing PDU length checks for SMP johan.hedberg
                   ` (4 preceding siblings ...)
  2014-02-18  8:19 ` [PATCH 6/9] Bluetooth: Add hci_bdaddr_is_rpa convenience function johan.hedberg
@ 2014-02-18  8:19 ` johan.hedberg
  2014-02-18  8:19 ` [PATCH 8/9] Bluetooth: Enable support for remote IRK distribution johan.hedberg
  2014-02-18  8:19 ` [PATCH 9/9] Bluetooth: Fix properly ignoring unexpected SMP PDUs johan.hedberg
  7 siblings, 0 replies; 11+ messages in thread
From: johan.hedberg @ 2014-02-18  8:19 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@intel.com>

This patch implements the Load IRKs command for the management
interface. The command is used to load the kernel with the initial set
of IRKs. It also sets a HCI_RPA_RESOLVING flag to indicate that we can
start requesting devices to distribute their IRK to us.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 include/net/bluetooth/hci.h  |  1 +
 include/net/bluetooth/mgmt.h | 12 +++++++
 net/bluetooth/mgmt.c         | 79 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 92 insertions(+)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 352d3d7d06bb..d3a8fff50f69 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -125,6 +125,7 @@ enum {
 	HCI_SSP_ENABLED,
 	HCI_SC_ENABLED,
 	HCI_SC_ONLY,
+	HCI_RPA_RESOLVING,
 	HCI_HS_ENABLED,
 	HCI_LE_ENABLED,
 	HCI_ADVERTISING,
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 4303fa90b7c1..e4fa13e559e2 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -389,6 +389,18 @@ struct mgmt_cp_set_scan_params {
 
 #define MGMT_OP_SET_DEBUG_KEYS		0x002E
 
+struct mgmt_irk_info {
+	struct mgmt_addr_info addr;
+	__u8 val[16];
+} __packed;
+
+#define MGMT_OP_LOAD_IRKS		0x0030
+struct mgmt_cp_load_irks {
+	__le16 irk_count;
+	struct mgmt_irk_info irks[0];
+} __packed;
+#define MGMT_LOAD_IRKS_SIZE		2
+
 #define MGMT_EV_CMD_COMPLETE		0x0001
 struct mgmt_ev_cmd_complete {
 	__le16	opcode;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 70bef3d5db57..782e2bb10881 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -81,6 +81,7 @@ static const u16 mgmt_commands[] = {
 	MGMT_OP_SET_SCAN_PARAMS,
 	MGMT_OP_SET_SECURE_CONN,
 	MGMT_OP_SET_DEBUG_KEYS,
+	MGMT_OP_LOAD_IRKS,
 };
 
 static const u16 mgmt_events[] = {
@@ -4158,6 +4159,82 @@ unlock:
 	return err;
 }
 
+static bool irk_is_valid(struct mgmt_irk_info *irk)
+{
+	switch (irk->addr.type) {
+	case BDADDR_LE_PUBLIC:
+		return true;
+
+	case BDADDR_LE_RANDOM:
+		/* Two most significant bits shall be set */
+		if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
+			return false;
+		return true;
+	}
+
+	return false;
+}
+
+static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
+		     u16 len)
+{
+	struct mgmt_cp_load_irks *cp = cp_data;
+	u16 irk_count, expected_len;
+	int i, err;
+
+	BT_DBG("request for %s", hdev->name);
+
+	if (!lmp_le_capable(hdev))
+		return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
+				  MGMT_STATUS_NOT_SUPPORTED);
+
+	irk_count = __le16_to_cpu(cp->irk_count);
+
+	expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
+	if (expected_len != len) {
+		BT_ERR("load_irks: expected %u bytes, got %u bytes",
+		       len, expected_len);
+		return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
+				  MGMT_STATUS_INVALID_PARAMS);
+	}
+
+	BT_DBG("%s irk_count %u", hdev->name, irk_count);
+
+	for (i = 0; i < irk_count; i++) {
+		struct mgmt_irk_info *key = &cp->irks[i];
+
+		if (!irk_is_valid(key))
+			return cmd_status(sk, hdev->id,
+					  MGMT_OP_LOAD_IRKS,
+					  MGMT_STATUS_INVALID_PARAMS);
+	}
+
+	hci_dev_lock(hdev);
+
+	hci_smp_irks_clear(hdev);
+
+	for (i = 0; i < irk_count; i++) {
+		struct mgmt_irk_info *irk = &cp->irks[i];
+		u8 addr_type;
+
+		if (irk->addr.type == BDADDR_LE_PUBLIC)
+			addr_type = ADDR_LE_DEV_PUBLIC;
+		else
+			addr_type = ADDR_LE_DEV_RANDOM;
+
+		hci_add_irk(hdev, &irk->addr.bdaddr, addr_type, irk->val,
+			    BDADDR_ANY);
+	}
+
+	set_bit(HCI_RPA_RESOLVING, &hdev->dev_flags);
+
+	err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
+
+	hci_dev_unlock(hdev);
+
+	return err;
+}
+
 static bool ltk_is_valid(struct mgmt_ltk_info *key)
 {
 	if (key->master != 0x00 && key->master != 0x01)
@@ -4296,6 +4373,8 @@ static const struct mgmt_handler {
 	{ set_scan_params,        false, MGMT_SET_SCAN_PARAMS_SIZE },
 	{ set_secure_conn,        false, MGMT_SETTING_SIZE },
 	{ set_debug_keys,         false, MGMT_SETTING_SIZE },
+	{ },
+	{ load_irks,              true,  MGMT_LOAD_IRKS_SIZE },
 };
 
 
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 8/9] Bluetooth: Enable support for remote IRK distribution
  2014-02-18  8:19 [PATCH 1/9] Bluetooth: Fix missing PDU length checks for SMP johan.hedberg
                   ` (5 preceding siblings ...)
  2014-02-18  8:19 ` [PATCH 7/9] Bluetooth: Implement mgmt_load_irks command johan.hedberg
@ 2014-02-18  8:19 ` johan.hedberg
  2014-02-18  8:19 ` [PATCH 9/9] Bluetooth: Fix properly ignoring unexpected SMP PDUs johan.hedberg
  7 siblings, 0 replies; 11+ messages in thread
From: johan.hedberg @ 2014-02-18  8:19 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@intel.com>

This patch does the necessary changes to request the remote device to
distribute its IRK to us during the SMP pairing procedure. This includes
setting the right key distribution values in the pairing
request/response and handling of the two related SMP PDUs, i.e. Identity
Information and Identity Address Information.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/smp.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 net/bluetooth/smp.h |  4 +++
 2 files changed, 77 insertions(+), 7 deletions(-)

diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 5f500b479f45..024baa789eb9 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -249,31 +249,42 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
 			      struct smp_cmd_pairing *req,
 			      struct smp_cmd_pairing *rsp, __u8 authreq)
 {
-	u8 dist_keys = 0;
+	struct smp_chan *smp = conn->smp_chan;
+	struct hci_conn *hcon = conn->hcon;
+	struct hci_dev *hdev = hcon->hdev;
+	u8 local_dist = 0, remote_dist = 0;
 
 	if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->dev_flags)) {
-		dist_keys = SMP_DIST_ENC_KEY;
+		local_dist = SMP_DIST_ENC_KEY;
+		remote_dist = SMP_DIST_ENC_KEY;
 		authreq |= SMP_AUTH_BONDING;
 	} else {
 		authreq &= ~SMP_AUTH_BONDING;
 	}
 
+	if (test_bit(HCI_RPA_RESOLVING, &hdev->dev_flags))
+		remote_dist |= SMP_DIST_ID_KEY;
+
 	if (rsp == NULL) {
 		req->io_capability = conn->hcon->io_capability;
 		req->oob_flag = SMP_OOB_NOT_PRESENT;
 		req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
-		req->init_key_dist = dist_keys;
-		req->resp_key_dist = dist_keys;
+		req->init_key_dist = local_dist;
+		req->resp_key_dist = remote_dist;
 		req->auth_req = (authreq & AUTH_REQ_MASK);
+
+		smp->remote_key_dist = remote_dist;
 		return;
 	}
 
 	rsp->io_capability = conn->hcon->io_capability;
 	rsp->oob_flag = SMP_OOB_NOT_PRESENT;
 	rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
-	rsp->init_key_dist = req->init_key_dist & dist_keys;
-	rsp->resp_key_dist = req->resp_key_dist & dist_keys;
+	rsp->init_key_dist = req->init_key_dist & remote_dist;
+	rsp->resp_key_dist = req->resp_key_dist & local_dist;
 	rsp->auth_req = (authreq & AUTH_REQ_MASK);
+
+	smp->remote_key_dist = rsp->init_key_dist;
 }
 
 static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
@@ -907,12 +918,61 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
 	hci_add_ltk(hdev, &hcon->dst, hcon->dst_type, HCI_SMP_LTK, 1,
 		    authenticated, smp->tk, smp->enc_key_size,
 		    rp->ediv, rp->rand);
-	smp_distribute_keys(conn, 1);
+	if (!(smp->remote_key_dist & SMP_DIST_ID_KEY))
+		smp_distribute_keys(conn, 1);
 	hci_dev_unlock(hdev);
 
 	return 0;
 }
 
+static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+	struct smp_cmd_ident_info *info = (void *) skb->data;
+	struct smp_chan *smp = conn->smp_chan;
+
+	BT_DBG("");
+
+	if (skb->len < sizeof(*info))
+		return SMP_UNSPECIFIED;
+
+	skb_pull(skb, sizeof(*info));
+
+	memcpy(smp->irk, info->irk, 16);
+
+	return 0;
+}
+
+static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
+				   struct sk_buff *skb)
+{
+	struct smp_cmd_ident_addr_info *info = (void *) skb->data;
+	struct smp_chan *smp = conn->smp_chan;
+	struct hci_conn *hcon = conn->hcon;
+	bdaddr_t rpa;
+
+	BT_DBG("");
+
+	if (skb->len < sizeof(*info))
+		return SMP_UNSPECIFIED;
+
+	skb_pull(skb, sizeof(*info));
+
+	bacpy(&smp->id_addr, &info->bdaddr);
+	smp->id_addr_type = info->addr_type;
+
+	if (hci_bdaddr_is_rpa(&hcon->dst, hcon->dst_type))
+		bacpy(&rpa, &hcon->dst);
+	else
+		bacpy(&rpa, BDADDR_ANY);
+
+	hci_add_irk(conn->hcon->hdev, &smp->id_addr, smp->id_addr_type,
+		    smp->irk, &rpa);
+
+	smp_distribute_keys(conn, 1);
+
+	return 0;
+}
+
 int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
 {
 	struct hci_conn *hcon = conn->hcon;
@@ -987,7 +1047,13 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
 		break;
 
 	case SMP_CMD_IDENT_INFO:
+		reason = smp_cmd_ident_info(conn, skb);
+		break;
+
 	case SMP_CMD_IDENT_ADDR_INFO:
+		reason = smp_cmd_ident_addr_info(conn, skb);
+		break;
+
 	case SMP_CMD_SIGN_INFO:
 		/* Just ignored */
 		reason = 0;
diff --git a/net/bluetooth/smp.h b/net/bluetooth/smp.h
index 950d039c2ea2..4f373bc56ad7 100644
--- a/net/bluetooth/smp.h
+++ b/net/bluetooth/smp.h
@@ -128,6 +128,10 @@ struct smp_chan {
 	u8		pcnf[16]; /* SMP Pairing Confirm */
 	u8		tk[16]; /* SMP Temporary Key */
 	u8		enc_key_size;
+	u8		remote_key_dist;
+	bdaddr_t	id_addr;
+	u8		id_addr_type;
+	u8		irk[16];
 	unsigned long	smp_flags;
 	struct crypto_blkcipher	*tfm;
 	struct work_struct confirm;
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 9/9] Bluetooth: Fix properly ignoring unexpected SMP PDUs
  2014-02-18  8:19 [PATCH 1/9] Bluetooth: Fix missing PDU length checks for SMP johan.hedberg
                   ` (6 preceding siblings ...)
  2014-02-18  8:19 ` [PATCH 8/9] Bluetooth: Enable support for remote IRK distribution johan.hedberg
@ 2014-02-18  8:19 ` johan.hedberg
  7 siblings, 0 replies; 11+ messages in thread
From: johan.hedberg @ 2014-02-18  8:19 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@intel.com>

If we didn't request certain pieces of information during the key
distribution negotiation we should properly ignore those PDUs if the
peer incorrectly sends them. This includes the Encryption Information
and Master Identification PDUs if the EncKey bit was not set, and the
Identity Information and Identity Address Information PDUs if the IdKey
bit was not set.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/smp.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 024baa789eb9..5867c1c3f436 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -891,6 +891,10 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
 	if (skb->len < sizeof(*rp))
 		return SMP_UNSPECIFIED;
 
+	/* Ignore this PDU if it wasn't requested */
+	if (!(smp->remote_key_dist & SMP_DIST_ENC_KEY))
+		return 0;
+
 	skb_pull(skb, sizeof(*rp));
 
 	memcpy(smp->tk, rp->ltk, sizeof(smp->tk));
@@ -911,6 +915,10 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
 	if (skb->len < sizeof(*rp))
 		return SMP_UNSPECIFIED;
 
+	/* Ignore this PDU if it wasn't requested */
+	if (!(smp->remote_key_dist & SMP_DIST_ENC_KEY))
+		return 0;
+
 	skb_pull(skb, sizeof(*rp));
 
 	hci_dev_lock(hdev);
@@ -935,6 +943,10 @@ static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb)
 	if (skb->len < sizeof(*info))
 		return SMP_UNSPECIFIED;
 
+	/* Ignore this PDU if it wasn't requested */
+	if (!(smp->remote_key_dist & SMP_DIST_ID_KEY))
+		return 0;
+
 	skb_pull(skb, sizeof(*info));
 
 	memcpy(smp->irk, info->irk, 16);
@@ -955,6 +967,10 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
 	if (skb->len < sizeof(*info))
 		return SMP_UNSPECIFIED;
 
+	/* Ignore this PDU if it wasn't requested */
+	if (!(smp->remote_key_dist & SMP_DIST_ID_KEY))
+		return 0;
+
 	skb_pull(skb, sizeof(*info));
 
 	bacpy(&smp->id_addr, &info->bdaddr);
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2] Bluetooth: Add AES crypto context for each HCI device
  2014-02-18  8:19 ` [PATCH 4/9] Bluetooth: Add AES crypto context for each HCI device johan.hedberg
@ 2014-02-18  8:40   ` johan.hedberg
  2014-02-18  8:54     ` Marcel Holtmann
  0 siblings, 1 reply; 11+ messages in thread
From: johan.hedberg @ 2014-02-18  8:40 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@intel.com>

Previously the crypto context has only been available for LE SMP
sessions, but now that we'll need to perform operations also during
discovery it makes sense to have this context part of the hci_dev
struct. Later, the context can be removed from the SMP context.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
v2: Properly initialize "error" if crypto init fails

 include/net/bluetooth/hci_core.h |  1 +
 net/bluetooth/hci_core.c         | 17 ++++++++++++++++-
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 92fa75fce29d..b344890b18f5 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -259,6 +259,7 @@ struct hci_dev {
 	__u32			req_status;
 	__u32			req_result;
 
+	struct crypto_blkcipher	*tfm_aes;
 
 	struct discovery_state	discovery;
 	struct hci_conn_hash	conn_hash;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index b40d52446f8f..df25af5502ef 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -29,6 +29,7 @@
 #include <linux/idr.h>
 #include <linux/rfkill.h>
 #include <linux/debugfs.h>
+#include <linux/crypto.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -3205,9 +3206,18 @@ int hci_register_dev(struct hci_dev *hdev)
 
 	dev_set_name(&hdev->dev, "%s", hdev->name);
 
+	hdev->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0,
+					       CRYPTO_ALG_ASYNC);
+	if (IS_ERR(hdev->tfm_aes)) {
+		BT_ERR("Unable to create crypto context");
+		error = PTR_ERR(hdev->tfm_aes);
+		hdev->tfm_aes = NULL;
+		goto err_wqueue;
+	}
+
 	error = device_add(&hdev->dev);
 	if (error < 0)
-		goto err_wqueue;
+		goto err_tfm;
 
 	hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
 				    RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops,
@@ -3243,6 +3253,8 @@ int hci_register_dev(struct hci_dev *hdev)
 
 	return id;
 
+err_tfm:
+	crypto_free_blkcipher(hdev->tfm_aes);
 err_wqueue:
 	destroy_workqueue(hdev->workqueue);
 	destroy_workqueue(hdev->req_workqueue);
@@ -3293,6 +3305,9 @@ void hci_unregister_dev(struct hci_dev *hdev)
 		rfkill_destroy(hdev->rfkill);
 	}
 
+	if (hdev->tfm_aes)
+		crypto_free_blkcipher(hdev->tfm_aes);
+
 	device_del(&hdev->dev);
 
 	debugfs_remove_recursive(hdev->debugfs);
-- 
1.8.5.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] Bluetooth: Add AES crypto context for each HCI device
  2014-02-18  8:40   ` [PATCH v2] " johan.hedberg
@ 2014-02-18  8:54     ` Marcel Holtmann
  0 siblings, 0 replies; 11+ messages in thread
From: Marcel Holtmann @ 2014-02-18  8:54 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: bluez mailin list (linux-bluetooth@vger.kernel.org)

Hi Johan,

> Previously the crypto context has only been available for LE SMP
> sessions, but now that we'll need to perform operations also during
> discovery it makes sense to have this context part of the hci_dev
> struct. Later, the context can be removed from the SMP context.
> 
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
> v2: Properly initialize "error" if crypto init fails
> 
> include/net/bluetooth/hci_core.h |  1 +
> net/bluetooth/hci_core.c         | 17 ++++++++++++++++-
> 2 files changed, 17 insertions(+), 1 deletion(-)

all 9 patches have been applied to bluetooth-next tree.

Regards

Marcel


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2014-02-18  8:54 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-18  8:19 [PATCH 1/9] Bluetooth: Fix missing PDU length checks for SMP johan.hedberg
2014-02-18  8:19 ` [PATCH 2/9] Bluetooth: Fix minor whitespace issues in SMP code johan.hedberg
2014-02-18  8:19 ` [PATCH 3/9] Bluetooth: Add smp_irk_matches helper function johan.hedberg
2014-02-18  8:19 ` [PATCH 4/9] Bluetooth: Add AES crypto context for each HCI device johan.hedberg
2014-02-18  8:40   ` [PATCH v2] " johan.hedberg
2014-02-18  8:54     ` Marcel Holtmann
2014-02-18  8:19 ` [PATCH 5/9] Bluetooth: Add basic IRK management support johan.hedberg
2014-02-18  8:19 ` [PATCH 6/9] Bluetooth: Add hci_bdaddr_is_rpa convenience function johan.hedberg
2014-02-18  8:19 ` [PATCH 7/9] Bluetooth: Implement mgmt_load_irks command johan.hedberg
2014-02-18  8:19 ` [PATCH 8/9] Bluetooth: Enable support for remote IRK distribution johan.hedberg
2014-02-18  8:19 ` [PATCH 9/9] Bluetooth: Fix properly ignoring unexpected SMP PDUs johan.hedberg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.