From: Johan Hedberg <johan.hedberg@gmail.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH 37/49] Bluetooth: Add full SMP BR/EDR support
Date: Wed, 3 Dec 2014 17:02:31 +0200 [thread overview]
Message-ID: <1417618963-18010-38-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>
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.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/l2cap_core.c | 4 +
net/bluetooth/smp.c | 230 ++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 212 insertions(+), 22 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 43349ed4c249..a8da7ea9c2c0 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -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);
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 8c1b53f32f10..12294935d258 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -915,11 +915,13 @@ static void smp_notify_keys(struct l2cap_conn *conn)
mgmt_new_irk(hdev, smp->remote_irk);
/* Now that user space can be considered to know the
* identity address track the connection based on it
- * from now on.
+ * from now on (assuming this is an LE link).
*/
- bacpy(&hcon->dst, &smp->remote_irk->bdaddr);
- hcon->dst_type = smp->remote_irk->addr_type;
- queue_work(hdev->workqueue, &conn->id_addr_update_work);
+ if (hcon->type == LE_LINK) {
+ bacpy(&hcon->dst, &smp->remote_irk->bdaddr);
+ hcon->dst_type = smp->remote_irk->addr_type;
+ queue_work(hdev->workqueue, &conn->id_addr_update_work);
+ }
/* When receiving an indentity resolving key for
* a remote device that does not use a resolvable
@@ -938,10 +940,20 @@ static void smp_notify_keys(struct l2cap_conn *conn)
}
}
- /* The LTKs and CSRKs should be persistent only if both sides
- * had the bonding bit set in their authentication requests.
- */
- persistent = !!((req->auth_req & rsp->auth_req) & SMP_AUTH_BONDING);
+ if (hcon->type == ACL_LINK) {
+ if (hcon->key_type == HCI_LK_DEBUG_COMBINATION)
+ persistent = false;
+ else
+ persistent = !test_bit(HCI_CONN_FLUSH_KEY,
+ &hcon->flags);
+ } else {
+ /* The LTKs and CSRKs should be persistent only if both sides
+ * had the bonding bit set in their authentication requests.
+ */
+ persistent = !!((req->auth_req & rsp->auth_req) &
+ SMP_AUTH_BONDING);
+ }
+
if (smp->csrk) {
smp->csrk->bdaddr_type = hcon->dst_type;
@@ -1057,6 +1069,35 @@ static void smp_allow_key_dist(struct smp_chan *smp)
SMP_ALLOW_CMD(smp, SMP_CMD_SIGN_INFO);
}
+static void sc_generate_ltk(struct smp_chan *smp)
+{
+ /* These constants are as specified in the core specification.
+ * In ASCII they spell out to 'tmp2' and 'brle'.
+ */
+ const u8 tmp2[4] = { 0x32, 0x70, 0x6d, 0x74 };
+ const u8 brle[4] = { 0x65, 0x6c, 0x72, 0x62 };
+ struct hci_conn *hcon = smp->conn->hcon;
+ struct hci_dev *hdev = hcon->hdev;
+ struct link_key *key;
+
+ key = hci_find_link_key(hdev, &hcon->dst);
+ if (!key) {
+ BT_ERR("%s No Link Key found to generate LTK", hdev->name);
+ return;
+ }
+
+ if (key->type == HCI_LK_DEBUG_COMBINATION)
+ set_bit(SMP_FLAG_DEBUG_KEY, &smp->flags);
+
+ if (smp_h6(smp->tfm_cmac, key->val, tmp2, smp->tk))
+ return;
+
+ if (smp_h6(smp->tfm_cmac, smp->tk, brle, smp->tk))
+ return;
+
+ sc_add_ltk(smp);
+}
+
static void smp_distribute_keys(struct smp_chan *smp)
{
struct smp_cmd_pairing *req, *rsp;
@@ -1086,8 +1127,10 @@ static void smp_distribute_keys(struct smp_chan *smp)
}
if (test_bit(SMP_FLAG_SC, &smp->flags)) {
- if (*keydist & SMP_DIST_LINK_KEY)
+ if (hcon->type == LE_LINK && (*keydist & SMP_DIST_LINK_KEY))
sc_generate_link_key(smp);
+ if (hcon->type == ACL_LINK && (*keydist & SMP_DIST_ENC_KEY))
+ sc_generate_ltk(smp);
/* Clear the keys which are generated but not distributed */
*keydist &= ~SMP_SC_NO_DIST;
@@ -1493,6 +1536,46 @@ unlock:
return err;
}
+static void build_bredr_pairing_cmd(struct smp_chan *smp,
+ struct smp_cmd_pairing *req,
+ struct smp_cmd_pairing *rsp)
+{
+ struct l2cap_conn *conn = smp->conn;
+ struct hci_dev *hdev = conn->hcon->hdev;
+ u8 local_dist = 0, remote_dist = 0;
+
+ if (test_bit(HCI_BONDABLE, &hdev->dev_flags)) {
+ local_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN;
+ remote_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN;
+ }
+
+ if (test_bit(HCI_RPA_RESOLVING, &hdev->dev_flags))
+ remote_dist |= SMP_DIST_ID_KEY;
+
+ if (test_bit(HCI_PRIVACY, &hdev->dev_flags))
+ local_dist |= SMP_DIST_ID_KEY;
+
+ if (!rsp) {
+ memset(req, 0, sizeof(*req));
+
+ req->init_key_dist = local_dist;
+ req->resp_key_dist = remote_dist;
+ req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
+
+ smp->remote_key_dist = remote_dist;
+
+ return;
+ }
+
+ memset(rsp, 0, sizeof(*rsp));
+
+ 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;
+
+ smp->remote_key_dist = rsp->init_key_dist;
+}
+
static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_pairing rsp, *req = (void *) skb->data;
@@ -1529,6 +1612,31 @@ 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));
+ /* SMP over BR/EDR requires special treatment */
+ if (conn->hcon->type == ACL_LINK) {
+ /* We must have a BR/EDR SC link */
+ if (!test_bit(HCI_CONN_AES_CCM, &conn->hcon->flags))
+ return SMP_CROSS_TRANSP_NOT_ALLOWED;
+
+ set_bit(SMP_FLAG_SC, &smp->flags);
+
+ build_bredr_pairing_cmd(smp, req, &rsp);
+
+ key_size = min(req->max_key_size, rsp.max_key_size);
+ if (check_enc_key_size(conn, key_size))
+ return SMP_ENC_KEY_SIZE;
+
+ /* Clear bits which are generated but not distributed */
+ smp->remote_key_dist &= ~SMP_SC_NO_DIST;
+
+ smp->prsp[0] = SMP_CMD_PAIRING_RSP;
+ memcpy(&smp->prsp[1], &rsp, sizeof(rsp));
+ smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp);
+
+ smp_distribute_keys(smp);
+ return 0;
+ }
+
build_pairing_cmd(conn, req, &rsp, auth);
if (rsp.auth_req & SMP_AUTH_SC)
@@ -1644,6 +1752,22 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
auth = rsp->auth_req & AUTH_REQ_MASK(hdev);
+ smp->prsp[0] = SMP_CMD_PAIRING_RSP;
+ memcpy(&smp->prsp[1], rsp, sizeof(*rsp));
+
+ /* Update remote key distribution in case the remote cleared
+ * some bits that we had enabled in our request.
+ */
+ smp->remote_key_dist &= rsp->resp_key_dist;
+
+ /* For BR/EDR this means we're done and can start phase 3 */
+ if (conn->hcon->type == ACL_LINK) {
+ /* Clear bits which are generated but not distributed */
+ smp->remote_key_dist &= ~SMP_SC_NO_DIST;
+ smp_distribute_keys(smp);
+ return 0;
+ }
+
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)
@@ -1661,9 +1785,6 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
get_random_bytes(smp->prnd, sizeof(smp->prnd));
- smp->prsp[0] = SMP_CMD_PAIRING_RSP;
- memcpy(&smp->prsp[1], rsp, sizeof(*rsp));
-
/* Update remote key distribution in case the remote cleared
* some bits that we had enabled in our request.
*/
@@ -2373,11 +2494,6 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb)
__u8 code, reason;
int err = 0;
- if (hcon->type != LE_LINK) {
- kfree_skb(skb);
- return 0;
- }
-
if (skb->len < 1)
return -EILSEQ;
@@ -2496,6 +2612,74 @@ static void smp_teardown_cb(struct l2cap_chan *chan, int err)
l2cap_chan_put(chan);
}
+static void bredr_pairing(struct l2cap_chan *chan)
+{
+ struct l2cap_conn *conn = chan->conn;
+ struct hci_conn *hcon = conn->hcon;
+ struct hci_dev *hdev = hcon->hdev;
+ struct smp_cmd_pairing req;
+ struct smp_chan *smp;
+
+ BT_DBG("chan %p", chan);
+
+ /* Only new pairings are interesting */
+ if (!test_bit(HCI_CONN_NEW_LINK_KEY, &hcon->flags))
+ return;
+
+ /* Don't bother if we're not encrypted */
+ if (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags))
+ return;
+
+ /* Only master may initiate SMP over BR/EDR */
+ if (hcon->role != HCI_ROLE_MASTER)
+ return;
+
+ /* Secure Connections support must be enabled */
+ if (!test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
+ return;
+
+ /* BR/EDR must use Secure Connections for SMP */
+ if (!test_bit(HCI_CONN_AES_CCM, &hcon->flags) &&
+ !test_bit(HCI_FORCE_LESC, &hdev->dbg_flags))
+ return;
+
+ /* If our LE support is not enabled don't do anything */
+ if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
+ return;
+
+ /* Don't bother if remote LE support is not enabled */
+ if (!lmp_host_le_capable(hcon))
+ return;
+
+ /* Remote must support SMP fixed chan for BR/EDR */
+ if (!(conn->remote_fixed_chan & L2CAP_FC_SMP_BREDR))
+ return;
+
+ /* Don't bother if SMP is already ongoing */
+ if (chan->data)
+ return;
+
+ smp = smp_chan_create(conn);
+ if (!smp) {
+ BT_ERR("%s unable to create SMP context for BR/EDR",
+ hdev->name);
+ return;
+ }
+
+ set_bit(SMP_FLAG_SC, &smp->flags);
+
+ BT_DBG("%s starting SMP over BR/EDR", hdev->name);
+
+ /* Prepare and send the BR/EDR SMP Pairing Request */
+ build_bredr_pairing_cmd(smp, &req, NULL);
+
+ smp->preq[0] = SMP_CMD_PAIRING_REQ;
+ memcpy(&smp->preq[1], &req, sizeof(req));
+
+ smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(req), &req);
+ SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RSP);
+}
+
static void smp_resume_cb(struct l2cap_chan *chan)
{
struct smp_chan *smp = chan->data;
@@ -2504,8 +2688,10 @@ static void smp_resume_cb(struct l2cap_chan *chan)
BT_DBG("chan %p", chan);
- if (hcon->type == ACL_LINK)
+ if (hcon->type == ACL_LINK) {
+ bredr_pairing(chan);
return;
+ }
if (!smp)
return;
@@ -2521,23 +2707,23 @@ static void smp_resume_cb(struct l2cap_chan *chan)
static void smp_ready_cb(struct l2cap_chan *chan)
{
struct l2cap_conn *conn = chan->conn;
+ struct hci_conn *hcon = conn->hcon;
BT_DBG("chan %p", chan);
conn->smp = chan;
l2cap_chan_hold(chan);
+
+ if (hcon->type == ACL_LINK && test_bit(HCI_CONN_ENCRYPT, &hcon->flags))
+ bredr_pairing(chan);
}
static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
{
- struct hci_conn *hcon = chan->conn->hcon;
int err;
BT_DBG("chan %p", chan);
- if (hcon->type == ACL_LINK)
- return -EOPNOTSUPP;
-
err = smp_sig_channel(chan, skb);
if (err) {
struct smp_chan *smp = chan->data;
--
2.1.0
next prev 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 ` [PATCH 30/49] Bluetooth: Add passkey entry support for " Johan Hedberg
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 ` Johan Hedberg [this message]
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-38-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).