From 39e3e74423a35bfc95b077fb65acaa00d1d39d64 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 20 Feb 2015 13:48:24 +0200 Subject: Bluetooth: Use hci_copy_identity_addr() helper for SMP chan creation The only reason the SMP code is essentially duplicating the hci_copy_identity_addr() function is that the helper returns the address type in the HCI format rather than the three-value format expected by l2cap_chan. This patch converts the SMP code to use the helper and then do a simple conversion from one address type to another. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index c09a821f381d..b2803bd6e0d8 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -2951,24 +2951,14 @@ create_chan: l2cap_chan_set_defaults(chan); if (cid == L2CAP_CID_SMP) { - /* If usage of static address is forced or if the devices - * does not have a public address, then listen on the static - * address. - * - * In case BR/EDR has been disabled on a dual-mode controller - * and a static address has been configued, then listen on - * the static address instead. - */ - if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags) || - !bacmp(&hdev->bdaddr, BDADDR_ANY) || - (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) && - bacmp(&hdev->static_addr, BDADDR_ANY))) { - bacpy(&chan->src, &hdev->static_addr); - chan->src_type = BDADDR_LE_RANDOM; - } else { - bacpy(&chan->src, &hdev->bdaddr); + u8 bdaddr_type; + + hci_copy_identity_address(hdev, &chan->src, &bdaddr_type); + + if (bdaddr_type == ADDR_LE_DEV_PUBLIC) chan->src_type = BDADDR_LE_PUBLIC; - } + else + chan->src_type = BDADDR_LE_RANDOM; } else { bacpy(&chan->src, &hdev->bdaddr); chan->src_type = BDADDR_BREDR; -- cgit From 4cd3928a8bee83d86fb3865bb243ab2ff1dd0eb6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Fri, 27 Feb 2015 10:11:13 +0200 Subject: Bluetooth: Update New CSRK event to match latest specification The 'master' parameter of the New CSRK event was recently renamed to 'type', with the old values kept for backwards compatibility as unauthenticated local/remote keys. This patch updates the code to take into account the two new (authenticated) values and ensures they get used based on the security level of the connection that the respective keys get distributed over. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index b2803bd6e0d8..c91c19bfc0a8 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1252,7 +1252,10 @@ static void smp_distribute_keys(struct smp_chan *smp) csrk = kzalloc(sizeof(*csrk), GFP_KERNEL); if (csrk) { - csrk->master = 0x00; + if (hcon->sec_level > BT_SECURITY_MEDIUM) + csrk->type = MGMT_CSRK_LOCAL_AUTHENTICATED; + else + csrk->type = MGMT_CSRK_LOCAL_UNAUTHENTICATED; memcpy(csrk->val, sign.csrk, sizeof(csrk->val)); } smp->slave_csrk = csrk; @@ -2352,7 +2355,10 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb) csrk = kzalloc(sizeof(*csrk), GFP_KERNEL); if (csrk) { - csrk->master = 0x01; + if (conn->hcon->sec_level > BT_SECURITY_MEDIUM) + csrk->type = MGMT_CSRK_REMOTE_AUTHENTICATED; + else + csrk->type = MGMT_CSRK_REMOTE_UNAUTHENTICATED; memcpy(csrk->val, rp->csrk, sizeof(csrk->val)); } smp->csrk = csrk; -- cgit From 983f9814c0199c26a58cbfe98f071e3bfa968839 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 11 Mar 2015 17:47:40 -0700 Subject: Bluetooth: Remove two else branches that are not needed The SMP code contains two else branches that are not needed since the successful test will actually leave the function. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/smp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index c91c19bfc0a8..d6ef7e48c2c3 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1743,10 +1743,10 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) 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); } + SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM); + /* Request setup of TK */ ret = tk_request(conn, 0, auth, rsp.io_capability, req->io_capability); if (ret) @@ -1926,8 +1926,8 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) if (test_bit(SMP_FLAG_TK_VALID, &smp->flags)) return smp_confirm(smp); - else - set_bit(SMP_FLAG_CFM_PENDING, &smp->flags); + + set_bit(SMP_FLAG_CFM_PENDING, &smp->flags); return 0; } -- cgit From d7a5a11d7fa80beb43d5f7cb421c86f9b4d21200 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 13 Mar 2015 02:11:00 -0700 Subject: Bluetooth: Introduce hci_dev_test_flag helper macro Instead of manually coding test_bit on hdev->dev_flags all the time, use hci_dev_test_flag helper macro. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/smp.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index d6ef7e48c2c3..81975f274c2b 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -52,7 +52,7 @@ #define SMP_TIMEOUT msecs_to_jiffies(30000) -#define AUTH_REQ_MASK(dev) (test_bit(HCI_SC_ENABLED, &(dev)->dev_flags) ? \ +#define AUTH_REQ_MASK(dev) (hci_dev_test_flag(dev, HCI_SC_ENABLED) ? \ 0x1f : 0x07) #define KEY_DIST_MASK 0x07 @@ -589,7 +589,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, struct hci_dev *hdev = hcon->hdev; u8 local_dist = 0, remote_dist = 0, oob_flag = SMP_OOB_NOT_PRESENT; - if (test_bit(HCI_BONDABLE, &conn->hcon->hdev->dev_flags)) { + if (hci_dev_test_flag(hdev, HCI_BONDABLE)) { local_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN; remote_dist = SMP_DIST_ENC_KEY | SMP_DIST_SIGN; authreq |= SMP_AUTH_BONDING; @@ -597,18 +597,18 @@ static void build_pairing_cmd(struct l2cap_conn *conn, authreq &= ~SMP_AUTH_BONDING; } - if (test_bit(HCI_RPA_RESOLVING, &hdev->dev_flags)) + if (hci_dev_test_flag(hdev, HCI_RPA_RESOLVING)) remote_dist |= SMP_DIST_ID_KEY; - if (test_bit(HCI_PRIVACY, &hdev->dev_flags)) + if (hci_dev_test_flag(hdev, HCI_PRIVACY)) local_dist |= SMP_DIST_ID_KEY; - if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags) && + if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) && (authreq & SMP_AUTH_SC)) { struct oob_data *oob_data; u8 bdaddr_type; - if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { + if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) { local_dist |= SMP_DIST_LINK_KEY; remote_dist |= SMP_DIST_LINK_KEY; } @@ -692,7 +692,7 @@ static void smp_chan_destroy(struct l2cap_conn *conn) * 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)) { + !hci_dev_test_flag(hcon->hdev, HCI_KEEP_DEBUG_KEYS)) { list_del_rcu(&smp->ltk->list); kfree_rcu(smp->ltk, rcu); smp->ltk = NULL; @@ -1052,7 +1052,7 @@ static void smp_notify_keys(struct l2cap_conn *conn) /* Don't keep debug keys around if the relevant * flag is not set. */ - if (!test_bit(HCI_KEEP_DEBUG_KEYS, &hdev->dev_flags) && + if (!hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS) && key->type == HCI_LK_DEBUG_COMBINATION) { list_del_rcu(&key->list); kfree_rcu(key, rcu); @@ -1604,15 +1604,15 @@ static void build_bredr_pairing_cmd(struct smp_chan *smp, struct hci_dev *hdev = conn->hcon->hdev; u8 local_dist = 0, remote_dist = 0; - if (test_bit(HCI_BONDABLE, &hdev->dev_flags)) { + if (hci_dev_test_flag(hdev, HCI_BONDABLE)) { 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)) + if (hci_dev_test_flag(hdev, HCI_RPA_RESOLVING)) remote_dist |= SMP_DIST_ID_KEY; - if (test_bit(HCI_PRIVACY, &hdev->dev_flags)) + if (hci_dev_test_flag(hdev, HCI_PRIVACY)) local_dist |= SMP_DIST_ID_KEY; if (!rsp) { @@ -1664,11 +1664,11 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) /* We didn't start the pairing, so match remote */ auth = req->auth_req & AUTH_REQ_MASK(hdev); - if (!test_bit(HCI_BONDABLE, &hdev->dev_flags) && + if (!hci_dev_test_flag(hdev, HCI_BONDABLE) && (auth & SMP_AUTH_BONDING)) return SMP_PAIRING_NOTSUPP; - if (test_bit(HCI_SC_ONLY, &hdev->dev_flags) && !(auth & SMP_AUTH_SC)) + if (hci_dev_test_flag(hdev, HCI_SC_ONLY) && !(auth & SMP_AUTH_SC)) return SMP_AUTH_REQUIREMENTS; smp->preq[0] = SMP_CMD_PAIRING_REQ; @@ -1761,7 +1761,7 @@ static u8 sc_send_public_key(struct smp_chan *smp) BT_DBG(""); - if (test_bit(HCI_USE_DEBUG_KEYS, &hdev->dev_flags)) { + if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS)) { BT_DBG("Using debug keys"); memcpy(smp->local_pk, debug_pk, 64); memcpy(smp->local_sk, debug_sk, 32); @@ -1816,7 +1816,7 @@ 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)) + if (hci_dev_test_flag(hdev, HCI_SC_ONLY) && !(auth & SMP_AUTH_SC)) return SMP_AUTH_REQUIREMENTS; smp->prsp[0] = SMP_CMD_PAIRING_RSP; @@ -2086,7 +2086,7 @@ 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)) + if (hci_dev_test_flag(hdev, HCI_SC_ONLY) && !(auth & SMP_AUTH_SC)) return SMP_AUTH_REQUIREMENTS; if (hcon->io_capability == HCI_IO_NO_INPUT_OUTPUT) @@ -2107,7 +2107,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) if (!smp) return SMP_UNSPECIFIED; - if (!test_bit(HCI_BONDABLE, &hcon->hdev->dev_flags) && + if (!hci_dev_test_flag(hdev, HCI_BONDABLE) && (auth & SMP_AUTH_BONDING)) return SMP_PAIRING_NOTSUPP; @@ -2141,7 +2141,7 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level) chan = conn->smp; - if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) + if (!hci_dev_test_flag(hcon->hdev, HCI_LE_ENABLED)) return 1; if (smp_sufficient_security(hcon, sec_level, SMP_USE_LTK)) @@ -2170,7 +2170,7 @@ 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)) + if (hci_dev_test_flag(hcon->hdev, HCI_SC_ENABLED)) authreq |= SMP_AUTH_SC; /* Require MITM if IO Capability allows or the security level @@ -2606,7 +2606,7 @@ static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb) if (skb->len < 1) return -EILSEQ; - if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) { + if (!hci_dev_test_flag(hcon->hdev, HCI_LE_ENABLED)) { reason = SMP_PAIRING_NOTSUPP; goto done; } @@ -2744,7 +2744,7 @@ static void bredr_pairing(struct l2cap_chan *chan) return; /* Secure Connections support must be enabled */ - if (!test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) + if (!hci_dev_test_flag(hdev, HCI_SC_ENABLED)) return; /* BR/EDR must use Secure Connections for SMP */ @@ -2753,7 +2753,7 @@ static void bredr_pairing(struct l2cap_chan *chan) return; /* If our LE support is not enabled don't do anything */ - if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) + if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED)) return; /* Don't bother if remote LE support is not enabled */ -- cgit From b7cb93e52839ee44959adabc17c2a17422e6bd4b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 13 Mar 2015 10:20:35 -0700 Subject: Bluetooth: Merge hdev->dbg_flags fields into hdev->dev_flags With the extension of hdev->dev_flags utilizing a bitmap now, the space is no longer restricted. Merge the hdev->dbg_flags into hdev->dev_flags to save space on 64-bit architectures. On 32-bit architectures no size reduction happens. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/smp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 81975f274c2b..9155840068cf 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1679,7 +1679,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) if (conn->hcon->type == ACL_LINK) { /* We must have a BR/EDR SC link */ if (!test_bit(HCI_CONN_AES_CCM, &conn->hcon->flags) && - !test_bit(HCI_FORCE_BREDR_SMP, &hdev->dbg_flags)) + !hci_dev_test_flag(hdev, HCI_FORCE_BREDR_SMP)) return SMP_CROSS_TRANSP_NOT_ALLOWED; set_bit(SMP_FLAG_SC, &smp->flags); @@ -2749,7 +2749,7 @@ static void bredr_pairing(struct l2cap_chan *chan) /* BR/EDR must use Secure Connections for SMP */ if (!test_bit(HCI_CONN_AES_CCM, &hcon->flags) && - !test_bit(HCI_FORCE_BREDR_SMP, &hdev->dbg_flags)) + !hci_dev_test_flag(hdev, HCI_FORCE_BREDR_SMP)) return; /* If our LE support is not enabled don't do anything */ @@ -3003,7 +3003,7 @@ static ssize_t force_bredr_smp_read(struct file *file, struct hci_dev *hdev = file->private_data; char buf[3]; - buf[0] = test_bit(HCI_FORCE_BREDR_SMP, &hdev->dbg_flags) ? 'Y': 'N'; + buf[0] = hci_dev_test_flag(hdev, HCI_FORCE_BREDR_SMP) ? 'Y': 'N'; buf[1] = '\n'; buf[2] = '\0'; return simple_read_from_buffer(user_buf, count, ppos, buf, 2); @@ -3025,7 +3025,7 @@ static ssize_t force_bredr_smp_write(struct file *file, if (strtobool(buf, &enable)) return -EINVAL; - if (enable == test_bit(HCI_FORCE_BREDR_SMP, &hdev->dbg_flags)) + if (enable == hci_dev_test_flag(hdev, HCI_FORCE_BREDR_SMP)) return -EALREADY; if (enable) { @@ -3044,7 +3044,7 @@ static ssize_t force_bredr_smp_write(struct file *file, smp_del_chan(chan); } - change_bit(HCI_FORCE_BREDR_SMP, &hdev->dbg_flags); + hci_dev_change_flag(hdev, HCI_FORCE_BREDR_SMP); return count; } -- cgit From 276812ec3e945493443e399921a07e9d6aa4d5b2 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 16 Mar 2015 01:10:18 -0700 Subject: Bluetooth: Use kzfree instead of kfree in security manager Within the security manager, it makes sense to use kzfree instead of kfree for all data structures. This ensures that no key material leaks by accident. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/smp.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 9155840068cf..a2be6fcc3c51 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -681,9 +681,9 @@ static void smp_chan_destroy(struct l2cap_conn *conn) complete = test_bit(SMP_FLAG_COMPLETE, &smp->flags); mgmt_smp_complete(hcon, complete); - kfree(smp->csrk); - kfree(smp->slave_csrk); - kfree(smp->link_key); + kzfree(smp->csrk); + kzfree(smp->slave_csrk); + kzfree(smp->link_key); crypto_free_blkcipher(smp->tfm_aes); crypto_free_hash(smp->tfm_cmac); @@ -717,7 +717,7 @@ static void smp_chan_destroy(struct l2cap_conn *conn) } chan->data = NULL; - kfree(smp); + kzfree(smp); hci_conn_drop(hcon); } @@ -1097,13 +1097,13 @@ static void sc_generate_link_key(struct smp_chan *smp) return; if (smp_h6(smp->tfm_cmac, smp->tk, tmp1, smp->link_key)) { - kfree(smp->link_key); + kzfree(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); + kzfree(smp->link_key); smp->link_key = NULL; return; } @@ -1300,7 +1300,7 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) smp->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(smp->tfm_aes)) { BT_ERR("Unable to create ECB crypto context"); - kfree(smp); + kzfree(smp); return NULL; } @@ -1308,7 +1308,7 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn) if (IS_ERR(smp->tfm_cmac)) { BT_ERR("Unable to create CMAC crypto context"); crypto_free_blkcipher(smp->tfm_aes); - kfree(smp); + kzfree(smp); return NULL; } -- cgit From 88a479d9507eb7a510a612705aa686c52d24b2ab Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 16 Mar 2015 01:10:19 -0700 Subject: Bluetooth: Create SMP device structure for local crypto context Every Bluetooth Low Energy controller requires a local crypto context to handle the resolvable private addresses. At the moment this is just a single crypto context, but for out-of-band data generation it will require an additional. To facility this, create a struct smp_dev that will hold all the extra information. This patch is just the refactoring in preparation for future changes. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/smp.c | 47 +++++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 16 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index a2be6fcc3c51..952ba6376e1c 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -73,6 +73,10 @@ enum { SMP_FLAG_OOB, }; +struct smp_dev { + struct crypto_blkcipher *tfm_aes; +}; + struct smp_chan { struct l2cap_conn *conn; struct delayed_work security_timer; @@ -478,18 +482,18 @@ 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; + struct smp_dev *smp; u8 hash[3]; int err; if (!chan || !chan->data) return false; - tfm = chan->data; + smp = chan->data; BT_DBG("RPA %pMR IRK %*phN", bdaddr, 16, irk); - err = smp_ah(tfm, irk, &bdaddr->b[3], hash); + err = smp_ah(smp->tfm_aes, irk, &bdaddr->b[3], hash); if (err) return false; @@ -499,20 +503,20 @@ bool smp_irk_matches(struct hci_dev *hdev, const u8 irk[16], 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; + struct smp_dev *smp; int err; if (!chan || !chan->data) return -EOPNOTSUPP; - tfm = chan->data; + smp = chan->data; get_random_bytes(&rpa->b[3], 3); rpa->b[5] &= 0x3f; /* Clear two most significant bits */ rpa->b[5] |= 0x40; /* Set second most significant bit */ - err = smp_ah(tfm, irk, &rpa->b[3], rpa->b); + err = smp_ah(smp->tfm_aes, irk, &rpa->b[3], rpa->b); if (err < 0) return err; @@ -2930,27 +2934,36 @@ static const struct l2cap_ops smp_root_chan_ops = { static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid) { struct l2cap_chan *chan; - struct crypto_blkcipher *tfm_aes; + struct smp_dev *smp; + struct crypto_blkcipher *tfm_aes; if (cid == L2CAP_CID_SMP_BREDR) { - tfm_aes = NULL; + smp = NULL; goto create_chan; } - tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, 0); + smp = kzalloc(sizeof(*smp), GFP_KERNEL); + if (!smp) + return ERR_PTR(-ENOMEM); + + tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(tfm_aes)) { - BT_ERR("Unable to create crypto context"); + BT_ERR("Unable to create ECB crypto context"); + kzfree(smp); return ERR_CAST(tfm_aes); } + smp->tfm_aes = tfm_aes; + create_chan: chan = l2cap_chan_create(); if (!chan) { - crypto_free_blkcipher(tfm_aes); + crypto_free_blkcipher(smp->tfm_aes); + kzfree(smp); return ERR_PTR(-ENOMEM); } - chan->data = tfm_aes; + chan->data = smp; l2cap_add_scid(chan, cid); @@ -2983,14 +2996,16 @@ create_chan: static void smp_del_chan(struct l2cap_chan *chan) { - struct crypto_blkcipher *tfm_aes; + struct smp_dev *smp; BT_DBG("chan %p", chan); - tfm_aes = chan->data; - if (tfm_aes) { + smp = chan->data; + if (smp) { chan->data = NULL; - crypto_free_blkcipher(tfm_aes); + if (smp->tfm_aes) + crypto_free_blkcipher(smp->tfm_aes); + kzfree(smp); } l2cap_chan_put(chan); -- cgit From 6e2dc6d1133f5f8bfd028ba7d1c3fb0b3fa717e9 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 16 Mar 2015 01:10:21 -0700 Subject: Bluetooth: Add support for AES-CMAC hash for security manager device The security manager device will require the use of AES-CMAC hash for out-of-band data generation. This patch makes sure it is correctly set up and available. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/smp.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 952ba6376e1c..12e9c833885b 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -75,6 +75,7 @@ enum { struct smp_dev { struct crypto_blkcipher *tfm_aes; + struct crypto_hash *tfm_cmac; }; struct smp_chan { @@ -2936,6 +2937,7 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid) struct l2cap_chan *chan; struct smp_dev *smp; struct crypto_blkcipher *tfm_aes; + struct crypto_hash *tfm_cmac; if (cid == L2CAP_CID_SMP_BREDR) { smp = NULL; @@ -2953,12 +2955,22 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid) return ERR_CAST(tfm_aes); } + tfm_cmac = crypto_alloc_hash("cmac(aes)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm_cmac)) { + BT_ERR("Unable to create CMAC crypto context"); + crypto_free_blkcipher(tfm_aes); + kzfree(smp); + return ERR_CAST(tfm_cmac); + } + smp->tfm_aes = tfm_aes; + smp->tfm_cmac = tfm_cmac; create_chan: chan = l2cap_chan_create(); if (!chan) { crypto_free_blkcipher(smp->tfm_aes); + crypto_free_hash(smp->tfm_cmac); kzfree(smp); return ERR_PTR(-ENOMEM); } @@ -3005,6 +3017,8 @@ static void smp_del_chan(struct l2cap_chan *chan) chan->data = NULL; if (smp->tfm_aes) crypto_free_blkcipher(smp->tfm_aes); + if (smp->tfm_cmac) + crypto_free_hash(smp->tfm_cmac); kzfree(smp); } -- cgit From 60a27d653d972584e5e98ab3558c62c3d3bc547a Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 16 Mar 2015 01:10:22 -0700 Subject: Bluetooth: Add function for generating LE SC out-of-band data This patch adds a smp_generate_oob function that allows to create local out-of-band data that can be used for pairing and also provides the confirmation and random value. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/smp.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 12e9c833885b..1669e7127e2e 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -74,6 +74,12 @@ enum { }; struct smp_dev { + /* Secure Connections OOB data */ + u8 local_pk[64]; + u8 local_sk[32]; + u8 local_rr[16]; + bool debug_key; + struct crypto_blkcipher *tfm_aes; struct crypto_hash *tfm_cmac; }; @@ -526,6 +532,53 @@ int smp_generate_rpa(struct hci_dev *hdev, const u8 irk[16], bdaddr_t *rpa) return 0; } +int smp_generate_oob(struct hci_dev *hdev, u8 hash[16], u8 rand[16]) +{ + struct l2cap_chan *chan = hdev->smp_data; + struct smp_dev *smp; + int err; + + if (!chan || !chan->data) + return -EOPNOTSUPP; + + smp = chan->data; + + if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS)) { + BT_DBG("Using debug keys"); + memcpy(smp->local_pk, debug_pk, 64); + memcpy(smp->local_sk, debug_sk, 32); + smp->debug_key = true; + } else { + while (true) { + /* Generate local key pair for Secure Connections */ + if (!ecc_make_key(smp->local_pk, smp->local_sk)) + return -EIO; + + /* 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; + } + smp->debug_key = false; + } + + SMP_DBG("OOB Public Key X: %32phN", smp->local_pk); + SMP_DBG("OOB Public Key Y: %32phN", smp->local_pk + 32); + SMP_DBG("OOB Private Key: %32phN", smp->local_sk); + + get_random_bytes(smp->local_rr, 16); + + err = smp_f4(smp->tfm_cmac, smp->local_pk, smp->local_pk, + smp->local_rr, 0, hash); + if (err < 0) + return err; + + memcpy(rand, smp->local_rr, 16); + + return 0; +} + static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data) { struct l2cap_chan *chan = conn->smp; -- cgit From 33d0c030717bd939dab467f95966d8a64187e5c1 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 16 Mar 2015 01:10:24 -0700 Subject: Bluetooth: Use OOB key pair for LE SC pairing with OOB method The OOB public and secret key pair is different from the non-OOB pairing procedure. SO when OOB method is in use, then use this key pair instead of generating a new one. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/smp.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 1669e7127e2e..0fcd8c8f1a6b 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1819,6 +1819,25 @@ static u8 sc_send_public_key(struct smp_chan *smp) BT_DBG(""); + if (test_bit(SMP_FLAG_OOB, &smp->flags)) { + struct l2cap_chan *chan = hdev->smp_data; + struct smp_dev *smp_dev; + + if (!chan || !chan->data) + return SMP_UNSPECIFIED; + + smp_dev = chan->data; + + memcpy(smp->local_pk, smp_dev->local_pk, 64); + memcpy(smp->local_sk, smp_dev->local_sk, 32); + memcpy(smp->rr, smp_dev->local_rr, 16); + + if (smp_dev->debug_key) + set_bit(SMP_FLAG_DEBUG_KEY, &smp->flags); + + goto done; + } + if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS)) { BT_DBG("Using debug keys"); memcpy(smp->local_pk, debug_pk, 64); @@ -1838,6 +1857,7 @@ static u8 sc_send_public_key(struct smp_chan *smp) } } +done: 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); -- cgit From 8e4e2ee5d80875177e03d57b807e0784f3d91e0e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 16 Mar 2015 01:10:25 -0700 Subject: Bluetooth: Use smp->local_pk + 32 instead of &smp->local_pk[32] Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 0fcd8c8f1a6b..f0c5c2827372 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1859,7 +1859,7 @@ static u8 sc_send_public_key(struct smp_chan *smp) done: SMP_DBG("Local Public Key X: %32phN", smp->local_pk); - SMP_DBG("Local Public Key Y: %32phN", &smp->local_pk[32]); + 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); -- cgit From 882fafad71a4bac8e8a2445dfb08c38a71b4eef1 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Mar 2015 11:45:43 +0200 Subject: Bluetooth: Fix local OOB data handling for SMP We need to store the local ra/rb value in order to verify the Check value received from the remote. This patch adds a new 'lr' for the local ra/rb value and makes sure it gets used when verifying the DHKey Check PDU received from the remote. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index f0c5c2827372..1cc15de6ff1e 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -95,7 +95,8 @@ 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 rr[16]; /* Remote OOB ra/rb value */ + u8 lr[16]; /* Local OOB ra/rb value */ u8 enc_key_size; u8 remote_key_dist; bdaddr_t id_addr; @@ -1830,7 +1831,7 @@ static u8 sc_send_public_key(struct smp_chan *smp) memcpy(smp->local_pk, smp_dev->local_pk, 64); memcpy(smp->local_sk, smp_dev->local_sk, 32); - memcpy(smp->rr, smp_dev->local_rr, 16); + memcpy(smp->lr, smp_dev->local_rr, 16); if (smp_dev->debug_key) set_bit(SMP_FLAG_DEBUG_KEY, &smp->flags); @@ -2634,6 +2635,8 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb) if (smp->method == REQ_PASSKEY || smp->method == DSP_PASSKEY) put_unaligned_le32(hcon->passkey_notify, r); + else if (smp->method == REQ_OOB) + memcpy(r, smp->lr, 16); err = smp_f6(smp->tfm_cmac, smp->mackey, smp->rrnd, smp->prnd, r, io_cap, remote_addr, local_addr, e); -- cgit From 1a8bab4f390130268e5384ccf1bde47925102c72 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Mar 2015 11:45:44 +0200 Subject: Bluetooth: Track local vs remote OOB data availability There are several decisions in the SMP logic that depend not only on whether we're doing SMP or not, but also whether local and/or remote OOB data is present. This patch splits the existing SMP_FLAG_OOB into two new flags to track local and remote OOB data respectively. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 1cc15de6ff1e..c8382f4fcd5c 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -70,7 +70,8 @@ enum { SMP_FLAG_DEBUG_KEY, SMP_FLAG_WAIT_USER, SMP_FLAG_DHKEY_PENDING, - SMP_FLAG_OOB, + SMP_FLAG_REMOTE_OOB, + SMP_FLAG_LOCAL_OOB, }; struct smp_dev { @@ -680,7 +681,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, oob_data = hci_find_remote_oob_data(hdev, &hcon->dst, bdaddr_type); if (oob_data && oob_data->present) { - set_bit(SMP_FLAG_OOB, &smp->flags); + set_bit(SMP_FLAG_REMOTE_OOB, &smp->flags); oob_flag = SMP_OOB_PRESENT; memcpy(smp->rr, oob_data->rand256, 16); memcpy(smp->pcnf, oob_data->hash256, 16); @@ -1820,7 +1821,7 @@ static u8 sc_send_public_key(struct smp_chan *smp) BT_DBG(""); - if (test_bit(SMP_FLAG_OOB, &smp->flags)) { + if (test_bit(SMP_FLAG_LOCAL_OOB, &smp->flags)) { struct l2cap_chan *chan = hdev->smp_data; struct smp_dev *smp_dev; @@ -2453,7 +2454,8 @@ 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)) + if (test_bit(SMP_FLAG_REMOTE_OOB, &smp->flags) || + test_bit(SMP_FLAG_LOCAL_OOB, &smp->flags)) return REQ_OOB; /* The preq/prsp contain the raw Pairing Request/Response PDUs -- cgit From 58428563b5ea19c2ac8b6aca8073e48539023b26 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Mar 2015 11:45:45 +0200 Subject: Bluetooth: Set local OOB data flag if remote has our OOB data If the SMP Pairing Request or Response PDU received from the remote device indicates that it has received our OOB data we should set the SMP_FLAG_LOCAL_OOB flag. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index c8382f4fcd5c..b8a6ce840603 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1735,6 +1735,9 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) memcpy(&smp->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); + if (req->oob_flag == SMP_OOB_PRESENT) + set_bit(SMP_FLAG_LOCAL_OOB, &smp->flags); + /* SMP over BR/EDR requires special treatment */ if (conn->hcon->type == ACL_LINK) { /* We must have a BR/EDR SC link */ @@ -1899,6 +1902,9 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) if (hci_dev_test_flag(hdev, HCI_SC_ONLY) && !(auth & SMP_AUTH_SC)) return SMP_AUTH_REQUIREMENTS; + if (rsp->oob_flag == SMP_OOB_PRESENT) + set_bit(SMP_FLAG_LOCAL_OOB, &smp->flags); + smp->prsp[0] = SMP_CMD_PAIRING_RSP; memcpy(&smp->prsp[1], rsp, sizeof(*rsp)); -- cgit From 94ea7257ef24a007cb0e26476ed8871f179a749f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Mar 2015 11:45:46 +0200 Subject: Bluetooth: Fix verifying confirm value when lacking remote OOB data If we haven't received remote OOB data we cannot perform any special checks on the confirm value. This patch updates the check after having received the public key to only perform the verification if we have remote OOB data present. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index b8a6ce840603..de53ba1905fe 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -2562,7 +2562,7 @@ 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) { + if (test_bit(SMP_FLAG_REMOTE_OOB, &smp->flags)) { err = smp_f4(smp->tfm_cmac, smp->remote_pk, smp->remote_pk, smp->rr, 0, cfm.confirm_val); if (err) @@ -2570,7 +2570,9 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb) if (memcmp(cfm.confirm_val, smp->pcnf, 16)) return SMP_CONFIRM_FAILED; + } + if (smp->method == REQ_OOB) { if (hcon->out) smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd), smp->prnd); -- cgit From a8ca617c1356cafa669dc467a386787cc1d83809 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Mar 2015 18:12:57 +0200 Subject: Bluetooth: Don't send public key if OOB data verification fails When we receive the remote public key, if we have remote OOB data there's no point in sending our public key to the remote if the OOB data doesn't match. This patch moves the test for this higher up in the smp_cmd_public_key() function. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index de53ba1905fe..82824213d0fb 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -2515,6 +2515,16 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb) memcpy(smp->remote_pk, key, 64); + if (test_bit(SMP_FLAG_REMOTE_OOB, &smp->flags)) { + err = smp_f4(smp->tfm_cmac, smp->remote_pk, smp->remote_pk, + smp->rr, 0, cfm.confirm_val); + if (err) + return SMP_UNSPECIFIED; + + if (memcmp(cfm.confirm_val, smp->pcnf, 16)) + return SMP_CONFIRM_FAILED; + } + /* Non-initiating device sends its public key after receiving * the key from the initiating device. */ @@ -2562,16 +2572,6 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb) return sc_passkey_round(smp, SMP_CMD_PUBLIC_KEY); } - if (test_bit(SMP_FLAG_REMOTE_OOB, &smp->flags)) { - err = smp_f4(smp->tfm_cmac, smp->remote_pk, smp->remote_pk, - smp->rr, 0, cfm.confirm_val); - if (err) - return SMP_UNSPECIFIED; - - if (memcmp(cfm.confirm_val, smp->pcnf, 16)) - return SMP_CONFIRM_FAILED; - } - if (smp->method == REQ_OOB) { if (hcon->out) smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, -- cgit From cb06d366fbf88f3923951d862f8c5b03fb483b43 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 16 Mar 2015 21:12:34 +0200 Subject: Bluetooth: Add clarifying comment when setting local OOB flag It might be a bit counterintuitive to set a 'local' flag based on remote data. This patch adds a clarifying comment to the pairing req/rsp handlers when setting the LOCAL_OOB flag based on the PDU received from the remote side. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 82824213d0fb..1bd281060de2 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1735,6 +1735,10 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) memcpy(&smp->preq[1], req, sizeof(*req)); skb_pull(skb, sizeof(*req)); + /* If the remote side's OOB flag is set it means it has + * successfully received our local OOB data - therefore set the + * flag to indicate that local OOB is in use. + */ if (req->oob_flag == SMP_OOB_PRESENT) set_bit(SMP_FLAG_LOCAL_OOB, &smp->flags); @@ -1902,6 +1906,10 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) if (hci_dev_test_flag(hdev, HCI_SC_ONLY) && !(auth & SMP_AUTH_SC)) return SMP_AUTH_REQUIREMENTS; + /* If the remote side's OOB flag is set it means it has + * successfully received our local OOB data - therefore set the + * flag to indicate that local OOB is in use. + */ if (rsp->oob_flag == SMP_OOB_PRESENT) set_bit(SMP_FLAG_LOCAL_OOB, &smp->flags); -- cgit From e091526dfdaa955a7481a696094ac9e5d1bdb0fe Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 16 Mar 2015 12:34:55 -0700 Subject: Bluetooth: Use smp->remote_pk + 32 instead of &smp->remote_pk[32] Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 1bd281060de2..2b5c13932b0a 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -2543,7 +2543,7 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb) } SMP_DBG("Remote Public Key X: %32phN", smp->remote_pk); - SMP_DBG("Remote Public Key Y: %32phN", &smp->remote_pk[32]); + SMP_DBG("Remote Public Key Y: %32phN", smp->remote_pk + 32); if (!ecdh_shared_secret(smp->remote_pk, smp->local_sk, smp->dhkey)) return SMP_UNSPECIFIED; -- cgit From bc07cd696e1863d082fdc8650351b288bd41629b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 16 Mar 2015 12:34:56 -0700 Subject: Bluetooth: Add extra SMP_DBG statement for remote OOB data Just for pure debugging purposes print the remote out-of-band data that has been received and is going to be used. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/smp.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 2b5c13932b0a..ebe69e91fb6c 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -685,6 +685,8 @@ static void build_pairing_cmd(struct l2cap_conn *conn, oob_flag = SMP_OOB_PRESENT; memcpy(smp->rr, oob_data->rand256, 16); memcpy(smp->pcnf, oob_data->hash256, 16); + SMP_DBG("OOB Remote Confirmation: %16phN", smp->pcnf); + SMP_DBG("OOB Remote Random: %16phN", smp->rr); } } else { -- cgit From fb334fee60ebd1aea23cc5daf3abac10139c9a24 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 16 Mar 2015 12:34:57 -0700 Subject: Bluetooth: Rename smp->local_rr into smp->local_rand The variable for the out-of-band random number was badly named and with that confusing. Just rename it to local_rand so it is clear what value it represents. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/smp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index ebe69e91fb6c..60180b47ce71 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -78,7 +78,7 @@ struct smp_dev { /* Secure Connections OOB data */ u8 local_pk[64]; u8 local_sk[32]; - u8 local_rr[16]; + u8 local_rand[16]; bool debug_key; struct crypto_blkcipher *tfm_aes; @@ -569,14 +569,14 @@ int smp_generate_oob(struct hci_dev *hdev, u8 hash[16], u8 rand[16]) SMP_DBG("OOB Public Key Y: %32phN", smp->local_pk + 32); SMP_DBG("OOB Private Key: %32phN", smp->local_sk); - get_random_bytes(smp->local_rr, 16); + get_random_bytes(smp->local_rand, 16); err = smp_f4(smp->tfm_cmac, smp->local_pk, smp->local_pk, - smp->local_rr, 0, hash); + smp->local_rand, 0, hash); if (err < 0) return err; - memcpy(rand, smp->local_rr, 16); + memcpy(rand, smp->local_rand, 16); return 0; } @@ -1841,7 +1841,7 @@ static u8 sc_send_public_key(struct smp_chan *smp) memcpy(smp->local_pk, smp_dev->local_pk, 64); memcpy(smp->local_sk, smp_dev->local_sk, 32); - memcpy(smp->lr, smp_dev->local_rr, 16); + memcpy(smp->lr, smp_dev->local_rand, 16); if (smp_dev->debug_key) set_bit(SMP_FLAG_DEBUG_KEY, &smp->flags); -- cgit From 19c5ce9c5ff80a26cba3afb3684d56539444ee40 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 15 Mar 2015 19:34:04 +0200 Subject: Bluetooth: Add workaround for broken OS X legacy SMP pairing OS X version 10.10.2 (and possibly older versions) doesn't support LE Secure Connections but incorrectly copies all authentication request bits from a Security Request to its Pairing Request. The result is that an SC capable initiator (such as BlueZ) will think OS X intends to do SC when in fact it's incapable of it: < ACL Data TX: Handle 3585 flags 0x00 dlen 6 SMP: Security Request (0x0b) len 1 Authentication requirement: Bonding, No MITM, SC, No Keypresses (0x09) > ACL Data RX: Handle 3585 flags 0x02 dlen 11 SMP: Pairing Request (0x01) len 6 IO capability: KeyboardDisplay (0x04) OOB data: Authentication data not present (0x00) Authentication requirement: Bonding, No MITM, SC, No Keypresses (0x09) Max encryption key size: 16 Initiator key distribution: EncKey (0x01) Responder key distribution: EncKey IdKey Sign (0x07) < ACL Data TX: Handle 3585 flags 0x00 dlen 11 SMP: Pairing Response (0x02) len 6 IO capability: NoInputNoOutput (0x03) OOB data: Authentication data not present (0x00) Authentication requirement: Bonding, No MITM, SC, No Keypresses (0x09) Max encryption key size: 16 Initiator key distribution: EncKey (0x01) Responder key distribution: EncKey Sign (0x05) The pairing eventually fails when we get an unexpected Pairing Confirm PDU instead of a Public Key PDU: > ACL Data RX: Handle 3585 flags 0x02 dlen 21 SMP: Pairing Confirm (0x03) len 16 Confim value: bcc3bed31b8f313a78ec3cce32685faf It is only at this point that we can speculate that the remote doesn't really support SC. This patch creates a workaround for the just-works model, however the MITM case is unsolvable because the OS X user has already been requested to enter a PIN which we're now expected to randomly generate and show the user (i.e. a chicken-and-egg problem). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 8 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 60180b47ce71..6a5afb972358 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -880,6 +880,12 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth, return 0; } + /* If this function is used for SC -> legacy fallback we + * can only recover the just-works case. + */ + if (test_bit(SMP_FLAG_SC, &smp->flags)) + return -EINVAL; + /* Not Just Works/Confirm results in MITM Authentication */ if (smp->method != JUST_CFM) { set_bit(SMP_FLAG_MITM_AUTH, &smp->flags); @@ -1806,6 +1812,13 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) clear_bit(SMP_FLAG_INITIATOR, &smp->flags); + /* Strictly speaking we shouldn't allow Pairing Confirm for the + * SC case, however some implementations incorrectly copy RFU auth + * req bits from our security request, which may create a false + * positive SC enablement. + */ + SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM); + if (test_bit(SMP_FLAG_SC, &smp->flags)) { SMP_ALLOW_CMD(smp, SMP_CMD_PUBLIC_KEY); /* Clear bits which are generated but not distributed */ @@ -1814,8 +1827,6 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb) return 0; } - SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_CONFIRM); - /* Request setup of TK */ ret = tk_request(conn, 0, auth, rsp.io_capability, req->io_capability); if (ret) @@ -1981,10 +1992,6 @@ static u8 sc_check_confirm(struct smp_chan *smp) BT_DBG(""); - /* Public Key exchange must happen before any other steps */ - if (!test_bit(SMP_FLAG_REMOTE_PK, &smp->flags)) - return SMP_UNSPECIFIED; - if (smp->method == REQ_PASSKEY || smp->method == DSP_PASSKEY) return sc_passkey_round(smp, SMP_CMD_PAIRING_CONFIRM); @@ -1997,6 +2004,47 @@ static u8 sc_check_confirm(struct smp_chan *smp) return 0; } +/* Work-around for some implementations that incorrectly copy RFU bits + * from our security request and thereby create the impression that + * we're doing SC when in fact the remote doesn't support it. + */ +static int fixup_sc_false_positive(struct smp_chan *smp) +{ + struct l2cap_conn *conn = smp->conn; + struct hci_conn *hcon = conn->hcon; + struct hci_dev *hdev = hcon->hdev; + struct smp_cmd_pairing *req, *rsp; + u8 auth; + + /* The issue is only observed when we're in slave role */ + if (hcon->out) + return SMP_UNSPECIFIED; + + if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) { + BT_ERR("Refusing SMP SC -> legacy fallback in SC-only mode"); + return SMP_UNSPECIFIED; + } + + BT_ERR("Trying to fall back to legacy SMP"); + + req = (void *) &smp->preq[1]; + rsp = (void *) &smp->prsp[1]; + + /* Rebuild key dist flags which may have been cleared for SC */ + smp->remote_key_dist = (req->init_key_dist & rsp->resp_key_dist); + + auth = req->auth_req & AUTH_REQ_MASK(hdev); + + if (tk_request(conn, 0, auth, rsp->io_capability, req->io_capability)) { + BT_ERR("Failed to fall back to legacy SMP"); + return SMP_UNSPECIFIED; + } + + clear_bit(SMP_FLAG_SC, &smp->flags); + + return 0; +} + static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) { struct l2cap_chan *chan = conn->smp; @@ -2010,8 +2058,19 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb) memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf)); skb_pull(skb, sizeof(smp->pcnf)); - if (test_bit(SMP_FLAG_SC, &smp->flags)) - return sc_check_confirm(smp); + if (test_bit(SMP_FLAG_SC, &smp->flags)) { + int ret; + + /* Public Key exchange must happen before any other steps */ + if (test_bit(SMP_FLAG_REMOTE_PK, &smp->flags)) + return sc_check_confirm(smp); + + BT_ERR("Unexpected SMP Pairing Confirm"); + + ret = fixup_sc_false_positive(smp); + if (ret) + return ret; + } if (conn->hcon->out) { smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd), -- cgit From 63511f6d5ba0c20850448991be297751ddb6798c Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 17 Mar 2015 11:38:24 -0700 Subject: Bluetooth: Fix potential NULL dereference in SMP channel setup When the allocation of the L2CAP channel for the BR/EDR security manager fails, then the smp variable might be NULL. In that case do not try to free the non-existing crypto contexts Reported-by: Dan Carpenter Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/smp.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 6a5afb972358..1ec3f66b5a74 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -3124,9 +3124,11 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid) create_chan: chan = l2cap_chan_create(); if (!chan) { - crypto_free_blkcipher(smp->tfm_aes); - crypto_free_hash(smp->tfm_cmac); - kzfree(smp); + if (smp) { + crypto_free_blkcipher(smp->tfm_aes); + crypto_free_hash(smp->tfm_cmac); + kzfree(smp); + } return ERR_PTR(-ENOMEM); } -- cgit From a4368ff3ed3b57e4b5e36d83b75604f68bbcdaad Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 30 Mar 2015 23:21:01 +0300 Subject: Bluetooth: Refactor L2CAP variables into l2cap_ctrl We're getting very close to the maximum possible size of bt_skb_cb. To prepare to shrink the struct with the help of a union this patch moves all L2CAP related variables into the l2cap_ctrl struct. To later add other 'ctrl' structs the L2CAP one is renamed simple 'l2cap' instead of 'control'. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 1ec3f66b5a74..1910c5806974 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -3017,7 +3017,7 @@ static struct sk_buff *smp_alloc_skb_cb(struct l2cap_chan *chan, return ERR_PTR(-ENOMEM); skb->priority = HCI_PRIO_MAX; - bt_cb(skb)->chan = chan; + bt_cb(skb)->l2cap.chan = chan; return skb; } -- cgit From 64dd374eac154f747623b256c59ecaf5affba724 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 1 Apr 2015 12:52:13 -0700 Subject: Bluetooth: Export SMP selftest result in debugfs When SMP selftest is enabled, then besides printing the result into the kernel message buffer, also create a debugfs file that allows retrieving the same information. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- net/bluetooth/smp.c | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) (limited to 'net/bluetooth/smp.c') diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 1910c5806974..1ab3dc9c8f99 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -3549,6 +3549,21 @@ static int __init test_h6(struct crypto_hash *tfm_cmac) return 0; } +static char test_smp_buffer[32]; + +static ssize_t test_smp_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + return simple_read_from_buffer(user_buf, count, ppos, test_smp_buffer, + strlen(test_smp_buffer)); +} + +static const struct file_operations test_smp_fops = { + .open = simple_open, + .read = test_smp_read, + .llseek = default_llseek, +}; + static int __init run_selftests(struct crypto_blkcipher *tfm_aes, struct crypto_hash *tfm_cmac) { @@ -3561,49 +3576,49 @@ static int __init run_selftests(struct crypto_blkcipher *tfm_aes, err = test_ah(tfm_aes); if (err) { BT_ERR("smp_ah test failed"); - return err; + goto done; } err = test_c1(tfm_aes); if (err) { BT_ERR("smp_c1 test failed"); - return err; + goto done; } err = test_s1(tfm_aes); if (err) { BT_ERR("smp_s1 test failed"); - return err; + goto done; } err = test_f4(tfm_cmac); if (err) { BT_ERR("smp_f4 test failed"); - return err; + goto done; } err = test_f5(tfm_cmac); if (err) { BT_ERR("smp_f5 test failed"); - return err; + goto done; } err = test_f6(tfm_cmac); if (err) { BT_ERR("smp_f6 test failed"); - return err; + goto done; } err = test_g2(tfm_cmac); if (err) { BT_ERR("smp_g2 test failed"); - return err; + goto done; } err = test_h6(tfm_cmac); if (err) { BT_ERR("smp_h6 test failed"); - return err; + goto done; } rettime = ktime_get(); @@ -3612,7 +3627,17 @@ static int __init run_selftests(struct crypto_blkcipher *tfm_aes, BT_INFO("SMP test passed in %llu usecs", duration); - return 0; +done: + if (!err) + snprintf(test_smp_buffer, sizeof(test_smp_buffer), + "PASS (%llu usecs)\n", duration); + else + snprintf(test_smp_buffer, sizeof(test_smp_buffer), "FAIL\n"); + + debugfs_create_file("selftest_smp", 0444, bt_debugfs, NULL, + &test_smp_fops); + + return err; } int __init bt_selftest_smp(void) -- cgit