2011-07-01 19:07:35

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v2 00/12] Bluetooth: SMP Keys exchange and storage

Hi,

This patch series implement the so called SMP phase 3, where after
encryption has been estabilished, keys may be exchanged and, if
requested also stored.

Some notes about this series:
- the linkkeys list is also used for SMP keys;
- new fields were added to the mgmt_key_info structure;
- the size of the key used for encryption is exported through the BT_SECURITY
socket option, upper layers may reject some connections on that basis;

Cheers,

Vinicius Costa Gomes (12):
Bluetooth: Add support for SMP phase 3 (key distribution)
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: 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: Add support for storing the key size
Bluetooth: Add support for returning the encryption key size

include/net/bluetooth/bluetooth.h | 1 +
include/net/bluetooth/hci.h | 4 +
include/net/bluetooth/hci_core.h | 23 ++++-
include/net/bluetooth/mgmt.h | 2 +
include/net/bluetooth/smp.h | 1 +
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 | 202 +++++++++++++++++++++++++++++++++----
11 files changed, 361 insertions(+), 38 deletions(-)

--
1.7.6



2011-07-07 21:56:56

by Vinicius Costa Gomes

[permalink] [raw]
Subject: Re: [PATCH v3 03/12] Bluetooth: Add functions to manipulate the link key list for SMP

Hi Marcel,

On 10:09 Thu 07 Jul, Marcel Holtmann wrote:
> Hi Vinicius,
>
> > 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 | 73 ++++++++++++++++++++++++++++++++++++++
> > 2 files changed, 78 insertions(+), 0 deletions(-)
> >
> > diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> > index a3d49d8..353d4a9 100644
> > --- a/include/net/bluetooth/hci_core.h
> > +++ b/include/net/bluetooth/hci_core.h
> > @@ -552,6 +552,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, struct hci_conn *conn, int new_key,
> > bdaddr_t *bdaddr, u8 *val, 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 cd59b84..1cf8b89 100644
> > --- a/net/bluetooth/hci_core.c
> > +++ b/net/bluetooth/hci_core.c
> > @@ -1059,6 +1059,42 @@ static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
> > return 0;
> > }
> >
> > +struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
> > +{
> > + struct link_key *k;
> > +
> > + list_for_each_entry(k, &hdev->link_keys, list) {
> > + struct key_master_id *id;
> > +
> > + if (k->type != HCI_LK_SMP_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 link_key *k;
> > +
> > + list_for_each_entry(k, &hdev->link_keys, list)
> > + if ((k->type == type) && (bacmp(bdaddr, &k->bdaddr) == 0))
> > + return k;
>
> please just do if (k->type == type && bacmp(....) == 0). No need for the
> extra braces.

Done.


Cheers,
--
Vinicius

2011-07-07 08:09:11

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v3 03/12] Bluetooth: Add functions to manipulate the link key list for SMP

Hi Vinicius,

> 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 | 73 ++++++++++++++++++++++++++++++++++++++
> 2 files changed, 78 insertions(+), 0 deletions(-)
>
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index a3d49d8..353d4a9 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -552,6 +552,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, struct hci_conn *conn, int new_key,
> bdaddr_t *bdaddr, u8 *val, 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 cd59b84..1cf8b89 100644
> --- a/net/bluetooth/hci_core.c
> +++ b/net/bluetooth/hci_core.c
> @@ -1059,6 +1059,42 @@ static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
> return 0;
> }
>
> +struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
> +{
> + struct link_key *k;
> +
> + list_for_each_entry(k, &hdev->link_keys, list) {
> + struct key_master_id *id;
> +
> + if (k->type != HCI_LK_SMP_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 link_key *k;
> +
> + list_for_each_entry(k, &hdev->link_keys, list)
> + if ((k->type == type) && (bacmp(bdaddr, &k->bdaddr) == 0))
> + return k;

please just do if (k->type == type && bacmp(....) == 0). No need for the
extra braces.

> + return NULL;
> +}
> +EXPORT_SYMBOL(hci_find_link_key_type);
> +
> int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
> bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len)
> {
> @@ -1114,6 +1150,43 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
> 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, HCI_LK_SMP_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 = HCI_LK_SMP_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;



2011-07-06 19:24:24

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v3 08/12] 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 | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 34d236d..e6fc731 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -477,6 +477,17 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)

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

build_pairing_cmd(conn, &cp, NULL, authreq);
conn->preq[0] = SMP_CMD_PAIRING_REQ;
@@ -492,6 +503,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.6


2011-07-06 19:23:07

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v3 03/12] 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 | 73 ++++++++++++++++++++++++++++++++++++++
2 files changed, 78 insertions(+), 0 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index a3d49d8..353d4a9 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -552,6 +552,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, struct hci_conn *conn, int new_key,
bdaddr_t *bdaddr, u8 *val, 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 cd59b84..1cf8b89 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1059,6 +1059,42 @@ static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
return 0;
}

+struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
+{
+ struct link_key *k;
+
+ list_for_each_entry(k, &hdev->link_keys, list) {
+ struct key_master_id *id;
+
+ if (k->type != HCI_LK_SMP_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 link_key *k;
+
+ list_for_each_entry(k, &hdev->link_keys, 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, struct hci_conn *conn, int new_key,
bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len)
{
@@ -1114,6 +1150,43 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
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, HCI_LK_SMP_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 = HCI_LK_SMP_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.6


2011-07-04 17:51:32

by Vinicius Costa Gomes

[permalink] [raw]
Subject: Re: [PATCH v2 08/12] Bluetooth: Use the stored LTK for restabilishing security

Hi Gustavo,

On 16:28 Fri 01 Jul, Gustavo F. Padovan wrote:
> * Vinicius Costa Gomes <[email protected]> [2011-07-01 16:07:43 -0300]:
>
> > 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 34d236d..191aaec 100644
> > --- a/net/bluetooth/smp.c
> > +++ b/net/bluetooth/smp.c
> > @@ -476,6 +476,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,
> > + HCI_LK_SMP_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) {
>
> hey, why do you need this if? it is the same comparison as above.

Nothing too important, just to emphasize that each block is a different
step of the protocol: first we check if we already have an LTK for that
device, then we start the Pairing negotiation. But I fixed this, if I
need to write this email, then the code needed changing ;-) Thanks.

>
> Gustavo

Cheers,
--
Vinicius

2011-07-04 17:38:12

by Vinicius Costa Gomes

[permalink] [raw]
Subject: Re: [PATCH v2 03/12] Bluetooth: Add functions to manipulate the link key list for SMP

Hi Gustavo,

On 16:23 Fri 01 Jul, Gustavo F. Padovan wrote:
> * Vinicius Costa Gomes <[email protected]> [2011-07-01 16:07:38 -0300]:
>
> > 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 c92e89b..751104a 100644
> > --- a/include/net/bluetooth/hci_core.h
> > +++ b/include/net/bluetooth/hci_core.h
> > @@ -554,6 +554,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, struct hci_conn *conn, int new_key,
> > bdaddr_t *bdaddr, u8 *val, 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 0029e17..bf9c023 100644
> > --- a/net/bluetooth/hci_core.c
> > +++ b/net/bluetooth/hci_core.c
> > @@ -1059,6 +1059,50 @@ static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
> > return 0;
> > }
> >
> > +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);
>
> list_for_each_entry() please.

Done.

>
> > +
> > + if (k->type != HCI_LK_SMP_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);
>
> same here.

Done.

>
> Gustavo


Cheers,
--
Vinicius

2011-07-01 19:28:52

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH v2 08/12] Bluetooth: Use the stored LTK for restabilishing security

* Vinicius Costa Gomes <[email protected]> [2011-07-01 16:07:43 -0300]:

> 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 34d236d..191aaec 100644
> --- a/net/bluetooth/smp.c
> +++ b/net/bluetooth/smp.c
> @@ -476,6 +476,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,
> + HCI_LK_SMP_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) {

hey, why do you need this if? it is the same comparison as above.

Gustavo

2011-07-01 19:23:50

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH v2 03/12] Bluetooth: Add functions to manipulate the link key list for SMP

* Vinicius Costa Gomes <[email protected]> [2011-07-01 16:07:38 -0300]:

> 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 c92e89b..751104a 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -554,6 +554,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, struct hci_conn *conn, int new_key,
> bdaddr_t *bdaddr, u8 *val, 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 0029e17..bf9c023 100644
> --- a/net/bluetooth/hci_core.c
> +++ b/net/bluetooth/hci_core.c
> @@ -1059,6 +1059,50 @@ static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
> return 0;
> }
>
> +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);

list_for_each_entry() please.

> +
> + if (k->type != HCI_LK_SMP_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);

same here.

Gustavo

2011-07-01 19:07:47

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v2 12/12] 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 7bccaf9..ec10fb5 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 39082d4..4ece64f 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-01 19:07:46

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v2 11/12] 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 308a9f7..1c291e0 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;
@@ -557,7 +558,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 bf9c023..5f50dc2 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1159,7 +1159,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;
@@ -1184,6 +1184,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 9c7c370..620f307 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2811,6 +2811,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 336f971..8cae839 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 d9fffbd..62d6670 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;
@@ -483,6 +485,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);

@@ -648,8 +652,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


2011-07-01 19:07:45

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v2 10/12] 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 64c0418..336f971 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(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-01 19:07:44

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v2 09/12] 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 751104a..308a9f7 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -265,7 +265,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 191aaec..d9fffbd 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -367,8 +367,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, conn->hcon->dst_type, conn->dst,
--
1.7.6


2011-07-01 19:07:43

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v2 08/12] 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 34d236d..191aaec 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -476,6 +476,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,
+ HCI_LK_SMP_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);
@@ -492,6 +506,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.6


2011-07-01 19:07:42

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v2 07/12] 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 | 23 +++++++++++++++--------
1 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 024bb3e..34d236d 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -390,29 +390,36 @@ 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);

+ hci_le_start_enc(hcon, ediv, rand, stk);
+ } else {
+ u8 stk[16], r[16], rand[8];
+ __le16 ediv;
+
memset(rand, 0, sizeof(rand));
ediv = 0;
- hci_le_start_enc(hcon, ediv, rand, hcon->ltk);
- } else {
- u8 r[16];

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);
}

return 0;
--
1.7.6


2011-07-01 19:07:41

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v2 06/12] 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 | 20 ++++++++++++++------
1 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index c7a0cbe..024bb3e 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -493,18 +493,23 @@ 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)
{
- BT_DBG("conn %p", conn);
- /* FIXME: store the ltk */
+ struct smp_cmd_encrypt_info *rp = (void *) skb->data;
+
+ skb_pull(skb, sizeof(*rp));
+
+ memcpy(conn->tk, rp->ltk, sizeof(conn->tk));
+
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;
+ struct smp_cmd_master_ident *rp = (void *) skb->data;
+
+ skb_pull(skb, sizeof(*rp));

- BT_DBG("keydist 0x%x", keydist);
- /* FIXME: store ediv and rand */
+ hci_add_ltk(conn->hcon->hdev, 1, conn->src, rp->ediv,
+ rp->rand, conn->tk);

smp_distribute_keys(conn, 1);

@@ -623,6 +628,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.6


2011-07-01 19:07:40

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v2 05/12] 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.

If we are in the "not pairable" state, it makes no sense to
exchange any key. This allows for simplification of the key
negociation method.

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

diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 1863c574..c7a0cbe 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -197,14 +197,34 @@ 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 dist_keys;
+
+ dist_keys = 0;
+ if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->flags)) {
+ dist_keys = SMP_DIST_ENC_KEY | SMP_DIST_ID_KEY | SMP_DIST_SIGN;
+ 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 = dist_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 & dist_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)
@@ -233,7 +253,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))
@@ -412,7 +432,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));
@@ -451,7 +471,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.6


2011-07-01 19:07:39

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v2 04/12] 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 ac2c5e8..9c7c370 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2793,21 +2793,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_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
--
1.7.6


2011-07-01 19:07:38

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v2 03/12] 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 c92e89b..751104a 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -554,6 +554,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, struct hci_conn *conn, int new_key,
bdaddr_t *bdaddr, u8 *val, 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 0029e17..bf9c023 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1059,6 +1059,50 @@ static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
return 0;
}

+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 != HCI_LK_SMP_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, struct hci_conn *conn, int new_key,
bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len)
{
@@ -1114,6 +1158,43 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
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, HCI_LK_SMP_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 = HCI_LK_SMP_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.6


2011-07-01 19:07:37

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v2 02/12] 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.h | 4 ++++
include/net/bluetooth/hci_core.h | 16 ++++++++++++++++
include/net/bluetooth/mgmt.h | 2 ++
3 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 65345cd..3b6d057 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -254,6 +254,10 @@ enum {
#define HCI_LK_UNAUTH_COMBINATION 0x04
#define HCI_LK_AUTH_COMBINATION 0x05
#define HCI_LK_CHANGED_COMBINATION 0x06
+/* The spec doesn't define types for SMP keys */
+#define HCI_LK_SMP_LTK 0x81
+#define HCI_LK_SMP_IRK 0x82
+#define HCI_LK_SMP_CSRK 0x83

/* ----- HCI Commands ---- */
#define HCI_OP_NOP 0x0000
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 26233d4..c92e89b 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -74,12 +74,28 @@ struct bt_uuid {
u8 svc_hint;
};

+struct key_master_id {
+ __le16 ediv;
+ u8 rand[8];
+} __packed;
+
+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 45bea25..5428fd3 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.6


2011-07-01 19:07:36

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH v2 01/12] 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 9ec9c8c..a9553b3 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4177,6 +4177,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
chan->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 a36f870..1863c574 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -202,8 +202,8 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
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 = 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;
}

@@ -471,6 +471,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];
@@ -512,10 +532,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);

@@ -532,3 +562,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.6