summaryrefslogtreecommitdiffstats
path: root/kernel/net/bluetooth/smp.c
diff options
context:
space:
mode:
authorJosé Pekkarinen <jose.pekkarinen@nokia.com>2016-04-11 10:41:07 +0300
committerJosé Pekkarinen <jose.pekkarinen@nokia.com>2016-04-13 08:17:18 +0300
commite09b41010ba33a20a87472ee821fa407a5b8da36 (patch)
treed10dc367189862e7ca5c592f033dc3726e1df4e3 /kernel/net/bluetooth/smp.c
parentf93b97fd65072de626c074dbe099a1fff05ce060 (diff)
These changes are the raw update to linux-4.4.6-rt14. Kernel sources
are taken from kernel.org, and rt patch from the rt wiki download page. During the rebasing, the following patch collided: Force tick interrupt and get rid of softirq magic(I70131fb85). Collisions have been removed because its logic was found on the source already. Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769 Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'kernel/net/bluetooth/smp.c')
-rw-r--r--kernel/net/bluetooth/smp.c253
1 files changed, 190 insertions, 63 deletions
diff --git a/kernel/net/bluetooth/smp.c b/kernel/net/bluetooth/smp.c
index 7b815bcc8..4b175df35 100644
--- a/kernel/net/bluetooth/smp.c
+++ b/kernel/net/bluetooth/smp.c
@@ -33,6 +33,9 @@
#include "ecc.h"
#include "smp.h"
+#define SMP_DEV(hdev) \
+ ((struct smp_dev *)((struct l2cap_chan *)((hdev)->smp_data))->data)
+
/* 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.
@@ -81,6 +84,9 @@ struct smp_dev {
u8 local_rand[16];
bool debug_key;
+ u8 min_key_size;
+ u8 max_key_size;
+
struct crypto_blkcipher *tfm_aes;
struct crypto_hash *tfm_cmac;
};
@@ -371,6 +377,8 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
uint8_t tmp[16], data[16];
int err;
+ SMP_DBG("k %16phN r %16phN", k, r);
+
if (!tfm) {
BT_ERR("tfm %p", tfm);
return -EINVAL;
@@ -400,6 +408,8 @@ static int smp_e(struct crypto_blkcipher *tfm, const u8 *k, u8 *r)
/* Most significant octet of encryptedData corresponds to data[0] */
swap_buf(data, r, 16);
+ SMP_DBG("r %16phN", r);
+
return err;
}
@@ -410,6 +420,10 @@ static int smp_c1(struct crypto_blkcipher *tfm_aes, const u8 k[16],
u8 p1[16], p2[16];
int err;
+ SMP_DBG("k %16phN r %16phN", k, r);
+ SMP_DBG("iat %u ia %6phN rat %u ra %6phN", _iat, ia, _rat, ra);
+ SMP_DBG("preq %7phN pres %7phN", preq, pres);
+
memset(p1, 0, 16);
/* p1 = pres || preq || _rat || _iat */
@@ -418,10 +432,7 @@ static int smp_c1(struct crypto_blkcipher *tfm_aes, const u8 k[16],
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);
+ SMP_DBG("p1 %16phN", p1);
/* res = r XOR p1 */
u128_xor((u128 *) res, (u128 *) r, (u128 *) p1);
@@ -433,6 +444,13 @@ static int smp_c1(struct crypto_blkcipher *tfm_aes, const u8 k[16],
return err;
}
+ /* p2 = padding || ia || ra */
+ memcpy(p2, ra, 6);
+ memcpy(p2 + 6, ia, 6);
+ memset(p2 + 12, 0, 4);
+
+ SMP_DBG("p2 %16phN", p2);
+
/* res = res XOR p2 */
u128_xor((u128 *) res, (u128 *) res, (u128 *) p2);
@@ -477,7 +495,7 @@ static int smp_ah(struct crypto_blkcipher *tfm, const u8 irk[16],
}
/* The output of the random address function ah is:
- * ah(h, r) = e(k, r') mod 2^24
+ * ah(k, r) = e(k, r') mod 2^24
* The output of the security function e is then truncated to 24 bits
* by taking the least significant 24 bits of the output of e as the
* result of ah.
@@ -696,7 +714,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
if (rsp == NULL) {
req->io_capability = conn->hcon->io_capability;
req->oob_flag = oob_flag;
- req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
+ req->max_key_size = SMP_DEV(hdev)->max_key_size;
req->init_key_dist = local_dist;
req->resp_key_dist = remote_dist;
req->auth_req = (authreq & AUTH_REQ_MASK(hdev));
@@ -707,7 +725,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
rsp->io_capability = conn->hcon->io_capability;
rsp->oob_flag = oob_flag;
- rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
+ rsp->max_key_size = SMP_DEV(hdev)->max_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(hdev));
@@ -718,10 +736,11 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
{
struct l2cap_chan *chan = conn->smp;
+ struct hci_dev *hdev = conn->hcon->hdev;
struct smp_chan *smp = chan->data;
- if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) ||
- (max_key_size < SMP_MIN_ENC_KEY_SIZE))
+ if (max_key_size > SMP_DEV(hdev)->max_key_size ||
+ max_key_size < SMP_MIN_ENC_KEY_SIZE)
return SMP_ENC_KEY_SIZE;
smp->enc_key_size = max_key_size;
@@ -792,7 +811,6 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason)
smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
&reason);
- clear_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags);
mgmt_auth_failed(hcon, HCI_ERROR_AUTH_FAILURE);
if (chan->data)
@@ -985,13 +1003,10 @@ static u8 smp_random(struct smp_chan *smp)
smp_s1(smp->tfm_aes, smp->tk, smp->rrnd, smp->prnd, stk);
- memset(stk + smp->enc_key_size, 0,
- SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
-
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags))
return SMP_UNSPECIFIED;
- hci_le_start_enc(hcon, ediv, rand, stk);
+ hci_le_start_enc(hcon, ediv, rand, stk, smp->enc_key_size);
hcon->enc_key_size = smp->enc_key_size;
set_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags);
} else {
@@ -1004,9 +1019,6 @@ static u8 smp_random(struct smp_chan *smp)
smp_s1(smp->tfm_aes, smp->tk, smp->prnd, smp->rrnd, stk);
- memset(stk + smp->enc_key_size, 0,
- SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
-
if (hcon->pending_sec_level == BT_SECURITY_HIGH)
auth = 1;
else
@@ -1033,35 +1045,6 @@ static void smp_notify_keys(struct l2cap_conn *conn)
struct smp_cmd_pairing *rsp = (void *) &smp->prsp[1];
bool persistent;
- if (smp->remote_irk) {
- 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 (assuming this is an LE link).
- */
- 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
- * private address, just remove the key so that
- * it is possible to use the controller white
- * list for scanning.
- *
- * Userspace will have been told to not store
- * this key at this point. So it is safe to
- * just remove it.
- */
- if (!bacmp(&smp->remote_irk->rpa, BDADDR_ANY)) {
- list_del_rcu(&smp->remote_irk->list);
- kfree_rcu(smp->remote_irk, rcu);
- smp->remote_irk = NULL;
- }
- }
-
if (hcon->type == ACL_LINK) {
if (hcon->key_type == HCI_LK_DEBUG_COMBINATION)
persistent = false;
@@ -1069,13 +1052,27 @@ static void smp_notify_keys(struct l2cap_conn *conn)
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.
+ /* The LTKs, IRKs 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->remote_irk) {
+ mgmt_new_irk(hdev, smp->remote_irk, persistent);
+
+ /* Now that user space can be considered to know the
+ * identity address track the connection based on it
+ * from now on (assuming this is an LE link).
+ */
+ 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);
+ }
+ }
if (smp->csrk) {
smp->csrk->bdaddr_type = hcon->dst_type;
@@ -1144,9 +1141,6 @@ static void sc_add_ltk(struct smp_chan *smp)
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);
@@ -1268,7 +1262,14 @@ static void smp_distribute_keys(struct smp_chan *smp)
__le16 ediv;
__le64 rand;
- get_random_bytes(enc.ltk, sizeof(enc.ltk));
+ /* Make sure we generate only the significant amount of
+ * bytes based on the encryption key size, and set the rest
+ * of the value to zeroes.
+ */
+ get_random_bytes(enc.ltk, smp->enc_key_size);
+ memset(enc.ltk + smp->enc_key_size, 0,
+ sizeof(enc.ltk) - smp->enc_key_size);
+
get_random_bytes(&ediv, sizeof(ediv));
get_random_bytes(&rand, sizeof(rand));
@@ -1688,7 +1689,7 @@ static void build_bredr_pairing_cmd(struct smp_chan *smp,
req->init_key_dist = local_dist;
req->resp_key_dist = remote_dist;
- req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
+ req->max_key_size = conn->hcon->enc_key_size;
smp->remote_key_dist = remote_dist;
@@ -1697,7 +1698,7 @@ static void build_bredr_pairing_cmd(struct smp_chan *smp,
memset(rsp, 0, sizeof(*rsp));
- rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
+ rsp->max_key_size = conn->hcon->enc_key_size;
rsp->init_key_dist = req->init_key_dist & remote_dist;
rsp->resp_key_dist = req->resp_key_dist & local_dist;
@@ -2190,7 +2191,7 @@ static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level)
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags))
return true;
- hci_le_start_enc(hcon, key->ediv, key->rand, key->val);
+ hci_le_start_enc(hcon, key->ediv, key->rand, key->val, key->enc_size);
hcon->enc_key_size = key->enc_size;
/* We never store STKs for master role, so clear this flag */
@@ -2294,12 +2295,6 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
if (!conn)
return 1;
- chan = conn->smp;
- if (!chan) {
- BT_ERR("SMP security requested but not available");
- return 1;
- }
-
if (!hci_dev_test_flag(hcon->hdev, HCI_LE_ENABLED))
return 1;
@@ -2313,6 +2308,12 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
if (smp_ltk_encrypt(conn, hcon->pending_sec_level))
return 0;
+ chan = conn->smp;
+ if (!chan) {
+ BT_ERR("SMP security requested but not available");
+ return 1;
+ }
+
l2cap_chan_lock(chan);
/* If SMP is already in progress ignore this request */
@@ -2363,6 +2364,32 @@ unlock:
return ret;
}
+void smp_cancel_pairing(struct hci_conn *hcon)
+{
+ struct l2cap_conn *conn = hcon->l2cap_data;
+ struct l2cap_chan *chan;
+ struct smp_chan *smp;
+
+ if (!conn)
+ return;
+
+ chan = conn->smp;
+ if (!chan)
+ return;
+
+ l2cap_chan_lock(chan);
+
+ smp = chan->data;
+ if (smp) {
+ if (test_bit(SMP_FLAG_COMPLETE, &smp->flags))
+ smp_failure(conn, 0);
+ else
+ smp_failure(conn, SMP_UNSPECIFIED);
+ }
+
+ l2cap_chan_unlock(chan);
+}
+
static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
{
struct smp_cmd_encrypt_info *rp = (void *) skb->data;
@@ -2742,7 +2769,7 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)
sc_add_ltk(smp);
if (hcon->out) {
- hci_le_start_enc(hcon, 0, 0, smp->tk);
+ hci_le_start_enc(hcon, 0, 0, smp->tk, smp->enc_key_size);
hcon->enc_key_size = smp->enc_key_size;
}
@@ -2984,8 +3011,13 @@ static void smp_ready_cb(struct l2cap_chan *chan)
BT_DBG("chan %p", chan);
+ /* No need to call l2cap_chan_hold() here since we already own
+ * the reference taken in smp_new_conn_cb(). This is just the
+ * first time that we tie it to a specific pointer. The code in
+ * l2cap_core.c ensures that there's no risk this function wont
+ * get called if smp_new_conn_cb was previously called.
+ */
conn->smp = chan;
- l2cap_chan_hold(chan);
if (hcon->type == ACL_LINK && test_bit(HCI_CONN_ENCRYPT, &hcon->flags))
bredr_pairing(chan);
@@ -3124,6 +3156,8 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)
smp->tfm_aes = tfm_aes;
smp->tfm_cmac = tfm_cmac;
+ smp->min_key_size = SMP_MIN_ENC_KEY_SIZE;
+ smp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
create_chan:
chan = l2cap_chan_create();
@@ -3246,6 +3280,94 @@ static const struct file_operations force_bredr_smp_fops = {
.llseek = default_llseek,
};
+static ssize_t le_min_key_size_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct hci_dev *hdev = file->private_data;
+ char buf[4];
+
+ snprintf(buf, sizeof(buf), "%2u\n", SMP_DEV(hdev)->min_key_size);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+}
+
+static ssize_t le_min_key_size_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct hci_dev *hdev = file->private_data;
+ char buf[32];
+ size_t buf_size = min(count, (sizeof(buf) - 1));
+ u8 key_size;
+
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+
+ buf[buf_size] = '\0';
+
+ sscanf(buf, "%hhu", &key_size);
+
+ if (key_size > SMP_DEV(hdev)->max_key_size ||
+ key_size < SMP_MIN_ENC_KEY_SIZE)
+ return -EINVAL;
+
+ SMP_DEV(hdev)->min_key_size = key_size;
+
+ return count;
+}
+
+static const struct file_operations le_min_key_size_fops = {
+ .open = simple_open,
+ .read = le_min_key_size_read,
+ .write = le_min_key_size_write,
+ .llseek = default_llseek,
+};
+
+static ssize_t le_max_key_size_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct hci_dev *hdev = file->private_data;
+ char buf[4];
+
+ snprintf(buf, sizeof(buf), "%2u\n", SMP_DEV(hdev)->max_key_size);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+}
+
+static ssize_t le_max_key_size_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct hci_dev *hdev = file->private_data;
+ char buf[32];
+ size_t buf_size = min(count, (sizeof(buf) - 1));
+ u8 key_size;
+
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+
+ buf[buf_size] = '\0';
+
+ sscanf(buf, "%hhu", &key_size);
+
+ if (key_size > SMP_MAX_ENC_KEY_SIZE ||
+ key_size < SMP_DEV(hdev)->min_key_size)
+ return -EINVAL;
+
+ SMP_DEV(hdev)->max_key_size = key_size;
+
+ return count;
+}
+
+static const struct file_operations le_max_key_size_fops = {
+ .open = simple_open,
+ .read = le_max_key_size_read,
+ .write = le_max_key_size_write,
+ .llseek = default_llseek,
+};
+
int smp_register(struct hci_dev *hdev)
{
struct l2cap_chan *chan;
@@ -3270,6 +3392,11 @@ int smp_register(struct hci_dev *hdev)
hdev->smp_data = chan;
+ debugfs_create_file("le_min_key_size", 0644, hdev->debugfs, hdev,
+ &le_min_key_size_fops);
+ debugfs_create_file("le_max_key_size", 0644, hdev->debugfs, hdev,
+ &le_max_key_size_fops);
+
/* If the controller does not support BR/EDR Secure Connections
* feature, then the BR/EDR SMP channel shall not be present.
*