2011-07-08 21:31:44

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v5 1/3] Bluetooth: Add support for communicating keys with userspace

As the key format has changed to something that has a dynamic size,
the way that keys are received and sent must be changed.

The structure fields order is changed to make the parsing of the
information received from the Management Interface easier.

Signed-off-by: Vinicius Costa Gomes <[email protected]>
---
net/bluetooth/mgmt.c | 60 +++++++++++++++++++++++++++++++++++++------------
1 files changed, 45 insertions(+), 15 deletions(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 4fd11e5..f424d6a 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -908,7 +908,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
struct hci_dev *hdev;
struct mgmt_cp_load_keys *cp;
u16 key_count, expected_len;
- int i;
+ int i, err;

cp = (void *) data;

@@ -918,9 +918,9 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
key_count = get_unaligned_le16(&cp->key_count);

expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
- if (expected_len != len) {
- BT_ERR("load_keys: expected %u bytes, got %u bytes",
- len, expected_len);
+ if (expected_len > len) {
+ BT_ERR("load_keys: expected at least %u bytes, got %u bytes",
+ expected_len, len);
return -EINVAL;
}

@@ -942,17 +942,36 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
else
clear_bit(HCI_DEBUG_KEYS, &hdev->flags);

- for (i = 0; i < key_count; i++) {
- struct mgmt_key_info *key = &cp->keys[i];
+ len -= sizeof(*cp);
+ i = 0;
+
+ while (i < len) {
+ struct mgmt_key_info *key = (void *) cp->keys + i;
+
+ i += sizeof(*key) + key->dlen;
+
+ if (key->type == HCI_LK_SMP_LTK) {
+ struct key_master_id *id = (void *) key->data;
+
+ if (key->dlen != sizeof(struct key_master_id))
+ continue;
+
+ hci_add_ltk(hdev, 0, &key->bdaddr, id->ediv,
+ id->rand, key->val);
+
+ continue;
+ }

hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
key->pin_len);
}

+ err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
+
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);

- return 0;
+ return err;
}

static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
@@ -1958,17 +1977,28 @@ int mgmt_connectable(u16 index, u8 connectable)

int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
{
- struct mgmt_ev_new_key ev;
+ struct mgmt_ev_new_key *ev;
+ int err, total;

- memset(&ev, 0, sizeof(ev));
+ total = sizeof(struct mgmt_ev_new_key) + key->dlen;
+ ev = kzalloc(total, GFP_ATOMIC);
+ if (!ev)
+ return -ENOMEM;
+
+ bacpy(&ev->key.bdaddr, &key->bdaddr);
+ ev->key.type = key->type;
+ memcpy(ev->key.val, key->val, 16);
+ ev->key.pin_len = key->pin_len;
+ ev->key.dlen = key->dlen;
+ ev->store_hint = persistent;
+
+ memcpy(ev->key.data, key->data, key->dlen);

- ev.store_hint = persistent;
- bacpy(&ev.key.bdaddr, &key->bdaddr);
- ev.key.type = key->type;
- memcpy(ev.key.val, key->val, 16);
- ev.key.pin_len = key->pin_len;
+ err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);

- return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
+ kfree(ev);
+
+ return err;
}

int mgmt_connected(u16 index, bdaddr_t *bdaddr)
--
1.7.6



2011-07-08 21:41:36

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH v5 3/3] Bluetooth: Add support for returning the encryption key size

* Vinicius Costa Gomes <[email protected]> [2011-07-08 18:31:46 -0300]:

> This will be useful when userspace wants to restrict some kinds of
> operations based on the length of the key size used to encrypt the
> link.
>
> Signed-off-by: Vinicius Costa Gomes <[email protected]>
> ---
> include/net/bluetooth/bluetooth.h | 1 +
> net/bluetooth/l2cap_sock.c | 4 ++++
> 2 files changed, 5 insertions(+), 0 deletions(-)

All applied now. Thanks.

Gustavo

2011-07-08 21:31:46

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v5 3/3] Bluetooth: Add support for returning the encryption key size

This will be useful when userspace wants to restrict some kinds of
operations based on the length of the key size used to encrypt the
link.

Signed-off-by: Vinicius Costa Gomes <[email protected]>
---
include/net/bluetooth/bluetooth.h | 1 +
net/bluetooth/l2cap_sock.c | 4 ++++
2 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 0cfa75b..e727555 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -56,6 +56,7 @@
#define BT_SECURITY 4
struct bt_security {
__u8 level;
+ __u8 key_size;
};
#define BT_SECURITY_SDP 0
#define BT_SECURITY_LOW 1
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 146b614..5c36b3e 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -422,8 +422,12 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
break;
}

+ memset(&sec, 0, sizeof(sec));
sec.level = chan->sec_level;

+ if (sk->sk_state == BT_CONNECTED)
+ sec.key_size = chan->conn->hcon->enc_key_size;
+
len = min_t(unsigned int, len, sizeof(sec));
if (copy_to_user(optval, (char *) &sec, len))
err = -EFAULT;
--
1.7.6


2011-07-08 21:31:45

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v5 2/3] Bluetooth: Add support for storing the key size

In some cases it will be useful having the key size used for
encrypting the link. For example, some profiles may restrict
some operations depending on the key length.

The key size is stored in the key that is passed to userspace
using the pin_length field in the key structure.

For now this field is only valid for LE controllers. 3.0+HS
controllers define the Read Encryption Key Size command, this
field is intended for storing the value returned by that
command.

Signed-off-by: Vinicius Costa Gomes <[email protected]>
---
include/net/bluetooth/hci_core.h | 3 ++-
net/bluetooth/hci_core.c | 3 ++-
net/bluetooth/hci_event.c | 1 +
net/bluetooth/mgmt.c | 4 ++--
net/bluetooth/smp.c | 14 +++++++++-----
5 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 4ff530e..c41e275 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -261,6 +261,7 @@ struct hci_conn {
__u8 sec_level;
__u8 pending_sec_level;
__u8 pin_length;
+ __u8 enc_key_size;
__u8 io_capability;
__u8 power_save;
__u16 disc_timeout;
@@ -556,7 +557,7 @@ struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]);
struct link_key *hci_find_link_key_type(struct hci_dev *hdev,
bdaddr_t *bdaddr, u8 type);
int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
- __le16 ediv, u8 rand[8], u8 ltk[16]);
+ u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16]);
int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);

int hci_remote_oob_data_clear(struct hci_dev *hdev);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 4885914..908fcd3 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1149,7 +1149,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
}

int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
- __le16 ediv, u8 rand[8], u8 ltk[16])
+ u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16])
{
struct link_key *key, *old_key;
struct key_master_id *id;
@@ -1174,6 +1174,7 @@ int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
bacpy(&key->bdaddr, bdaddr);
memcpy(key->val, ltk, sizeof(key->val));
key->type = HCI_LK_SMP_LTK;
+ key->pin_len = key_size;

id = (void *) &key->data;
id->ediv = ediv;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index ca5ff6e..a40170e 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2876,6 +2876,7 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,

memcpy(cp.ltk, ltk->val, sizeof(ltk->val));
cp.handle = cpu_to_le16(conn->handle);
+ conn->pin_length = ltk->pin_len;

hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index f424d6a..53e109e 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -956,8 +956,8 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
if (key->dlen != sizeof(struct key_master_id))
continue;

- hci_add_ltk(hdev, 0, &key->bdaddr, id->ediv,
- id->rand, key->val);
+ hci_add_ltk(hdev, 0, &key->bdaddr, key->pin_len,
+ id->ediv, id->rand, key->val);

continue;
}
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index a8b971b..391888b 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -401,6 +401,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);

hci_le_start_enc(hcon, ediv, rand, stk);
+ hcon->enc_key_size = conn->smp_key_size;
} else {
u8 stk[16], r[16], rand[8];
__le16 ediv;
@@ -417,7 +418,8 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
memset(stk + conn->smp_key_size, 0,
SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);

- hci_add_ltk(conn->hcon->hdev, 0, conn->dst, ediv, rand, stk);
+ hci_add_ltk(conn->hcon->hdev, 0, conn->dst, conn->smp_key_size,
+ ediv, rand, stk);
}

return 0;
@@ -487,6 +489,8 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)

hci_le_start_enc(hcon, master->ediv, master->rand,
key->val);
+ hcon->enc_key_size = key->pin_len;
+
goto done;
}

@@ -528,8 +532,8 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)

skb_pull(skb, sizeof(*rp));

- hci_add_ltk(conn->hcon->hdev, 1, conn->src, rp->ediv,
- rp->rand, conn->tk);
+ hci_add_ltk(conn->hcon->hdev, 1, conn->src, conn->smp_key_size,
+ rp->ediv, rp->rand, conn->tk);

smp_distribute_keys(conn, 1);

@@ -654,8 +658,8 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)

smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);

- hci_add_ltk(conn->hcon->hdev, 1, conn->dst, ediv,
- ident.rand, enc.ltk);
+ hci_add_ltk(conn->hcon->hdev, 1, conn->dst, conn->smp_key_size,
+ ediv, ident.rand, enc.ltk);

ident.ediv = cpu_to_le16(ediv);

--
1.7.6