2012-01-17 23:28:40

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ 01/11] mgmt-api: Update the commands for exchanging LTK's

For restoring the device from storage we need to have the Address type
of the device, the LTK is a good place for this.

In some cases, we may be notified of keys that were generated in the
Host, that key key would be used when the Host is the slave role in
a later connection, we should be able to differentiate this type of
key because it doesn't mean that we have a bonding with the Remote
Device.
---
doc/mgmt-api.txt | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt
index 3e188c2..8fe7c94 100644
--- a/doc/mgmt-api.txt
+++ b/doc/mgmt-api.txt
@@ -477,7 +477,9 @@ Load Long Term Keys Command
Command Parameters: Key Count (2 Octets)
Key1 {
Address (6 Octets)
+ Type (1 Octet)
Authenticated (1 Octet)
+ Master (1 Octet)
Encryption Size (1 Octet)
Enc. Diversifier (2 Octets)
Random Number (8 Octets)
@@ -758,7 +760,9 @@ Controller Index <controller id>
Event Parameters Store Hint (1 Octet)
Key {
Address (6 Octets)
+ Type (1 Octet)
Authenticated (1 Octet)
+ Master (1 Octet)
Encryption Size (1 Octet)
Enc. Diversifier (2 Octets)
Random Number (8 Octets)
--
1.7.8.1



2012-01-18 22:34:26

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH BlueZ 08/11] Add support for sending the Load Long Term Keys commands

Hi Vinicius,

On Tue, Jan 17, 2012, Vinicius Costa Gomes wrote:
> Also this adds another method to the adapter_ops method table,
> this method allows LTKs to be loaded to the kernel.
> ---
> plugins/hciops.c | 6 +++++
> plugins/mgmtops.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> src/adapter.h | 12 +++++++++++
> 3 files changed, 73 insertions(+), 0 deletions(-)

All patches up until this one have been applied. I'm waiting for an
update for the rest based on our discussion in IRC.

Johan

2012-01-18 17:12:31

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ 02/11] Add messages to the mgmt interface to handle SMP key storage

The SMP keys are to be communicated to/from userspace using these
messages.
---
Johan,

Just a note that I need to update my kernel patches after you remove
the Remote Name event.

lib/mgmt.h | 22 ++++++++++++++++++++++
1 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/lib/mgmt.h b/lib/mgmt.h
index 5414ea6..af63889 100644
--- a/lib/mgmt.h
+++ b/lib/mgmt.h
@@ -275,6 +275,22 @@ struct mgmt_cp_unblock_device {
bdaddr_t bdaddr;
} __packed;

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


2012-01-18 14:51:42

by Anderson Lizardo

[permalink] [raw]
Subject: Re: [PATCH BlueZ 01/11] mgmt-api: Update the commands for exchanging LTK's

Hi Chen,

On Wed, Jan 18, 2012 at 10:41 AM, Ganir, Chen <[email protected]> wrote:
>> Note that BlueZ is still relying on the kernel LE advertising cache
>> (which is refreshed with either the automatic scanning prior to
>> connection, or with the future background scanning support) for
>> detecting address type for non-bonded devices. We have no plans to
>> change that in near feature, because IIRC it would require changing
>> bluetooth socket API (which would break all current BR/EDR
>> applications).
>>
>> This is an issue separate from LTK storage, if you are interested on
>> pursuing this, feel free to make a proposal.
>>
>
> I have a working implementation now that is able to create a connection for bonded devices (currently just bonded devices, but in the future, any created device node) without relying on the scan cache. I simply store the device address, and use it when connecting to that device. I see no reason or possibility for a device to change its address type during its life time (correct me if I'm wrong, and please describe a use case for that).

How do you know which address type to use for LE Create Connection
(Own_Address_Type in page 1073) on the kernel side? AFAIK, there is no
way to differentiate a public address from random just by looking at
the address (the public address has no "reserved" bits). You need the
address type as found on the advertising reports.

What do you mean by "store"? for how long it is stored, specially for
non-bonded devices? Is it on kernel or userspace?

Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

2012-01-18 14:41:34

by Ganir, Chen

[permalink] [raw]
Subject: RE: [PATCH BlueZ 01/11] mgmt-api: Update the commands for exchanging LTK's

Lizardo,


> -----Original Message-----
> From: Anderson Lizardo [mailto:[email protected]]
> Sent: Wednesday, January 18, 2012 12:41 PM
> To: Ganir, Chen
> Cc: Vinicius Costa Gomes; [email protected]
> Subject: Re: [PATCH BlueZ 01/11] mgmt-api: Update the commands for
> exchanging LTK's
>
> Hi Chen,
>
> On Wed, Jan 18, 2012 at 3:17 AM, Ganir, Chen <[email protected]> wrote:
> > Storing the address type in the LTK is not perfect. For this to work
> properly, you will store the address type only for devices which
> exchanged keys. What if we have devices which do not do pairing or
> exchange keys at all ? What if we use the CreateDevice instead of
> CreatePairedDevice? In that case we will not have the address type for
> future reconnections. We need to store the device address type in a
> separate file (for example, addresstypes) and manage it separately from
> the LTK management.
>
> Note that BlueZ is still relying on the kernel LE advertising cache
> (which is refreshed with either the automatic scanning prior to
> connection, or with the future background scanning support) for
> detecting address type for non-bonded devices. We have no plans to
> change that in near feature, because IIRC it would require changing
> bluetooth socket API (which would break all current BR/EDR
> applications).
>
> This is an issue separate from LTK storage, if you are interested on
> pursuing this, feel free to make a proposal.
>

I have a working implementation now that is able to create a connection for bonded devices (currently just bonded devices, but in the future, any created device node) without relying on the scan cache. I simply store the device address, and use it when connecting to that device. I see no reason or possibility for a device to change its address type during its life time (correct me if I'm wrong, and please describe a use case for that).



> Best Regards,
> --
> Anderson Lizardo
> Instituto Nokia de Tecnologia - INdT
> Manaus - Brazil


Thanks,
Chen Ganir

2012-01-18 14:37:32

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH BlueZ 02/11] Add messages to the mgmt interface to handle SMP key storage

Hi Vinicius,

On Wed, Jan 18, 2012, Vinicius Costa Gomes wrote:
> On 13:57 Wed 18 Jan, Johan Hedberg wrote:
> > Hi Vinicius,
> >
> > On Tue, Jan 17, 2012, Vinicius Costa Gomes wrote:
> > > +#define MGMT_EV_NEW_LONG_TERM_KEY 0x0016
> > > +struct mgmt_ev_new_long_term_key {
> > > + uint8_t store_hint;
> > > + struct mgmt_ltk_info key;
> > > +} __packed;
> >
> > I've pushed the first patch, but this doesn't match mgmt-api.txt. In the
> > API doc the event code is 0x0015.
>
> Going to fix it. That happened because in the kernel side we still have
> the Remote Name event, that was removed from userspace. I will send a
> patch to remove that event.

Please don't. I already have the kernel-side mgmt_ev_remote_name removal
in my own local tree together with a quite big patch set (13 patches
right now). I'll send it to linux-bluetooth as soon as I finish some
final polishing.

Johan

2012-01-18 14:26:51

by Vinicius Costa Gomes

[permalink] [raw]
Subject: Re: [PATCH BlueZ 02/11] Add messages to the mgmt interface to handle SMP key storage

Hi Johan,

On 13:57 Wed 18 Jan, Johan Hedberg wrote:
> Hi Vinicius,
>
> On Tue, Jan 17, 2012, Vinicius Costa Gomes wrote:
> > +#define MGMT_EV_NEW_LONG_TERM_KEY 0x0016
> > +struct mgmt_ev_new_long_term_key {
> > + uint8_t store_hint;
> > + struct mgmt_ltk_info key;
> > +} __packed;
>
> I've pushed the first patch, but this doesn't match mgmt-api.txt. In the
> API doc the event code is 0x0015.

Going to fix it. That happened because in the kernel side we still have
the Remote Name event, that was removed from userspace. I will send a
patch to remove that event.

>
> Johan

Cheers,
--
Vinicius

2012-01-18 11:57:35

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH BlueZ 02/11] Add messages to the mgmt interface to handle SMP key storage

Hi Vinicius,

On Tue, Jan 17, 2012, Vinicius Costa Gomes wrote:
> +#define MGMT_EV_NEW_LONG_TERM_KEY 0x0016
> +struct mgmt_ev_new_long_term_key {
> + uint8_t store_hint;
> + struct mgmt_ltk_info key;
> +} __packed;

I've pushed the first patch, but this doesn't match mgmt-api.txt. In the
API doc the event code is 0x0015.

Johan

2012-01-18 10:40:42

by Anderson Lizardo

[permalink] [raw]
Subject: Re: [PATCH BlueZ 01/11] mgmt-api: Update the commands for exchanging LTK's

Hi Chen,

On Wed, Jan 18, 2012 at 3:17 AM, Ganir, Chen <[email protected]> wrote:
> Storing the address type in the LTK is not perfect. For this to work properly, you will store the address type only for devices which exchanged keys. What if we have devices which do not do pairing or exchange keys at all ? What if we use the CreateDevice instead of CreatePairedDevice? In that case we will not have the address type for future reconnections. We need to store the device address type in a separate file (for example, addresstypes) and manage it separately from the LTK management.

Note that BlueZ is still relying on the kernel LE advertising cache
(which is refreshed with either the automatic scanning prior to
connection, or with the future background scanning support) for
detecting address type for non-bonded devices. We have no plans to
change that in near feature, because IIRC it would require changing
bluetooth socket API (which would break all current BR/EDR
applications).

This is an issue separate from LTK storage, if you are interested on
pursuing this, feel free to make a proposal.

Best Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

2012-01-18 07:17:02

by Ganir, Chen

[permalink] [raw]
Subject: RE: [PATCH BlueZ 01/11] mgmt-api: Update the commands for exchanging LTK's

Vinicius,

> -----Original Message-----
> From: [email protected] [mailto:linux-bluetooth-
> [email protected]] On Behalf Of Vinicius Costa Gomes
> Sent: Wednesday, January 18, 2012 1:29 AM
> To: [email protected]
> Cc: Vinicius Costa Gomes
> Subject: [PATCH BlueZ 01/11] mgmt-api: Update the commands for
> exchanging LTK's
>
> For restoring the device from storage we need to have the Address type
> of the device, the LTK is a good place for this.

Storing the address type in the LTK is not perfect. For this to work properly, you will store the address type only for devices which exchanged keys. What if we have devices which do not do pairing or exchange keys at all ? What if we use the CreateDevice instead of CreatePairedDevice? In that case we will not have the address type for future reconnections. We need to store the device address type in a separate file (for example, addresstypes) and manage it separately from the LTK management.

>
> In some cases, we may be notified of keys that were generated in the
> Host, that key key would be used when the Host is the slave role in
> a later connection, we should be able to differentiate this type of
> key because it doesn't mean that we have a bonding with the Remote
> Device.
> ---
> doc/mgmt-api.txt | 4 ++++
> 1 files changed, 4 insertions(+), 0 deletions(-)
>
> diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt
> index 3e188c2..8fe7c94 100644
> --- a/doc/mgmt-api.txt
> +++ b/doc/mgmt-api.txt
> @@ -477,7 +477,9 @@ Load Long Term Keys Command
> Command Parameters: Key Count (2 Octets)
> Key1 {
> Address (6 Octets)
> + Type (1 Octet)
> Authenticated (1 Octet)
> + Master (1 Octet)
> Encryption Size (1 Octet)
> Enc. Diversifier (2 Octets)
> Random Number (8 Octets)
> @@ -758,7 +760,9 @@ Controller Index <controller id>
> Event Parameters Store Hint (1 Octet)
> Key {
> Address (6 Octets)
> + Type (1 Octet)
> Authenticated (1 Octet)
> + Master (1 Octet)
> Encryption Size (1 Octet)
> Enc. Diversifier (2 Octets)
> Random Number (8 Octets)
> --
> 1.7.8.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-
> bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html


Thanks,
Chen Ganir


2012-01-17 23:28:50

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ 11/11] Remove the SMP Long Term Key when the device is removed

---
src/device.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/src/device.c b/src/device.c
index 16855b1..8d02c2c 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1088,6 +1088,7 @@ static void device_remove_stored(struct btd_device *device)
if (device_is_bonded(device)) {
delete_entry(&src, "linkkeys", addr);
delete_entry(&src, "aliases", addr);
+ delete_entry(&src, "longtermkeys", addr);
device_set_bonded(device, FALSE);
device->paired = FALSE;
btd_adapter_remove_bonding(device->adapter, &device->bdaddr);
--
1.7.8.1


2012-01-17 23:28:49

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ 10/11] Fix memory leak when loading keys

If we need a copy of those keys we should copy them.
---
plugins/hciops.c | 13 ++++++++++++-
1 files changed, 12 insertions(+), 1 deletions(-)

diff --git a/plugins/hciops.c b/plugins/hciops.c
index f519e0c..72c12cb 100644
--- a/plugins/hciops.c
+++ b/plugins/hciops.c
@@ -3558,6 +3558,7 @@ static int hciops_restore_powered(int index)
static int hciops_load_keys(int index, GSList *keys, gboolean debug_keys)
{
struct dev_info *dev = &devs[index];
+ GSList *l, *new;

DBG("hci%d keys %d debug_keys %d", index, g_slist_length(keys),
debug_keys);
@@ -3565,7 +3566,17 @@ static int hciops_load_keys(int index, GSList *keys, gboolean debug_keys)
if (dev->keys != NULL)
return -EEXIST;

- dev->keys = keys;
+ for (new = NULL, l = keys; l; l = l->next) {
+ struct link_key_info *orig, *dup;
+
+ orig = l->data;
+
+ dup = g_memdup(orig, sizeof(*orig));
+
+ new = g_slist_prepend(new, dup);
+ }
+
+ dev->keys = new;
dev->debug_keys = debug_keys;

return 0;
--
1.7.8.1


2012-01-17 23:28:48

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ 09/11] Add support for creating devices from the stored LTK's

---
src/adapter.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 111 insertions(+), 3 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 2984d80..f549d40 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1829,6 +1829,65 @@ static struct link_key_info *get_key_info(const char *addr, const char *value)
return info;
}

+static int str2buf(const char *str, uint8_t *buf, size_t blen)
+{
+ int i, dlen;
+
+ if (str == NULL)
+ return -EINVAL;
+
+ memset(buf, 0, blen);
+
+ dlen = MIN((strlen(str) / 2), blen);
+
+ for (i = 0; i < dlen; i++)
+ sscanf(str + (i * 2), "%02hhX", &buf[i]);
+
+ return 0;
+}
+
+static struct smp_ltk_info *get_ltk_info(const char *addr, const char *value)
+{
+ struct smp_ltk_info *ltk;
+ char tmp[3], *ptr;
+ int i, ret, total;
+
+ total = strlen(value);
+ if (total < 60) {
+ error("Unexpectedly short (%zu) LTK", strlen(value));
+ return NULL;
+ }
+
+ ltk = g_new0(struct smp_ltk_info, 1);
+
+ str2ba(addr, &ltk->bdaddr);
+
+ memset(tmp, 0, sizeof(tmp));
+
+ for (i = 0; i < 16; i++) {
+ memcpy(tmp, value + (i * 2), 2);
+ ltk->val[i] = (uint8_t) strtol(tmp, NULL, 16);
+ }
+
+ ptr = (char *) value + 33;
+ total -= 33;
+
+ ret = sscanf(ptr, " %hhd %hhd %hhd %hhd %hd %n",
+ (uint8_t *) &ltk->addr_type,
+ &ltk->authenticated, &ltk->master,
+ &ltk->enc_size, &ltk->ediv, &i);
+ if (ret < 2) {
+ g_free(ltk);
+ return NULL;
+ }
+ ptr += i;
+ total -= i;
+
+ str2buf(ptr, ltk->rand, sizeof(ltk->rand));
+
+ return ltk;
+}
+
static void create_stored_device_from_linkkeys(char *key, char *value,
void *user_data)
{
@@ -1852,6 +1911,37 @@ static void create_stored_device_from_linkkeys(char *key, char *value,
}
}

+static void create_stored_device_from_ltks(char *key, char *value,
+ void *user_data)
+{
+ struct adapter_keys *keys = user_data;
+ struct btd_adapter *adapter = keys->adapter;
+ struct btd_device *device;
+ struct smp_ltk_info *info;
+ char srcaddr[18];
+ bdaddr_t src;
+
+ info = get_ltk_info(key, value);
+ if (info)
+ keys->keys = g_slist_append(keys->keys, info);
+
+ if (g_slist_find_custom(adapter->devices, key,
+ (GCompareFunc) device_address_cmp))
+ return;
+
+ adapter_get_address(adapter, &src);
+ ba2str(&src, srcaddr);
+
+ if (g_strcmp0(srcaddr, key) == 0)
+ return;
+
+ device = device_create(connection, adapter, key, info->addr_type);
+ if (device) {
+ device_set_temporary(device, FALSE);
+ adapter->devices = g_slist_append(adapter->devices, device);
+ }
+}
+
static void create_stored_device_from_blocked(char *key, char *value,
void *user_data)
{
@@ -1939,6 +2029,13 @@ static void create_stored_device_from_primary(char *key, char *value,
g_slist_free(uuids);
}

+static void smp_key_free(void *data)
+{
+ struct smp_ltk_info *info = data;
+
+ g_free(info);
+}
+
static void load_devices(struct btd_adapter *adapter)
{
char filename[PATH_MAX + 1];
@@ -1961,11 +2058,22 @@ static void load_devices(struct btd_adapter *adapter)

err = adapter_ops->load_keys(adapter->dev_id, keys.keys,
main_opts.debug_keys);
- if (err < 0) {
+ if (err < 0)
error("Unable to load keys to adapter_ops: %s (%d)",
strerror(-err), -err);
- g_slist_free_full(keys.keys, g_free);
- }
+
+ g_slist_free_full(keys.keys, g_free);
+ keys.keys = NULL;
+
+ create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "longtermkeys");
+ textfile_foreach(filename, create_stored_device_from_ltks, &keys);
+
+ err = adapter_ops->load_ltks(adapter->dev_id, keys.keys);
+ if (err < 0)
+ error("Unable to load keys to adapter_ops: %s (%d)",
+ strerror(-err), -err);
+ g_slist_free_full(keys.keys, smp_key_free);
+ keys.keys = NULL;

create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "blocked");
textfile_foreach(filename, create_stored_device_from_blocked, adapter);
--
1.7.8.1


2012-01-17 23:28:47

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ 08/11] Add support for sending the Load Long Term Keys commands

Also this adds another method to the adapter_ops method table,
this method allows LTKs to be loaded to the kernel.
---
plugins/hciops.c | 6 +++++
plugins/mgmtops.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++
src/adapter.h | 12 +++++++++++
3 files changed, 73 insertions(+), 0 deletions(-)

diff --git a/plugins/hciops.c b/plugins/hciops.c
index 0c59c31..f519e0c 100644
--- a/plugins/hciops.c
+++ b/plugins/hciops.c
@@ -3779,6 +3779,11 @@ static int hciops_confirm_name(int index, bdaddr_t *bdaddr,
return 0;
}

+static int hciops_load_ltks(int index, GSList *keys)
+{
+ return -ENOSYS;
+}
+
static struct btd_adapter_ops hci_ops = {
.setup = hciops_setup,
.cleanup = hciops_cleanup,
@@ -3815,6 +3820,7 @@ static struct btd_adapter_ops hci_ops = {
.add_remote_oob_data = hciops_add_remote_oob_data,
.remove_remote_oob_data = hciops_remove_remote_oob_data,
.confirm_name = hciops_confirm_name,
+ .load_ltks = hciops_load_ltks,
};

static int hciops_init(void)
diff --git a/plugins/mgmtops.c b/plugins/mgmtops.c
index 610bb72..40e1572 100644
--- a/plugins/mgmtops.c
+++ b/plugins/mgmtops.c
@@ -2075,6 +2075,60 @@ static int mgmt_confirm_name(int index, bdaddr_t *bdaddr, gboolean name_known)
return 0;
}

+
+static int mgmtops_load_ltks(int index, GSList *keys)
+{
+ char *buf;
+ struct mgmt_hdr *hdr;
+ struct mgmt_cp_load_long_term_keys *cp;
+ struct mgmt_ltk_info *key;
+ size_t key_count, cp_size;
+ GSList *l;
+ int err;
+
+ key_count = g_slist_length(keys);
+
+ DBG("index %d keys %zu", index, key_count);
+
+ cp_size = sizeof(*cp) + (key_count * sizeof(*key));
+
+ buf = g_try_malloc0(sizeof(*hdr) + cp_size);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ memset(buf, 0, sizeof(buf));
+
+ hdr = (void *) buf;
+ hdr->opcode = htobs(MGMT_OP_LOAD_LONG_TERM_KEYS);
+ hdr->len = htobs(cp_size);
+ hdr->index = htobs(index);
+
+ cp = (void *) (buf + sizeof(*hdr));
+ cp->key_count = htobs(key_count);
+
+ for (l = keys, key = cp->keys; l != NULL; l = g_slist_next(l), key++) {
+ struct smp_ltk_info *info = l->data;
+
+ bacpy(&key->addr.bdaddr, &info->bdaddr);
+ key->addr.type = info->addr_type;
+ memcpy(key->val, info->val, sizeof(info->val));
+ memcpy(key->rand, info->rand, sizeof(info->rand));
+ memcpy(&key->ediv, &info->ediv, sizeof(key->ediv));
+ key->authenticated = info->authenticated;
+ key->master = info->master;
+ key->enc_size = info->enc_size;
+ }
+
+ if (write(mgmt_sock, buf, sizeof(*hdr) + cp_size) < 0)
+ err = -errno;
+ else
+ err = 0;
+
+ g_free(buf);
+
+ return err;
+}
+
static struct btd_adapter_ops mgmt_ops = {
.setup = mgmt_setup,
.cleanup = mgmt_cleanup,
@@ -2111,6 +2165,7 @@ static struct btd_adapter_ops mgmt_ops = {
.add_remote_oob_data = mgmt_add_remote_oob_data,
.remove_remote_oob_data = mgmt_remove_remote_oob_data,
.confirm_name = mgmt_confirm_name,
+ .load_ltks = mgmtops_load_ltks,
};

static int mgmt_init(void)
diff --git a/src/adapter.h b/src/adapter.h
index fb1dcdf..1e11e93 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -56,6 +56,17 @@ struct link_key_info {
uint8_t pin_len;
};

+struct smp_ltk_info {
+ bdaddr_t bdaddr;
+ addr_type_t addr_type;
+ uint8_t authenticated;
+ uint8_t master;
+ uint8_t enc_size;
+ uint16_t ediv;
+ uint8_t rand[8];
+ uint8_t val[16];
+};
+
struct remote_dev_info {
bdaddr_t bdaddr;
addr_type_t type;
@@ -209,6 +220,7 @@ struct btd_adapter_ops {
uint8_t *randomizer);
int (*remove_remote_oob_data) (int index, bdaddr_t *bdaddr);
int (*confirm_name) (int index, bdaddr_t *bdaddr, gboolean name_known);
+ int (*load_ltks) (int index, GSList *keys);
};

int btd_register_adapter_ops(struct btd_adapter_ops *ops, gboolean priority);
--
1.7.8.1


2012-01-17 23:28:46

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ 07/11] Add support for handing the New LTK mgmt event

This event would cause this key to be permanently stored.
---
plugins/mgmtops.c | 35 +++++++++++++++++++++++++++++++++++
1 files changed, 35 insertions(+), 0 deletions(-)

diff --git a/plugins/mgmtops.c b/plugins/mgmtops.c
index 6d98ad9..610bb72 100644
--- a/plugins/mgmtops.c
+++ b/plugins/mgmtops.c
@@ -1386,6 +1386,38 @@ static void mgmt_device_unblocked(int sk, uint16_t index, void *buf, size_t len)
btd_event_device_unblocked(&info->bdaddr, &ev->bdaddr);
}

+static void mgmt_new_ltk(int sk, uint16_t index, void *buf, size_t len)
+{
+ struct mgmt_ev_new_long_term_key *ev = buf;
+ struct controller_info *info;
+
+ if (len != sizeof(*ev)) {
+ error("new_smp_key event size mismatch (%zu != %zu)",
+ len, sizeof(*ev));
+ return;
+ }
+
+ DBG("Controller %u new LTK authenticated %u enc_size %u", index,
+ ev->key.authenticated, ev->key.enc_size);
+
+ if (index > max_index) {
+ error("Unexpected index %u in new_key event", index);
+ return;
+ }
+
+ info = &controllers[index];
+
+ if (ev->store_hint) {
+ btd_event_ltk_notify(&info->bdaddr, &ev->key.addr.bdaddr,
+ ev->key.addr.type, ev->key.val,
+ ev->key.authenticated, ev->key.enc_size,
+ ev->key.master, ev->key.ediv, ev->key.rand);
+ }
+
+ if (ev->key.master)
+ bonding_complete(info, &ev->key.addr.bdaddr, 0);
+}
+
static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data)
{
char buf[MGMT_BUF_SIZE];
@@ -1487,6 +1519,9 @@ static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data
case MGMT_EV_USER_PASSKEY_REQUEST:
mgmt_passkey_request(sk, index, buf + MGMT_HDR_SIZE, len);
break;
+ case MGMT_EV_NEW_LONG_TERM_KEY:
+ mgmt_new_ltk(sk, index, buf + MGMT_HDR_SIZE, len);
+ break;
default:
error("Unknown Management opcode %u (index %u)", opcode, index);
break;
--
1.7.8.1


2012-01-17 23:28:45

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ 06/11] Add support for storing a LTK when it enters bluetoothd

---
src/event.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/event.h | 4 +++
2 files changed, 78 insertions(+), 0 deletions(-)

diff --git a/src/event.c b/src/event.c
index d0e192b..e1d49a1 100644
--- a/src/event.c
+++ b/src/event.c
@@ -345,6 +345,56 @@ void btd_event_remote_name(bdaddr_t *local, bdaddr_t *peer, char *name)
device_set_name(device, name);
}

+static char *buf2str(uint8_t *data, int datalen)
+{
+ char *buf;
+ int i;
+
+ buf = g_try_new0(char, (datalen * 2) + 1);
+ if (buf == NULL)
+ return NULL;
+
+ for (i = 0; i < datalen; i++)
+ sprintf(buf + (i * 2), "%2.2x", data[i]);
+
+ return buf;
+}
+
+static int store_longtermkey(bdaddr_t *local, bdaddr_t *peer,
+ addr_type_t addr_type, unsigned char *key,
+ uint8_t master, uint8_t authenticated,
+ uint8_t enc_size, uint16_t ediv, uint8_t rand[8])
+{
+ GString *newkey;
+ char *val, *str;
+ int err;
+
+ val = buf2str(key, 16);
+ if (val == NULL)
+ return -ENOMEM;
+
+ newkey = g_string_new(val);
+ g_free(val);
+
+ g_string_append_printf(newkey, " %d %d %d %d %d ", addr_type,
+ authenticated, master, enc_size, ediv);
+
+ str = buf2str(rand, 8);
+ if (str == NULL) {
+ g_string_free(newkey, TRUE);
+ return -ENOMEM;
+ }
+
+ newkey = g_string_append(newkey, str);
+ g_free(str);
+
+ err = write_longtermkeys(local, peer, newkey->str);
+
+ g_string_free(newkey, TRUE);
+
+ return err;
+}
+
int btd_event_link_key_notify(bdaddr_t *local, bdaddr_t *peer,
uint8_t *key, uint8_t key_type,
uint8_t pin_length)
@@ -370,6 +420,30 @@ int btd_event_link_key_notify(bdaddr_t *local, bdaddr_t *peer,
return ret;
}

+int btd_event_ltk_notify(bdaddr_t *local, bdaddr_t *peer, addr_type_t addr_type,
+ uint8_t *key, uint8_t master,
+ uint8_t authenticated, uint8_t enc_size,
+ uint16_t ediv, uint8_t rand[8])
+{
+ struct btd_adapter *adapter;
+ struct btd_device *device;
+ int ret;
+
+ if (!get_adapter_and_device(local, peer, &adapter, &device, TRUE))
+ return -ENODEV;
+
+ ret = store_longtermkey(local, peer, addr_type, key, master,
+ authenticated, enc_size, ediv, rand);
+ if (ret == 0) {
+ device_set_bonded(device, TRUE);
+
+ if (device_is_temporary(device))
+ device_set_temporary(device, FALSE);
+ }
+
+ return ret;
+}
+
void btd_event_conn_complete(bdaddr_t *local, bdaddr_t *peer,
char *name, uint8_t *dev_class)
{
diff --git a/src/event.h b/src/event.h
index 57b7fd9..ec38e3e 100644
--- a/src/event.h
+++ b/src/event.h
@@ -42,3 +42,7 @@ void btd_event_device_blocked(bdaddr_t *local, bdaddr_t *peer);
void btd_event_device_unblocked(bdaddr_t *local, bdaddr_t *peer);
int btd_event_link_key_notify(bdaddr_t *local, bdaddr_t *peer, uint8_t *key,
uint8_t key_type, uint8_t pin_length);
+int btd_event_ltk_notify(bdaddr_t *local, bdaddr_t *peer, addr_type_t addr_type,
+ uint8_t *key, uint8_t master,
+ uint8_t authenticated, uint8_t enc_size,
+ uint16_t ediv, uint8_t rand[8]);
--
1.7.8.1


2012-01-17 23:28:44

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ 05/11] Fix using "magic" values for the key types

---
plugins/hciops.c | 10 ++++++----
1 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/plugins/hciops.c b/plugins/hciops.c
index 0ebf533..0c59c31 100644
--- a/plugins/hciops.c
+++ b/plugins/hciops.c
@@ -1028,12 +1028,12 @@ static void link_key_notify(int index, void *ptr)
DBG("local auth 0x%02x and remote auth 0x%02x",
conn->loc_auth, conn->rem_auth);

- if (key_type == 0x06) {
+ if (key_type == HCI_LK_CHANGED_COMBINATION) {
/* Some buggy controller combinations generate a changed
* combination key for legacy pairing even when there's no
* previous key */
if (conn->rem_auth == 0xff && old_key_type == 0xff)
- key_type = 0x00;
+ key_type = HCI_LK_COMBINATION;
else if (old_key_type != 0xff)
key_type = old_key_type;
else
@@ -1045,7 +1045,7 @@ static void link_key_notify(int index, void *ptr)
key_info->type = key_type;

/* Skip the storage check if this is a debug key */
- if (key_type == 0x03)
+ if (key_type == HCI_LK_DEBUG_COMBINATION)
goto done;

/* Store the link key persistently if one of the following is true:
@@ -1059,7 +1059,9 @@ static void link_key_notify(int index, void *ptr)
* If none of the above match only keep the link key around for
* this connection and set the temporary flag for the device.
*/
- if (key_type < 0x03 || (key_type == 0x06 && old_key_type != 0xff) ||
+ if (key_type < HCI_LK_DEBUG_COMBINATION ||
+ (key_type == HCI_LK_CHANGED_COMBINATION
+ && old_key_type != HCI_LK_INVALID) ||
(conn->loc_auth > 0x01 && conn->rem_auth > 0x01) ||
(conn->loc_auth == 0x02 || conn->loc_auth == 0x03) ||
(conn->rem_auth == 0x02 || conn->rem_auth == 0x03)) {
--
1.7.8.1


2012-01-17 23:28:43

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ 04/11] Add macros for the possible link key types

---
lib/hci.h | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/lib/hci.h b/lib/hci.h
index 48692fa..7f68ea0 100644
--- a/lib/hci.h
+++ b/lib/hci.h
@@ -293,6 +293,16 @@ enum {
#define HCI_LM_RELIABLE 0x0010
#define HCI_LM_SECURE 0x0020

+/* Link Key types */
+#define HCI_LK_COMBINATION 0x00
+#define HCI_LK_LOCAL_UNIT 0x01
+#define HCI_LK_REMOTE_UNIT 0x02
+#define HCI_LK_DEBUG_COMBINATION 0x03
+#define HCI_LK_UNAUTH_COMBINATION 0x04
+#define HCI_LK_AUTH_COMBINATION 0x05
+#define HCI_LK_CHANGED_COMBINATION 0x06
+#define HCI_LK_INVALID 0xFF
+
/* ----- HCI Commands ----- */

/* Link Control */
--
1.7.8.1


2012-01-17 23:28:42

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ 03/11] Add storage functions to handle SMP keys

For now, only the Long Term Key (LTK) is stored.
---
src/storage.c | 32 ++++++++++++++++++++++++++++++++
src/storage.h | 2 ++
2 files changed, 34 insertions(+), 0 deletions(-)

diff --git a/src/storage.c b/src/storage.c
index a47720a..960eeb5 100644
--- a/src/storage.c
+++ b/src/storage.c
@@ -1310,3 +1310,35 @@ void delete_device_ccc(bdaddr_t *local, bdaddr_t *peer)
create_filename(filename, PATH_MAX, local, "ccc");
delete_by_pattern(filename, addr);
}
+
+int write_longtermkeys(bdaddr_t *local, bdaddr_t *peer, const char *key)
+{
+ char filename[PATH_MAX + 1], addr[18];
+
+ if (!key)
+ return -EINVAL;
+
+ create_filename(filename, PATH_MAX, local, "longtermkeys");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ ba2str(peer, addr);
+ return textfile_put(filename, addr, key);
+}
+
+gboolean has_longtermkeys(bdaddr_t *local, bdaddr_t *peer)
+{
+ char filename[PATH_MAX + 1], addr[18], *str;
+
+ create_filename(filename, PATH_MAX, local, "longtermkeys");
+
+ ba2str(peer, addr);
+
+ str = textfile_caseget(filename, addr);
+ if (str) {
+ free(str);
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/src/storage.h b/src/storage.h
index 51259f6..604cc49 100644
--- a/src/storage.h
+++ b/src/storage.h
@@ -88,6 +88,8 @@ int read_device_ccc(bdaddr_t *local, bdaddr_t *peer, uint16_t handle,
int write_device_ccc(bdaddr_t *local, bdaddr_t *peer, uint16_t handle,
uint16_t value);
void delete_device_ccc(bdaddr_t *local, bdaddr_t *peer);
+int write_longtermkeys(bdaddr_t *local, bdaddr_t *peer, const char *key);
+gboolean has_longtermkeys(bdaddr_t *local, bdaddr_t *peer);

#define PNP_UUID "00001200-0000-1000-8000-00805f9b34fb"

--
1.7.8.1


2012-01-17 23:28:41

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH BlueZ 02/11] Add messages to the mgmt interface to handle SMP key storage

The SMP keys are to be communicated to/from userspace using these
messages.
---
lib/mgmt.h | 22 ++++++++++++++++++++++
1 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/lib/mgmt.h b/lib/mgmt.h
index fa684e8..eae8deb 100644
--- a/lib/mgmt.h
+++ b/lib/mgmt.h
@@ -275,6 +275,22 @@ struct mgmt_cp_unblock_device {
bdaddr_t bdaddr;
} __packed;

+struct mgmt_ltk_info {
+ struct mgmt_addr_info addr;
+ uint8_t authenticated;
+ uint8_t master;
+ uint8_t enc_size;
+ uint16_t ediv;
+ uint8_t rand[8];
+ uint8_t val[16];
+} __packed;
+
+#define MGMT_OP_LOAD_LONG_TERM_KEYS 0x0026
+struct mgmt_cp_load_long_term_keys {
+ uint16_t key_count;
+ struct mgmt_ltk_info keys[0];
+} __packed;
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
uint16_t opcode;
@@ -374,3 +390,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 {
+ uint8_t store_hint;
+ struct mgmt_ltk_info key;
+} __packed;
--
1.7.8.1