2012-01-13 19:39:32

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH 0/8] New MGMT messages for SMP Long Term Keys

Hi,

This is the last version of the code that will allow the permanent
storage of SMP Long Term Keys.

The main changes from the last version are:
* In the structure that represents a LTK the field pin_length was
replaced by the information whether or not that key is
authenticated;

* Still on that structure, it was added information about the role in
which the key should be used, e.g. a key marked as master should
only be used when the host is in the master role;

* More specific types for each type and role of key, previously it was
used the address field of the key to indentify the role of the key.

* The address type of the remote is sent with the LTK, this information
will be useful for userspace when recreating the device from storage.

Marcel, as I changed the key format in the patch "Bluetooth: Add
structures for the new LTK exchange messages" I decided to remove your
Ack from it.

Cheers,
--

Vinicius Costa Gomes (8):
Bluetooth: Add structures for the new LTK exchange messages
Bluetooth: Rename smp_key_size to enc_key_size
Bluetooth: Add new structures for handling SMP Long Term Keys
Bluetooth: Use the updated key structures for handling LTKs
Bluetooth: Add MGMT handlers for dealing with SMP LTK's
Bluetooth: Add support for removing LTK's when pairing is removed
Bluetooth: Clean up structures left unused
Bluetooth: Add support for notifying userspace of new LTK's

include/net/bluetooth/hci.h | 9 ++--
include/net/bluetooth/hci_core.h | 35 +++++++------
include/net/bluetooth/mgmt.h | 22 ++++++++
include/net/bluetooth/smp.h | 2 +-
net/bluetooth/hci_core.c | 111 ++++++++++++++++++++++++--------------
net/bluetooth/hci_event.c | 9 +++-
net/bluetooth/mgmt.c | 88 ++++++++++++++++++++++++++++++
net/bluetooth/smp.c | 50 ++++++++++-------
8 files changed, 241 insertions(+), 85 deletions(-)

--
1.7.8.1



2012-01-13 19:39:40

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH 8/8] Bluetooth: Add support for notifying userspace of new LTK's

If we want to have proper pairing support over LE we need to
inform userspace that a new LTK is available, so userspace
can store that key permanently.

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

diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 5f41e74..ffb66a1 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1343,6 +1343,9 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type,
if (!new_key)
return 0;

+ if (type & HCI_SMP_LTK)
+ mgmt_new_ltk(hdev, key, 1);
+
return 0;
}

--
1.7.8.1


2012-01-13 19:39:39

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH 7/8] Bluetooth: Clean up structures left unused

With the use of the new structures and lists for the SMP LTK's
we may remove some code that is now unused. No need to have extra
fields of information inside link_key now that it is only used
for Link Keys.

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

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 3056115..e12b719 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -269,10 +269,6 @@ 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
/* The spec doesn't define types for SMP keys, the _MASTER suffix is implied */
#define HCI_SMP_STK 0x80
#define HCI_SMP_STK_SLAVE 0x81
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 4ab8019..faf987e 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -100,28 +100,12 @@ struct smp_ltk {
u8 val[16];
} __packed;

-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 {
--
1.7.8.1


2012-01-13 19:39:38

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH 6/8] Bluetooth: Add support for removing LTK's when pairing is removed

Instead of having a separated command for removing SMP keys, we use the
Remove Keys command to remove *all* keys.

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

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 34ccaf4..4ab8019 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -658,6 +658,7 @@ int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type,
int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
struct smp_ltk *hci_find_ltk_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 addr_type);
+int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr);
int hci_smp_ltks_clear(struct hci_dev *hdev);

int hci_remote_oob_data_clear(struct hci_dev *hdev);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 3cbee32..f244349 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1113,6 +1113,12 @@ static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
bacpy(&rp.bdaddr, &cp->bdaddr);
rp.status = MGMT_STATUS_FAILED;

+ err = hci_remove_ltk(hdev, &cp->bdaddr);
+ if (err < 0) {
+ err = cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, -err);
+ goto unlock;
+ }
+
err = hci_remove_link_key(hdev, &cp->bdaddr);
if (err < 0) {
rp.status = MGMT_STATUS_NOT_PAIRED;
--
1.7.8.1


2012-01-13 19:39:37

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH 5/8] Bluetooth: Add MGMT handlers for dealing with SMP LTK's

This adds a method to notify that a new LTK is available and
a handler to store keys coming from userspace into the kernel LTK
list.

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

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 7ce25ad..34ccaf4 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -949,6 +949,8 @@ int mgmt_discovering(struct hci_dev *hdev, u8 discovering);
int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr);

+int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent);
+
/* HCI info for socket */
#define hci_pi(sk) ((struct hci_pinfo *) sk)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 2dae2e8..3cbee32 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2179,6 +2179,62 @@ done:
return err;
}

+static int load_long_term_keys(struct sock *sk, u16 index,
+ unsigned char *data, u16 len)
+{
+ struct hci_dev *hdev;
+ struct mgmt_cp_load_long_term_keys *cp;
+ u16 key_count, expected_len;
+ int i;
+
+ cp = (void *) data;
+
+ if (len < sizeof(*cp))
+ return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
+ EINVAL);
+
+ key_count = get_unaligned_le16(&cp->key_count);
+
+ expected_len = sizeof(*cp) + key_count *
+ sizeof(struct mgmt_ltk_info);
+ if (expected_len != len) {
+ BT_ERR("load_keys: expected %u bytes, got %u bytes",
+ len, expected_len);
+ return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
+ EINVAL);
+ }
+
+ hdev = hci_dev_get(index);
+ if (!hdev)
+ return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
+ ENODEV);
+
+ BT_DBG("hci%u key_count %u", index, key_count);
+
+ hci_dev_lock(hdev);
+
+ hci_smp_ltks_clear(hdev);
+
+ for (i = 0; i < key_count; i++) {
+ struct mgmt_ltk_info *key = &cp->keys[i];
+ u8 type;
+
+ if (key->master)
+ type = HCI_SMP_LTK;
+ else
+ type = HCI_SMP_LTK_SLAVE;
+
+ hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
+ type, 0, key->authenticated, key->val,
+ key->enc_size, key->ediv, key->rand);
+ }
+
+ hci_dev_unlock(hdev);
+ hci_dev_put(hdev);
+
+ return 0;
+}
+
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
{
unsigned char *buf;
@@ -2311,6 +2367,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
case MGMT_OP_UNBLOCK_DEVICE:
err = unblock_device(sk, index, buf + sizeof(*hdr), len);
break;
+ case MGMT_OP_LOAD_LONG_TERM_KEYS:
+ err = load_long_term_keys(sk, index, buf + sizeof(*hdr), len);
+ break;
default:
BT_DBG("Unknown op %u", opcode);
err = cmd_status(sk, index, opcode,
@@ -2464,6 +2523,29 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
}

+int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
+{
+ struct mgmt_ev_new_long_term_key ev;
+
+ memset(&ev, 0, sizeof(ev));
+
+ ev.store_hint = persistent;
+ bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
+ ev.key.addr.type = key->bdaddr_type;
+ ev.key.authenticated = key->authenticated;
+ ev.key.enc_size = key->enc_size;
+ ev.key.ediv = key->ediv;
+
+ if (key->type == HCI_SMP_LTK)
+ ev.key.master = 1;
+
+ memcpy(ev.key.rand, key->rand, sizeof(key->rand));
+ memcpy(ev.key.val, key->val, sizeof(key->val));
+
+ return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
+ &ev, sizeof(ev), NULL);
+}
+
int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type)
{
--
1.7.8.1


2012-01-13 19:39:36

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH 4/8] Bluetooth: Use the updated key structures for handling LTKs

This updates all the users of the older way, that was using the
link_keys list to store the SMP keys, to use the new way.

This includes defining new types for the keys, we have a type for each
combination of STK/LTK and Master/Slave.

Signed-off-by: Vinicius Costa Gomes <[email protected]>
---
include/net/bluetooth/hci_core.h | 11 +++--
net/bluetooth/hci_core.c | 79 ++++++++++++++++++--------------------
net/bluetooth/hci_event.c | 9 +++-
net/bluetooth/smp.c | 38 +++++++++++-------
4 files changed, 73 insertions(+), 64 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 9d77a66..7ce25ad 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -651,12 +651,13 @@ 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,
- u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16]);
+struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]);
+int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type,
+ int new_key, u8 authenticated, u8 tk[16],
+ u8 enc_size, u16 ediv, u8 rand[8]);
int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr);
+struct smp_ltk *hci_find_ltk_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
+ u8 addr_type);
int hci_smp_ltks_clear(struct hci_dev *hdev);

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 3b5902d..5f41e74 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1222,41 +1222,40 @@ 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])
+/* If the returned key is a STK it should be free'd by the caller */
+struct smp_ltk *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;
+ struct smp_ltk *k, *tmp;

- if (k->type != HCI_LK_SMP_LTK)
+ list_for_each_entry_safe(k, tmp, &hdev->ltks, list) {
+ if (k->ediv != ediv ||
+ memcmp(rand, k->rand, sizeof(k->rand)))
continue;

- if (k->dlen != sizeof(*id))
- continue;
+ /* The STK should only be used once, no need to keep it */
+ if (k->type & HCI_SMP_STK)
+ list_del(&k->list);

- id = (void *) &k->data;
- if (id->ediv == ediv &&
- (memcmp(rand, id->rand, sizeof(id->rand)) == 0))
- return k;
+ 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 smp_ltk *hci_find_ltk_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
+ u8 addr_type)
{
- struct link_key *k;
+ struct smp_ltk *k;

- list_for_each_entry(k, &hdev->link_keys, list)
- if (k->type == type && bacmp(bdaddr, &k->bdaddr) == 0)
+ list_for_each_entry(k, &hdev->ltks, list)
+ if (addr_type == k->bdaddr_type &&
+ bacmp(bdaddr, &k->bdaddr) == 0)
return k;

return NULL;
}
-EXPORT_SYMBOL(hci_find_link_key_type);
+EXPORT_SYMBOL(hci_find_ltk_addr);

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)
@@ -1313,40 +1312,36 @@ 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,
- u8 key_size, __le16 ediv, u8 rand[8], u8 ltk[16])
+int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type,
+ int new_key, u8 authenticated, u8 tk[16],
+ u8 enc_size, u16 ediv, u8 rand[8])
{
- struct link_key *key, *old_key;
- struct key_master_id *id;
- u8 old_key_type;
+ struct smp_ltk *key, *old_key;

- BT_DBG("%s addr %s", hdev->name, batostr(bdaddr));
+ if (!(type & HCI_SMP_STK) && !(type & HCI_SMP_LTK))
+ return 0;

- old_key = hci_find_link_key_type(hdev, bdaddr, HCI_LK_SMP_LTK);
- if (old_key) {
+ old_key = hci_find_ltk_addr(hdev, bdaddr, addr_type);
+ if (old_key)
key = old_key;
- old_key_type = old_key->type;
- } else {
- key = kzalloc(sizeof(*key) + sizeof(*id), GFP_ATOMIC);
+ else {
+ key = kzalloc(sizeof(*key), GFP_ATOMIC);
if (!key)
return -ENOMEM;
- list_add(&key->list, &hdev->link_keys);
- old_key_type = 0xff;
+ list_add(&key->list, &hdev->ltks);
}

- key->dlen = sizeof(*id);
-
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;
- memcpy(id->rand, rand, sizeof(id->rand));
+ key->bdaddr_type = addr_type;
+ memcpy(key->val, tk, sizeof(key->val));
+ key->authenticated = authenticated;
+ key->ediv = ediv;
+ key->enc_size = enc_size;
+ key->type = type;
+ memcpy(key->rand, rand, sizeof(key->rand));

- if (new_key)
- mgmt_new_link_key(hdev, key, old_key_type);
+ if (!new_key)
+ return 0;

return 0;
}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 94a9ca2..750fc0c 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3227,7 +3227,7 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
struct hci_cp_le_ltk_reply cp;
struct hci_cp_le_ltk_neg_reply neg;
struct hci_conn *conn;
- struct link_key *ltk;
+ struct smp_ltk *ltk;

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

@@ -3243,10 +3243,15 @@ 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;
+
+ if (ltk->authenticated)
+ conn->sec_level = BT_SECURITY_HIGH;

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

+ if (ltk->type & HCI_SMP_STK)
+ kfree(ltk);
+
hci_dev_unlock(hdev);

return;
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index b7f2fd1..7bc82e4 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -472,8 +472,9 @@ static void random_work(struct work_struct *work)
memset(stk + smp->enc_key_size, 0,
SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);

- hci_add_ltk(hcon->hdev, 0, conn->dst, smp->enc_key_size,
- ediv, rand, stk);
+ hci_add_ltk(hcon->hdev, conn->dst, hcon->dst_type,
+ HCI_SMP_STK_SLAVE, 0, 0, stk,
+ smp->enc_key_size, ediv, rand);
}

return;
@@ -698,12 +699,10 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)

static u8 smp_ltk_encrypt(struct l2cap_conn *conn)
{
- struct link_key *key;
- struct key_master_id *master;
+ struct smp_ltk *key;
struct hci_conn *hcon = conn->hcon;

- key = hci_find_link_key_type(hcon->hdev, conn->dst,
- HCI_LK_SMP_LTK);
+ key = hci_find_ltk_addr(hcon->hdev, conn->dst, hcon->dst_type);
if (!key)
return 0;

@@ -711,10 +710,8 @@ static u8 smp_ltk_encrypt(struct l2cap_conn *conn)
&hcon->pend))
return 1;

- master = (void *) key->data;
- hci_le_start_enc(hcon, master->ediv, master->rand,
- key->val);
- hcon->enc_key_size = key->pin_len;
+ hci_le_start_enc(hcon, key->ediv, key->rand, key->val);
+ hcon->enc_key_size = key->enc_size;

return 1;

@@ -817,13 +814,19 @@ 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_chan *smp = conn->smp_chan;
+ struct hci_dev *hdev = conn->hcon->hdev;
+ struct hci_conn *hcon = conn->hcon;
+ u8 authenticated;

skb_pull(skb, sizeof(*rp));

- hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->enc_key_size,
- rp->ediv, rp->rand, smp->tk);
-
+ hci_dev_lock(hdev);
+ authenticated = (conn->hcon->sec_level == BT_SECURITY_HIGH);
+ hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type,
+ HCI_SMP_LTK, 1, authenticated, smp->tk,
+ smp->enc_key_size, rp->ediv, rp->rand);
smp_distribute_keys(conn, 1);
+ hci_dev_unlock(hdev);

return 0;
}
@@ -933,6 +936,8 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
if (*keydist & SMP_DIST_ENC_KEY) {
struct smp_cmd_encrypt_info enc;
struct smp_cmd_master_ident ident;
+ struct hci_conn *hcon = conn->hcon;
+ u8 authenticated;
__le16 ediv;

get_random_bytes(enc.ltk, sizeof(enc.ltk));
@@ -941,8 +946,11 @@ 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, smp->enc_key_size,
- ediv, ident.rand, enc.ltk);
+ authenticated = hcon->sec_level == BT_SECURITY_HIGH;
+ hci_add_ltk(conn->hcon->hdev, conn->dst, hcon->dst_type,
+ HCI_SMP_LTK_SLAVE, 1, authenticated,
+ enc.ltk, smp->enc_key_size,
+ ediv, ident.rand);

ident.ediv = cpu_to_le16(ediv);

--
1.7.8.1


2012-01-13 19:39:35

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH 3/8] Bluetooth: Add new structures for handling SMP Long Term Keys

This includes a new list for storing the keys and a new structure used
to represent each key.

Some notes: authenticated is used to identify that the key may be used
to setup a HIGH security link. As the same list is used to store both
the STK's and the LTK's the type field is used so we can separate
between those two types of keys and if the key should be used when
in the master or slave role.

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

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 8499307..3056115 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -273,6 +273,11 @@ enum {
#define HCI_LK_SMP_LTK 0x81
#define HCI_LK_SMP_IRK 0x82
#define HCI_LK_SMP_CSRK 0x83
+/* The spec doesn't define types for SMP keys, the _MASTER suffix is implied */
+#define HCI_SMP_STK 0x80
+#define HCI_SMP_STK_SLAVE 0x81
+#define HCI_SMP_LTK 0x82
+#define HCI_SMP_LTK_SLAVE 0x83

/* ---- HCI Error Codes ---- */
#define HCI_ERROR_AUTH_FAILURE 0x05
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 59e3541..9d77a66 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -88,6 +88,18 @@ struct bt_uuid {
u8 svc_hint;
};

+struct smp_ltk {
+ struct list_head list;
+ bdaddr_t bdaddr;
+ u8 bdaddr_type;
+ u8 authenticated;
+ u8 type;
+ u8 enc_size;
+ __le16 ediv;
+ u8 rand[8];
+ u8 val[16];
+} __packed;
+
struct key_master_id {
__le16 ediv;
u8 rand[8];
@@ -240,6 +252,8 @@ struct hci_dev {

struct list_head link_keys;

+ struct list_head ltks;
+
struct list_head remote_oob_data;

struct list_head adv_entries;
@@ -643,6 +657,7 @@ struct link_key *hci_find_link_key_type(struct hci_dev *hdev,
int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
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_smp_ltks_clear(struct hci_dev *hdev);

int hci_remote_oob_data_clear(struct hci_dev *hdev);
struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index a7b7200..3b5902d 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1163,6 +1163,18 @@ int hci_link_keys_clear(struct hci_dev *hdev)
return 0;
}

+int hci_smp_ltks_clear(struct hci_dev *hdev)
+{
+ struct smp_ltk *k, *tmp;
+
+ list_for_each_entry_safe(k, tmp, &hdev->ltks, list) {
+ list_del(&k->list);
+ kfree(k);
+ }
+
+ return 0;
+}
+
struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
struct link_key *k;
@@ -1355,6 +1367,23 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
return 0;
}

+int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr)
+{
+ struct smp_ltk *k, *tmp;
+
+ list_for_each_entry_safe(k, tmp, &hdev->ltks, list) {
+ if (bacmp(bdaddr, &k->bdaddr))
+ continue;
+
+ BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
+
+ list_del(&k->list);
+ kfree(k);
+ }
+
+ return 0;
+}
+
/* HCI command timer function */
static void hci_cmd_timer(unsigned long arg)
{
@@ -1638,6 +1667,7 @@ int hci_register_dev(struct hci_dev *hdev)
INIT_LIST_HEAD(&hdev->uuids);

INIT_LIST_HEAD(&hdev->link_keys);
+ INIT_LIST_HEAD(&hdev->ltks);

INIT_LIST_HEAD(&hdev->remote_oob_data);

@@ -1739,6 +1769,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_blacklist_clear(hdev);
hci_uuids_clear(hdev);
hci_link_keys_clear(hdev);
+ hci_smp_ltks_clear(hdev);
hci_remote_oob_data_clear(hdev);
hci_adv_entries_clear(hdev);
hci_dev_unlock(hdev);
--
1.7.8.1


2012-01-13 19:39:34

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH 2/8] Bluetooth: Rename smp_key_size to enc_key_size

This makes clear that this is the size of the key used to
encrypt the link.

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

diff --git a/include/net/bluetooth/smp.h b/include/net/bluetooth/smp.h
index aeaf5fa..7b3acdd 100644
--- a/include/net/bluetooth/smp.h
+++ b/include/net/bluetooth/smp.h
@@ -127,7 +127,7 @@ struct smp_chan {
u8 rrnd[16]; /* SMP Pairing Random (remote) */
u8 pcnf[16]; /* SMP Pairing Confirm */
u8 tk[16]; /* SMP Temporary Key */
- u8 smp_key_size;
+ u8 enc_key_size;
unsigned long smp_flags;
struct crypto_blkcipher *tfm;
struct work_struct confirm;
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 65a9024..b7f2fd1 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -250,7 +250,7 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
(max_key_size < SMP_MIN_ENC_KEY_SIZE))
return SMP_ENC_KEY_SIZE;

- smp->smp_key_size = max_key_size;
+ smp->enc_key_size = max_key_size;

return 0;
}
@@ -446,8 +446,8 @@ static void random_work(struct work_struct *work)
smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key);
swap128(key, stk);

- memset(stk + smp->smp_key_size, 0,
- SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size);
+ memset(stk + smp->enc_key_size, 0,
+ SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);

if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) {
reason = SMP_UNSPECIFIED;
@@ -455,7 +455,7 @@ static void random_work(struct work_struct *work)
}

hci_le_start_enc(hcon, ediv, rand, stk);
- hcon->enc_key_size = smp->smp_key_size;
+ hcon->enc_key_size = smp->enc_key_size;
} else {
u8 stk[16], r[16], rand[8];
__le16 ediv;
@@ -469,10 +469,10 @@ static void random_work(struct work_struct *work)
smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, key);
swap128(key, stk);

- memset(stk + smp->smp_key_size, 0,
- SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size);
+ memset(stk + smp->enc_key_size, 0,
+ SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);

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

@@ -820,7 +820,7 @@ 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->dst, smp->smp_key_size,
+ hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->enc_key_size,
rp->ediv, rp->rand, smp->tk);

smp_distribute_keys(conn, 1);
@@ -941,7 +941,7 @@ 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, smp->smp_key_size,
+ hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->enc_key_size,
ediv, ident.rand, enc.ltk);

ident.ediv = cpu_to_le16(ediv);
--
1.7.8.1


2012-01-13 19:39:33

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH 1/8] Bluetooth: Add structures for the new LTK exchange messages

This defines two new messages, one event that will inform
userspace that a new Long Term Key was exchanged and one that
will allow userspace to load LTKs into the kernel.

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

diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index be65d34..994b551 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -288,6 +288,22 @@ struct mgmt_cp_unblock_device {
bdaddr_t bdaddr;
} __packed;

+struct mgmt_ltk_info {
+ struct mgmt_addr_info addr;
+ __u8 authenticated;
+ __u8 master;
+ __u8 enc_size;
+ __le16 ediv;
+ __u8 rand[8];
+ __u8 val[16];
+} __packed;
+
+#define MGMT_OP_LOAD_LONG_TERM_KEYS 0x0026
+struct mgmt_cp_load_long_term_keys {
+ __u16 key_count;
+ struct mgmt_ltk_info keys[0];
+} __packed;
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
@@ -388,3 +404,9 @@ struct mgmt_ev_device_blocked {
struct mgmt_ev_device_unblocked {
bdaddr_t bdaddr;
} __packed;
+
+#define MGMT_EV_NEW_LONG_TERM_KEY 0x0016
+struct mgmt_ev_new_long_term_key {
+ __u8 store_hint;
+ struct mgmt_ltk_info key;
+} __packed;
--
1.7.8.1