Skip to contentSkip to conversation

Bluetooth: LE Secure Connections support

PATCH In review Johan Hedberg 2 participants 51 messages Dec 3, 2014

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover Bluetooth: LE Secure Connections support

Hi,

First of all, appologies to all for this huge patch set. It's work from the past 6 months or so that wasn't releasable until the 4.2 specification goes public. That happened just some moments ago:

http://www.bluetooth.com/SiteCollectionDocuments/4-2/bluetooth4-2.aspx

I'm sending the patches to the mailing list mainly for reference since Marcel will probably directly merge them from my tree. Any issues/fixes etc should be done on top of them.

Johan

----------------------------------------------------------------
Johan Hedberg (49):
Bluetooth: Add basic SMP defines for LE Secure Connections
Bluetooth: Make auth_req mask dependent on SC enabled or not
Bluetooth: Add SMP flag for SC and set it when necessary.
Bluetooth: Update SMP security level to/from auth_req for SC
Bluetooth: Add mgmt support for LE Secure Connections LTK types
Bluetooth: Set the correct security level for SC LTKs
Bluetooth: Use custom macro for testing BR/EDR SC enabled
Bluetooth: Add mgmt_set_secure_conn support for any LE adapter
Bluetooth: Update LTK lookup to correctly deal with SC LTKs
Bluetooth: Remove unused hci_find_ltk function
Bluetooth: Rename hci_find_ltk_by_addr to hci_find_ltk
Bluetooth: Set link key generation bit if necessary for LE SC
Bluetooth: Add basic support for AES-CMAC
Bluetooth: Add ECC library for LE Secure Connections
Bluetooth: Add basic support for sending our LE SC public key
Bluetooth: Add handler function for receiving LE SC public key
Bluetooth: Add support for sending LE SC Confirm value
Bluetooth: Add LE SC support for responding to Pairing Confirm PDU
Bluetooth: Add support for LE SC numeric comparison
Bluetooth: Add support for handling LE SC user response
Bluetooth: Add support for LE SC DHKey check PDU
Bluetooth: Add support for LE SC key generation
Bluetooth: Track authentication method in SMP context
Bluetooth: Add selection of the SC authentication method
Bluetooth: Detect SMP SC debug keys
Bluetooth: Add check for accidentally generating a debug key
Bluetooth: Set correct LTK type and authentication for SC
Bluetooth: Add support for SC just-works pairing
Bluetooth: Fix BR/EDR Link Key type when derived through LE SC
Bluetooth: Add passkey entry support for LE SC
Bluetooth: Fix DHKey Check sending order for slave role
Bluetooth: Add dummy handler for LE SC keypress notification
Bluetooth: Use debug keys for SMP when HCI_USE_DEBUG_KEYS is set
Bluetooth: Add hci_conn flag for new link key generation
Bluetooth: Add debugfs switch for forcing SMP over BR/EDR
Bluetooth: Add skeleton for BR/EDR SMP channel
Bluetooth: Add full SMP BR/EDR support
Bluetooth: Add SC-only mode support for SMP
Bluetooth: Unify remote OOB data functions
Bluetooth: Store address type with OOB data
Bluetooth: Add support for adding remote OOB data for LE
Bluetooth: Set SMP OOB flag if OOB data is available
Bluetooth: Add basic LE SC OOB support for remote OOB data
Bluetooth: Introduce SMP_DBG macro for low-level debuging
Bluetooth: Fix missing const declarations in SMP functions
Bluetooth: Organize SMP crypto functions to logical sections
Bluetooth: Fix SMP debug key handling
Bluetooth: Fix minor coding style issue in smp.c
Bluetooth: Fix false-positive "uninitialized" compiler warning

 include/net/bluetooth/hci.h      |    1 +
 include/net/bluetooth/hci_core.h |   23 +-
 include/net/bluetooth/l2cap.h    |    2 +
 include/net/bluetooth/mgmt.h     |    3 +
 net/bluetooth/Kconfig            |    1 +
 net/bluetooth/Makefile           |    2 +-
 net/bluetooth/ecc.c              |  816 ++++++++++++++++++++
 net/bluetooth/ecc.h              |   54 ++
 net/bluetooth/hci_core.c         |  155 ++--
 net/bluetooth/hci_event.c        |   23 +-
 net/bluetooth/l2cap_core.c       |    4 +
 net/bluetooth/mgmt.c             |   75 +-
 net/bluetooth/smp.c              | 1543 +++++++++++++++++++++++++++++++++----
 net/bluetooth/smp.h              |   51 +-
 14 files changed, 2509 insertions(+), 244 deletions(-)
#1 lore raw

PATCH 1/49 Bluetooth: Add basic SMP defines for LE Secure Connections

From: Johan Hedberg <[email protected]>

This patch adds basic SMP defines for commands, error codes and PDU definitions for the LE Secure Connections feature.

---
 net/bluetooth/smp.h | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)
net/bluetooth/smp.h +24 -1
index f76083b85005..7c3c351909f5 100644
@@ -50,10 +50,13 @@ struct smp_cmd_pairing {
 #define SMP_DIST_ENC_KEY	0x01
 #define SMP_DIST_ID_KEY		0x02
 #define SMP_DIST_SIGN		0x04
+#define SMP_DIST_LINK_KEY	0x08
 
 #define SMP_AUTH_NONE		0x00
 #define SMP_AUTH_BONDING	0x01
 #define SMP_AUTH_MITM		0x04
+#define SMP_AUTH_SC		0x08
+#define SMP_AUTH_KEYPRESS	0x10
 
 #define SMP_CMD_PAIRING_CONFIRM	0x03
 struct smp_cmd_pairing_confirm {
@@ -102,7 +105,23 @@ struct smp_cmd_security_req {
 	__u8	auth_req;
 } __packed;
 
-#define SMP_CMD_MAX		0x0b
+#define SMP_CMD_PUBLIC_KEY	0x0c
+struct smp_cmd_public_key {
+	__u8	x[32];
+	__u8	y[32];
+} __packed;
+
+#define SMP_CMD_DHKEY_CHECK	0x0d
+struct smp_cmd_dhkey_check {
+	__u8	e[16];
+} __packed;
+
+#define SMP_CMD_KEYPRESS_NOTIFY	0x0e
+struct smp_cmd_keypress_notify {
+	__u8	value;
+} __packed;
+
+#define SMP_CMD_MAX		0x0e
 
 #define SMP_PASSKEY_ENTRY_FAILED	0x01
 #define SMP_OOB_NOT_AVAIL		0x02
@@ -114,6 +133,10 @@ struct smp_cmd_security_req {
 #define SMP_UNSPECIFIED			0x08
 #define SMP_REPEATED_ATTEMPTS		0x09
 #define SMP_INVALID_PARAMS		0x0a
+#define SMP_DHKEY_CHECK_FAILED		0x0b
+#define SMP_NUMERIC_COMP_FAILED		0x0c
+#define SMP_BREDR_PAIRING_IN_PROGRESS	0x0d
+#define SMP_CROSS_TRANSP_NOT_ALLOWED	0x0e
 
 #define SMP_MIN_ENC_KEY_SIZE		7
 #define SMP_MAX_ENC_KEY_SIZE		16
Signature · 1 line
2.1.0
#2 lore raw

PATCH 2/49 Bluetooth: Make auth_req mask dependent on SC enabled or not

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

If we haven't enabled SC support on our side we should use the same mask for the authentication requirement as we were using before SC support was added, otherwise we should use the extended mask for SC.

---
 net/bluetooth/smp.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)
net/bluetooth/smp.c +10 -7
index 069b76e03b57..bfa839eed89b 100644
@@ -35,8 +35,9 @@
 
 #define SMP_TIMEOUT	msecs_to_jiffies(30000)
 
-#define AUTH_REQ_MASK   0x07
-#define KEY_DIST_MASK	0x07
+#define AUTH_REQ_MASK(dev)	(test_bit(HCI_SC_ENABLED, &(dev)->dev_flags) ? \
+				 0x1f : 0x07)
+#define KEY_DIST_MASK		0x07
 
 enum {
 	SMP_FLAG_TK_VALID,
@@ -332,7 +333,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
 		req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
 		req->init_key_dist = local_dist;
 		req->resp_key_dist = remote_dist;
-		req->auth_req = (authreq & AUTH_REQ_MASK);
+		req->auth_req = (authreq & AUTH_REQ_MASK(hdev));
 
 		smp->remote_key_dist = remote_dist;
 		return;
@@ -343,7 +344,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
 	rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
 	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);
+	rsp->auth_req = (authreq & AUTH_REQ_MASK(hdev));
 
 	smp->remote_key_dist = rsp->init_key_dist;
 }
@@ -942,7 +943,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 		return SMP_UNSPECIFIED;
 
 	/* We didn't start the pairing, so match remote */
-	auth = req->auth_req & AUTH_REQ_MASK;
+	auth = req->auth_req & AUTH_REQ_MASK(hdev);
 
 	if (!test_bit(HCI_BONDABLE, &hdev->dev_flags) &&
 	    (auth & SMP_AUTH_BONDING))
@@ -997,6 +998,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 	struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
 	struct l2cap_chan *chan = conn->smp;
 	struct smp_chan *smp = chan->data;
+	struct hci_dev *hdev = conn->hcon->hdev;
 	u8 key_size, auth;
 	int ret;
 
@@ -1016,7 +1018,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 	if (check_enc_key_size(conn, key_size))
 		return SMP_ENC_KEY_SIZE;
 
-	auth = rsp->auth_req & AUTH_REQ_MASK;
+	auth = rsp->auth_req & AUTH_REQ_MASK(hdev);
 
 	/* If we need MITM check that it can be achieved */
 	if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) {
@@ -1151,6 +1153,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
 	struct smp_cmd_security_req *rp = (void *) skb->data;
 	struct smp_cmd_pairing cp;
 	struct hci_conn *hcon = conn->hcon;
+	struct hci_dev *hdev = hcon->hdev;
 	struct smp_chan *smp;
 	u8 sec_level, auth;
 
@@ -1162,7 +1165,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
 	if (hcon->role != HCI_ROLE_MASTER)
 		return SMP_CMD_NOTSUPP;
 
-	auth = rp->auth_req & AUTH_REQ_MASK;
+	auth = rp->auth_req & AUTH_REQ_MASK(hdev);
 
 	if (hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT)
 		sec_level = BT_SECURITY_MEDIUM;
Signature · 1 line
2.1.0
#3 lore raw

PATCH 3/49 Bluetooth: Add SMP flag for SC and set it when necessary.

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

This patch adds a new SMP flag for tracking whether Secure Connections is in use and sets the flag when both remote and local side have elected to use Secure Connections.

---
 net/bluetooth/smp.c | 7 +++++++
 1 file changed, 7 insertions(+)
net/bluetooth/smp.c +7 -0
index bfa839eed89b..3808ade96d08 100644
@@ -45,6 +45,7 @@ enum {
 	SMP_FLAG_MITM_AUTH,
 	SMP_FLAG_COMPLETE,
 	SMP_FLAG_INITIATOR,
+	SMP_FLAG_SC,
 };
 
 struct smp_chan {
@@ -973,6 +974,9 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	build_pairing_cmd(conn, req, &rsp, auth);
 
+	if (rsp.auth_req & SMP_AUTH_SC)
+		set_bit(SMP_FLAG_SC, &smp->flags);
+
 	key_size = min(req->max_key_size, rsp.max_key_size);
 	if (check_enc_key_size(conn, key_size))
 		return SMP_ENC_KEY_SIZE;
@@ -1020,6 +1024,9 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	auth = rsp->auth_req & AUTH_REQ_MASK(hdev);
 
+	if ((req->auth_req & SMP_AUTH_SC) && (auth & SMP_AUTH_SC))
+		set_bit(SMP_FLAG_SC, &smp->flags);
+
 	/* If we need MITM check that it can be achieved */
 	if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) {
 		u8 method;
Signature · 1 line
2.1.0
#4 lore raw

PATCH 4/49 Bluetooth: Update SMP security level to/from auth_req for SC

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

This patch updates the functions which map the SMP authentication request to a security level and vice-versa to take into account the Secure Connections feature.

---
 net/bluetooth/smp.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)
net/bluetooth/smp.c +14 -4
index 3808ade96d08..4ecbf2774fbd 100644
@@ -284,17 +284,22 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
 	schedule_delayed_work(&smp->security_timer, SMP_TIMEOUT);
 }
 
-static __u8 authreq_to_seclevel(__u8 authreq)
+static u8 authreq_to_seclevel(u8 authreq)
 {
-	if (authreq & SMP_AUTH_MITM)
-		return BT_SECURITY_HIGH;
-	else
+	if (authreq & SMP_AUTH_MITM) {
+		if (authreq & SMP_AUTH_SC)
+			return BT_SECURITY_FIPS;
+		else
+			return BT_SECURITY_HIGH;
+	} else {
 		return BT_SECURITY_MEDIUM;
+	}
 }
 
 static __u8 seclevel_to_authreq(__u8 sec_level)
 {
 	switch (sec_level) {
+	case BT_SECURITY_FIPS:
 	case BT_SECURITY_HIGH:
 		return SMP_AUTH_MITM | SMP_AUTH_BONDING;
 	case BT_SECURITY_MEDIUM:
@@ -1026,6 +1031,8 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	if ((req->auth_req & SMP_AUTH_SC) && (auth & SMP_AUTH_SC))
 		set_bit(SMP_FLAG_SC, &smp->flags);
+	else if (conn->hcon->pending_sec_level > BT_SECURITY_HIGH)
+		conn->hcon->pending_sec_level = BT_SECURITY_HIGH;
 
 	/* If we need MITM check that it can be achieved */
 	if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) {
@@ -1255,6 +1262,9 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
 
 	authreq = seclevel_to_authreq(sec_level);
 
+	if (test_bit(HCI_SC_ENABLED, &hcon->hdev->dev_flags))
+		authreq |= SMP_AUTH_SC;
+
 	/* Require MITM if IO Capability allows or the security level
 	 * requires it.
 	 */
Signature · 1 line
2.1.0
#5 lore raw

PATCH 5/49 Bluetooth: Add mgmt support for LE Secure Connections LTK types

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

We need a dedicated LTK type for LTK resulting from a Secure Connections based SMP pairing. This patch adds a new define for it and ensures that both the New LTK event as well as the Load LTKs command supports it.

---
 include/net/bluetooth/mgmt.h |  3 +++
 net/bluetooth/mgmt.c         | 33 ++++++++++++++++++++++++++-------
 net/bluetooth/smp.h          | 13 +++++++++++++
 3 files changed, 42 insertions(+), 7 deletions(-)
include/net/bluetooth/mgmt.h +3 -0
index b391fd663468..9b382ea34fd9 100644
@@ -184,6 +184,9 @@ struct mgmt_cp_load_link_keys {
 
 #define MGMT_LTK_UNAUTHENTICATED	0x00
 #define MGMT_LTK_AUTHENTICATED		0x01
+#define MGMT_LTK_P256_UNAUTH		0x02
+#define MGMT_LTK_P256_AUTH		0x03
+#define MGMT_LTK_P256_DEBUG		0x04
 
 struct mgmt_ltk_info {
 	struct mgmt_addr_info addr;
net/bluetooth/mgmt.c +26 -7
index cbeef5f62f3b..7974a39a42d9 100644
@@ -4910,18 +4910,26 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
 		else
 			addr_type = ADDR_LE_DEV_RANDOM;
 
-		if (key->master)
-			type = SMP_LTK;
-		else
-			type = SMP_LTK_SLAVE;
-
 		switch (key->type) {
 		case MGMT_LTK_UNAUTHENTICATED:
 			authenticated = 0x00;
+			type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
 			break;
 		case MGMT_LTK_AUTHENTICATED:
 			authenticated = 0x01;
+			type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
+			break;
+		case MGMT_LTK_P256_UNAUTH:
+			authenticated = 0x00;
+			type = SMP_LTK_P256;
+			break;
+		case MGMT_LTK_P256_AUTH:
+			authenticated = 0x01;
+			type = SMP_LTK_P256;
 			break;
+		case MGMT_LTK_P256_DEBUG:
+			authenticated = 0x00;
+			type = SMP_LTK_P256_DEBUG;
 		default:
 			continue;
 		}
@@ -6101,8 +6109,19 @@ void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
 
 static u8 mgmt_ltk_type(struct smp_ltk *ltk)
 {
-	if (ltk->authenticated)
-		return MGMT_LTK_AUTHENTICATED;
+	switch (ltk->type) {
+	case SMP_LTK:
+	case SMP_LTK_SLAVE:
+		if (ltk->authenticated)
+			return MGMT_LTK_AUTHENTICATED;
+		return MGMT_LTK_UNAUTHENTICATED;
+	case SMP_LTK_P256:
+		if (ltk->authenticated)
+			return MGMT_LTK_P256_AUTH;
+		return MGMT_LTK_P256_UNAUTH;
+	case SMP_LTK_P256_DEBUG:
+		return MGMT_LTK_P256_DEBUG;
+	}
 
 	return MGMT_LTK_UNAUTHENTICATED;
 }
net/bluetooth/smp.h +13 -0
index 7c3c351909f5..81d24c0ea08b 100644
@@ -146,8 +146,21 @@ enum {
 	SMP_STK,
 	SMP_LTK,
 	SMP_LTK_SLAVE,
+	SMP_LTK_P256,
+	SMP_LTK_P256_DEBUG,
 };
 
+static inline bool smp_ltk_is_sc(struct smp_ltk *key)
+{
+	switch (key->type) {
+	case SMP_LTK_P256:
+	case SMP_LTK_P256_DEBUG:
+		return true;
+	}
+
+	return false;
+}
+
 static inline u8 smp_ltk_sec_level(struct smp_ltk *key)
 {
 	if (key->authenticated)
Signature · 1 line
2.1.0
#6 lore raw

PATCH 6/49 Bluetooth: Set the correct security level for SC LTKs

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

When the looked-up LTK is one generated by Secure Connections pairing the security level it gives is BT_SECURITY_FIPS. This patch updates the LTK request event handler to correctly set this level.

---
 net/bluetooth/smp.h | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
net/bluetooth/smp.h +6 -2
index 81d24c0ea08b..f955d6b7ceb2 100644
@@ -163,8 +163,12 @@ static inline bool smp_ltk_is_sc(struct smp_ltk *key)
 
 static inline u8 smp_ltk_sec_level(struct smp_ltk *key)
 {
-	if (key->authenticated)
-		return BT_SECURITY_HIGH;
+	if (key->authenticated) {
+		if (smp_ltk_is_sc(key))
+			return BT_SECURITY_FIPS;
+		else
+			return BT_SECURITY_HIGH;
+	}
 
 	return BT_SECURITY_MEDIUM;
 }
Signature · 1 line
2.1.0
#7 lore raw

PATCH 7/49 Bluetooth: Use custom macro for testing BR/EDR SC enabled

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

Since the HCI_SC_ENABLED flag will also be used for controllers without BR/EDR Secure Connections support whenever we need to check specifically for SC for BR/EDR we also need to check that the controller actually supports it. This patch adds a convenience macro for check all the necessary conditions and converts the places in the code that need it to use it.

---
 include/net/bluetooth/hci_core.h | 3 +++
 net/bluetooth/hci_core.c         | 4 +---
 net/bluetooth/hci_event.c        | 2 +-
 net/bluetooth/mgmt.c             | 5 ++---
 4 files changed, 7 insertions(+), 7 deletions(-)
include/net/bluetooth/hci_core.h +3 -0
index 396c09840fdf..7f08ea36d246 100644
@@ -999,6 +999,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
 
 #define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
 				!test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
+#define bredr_sc_enabled(dev) ((lmp_sc_capable(dev) || \
+				test_bit(HCI_FORCE_SC, &(dev)->dbg_flags)) && \
+			       test_bit(HCI_SC_ENABLED, &(dev)->dev_flags))
 
 /* ----- HCI protocols ----- */
 #define HCI_PROTO_DEFER             0x01
net/bluetooth/hci_core.c +1 -3
index 5c319a49a5a4..2586e405adb3 100644
@@ -1734,9 +1734,7 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt)
 		hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL);
 
 	/* Enable Secure Connections if supported and configured */
-	if ((lmp_sc_capable(hdev) ||
-	     test_bit(HCI_FORCE_SC, &hdev->dbg_flags)) &&
-	    test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) {
+	if (bredr_sc_enabled(hdev)) {
 		u8 support = 0x01;
 		hci_req_add(req, HCI_OP_WRITE_SC_SUPPORT,
 			    sizeof(support), &support);
net/bluetooth/hci_event.c +1 -1
index d76d4f821189..f980fc46ea5e 100644
@@ -4027,7 +4027,7 @@ static void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
 
 	data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
 	if (data) {
-		if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) {
+		if (bredr_sc_enabled(hdev)) {
 			struct hci_cp_remote_oob_ext_data_reply cp;
 
 			bacpy(&cp.bdaddr, &ev->bdaddr);
net/bluetooth/mgmt.c +2 -3
index 7974a39a42d9..868769543d83 100644
@@ -3562,7 +3562,7 @@ static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
 		goto unlock;
 	}
 
-	if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
+	if (bredr_sc_enabled(hdev))
 		err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
 				   0, NULL);
 	else
@@ -6803,8 +6803,7 @@ void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
 		cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
 			   mgmt_status(status));
 	} else {
-		if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
-		    hash256 && rand256) {
+		if (bredr_sc_enabled(hdev) && hash256 && rand256) {
 			struct mgmt_rp_read_local_oob_ext_data rp;
 
 			memcpy(rp.hash192, hash192, sizeof(rp.hash192));
Signature · 1 line
2.1.0
#8 lore raw

PATCH 8/49 Bluetooth: Add mgmt_set_secure_conn support for any LE adapter

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

Since LE Secure Connections is a purely host-side feature we should offer the Secure Connections mgmt setting for any adapter with LE support. This patch updates the supported settings value and the set_secure_conn command handler accordingly.

---
 net/bluetooth/mgmt.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)
net/bluetooth/mgmt.c +8 -9
index 868769543d83..6e8165364b7f 100644
@@ -574,6 +574,7 @@ static u32 get_supported_settings(struct hci_dev *hdev)
 	if (lmp_le_capable(hdev)) {
 		settings |= MGMT_SETTING_LE;
 		settings |= MGMT_SETTING_ADVERTISING;
+		settings |= MGMT_SETTING_SECURE_CONN;
 		settings |= MGMT_SETTING_PRIVACY;
 	}
 
@@ -4572,18 +4573,13 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
 {
 	struct mgmt_mode *cp = data;
 	struct pending_cmd *cmd;
-	u8 val, status;
+	u8 val;
 	int err;
 
 	BT_DBG("request for %s", hdev->name);
 
-	status = mgmt_bredr_support(hdev);
-	if (status)
-		return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
-				  status);
-
-	if (!lmp_sc_capable(hdev) &&
-	    !test_bit(HCI_FORCE_SC, &hdev->dbg_flags))
+	if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
+	    !lmp_sc_capable(hdev) && !test_bit(HCI_FORCE_SC, &hdev->dbg_flags))
 		return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
 				  MGMT_STATUS_NOT_SUPPORTED);
 
@@ -4593,7 +4589,10 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
 
 	hci_dev_lock(hdev);
 
-	if (!hdev_is_powered(hdev)) {
+	if (!hdev_is_powered(hdev) ||
+	    (!lmp_sc_capable(hdev) &&
+	     !test_bit(HCI_FORCE_SC, &hdev->dbg_flags)) ||
+	    !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
 		bool changed;
 
 		if (cp->val) {
Signature · 1 line
2.1.0
#9 lore raw

PATCH 9/49 Bluetooth: Update LTK lookup to correctly deal with SC LTKs

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

LTKs derived from Secure Connections based pairing are symmetric, i.e. they should match both master and slave role. This patch updates the LTK lookup functions to ignore the desired role when dealing with SC LTKs.

Furthermore, with Secure Connections the EDiv and Rand values are not used and should always be set to zero. This patch updates the LTK lookup to first use the bdaddr as key and then do the necessary verifications of EDiv and Rand based on whether the found LTK is for SC or not.

---
 net/bluetooth/hci_core.c  | 30 +++++++++++++++++++++++-------
 net/bluetooth/hci_event.c | 15 +++++++++++++--
 2 files changed, 36 insertions(+), 9 deletions(-)
net/bluetooth/hci_core.c +23 -7
index 2586e405adb3..e091e8ffeb8e 100644
@@ -3195,11 +3195,18 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand,
 		if (k->ediv != ediv || k->rand != rand)
 			continue;
 
-		if (ltk_role(k->type) != role)
-			continue;
+		if (smp_ltk_is_sc(k)) {
+			if (k->type == SMP_LTK_P256_DEBUG &&
+			    !test_bit(HCI_KEEP_DEBUG_KEYS, &hdev->dev_flags))
+				continue;
+			rcu_read_unlock();
+			return k;
+		}
 
-		rcu_read_unlock();
-		return k;
+		if (ltk_role(k->type) == role) {
+			rcu_read_unlock();
+			return k;
+		}
 	}
 	rcu_read_unlock();
 
@@ -3213,9 +3220,18 @@ struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(k, &hdev->long_term_keys, list) {
-		if (addr_type == k->bdaddr_type &&
-		    bacmp(bdaddr, &k->bdaddr) == 0 &&
-		    ltk_role(k->type) == role) {
+		if (addr_type != k->bdaddr_type || bacmp(bdaddr, &k->bdaddr))
+			continue;
+
+		if (smp_ltk_is_sc(k)) {
+			if (k->type == SMP_LTK_P256_DEBUG &&
+			    !test_bit(HCI_KEEP_DEBUG_KEYS, &hdev->dev_flags))
+				continue;
+			rcu_read_unlock();
+			return k;
+		}
+
+		if (ltk_role(k->type) == role) {
 			rcu_read_unlock();
 			return k;
 		}
net/bluetooth/hci_event.c +13 -2
index f980fc46ea5e..0058b545c5ed 100644
@@ -4590,10 +4590,21 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 	if (conn == NULL)
 		goto not_found;
 
-	ltk = hci_find_ltk(hdev, ev->ediv, ev->rand, conn->role);
-	if (ltk == NULL)
+	ltk = hci_find_ltk_by_addr(hdev, &conn->dst, conn->dst_type,
+				   conn->role);
+	if (!ltk)
 		goto not_found;
 
+	if (smp_ltk_is_sc(ltk)) {
+		/* With SC both EDiv and Rand are set to zero */
+		if (ev->ediv || ev->rand)
+			goto not_found;
+	} else {
+		/* For non-SC keys check that EDiv and Rand match */
+		if (ev->ediv != ltk->ediv || ev->rand != ltk->rand)
+			goto not_found;
+	}
+
 	memcpy(cp.ltk, ltk->val, sizeof(ltk->val));
 	cp.handle = cpu_to_le16(conn->handle);
 
Signature · 1 line
2.1.0
#10 lore raw

PATCH 10/49 Bluetooth: Remove unused hci_find_ltk function

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

Now that LTKs are always looked up based on bdaddr (with EDiv/Rand checks done after a successful lookup) the hci_find_ltk function is not needed anymore. This patch removes the function.

---
 include/net/bluetooth/hci_core.h |  2 --
 net/bluetooth/hci_core.c         | 28 ----------------------------
 2 files changed, 30 deletions(-)
include/net/bluetooth/hci_core.h +0 -2
index 7f08ea36d246..b41969b561d8 100644
@@ -921,8 +921,6 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
 struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn,
 				  bdaddr_t *bdaddr, u8 *val, u8 type,
 				  u8 pin_len, bool *persistent);
-struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand,
-			     u8 role);
 struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
 			    u8 addr_type, u8 type, u8 authenticated,
 			    u8 tk[16], u8 enc_size, __le16 ediv, __le64 rand);
net/bluetooth/hci_core.c +0 -28
index e091e8ffeb8e..cb9bc8e2c58d 100644
@@ -3185,34 +3185,6 @@ static u8 ltk_role(u8 type)
 	return HCI_ROLE_SLAVE;
 }
 
-struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand,
-			     u8 role)
-{
-	struct smp_ltk *k;
-
-	rcu_read_lock();
-	list_for_each_entry_rcu(k, &hdev->long_term_keys, list) {
-		if (k->ediv != ediv || k->rand != rand)
-			continue;
-
-		if (smp_ltk_is_sc(k)) {
-			if (k->type == SMP_LTK_P256_DEBUG &&
-			    !test_bit(HCI_KEEP_DEBUG_KEYS, &hdev->dev_flags))
-				continue;
-			rcu_read_unlock();
-			return k;
-		}
-
-		if (ltk_role(k->type) == role) {
-			rcu_read_unlock();
-			return k;
-		}
-	}
-	rcu_read_unlock();
-
-	return NULL;
-}
-
 struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
 				     u8 addr_type, u8 role)
 {
Signature · 1 line
2.1.0
#11 lore raw

PATCH 11/49 Bluetooth: Rename hci_find_ltk_by_addr to hci_find_ltk

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

Now that hci_find_ltk_by_addr is the only LTK lookup function there's no need to keep the long name anymore. This patch shortens the function name to simply hci_find_ltk.

---
 include/net/bluetooth/hci_core.h | 4 ++--
 net/bluetooth/hci_core.c         | 6 +++---
 net/bluetooth/hci_event.c        | 3 +--
 net/bluetooth/smp.c              | 6 ++----
 4 files changed, 8 insertions(+), 11 deletions(-)
include/net/bluetooth/hci_core.h +2 -2
index b41969b561d8..90929641d0f0 100644
@@ -924,8 +924,8 @@ struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn,
 struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
 			    u8 addr_type, u8 type, u8 authenticated,
 			    u8 tk[16], u8 enc_size, __le16 ediv, __le64 rand);
-struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
-				     u8 addr_type, u8 role);
+struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
+			     u8 addr_type, u8 role);
 int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type);
 void hci_smp_ltks_clear(struct hci_dev *hdev);
 int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
net/bluetooth/hci_core.c +3 -3
index cb9bc8e2c58d..6c3220e9484f 100644
@@ -3185,8 +3185,8 @@ static u8 ltk_role(u8 type)
 	return HCI_ROLE_SLAVE;
 }
 
-struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
-				     u8 addr_type, u8 role)
+struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
+			     u8 addr_type, u8 role)
 {
 	struct smp_ltk *k;
 
@@ -3313,7 +3313,7 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
 	struct smp_ltk *key, *old_key;
 	u8 role = ltk_role(type);
 
-	old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type, role);
+	old_key = hci_find_ltk(hdev, bdaddr, addr_type, role);
 	if (old_key)
 		key = old_key;
 	else {
net/bluetooth/hci_event.c +1 -2
index 0058b545c5ed..34ecbf0b7e5b 100644
@@ -4590,8 +4590,7 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 	if (conn == NULL)
 		goto not_found;
 
-	ltk = hci_find_ltk_by_addr(hdev, &conn->dst, conn->dst_type,
-				   conn->role);
+	ltk = hci_find_ltk(hdev, &conn->dst, conn->dst_type, conn->role);
 	if (!ltk)
 		goto not_found;
 
net/bluetooth/smp.c +2 -4
index 4ecbf2774fbd..0973e37073e2 100644
@@ -1118,8 +1118,7 @@ static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level)
 	struct smp_ltk *key;
 	struct hci_conn *hcon = conn->hcon;
 
-	key = hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type,
-				   hcon->role);
+	key = hci_find_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, hcon->role);
 	if (!key)
 		return false;
 
@@ -1152,8 +1151,7 @@ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level,
 	 */
 	if (key_pref == SMP_USE_LTK &&
 	    test_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags) &&
-	    hci_find_ltk_by_addr(hcon->hdev, &hcon->dst, hcon->dst_type,
-				 hcon->role))
+	    hci_find_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, hcon->role))
 		return false;
 
 	if (hcon->sec_level >= sec_level)
Signature · 1 line
2.1.0
#12 lore raw

PATCH 12/49 Bluetooth: Set link key generation bit if necessary for LE SC

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

Depending on whether Secure Connections is enabled or not we may need to add the link key generation bit to the key distribution. This patch does the necessary modifications to the build_pairing_cmd() function.

---
 net/bluetooth/smp.c | 10 ++++++++++
 1 file changed, 10 insertions(+)
net/bluetooth/smp.c +10 -0
index 0973e37073e2..d993d7d4fcc8 100644
@@ -333,6 +333,16 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
 	if (test_bit(HCI_PRIVACY, &hdev->dev_flags))
 		local_dist |= SMP_DIST_ID_KEY;
 
+	if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) {
+		if ((authreq & SMP_AUTH_SC) &&
+		    test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
+			local_dist |= SMP_DIST_LINK_KEY;
+			remote_dist |= SMP_DIST_LINK_KEY;
+		}
+	} else {
+		authreq &= ~SMP_AUTH_SC;
+	}
+
 	if (rsp == NULL) {
 		req->io_capability = conn->hcon->io_capability;
 		req->oob_flag = SMP_OOB_NOT_PRESENT;
Signature · 1 line
2.1.0
#13 lore raw

PATCH 13/49 Bluetooth: Add basic support for AES-CMAC

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

Most of the LE Secure Connections SMP crypto functions build on top of the AES-CMAC function. This patch adds access to AES-CMAC in the kernel crypto subsystem by allocating a crypto_hash handle for it in a similar way that we have one for AES-CBC.

---
 net/bluetooth/Kconfig |  1 +
 net/bluetooth/smp.c   | 10 ++++++++++
 2 files changed, 11 insertions(+)
net/bluetooth/Kconfig +1 -0
index 5e97a8ff850b..29bcafc41adf 100644
@@ -10,6 +10,7 @@ menuconfig BT
 	select CRYPTO
 	select CRYPTO_BLKCIPHER
 	select CRYPTO_AES
+	select CRYPTO_CMAC
 	select CRYPTO_ECB
 	select CRYPTO_SHA256
 	help
net/bluetooth/smp.c +10 -0
index d993d7d4fcc8..4fed367da380 100644
@@ -72,6 +72,7 @@ struct smp_chan {
 	unsigned long	flags;
 
 	struct crypto_blkcipher	*tfm_aes;
+	struct crypto_hash	*tfm_cmac;
 };
 
 static inline void swap_buf(const u8 *src, u8 *dst, size_t len)
@@ -396,6 +397,7 @@ static void smp_chan_destroy(struct l2cap_conn *conn)
 	kfree(smp->slave_csrk);
 
 	crypto_free_blkcipher(smp->tfm_aes);
+	crypto_free_hash(smp->tfm_cmac);
 
 	/* If pairing failed clean up any keys we might have */
 	if (!complete) {
@@ -861,6 +863,14 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
 		return NULL;
 	}
 
+	smp->tfm_cmac = crypto_alloc_hash("cmac(aes)", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(smp->tfm_cmac)) {
+		BT_ERR("Unable to create CMAC crypto context");
+		crypto_free_blkcipher(smp->tfm_aes);
+		kfree(smp);
+		return NULL;
+	}
+
 	smp->conn = conn;
 	chan->data = smp;
 
Signature · 1 line
2.1.0
#14 lore raw

PATCH 14/49 Bluetooth: Add ECC library for LE Secure Connections

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

This patch adds a simple ECC library that will act as a fundamental building block for LE Secure Connections. The library has a simple API consisting of two functions: one for generating a public/private key pair and another one for generating a Diffie-Hellman key from a local private key and a remote public key.

The code has been taken from https://github.com/kmackay/easy-ecc and modified to conform with the kernel coding style.

---
 net/bluetooth/Makefile |   2 +-
 net/bluetooth/ecc.c    | 816 +++++++++++++++++++++++++++++++++++++++++++++++++
 net/bluetooth/ecc.h    |  54 ++++
 3 files changed, 871 insertions(+), 1 deletion(-)
 create mode 100644 net/bluetooth/ecc.c
 create mode 100644 net/bluetooth/ecc.h
net/bluetooth/Makefile +1 -1
index 886e9aa3ecf1..a5432a6a0ae6 100644
@@ -13,6 +13,6 @@ bluetooth_6lowpan-y := 6lowpan.o
 
 bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
 	hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
-	a2mp.o amp.o
+	a2mp.o amp.o ecc.o
 
 subdir-ccflags-y += -D__CHECK_ENDIAN__
net/bluetooth/ecc.c new file +816 -0

816 lines not on this page · raw message

net/bluetooth/ecc.h new file +54 -0

54 lines not on this page · raw message

Signature · 1 line
2.1.0
#15 lore raw

PATCH 15/49 Bluetooth: Add basic support for sending our LE SC public key

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

When the initial pairing request & response PDUs have been exchanged and both have had the LE SC bit set the next step is to generate a ECDH key pair and to send the public key to the remote side. This patch adds basic support for generating the key pair and sending the public key using the new Public Key SMP PDU. It is the initiating device that sends the public key first and the non-initiating device responds by sending its public key respectively (in a subsequent patch).

---
 net/bluetooth/smp.c | 45 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 44 insertions(+), 1 deletion(-)
net/bluetooth/smp.c +44 -1
index 4fed367da380..9317583751eb 100644
@@ -29,10 +29,14 @@
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/mgmt.h>
 
+#include "ecc.h"
 #include "smp.h"
 
 #define SMP_ALLOW_CMD(smp, code)	set_bit(code, &smp->allow_cmd)
 
+/* Keys which are not distributed with Secure Connections */
+#define SMP_SC_NO_DIST (SMP_DIST_ENC_KEY | SMP_DIST_LINK_KEY);
+
 #define SMP_TIMEOUT	msecs_to_jiffies(30000)
 
 #define AUTH_REQ_MASK(dev)	(test_bit(HCI_SC_ENABLED, &(dev)->dev_flags) ? \
@@ -71,6 +75,10 @@ struct smp_chan {
 	struct smp_irk	*remote_irk;
 	unsigned long	flags;
 
+	/* Secure Connections variables */
+	u8			local_pk[64];
+	u8			local_sk[32];
+
 	struct crypto_blkcipher	*tfm_aes;
 	struct crypto_hash	*tfm_cmac;
 };
@@ -1012,7 +1020,18 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 	memcpy(&smp->prsp[1], &rsp, sizeof(rsp));
 
 	smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp);
-	SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
+
+	clear_bit(SMP_FLAG_INITIATOR, &smp->flags);
+
+	if (test_bit(SMP_FLAG_SC, &smp->flags)) {
+		SMP_ALLOW_CMD(smp, SMP_CMD_PUBLIC_KEY);
+		/* Clear bits which are generated but not distributed */
+		smp->remote_key_dist &= ~SMP_SC_NO_DIST;
+		/* Wait for Public Key from Initiating Device */
+		return 0;
+	} else {
+		SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
+	}
 
 	/* Request setup of TK */
 	ret = tk_request(conn, 0, auth, rsp.io_capability, req->io_capability);
@@ -1022,6 +1041,23 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 	return 0;
 }
 
+static u8 sc_send_public_key(struct smp_chan *smp)
+{
+	BT_DBG("");
+
+	/* Generate local key pair for Secure Connections */
+	if (!ecc_make_key(smp->local_pk, smp->local_sk))
+		return SMP_UNSPECIFIED;
+
+	BT_DBG("Local Public Key X: %32phN", smp->local_pk);
+	BT_DBG("Local Public Key Y: %32phN", &smp->local_pk[32]);
+	BT_DBG("Local Private Key:  %32phN", smp->local_sk);
+
+	smp_send_cmd(smp->conn, SMP_CMD_PUBLIC_KEY, 64, smp->local_pk);
+
+	return 0;
+}
+
 static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 {
 	struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
@@ -1074,6 +1110,13 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 	 */
 	smp->remote_key_dist &= rsp->resp_key_dist;
 
+	if (test_bit(SMP_FLAG_SC, &smp->flags)) {
+		/* Clear bits which are generated but not distributed */
+		smp->remote_key_dist &= ~SMP_SC_NO_DIST;
+		SMP_ALLOW_CMD(smp, SMP_CMD_PUBLIC_KEY);
+		return sc_send_public_key(smp);
+	}
+
 	auth |= req->auth_req;
 
 	ret = tk_request(conn, 0, auth, req->io_capability, rsp->io_capability);
Signature · 1 line
2.1.0
#16 lore raw

PATCH 16/49 Bluetooth: Add handler function for receiving LE SC public key

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

This patch adds a handler function for the LE SC SMP Public Key PDU. When we receive the key we proceed with generating the shared DHKey value from the remote public key and local private key.

---
 net/bluetooth/smp.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)
net/bluetooth/smp.c +44 -0
index 9317583751eb..1cc438c9c2cb 100644
@@ -50,6 +50,7 @@ enum {
 	SMP_FLAG_COMPLETE,
 	SMP_FLAG_INITIATOR,
 	SMP_FLAG_SC,
+	SMP_FLAG_REMOTE_PK,
 };
 
 struct smp_chan {
@@ -78,6 +79,8 @@ struct smp_chan {
 	/* Secure Connections variables */
 	u8			local_pk[64];
 	u8			local_sk[32];
+	u8			remote_pk[64];
+	u8			dhkey[32];
 
 	struct crypto_blkcipher	*tfm_aes;
 	struct crypto_hash	*tfm_cmac;
@@ -1513,6 +1516,43 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb)
 	return 0;
 }
 
+static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+	struct smp_cmd_public_key *key = (void *) skb->data;
+	struct hci_conn *hcon = conn->hcon;
+	struct l2cap_chan *chan = conn->smp;
+	struct smp_chan *smp = chan->data;
+	int err;
+
+	BT_DBG("conn %p", conn);
+
+	if (skb->len < sizeof(*key))
+		return SMP_INVALID_PARAMS;
+
+	memcpy(smp->remote_pk, key, 64);
+
+	/* Non-initiating device sends its public key after receiving
+	 * the key from the initiating device.
+	 */
+	if (!hcon->out) {
+		err = sc_send_public_key(smp);
+		if (err)
+			return err;
+	}
+
+	BT_DBG("Remote Public Key X: %32phN", smp->remote_pk);
+	BT_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;
+
+	BT_DBG("DHKey %32phN", smp->dhkey);
+
+	set_bit(SMP_FLAG_REMOTE_PK, &smp->flags);
+
+	return 0;
+}
+
 static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb)
 {
 	struct l2cap_conn *conn = chan->conn;
@@ -1597,6 +1637,10 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb)
 		reason = smp_cmd_sign_info(conn, skb);
 		break;
 
+	case SMP_CMD_PUBLIC_KEY:
+		reason = smp_cmd_public_key(conn, skb);
+		break;
+
 	default:
 		BT_DBG("Unknown command code 0x%2.2x", code);
 		reason = SMP_CMD_NOTSUPP;
Signature · 1 line
2.1.0
#17 lore raw

PATCH 17/49 Bluetooth: Add support for sending LE SC Confirm value

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

Once the public key exchange is complete the next step is for the non-initiating device to send a SMP Pairing Confirm PDU to the initiating device. This requires the use of a new smp_f4 confirm value generation function which in turn builds on the AES-CMAC cryptographic function.

---
 net/bluetooth/smp.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 96 insertions(+)
net/bluetooth/smp.c +96 -0
index 1cc438c9c2cb..a1bfcb601c03 100644
@@ -43,6 +43,9 @@
 				 0x1f : 0x07)
 #define KEY_DIST_MASK		0x07
 
+/* Maximum message length that can be passed to aes_cmac */
+#define CMAC_MSG_MAX	80
+
 enum {
 	SMP_FLAG_TK_VALID,
 	SMP_FLAG_CFM_PENDING,
@@ -94,6 +97,84 @@ static inline void swap_buf(const u8 *src, u8 *dst, size_t len)
 		dst[len - 1 - i] = src[i];
 }
 
+static int aes_cmac(struct crypto_hash *tfm, const u8 k[16], const u8 *m,
+		    size_t len, u8 mac[16])
+{
+	uint8_t tmp[16], mac_msb[16], msg_msb[CMAC_MSG_MAX];
+	struct hash_desc desc;
+	struct scatterlist sg;
+	int err;
+
+	if (len > CMAC_MSG_MAX)
+		return -EFBIG;
+
+	if (!tfm) {
+		BT_ERR("tfm %p", tfm);
+		return -EINVAL;
+	}
+
+	desc.tfm = tfm;
+	desc.flags = 0;
+
+	crypto_hash_init(&desc);
+
+	/* Swap key and message from LSB to MSB */
+	swap_buf(k, tmp, 16);
+	swap_buf(m, msg_msb, len);
+
+	BT_DBG("msg (len %zu) %*phN", len, len, m);
+	BT_DBG("key %16phN", k);
+
+	err = crypto_hash_setkey(tfm, tmp, 16);
+	if (err) {
+		BT_ERR("cipher setkey failed: %d", err);
+		return err;
+	}
+
+	sg_init_one(&sg, msg_msb, len);
+
+	err = crypto_hash_update(&desc, &sg, len);
+	if (err) {
+		BT_ERR("Hash update error %d", err);
+		return err;
+	}
+
+	err = crypto_hash_final(&desc, mac_msb);
+	if (err) {
+		BT_ERR("Hash final error %d", err);
+		return err;
+	}
+
+	swap_buf(mac_msb, mac, 16);
+
+	BT_DBG("mac %16phN", mac);
+
+	return 0;
+}
+
+static int smp_f4(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32],
+		  const u8 x[16], u8 z, u8 res[16])
+{
+	u8 m[65];
+	int err;
+
+	BT_DBG("u %32phN", u);
+	BT_DBG("v %32phN", v);
+	BT_DBG("x %16phN z %02x", x, z);
+
+	m[0] = z;
+	memcpy(m + 1, v, 32);
+	memcpy(m + 33, u, 32);
+
+	err = aes_cmac(tfm_cmac, x, m, sizeof(m), res);
+	if (err)
+		return err;
+
+	BT_DBG("res %16phN", res);
+
+	return err;
+}
+
 static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
 {
 	struct blkcipher_desc desc;
@@ -1522,6 +1603,7 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
 	struct hci_conn *hcon = conn->hcon;
 	struct l2cap_chan *chan = conn->smp;
 	struct smp_chan *smp = chan->data;
+	struct smp_cmd_pairing_confirm cfm;
 	int err;
 
 	BT_DBG("conn %p", conn);
@@ -1550,6 +1632,20 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	set_bit(SMP_FLAG_REMOTE_PK, &smp->flags);
 
+	/* The Initiating device waits for the non-initiating device to
+	 * send the confirm value.
+	 */
+	if (conn->hcon->out)
+		return 0;
+
+	err = smp_f4(smp->tfm_cmac, smp->local_pk, smp->remote_pk, smp->prnd,
+		     0, cfm.confirm_val);
+	if (err)
+		return SMP_UNSPECIFIED;
+
+	smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cfm), &cfm);
+	SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM);
+
 	return 0;
 }
 
Signature · 1 line
2.1.0
#18 lore raw

PATCH 18/49 Bluetooth: Add LE SC support for responding to Pairing Confirm PDU

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

When LE SC is being used we should always respond to it by sending our local random number. This patch adds a convenience function for it which also contains a check for the pre-requisite public key exchange completion

---
 net/bluetooth/smp.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)
net/bluetooth/smp.c +22 -0
index a1bfcb601c03..36f3c75ac858 100644
@@ -1216,6 +1216,25 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 	return 0;
 }
 
+static u8 sc_check_confirm(struct smp_chan *smp)
+{
+	struct l2cap_conn *conn = smp->conn;
+
+	BT_DBG("");
+
+	/* Public Key exchange must happen before any other steps */
+	if (!test_bit(SMP_FLAG_REMOTE_PK, &smp->flags))
+		return SMP_UNSPECIFIED;
+
+	if (conn->hcon->out) {
+		smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
+			     smp->prnd);
+		SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM);
+	}
+
+	return 0;
+}
+
 static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
 {
 	struct l2cap_chan *chan = conn->smp;
@@ -1229,6 +1248,9 @@ 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 (conn->hcon->out) {
 		smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
 			     smp->prnd);
Signature · 1 line
2.1.0
#19 lore raw

PATCH 19/49 Bluetooth: Add support for LE SC numeric comparison

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

After the Pairing Confirm and Random PDUs have been exchanged in LE SC it's time to generate a numeric comparison value using a new smp_g2 cryptographic function (which also builds on AES-CMAC). This patch adds the smp_g2 implementation and updates the Pairing Random PDU handler to proceed with the value genration and user confirmation.

---
 net/bluetooth/smp.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 70 insertions(+), 1 deletion(-)
net/bluetooth/smp.c +70 -1
index 36f3c75ac858..00bafcae8814 100644
@@ -175,6 +175,32 @@ static int smp_f4(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32],
 	return err;
 }
 
+static int smp_g2(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32],
+		  const u8 x[16], const u8 y[16], u32 *val)
+{
+	u8 m[80], tmp[16];
+	int err;
+
+	BT_DBG("u %32phN", u);
+	BT_DBG("v %32phN", v);
+	BT_DBG("x %16phN y %16phN", x, y);
+
+	memcpy(m, y, 16);
+	memcpy(m + 16, v, 32);
+	memcpy(m + 48, u, 32);
+
+	err = aes_cmac(tfm_cmac, x, m, sizeof(m), tmp);
+	if (err)
+		return err;
+
+	*val = get_unaligned_le32(tmp);
+	*val %= 1000000;
+
+	BT_DBG("val %06u", *val);
+
+	return 0;
+}
+
 static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
 {
 	struct blkcipher_desc desc;
@@ -1270,6 +1296,10 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 {
 	struct l2cap_chan *chan = conn->smp;
 	struct smp_chan *smp = chan->data;
+	struct hci_conn *hcon = conn->hcon;
+	u8 *pkax, *pkbx, *na, *nb;
+	u32 passkey;
+	int err;
 
 	BT_DBG("conn %p", conn);
 
@@ -1279,7 +1309,46 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 	memcpy(smp->rrnd, skb->data, sizeof(smp->rrnd));
 	skb_pull(skb, sizeof(smp->rrnd));
 
-	return smp_random(smp);
+	if (!test_bit(SMP_FLAG_SC, &smp->flags))
+		return smp_random(smp);
+
+	if (hcon->out) {
+		u8 cfm[16];
+
+		err = smp_f4(smp->tfm_cmac, smp->remote_pk, smp->local_pk,
+			     smp->rrnd, 0, cfm);
+		if (err)
+			return SMP_UNSPECIFIED;
+
+		if (memcmp(smp->pcnf, cfm, 16))
+			return SMP_CONFIRM_FAILED;
+
+		pkax = smp->local_pk;
+		pkbx = smp->remote_pk;
+		na   = smp->prnd;
+		nb   = smp->rrnd;
+	} else {
+		smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
+			     smp->prnd);
+		SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
+
+		pkax = smp->remote_pk;
+		pkbx = smp->local_pk;
+		na   = smp->rrnd;
+		nb   = smp->prnd;
+	}
+
+	err = smp_g2(smp->tfm_cmac, pkax, pkbx, na, nb, &passkey);
+	if (err)
+		return SMP_UNSPECIFIED;
+
+	err = mgmt_user_confirm_request(hcon->hdev, &hcon->dst,
+					hcon->type, hcon->dst_type,
+					passkey, 0);
+	if (err)
+		return SMP_UNSPECIFIED;
+
+	return 0;
 }
 
 static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level)
Signature · 1 line
2.1.0
#20 lore raw

PATCH 20/49 Bluetooth: Add support for handling LE SC user response

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

With LE SC, once the user has responded to the numeric comparison it's time to send DHKey check values in both directions. The DHKey check value is generated using new smp_f5 and smp_f6 cryptographic functions. The smp_f5 function is responsible for generating the LTK and the MacKey values whereas the smp_f6 function takes the MacKey as input and generates the DHKey Check value.

---
 net/bluetooth/smp.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 154 insertions(+)
net/bluetooth/smp.c +154 -0
index 00bafcae8814..bdbfbdba0089 100644
@@ -84,6 +84,7 @@ struct smp_chan {
 	u8			local_sk[32];
 	u8			remote_pk[64];
 	u8			dhkey[32];
+	u8			mackey[16];
 
 	struct crypto_blkcipher	*tfm_aes;
 	struct crypto_hash	*tfm_cmac;
@@ -175,6 +176,86 @@ static int smp_f4(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32],
 	return err;
 }
 
+static int smp_f5(struct crypto_hash *tfm_cmac, u8 w[32], u8 n1[16], u8 n2[16],
+		  u8 a1[7], u8 a2[7], u8 mackey[16], u8 ltk[16])
+{
+	/* The btle, salt and length "magic" values are as defined in
+	 * the SMP section of the Bluetooth core specification. In ASCII
+	 * the btle value ends up being 'btle'. The salt is just a
+	 * random number whereas length is the value 256 in little
+	 * endian format.
+	 */
+	const u8 btle[4] = { 0x65, 0x6c, 0x74, 0x62 };
+	const u8 salt[16] = { 0xbe, 0x83, 0x60, 0x5a, 0xdb, 0x0b, 0x37, 0x60,
+			      0x38, 0xa5, 0xf5, 0xaa, 0x91, 0x83, 0x88, 0x6c };
+	const u8 length[2] = { 0x00, 0x01 };
+	u8 m[53], t[16];
+	int err;
+
+	BT_DBG("w %32phN", w);
+	BT_DBG("n1 %16phN n2 %16phN", n1, n2);
+	BT_DBG("a1 %7phN a2 %7phN", a1, a2);
+
+	err = aes_cmac(tfm_cmac, salt, w, 32, t);
+	if (err)
+		return err;
+
+	BT_DBG("t %16phN", t);
+
+	memcpy(m, length, 2);
+	memcpy(m + 2, a2, 7);
+	memcpy(m + 9, a1, 7);
+	memcpy(m + 16, n2, 16);
+	memcpy(m + 32, n1, 16);
+	memcpy(m + 48, btle, 4);
+
+	m[52] = 0; /* Counter */
+
+	err = aes_cmac(tfm_cmac, t, m, sizeof(m), mackey);
+	if (err)
+		return err;
+
+	BT_DBG("mackey %16phN", mackey);
+
+	m[52] = 1; /* Counter */
+
+	err = aes_cmac(tfm_cmac, t, m, sizeof(m), ltk);
+	if (err)
+		return err;
+
+	BT_DBG("ltk %16phN", ltk);
+
+	return 0;
+}
+
+static int smp_f6(struct crypto_hash *tfm_cmac, const u8 w[16],
+		  const u8 n1[16], u8 n2[16], const u8 r[16],
+		  const u8 io_cap[3], const u8 a1[7], const u8 a2[7],
+		  u8 res[16])
+{
+	u8 m[65];
+	int err;
+
+	BT_DBG("w %16phN", w);
+	BT_DBG("n1 %16phN n2 %16phN", n1, n2);
+	BT_DBG("r %16phN io_cap %3phN a1 %7phN a2 %7phN", r, io_cap, a1, a2);
+
+	memcpy(m, a2, 7);
+	memcpy(m + 7, a1, 7);
+	memcpy(m + 14, io_cap, 3);
+	memcpy(m + 17, r, 16);
+	memcpy(m + 33, n2, 16);
+	memcpy(m + 49, n1, 16);
+
+	err = aes_cmac(tfm_cmac, w, m, sizeof(m), res);
+	if (err)
+		return err;
+
+	BT_DBG("res %16phN", res);
+
+	return err;
+}
+
 static int smp_g2(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32],
 		  const u8 x[16], const u8 y[16], u32 *val)
 {
@@ -1001,6 +1082,69 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
 	return smp;
 }
 
+static int sc_mackey_and_ltk(struct smp_chan *smp, u8 mackey[16], u8 ltk[16])
+{
+	struct hci_conn *hcon = smp->conn->hcon;
+	u8 *na, *nb, a[7], b[7];
+
+	if (hcon->out) {
+		na   = smp->prnd;
+		nb   = smp->rrnd;
+	} else {
+		na   = smp->rrnd;
+		nb   = smp->prnd;
+	}
+
+	memcpy(a, &hcon->init_addr, 6);
+	memcpy(b, &hcon->resp_addr, 6);
+	a[6] = hcon->init_addr_type;
+	b[6] = hcon->resp_addr_type;
+
+	return smp_f5(smp->tfm_cmac, smp->dhkey, na, nb, a, b, mackey, ltk);
+}
+
+static int sc_user_reply(struct smp_chan *smp, u16 mgmt_op, __le32 passkey)
+{
+	struct hci_conn *hcon = smp->conn->hcon;
+	struct smp_cmd_dhkey_check check;
+	u8 a[7], b[7], *local_addr, *remote_addr;
+	u8 io_cap[3], r[16];
+
+	switch (mgmt_op) {
+	case MGMT_OP_USER_PASSKEY_NEG_REPLY:
+		smp_failure(smp->conn, SMP_PASSKEY_ENTRY_FAILED);
+		return 0;
+	case MGMT_OP_USER_CONFIRM_NEG_REPLY:
+		smp_failure(smp->conn, SMP_NUMERIC_COMP_FAILED);
+		return 0;
+	}
+
+	memcpy(a, &hcon->init_addr, 6);
+	memcpy(b, &hcon->resp_addr, 6);
+	a[6] = hcon->init_addr_type;
+	b[6] = hcon->resp_addr_type;
+
+	if (hcon->out) {
+		local_addr = a;
+		remote_addr = b;
+		memcpy(io_cap, &smp->preq[1], 3);
+	} else {
+		local_addr = b;
+		remote_addr = a;
+		memcpy(io_cap, &smp->prsp[1], 3);
+	}
+
+	memcpy(r, &passkey, sizeof(passkey));
+	memset(r + sizeof(passkey), 0, sizeof(r) - sizeof(passkey));
+
+	smp_f6(smp->tfm_cmac, smp->mackey, smp->prnd, smp->rrnd, r, io_cap,
+	       local_addr, remote_addr, check.e);
+
+	smp_send_cmd(smp->conn, SMP_CMD_DHKEY_CHECK, sizeof(check), &check);
+
+	return 0;
+}
+
 int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
 {
 	struct l2cap_conn *conn = hcon->l2cap_data;
@@ -1026,6 +1170,11 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
 
 	smp = chan->data;
 
+	if (test_bit(SMP_FLAG_SC, &smp->flags)) {
+		err = sc_user_reply(smp, mgmt_op, passkey);
+		goto unlock;
+	}
+
 	switch (mgmt_op) {
 	case MGMT_OP_USER_PASSKEY_REPLY:
 		value = le32_to_cpu(passkey);
@@ -1338,6 +1487,11 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 		nb   = smp->prnd;
 	}
 
+	/* Generate MacKey and LTK */
+	err = sc_mackey_and_ltk(smp, smp->mackey, smp->tk);
+	if (err)
+		return SMP_UNSPECIFIED;
+
 	err = smp_g2(smp->tfm_cmac, pkax, pkbx, na, nb, &passkey);
 	if (err)
 		return SMP_UNSPECIFIED;
Signature · 1 line
2.1.0
#21 lore raw

PATCH 21/49 Bluetooth: Add support for LE SC DHKey check PDU

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

Once we receive the DHKey check PDU it's time to first verify that the value is correct and then proceed with encrypting the link.

---
 net/bluetooth/smp.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)
net/bluetooth/smp.c +56 -0
index bdbfbdba0089..a759105b252c 100644
@@ -1894,6 +1894,58 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
 	return 0;
 }
 
+static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+	struct smp_cmd_dhkey_check *check = (void *) skb->data;
+	struct l2cap_chan *chan = conn->smp;
+	struct hci_conn *hcon = conn->hcon;
+	struct smp_chan *smp = chan->data;
+	u8 a[7], b[7], *local_addr, *remote_addr;
+	u8 io_cap[3], r[16], e[16];
+	int err;
+
+	BT_DBG("conn %p", conn);
+
+	if (skb->len < sizeof(*check))
+		return SMP_INVALID_PARAMS;
+
+	memcpy(a, &hcon->init_addr, 6);
+	memcpy(b, &hcon->resp_addr, 6);
+	a[6] = hcon->init_addr_type;
+	b[6] = hcon->resp_addr_type;
+
+	if (hcon->out) {
+		local_addr = a;
+		remote_addr = b;
+		memcpy(io_cap, &smp->prsp[1], 3);
+	} else {
+		local_addr = b;
+		remote_addr = a;
+		memcpy(io_cap, &smp->preq[1], 3);
+	}
+
+	memset(r, 0, sizeof(r));
+
+	err = smp_f6(smp->tfm_cmac, smp->mackey, smp->rrnd, smp->prnd, r,
+		     io_cap, remote_addr, local_addr, e);
+	if (err)
+		return SMP_UNSPECIFIED;
+
+	if (memcmp(check->e, e, 16))
+		return SMP_DHKEY_CHECK_FAILED;
+
+	smp->ltk = hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type,
+			       SMP_LTK_P256, 0, smp->tk, smp->enc_key_size,
+			       0, 0);
+
+	if (hcon->out) {
+		hci_le_start_enc(hcon, 0, 0, smp->tk);
+		hcon->enc_key_size = smp->enc_key_size;
+	}
+
+	return 0;
+}
+
 static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb)
 {
 	struct l2cap_conn *conn = chan->conn;
@@ -1982,6 +2034,10 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb)
 		reason = smp_cmd_public_key(conn, skb);
 		break;
 
+	case SMP_CMD_DHKEY_CHECK:
+		reason = smp_cmd_dhkey_check(conn, skb);
+		break;
+
 	default:
 		BT_DBG("Unknown command code 0x%2.2x", code);
 		reason = SMP_CMD_NOTSUPP;
Signature · 1 line
2.1.0
#22 lore raw

PATCH 22/49 Bluetooth: Add support for LE SC key generation

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

As the last step of the LE SC pairing process it's time to generate and distribute keys. The generation part is unique to LE SC and so this patch adds a dedicated function for it. We also clear the distribution bits for keys which are not distributed with LE SC, so that the code shared with legacy SMP will not go ahead and try to distribute them.

---
 net/bluetooth/smp.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)
net/bluetooth/smp.c +57 -0
index a759105b252c..816cbb63b68b 100644
@@ -77,6 +77,7 @@ struct smp_chan {
 	struct smp_ltk	*ltk;
 	struct smp_ltk	*slave_ltk;
 	struct smp_irk	*remote_irk;
+	u8		*link_key;
 	unsigned long	flags;
 
 	/* Secure Connections variables */
@@ -321,6 +322,22 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
 	return err;
 }
 
+static int smp_h6(struct crypto_hash *tfm_cmac, const u8 w[16],
+		  const u8 key_id[4], u8 res[16])
+{
+	int err;
+
+	BT_DBG("w %16phN key_id %4phN", w, key_id);
+
+	err = aes_cmac(tfm_cmac, w, key_id, 4, res);
+	if (err)
+		return err;
+
+	BT_DBG("res %16phN", res);
+
+	return err;
+}
+
 static int smp_ah(struct crypto_blkcipher *tfm, u8 irk[16], u8 r[3], u8 res[3])
 {
 	u8 _res[16];
@@ -594,6 +611,7 @@ static void smp_chan_destroy(struct l2cap_conn *conn)
 
 	kfree(smp->csrk);
 	kfree(smp->slave_csrk);
+	kfree(smp->link_key);
 
 	crypto_free_blkcipher(smp->tfm_aes);
 	crypto_free_hash(smp->tfm_cmac);
@@ -907,6 +925,37 @@ static void smp_notify_keys(struct l2cap_conn *conn)
 		bacpy(&smp->slave_ltk->bdaddr, &hcon->dst);
 		mgmt_new_ltk(hdev, smp->slave_ltk, persistent);
 	}
+
+	if (smp->link_key) {
+		hci_add_link_key(hdev, smp->conn->hcon, &hcon->dst,
+				 smp->link_key, HCI_LK_AUTH_COMBINATION_P256,
+				 0, NULL);
+	}
+}
+
+static void sc_generate_link_key(struct smp_chan *smp)
+{
+	/* These constants are as specified in the core specification.
+	 * In ASCII they spell out to 'tmp1' and 'lebr'.
+	 */
+	const u8 tmp1[4] = { 0x31, 0x70, 0x6d, 0x74 };
+	const u8 lebr[4] = { 0x72, 0x62, 0x65, 0x6c };
+
+	smp->link_key = kzalloc(16, GFP_KERNEL);
+	if (!smp->link_key)
+		return;
+
+	if (smp_h6(smp->tfm_cmac, smp->tk, tmp1, smp->link_key)) {
+		kfree(smp->link_key);
+		smp->link_key = NULL;
+		return;
+	}
+
+	if (smp_h6(smp->tfm_cmac, smp->link_key, lebr, smp->link_key)) {
+		kfree(smp->link_key);
+		smp->link_key = NULL;
+		return;
+	}
 }
 
 static void smp_allow_key_dist(struct smp_chan *smp)
@@ -951,6 +1000,14 @@ static void smp_distribute_keys(struct smp_chan *smp)
 		*keydist &= req->resp_key_dist;
 	}
 
+	if (test_bit(SMP_FLAG_SC, &smp->flags)) {
+		if (*keydist & SMP_DIST_LINK_KEY)
+			sc_generate_link_key(smp);
+
+		/* Clear the keys which are generated but not distributed */
+		*keydist &= ~SMP_SC_NO_DIST;
+	}
+
 	BT_DBG("keydist 0x%x", *keydist);
 
 	if (*keydist & SMP_DIST_ENC_KEY) {
Signature · 1 line
2.1.0
#23 lore raw

PATCH 23/49 Bluetooth: Track authentication method in SMP context

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

For Secure Connections we'll select the authentication method as soon as we receive the public key, but only use it later (both when actually triggering the method as well as when determining the quality of the resulting LTK). Store the method therefore in the SMP context.

---
 net/bluetooth/smp.c | 32 +++++++++++++++++---------------
 1 file changed, 17 insertions(+), 15 deletions(-)
net/bluetooth/smp.c +17 -15
index 816cbb63b68b..651963f26da0 100644
@@ -79,6 +79,7 @@ struct smp_chan {
 	struct smp_irk	*remote_irk;
 	u8		*link_key;
 	unsigned long	flags;
+	u8		method;
 
 	/* Secure Connections variables */
 	u8			local_pk[64];
@@ -688,7 +689,6 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
 	struct hci_conn *hcon = conn->hcon;
 	struct l2cap_chan *chan = conn->smp;
 	struct smp_chan *smp = chan->data;
-	u8 method;
 	u32 passkey = 0;
 	int ret = 0;
 
@@ -705,26 +705,28 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
 	 * table.
 	 */
 	if (!(auth & SMP_AUTH_MITM))
-		method = JUST_CFM;
+		smp->method = JUST_CFM;
 	else
-		method = get_auth_method(smp, local_io, remote_io);
+		smp->method = get_auth_method(smp, local_io, remote_io);
 
 	/* Don't confirm locally initiated pairing attempts */
-	if (method == JUST_CFM && test_bit(SMP_FLAG_INITIATOR, &smp->flags))
-		method = JUST_WORKS;
+	if (smp->method == JUST_CFM && test_bit(SMP_FLAG_INITIATOR,
+						&smp->flags))
+		smp->method = JUST_WORKS;
 
 	/* Don't bother user space with no IO capabilities */
-	if (method == JUST_CFM && hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT)
-		method = JUST_WORKS;
+	if (smp->method == JUST_CFM &&
+	    hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT)
+		smp->method = JUST_WORKS;
 
 	/* If Just Works, Continue with Zero TK */
-	if (method == JUST_WORKS) {
+	if (smp->method == JUST_WORKS) {
 		set_bit(SMP_FLAG_TK_VALID, &smp->flags);
 		return 0;
 	}
 
 	/* Not Just Works/Confirm results in MITM Authentication */
-	if (method != JUST_CFM) {
+	if (smp->method != JUST_CFM) {
 		set_bit(SMP_FLAG_MITM_AUTH, &smp->flags);
 		if (hcon->pending_sec_level < BT_SECURITY_HIGH)
 			hcon->pending_sec_level = BT_SECURITY_HIGH;
@@ -733,15 +735,15 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
 	/* If both devices have Keyoard-Display I/O, the master
 	 * Confirms and the slave Enters the passkey.
 	 */
-	if (method == OVERLAP) {
+	if (smp->method == OVERLAP) {
 		if (hcon->role == HCI_ROLE_MASTER)
-			method = CFM_PASSKEY;
+			smp->method = CFM_PASSKEY;
 		else
-			method = REQ_PASSKEY;
+			smp->method = REQ_PASSKEY;
 	}
 
 	/* Generate random passkey. */
-	if (method == CFM_PASSKEY) {
+	if (smp->method == CFM_PASSKEY) {
 		memset(smp->tk, 0, sizeof(smp->tk));
 		get_random_bytes(&passkey, sizeof(passkey));
 		passkey %= 1000000;
@@ -750,10 +752,10 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
 		set_bit(SMP_FLAG_TK_VALID, &smp->flags);
 	}
 
-	if (method == REQ_PASSKEY)
+	if (smp->method == REQ_PASSKEY)
 		ret = mgmt_user_passkey_request(hcon->hdev, &hcon->dst,
 						hcon->type, hcon->dst_type);
-	else if (method == JUST_CFM)
+	else if (smp->method == JUST_CFM)
 		ret = mgmt_user_confirm_request(hcon->hdev, &hcon->dst,
 						hcon->type, hcon->dst_type,
 						passkey, 1);
Signature · 1 line
2.1.0
#24 lore raw

PATCH 24/49 Bluetooth: Add selection of the SC authentication method

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

This patch adds code to select the authentication method for Secure Connections based on the local and remote capabilities. A new DSP_PASSKEY method is also added for displaying the passkey - something that is not part of legacy SMP pairing.

---
 net/bluetooth/smp.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 69 insertions(+), 5 deletions(-)
net/bluetooth/smp.c +69 -5
index 651963f26da0..8753d8120850 100644
@@ -661,6 +661,7 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason)
 #define REQ_PASSKEY	0x02
 #define CFM_PASSKEY	0x03
 #define REQ_OOB		0x04
+#define DSP_PASSKEY	0x05
 #define OVERLAP		0xFF
 
 static const u8 gen_method[5][5] = {
@@ -671,6 +672,14 @@ static const u8 gen_method[5][5] = {
 	{ CFM_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, OVERLAP     },
 };
 
+static const u8 sc_method[5][5] = {
+	{ JUST_WORKS,  JUST_CFM,    REQ_PASSKEY, JUST_WORKS, REQ_PASSKEY },
+	{ JUST_WORKS,  CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, CFM_PASSKEY },
+	{ DSP_PASSKEY, DSP_PASSKEY, REQ_PASSKEY, JUST_WORKS, DSP_PASSKEY },
+	{ JUST_WORKS,  JUST_CFM,    JUST_WORKS,  JUST_WORKS, JUST_CFM    },
+	{ DSP_PASSKEY, CFM_PASSKEY, REQ_PASSKEY, JUST_WORKS, CFM_PASSKEY },
+};
+
 static u8 get_auth_method(struct smp_chan *smp, u8 local_io, u8 remote_io)
 {
 	/* If either side has unknown io_caps, use JUST_CFM (which gets
@@ -680,6 +689,9 @@ static u8 get_auth_method(struct smp_chan *smp, u8 local_io, u8 remote_io)
 	    remote_io > SMP_IO_KEYBOARD_DISPLAY)
 		return JUST_CFM;
 
+	if (test_bit(SMP_FLAG_SC, &smp->flags))
+		return sc_method[remote_io][local_io];
+
 	return gen_method[remote_io][local_io];
 }
 
@@ -1305,6 +1317,11 @@ 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));
 
+	build_pairing_cmd(conn, req, &rsp, auth);
+
+	if (rsp.auth_req & SMP_AUTH_SC)
+		set_bit(SMP_FLAG_SC, &smp->flags);
+
 	if (conn->hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT)
 		sec_level = BT_SECURITY_MEDIUM;
 	else
@@ -1323,11 +1340,6 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 			return SMP_AUTH_REQUIREMENTS;
 	}
 
-	build_pairing_cmd(conn, req, &rsp, auth);
-
-	if (rsp.auth_req & SMP_AUTH_SC)
-		set_bit(SMP_FLAG_SC, &smp->flags);
-
 	key_size = min(req->max_key_size, rsp.max_key_size);
 	if (check_enc_key_size(conn, key_size))
 		return SMP_ENC_KEY_SIZE;
@@ -1901,12 +1913,54 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb)
 	return 0;
 }
 
+static u8 sc_select_method(struct smp_chan *smp)
+{
+	struct l2cap_conn *conn = smp->conn;
+	struct hci_conn *hcon = conn->hcon;
+	struct smp_cmd_pairing *local, *remote;
+	u8 local_mitm, remote_mitm, local_io, remote_io, method;
+
+	/* The preq/prsp contain the raw Pairing Request/Response PDUs
+	 * which are needed as inputs to some crypto functions. To get
+	 * the "struct smp_cmd_pairing" from them we need to skip the
+	 * first byte which contains the opcode.
+	 */
+	if (hcon->out) {
+		local = (void *) &smp->preq[1];
+		remote = (void *) &smp->prsp[1];
+	} else {
+		local = (void *) &smp->prsp[1];
+		remote = (void *) &smp->preq[1];
+	}
+
+	local_io = local->io_capability;
+	remote_io = remote->io_capability;
+
+	local_mitm = (local->auth_req & SMP_AUTH_MITM);
+	remote_mitm = (remote->auth_req & SMP_AUTH_MITM);
+
+	/* If either side wants MITM, look up the method from the table,
+	 * otherwise use JUST WORKS.
+	 */
+	if (local_mitm || remote_mitm)
+		method = get_auth_method(smp, local_io, remote_io);
+	else
+		method = JUST_WORKS;
+
+	/* Don't confirm locally initiated pairing attempts */
+	if (method == JUST_CFM && test_bit(SMP_FLAG_INITIATOR, &smp->flags))
+		method = JUST_WORKS;
+
+	return method;
+}
+
 static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
 {
 	struct smp_cmd_public_key *key = (void *) skb->data;
 	struct hci_conn *hcon = conn->hcon;
 	struct l2cap_chan *chan = conn->smp;
 	struct smp_chan *smp = chan->data;
+	struct hci_dev *hdev = hcon->hdev;
 	struct smp_cmd_pairing_confirm cfm;
 	int err;
 
@@ -1936,6 +1990,16 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	set_bit(SMP_FLAG_REMOTE_PK, &smp->flags);
 
+	smp->method = sc_select_method(smp);
+
+	BT_DBG("%s selected method 0x%02x", hdev->name, smp->method);
+
+	/* JUST_WORKS and JUST_CFM result in an unauthenticated key */
+	if (smp->method == JUST_WORKS || smp->method == JUST_CFM)
+		hcon->pending_sec_level = BT_SECURITY_MEDIUM;
+	else
+		hcon->pending_sec_level = BT_SECURITY_FIPS;
+
 	/* The Initiating device waits for the non-initiating device to
 	 * send the confirm value.
 	 */
Signature · 1 line
2.1.0
#25 lore raw

PATCH 25/49 Bluetooth: Detect SMP SC debug keys

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

We need to be able to detect if the remote side used a debug key for the pairing. This patch adds the debug key defines and sets a flag to indicate that a debug key was used. The debug private key (debug_sk) is also added in this patch but will only be used in a subsequent patch when local debug key support is implemented.

---
 net/bluetooth/smp.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
net/bluetooth/smp.c +27 -0
index 8753d8120850..74b0489fea4f 100644
@@ -54,6 +54,7 @@ enum {
 	SMP_FLAG_INITIATOR,
 	SMP_FLAG_SC,
 	SMP_FLAG_REMOTE_PK,
+	SMP_FLAG_DEBUG_KEY,
 };
 
 struct smp_chan {
@@ -92,6 +93,29 @@ struct smp_chan {
 	struct crypto_hash	*tfm_cmac;
 };
 
+/* These debug key values are defined in the SMP section of the core
+ * specification. debug_pk is the public debug key and debug_sk the
+ * private debug key.
+ */
+static const u8 debug_pk[64] = {
+		0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc,
+		0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef,
+		0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e,
+		0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20,
+
+		0x8b, 0xd2, 0x89, 0x15, 0xd0, 0x8e, 0x1c, 0x74,
+		0x24, 0x30, 0xed, 0x8f, 0xc2, 0x45, 0x63, 0x76,
+		0x5c, 0x15, 0x52, 0x5a, 0xbf, 0x9a, 0x32, 0x63,
+		0x6d, 0xeb, 0x2a, 0x65, 0x49, 0x9c, 0x80, 0xdc,
+};
+
+static const u8 debug_sk[32] = {
+		0xbd, 0x1a, 0x3c, 0xcd, 0xa6, 0xb8, 0x99, 0x58,
+		0x99, 0xb7, 0x40, 0xeb, 0x7b, 0x60, 0xff, 0x4a,
+		0x50, 0x3f, 0x10, 0xd2, 0xe3, 0xb3, 0xc9, 0x74,
+		0x38, 0x5f, 0xc5, 0xa3, 0xd4, 0xf6, 0x49, 0x3f,
+};
+
 static inline void swap_buf(const u8 *src, u8 *dst, size_t len)
 {
 	size_t i;
@@ -2000,6 +2024,9 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
 	else
 		hcon->pending_sec_level = BT_SECURITY_FIPS;
 
+	if (!memcmp(debug_pk, smp->remote_pk, 64))
+		set_bit(SMP_FLAG_DEBUG_KEY, &smp->flags);
+
 	/* The Initiating device waits for the non-initiating device to
 	 * send the confirm value.
 	 */
Signature · 1 line
2.1.0
#26 lore raw

PATCH 26/49 Bluetooth: Add check for accidentally generating a debug key

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

It is very unlikely, but to have a 100% guarantee of the generated key type we need to reject any keys which happen to match the debug key.

---
 net/bluetooth/smp.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)
net/bluetooth/smp.c +11 -3
index 74b0489fea4f..13fbe05d33cb 100644
@@ -1399,9 +1399,17 @@ static u8 sc_send_public_key(struct smp_chan *smp)
 {
 	BT_DBG("");
 
-	/* Generate local key pair for Secure Connections */
-	if (!ecc_make_key(smp->local_pk, smp->local_sk))
-		return SMP_UNSPECIFIED;
+	while (true) {
+		/* Generate local key pair for Secure Connections */
+		if (!ecc_make_key(smp->local_pk, smp->local_sk))
+			return SMP_UNSPECIFIED;
+
+		/* This is unlikely, but we need to check that we didn't
+		 * accidentially generate a debug key.
+		 */
+		if (memcmp(smp->local_sk, debug_sk, 32))
+			break;
+	}
 
 	BT_DBG("Local Public Key X: %32phN", smp->local_pk);
 	BT_DBG("Local Public Key Y: %32phN", &smp->local_pk[32]);
Signature · 1 line
2.1.0
#27 lore raw

PATCH 27/49 Bluetooth: Set correct LTK type and authentication for SC

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

After generating the LTK we should set the correct type (normal SC or debug) and authentication information for it.

---
 net/bluetooth/smp.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)
net/bluetooth/smp.c +12 -1
index 13fbe05d33cb..8c7862044e44 100644
@@ -2060,6 +2060,7 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)
 	struct smp_chan *smp = chan->data;
 	u8 a[7], b[7], *local_addr, *remote_addr;
 	u8 io_cap[3], r[16], e[16];
+	u8 key_type, auth;
 	int err;
 
 	BT_DBG("conn %p", conn);
@@ -2092,8 +2093,18 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)
 	if (memcmp(check->e, e, 16))
 		return SMP_DHKEY_CHECK_FAILED;
 
+	if (test_bit(SMP_FLAG_DEBUG_KEY, &smp->flags))
+		key_type = SMP_LTK_P256_DEBUG;
+	else
+		key_type = SMP_LTK_P256;
+
+	if (hcon->pending_sec_level == BT_SECURITY_FIPS)
+		auth = 1;
+	else
+		auth = 0;
+
 	smp->ltk = hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type,
-			       SMP_LTK_P256, 0, smp->tk, smp->enc_key_size,
+			       key_type, auth, smp->tk, smp->enc_key_size,
 			       0, 0);
 
 	if (hcon->out) {
Signature · 1 line
2.1.0
#28 lore raw

PATCH 28/49 Bluetooth: Add support for SC just-works pairing

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

If the just-works method was chosen we shouldn't send anything to user space but simply proceed with sending the DHKey Check PDU. This patch adds the necessary code for it.

---
 net/bluetooth/smp.c | 39 +++++++++++++++++++++++++++------------
 1 file changed, 27 insertions(+), 12 deletions(-)
net/bluetooth/smp.c +27 -12
index 8c7862044e44..7fdeca7edb7c 100644
@@ -1198,22 +1198,13 @@ static int sc_mackey_and_ltk(struct smp_chan *smp, u8 mackey[16], u8 ltk[16])
 	return smp_f5(smp->tfm_cmac, smp->dhkey, na, nb, a, b, mackey, ltk);
 }
 
-static int sc_user_reply(struct smp_chan *smp, u16 mgmt_op, __le32 passkey)
+static void sc_dhkey_check(struct smp_chan *smp, __le32 passkey)
 {
 	struct hci_conn *hcon = smp->conn->hcon;
 	struct smp_cmd_dhkey_check check;
 	u8 a[7], b[7], *local_addr, *remote_addr;
 	u8 io_cap[3], r[16];
 
-	switch (mgmt_op) {
-	case MGMT_OP_USER_PASSKEY_NEG_REPLY:
-		smp_failure(smp->conn, SMP_PASSKEY_ENTRY_FAILED);
-		return 0;
-	case MGMT_OP_USER_CONFIRM_NEG_REPLY:
-		smp_failure(smp->conn, SMP_NUMERIC_COMP_FAILED);
-		return 0;
-	}
-
 	memcpy(a, &hcon->init_addr, 6);
 	memcpy(b, &hcon->resp_addr, 6);
 	a[6] = hcon->init_addr_type;
@@ -1229,13 +1220,29 @@ static int sc_user_reply(struct smp_chan *smp, u16 mgmt_op, __le32 passkey)
 		memcpy(io_cap, &smp->prsp[1], 3);
 	}
 
-	memcpy(r, &passkey, sizeof(passkey));
-	memset(r + sizeof(passkey), 0, sizeof(r) - sizeof(passkey));
+	memset(r, 0, sizeof(r));
+
+	if (smp->method == REQ_PASSKEY || smp->method == DSP_PASSKEY)
+		memcpy(r, &passkey, sizeof(passkey));
 
 	smp_f6(smp->tfm_cmac, smp->mackey, smp->prnd, smp->rrnd, r, io_cap,
 	       local_addr, remote_addr, check.e);
 
 	smp_send_cmd(smp->conn, SMP_CMD_DHKEY_CHECK, sizeof(check), &check);
+}
+
+static int sc_user_reply(struct smp_chan *smp, u16 mgmt_op, __le32 passkey)
+{
+	switch (mgmt_op) {
+	case MGMT_OP_USER_PASSKEY_NEG_REPLY:
+		smp_failure(smp->conn, SMP_PASSKEY_ENTRY_FAILED);
+		return 0;
+	case MGMT_OP_USER_CONFIRM_NEG_REPLY:
+		smp_failure(smp->conn, SMP_NUMERIC_COMP_FAILED);
+		return 0;
+	}
+
+	sc_dhkey_check(smp, passkey);
 
 	return 0;
 }
@@ -1599,6 +1606,14 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 	if (err)
 		return SMP_UNSPECIFIED;
 
+	if (smp->method == JUST_WORKS) {
+		if (hcon->out) {
+			sc_dhkey_check(smp, passkey);
+			SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
+		}
+		return 0;
+	}
+
 	err = mgmt_user_confirm_request(hcon->hdev, &hcon->dst,
 					hcon->type, hcon->dst_type,
 					passkey, 0);
Signature · 1 line
2.1.0
#29 lore raw

PATCH 29/49 Bluetooth: Fix BR/EDR Link Key type when derived through LE SC

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

We need to set the correct Link Key type based on the properties of the LE SC pairing that it was derived from. If debug keys were used the type should be a debug key, and the authenticated vs unauthenticated information should be set on what kind of security level was reached.

---
 net/bluetooth/hci_core.c |  4 ++++
 net/bluetooth/smp.c      | 27 ++++++++++++++++++++++++---
 2 files changed, 28 insertions(+), 3 deletions(-)
net/bluetooth/hci_core.c +4 -0
index 6c3220e9484f..2fa9f2b2bee3 100644
@@ -3160,6 +3160,10 @@ static bool hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
 	if (!conn)
 		return true;
 
+	/* BR/EDR key derived using SC from an LE link */
+	if (conn->type == LE_LINK)
+		return true;
+
 	/* Neither local nor remote side had no-bonding as requirement */
 	if (conn->auth_type > 0x01 && conn->remote_auth > 0x01)
 		return true;
net/bluetooth/smp.c +24 -3
index 7fdeca7edb7c..861d2cf3ccc9 100644
@@ -965,9 +965,30 @@ static void smp_notify_keys(struct l2cap_conn *conn)
 	}
 
 	if (smp->link_key) {
-		hci_add_link_key(hdev, smp->conn->hcon, &hcon->dst,
-				 smp->link_key, HCI_LK_AUTH_COMBINATION_P256,
-				 0, NULL);
+		struct link_key *key;
+		u8 type;
+
+		if (test_bit(SMP_FLAG_DEBUG_KEY, &smp->flags))
+			type = HCI_LK_DEBUG_COMBINATION;
+		else if (hcon->sec_level == BT_SECURITY_FIPS)
+			type = HCI_LK_AUTH_COMBINATION_P256;
+		else
+			type = HCI_LK_UNAUTH_COMBINATION_P256;
+
+		key = hci_add_link_key(hdev, smp->conn->hcon, &hcon->dst,
+				       smp->link_key, type, 0, &persistent);
+		if (key) {
+			mgmt_new_link_key(hdev, key, persistent);
+
+			/* Don't keep debug keys around if the relevant
+			 * flag is not set.
+			 */
+			if (!test_bit(HCI_KEEP_DEBUG_KEYS, &hdev->dev_flags) &&
+			    key->type == HCI_LK_DEBUG_COMBINATION) {
+				list_del_rcu(&key->list);
+				kfree_rcu(key, rcu);
+			}
+		}
 	}
 }
 
Signature · 1 line
2.1.0
#30 lore raw

PATCH 30/49 Bluetooth: Add passkey entry support for LE SC

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

The passkey entry mechanism involves either both sides requesting the user for a passkey, or one side requesting the passkey while the other one displays it. The behavior as far as SMP PDUs are concerned are considerably different from numeric comparison and therefore requires several new functions to handle it.

In essence passkey entry involves both sides gradually committing to each bit of the passkey which involves 20 rounds of pairing confirm and pairing random PDUS being sent in both directions.

This patch adds a new smp->passkey_round variable to track the current round of the passkey commitment and reuses the variables already present in struct hci_conn for the passkey and entered key count.

---
 net/bluetooth/smp.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 180 insertions(+), 11 deletions(-)
net/bluetooth/smp.c +180 -11
index 861d2cf3ccc9..7a9b491ffa1a 100644
@@ -55,6 +55,7 @@ enum {
 	SMP_FLAG_SC,
 	SMP_FLAG_REMOTE_PK,
 	SMP_FLAG_DEBUG_KEY,
+	SMP_FLAG_WAIT_USER,
 };
 
 struct smp_chan {
@@ -81,6 +82,7 @@ struct smp_chan {
 	u8		*link_key;
 	unsigned long	flags;
 	u8		method;
+	u8		passkey_round;
 
 	/* Secure Connections variables */
 	u8			local_pk[64];
@@ -1219,7 +1221,7 @@ static int sc_mackey_and_ltk(struct smp_chan *smp, u8 mackey[16], u8 ltk[16])
 	return smp_f5(smp->tfm_cmac, smp->dhkey, na, nb, a, b, mackey, ltk);
 }
 
-static void sc_dhkey_check(struct smp_chan *smp, __le32 passkey)
+static void sc_dhkey_check(struct smp_chan *smp)
 {
 	struct hci_conn *hcon = smp->conn->hcon;
 	struct smp_cmd_dhkey_check check;
@@ -1244,7 +1246,7 @@ static void sc_dhkey_check(struct smp_chan *smp, __le32 passkey)
 	memset(r, 0, sizeof(r));
 
 	if (smp->method == REQ_PASSKEY || smp->method == DSP_PASSKEY)
-		memcpy(r, &passkey, sizeof(passkey));
+		put_unaligned_le32(hcon->passkey_notify, r);
 
 	smp_f6(smp->tfm_cmac, smp->mackey, smp->prnd, smp->rrnd, r, io_cap,
 	       local_addr, remote_addr, check.e);
@@ -1252,8 +1254,124 @@ static void sc_dhkey_check(struct smp_chan *smp, __le32 passkey)
 	smp_send_cmd(smp->conn, SMP_CMD_DHKEY_CHECK, sizeof(check), &check);
 }
 
+static u8 sc_passkey_send_confirm(struct smp_chan *smp)
+{
+	struct l2cap_conn *conn = smp->conn;
+	struct hci_conn *hcon = conn->hcon;
+	struct smp_cmd_pairing_confirm cfm;
+	u8 r;
+
+	r = ((hcon->passkey_notify >> smp->passkey_round) & 0x01);
+	r |= 0x80;
+
+	get_random_bytes(smp->prnd, sizeof(smp->prnd));
+
+	if (smp_f4(smp->tfm_cmac, smp->local_pk, smp->remote_pk, smp->prnd, r,
+		   cfm.confirm_val))
+		return SMP_UNSPECIFIED;
+
+	smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cfm), &cfm);
+
+	return 0;
+}
+
+static u8 sc_passkey_round(struct smp_chan *smp, u8 smp_op)
+{
+	struct l2cap_conn *conn = smp->conn;
+	struct hci_conn *hcon = conn->hcon;
+	struct hci_dev *hdev = hcon->hdev;
+	u8 cfm[16], r;
+
+	/* Ignore the PDU if we've already done 20 rounds (0 - 19) */
+	if (smp->passkey_round >= 20)
+		return 0;
+
+	switch (smp_op) {
+	case SMP_CMD_PAIRING_RANDOM:
+		r = ((hcon->passkey_notify >> smp->passkey_round) & 0x01);
+		r |= 0x80;
+
+		if (smp_f4(smp->tfm_cmac, smp->remote_pk, smp->local_pk,
+			   smp->rrnd, r, cfm))
+			return SMP_UNSPECIFIED;
+
+		if (memcmp(smp->pcnf, cfm, 16))
+			return SMP_CONFIRM_FAILED;
+
+		smp->passkey_round++;
+
+		if (smp->passkey_round == 20) {
+			/* Generate MacKey and LTK */
+			if (sc_mackey_and_ltk(smp, smp->mackey, smp->tk))
+				return SMP_UNSPECIFIED;
+		}
+
+		/* The round is only complete when the initiator
+		 * receives pairing random.
+		 */
+		if (!hcon->out) {
+			smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM,
+				     sizeof(smp->prnd), smp->prnd);
+			if (smp->passkey_round == 20) {
+				sc_dhkey_check(smp);
+				SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
+			} else {
+				SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
+			}
+			return 0;
+		}
+
+		/* Start the next round */
+		if (smp->passkey_round != 20)
+			return sc_passkey_round(smp, 0);
+
+		/* Passkey rounds are complete - start DHKey Check */
+		sc_dhkey_check(smp);
+		SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
+
+		break;
+
+	case SMP_CMD_PAIRING_CONFIRM:
+		if (test_bit(SMP_FLAG_WAIT_USER, &smp->flags)) {
+			set_bit(SMP_FLAG_CFM_PENDING, &smp->flags);
+			return 0;
+		}
+
+		SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM);
+
+		if (hcon->out) {
+			smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM,
+				     sizeof(smp->prnd), smp->prnd);
+			return 0;
+		}
+
+		return sc_passkey_send_confirm(smp);
+
+	case SMP_CMD_PUBLIC_KEY:
+	default:
+		/* Initiating device starts the round */
+		if (!hcon->out)
+			return 0;
+
+		BT_DBG("%s Starting passkey round %u", hdev->name,
+		       smp->passkey_round + 1);
+
+		SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
+
+		return sc_passkey_send_confirm(smp);
+	}
+
+	return 0;
+}
+
 static int sc_user_reply(struct smp_chan *smp, u16 mgmt_op, __le32 passkey)
 {
+	struct l2cap_conn *conn = smp->conn;
+	struct hci_conn *hcon = conn->hcon;
+	u8 smp_op;
+
+	clear_bit(SMP_FLAG_WAIT_USER, &smp->flags);
+
 	switch (mgmt_op) {
 	case MGMT_OP_USER_PASSKEY_NEG_REPLY:
 		smp_failure(smp->conn, SMP_PASSKEY_ENTRY_FAILED);
@@ -1261,9 +1379,22 @@ static int sc_user_reply(struct smp_chan *smp, u16 mgmt_op, __le32 passkey)
 	case MGMT_OP_USER_CONFIRM_NEG_REPLY:
 		smp_failure(smp->conn, SMP_NUMERIC_COMP_FAILED);
 		return 0;
+	case MGMT_OP_USER_PASSKEY_REPLY:
+		hcon->passkey_notify = le32_to_cpu(passkey);
+		smp->passkey_round = 0;
+
+		if (test_and_clear_bit(SMP_FLAG_CFM_PENDING, &smp->flags))
+			smp_op = SMP_CMD_PAIRING_CONFIRM;
+		else
+			smp_op = 0;
+
+		if (sc_passkey_round(smp, smp_op))
+			return -EIO;
+
+		return 0;
 	}
 
-	sc_dhkey_check(smp, passkey);
+	sc_dhkey_check(smp);
 
 	return 0;
 }
@@ -1532,6 +1663,9 @@ static u8 sc_check_confirm(struct smp_chan *smp)
 	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);
+
 	if (conn->hcon->out) {
 		smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
 			     smp->prnd);
@@ -1592,6 +1726,10 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 	if (!test_bit(SMP_FLAG_SC, &smp->flags))
 		return smp_random(smp);
 
+	/* Passkey entry has special treatment */
+	if (smp->method == REQ_PASSKEY || smp->method == DSP_PASSKEY)
+		return sc_passkey_round(smp, SMP_CMD_PAIRING_RANDOM);
+
 	if (hcon->out) {
 		u8 cfm[16];
 
@@ -1623,24 +1761,25 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 	if (err)
 		return SMP_UNSPECIFIED;
 
-	err = smp_g2(smp->tfm_cmac, pkax, pkbx, na, nb, &passkey);
-	if (err)
-		return SMP_UNSPECIFIED;
-
 	if (smp->method == JUST_WORKS) {
 		if (hcon->out) {
-			sc_dhkey_check(smp, passkey);
+			sc_dhkey_check(smp);
 			SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
 		}
 		return 0;
 	}
 
-	err = mgmt_user_confirm_request(hcon->hdev, &hcon->dst,
-					hcon->type, hcon->dst_type,
-					passkey, 0);
+	err = smp_g2(smp->tfm_cmac, pkax, pkbx, na, nb, &passkey);
+	if (err)
+		return SMP_UNSPECIFIED;
+
+	err = mgmt_user_confirm_request(hcon->hdev, &hcon->dst, hcon->type,
+					hcon->dst_type, passkey, 0);
 	if (err)
 		return SMP_UNSPECIFIED;
 
+	set_bit(SMP_FLAG_WAIT_USER, &smp->flags);
+
 	return 0;
 }
 
@@ -2071,6 +2210,33 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
 	if (!memcmp(debug_pk, smp->remote_pk, 64))
 		set_bit(SMP_FLAG_DEBUG_KEY, &smp->flags);
 
+	if (smp->method == DSP_PASSKEY) {
+		get_random_bytes(&hcon->passkey_notify,
+				 sizeof(hcon->passkey_notify));
+		hcon->passkey_notify %= 1000000;
+		hcon->passkey_entered = 0;
+		smp->passkey_round = 0;
+		if (mgmt_user_passkey_notify(hdev, &hcon->dst, hcon->type,
+					     hcon->dst_type,
+					     hcon->passkey_notify,
+					     hcon->passkey_entered))
+			return SMP_UNSPECIFIED;
+		SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
+		return sc_passkey_round(smp, SMP_CMD_PUBLIC_KEY);
+	}
+
+	if (hcon->out)
+		SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
+
+	if (smp->method == REQ_PASSKEY) {
+		if (mgmt_user_passkey_request(hdev, &hcon->dst, hcon->type,
+					      hcon->dst_type))
+			return SMP_UNSPECIFIED;
+		SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
+		set_bit(SMP_FLAG_WAIT_USER, &smp->flags);
+		return 0;
+	}
+
 	/* The Initiating device waits for the non-initiating device to
 	 * send the confirm value.
 	 */
@@ -2121,6 +2287,9 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	memset(r, 0, sizeof(r));
 
+	if (smp->method == REQ_PASSKEY || smp->method == DSP_PASSKEY)
+		put_unaligned_le32(hcon->passkey_notify, r);
+
 	err = smp_f6(smp->tfm_cmac, smp->mackey, smp->rrnd, smp->prnd, r,
 		     io_cap, remote_addr, local_addr, e);
 	if (err)
Signature · 1 line
2.1.0
#31 lore raw

PATCH 31/49 Bluetooth: Fix DHKey Check sending order for slave role

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

According to the LE SC specification the initiating device sends its DHKey check first and the non-initiating devices sends its DHKey check as a response to this. It's also important that the non-initiating device doesn't send the response if it's still waiting for user input. In order to synchronize all this a new flag is added.

---
 net/bluetooth/smp.c | 60 ++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 43 insertions(+), 17 deletions(-)
net/bluetooth/smp.c +43 -17
index 7a9b491ffa1a..458d07d5603b 100644
@@ -56,6 +56,7 @@ enum {
 	SMP_FLAG_REMOTE_PK,
 	SMP_FLAG_DEBUG_KEY,
 	SMP_FLAG_WAIT_USER,
+	SMP_FLAG_DHKEY_PENDING,
 };
 
 struct smp_chan {
@@ -994,6 +995,29 @@ static void smp_notify_keys(struct l2cap_conn *conn)
 	}
 }
 
+static void sc_add_ltk(struct smp_chan *smp)
+{
+	struct hci_conn *hcon = smp->conn->hcon;
+	u8 key_type, auth;
+
+	if (test_bit(SMP_FLAG_DEBUG_KEY, &smp->flags))
+		key_type = SMP_LTK_P256_DEBUG;
+	else
+		key_type = SMP_LTK_P256;
+
+	if (hcon->pending_sec_level == BT_SECURITY_FIPS)
+		auth = 1;
+	else
+		auth = 0;
+
+	memset(smp->tk + smp->enc_key_size, 0,
+	       SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
+
+	smp->ltk = hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type,
+			       key_type, auth, smp->tk, smp->enc_key_size,
+			       0, 0);
+}
+
 static void sc_generate_link_key(struct smp_chan *smp)
 {
 	/* These constants are as specified in the core specification.
@@ -1312,12 +1336,10 @@ static u8 sc_passkey_round(struct smp_chan *smp, u8 smp_op)
 		if (!hcon->out) {
 			smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM,
 				     sizeof(smp->prnd), smp->prnd);
-			if (smp->passkey_round == 20) {
-				sc_dhkey_check(smp);
+			if (smp->passkey_round == 20)
 				SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
-			} else {
+			else
 				SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
-			}
 			return 0;
 		}
 
@@ -1394,7 +1416,14 @@ static int sc_user_reply(struct smp_chan *smp, u16 mgmt_op, __le32 passkey)
 		return 0;
 	}
 
-	sc_dhkey_check(smp);
+	/* Initiator sends DHKey check first */
+	if (hcon->out) {
+		sc_dhkey_check(smp);
+		SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
+	} else if (test_and_clear_bit(SMP_FLAG_DHKEY_PENDING, &smp->flags)) {
+		sc_dhkey_check(smp);
+		sc_add_ltk(smp);
+	}
 
 	return 0;
 }
@@ -2262,7 +2291,6 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)
 	struct smp_chan *smp = chan->data;
 	u8 a[7], b[7], *local_addr, *remote_addr;
 	u8 io_cap[3], r[16], e[16];
-	u8 key_type, auth;
 	int err;
 
 	BT_DBG("conn %p", conn);
@@ -2298,19 +2326,17 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)
 	if (memcmp(check->e, e, 16))
 		return SMP_DHKEY_CHECK_FAILED;
 
-	if (test_bit(SMP_FLAG_DEBUG_KEY, &smp->flags))
-		key_type = SMP_LTK_P256_DEBUG;
-	else
-		key_type = SMP_LTK_P256;
+	if (!hcon->out) {
+		if (test_bit(SMP_FLAG_WAIT_USER, &smp->flags)) {
+			set_bit(SMP_FLAG_DHKEY_PENDING, &smp->flags);
+			return 0;
+		}
 
-	if (hcon->pending_sec_level == BT_SECURITY_FIPS)
-		auth = 1;
-	else
-		auth = 0;
+		/* Slave sends DHKey check as response to master */
+		sc_dhkey_check(smp);
+	}
 
-	smp->ltk = hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type,
-			       key_type, auth, smp->tk, smp->enc_key_size,
-			       0, 0);
+	sc_add_ltk(smp);
 
 	if (hcon->out) {
 		hci_le_start_enc(hcon, 0, 0, smp->tk);
Signature · 1 line
2.1.0
#32 lore raw

PATCH 32/49 Bluetooth: Add dummy handler for LE SC keypress notification

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

Since we don not actively try to clear the keypress notification bit we might get these PDUs. To avoid failing the pairing process add a simple dummy handler for these for now.

---
 net/bluetooth/smp.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
net/bluetooth/smp.c +14 -0
index 458d07d5603b..16bd15e04b85 100644
@@ -2346,6 +2346,16 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)
 	return 0;
 }
 
+static int smp_cmd_keypress_notify(struct l2cap_conn *conn,
+				   struct sk_buff *skb)
+{
+	struct smp_cmd_keypress_notify *kp = (void *) skb->data;
+
+	BT_DBG("value 0x%02x", kp->value);
+
+	return 0;
+}
+
 static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb)
 {
 	struct l2cap_conn *conn = chan->conn;
@@ -2438,6 +2448,10 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb)
 		reason = smp_cmd_dhkey_check(conn, skb);
 		break;
 
+	case SMP_CMD_KEYPRESS_NOTIFY:
+		reason = smp_cmd_keypress_notify(conn, skb);
+		break;
+
 	default:
 		BT_DBG("Unknown command code 0x%2.2x", code);
 		reason = SMP_CMD_NOTSUPP;
Signature · 1 line
2.1.0
#33 lore raw

PATCH 33/49 Bluetooth: Use debug keys for SMP when HCI_USE_DEBUG_KEYS is set

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

The HCI_USE_DEBUG_KEYS flag is intended to force our side to always use debug keys for pairing. This means both BR/EDR SSP as well as SMP with LE Secure Connections. This patch updates the SMP code to use the debug keys instead of generating a random local key pair when the flag is set.

---
 net/bluetooth/smp.c | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)
net/bluetooth/smp.c +18 -9
index 16bd15e04b85..3aad5864a5e1 100644
@@ -1585,18 +1585,27 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 
 static u8 sc_send_public_key(struct smp_chan *smp)
 {
+	struct hci_dev *hdev = smp->conn->hcon->hdev;
+
 	BT_DBG("");
 
-	while (true) {
-		/* Generate local key pair for Secure Connections */
-		if (!ecc_make_key(smp->local_pk, smp->local_sk))
-			return SMP_UNSPECIFIED;
+	if (test_bit(HCI_USE_DEBUG_KEYS, &hdev->dev_flags)) {
+		BT_DBG("Using debug keys");
+		memcpy(smp->local_pk, debug_pk, 64);
+		memcpy(smp->local_sk, debug_sk, 32);
+		set_bit(SMP_FLAG_DEBUG_KEY, &smp->flags);
+	} else {
+		while (true) {
+			/* Generate local key pair for Secure Connections */
+			if (!ecc_make_key(smp->local_pk, smp->local_sk))
+				return SMP_UNSPECIFIED;
 
-		/* This is unlikely, but we need to check that we didn't
-		 * accidentially generate a debug key.
-		 */
-		if (memcmp(smp->local_sk, debug_sk, 32))
-			break;
+			/* This is unlikely, but we need to check that
+			 * we didn't accidentially generate a debug key.
+			 */
+			if (memcmp(smp->local_sk, debug_sk, 32))
+				break;
+		}
 	}
 
 	BT_DBG("Local Public Key X: %32phN", smp->local_pk);
Signature · 1 line
2.1.0
#34 lore raw

PATCH 34/49 Bluetooth: Add hci_conn flag for new link key generation

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

For LE Secure Connections we want to trigger cross transport key generation only if a new link key was actually created during the BR/EDR connection. This patch adds a new flag to track this information.

---
 include/net/bluetooth/hci_core.h | 1 +
 net/bluetooth/hci_event.c        | 3 +++
 2 files changed, 4 insertions(+)
include/net/bluetooth/hci_core.h +1 -0
index 90929641d0f0..42f9362a83c1 100644
@@ -559,6 +559,7 @@ enum {
 	HCI_CONN_AUTH_INITIATOR,
 	HCI_CONN_DROP,
 	HCI_CONN_PARAM_REMOVAL_PEND,
+	HCI_CONN_NEW_LINK_KEY,
 };
 
 static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
net/bluetooth/hci_event.c +3 -0
index 34ecbf0b7e5b..c3d6390e3b7b 100644
@@ -3249,6 +3249,8 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
 	if (conn) {
+		clear_bit(HCI_CONN_NEW_LINK_KEY, &conn->flags);
+
 		if ((key->type == HCI_LK_UNAUTH_COMBINATION_P192 ||
 		     key->type == HCI_LK_UNAUTH_COMBINATION_P256) &&
 		    conn->auth_type != 0xff && (conn->auth_type & 0x01)) {
@@ -3301,6 +3303,7 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
 	conn->disc_timeout = HCI_DISCONN_TIMEOUT;
 	hci_conn_drop(conn);
 
+	set_bit(HCI_CONN_NEW_LINK_KEY, &conn->flags);
 	conn_set_key(conn, ev->key_type, conn->pin_length);
 
 	if (!test_bit(HCI_MGMT, &hdev->dev_flags))
Signature · 1 line
2.1.0
#35 lore raw

PATCH 35/49 Bluetooth: Add debugfs switch for forcing SMP over BR/EDR

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

To make it possible to use LE SC functionality over BR/EDR with pre-4.1 controllers (that do not support BR/EDR SC links) it's useful to be able to force LE SC operations even over a traditional SSP protected link. This patch adds a debugfs switch to force a special debug flag which is used to skip the checks for BR/EDR SC support.

---
 include/net/bluetooth/hci.h |  1 +
 net/bluetooth/hci_core.c    | 47 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+)
include/net/bluetooth/hci.h +1 -0
index e56f9099f8e3..569c077778b6 100644
@@ -163,6 +163,7 @@ enum {
 enum {
 	HCI_DUT_MODE,
 	HCI_FORCE_SC,
+	HCI_FORCE_LESC,
 	HCI_FORCE_STATIC_ADDR,
 };
 
net/bluetooth/hci_core.c +47 -0

59 lines not on this page · raw message

Signature · 1 line
2.1.0
#36 lore raw

PATCH 36/49 Bluetooth: Add skeleton for BR/EDR SMP channel

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

This patch adds the very basic code for creating and destroying SMP L2CAP channels for BR/EDR connections.

---
 include/net/bluetooth/hci_core.h |  1 +
 include/net/bluetooth/l2cap.h    |  2 +
 net/bluetooth/smp.c              | 89 ++++++++++++++++++++++++++++++++--------
 3 files changed, 74 insertions(+), 18 deletions(-)
include/net/bluetooth/hci_core.h +1 -0
index 42f9362a83c1..f39e65096b1f 100644
@@ -306,6 +306,7 @@ struct hci_dev {
 	__u32			req_result;
 
 	void			*smp_data;
+	void			*smp_bredr_data;
 
 	struct discovery_state	discovery;
 	struct hci_conn_hash	conn_hash;
include/net/bluetooth/l2cap.h +2 -0
index d71dc3579354..eee3ef530e79 100644
@@ -141,6 +141,7 @@ struct l2cap_conninfo {
 #define L2CAP_FC_ATT		0x10
 #define L2CAP_FC_SIG_LE		0x20
 #define L2CAP_FC_SMP_LE		0x40
+#define L2CAP_FC_SMP_BREDR	0x80
 
 /* L2CAP Control Field bit masks */
 #define L2CAP_CTRL_SAR			0xC000
@@ -255,6 +256,7 @@ struct l2cap_conn_rsp {
 #define L2CAP_CID_ATT		0x0004
 #define L2CAP_CID_LE_SIGNALING	0x0005
 #define L2CAP_CID_SMP		0x0006
+#define L2CAP_CID_SMP_BREDR	0x0007
 #define L2CAP_CID_DYN_START	0x0040
 #define L2CAP_CID_DYN_END	0xffff
 #define L2CAP_CID_LE_DYN_END	0x007f
net/bluetooth/smp.c +71 -18

147 lines not on this page · raw message

Signature · 1 line
2.1.0
#37 lore raw

PATCH 37/49 Bluetooth: Add full SMP BR/EDR support

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

When doing SMP over BR/EDR some of the routines can be shared with the LE functionality whereas others needs to be split into their own BR/EDR specific branches. This patch implements the split of BR/EDR specific SMP code from the LE-only code, making sure SMP over BR/EDR works as specified.

---
 net/bluetooth/l2cap_core.c |   4 +
 net/bluetooth/smp.c        | 230 ++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 212 insertions(+), 22 deletions(-)
net/bluetooth/l2cap_core.c +4 -0
index 43349ed4c249..a8da7ea9c2c0 100644
@@ -6967,6 +6967,10 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
 	    test_bit(HCI_HS_ENABLED, &hcon->hdev->dev_flags))
 		conn->local_fixed_chan |= L2CAP_FC_A2MP;
 
+	if (bredr_sc_enabled(hcon->hdev) &&
+	    test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags))
+		conn->local_fixed_chan |= L2CAP_FC_SMP_BREDR;
+
 	mutex_init(&conn->ident_lock);
 	mutex_init(&conn->chan_lock);
 
net/bluetooth/smp.c +208 -22

318 lines not on this page · raw message

Signature · 1 line
2.1.0
#38 lore raw

PATCH 38/49 Bluetooth: Add SC-only mode support for SMP

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

When Secure Connections-only mode is enabled we should reject any pairing command that does not have Secure Connections set in the authentication requirements. This patch adds the appropriate logic for this to the command handlers of Pairing Request/Response and Security Request.

---
 net/bluetooth/smp.c | 9 +++++++++
 1 file changed, 9 insertions(+)
net/bluetooth/smp.c +9 -0
index 12294935d258..3a4579b3ab06 100644
@@ -1608,6 +1608,9 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 	    (auth & SMP_AUTH_BONDING))
 		return SMP_PAIRING_NOTSUPP;
 
+	if (test_bit(HCI_SC_ONLY, &hdev->dev_flags) && !(auth & SMP_AUTH_SC))
+		return SMP_AUTH_REQUIREMENTS;
+
 	smp->preq[0] = SMP_CMD_PAIRING_REQ;
 	memcpy(&smp->preq[1], req, sizeof(*req));
 	skb_pull(skb, sizeof(*req));
@@ -1752,6 +1755,9 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	auth = rsp->auth_req & AUTH_REQ_MASK(hdev);
 
+	if (test_bit(HCI_SC_ONLY, &hdev->dev_flags) && !(auth & SMP_AUTH_SC))
+		return SMP_AUTH_REQUIREMENTS;
+
 	smp->prsp[0] = SMP_CMD_PAIRING_RSP;
 	memcpy(&smp->prsp[1], rsp, sizeof(*rsp));
 
@@ -2008,6 +2014,9 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	auth = rp->auth_req & AUTH_REQ_MASK(hdev);
 
+	if (test_bit(HCI_SC_ONLY, &hdev->dev_flags) && !(auth & SMP_AUTH_SC))
+		return SMP_AUTH_REQUIREMENTS;
+
 	if (hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT)
 		sec_level = BT_SECURITY_MEDIUM;
 	else
Signature · 1 line
2.1.0
#39 lore raw

PATCH 39/49 Bluetooth: Unify remote OOB data functions

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

There's no need to duplicate code for the 192 vs 192+256 variants of the OOB data functions. This is also helpful to pave the way to support LE SC OOB data where only 256 bit data is provided.

---
 include/net/bluetooth/hci_core.h |  6 ++----
 net/bluetooth/hci_core.c         | 46 +++++++++++++---------------------------
 net/bluetooth/mgmt.c             |  9 ++++----
 3 files changed, 22 insertions(+), 39 deletions(-)
include/net/bluetooth/hci_core.h +2 -4
index f39e65096b1f..3e89ece75039 100644
@@ -944,10 +944,8 @@ void hci_remote_oob_data_clear(struct hci_dev *hdev);
 struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
 					  bdaddr_t *bdaddr);
 int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
-			    u8 *hash, u8 *rand);
-int hci_add_remote_oob_ext_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
-				u8 *hash192, u8 *rand192,
-				u8 *hash256, u8 *rand256);
+			    u8 *hash192, u8 *rand192,
+			    u8 *hash256, u8 *rand256);
 int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr);
 
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
net/bluetooth/hci_core.c +15 -31

60 lines not on this page · raw message

net/bluetooth/mgmt.c +5 -4
index 6e8165364b7f..0d92ba99ca93 100644
@@ -3599,7 +3599,8 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
 		}
 
 		err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
-					      cp->hash, cp->rand);
+					      cp->hash, cp->rand,
+					      NULL, NULL);
 		if (err < 0)
 			status = MGMT_STATUS_FAILED;
 		else
@@ -3619,9 +3620,9 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
 			goto unlock;
 		}
 
-		err = hci_add_remote_oob_ext_data(hdev, &cp->addr.bdaddr,
-						  cp->hash192, cp->rand192,
-						  cp->hash256, cp->rand256);
+		err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
+					      cp->hash192, cp->rand192,
+					      cp->hash256, cp->rand256);
 		if (err < 0)
 			status = MGMT_STATUS_FAILED;
 		else
Signature · 1 line
2.1.0
#40 lore raw

PATCH 40/49 Bluetooth: Store address type with OOB data

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

To be able to support OOB data for LE pairing we need to store the address type of the remote device. This patch extends the relevant functions and data types with a bdaddr_type variable.

---
 include/net/bluetooth/hci_core.h |  8 +++++---
 net/bluetooth/hci_core.c         | 26 ++++++++++++++++----------
 net/bluetooth/hci_event.c        |  4 ++--
 net/bluetooth/mgmt.c             | 11 ++++++-----
 4 files changed, 29 insertions(+), 20 deletions(-)
include/net/bluetooth/hci_core.h +5 -3
index 3e89ece75039..1dae7001fc31 100644
@@ -140,6 +140,7 @@ struct link_key {
 struct oob_data {
 	struct list_head list;
 	bdaddr_t bdaddr;
+	u8 bdaddr_type;
 	u8 hash192[16];
 	u8 rand192[16];
 	u8 hash256[16];
@@ -942,11 +943,12 @@ void hci_smp_irks_clear(struct hci_dev *hdev);
 
 void hci_remote_oob_data_clear(struct hci_dev *hdev);
 struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
-					  bdaddr_t *bdaddr);
+					  bdaddr_t *bdaddr, u8 bdaddr_type);
 int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
-			    u8 *hash192, u8 *rand192,
+			    u8 bdaddr_type, u8 *hash192, u8 *rand192,
 			    u8 *hash256, u8 *rand256);
-int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr);
+int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
+			       u8 bdaddr_type);
 
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
 
net/bluetooth/hci_core.c +16 -10
index 967fbfe80f1f..c8123f04a33c 100644
@@ -2160,7 +2160,7 @@ u32 hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
 
 	BT_DBG("cache %p, %pMR", cache, &data->bdaddr);
 
-	hci_remove_remote_oob_data(hdev, &data->bdaddr);
+	hci_remove_remote_oob_data(hdev, &data->bdaddr, BDADDR_BREDR);
 
 	if (!data->ssp_mode)
 		flags |= MGMT_DEV_FOUND_LEGACY_PAIRING;
@@ -3479,26 +3479,31 @@ static void hci_cmd_timeout(struct work_struct *work)
 }
 
 struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
-					  bdaddr_t *bdaddr)
+					  bdaddr_t *bdaddr, u8 bdaddr_type)
 {
 	struct oob_data *data;
 
-	list_for_each_entry(data, &hdev->remote_oob_data, list)
-		if (bacmp(bdaddr, &data->bdaddr) == 0)
-			return data;
+	list_for_each_entry(data, &hdev->remote_oob_data, list) {
+		if (bacmp(bdaddr, &data->bdaddr) != 0)
+			continue;
+		if (data->bdaddr_type != bdaddr_type)
+			continue;
+		return data;
+	}
 
 	return NULL;
 }
 
-int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr)
+int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
+			       u8 bdaddr_type)
 {
 	struct oob_data *data;
 
-	data = hci_find_remote_oob_data(hdev, bdaddr);
+	data = hci_find_remote_oob_data(hdev, bdaddr, bdaddr_type);
 	if (!data)
 		return -ENOENT;
 
-	BT_DBG("%s removing %pMR", hdev->name, bdaddr);
+	BT_DBG("%s removing %pMR (%u)", hdev->name, bdaddr, bdaddr_type);
 
 	list_del(&data->list);
 	kfree(data);
@@ -3517,18 +3522,19 @@ void hci_remote_oob_data_clear(struct hci_dev *hdev)
 }
 
 int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
-			    u8 *hash192, u8 *rand192,
+			    u8 bdaddr_type, u8 *hash192, u8 *rand192,
 			    u8 *hash256, u8 *rand256)
 {
 	struct oob_data *data;
 
-	data = hci_find_remote_oob_data(hdev, bdaddr);
+	data = hci_find_remote_oob_data(hdev, bdaddr, bdaddr_type);
 	if (!data) {
 		data = kmalloc(sizeof(*data), GFP_KERNEL);
 		if (!data)
 			return -ENOMEM;
 
 		bacpy(&data->bdaddr, bdaddr);
+		data->bdaddr_type = bdaddr_type;
 		list_add(&data->list, &hdev->remote_oob_data);
 	}
 
net/bluetooth/hci_event.c +2 -2
index c3d6390e3b7b..f4e2a61bb6aa 100644
@@ -3773,7 +3773,7 @@ static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
 		cp.authentication = conn->auth_type;
 
-		if (hci_find_remote_oob_data(hdev, &conn->dst) &&
+		if (hci_find_remote_oob_data(hdev, &conn->dst, BDADDR_BREDR) &&
 		    (conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags)))
 			cp.oob_data = 0x01;
 		else
@@ -4028,7 +4028,7 @@ static void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
 	if (!test_bit(HCI_MGMT, &hdev->dev_flags))
 		goto unlock;
 
-	data = hci_find_remote_oob_data(hdev, &ev->bdaddr);
+	data = hci_find_remote_oob_data(hdev, &ev->bdaddr, BDADDR_BREDR);
 	if (data) {
 		if (bredr_sc_enabled(hdev)) {
 			struct hci_cp_remote_oob_ext_data_reply cp;
net/bluetooth/mgmt.c +6 -5
index 0d92ba99ca93..57de9f7222aa 100644
@@ -3599,8 +3599,8 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
 		}
 
 		err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
-					      cp->hash, cp->rand,
-					      NULL, NULL);
+					      cp->addr.type, cp->hash,
+					      cp->rand, NULL, NULL);
 		if (err < 0)
 			status = MGMT_STATUS_FAILED;
 		else
@@ -3621,8 +3621,9 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
 		}
 
 		err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
-					      cp->hash192, cp->rand192,
-					      cp->hash256, cp->rand256);
+					      cp->addr.type, cp->hash192,
+					      cp->rand192, cp->hash256,
+					      cp->rand256);
 		if (err < 0)
 			status = MGMT_STATUS_FAILED;
 		else
@@ -3663,7 +3664,7 @@ static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
 		goto done;
 	}
 
-	err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
+	err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
 	if (err < 0)
 		status = MGMT_STATUS_INVALID_PARAMS;
 	else
Signature · 1 line
2.1.0
#41 lore raw

PATCH 41/49 Bluetooth: Add support for adding remote OOB data for LE

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

This patch adds proper support for passing LE OOB data to the hci_add_remote_oob_data() function. For LE the 192-bit values are not valid and should therefore be passed as NULL values.

---
 net/bluetooth/mgmt.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)
net/bluetooth/mgmt.c +11 -3
index 57de9f7222aa..1e73bead7dd9 100644
@@ -3610,6 +3610,7 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
 				   status, &cp->addr, sizeof(cp->addr));
 	} else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
 		struct mgmt_cp_add_remote_oob_ext_data *cp = data;
+		u8 *rand192, *hash192;
 		u8 status;
 
 		if (cp->addr.type != BDADDR_BREDR) {
@@ -3620,10 +3621,17 @@ static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
 			goto unlock;
 		}
 
+		if (bdaddr_type_is_le(cp->addr.type)) {
+			rand192 = NULL;
+			hash192 = NULL;
+		} else {
+			rand192 = cp->rand192;
+			hash192 = cp->hash192;
+		}
+
 		err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
-					      cp->addr.type, cp->hash192,
-					      cp->rand192, cp->hash256,
-					      cp->rand256);
+					      cp->addr.type, hash192, rand192,
+					      cp->hash256, cp->rand256);
 		if (err < 0)
 			status = MGMT_STATUS_FAILED;
 		else
Signature · 1 line
2.1.0
#42 lore raw

PATCH 42/49 Bluetooth: Set SMP OOB flag if OOB data is available

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

If we have OOB data available for the remote device in question we should set the OOB flag appropriately in the SMP pairing request or response.

---
 net/bluetooth/smp.c | 31 +++++++++++++++++++++++++------
 1 file changed, 25 insertions(+), 6 deletions(-)
net/bluetooth/smp.c +25 -6
index 3a4579b3ab06..a38541d079f5 100644
@@ -57,6 +57,7 @@ enum {
 	SMP_FLAG_DEBUG_KEY,
 	SMP_FLAG_WAIT_USER,
 	SMP_FLAG_DHKEY_PENDING,
+	SMP_FLAG_OOB,
 };
 
 struct smp_chan {
@@ -562,7 +563,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
 	struct smp_chan *smp = chan->data;
 	struct hci_conn *hcon = conn->hcon;
 	struct hci_dev *hdev = hcon->hdev;
-	u8 local_dist = 0, remote_dist = 0;
+	u8 local_dist = 0, remote_dist = 0, oob_flag = SMP_OOB_NOT_PRESENT;
 
 	if (test_bit(HCI_BONDABLE, &conn->hcon->hdev->dev_flags)) {
 		local_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN;
@@ -578,19 +579,37 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
 	if (test_bit(HCI_PRIVACY, &hdev->dev_flags))
 		local_dist |= SMP_DIST_ID_KEY;
 
-	if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) {
-		if ((authreq & SMP_AUTH_SC) &&
-		    test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
+	if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
+	    (authreq & SMP_AUTH_SC)) {
+		struct oob_data *oob_data;
+		u8 bdaddr_type;
+
+		if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
 			local_dist |= SMP_DIST_LINK_KEY;
 			remote_dist |= SMP_DIST_LINK_KEY;
 		}
+
+		if (hcon->dst_type == ADDR_LE_DEV_PUBLIC)
+			bdaddr_type = BDADDR_LE_PUBLIC;
+		else
+			bdaddr_type = BDADDR_LE_RANDOM;
+
+		oob_data = hci_find_remote_oob_data(hdev, &hcon->dst,
+						    bdaddr_type);
+		if (oob_data) {
+			set_bit(SMP_FLAG_OOB, &smp->flags);
+			oob_flag = SMP_OOB_PRESENT;
+			memcpy(smp->rrnd, oob_data->rand256, 16);
+			memcpy(smp->pcnf, oob_data->hash256, 16);
+		}
+
 	} else {
 		authreq &= ~SMP_AUTH_SC;
 	}
 
 	if (rsp == NULL) {
 		req->io_capability = conn->hcon->io_capability;
-		req->oob_flag = SMP_OOB_NOT_PRESENT;
+		req->oob_flag = oob_flag;
 		req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
 		req->init_key_dist = local_dist;
 		req->resp_key_dist = remote_dist;
@@ -601,7 +620,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
 	}
 
 	rsp->io_capability = conn->hcon->io_capability;
-	rsp->oob_flag = SMP_OOB_NOT_PRESENT;
+	rsp->oob_flag = oob_flag;
 	rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
 	rsp->init_key_dist = req->init_key_dist & remote_dist;
 	rsp->resp_key_dist = req->resp_key_dist & local_dist;
Signature · 1 line
2.1.0
#43 lore raw

PATCH 43/49 Bluetooth: Add basic LE SC OOB support for remote OOB data

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

This patch adds basic OOB pairing support when we've received the remote OOB data. This includes tracking the remote r value (in smp->rr) as well as doing the appropriate f4() call when needed. Previously the OOB rand would have been stored in smp->rrnd however these are actually two independent values so we need separate variables for them. Na/Nb in the spec maps to smp->prnd/rrnd and ra/rb maps to smp->rr with smp->pr to come once local OOB data is supported.

---
 net/bluetooth/smp.c | 38 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 36 insertions(+), 2 deletions(-)
net/bluetooth/smp.c +36 -2
index a38541d079f5..62ca2aaf72fa 100644
@@ -71,6 +71,7 @@ struct smp_chan {
 	u8		rrnd[16]; /* SMP Pairing Random (remote) */
 	u8		pcnf[16]; /* SMP Pairing Confirm */
 	u8		tk[16]; /* SMP Temporary Key */
+	u8		rr[16];
 	u8		enc_key_size;
 	u8		remote_key_dist;
 	bdaddr_t	id_addr;
@@ -599,7 +600,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
 		if (oob_data) {
 			set_bit(SMP_FLAG_OOB, &smp->flags);
 			oob_flag = SMP_OOB_PRESENT;
-			memcpy(smp->rrnd, oob_data->rand256, 16);
+			memcpy(smp->rr, oob_data->rand256, 16);
 			memcpy(smp->pcnf, oob_data->hash256, 16);
 		}
 
@@ -1334,6 +1335,9 @@ static void sc_dhkey_check(struct smp_chan *smp)
 	if (smp->method == REQ_PASSKEY || smp->method == DSP_PASSKEY)
 		put_unaligned_le32(hcon->passkey_notify, r);
 
+	if (smp->method == REQ_OOB)
+		memcpy(r, smp->rr, 16);
+
 	smp_f6(smp->tfm_cmac, smp->mackey, smp->prnd, smp->rrnd, r, io_cap,
 	       local_addr, remote_addr, check.e);
 
@@ -1910,6 +1914,14 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 	if (!test_bit(SMP_FLAG_SC, &smp->flags))
 		return smp_random(smp);
 
+	if (smp->method == REQ_OOB) {
+		if (!hcon->out)
+			smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM,
+				     sizeof(smp->prnd), smp->prnd);
+		SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
+		goto mackey_and_ltk;
+	}
+
 	/* Passkey entry has special treatment */
 	if (smp->method == REQ_PASSKEY || smp->method == DSP_PASSKEY)
 		return sc_passkey_round(smp, SMP_CMD_PAIRING_RANDOM);
@@ -1940,12 +1952,13 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 		nb   = smp->prnd;
 	}
 
+mackey_and_ltk:
 	/* Generate MacKey and LTK */
 	err = sc_mackey_and_ltk(smp, smp->mackey, smp->tk);
 	if (err)
 		return SMP_UNSPECIFIED;
 
-	if (smp->method == JUST_WORKS) {
+	if (smp->method == JUST_WORKS || smp->method == REQ_OOB) {
 		if (hcon->out) {
 			sc_dhkey_check(smp);
 			SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
@@ -2314,6 +2327,9 @@ static u8 sc_select_method(struct smp_chan *smp)
 	struct smp_cmd_pairing *local, *remote;
 	u8 local_mitm, remote_mitm, local_io, remote_io, method;
 
+	if (test_bit(SMP_FLAG_OOB, &smp->flags))
+		return REQ_OOB;
+
 	/* The preq/prsp contain the raw Pairing Request/Response PDUs
 	 * which are needed as inputs to some crypto functions. To get
 	 * the "struct smp_cmd_pairing" from them we need to skip the
@@ -2412,6 +2428,24 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
 		return sc_passkey_round(smp, SMP_CMD_PUBLIC_KEY);
 	}
 
+	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);
+
+		SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM);
+
+		return 0;
+	}
+
 	if (hcon->out)
 		SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM);
 
Signature · 1 line
2.1.0
#44 lore raw

PATCH 44/49 Bluetooth: Introduce SMP_DBG macro for low-level debuging

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

The various inputs & outputs of the crypto functions as well as the values of the ECDH keys can be considered security sensitive. They should therefore not end up in dmesg by mistake. This patch introduces a new SMP_DBG macro which requires explicit compilation with -DDEBUG to be enabled. All crypto related data logs now use this macro instead of BT_DBG.

---
 net/bluetooth/smp.c | 68 +++++++++++++++++++++++++++++++----------------------
 1 file changed, 40 insertions(+), 28 deletions(-)
net/bluetooth/smp.c +40 -28
index 62ca2aaf72fa..7839354592f4 100644
@@ -32,6 +32,18 @@
 #include "ecc.h"
 #include "smp.h"
 
+/* Low-level debug macros to be used for stuff that we don't want
+ * accidentially in dmesg, i.e. the values of the various crypto keys
+ * and the inputs & outputs of crypto functions.
+ */
+#ifdef DEBUG
+#define SMP_DBG(fmt, ...) printk(KERN_DEBUG "%s: " fmt, __func__, \
+				 ##__VA_ARGS__)
+#else
+#define SMP_DBG(fmt, ...) no_printk(KERN_DEBUG "%s: " fmt, __func__, \
+				    ##__VA_ARGS__)
+#endif
+
 #define SMP_ALLOW_CMD(smp, code)	set_bit(code, &smp->allow_cmd)
 
 /* Keys which are not distributed with Secure Connections */
@@ -154,8 +166,8 @@ static int aes_cmac(struct crypto_hash *tfm, const u8 k[16], const u8 *m,
 	swap_buf(k, tmp, 16);
 	swap_buf(m, msg_msb, len);
 
-	BT_DBG("msg (len %zu) %*phN", len, len, m);
-	BT_DBG("key %16phN", k);
+	SMP_DBG("msg (len %zu) %*phN", len, len, m);
+	SMP_DBG("key %16phN", k);
 
 	err = crypto_hash_setkey(tfm, tmp, 16);
 	if (err) {
@@ -179,7 +191,7 @@ static int aes_cmac(struct crypto_hash *tfm, const u8 k[16], const u8 *m,
 
 	swap_buf(mac_msb, mac, 16);
 
-	BT_DBG("mac %16phN", mac);
+	SMP_DBG("mac %16phN", mac);
 
 	return 0;
 }
@@ -190,9 +202,9 @@ static int smp_f4(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32],
 	u8 m[65];
 	int err;
 
-	BT_DBG("u %32phN", u);
-	BT_DBG("v %32phN", v);
-	BT_DBG("x %16phN z %02x", x, z);
+	SMP_DBG("u %32phN", u);
+	SMP_DBG("v %32phN", v);
+	SMP_DBG("x %16phN z %02x", x, z);
 
 	m[0] = z;
 	memcpy(m + 1, v, 32);
@@ -202,7 +214,7 @@ static int smp_f4(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32],
 	if (err)
 		return err;
 
-	BT_DBG("res %16phN", res);
+	SMP_DBG("res %16phN", res);
 
 	return err;
 }
@@ -223,15 +235,15 @@ static int smp_f5(struct crypto_hash *tfm_cmac, u8 w[32], u8 n1[16], u8 n2[16],
 	u8 m[53], t[16];
 	int err;
 
-	BT_DBG("w %32phN", w);
-	BT_DBG("n1 %16phN n2 %16phN", n1, n2);
-	BT_DBG("a1 %7phN a2 %7phN", a1, a2);
+	SMP_DBG("w %32phN", w);
+	SMP_DBG("n1 %16phN n2 %16phN", n1, n2);
+	SMP_DBG("a1 %7phN a2 %7phN", a1, a2);
 
 	err = aes_cmac(tfm_cmac, salt, w, 32, t);
 	if (err)
 		return err;
 
-	BT_DBG("t %16phN", t);
+	SMP_DBG("t %16phN", t);
 
 	memcpy(m, length, 2);
 	memcpy(m + 2, a2, 7);
@@ -246,7 +258,7 @@ static int smp_f5(struct crypto_hash *tfm_cmac, u8 w[32], u8 n1[16], u8 n2[16],
 	if (err)
 		return err;
 
-	BT_DBG("mackey %16phN", mackey);
+	SMP_DBG("mackey %16phN", mackey);
 
 	m[52] = 1; /* Counter */
 
@@ -254,7 +266,7 @@ static int smp_f5(struct crypto_hash *tfm_cmac, u8 w[32], u8 n1[16], u8 n2[16],
 	if (err)
 		return err;
 
-	BT_DBG("ltk %16phN", ltk);
+	SMP_DBG("ltk %16phN", ltk);
 
 	return 0;
 }
@@ -267,9 +279,9 @@ static int smp_f6(struct crypto_hash *tfm_cmac, const u8 w[16],
 	u8 m[65];
 	int err;
 
-	BT_DBG("w %16phN", w);
-	BT_DBG("n1 %16phN n2 %16phN", n1, n2);
-	BT_DBG("r %16phN io_cap %3phN a1 %7phN a2 %7phN", r, io_cap, a1, a2);
+	SMP_DBG("w %16phN", w);
+	SMP_DBG("n1 %16phN n2 %16phN", n1, n2);
+	SMP_DBG("r %16phN io_cap %3phN a1 %7phN a2 %7phN", r, io_cap, a1, a2);
 
 	memcpy(m, a2, 7);
 	memcpy(m + 7, a1, 7);
@@ -293,9 +305,9 @@ static int smp_g2(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32],
 	u8 m[80], tmp[16];
 	int err;
 
-	BT_DBG("u %32phN", u);
-	BT_DBG("v %32phN", v);
-	BT_DBG("x %16phN y %16phN", x, y);
+	SMP_DBG("u %32phN", u);
+	SMP_DBG("v %32phN", v);
+	SMP_DBG("x %16phN y %16phN", x, y);
 
 	memcpy(m, y, 16);
 	memcpy(m + 16, v, 32);
@@ -308,7 +320,7 @@ static int smp_g2(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32],
 	*val = get_unaligned_le32(tmp);
 	*val %= 1000000;
 
-	BT_DBG("val %06u", *val);
+	SMP_DBG("val %06u", *val);
 
 	return 0;
 }
@@ -357,13 +369,13 @@ static int smp_h6(struct crypto_hash *tfm_cmac, const u8 w[16],
 {
 	int err;
 
-	BT_DBG("w %16phN key_id %4phN", w, key_id);
+	SMP_DBG("w %16phN key_id %4phN", w, key_id);
 
 	err = aes_cmac(tfm_cmac, w, key_id, 4, res);
 	if (err)
 		return err;
 
-	BT_DBG("res %16phN", res);
+	SMP_DBG("res %16phN", res);
 
 	return err;
 }
@@ -1742,9 +1754,9 @@ static u8 sc_send_public_key(struct smp_chan *smp)
 		}
 	}
 
-	BT_DBG("Local Public Key X: %32phN", smp->local_pk);
-	BT_DBG("Local Public Key Y: %32phN", &smp->local_pk[32]);
-	BT_DBG("Local Private Key:  %32phN", smp->local_sk);
+	SMP_DBG("Local Public Key X: %32phN", smp->local_pk);
+	SMP_DBG("Local Public Key Y: %32phN", &smp->local_pk[32]);
+	SMP_DBG("Local Private Key:  %32phN", smp->local_sk);
 
 	smp_send_cmd(smp->conn, SMP_CMD_PUBLIC_KEY, 64, smp->local_pk);
 
@@ -2390,13 +2402,13 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
 			return err;
 	}
 
-	BT_DBG("Remote Public Key X: %32phN", smp->remote_pk);
-	BT_DBG("Remote Public Key Y: %32phN", &smp->remote_pk[32]);
+	SMP_DBG("Remote Public Key X: %32phN", smp->remote_pk);
+	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;
 
-	BT_DBG("DHKey %32phN", smp->dhkey);
+	SMP_DBG("DHKey %32phN", smp->dhkey);
 
 	set_bit(SMP_FLAG_REMOTE_PK, &smp->flags);
 
Signature · 1 line
2.1.0
#45 lore raw

PATCH 45/49 Bluetooth: Fix missing const declarations in SMP functions

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

Several SMP functions take read-only data. This patch fixes the declaration of these parameters to use the const specifier as appropriate.

---
 net/bluetooth/smp.c | 18 ++++++++++--------
 net/bluetooth/smp.h |  5 +++--
 2 files changed, 13 insertions(+), 10 deletions(-)
net/bluetooth/smp.c +10 -8
index 7839354592f4..423e99d13207 100644
@@ -380,7 +380,8 @@ static int smp_h6(struct crypto_hash *tfm_cmac, const u8 w[16],
 	return err;
 }
 
-static int smp_ah(struct crypto_blkcipher *tfm, u8 irk[16], u8 r[3], u8 res[3])
+static int smp_ah(struct crypto_blkcipher *tfm, const u8 irk[16],
+		  const u8 r[3], u8 res[3])
 {
 	u8 _res[16];
 	int err;
@@ -406,7 +407,8 @@ static int smp_ah(struct crypto_blkcipher *tfm, u8 irk[16], u8 r[3], u8 res[3])
 	return 0;
 }
 
-bool smp_irk_matches(struct hci_dev *hdev, u8 irk[16], bdaddr_t *bdaddr)
+bool smp_irk_matches(struct hci_dev *hdev, const u8 irk[16],
+		     const bdaddr_t *bdaddr)
 {
 	struct l2cap_chan *chan = hdev->smp_data;
 	struct crypto_blkcipher *tfm;
@@ -427,7 +429,7 @@ bool smp_irk_matches(struct hci_dev *hdev, u8 irk[16], bdaddr_t *bdaddr)
 	return !memcmp(bdaddr->b, hash, 3);
 }
 
-int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa)
+int smp_generate_rpa(struct hci_dev *hdev, const u8 irk[16], bdaddr_t *rpa)
 {
 	struct l2cap_chan *chan = hdev->smp_data;
 	struct crypto_blkcipher *tfm;
@@ -452,9 +454,9 @@ int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa)
 	return 0;
 }
 
-static int smp_c1(struct crypto_blkcipher *tfm_aes, 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])
+static int smp_c1(struct crypto_blkcipher *tfm_aes, const u8 k[16],
+		  const u8 r[16], const u8 preq[7], const u8 pres[7], u8 _iat,
+		  const bdaddr_t *ia, u8 _rat, const bdaddr_t *ra, u8 res[16])
 {
 	u8 p1[16], p2[16];
 	int err;
@@ -493,8 +495,8 @@ static int smp_c1(struct crypto_blkcipher *tfm_aes, u8 k[16], u8 r[16],
 	return err;
 }
 
-static int smp_s1(struct crypto_blkcipher *tfm_aes, u8 k[16], u8 r1[16],
-		  u8 r2[16], u8 _r[16])
+static int smp_s1(struct crypto_blkcipher *tfm_aes, const u8 k[16],
+		  const u8 r1[16], const u8 r2[16], u8 _r[16])
 {
 	int err;
 
net/bluetooth/smp.h +3 -2
index f955d6b7ceb2..3296bf42ae80 100644
@@ -185,8 +185,9 @@ bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level,
 int smp_conn_security(struct hci_conn *hcon, __u8 sec_level);
 int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey);
 
-bool smp_irk_matches(struct hci_dev *hdev, u8 irk[16], bdaddr_t *bdaddr);
-int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa);
+bool smp_irk_matches(struct hci_dev *hdev, const u8 irk[16],
+		     const bdaddr_t *bdaddr);
+int smp_generate_rpa(struct hci_dev *hdev, const u8 irk[16], bdaddr_t *rpa);
 
 int smp_register(struct hci_dev *hdev);
 void smp_unregister(struct hci_dev *hdev);
Signature · 1 line
2.1.0
#46 lore raw

PATCH 46/49 Bluetooth: Organize SMP crypto functions to logical sections

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

This patch organizes the various SMP crypto functions so that the LE SC functions appear in one section and the legacy SMP functions in a separate one.

---
 net/bluetooth/smp.c | 134 ++++++++++++++++++++++++++++------------------------
 1 file changed, 71 insertions(+), 63 deletions(-)
net/bluetooth/smp.c +71 -63
index 423e99d13207..c5dcb6563579 100644
@@ -141,6 +141,10 @@ static inline void swap_buf(const u8 *src, u8 *dst, size_t len)
 		dst[len - 1 - i] = src[i];
 }
 
+/* The following functions map to the LE SC SMP crypto functions
+ * AES-CMAC, f4, f5, f6, g2 and h6.
+ */
+
 static int aes_cmac(struct crypto_hash *tfm, const u8 k[16], const u8 *m,
 		    size_t len, u8 mac[16])
 {
@@ -325,6 +329,26 @@ static int smp_g2(struct crypto_hash *tfm_cmac, const u8 u[32], const u8 v[32],
 	return 0;
 }
 
+static int smp_h6(struct crypto_hash *tfm_cmac, const u8 w[16],
+		  const u8 key_id[4], u8 res[16])
+{
+	int err;
+
+	SMP_DBG("w %16phN key_id %4phN", w, key_id);
+
+	err = aes_cmac(tfm_cmac, w, key_id, 4, res);
+	if (err)
+		return err;
+
+	SMP_DBG("res %16phN", res);
+
+	return err;
+}
+
+/* The following functions map to the legacy SMP crypto functions e, c1,
+ * s1 and ah.
+ */
+
 static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
 {
 	struct blkcipher_desc desc;
@@ -364,18 +388,59 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
 	return err;
 }
 
-static int smp_h6(struct crypto_hash *tfm_cmac, const u8 w[16],
-		  const u8 key_id[4], u8 res[16])
+static int smp_c1(struct crypto_blkcipher *tfm_aes, const u8 k[16],
+		  const u8 r[16], const u8 preq[7], const u8 pres[7], u8 _iat,
+		  const bdaddr_t *ia, u8 _rat, const bdaddr_t *ra, u8 res[16])
 {
+	u8 p1[16], p2[16];
 	int err;
 
-	SMP_DBG("w %16phN key_id %4phN", w, key_id);
+	memset(p1, 0, 16);
 
-	err = aes_cmac(tfm_cmac, w, key_id, 4, res);
-	if (err)
+	/* p1 = pres || preq || _rat || _iat */
+	p1[0] = _iat;
+	p1[1] = _rat;
+	memcpy(p1 + 2, preq, 7);
+	memcpy(p1 + 9, pres, 7);
+
+	/* p2 = padding || ia || ra */
+	memcpy(p2, ra, 6);
+	memcpy(p2 + 6, ia, 6);
+	memset(p2 + 12, 0, 4);
+
+	/* res = r XOR p1 */
+	u128_xor((u128 *) res, (u128 *) r, (u128 *) p1);
+
+	/* res = e(k, res) */
+	err = smp_e(tfm_aes, k, res);
+	if (err) {
+		BT_ERR("Encrypt data error");
 		return err;
+	}
 
-	SMP_DBG("res %16phN", res);
+	/* res = res XOR p2 */
+	u128_xor((u128 *) res, (u128 *) res, (u128 *) p2);
+
+	/* res = e(k, res) */
+	err = smp_e(tfm_aes, k, res);
+	if (err)
+		BT_ERR("Encrypt data error");
+
+	return err;
+}
+
+static int smp_s1(struct crypto_blkcipher *tfm_aes, const u8 k[16],
+		  const u8 r1[16], const u8 r2[16], u8 _r[16])
+{
+	int err;
+
+	/* Just least significant octets from r1 and r2 are considered */
+	memcpy(_r, r2, 8);
+	memcpy(_r + 8, r1, 8);
+
+	err = smp_e(tfm_aes, k, _r);
+	if (err)
+		BT_ERR("Encrypt data error");
 
 	return err;
 }
@@ -454,63 +519,6 @@ int smp_generate_rpa(struct hci_dev *hdev, const u8 irk[16], bdaddr_t *rpa)
 	return 0;
 }
 
-static int smp_c1(struct crypto_blkcipher *tfm_aes, const u8 k[16],
-		  const u8 r[16], const u8 preq[7], const u8 pres[7], u8 _iat,
-		  const bdaddr_t *ia, u8 _rat, const bdaddr_t *ra, u8 res[16])
-{
-	u8 p1[16], p2[16];
-	int err;
-
-	memset(p1, 0, 16);
-
-	/* p1 = pres || preq || _rat || _iat */
-	p1[0] = _iat;
-	p1[1] = _rat;
-	memcpy(p1 + 2, preq, 7);
-	memcpy(p1 + 9, pres, 7);
-
-	/* p2 = padding || ia || ra */
-	memcpy(p2, ra, 6);
-	memcpy(p2 + 6, ia, 6);
-	memset(p2 + 12, 0, 4);
-
-	/* res = r XOR p1 */
-	u128_xor((u128 *) res, (u128 *) r, (u128 *) p1);
-
-	/* res = e(k, res) */
-	err = smp_e(tfm_aes, k, res);
-	if (err) {
-		BT_ERR("Encrypt data error");
-		return err;
-	}
-
-	/* res = res XOR p2 */
-	u128_xor((u128 *) res, (u128 *) res, (u128 *) p2);
-
-	/* res = e(k, res) */
-	err = smp_e(tfm_aes, k, res);
-	if (err)
-		BT_ERR("Encrypt data error");
-
-	return err;
-}
-
-static int smp_s1(struct crypto_blkcipher *tfm_aes, const u8 k[16],
-		  const u8 r1[16], const u8 r2[16], u8 _r[16])
-{
-	int err;
-
-	/* Just least significant octets from r1 and r2 are considered */
-	memcpy(_r, r2, 8);
-	memcpy(_r + 8, r1, 8);
-
-	err = smp_e(tfm_aes, k, _r);
-	if (err)
-		BT_ERR("Encrypt data error");
-
-	return err;
-}
-
 static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
 {
 	struct l2cap_chan *chan = conn->smp;
Signature · 1 line
2.1.0
#47 lore raw

PATCH 47/49 Bluetooth: Fix SMP debug key handling

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

We need to keep debug keys around at least until the point that they are used - otherwise e.g. slave role behavior wouldn't work as there'd be no key to be looked up. The correct behavior should therefore be to return any stored keys but when we clean up the SMP context to remove the key from the hdev list if keeping debug keys around hasn't been requestsed.

---
 net/bluetooth/hci_core.c | 10 +---------
 net/bluetooth/smp.c      | 15 +++++++++++++--
 2 files changed, 14 insertions(+), 11 deletions(-)
net/bluetooth/hci_core.c +1 -9
index c8123f04a33c..f0018562b028 100644
@@ -3246,15 +3246,7 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
 		if (addr_type != k->bdaddr_type || bacmp(bdaddr, &k->bdaddr))
 			continue;
 
-		if (smp_ltk_is_sc(k)) {
-			if (k->type == SMP_LTK_P256_DEBUG &&
-			    !test_bit(HCI_KEEP_DEBUG_KEYS, &hdev->dev_flags))
-				continue;
-			rcu_read_unlock();
-			return k;
-		}
-
-		if (ltk_role(k->type) == role) {
+		if (smp_ltk_is_sc(k) || ltk_role(k->type) == role) {
 			rcu_read_unlock();
 			return k;
 		}
net/bluetooth/smp.c +13 -2
index c5dcb6563579..aeae4bed7ded 100644
@@ -670,6 +670,7 @@ static void smp_chan_destroy(struct l2cap_conn *conn)
 {
 	struct l2cap_chan *chan = conn->smp;
 	struct smp_chan *smp = chan->data;
+	struct hci_conn *hcon = conn->hcon;
 	bool complete;
 
 	BUG_ON(!smp);
@@ -677,7 +678,7 @@ static void smp_chan_destroy(struct l2cap_conn *conn)
 	cancel_delayed_work_sync(&smp->security_timer);
 
 	complete = test_bit(SMP_FLAG_COMPLETE, &smp->flags);
-	mgmt_smp_complete(conn->hcon, complete);
+	mgmt_smp_complete(hcon, complete);
 
 	kfree(smp->csrk);
 	kfree(smp->slave_csrk);
@@ -686,6 +687,16 @@ static void smp_chan_destroy(struct l2cap_conn *conn)
 	crypto_free_blkcipher(smp->tfm_aes);
 	crypto_free_hash(smp->tfm_cmac);
 
+	/* Ensure that we don't leave any debug key around if debug key
+	 * support hasn't been explicitly enabled.
+	 */
+	if (smp->ltk && smp->ltk->type == SMP_LTK_P256_DEBUG &&
+	    !test_bit(HCI_KEEP_DEBUG_KEYS, &hcon->hdev->dev_flags)) {
+		list_del_rcu(&smp->ltk->list);
+		kfree_rcu(smp->ltk, rcu);
+		smp->ltk = NULL;
+	}
+
 	/* If pairing failed clean up any keys we might have */
 	if (!complete) {
 		if (smp->ltk) {
@@ -706,7 +717,7 @@ static void smp_chan_destroy(struct l2cap_conn *conn)
 
 	chan->data = NULL;
 	kfree(smp);
-	hci_conn_drop(conn->hcon);
+	hci_conn_drop(hcon);
 }
 
 static void smp_failure(struct l2cap_conn *conn, u8 reason)
Signature · 1 line
2.1.0
#48 lore raw

PATCH 48/49 Bluetooth: Fix minor coding style issue in smp.c

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

The convention for checking for NULL pointers is !ptr and not ptr == NULL. This patch fixes such an occurrence in smp.c.

---
 net/bluetooth/smp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/bluetooth/smp.c +1 -1
index aeae4bed7ded..96e2b329c8ce 100644
@@ -356,7 +356,7 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
 	uint8_t tmp[16], data[16];
 	int err;
 
-	if (tfm == NULL) {
+	if (!tfm) {
 		BT_ERR("tfm %p", tfm);
 		return -EINVAL;
 	}
Signature · 1 line
2.1.0
#49 lore raw

PATCH 49/49 Bluetooth: Fix false-positive "uninitialized" compiler warning

In reply to Johan Hedberg

From: Johan Hedberg <[email protected]>

Some gcc versions don't seem to be able to properly track the flow of the smp_cmd_pairing_random() function and end up causing the following types of (false-positive) warnings:

smp.c:1995:6: warning: ‘nb’ may be used uninitialized in this function [-Wmaybe-uninitialized]
err = smp_g2(smp->tfm_cmac, pkax, pkbx, na, nb, &passkey);
smp.c:1995:6: warning: ‘na’ may be used uninitialized in this function [-Wmaybe-uninitialized]
err = smp_g2(smp->tfm_cmac, pkax, pkbx, na, nb, &passkey);

       ^
 smp.c:1995:6: warning: ‘pkbx’ may be used uninitialized in this function [-Wmaybe-uninitialized]
   err = smp_g2(smp->tfm_cmac, pkax, pkbx, na, nb, &passkey);
       ^

smp.c:1995:6: warning: ‘pkax’ may be used uninitialized in this function [-Wmaybe-uninitialized]
err = smp_g2(smp->tfm_cmac, pkax, pkbx, na, nb, &passkey);

This patch fixes the issue by moving the pkax/pkbx and na/nb initialization earlier in the function.

---
 net/bluetooth/smp.c | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)
net/bluetooth/smp.c +12 -10
index 96e2b329c8ce..53340e8f0b95 100644
@@ -1947,6 +1947,18 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 	if (!test_bit(SMP_FLAG_SC, &smp->flags))
 		return smp_random(smp);
 
+	if (hcon->out) {
+		pkax = smp->local_pk;
+		pkbx = smp->remote_pk;
+		na   = smp->prnd;
+		nb   = smp->rrnd;
+	} else {
+		pkax = smp->remote_pk;
+		pkbx = smp->local_pk;
+		na   = smp->rrnd;
+		nb   = smp->prnd;
+	}
+
 	if (smp->method == REQ_OOB) {
 		if (!hcon->out)
 			smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM,
@@ -1969,20 +1981,10 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 
 		if (memcmp(smp->pcnf, cfm, 16))
 			return SMP_CONFIRM_FAILED;
-
-		pkax = smp->local_pk;
-		pkbx = smp->remote_pk;
-		na   = smp->prnd;
-		nb   = smp->rrnd;
 	} else {
 		smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
 			     smp->prnd);
 		SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
-
-		pkax = smp->remote_pk;
-		pkbx = smp->local_pk;
-		na   = smp->rrnd;
-		nb   = smp->prnd;
 	}
 
 mackey_and_ltk:
Signature · 1 line
2.1.0
maintainer
#50 lore raw
In reply to Johan Hedberg

Hi Johan,

Quoted 64 lines

First of all, appologies to all for this huge patch set. It's work from the past 6 months or so that wasn't releasable until the 4.2 specification goes public. That happened just some moments ago:

http://www.bluetooth.com/SiteCollectionDocuments/4-2/bluetooth4-2.aspx

I'm sending the patches to the mailing list mainly for reference since Marcel will probably directly merge them from my tree. Any issues/fixes etc should be done on top of them.

Johan

----------------------------------------------------------------
Johan Hedberg (49):
Bluetooth: Add basic SMP defines for LE Secure Connections
Bluetooth: Make auth_req mask dependent on SC enabled or not
Bluetooth: Add SMP flag for SC and set it when necessary.
Bluetooth: Update SMP security level to/from auth_req for SC
Bluetooth: Add mgmt support for LE Secure Connections LTK types
Bluetooth: Set the correct security level for SC LTKs
Bluetooth: Use custom macro for testing BR/EDR SC enabled
Bluetooth: Add mgmt_set_secure_conn support for any LE adapter
Bluetooth: Update LTK lookup to correctly deal with SC LTKs
Bluetooth: Remove unused hci_find_ltk function
Bluetooth: Rename hci_find_ltk_by_addr to hci_find_ltk
Bluetooth: Set link key generation bit if necessary for LE SC
Bluetooth: Add basic support for AES-CMAC
Bluetooth: Add ECC library for LE Secure Connections
Bluetooth: Add basic support for sending our LE SC public key
Bluetooth: Add handler function for receiving LE SC public key
Bluetooth: Add support for sending LE SC Confirm value
Bluetooth: Add LE SC support for responding to Pairing Confirm PDU
Bluetooth: Add support for LE SC numeric comparison
Bluetooth: Add support for handling LE SC user response
Bluetooth: Add support for LE SC DHKey check PDU
Bluetooth: Add support for LE SC key generation
Bluetooth: Track authentication method in SMP context
Bluetooth: Add selection of the SC authentication method
Bluetooth: Detect SMP SC debug keys
Bluetooth: Add check for accidentally generating a debug key
Bluetooth: Set correct LTK type and authentication for SC
Bluetooth: Add support for SC just-works pairing
Bluetooth: Fix BR/EDR Link Key type when derived through LE SC
Bluetooth: Add passkey entry support for LE SC
Bluetooth: Fix DHKey Check sending order for slave role
Bluetooth: Add dummy handler for LE SC keypress notification
Bluetooth: Use debug keys for SMP when HCI_USE_DEBUG_KEYS is set
Bluetooth: Add hci_conn flag for new link key generation
Bluetooth: Add debugfs switch for forcing SMP over BR/EDR
Bluetooth: Add skeleton for BR/EDR SMP channel
Bluetooth: Add full SMP BR/EDR support
Bluetooth: Add SC-only mode support for SMP
Bluetooth: Unify remote OOB data functions
Bluetooth: Store address type with OOB data
Bluetooth: Add support for adding remote OOB data for LE
Bluetooth: Set SMP OOB flag if OOB data is available
Bluetooth: Add basic LE SC OOB support for remote OOB data
Bluetooth: Introduce SMP_DBG macro for low-level debuging
Bluetooth: Fix missing const declarations in SMP functions
Bluetooth: Organize SMP crypto functions to logical sections
Bluetooth: Fix SMP debug key handling
Bluetooth: Fix minor coding style issue in smp.c
Bluetooth: Fix false-positive "uninitialized" compiler warning

Quoted 15 lines
include/net/bluetooth/hci.h      |    1 +
include/net/bluetooth/hci_core.h |   23 +-
include/net/bluetooth/l2cap.h    |    2 +
include/net/bluetooth/mgmt.h     |    3 +
net/bluetooth/Kconfig            |    1 +
net/bluetooth/Makefile           |    2 +-
net/bluetooth/ecc.c              |  816 ++++++++++++++++++++
net/bluetooth/ecc.h              |   54 ++
net/bluetooth/hci_core.c         |  155 ++--
net/bluetooth/hci_event.c        |   23 +-
net/bluetooth/l2cap_core.c       |    4 +
net/bluetooth/mgmt.c             |   75 +-
net/bluetooth/smp.c              | 1543 +++++++++++++++++++++++++++++++++----
net/bluetooth/smp.h              |   51 +-
14 files changed, 2509 insertions(+), 244 deletions(-)

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

Regards

Marcel