linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Johan Hedberg <johan.hedberg@gmail.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH 30/49] Bluetooth: Add passkey entry support for LE SC
Date: Wed,  3 Dec 2014 17:02:24 +0200	[thread overview]
Message-ID: <1417618963-18010-31-git-send-email-johan.hedberg@gmail.com> (raw)
In-Reply-To: <1417618963-18010-1-git-send-email-johan.hedberg@gmail.com>

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

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.

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

diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 861d2cf3ccc9..7a9b491ffa1a 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -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)
-- 
2.1.0


  parent reply	other threads:[~2014-12-03 15:02 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-12-03 15:01 [PATCH 00/49] Bluetooth: LE Secure Connections support Johan Hedberg
2014-12-03 15:01 ` [PATCH 01/49] Bluetooth: Add basic SMP defines for LE Secure Connections Johan Hedberg
2014-12-03 15:01 ` [PATCH 02/49] Bluetooth: Make auth_req mask dependent on SC enabled or not Johan Hedberg
2014-12-03 15:01 ` [PATCH 03/49] Bluetooth: Add SMP flag for SC and set it when necessary Johan Hedberg
2014-12-03 15:01 ` [PATCH 04/49] Bluetooth: Update SMP security level to/from auth_req for SC Johan Hedberg
2014-12-03 15:01 ` [PATCH 05/49] Bluetooth: Add mgmt support for LE Secure Connections LTK types Johan Hedberg
2014-12-03 15:02 ` [PATCH 06/49] Bluetooth: Set the correct security level for SC LTKs Johan Hedberg
2014-12-03 15:02 ` [PATCH 07/49] Bluetooth: Use custom macro for testing BR/EDR SC enabled Johan Hedberg
2014-12-03 15:02 ` [PATCH 08/49] Bluetooth: Add mgmt_set_secure_conn support for any LE adapter Johan Hedberg
2014-12-03 15:02 ` [PATCH 09/49] Bluetooth: Update LTK lookup to correctly deal with SC LTKs Johan Hedberg
2014-12-03 15:02 ` [PATCH 10/49] Bluetooth: Remove unused hci_find_ltk function Johan Hedberg
2014-12-03 15:02 ` [PATCH 11/49] Bluetooth: Rename hci_find_ltk_by_addr to hci_find_ltk Johan Hedberg
2014-12-03 15:02 ` [PATCH 12/49] Bluetooth: Set link key generation bit if necessary for LE SC Johan Hedberg
2014-12-03 15:02 ` [PATCH 13/49] Bluetooth: Add basic support for AES-CMAC Johan Hedberg
2014-12-03 15:02 ` [PATCH 14/49] Bluetooth: Add ECC library for LE Secure Connections Johan Hedberg
2014-12-03 15:02 ` [PATCH 15/49] Bluetooth: Add basic support for sending our LE SC public key Johan Hedberg
2014-12-03 15:02 ` [PATCH 16/49] Bluetooth: Add handler function for receiving " Johan Hedberg
2014-12-03 15:02 ` [PATCH 17/49] Bluetooth: Add support for sending LE SC Confirm value Johan Hedberg
2014-12-03 15:02 ` [PATCH 18/49] Bluetooth: Add LE SC support for responding to Pairing Confirm PDU Johan Hedberg
2014-12-03 15:02 ` [PATCH 19/49] Bluetooth: Add support for LE SC numeric comparison Johan Hedberg
2014-12-03 15:02 ` [PATCH 20/49] Bluetooth: Add support for handling LE SC user response Johan Hedberg
2014-12-03 15:02 ` [PATCH 21/49] Bluetooth: Add support for LE SC DHKey check PDU Johan Hedberg
2014-12-03 15:02 ` [PATCH 22/49] Bluetooth: Add support for LE SC key generation Johan Hedberg
2014-12-03 15:02 ` [PATCH 23/49] Bluetooth: Track authentication method in SMP context Johan Hedberg
2014-12-03 15:02 ` [PATCH 24/49] Bluetooth: Add selection of the SC authentication method Johan Hedberg
2014-12-03 15:02 ` [PATCH 25/49] Bluetooth: Detect SMP SC debug keys Johan Hedberg
2014-12-03 15:02 ` [PATCH 26/49] Bluetooth: Add check for accidentally generating a debug key Johan Hedberg
2014-12-03 15:02 ` [PATCH 27/49] Bluetooth: Set correct LTK type and authentication for SC Johan Hedberg
2014-12-03 15:02 ` [PATCH 28/49] Bluetooth: Add support for SC just-works pairing Johan Hedberg
2014-12-03 15:02 ` [PATCH 29/49] Bluetooth: Fix BR/EDR Link Key type when derived through LE SC Johan Hedberg
2014-12-03 15:02 ` Johan Hedberg [this message]
2014-12-03 15:02 ` [PATCH 31/49] Bluetooth: Fix DHKey Check sending order for slave role Johan Hedberg
2014-12-03 15:02 ` [PATCH 32/49] Bluetooth: Add dummy handler for LE SC keypress notification Johan Hedberg
2014-12-03 15:02 ` [PATCH 33/49] Bluetooth: Use debug keys for SMP when HCI_USE_DEBUG_KEYS is set Johan Hedberg
2014-12-03 15:02 ` [PATCH 34/49] Bluetooth: Add hci_conn flag for new link key generation Johan Hedberg
2014-12-03 15:02 ` [PATCH 35/49] Bluetooth: Add debugfs switch for forcing SMP over BR/EDR Johan Hedberg
2014-12-03 15:02 ` [PATCH 36/49] Bluetooth: Add skeleton for BR/EDR SMP channel Johan Hedberg
2014-12-03 15:02 ` [PATCH 37/49] Bluetooth: Add full SMP BR/EDR support Johan Hedberg
2014-12-03 15:02 ` [PATCH 38/49] Bluetooth: Add SC-only mode support for SMP Johan Hedberg
2014-12-03 15:02 ` [PATCH 39/49] Bluetooth: Unify remote OOB data functions Johan Hedberg
2014-12-03 15:02 ` [PATCH 40/49] Bluetooth: Store address type with OOB data Johan Hedberg
2014-12-03 15:02 ` [PATCH 41/49] Bluetooth: Add support for adding remote OOB data for LE Johan Hedberg
2014-12-03 15:02 ` [PATCH 42/49] Bluetooth: Set SMP OOB flag if OOB data is available Johan Hedberg
2014-12-03 15:02 ` [PATCH 43/49] Bluetooth: Add basic LE SC OOB support for remote OOB data Johan Hedberg
2014-12-03 15:02 ` [PATCH 44/49] Bluetooth: Introduce SMP_DBG macro for low-level debuging Johan Hedberg
2014-12-03 15:02 ` [PATCH 45/49] Bluetooth: Fix missing const declarations in SMP functions Johan Hedberg
2014-12-03 15:02 ` [PATCH 46/49] Bluetooth: Organize SMP crypto functions to logical sections Johan Hedberg
2014-12-03 15:02 ` [PATCH 47/49] Bluetooth: Fix SMP debug key handling Johan Hedberg
2014-12-03 15:02 ` [PATCH 48/49] Bluetooth: Fix minor coding style issue in smp.c Johan Hedberg
2014-12-03 15:02 ` [PATCH 49/49] Bluetooth: Fix false-positive "uninitialized" compiler warning Johan Hedberg
2014-12-03 15:56 ` [PATCH 00/49] Bluetooth: LE Secure Connections support Marcel Holtmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1417618963-18010-31-git-send-email-johan.hedberg@gmail.com \
    --to=johan.hedberg@gmail.com \
    --cc=linux-bluetooth@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).