2011-06-07 23:08:10

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH 1/5] Add stubs for storing SMP keys

As we begin to support pairing over LE links, we need to store those
keys in permanent storage.

This patch changes the data types according to the current kernel interface
and adds new methods that will be used to store those keys. The documentation
of the Management API is updated to reflect this.
---
doc/mgmt-api.txt | 2 ++
lib/mgmt.h | 2 ++
plugins/hciops.c | 2 +-
plugins/mgmtops.c | 5 +++--
src/adapter.h | 2 ++
src/event.c | 10 ++++++----
src/event.h | 2 +-
src/storage.c | 5 +++++
src/storage.h | 1 +
9 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt
index 353705e..97eb4d3 100644
--- a/doc/mgmt-api.txt
+++ b/doc/mgmt-api.txt
@@ -172,6 +172,8 @@ Load Keys Command
Type (1 Octet)
Value (16 Octets)
PIN_Length (1 Octet)
+ Data Length (1 Octet)
+ Data (Data Length Octets)
}
Key2 { }
...
diff --git a/lib/mgmt.h b/lib/mgmt.h
index 57e7603..222dc1f 100644
--- a/lib/mgmt.h
+++ b/lib/mgmt.h
@@ -111,6 +111,8 @@ struct mgmt_key_info {
uint8_t type;
uint8_t val[16];
uint8_t pin_len;
+ uint8_t dlen;
+ uint8_t data[0];
} __packed;

#define MGMT_OP_LOAD_KEYS 0x000D
diff --git a/plugins/hciops.c b/plugins/hciops.c
index 9b1225c..101e287 100644
--- a/plugins/hciops.c
+++ b/plugins/hciops.c
@@ -993,7 +993,7 @@ static void link_key_notify(int index, void *ptr)

err = btd_event_link_key_notify(&dev->bdaddr, dba,
evt->link_key, key_type,
- dev->pin_length);
+ dev->pin_length, 0, NULL);

if (err == -ENODEV)
status = HCI_OE_LOW_RESOURCES;
diff --git a/plugins/mgmtops.c b/plugins/mgmtops.c
index 95de3d1..e950fff 100644
--- a/plugins/mgmtops.c
+++ b/plugins/mgmtops.c
@@ -407,8 +407,9 @@ static void mgmt_new_key(int sk, uint16_t index, void *buf, size_t len)

if (ev->store_hint)
btd_event_link_key_notify(&info->bdaddr, &ev->key.bdaddr,
- ev->key.val, ev->key.type,
- ev->key.pin_len);
+ ev->key.val, ev->key.type,
+ ev->key.pin_len, ev->key.dlen,
+ ev->key.data);

btd_event_bonding_complete(&info->bdaddr, &ev->key.bdaddr, 0);
}
diff --git a/src/adapter.h b/src/adapter.h
index 3526849..a9e8102 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -61,6 +61,8 @@ struct link_key_info {
unsigned char key[16];
uint8_t type;
uint8_t pin_len;
+ uint8_t dlen;
+ uint8_t data[0];
};

struct remote_dev_info {
diff --git a/src/event.c b/src/event.c
index 0b43884..b258dda 100644
--- a/src/event.c
+++ b/src/event.c
@@ -395,9 +395,8 @@ proceed:
adapter_set_state(adapter, STATE_IDLE);
}

-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_link_key_notify(bdaddr_t *local, bdaddr_t *peer, uint8_t *key,
+ uint8_t key_type, uint8_t pin_length, int dlen, uint8_t *data)
{
struct btd_adapter *adapter;
struct btd_device *device;
@@ -408,7 +407,10 @@ int btd_event_link_key_notify(bdaddr_t *local, bdaddr_t *peer,

DBG("storing link key of type 0x%02x", key_type);

- ret = write_link_key(local, peer, key, key_type, pin_length);
+ if (key_type < 0x10)
+ ret = write_link_key(local, peer, key, key_type, pin_length);
+ else
+ ret = write_longtermkeys(local, peer, NULL);

if (ret == 0 && device_is_temporary(device))
device_set_temporary(device, FALSE);
diff --git a/src/event.h b/src/event.h
index 22c199e..d83a04e 100644
--- a/src/event.h
+++ b/src/event.h
@@ -39,4 +39,4 @@ int btd_event_user_confirm(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey);
int btd_event_user_passkey(bdaddr_t *sba, bdaddr_t *dba);
int btd_event_user_notify(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey);
int btd_event_link_key_notify(bdaddr_t *local, bdaddr_t *peer, uint8_t *key,
- uint8_t key_type, uint8_t pin_length);
+ uint8_t key_type, uint8_t pin_length, int dlen, uint8_t *data);
diff --git a/src/storage.c b/src/storage.c
index d416d75..786e24b 100644
--- a/src/storage.c
+++ b/src/storage.c
@@ -1343,3 +1343,8 @@ device_type_t read_device_type(const bdaddr_t *sba, const bdaddr_t *dba)

return type;
}
+
+int write_longtermkeys(bdaddr_t *local, bdaddr_t *peer, const char *key)
+{
+ return 0;
+}
diff --git a/src/storage.h b/src/storage.h
index 6929ada..923e819 100644
--- a/src/storage.h
+++ b/src/storage.h
@@ -87,6 +87,7 @@ int read_device_attributes(const bdaddr_t *sba, textfile_cb func, void *data);
int write_device_type(const bdaddr_t *sba, const bdaddr_t *dba,
device_type_t type);
device_type_t read_device_type(const bdaddr_t *sba, const bdaddr_t *dba);
+int write_longtermkeys(bdaddr_t *local, bdaddr_t *peer, const char *key);

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

--
1.7.5.4



2011-06-07 23:08:14

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH 5/5] Fix using "magic" values for key types

Now that we have macros for the different type of keys we should
use them to make the code clearer.
---
plugins/hciops.c | 10 ++++++----
src/event.c | 19 ++++++++++++++++---
2 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/plugins/hciops.c b/plugins/hciops.c
index 101e287..6856dec 100644
--- a/plugins/hciops.c
+++ b/plugins/hciops.c
@@ -954,12 +954,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
@@ -971,7 +971,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:
@@ -985,7 +985,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 != 0xff) ||
(conn->loc_auth > 0x01 && conn->rem_auth > 0x01) ||
(conn->loc_auth == 0x02 || conn->loc_auth == 0x03) ||
(conn->rem_auth == 0x02 || conn->rem_auth == 0x03)) {
diff --git a/src/event.c b/src/event.c
index edf8a0f..6f5fa36 100644
--- a/src/event.c
+++ b/src/event.c
@@ -443,11 +443,24 @@ int btd_event_link_key_notify(bdaddr_t *local, bdaddr_t *peer, uint8_t *key,

DBG("storing link key of type 0x%02x", key_type);

- if (key_type & 0x10)
+ switch (key_type) {
+ case HCI_LK_COMBINATION:
+ case HCI_LK_LOCAL_UNIT:
+ case HCI_LK_REMOTE_UNIT:
+ case HCI_LK_DEBUG_COMBINATION:
+ case HCI_LK_UNAUTH_COMBINATION:
+ case HCI_LK_AUTH_COMBINATION:
+ case HCI_LK_CHANGED_COMBINATION:
+ ret = write_link_key(local, peer, key, key_type, pin_length);
+ break;
+ case HCI_LK_SMP_LTK:
ret = store_longtermkey(local, peer, key, key_type, pin_length,
dlen, data);
- else
- ret = write_link_key(local, peer, key, key_type, pin_length);
+ break;
+ default:
+ ret = -ENOTSUP;
+ break;
+ }

if (ret == 0 && device_is_temporary(device))
device_set_temporary(device, FALSE);
--
1.7.5.4


2011-06-07 23:08:13

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH 4/5] Define macros for link key types

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

diff --git a/lib/hci.h b/lib/hci.h
index 51184ee..dc4b36b 100644
--- a/lib/hci.h
+++ b/lib/hci.h
@@ -293,6 +293,19 @@ 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
+/* 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 ----- */

/* Link Control */
--
1.7.5.4


2011-06-07 23:08:12

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH 3/5] Add support for creating the device from the SMP keys

This adds support for creating the device from the SMP keys (for now
just the LTK) previously stored.
---
plugins/mgmtops.c | 26 ++++++++++++++---
src/adapter.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 93 insertions(+), 9 deletions(-)

diff --git a/plugins/mgmtops.c b/plugins/mgmtops.c
index cc5fd78..e27acdc 100644
--- a/plugins/mgmtops.c
+++ b/plugins/mgmtops.c
@@ -1838,13 +1838,20 @@ static int mgmt_load_keys(int index, GSList *keys, gboolean debug_keys)
struct mgmt_key_info *key;
size_t key_count, cp_size;
GSList *l;
- int err;
+ int err, i;

- key_count = g_slist_length(keys);
+ key_count = 0;
+ cp_size = sizeof(*cp);
+ for (l = keys; l; l = g_slist_next(l)) {
+ struct link_key_info *info = l->data;
+ key_count++;
+ cp_size += sizeof(struct mgmt_key_info) + info->dlen;
+ }

- DBG("index %d keys %zu debug_keys %d", index, key_count, debug_keys);
+ if (key_count == 0)
+ return 0;

- cp_size = sizeof(*cp) + (key_count * sizeof(*key));
+ DBG("index %d keys %zu debug_keys %d size %zd", index, key_count, debug_keys, cp_size);

buf = g_try_malloc0(sizeof(*hdr) + cp_size);
if (buf == NULL)
@@ -1861,13 +1868,22 @@ static int mgmt_load_keys(int index, GSList *keys, gboolean debug_keys)
cp->debug_keys = debug_keys;
cp->key_count = htobs(key_count);

- for (l = keys, key = cp->keys; l != NULL; l = g_slist_next(l), key++) {
+ key = cp->keys;
+ i = 0;
+
+ for (l = keys; l != NULL; l = g_slist_next(l)) {
struct link_key_info *info = l->data;

+ key = (void *) (cp->keys + i);
+
bacpy(&key->bdaddr, &info->bdaddr);
key->type = info->type;
memcpy(key->val, info->key, 16);
key->pin_len = info->pin_len;
+ memcpy(key->data, info->data, info->dlen);
+ key->dlen = info->dlen;
+
+ i += sizeof(struct mgmt_key_info) + info->dlen;
}

if (write(mgmt_sock, buf, sizeof(*hdr) + cp_size) < 0)
diff --git a/src/adapter.c b/src/adapter.c
index b189841..fe9350f 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1987,6 +1987,47 @@ static struct link_key_info *get_key_info(const char *addr, const char *value)
return info;
}

+static struct link_key_info *get_ltk_info(const char *addr, const char *value)
+{
+ struct link_key_info *info;
+ char tmp[3], *ptr;
+ int i, ret;
+
+ if (strlen(value) < 36) {
+ error("Unexpectedly short (%zu) link key line", strlen(value));
+ return NULL;
+ }
+
+ info = g_new0(struct link_key_info, 1);
+
+ str2ba(addr, &info->bdaddr);
+
+ memset(tmp, 0, sizeof(tmp));
+
+ for (i = 0; i < 16; i++) {
+ memcpy(tmp, value + (i * 2), 2);
+ info->key[i] = (uint8_t) strtol(tmp, NULL, 16);
+ }
+
+ ptr = (char *) value + 33;
+
+ ret = sscanf(ptr, "%hhd %hhd %hhd %n", &info->type, &info->pin_len,
+ &info->dlen, &i);
+ if (ret < 3) {
+ g_free(info);
+ return NULL;
+ }
+ ptr += i;
+
+ info = g_realloc(info, sizeof(struct link_key_info) + info->dlen);
+ for (i = 0; i < info->dlen; i++) {
+ memcpy(tmp, ptr + (i * 2), 2);
+ info->data[i] = (uint8_t) strtol(tmp, NULL, 16);
+ }
+
+ return info;
+}
+
static void create_stored_device_from_linkkeys(char *key, char *value,
void *user_data)
{
@@ -2010,6 +2051,29 @@ 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 link_key_info *info;
+
+ 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;
+
+ device = device_create(connection, adapter, key, DEVICE_TYPE_LE);
+ 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)
{
@@ -2140,14 +2204,18 @@ static void load_devices(struct btd_adapter *adapter)
create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "linkkeys");
textfile_foreach(filename, create_stored_device_from_linkkeys, &keys);

+ create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "longtermkeys");
+ textfile_foreach(filename, create_stored_device_from_ltks, &keys);
+
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_foreach(keys.keys, (GFunc) g_free, NULL);
- g_slist_free(keys.keys);
- }
+
+ g_slist_foreach(keys.keys, (GFunc) g_free, NULL);
+ g_slist_free(keys.keys);
+ keys.keys = NULL;

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


2011-06-07 23:08:11

by Vinicius Costa Gomes

[permalink] [raw]
Subject: [PATCH 2/5] Add support for storing SMP keys

---
plugins/mgmtops.c | 4 ++--
src/event.c | 43 ++++++++++++++++++++++++++++++++++++++++---
src/storage.c | 25 ++++++++++++++++++++++++-
src/storage.h | 1 +
4 files changed, 67 insertions(+), 6 deletions(-)

diff --git a/plugins/mgmtops.c b/plugins/mgmtops.c
index e950fff..cc5fd78 100644
--- a/plugins/mgmtops.c
+++ b/plugins/mgmtops.c
@@ -383,8 +383,8 @@ static void mgmt_new_key(int sk, uint16_t index, void *buf, size_t len)
struct mgmt_ev_new_key *ev = buf;
struct controller_info *info;

- if (len != sizeof(*ev)) {
- error("new_key event size mismatch (%zu != %zu)",
+ if (len < sizeof(*ev)) {
+ error("new_key event size mismatch (%zu < %zu)",
len, sizeof(*ev));
return;
}
diff --git a/src/event.c b/src/event.c
index b258dda..edf8a0f 100644
--- a/src/event.c
+++ b/src/event.c
@@ -395,6 +395,42 @@ proceed:
adapter_set_state(adapter, STATE_IDLE);
}

+static gchar *buf2str(uint8_t *data, int datalen)
+{
+ gchar *buf;
+ int i;
+
+ buf = g_new0(gchar, (datalen * 2) + 1);
+
+ 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, unsigned char *key,
+ uint8_t type, int length, int dlen, uint8_t *data)
+{
+ GString *newkey;
+ char *val, *str;
+ int err;
+
+ val = buf2str(key, 16);
+ newkey = g_string_new(val);
+
+ g_string_append_printf(newkey, " %d %d %d ", type, length, dlen);
+
+ str = buf2str(data, dlen);
+ 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, int dlen, uint8_t *data)
{
@@ -407,10 +443,11 @@ int btd_event_link_key_notify(bdaddr_t *local, bdaddr_t *peer, uint8_t *key,

DBG("storing link key of type 0x%02x", key_type);

- if (key_type < 0x10)
- ret = write_link_key(local, peer, key, key_type, pin_length);
+ if (key_type & 0x10)
+ ret = store_longtermkey(local, peer, key, key_type, pin_length,
+ dlen, data);
else
- ret = write_longtermkeys(local, peer, NULL);
+ ret = write_link_key(local, peer, key, key_type, pin_length);

if (ret == 0 && device_is_temporary(device))
device_set_temporary(device, FALSE);
diff --git a/src/storage.c b/src/storage.c
index 786e24b..7ec8df2 100644
--- a/src/storage.c
+++ b/src/storage.c
@@ -1346,5 +1346,28 @@ device_type_t read_device_type(const bdaddr_t *sba, const bdaddr_t *dba)

int write_longtermkeys(bdaddr_t *local, bdaddr_t *peer, const char *key)
{
- return 0;
+ 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);
+}
+
+char *read_longtermkeys(bdaddr_t *local, bdaddr_t *peer)
+{
+ char filename[PATH_MAX + 1], addr[18];
+
+ create_filename(filename, PATH_MAX, local, "longtermkeys");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ ba2str(peer, addr);
+
+ return textfile_caseget(filename, addr);
}
diff --git a/src/storage.h b/src/storage.h
index 923e819..23d9ab6 100644
--- a/src/storage.h
+++ b/src/storage.h
@@ -88,6 +88,7 @@ int write_device_type(const bdaddr_t *sba, const bdaddr_t *dba,
device_type_t type);
device_type_t read_device_type(const bdaddr_t *sba, const bdaddr_t *dba);
int write_longtermkeys(bdaddr_t *local, bdaddr_t *peer, const char *key);
+char *read_longtermkeys(bdaddr_t *local, bdaddr_t *peer);

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

--
1.7.5.4