2011-04-06 02:11:13

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [RFC 00/15] SM Phase 3 patches

Hi,

Disclaimer: these patches are implememented on top of the previous
SM work, so they are subject to change.

These patches start support for generating and storing the keys
produced during SM Phase 3. These patches will open the way for
having proper pairing over Low Energy connections.

As standard HCI commands don't provide any way for being notified
of new Low Energy keys, these patches extend some commands and
events from the Management Interface.

I still don't like the way that the STK is stored:
"Bluetooth: Use the link key list to temporarily store the STK"
I would like very much to hear some alternative ideas.

Another thing that I would like your opinion on is that some LE
profiles have some restrictions on the size of the key that was
used for encryption. I added a new field to struct bt_security
for this purpose:
"Bluetooth: Add support for returning the encryption key size"

The associated userspace patches can be found here[1].

--
Cheers,

[1] git://git.infradead.org/users/vcgomes/bluez.git mgmt
http://git.infradead.org/users/vcgomes/bluez.git (branch mgmt)

Vinicius Costa Gomes (15):
Bluetooth: Add support for SMP phase 3 (key distribution)
Bluetooth: Fix sending wrong IO Capabilities value
Bluetooth: Add new structures for supporting SM key distribution
Bluetooth: Add functions to manipulate the link key list for SMP
Bluetooth: Reject an encryption request when the key isn't found
Bluetooth: Add support for providing parameters to LE Start
Encryption
Bluetooth: Fix SM pairing parameters negotiation
Bluetooth: Add support for storing the LTK
Bluetooth: Use the link key list to temporarily store the STK
Bluetooth: Use the stored LTK for restabilishing security
Bluetooth: Remove unused field in hci_conn
Bluetooth: Add support for communicating keys with userspace
Bluetooth: Fix style issues reported by checkpatch.pl
Bluetooth: Add support for storing the key length
Bluetooth: Add support for returning the encryption key size

include/net/bluetooth/bluetooth.h | 34 +++---
include/net/bluetooth/hci_core.h | 29 +++++-
include/net/bluetooth/mgmt.h | 4 +-
include/net/bluetooth/smp.h | 1 +
net/bluetooth/hci_conn.c | 5 +-
net/bluetooth/hci_core.c | 82 +++++++++++++
net/bluetooth/hci_event.c | 19 +++-
net/bluetooth/l2cap_core.c | 1 +
net/bluetooth/l2cap_sock.c | 4 +
net/bluetooth/mgmt.c | 60 ++++++++---
net/bluetooth/smp.c | 227 ++++++++++++++++++++++++++++++++++---
11 files changed, 412 insertions(+), 54 deletions(-)

--
1.7.4.1


2011-04-06 02:11:28

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [RFC 15/15] 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 acf186d..28ae91a 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 12dbbf2..dd79b6b 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -492,8 +492,12 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
break;
}

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

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


2011-04-06 02:11:27

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [RFC 14/15] Bluetooth: Add support for storing the key length

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.

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

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index b402acd..1f95f03 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -549,7 +549,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 ab8ee1e..a573837 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1103,7 +1103,7 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
}

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;
@@ -1128,6 +1128,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 = KEY_TYPE_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 7282c39..2b57b99 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2649,6 +2649,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 9c25513..ffbcd6e 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 ba90f2c..990c89f 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -404,6 +404,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->pin_length = conn->smp_key_size;

hex_dump_to_buffer(key, sizeof(key), 16, 1, buf,
sizeof(buf), 0);
@@ -424,7 +425,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);

hex_dump_to_buffer(key, sizeof(key), 16, 1, buf,
sizeof(buf), 0);
@@ -494,6 +496,8 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)

hci_le_start_enc(hcon, master->ediv, master->rand,
key->val);
+ hcon->pin_length = key->pin_len;
+
goto done;
}
}
@@ -534,7 +538,7 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)

memset(rand, 0, sizeof(rand));

- err = hci_add_ltk(conn->hcon->hdev, 0, conn->dst, 0, rand, rp->ltk);
+ err = hci_add_ltk(conn->hcon->hdev, 0, conn->dst, 0, 0, rand, rp->ltk);
if (err)
return SMP_UNSPECIFIED;

@@ -561,8 +565,8 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
id->ediv = rp->ediv;
memcpy(id->rand, rp->rand, sizeof(rp->rand));

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

smp_distribute_keys(conn, 1);

@@ -681,8 +685,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.4.1


2011-04-06 02:11:26

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [RFC 13/15] Bluetooth: Fix style issues reported by checkpatch.pl

Signed-off-by: Vinicius Costa Gomes <[email protected]>
---
include/net/bluetooth/bluetooth.h | 33 ++++++++++++++++++---------------
1 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 4375043..acf186d 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -1,4 +1,4 @@
-/*
+/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2000-2001 Qualcomm Incorporated

@@ -12,20 +12,20 @@
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
- CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

- ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
- COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
+ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED.
*/

#ifndef __BLUETOOTH_H
#define __BLUETOOTH_H

-#include <asm/types.h>
+#include <linux/types.h>
#include <asm/byteorder.h>
#include <linux/list.h>
#include <linux/poll.h>
@@ -91,8 +91,8 @@ typedef struct {
__u8 b[6];
} __packed bdaddr_t;

-#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
-#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
+#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0} })
+#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff} })

/* Copy, swap, convert BD Address */
static inline int bacmp(bdaddr_t *ba1, bdaddr_t *ba2)
@@ -130,10 +130,11 @@ int bt_sock_register(int proto, const struct net_proto_family *ops);
int bt_sock_unregister(int proto);
void bt_sock_link(struct bt_sock_list *l, struct sock *s);
void bt_sock_unlink(struct bt_sock_list *l, struct sock *s);
-int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags);
+int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t len, int flags);
int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t len, int flags);
-uint bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait);
+uint bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait);
int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo);

@@ -157,20 +158,22 @@ static inline struct sk_buff *bt_skb_alloc(unsigned int len, gfp_t how)
{
struct sk_buff *skb;

- if ((skb = alloc_skb(len + BT_SKB_RESERVE, how))) {
+ skb = alloc_skb(len + BT_SKB_RESERVE, how);
+ if (skb) {
skb_reserve(skb, BT_SKB_RESERVE);
bt_cb(skb)->incoming = 0;
}
return skb;
}

-static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk, unsigned long len,
- int nb, int *err)
+static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk,
+ unsigned long len, int nb, int *err)
{
struct sk_buff *skb;

release_sock(sk);
- if ((skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err))) {
+ skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err);
+ if (skb) {
skb_reserve(skb, BT_SKB_RESERVE);
bt_cb(skb)->incoming = 0;
}
--
1.7.4.1


2011-04-06 02:11:25

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [RFC 12/15] 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]>
---
include/net/bluetooth/mgmt.h | 2 +-
net/bluetooth/mgmt.c | 60 +++++++++++++++++++++++++++++++----------
2 files changed, 46 insertions(+), 16 deletions(-)

diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index d467fb8..f4ef131 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -228,8 +228,8 @@ struct mgmt_ev_controller_error {

#define MGMT_EV_NEW_KEY 0x000A
struct mgmt_ev_new_key {
- struct mgmt_key_info key;
__u8 old_key_type;
+ struct mgmt_key_info key;
} __packed;

#define MGMT_EV_CONNECTED 0x000B
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index c304688..9c25513 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 == KEY_TYPE_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, 0, &key->bdaddr, key->val, key->type,
key->pin_len);
}

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

- return 0;
+ return err;
}

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

int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type)
{
- 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->old_key_type = old_key_type;
+ ev->key.dlen = key->dlen;
+
+ memcpy(ev->key.data, key->data, key->dlen);

- 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.old_key_type = old_key_type;
+ 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.4.1


2011-04-06 02:11:24

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [RFC 11/15] Bluetooth: Remove unused field in hci_conn

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

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 79b84d7..b402acd 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -266,7 +266,6 @@ struct hci_conn {
__u8 power_save;
__u16 disc_timeout;
unsigned long pend;
- __u8 ltk[16];

__u8 remote_cap;
__u8 remote_oob;
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 3fd97db..ba90f2c 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -372,8 +372,6 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
swap128(skb->data, random);
skb_pull(skb, sizeof(random));

- memset(hcon->ltk, 0, sizeof(hcon->ltk));
-
if (conn->hcon->out)
ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp, 0,
conn->src, 0, conn->dst, res);
--
1.7.4.1


2011-04-06 02:11:23

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [RFC 10/15] Bluetooth: Use the stored LTK for restabilishing security

Now that it's possible that the exchanged key is present in
the link key list, we may be able to estabilish security with
an already existing key, without need to perform any SMP
procedure.

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

diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 4a314cc..3fd97db 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -487,6 +487,20 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
authreq = seclevel_to_authreq(sec_level);

if (hcon->link_mode & HCI_LM_MASTER) {
+ struct link_key *key;
+
+ key = hci_find_link_key_type(hcon->hdev, conn->dst,
+ KEY_TYPE_LTK);
+ if (key) {
+ struct key_master_id *master = (void *) key->data;
+
+ hci_le_start_enc(hcon, master->ediv, master->rand,
+ key->val);
+ goto done;
+ }
+ }
+
+ if (hcon->link_mode & HCI_LM_MASTER) {
struct smp_cmd_pairing cp;

build_pairing_cmd(conn, &cp, NULL, authreq);
@@ -503,6 +517,7 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
}

+done:
hcon->pending_sec_level = sec_level;
set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);

--
1.7.4.1


2011-04-06 02:11:22

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [RFC 09/15] Bluetooth: Use the link key list to temporarily store the STK

With this we can use only one place to store all keys, without
need to use a field in the connection structure for this
purpose.

Signed-off-by: Vinicius Costa Gomes <[email protected]>
---
net/bluetooth/smp.c | 26 ++++++++++++++++----------
1 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 1aa620f..4a314cc 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -393,35 +393,41 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
}

if (conn->hcon->out) {
+ u8 stk[16], rand[8];
__le16 ediv;
- u8 rand[8];
+
+ memset(rand, 0, sizeof(rand));
+ ediv = 0;

smp_s1(tfm, conn->tk, random, conn->prnd, key);
- swap128(key, hcon->ltk);
+ swap128(key, stk);

- memset(hcon->ltk + conn->smp_key_size, 0,
+ memset(stk + conn->smp_key_size, 0,
SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);

-
- memset(rand, 0, sizeof(rand));
- ediv = 0;
- hci_le_start_enc(hcon, ediv, rand, hcon->ltk);
+ hci_le_start_enc(hcon, ediv, rand, stk);

hex_dump_to_buffer(key, sizeof(key), 16, 1, buf,
sizeof(buf), 0);
BT_DBG("key %s", buf);
} else {
- u8 r[16];
+ u8 stk[16], r[16], rand[8];
+ __le16 ediv;
+
+ memset(rand, 0, sizeof(rand));
+ ediv = 0;

swap128(conn->prnd, r);
smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);

smp_s1(tfm, conn->tk, conn->prnd, random, key);
- swap128(key, hcon->ltk);
+ swap128(key, stk);

- memset(hcon->ltk + conn->smp_key_size, 0,
+ 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);
+
hex_dump_to_buffer(key, sizeof(key), 16, 1, buf,
sizeof(buf), 0);
BT_DBG("key %s", buf);
--
1.7.4.1


2011-04-06 02:11:21

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [RFC 08/15] Bluetooth: Add support for storing the LTK

Now when the LTK is received from the remote or generated it is stored,
so it can later be used.

Signed-off-by: Vinicius Costa Gomes <[email protected]>
---
net/bluetooth/smp.c | 34 ++++++++++++++++++++++++++++++++--
1 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 3d2fb13..1aa620f 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -505,18 +505,45 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)

static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
{
+ struct smp_cmd_encrypt_info *rp = (void *) skb->data;
+ u8 rand[8];
+ int err;
+
+ skb_pull(skb, sizeof(*rp));
+
BT_DBG("conn %p", conn);
- /* FIXME: store the ltk */
+
+ memset(rand, 0, sizeof(rand));
+
+ err = hci_add_ltk(conn->hcon->hdev, 0, conn->dst, 0, rand, rp->ltk);
+ if (err)
+ return SMP_UNSPECIFIED;
+
return 0;
}

static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
{
+ struct smp_cmd_master_ident *rp = (void *) skb->data;
struct smp_cmd_pairing *paircmd = (void *) &conn->prsp[1];
+ struct link_key *key;
+ struct key_master_id *id;
u8 keydist = paircmd->init_key_dist;

+ skb_pull(skb, sizeof(*rp));
+
+ key = hci_find_link_key_type(conn->hcon->hdev, conn->dst, KEY_TYPE_LTK);
+ if (key == NULL)
+ return SMP_UNSPECIFIED;
+
BT_DBG("keydist 0x%x", keydist);
- /* FIXME: store ediv and rand */
+
+ id = (void *) key->data;
+ id->ediv = rp->ediv;
+ memcpy(id->rand, rp->rand, sizeof(rp->rand));
+
+ hci_add_ltk(conn->hcon->hdev, 1, conn->src, rp->ediv,
+ rp->rand, key->val);

smp_distribute_keys(conn, 1);

@@ -635,6 +662,9 @@ 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);
+
ident.ediv = cpu_to_le16(ediv);

smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident);
--
1.7.4.1


2011-04-06 02:11:20

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [RFC 07/15] Bluetooth: Fix SM pairing parameters negotiation

Before implementing SM key distribution, the pairing features
exchange must be better negotiated, taking into account some
features of the host and connection requirements.

Signed-off-by: Vinicius Costa Gomes <[email protected]>
---
net/bluetooth/smp.c | 42 ++++++++++++++++++++++++++++++++----------
1 files changed, 32 insertions(+), 10 deletions(-)

diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 1f1b318..3d2fb13 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -201,14 +201,36 @@ static __u8 seclevel_to_authreq(__u8 level)
}

static void build_pairing_cmd(struct l2cap_conn *conn,
- struct smp_cmd_pairing *cmd, __u8 authreq)
+ struct smp_cmd_pairing *req,
+ struct smp_cmd_pairing *rsp,
+ __u8 authreq)
{
- cmd->io_capability = conn->hcon->io_capability;
- cmd->oob_flag = SMP_OOB_NOT_PRESENT;
- cmd->max_key_size = SMP_MAX_ENC_KEY_SIZE;
- cmd->init_key_dist = SMP_DIST_ENC_KEY | SMP_DIST_ID_KEY | SMP_DIST_SIGN;
- cmd->resp_key_dist = SMP_DIST_ENC_KEY | SMP_DIST_ID_KEY | SMP_DIST_SIGN;
- cmd->auth_req = authreq;
+ u8 all_keys = SMP_DIST_ENC_KEY | SMP_DIST_ID_KEY |
+ SMP_DIST_SIGN;
+ u8 dist_keys;
+
+ dist_keys = 0;
+ if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->flags)) {
+ dist_keys = SMP_DIST_ENC_KEY;
+ authreq |= SMP_AUTH_BONDING;
+ }
+
+ if (rsp == NULL) {
+ req->io_capability = conn->hcon->io_capability;
+ req->oob_flag = SMP_OOB_NOT_PRESENT;
+ req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
+ req->init_key_dist = dist_keys;
+ req->resp_key_dist = all_keys;
+ req->auth_req = authreq;
+ return;
+ }
+
+ rsp->io_capability = conn->hcon->io_capability;
+ rsp->oob_flag = SMP_OOB_NOT_PRESENT;
+ rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
+ rsp->init_key_dist = req->init_key_dist & all_keys;
+ rsp->resp_key_dist = req->resp_key_dist & dist_keys;
+ rsp->auth_req = authreq;
}

static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
@@ -237,7 +259,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
return SMP_OOB_NOT_AVAIL;

/* We didn't start the pairing, so no requirements */
- build_pairing_cmd(conn, &rsp, SMP_AUTH_NONE);
+ build_pairing_cmd(conn, req, &rsp, SMP_AUTH_NONE);

key_size = min(req->max_key_size, rsp.max_key_size);
if (check_enc_key_size(conn, key_size))
@@ -422,7 +444,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
skb_pull(skb, sizeof(*rp));

memset(&cp, 0, sizeof(cp));
- build_pairing_cmd(conn, &cp, rp->auth_req);
+ build_pairing_cmd(conn, &cp, NULL, rp->auth_req);

conn->preq[0] = SMP_CMD_PAIRING_REQ;
memcpy(&conn->preq[1], &cp, sizeof(cp));
@@ -461,7 +483,7 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
if (hcon->link_mode & HCI_LM_MASTER) {
struct smp_cmd_pairing cp;

- build_pairing_cmd(conn, &cp, authreq);
+ build_pairing_cmd(conn, &cp, NULL, authreq);
conn->preq[0] = SMP_CMD_PAIRING_REQ;
memcpy(&conn->preq[1], &cp, sizeof(cp));

--
1.7.4.1


2011-04-06 02:11:19

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [RFC 06/15] Bluetooth: Add support for providing parameters to LE Start Encryption

With LTK support we need to be able to provide LE Start Encryption
with EDIV (Encrypted Diversifier) and Rand (just an 64 bit random
number).

Signed-off-by: Vinicius Costa Gomes <[email protected]>
---
include/net/bluetooth/hci_core.h | 3 ++-
net/bluetooth/hci_conn.c | 5 ++++-
net/bluetooth/smp.c | 8 +++++++-
3 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 72305d6..79b84d7 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -870,7 +870,8 @@ void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result);

void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
u16 latency, u16 to_multiplier);
-void hci_le_start_enc(struct hci_conn *conn, u8 ltk[16]);
+void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
+ __u8 ltk[16]);
void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16]);
void hci_le_ltk_neg_reply(struct hci_conn *conn);

diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 173806e..07337d3 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -205,7 +205,8 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
}
EXPORT_SYMBOL(hci_le_conn_update);

-void hci_le_start_enc(struct hci_conn *conn, u8 ltk[16])
+void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
+ __u8 ltk[16])
{
struct hci_dev *hdev = conn->hdev;
struct hci_cp_le_start_enc cp;
@@ -216,6 +217,8 @@ void hci_le_start_enc(struct hci_conn *conn, u8 ltk[16])

cp.handle = cpu_to_le16(conn->handle);
memcpy(cp.ltk, ltk, sizeof(cp.ltk));
+ cp.ediv = ediv;
+ memcpy(cp.rand, rand, sizeof(rand));

hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp);
}
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 3240be7..1f1b318 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -371,13 +371,19 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
}

if (conn->hcon->out) {
+ __le16 ediv;
+ u8 rand[8];
+
smp_s1(tfm, conn->tk, random, conn->prnd, key);
swap128(key, hcon->ltk);

memset(hcon->ltk + conn->smp_key_size, 0,
SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);

- hci_le_start_enc(hcon, hcon->ltk);
+
+ memset(rand, 0, sizeof(rand));
+ ediv = 0;
+ hci_le_start_enc(hcon, ediv, rand, hcon->ltk);

hex_dump_to_buffer(key, sizeof(key), 16, 1, buf,
sizeof(buf), 0);
--
1.7.4.1


2011-04-06 02:11:18

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [RFC 05/15] Bluetooth: Reject an encryption request when the key isn't found

Now that we have methods to finding keys by its parameters we can
reject an encryption request if the key isn't found.

Signed-off-by: Vinicius Costa Gomes <[email protected]>
---
net/bluetooth/hci_event.c | 18 ++++++++++++++++--
1 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index ce06d97..7282c39 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2631,21 +2631,35 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
{
struct hci_ev_le_ltk_req *ev = (void *) skb->data;
struct hci_cp_le_ltk_reply cp;
+ struct hci_cp_le_ltk_neg_reply neg;
struct hci_conn *conn;
+ struct link_key *ltk;

BT_DBG("%s handle %d", hdev->name, cpu_to_le16(ev->handle));

hci_dev_lock(hdev);

conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
+ if (conn == NULL)
+ goto not_found;
+
+ ltk = hci_find_ltk(hdev, ev->ediv, ev->random);
+ if (ltk == NULL)
+ goto not_found;

- memset(&cp, 0, sizeof(cp));
+ memcpy(cp.ltk, ltk->val, sizeof(ltk->val));
cp.handle = cpu_to_le16(conn->handle);
- memcpy(cp.ltk, conn->ltk, sizeof(conn->ltk));

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

hci_dev_unlock(hdev);
+
+ return;
+
+not_found:
+ neg.handle = ev->handle;
+ hci_send_cmd(hdev, HCI_OP_LE_LTK_NEG_REPLY, sizeof(neg), &neg);
+ hci_dev_unlock(hdev);
}

static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
--
1.7.4.1


2011-04-06 02:11:17

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [RFC 04/15] Bluetooth: Add functions to manipulate the link key list for SMP

As the LTK (the new type of key being handled now) has more data
associated with it, we need to store this extra data and retrieve
the keys based on that data.

Methods for searching for a key and for adding a new LTK are
introduced here.

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

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 74c9f07..72305d6 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -546,6 +546,11 @@ int hci_link_keys_clear(struct hci_dev *hdev);
struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
u8 *key, u8 type, u8 pin_len);
+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]);
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 1c2160f..ab8ee1e 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1024,6 +1024,50 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
return NULL;
}

+struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
+{
+ struct list_head *p;
+
+ list_for_each(p, &hdev->link_keys) {
+ struct link_key *k;
+ struct key_master_id *id;
+
+ k = list_entry(p, struct link_key, list);
+
+ if (k->type != KEY_TYPE_LTK)
+ continue;
+
+ if (k->dlen != sizeof(*id))
+ continue;
+
+ id = (void *) &k->data;
+ if (id->ediv == ediv &&
+ (memcmp(rand, id->rand, sizeof(id->rand)) == 0))
+ return k;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(hci_find_ltk);
+
+struct link_key *hci_find_link_key_type(struct hci_dev *hdev,
+ bdaddr_t *bdaddr, u8 type)
+{
+ struct list_head *p;
+
+ list_for_each(p, &hdev->link_keys) {
+ struct link_key *k;
+
+ k = list_entry(p, struct link_key, list);
+
+ if ((k->type == type) && (bacmp(bdaddr, &k->bdaddr) == 0))
+ return k;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(hci_find_link_key_type);
+
int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
u8 *val, u8 type, u8 pin_len)
{
@@ -1058,6 +1102,43 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
return 0;
}

+int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
+ __le16 ediv, u8 rand[8], u8 ltk[16])
+{
+ struct link_key *key, *old_key;
+ struct key_master_id *id;
+ u8 old_key_type;
+
+ BT_DBG("%s addr %s", hdev->name, batostr(bdaddr));
+
+ old_key = hci_find_link_key_type(hdev, bdaddr, KEY_TYPE_LTK);
+ if (old_key) {
+ key = old_key;
+ old_key_type = old_key->type;
+ } else {
+ key = kzalloc(sizeof(*key) + sizeof(*id), GFP_ATOMIC);
+ if (!key)
+ return -ENOMEM;
+ list_add(&key->list, &hdev->link_keys);
+ old_key_type = 0xff;
+ }
+
+ key->dlen = sizeof(*id);
+
+ bacpy(&key->bdaddr, bdaddr);
+ memcpy(key->val, ltk, sizeof(key->val));
+ key->type = KEY_TYPE_LTK;
+
+ id = (void *) &key->data;
+ id->ediv = ediv;
+ memcpy(id->rand, rand, sizeof(id->rand));
+
+ if (new_key)
+ mgmt_new_key(hdev->id, key, old_key_type);
+
+ return 0;
+}
+
int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
struct link_key *key;
--
1.7.4.1


2011-04-06 02:11:16

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [RFC 03/15] Bluetooth: Add new structures for supporting SM key distribution

We need these changes because SMP keys may have more information
associated with them, for example, in the LTK case, it has an
encrypted diversifier (ediv) and a random number (rand).

Signed-off-by: Vinicius Costa Gomes <[email protected]>
---
include/net/bluetooth/hci_core.h | 20 ++++++++++++++++++++
include/net/bluetooth/mgmt.h | 2 ++
2 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 669bcea..74c9f07 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -74,12 +74,32 @@ struct bt_uuid {
u8 svc_hint;
};

+struct key_master_id {
+ __le16 ediv;
+ u8 rand[8];
+} __packed;
+
+#define KEY_TYPE_LTK 0x11
+#define KEY_TYPE_IRK 0x12
+#define KEY_TYPE_CSRK 0x13
+
+struct link_key_data {
+ bdaddr_t bdaddr;
+ u8 type;
+ u8 val[16];
+ u8 pin_len;
+ u8 dlen;
+ u8 data[0];
+} __packed;
+
struct link_key {
struct list_head list;
bdaddr_t bdaddr;
u8 type;
u8 val[16];
u8 pin_len;
+ u8 dlen;
+ u8 data[0];
};

struct oob_data {
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 6b6ff92..d467fb8 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -101,6 +101,8 @@ struct mgmt_key_info {
u8 type;
u8 val[16];
u8 pin_len;
+ u8 dlen;
+ u8 data[0];
} __packed;

#define MGMT_OP_LOAD_KEYS 0x000D
--
1.7.4.1


2011-04-06 02:11:15

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [RFC 02/15] Bluetooth: Fix sending wrong IO Capabilities value

We should send the IO Capabilities set by userspace, using the
management interface, instead of a fixed value.

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

diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 88b3674..3240be7 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -203,7 +203,7 @@ static __u8 seclevel_to_authreq(__u8 level)
static void build_pairing_cmd(struct l2cap_conn *conn,
struct smp_cmd_pairing *cmd, __u8 authreq)
{
- cmd->io_capability = SMP_IO_NO_INPUT_OUTPUT;
+ cmd->io_capability = conn->hcon->io_capability;
cmd->oob_flag = SMP_OOB_NOT_PRESENT;
cmd->max_key_size = SMP_MAX_ENC_KEY_SIZE;
cmd->init_key_dist = SMP_DIST_ENC_KEY | SMP_DIST_ID_KEY | SMP_DIST_SIGN;
--
1.7.4.1


2011-04-06 02:11:14

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [RFC 01/15] Bluetooth: Add support for SMP phase 3 (key distribution)

This adds support for generating and distributing all the keys
specified in the third phase of SMP.

This will make possible to re-establish secure connections, resolve
private addresses and sign commands.

For now, the values generated are random.

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

diff --git a/include/net/bluetooth/smp.h b/include/net/bluetooth/smp.h
index 4fb7d19..46c4576 100644
--- a/include/net/bluetooth/smp.h
+++ b/include/net/bluetooth/smp.h
@@ -118,5 +118,6 @@ struct smp_cmd_security_req {
/* SMP Commands */
int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level);
int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb);
+int smp_distribute_keys(struct l2cap_conn *conn, __u8 force);

#endif /* __SMP_H */
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 3cc52df..b3b8816 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -3823,6 +3823,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
l2cap_pi(sk)->sec_level = hcon->sec_level;
del_timer(&conn->security_timer);
l2cap_chan_ready(sk);
+ smp_distribute_keys(conn, 0);
}

bh_unlock_sock(sk);
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 0ea639c..88b3674 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -206,8 +206,8 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
cmd->io_capability = SMP_IO_NO_INPUT_OUTPUT;
cmd->oob_flag = SMP_OOB_NOT_PRESENT;
cmd->max_key_size = SMP_MAX_ENC_KEY_SIZE;
- cmd->init_key_dist = 0x00;
- cmd->resp_key_dist = 0x00;
+ cmd->init_key_dist = SMP_DIST_ENC_KEY | SMP_DIST_ID_KEY | SMP_DIST_SIGN;
+ cmd->resp_key_dist = SMP_DIST_ENC_KEY | SMP_DIST_ID_KEY | SMP_DIST_SIGN;
cmd->auth_req = authreq;
}

@@ -475,6 +475,26 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
return 0;
}

+static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+ BT_DBG("conn %p", conn);
+ /* FIXME: store the ltk */
+ return 0;
+}
+
+static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+ struct smp_cmd_pairing *paircmd = (void *) &conn->prsp[1];
+ u8 keydist = paircmd->init_key_dist;
+
+ BT_DBG("keydist 0x%x", keydist);
+ /* FIXME: store ediv and rand */
+
+ smp_distribute_keys(conn, 1);
+
+ return 0;
+}
+
int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
{
__u8 code = skb->data[0];
@@ -516,10 +536,20 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
break;

case SMP_CMD_ENCRYPT_INFO:
+ reason = smp_cmd_encrypt_info(conn, skb);
+ break;
+
case SMP_CMD_MASTER_IDENT:
+ reason = smp_cmd_master_ident(conn, skb);
+ break;
+
case SMP_CMD_IDENT_INFO:
case SMP_CMD_IDENT_ADDR_INFO:
case SMP_CMD_SIGN_INFO:
+ /* Just ignored */
+ reason = 0;
+ break;
+
default:
BT_DBG("Unknown command code 0x%2.2x", code);

@@ -536,3 +566,83 @@ done:
kfree_skb(skb);
return err;
}
+
+int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
+{
+ struct smp_cmd_pairing *req, *rsp;
+ __u8 *keydist;
+
+ BT_DBG("conn %p force %d", conn, force);
+
+ if (IS_ERR(conn->hcon->hdev->tfm))
+ return PTR_ERR(conn->hcon->hdev->tfm);
+
+ rsp = (void *) &conn->prsp[1];
+
+ /* The responder sends its keys first */
+ if (!force && conn->hcon->out && (rsp->resp_key_dist & 0x07))
+ return 0;
+
+ req = (void *) &conn->preq[1];
+
+ if (conn->hcon->out) {
+ keydist = &rsp->init_key_dist;
+ *keydist &= req->init_key_dist;
+ } else {
+ keydist = &rsp->resp_key_dist;
+ *keydist &= req->resp_key_dist;
+ }
+
+
+ BT_DBG("keydist 0x%x", *keydist);
+
+ if (*keydist & SMP_DIST_ENC_KEY) {
+ struct smp_cmd_encrypt_info enc;
+ struct smp_cmd_master_ident ident;
+ __le16 ediv;
+
+ get_random_bytes(enc.ltk, sizeof(enc.ltk));
+ get_random_bytes(&ediv, sizeof(ediv));
+ get_random_bytes(ident.rand, sizeof(ident.rand));
+
+ smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
+
+ ident.ediv = cpu_to_le16(ediv);
+
+ smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident);
+
+ *keydist &= ~SMP_DIST_ENC_KEY;
+ }
+
+ if (*keydist & SMP_DIST_ID_KEY) {
+ struct smp_cmd_ident_addr_info addrinfo;
+ struct smp_cmd_ident_info idinfo;
+
+ /* Send a dummy key */
+ get_random_bytes(idinfo.irk, sizeof(idinfo.irk));
+
+ smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo);
+
+ /* Just public address */
+ memset(&addrinfo, 0, sizeof(addrinfo));
+ bacpy(&addrinfo.bdaddr, conn->src);
+
+ smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo),
+ &addrinfo);
+
+ *keydist &= ~SMP_DIST_ID_KEY;
+ }
+
+ if (*keydist & SMP_DIST_SIGN) {
+ struct smp_cmd_sign_info sign;
+
+ /* Send a dummy key */
+ get_random_bytes(sign.csrk, sizeof(sign.csrk));
+
+ smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign);
+
+ *keydist &= ~SMP_DIST_SIGN;
+ }
+
+ return 0;
+}
--
1.7.4.1