* [PATCH 2/3] android/bluetooth: Add support for loading LTKs
2014-03-18 15:18 [PATCH 1/3] android/bluetooth: Pass correct device type for bonding commands Szymon Janc
@ 2014-03-18 15:18 ` Szymon Janc
2014-03-18 15:18 ` [PATCH 3/3] android/bluetooth: Add support for new long term key mgmt event Szymon Janc
2014-03-19 9:23 ` [PATCH 1/3] android/bluetooth: Pass correct device type for bonding commands Szymon Janc
2 siblings, 0 replies; 4+ messages in thread
From: Szymon Janc @ 2014-03-18 15:18 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
---
android/bluetooth.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 112 insertions(+), 6 deletions(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 000f595..a6650ef 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -28,6 +28,7 @@
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
+#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -38,6 +39,7 @@
#include "lib/sdp.h"
#include "lib/mgmt.h"
#include "src/shared/mgmt.h"
+#include "src/shared/util.h"
#include "src/uuid-helper.h"
#include "src/eir.h"
#include "lib/sdp.h"
@@ -1585,6 +1587,37 @@ static void load_link_keys(GSList *keys, bt_bluetooth_ready cb)
}
}
+static void load_ltks(GSList *ltks)
+{
+ struct mgmt_cp_load_long_term_keys *cp;
+ struct mgmt_ltk_info *ltk;
+ size_t ltk_count, cp_size;
+ GSList *l;
+
+ ltk_count = g_slist_length(ltks);
+
+ DBG("ltks %zu", ltk_count);
+
+ cp_size = sizeof(*cp) + (ltk_count * sizeof(*ltk));
+
+ cp = g_malloc0(cp_size);
+
+ /* Even if the list of stored keys is empty, it is important to load
+ * an empty list into the kernel. That way it is ensured that no old
+ * keys from a previous daemon are present.
+ */
+ cp->key_count = htobs(ltk_count);
+
+ for (l = ltks, ltk = cp->keys; l != NULL; l = g_slist_next(l), ltk++)
+ memcpy(ltk, ltks->data, sizeof(*ltk));
+
+ if (mgmt_send(mgmt_if, MGMT_OP_LOAD_LONG_TERM_KEYS, adapter.index,
+ cp_size, cp, NULL, NULL, NULL) == 0)
+ error("Failed to load LTKs");
+
+ g_free(cp);
+}
+
static uint8_t get_adapter_uuids(void)
{
struct hal_ev_adapter_props_changed *ev;
@@ -1882,6 +1915,18 @@ static struct device *create_device_from_info(GKeyFile *key_file,
dev->bond_state = HAL_BOND_STATE_BONDED;
}
+ str = g_key_file_get_string(key_file, peer, "LongTermKey", NULL);
+ if (str) {
+ g_free(str);
+ dev->bond_state = HAL_BOND_STATE_BONDED;
+ }
+
+ str = g_key_file_get_string(key_file, peer, "SlaveLongTermKey", NULL);
+ if (str) {
+ g_free(str);
+ dev->bond_state = HAL_BOND_STATE_BONDED;
+ }
+
str = g_key_file_get_string(key_file, peer, "Name", NULL);
if (str) {
g_free(dev->name);
@@ -1950,6 +1995,51 @@ failed:
return info;
}
+static struct mgmt_ltk_info *get_ltk_info(GKeyFile *key_file, const char *peer,
+ bool master)
+{
+ const char *key_s, *keytype_s, *encsize_s, *ediv_s, *rand_s;
+ struct mgmt_ltk_info *info = NULL;
+ char *key;
+ unsigned int i;
+
+ key_s = master ? "LongTermKey" : "SlaveLongTermKey";
+ keytype_s = master ? "LongTermKeyType" : "SlaveLongTermKeyType";
+ encsize_s = master ? "LongTermKeyEncSize" : "SlaveLongTermKeyEncSize";
+ ediv_s = master ? "LongTermKeyEDiv" : "SlaveLongTermKeyEDiv";
+ rand_s = master ? "LongTermKeyRand" : "SlaveLongTermKeyRand";
+
+ key = g_key_file_get_string(key_file, peer, key_s, NULL);
+ if (!key || strlen(key) != 32)
+ goto failed;
+
+ info = g_new0(struct mgmt_ltk_info, 1);
+
+ str2ba(peer, &info->addr.bdaddr);
+
+ info->addr.type = g_key_file_get_integer(key_file, peer, "Type", NULL);
+
+ for (i = 0; i < sizeof(info->val); i++)
+ sscanf(key + (i * 2), "%02hhX", &info->val[i]);
+
+ info->type = g_key_file_get_integer(key_file, peer, keytype_s, NULL);
+
+ info->enc_size = g_key_file_get_integer(key_file, peer, encsize_s, NULL);
+
+ info->rand = g_key_file_get_uint64(key_file, peer, rand_s, NULL);
+ info->rand = cpu_to_le64(info->rand);
+
+ info->ediv = g_key_file_get_integer(key_file, peer, ediv_s, NULL);
+ info->ediv = cpu_to_le16(info->ediv);
+
+ info->master = master;
+
+failed:
+ g_free(key);
+
+ return info;
+}
+
static int device_timestamp_cmp(gconstpointer a, gconstpointer b)
{
const struct device *deva = a;
@@ -1991,6 +2081,7 @@ static void load_devices_info(bt_bluetooth_ready cb)
gsize len = 0;
unsigned int i;
GSList *keys = NULL;
+ GSList *ltks = NULL;
key_file = g_key_file_new();
@@ -2000,26 +2091,41 @@ static void load_devices_info(bt_bluetooth_ready cb)
for (i = 0; i < len; i++) {
struct mgmt_link_key_info *key_info;
+ struct mgmt_ltk_info *ltk_info;
+ struct mgmt_ltk_info *slave_ltk_info;
struct device *dev;
key_info = get_key_info(key_file, devs[i]);
- if (!key_info) {
- error("Failed to load linkkey for %s, skipping",
- devs[i]);
+ ltk_info = get_ltk_info(key_file, devs[i], true);
+ slave_ltk_info = get_ltk_info(key_file, devs[i], false);
+
+ if (!key_info && !ltk_info && !slave_ltk_info) {
+ error("Failed to load keys for %s, skipping", devs[i]);
+
continue;
}
- /* TODO ltk */
+ if (key_info)
+ keys = g_slist_prepend(keys, key_info);
+
+ if (ltk_info)
+ ltks = g_slist_prepend(ltks, ltk_info);
+
+ if (slave_ltk_info)
+ ltks = g_slist_prepend(ltks, slave_ltk_info);
dev = create_device_from_info(key_file, devs[i]);
- keys = g_slist_prepend(keys, key_info);
bonded_devices = g_slist_prepend(bonded_devices, dev);
}
+ load_ltks(ltks);
+ g_slist_free_full(ltks, g_free);
+
load_link_keys(keys, cb);
- g_strfreev(devs);
g_slist_free_full(keys, g_free);
+
+ g_strfreev(devs);
g_key_file_free(key_file);
}
--
1.8.5.3
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH 3/3] android/bluetooth: Add support for new long term key mgmt event
2014-03-18 15:18 [PATCH 1/3] android/bluetooth: Pass correct device type for bonding commands Szymon Janc
2014-03-18 15:18 ` [PATCH 2/3] android/bluetooth: Add support for loading LTKs Szymon Janc
@ 2014-03-18 15:18 ` Szymon Janc
2014-03-19 9:23 ` [PATCH 1/3] android/bluetooth: Pass correct device type for bonding commands Szymon Janc
2 siblings, 0 replies; 4+ messages in thread
From: Szymon Janc @ 2014-03-18 15:18 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
---
android/bluetooth.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 86 insertions(+), 2 deletions(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index a6650ef..845c761 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -1481,6 +1481,87 @@ static void mgmt_device_unpaired_event(uint16_t index, uint16_t length,
HAL_BOND_STATE_NONE);
}
+static void store_ltk(const bdaddr_t *dst, uint8_t bdaddr_type, bool master,
+ const uint8_t *key, uint8_t key_type, uint8_t enc_size,
+ uint16_t ediv, uint64_t rand)
+{
+ const char *key_s, *keytype_s, *encsize_s, *ediv_s, *rand_s;
+ GKeyFile *key_file;
+ char key_str[33];
+ gsize length = 0;
+ char addr[18];
+ char *data;
+ int i;
+
+ key_file = g_key_file_new();
+ if (!g_key_file_load_from_file(key_file, DEVICES_FILE, 0, NULL)) {
+ g_key_file_free(key_file);
+ return;
+ }
+
+ ba2str(dst, addr);
+
+ key_s = master ? "LongTermKey" : "SlaveLongTermKey";
+ keytype_s = master ? "LongTermKeyType" : "SlaveLongTermKeyType";
+ encsize_s = master ? "LongTermKeyEncSize" : "SlaveLongTermKeyEncSize";
+ ediv_s = master ? "LongTermKeyEDiv" : "SlaveLongTermKeyEDiv";
+ rand_s = master ? "LongTermKeyRand" : "SlaveLongTermKeyRand";
+
+ for (i = 0; i < 16; i++)
+ sprintf(key_str + (i * 2), "%2.2X", key[i]);
+
+ g_key_file_set_string(key_file, addr, key_s, key_str);
+
+ g_key_file_set_integer(key_file, addr, keytype_s, key_type);
+
+ g_key_file_set_integer(key_file, addr, encsize_s, enc_size);
+
+ g_key_file_set_integer(key_file, addr, ediv_s, ediv);
+
+ g_key_file_set_uint64(key_file, addr, rand_s, rand);
+
+ data = g_key_file_to_data(key_file, &length, NULL);
+ g_file_set_contents(DEVICES_FILE, data, length, NULL);
+ g_free(data);
+
+ g_key_file_free(key_file);
+}
+
+static void new_long_term_key_event(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ const struct mgmt_ev_new_long_term_key *ev = param;
+ const struct mgmt_addr_info *addr = &ev->key.addr;
+ char dst[18];
+
+ if (length < sizeof(*ev)) {
+ error("Too small long term key event (%u bytes)", length);
+ return;
+ }
+
+ ba2str(&addr->bdaddr, dst);
+
+ DBG("new LTK for %s type %u enc_size %u store_hint %u",
+ dst, ev->key.type, ev->key.enc_size, ev->store_hint);
+
+ set_device_bond_state(&addr->bdaddr, HAL_STATUS_SUCCESS,
+ HAL_BOND_STATE_BONDED);
+
+ if (ev->store_hint) {
+ const struct mgmt_ltk_info *key = &ev->key;
+ uint16_t ediv;
+ uint64_t rand;
+
+ ediv = le16_to_cpu(key->ediv);
+ rand = le64_to_cpu(key->rand);
+
+ store_ltk(&key->addr.bdaddr, key->addr.type, key->master,
+ key->val, key->type, key->enc_size, ediv, rand);
+ }
+
+ /* TODO browse services here? */
+}
+
static void register_mgmt_handlers(void)
{
mgmt_register(mgmt_if, MGMT_EV_NEW_SETTINGS, adapter.index,
@@ -1527,6 +1608,9 @@ static void register_mgmt_handlers(void)
mgmt_register(mgmt_if, MGMT_EV_DEVICE_UNPAIRED, adapter.index,
mgmt_device_unpaired_event, NULL, NULL);
+
+ mgmt_register(mgmt_if, MGMT_EV_NEW_LONG_TERM_KEY, adapter.index,
+ new_long_term_key_event, NULL, NULL);
}
static void load_link_keys_complete(uint8_t status, uint16_t length,
@@ -2791,8 +2875,8 @@ static void pair_device_complete(uint8_t status, uint16_t length,
DBG("status %u", status);
- /* On success bond state change will be send when new link key event
- * is received */
+ /* On success bond state change will be send when new link key or LTK
+ * event is received */
if (status == MGMT_STATUS_SUCCESS)
return;
--
1.8.5.3
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH 1/3] android/bluetooth: Pass correct device type for bonding commands
2014-03-18 15:18 [PATCH 1/3] android/bluetooth: Pass correct device type for bonding commands Szymon Janc
2014-03-18 15:18 ` [PATCH 2/3] android/bluetooth: Add support for loading LTKs Szymon Janc
2014-03-18 15:18 ` [PATCH 3/3] android/bluetooth: Add support for new long term key mgmt event Szymon Janc
@ 2014-03-19 9:23 ` Szymon Janc
2 siblings, 0 replies; 4+ messages in thread
From: Szymon Janc @ 2014-03-19 9:23 UTC (permalink / raw)
To: linux-bluetooth
On Tuesday 18 of March 2014 16:18:09 Szymon Janc wrote:
> For create_bond we fallback to BDEDR if device is not known. This can
> happen eg. with OOB. For cancel_bond and remove_bond we require device
> to be known.
> ---
> android/bluetooth.c | 45 ++++++++++++++++++++++++++++++++++++---------
> 1 file changed, 36 insertions(+), 9 deletions(-)
>
> diff --git a/android/bluetooth.c b/android/bluetooth.c
> index 1becdfb..000f595 100644
> --- a/android/bluetooth.c
> +++ b/android/bluetooth.c
> @@ -2697,13 +2697,18 @@ static void pair_device_complete(uint8_t status,
> uint16_t length, static void handle_create_bond_cmd(const void *buf,
> uint16_t len) {
> const struct hal_cmd_create_bond *cmd = buf;
> + struct device *dev;
> uint8_t status;
> struct mgmt_cp_pair_device cp;
>
> cp.io_cap = DEFAULT_IO_CAPABILITY;
> - cp.addr.type = BDADDR_BREDR;
> android2bdaddr(cmd->bdaddr, &cp.addr.bdaddr);
>
> + dev = find_device(&cp.addr.bdaddr);
> +
> + /* Fallback to BREDR if device is unknown eg. OOB */
> + cp.addr.type = dev ? dev->bdaddr_type : BDADDR_BREDR;
> +
> if (mgmt_send(mgmt_if, MGMT_OP_PAIR_DEVICE, adapter.index, sizeof(cp),
> &cp, pair_device_complete, NULL, NULL) == 0) {
> status = HAL_STATUS_FAILED;
> @@ -2724,17 +2729,28 @@ static void handle_cancel_bond_cmd(const void *buf,
> uint16_t len) {
> const struct hal_cmd_cancel_bond *cmd = buf;
> struct mgmt_addr_info cp;
> + struct device *dev;
> uint8_t status;
>
> - cp.type = BDADDR_BREDR;
> android2bdaddr(cmd->bdaddr, &cp.bdaddr);
>
> + dev = find_device(&cp.bdaddr);
> + if (!dev) {
> + status = HAL_STATUS_FAILED;
> + goto failed;
> + }
> +
> + cp.type = dev->bdaddr_type;
> +
> if (mgmt_reply(mgmt_if, MGMT_OP_CANCEL_PAIR_DEVICE, adapter.index,
> - sizeof(cp), &cp, NULL, NULL, NULL) > 0)
> - status = HAL_STATUS_SUCCESS;
> - else
> + sizeof(cp), &cp, NULL, NULL, NULL) == 0) {
> status = HAL_STATUS_FAILED;
> + goto failed;
> + }
> +
> + status = HAL_STATUS_SUCCESS;
>
> +failed:
> ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_BLUETOOTH, HAL_OP_CANCEL_BOND,
> status);
> }
> @@ -2757,19 +2773,30 @@ static void handle_remove_bond_cmd(const void *buf,
> uint16_t len) {
> const struct hal_cmd_remove_bond *cmd = buf;
> struct mgmt_cp_unpair_device cp;
> + struct device *dev;
> uint8_t status;
>
> cp.disconnect = 1;
> - cp.addr.type = BDADDR_BREDR;
> android2bdaddr(cmd->bdaddr, &cp.addr.bdaddr);
>
> + dev = find_device(&cp.addr.bdaddr);
> + if (!dev) {
> + status = HAL_STATUS_FAILED;
> + goto failed;
> + }
> +
> + cp.addr.type = dev->bdaddr_type;
> +
> if (mgmt_send(mgmt_if, MGMT_OP_UNPAIR_DEVICE, adapter.index,
> sizeof(cp), &cp, unpair_device_complete,
> - NULL, NULL) > 0)
> - status = HAL_STATUS_SUCCESS;
> - else
> + NULL, NULL) == 0) {
> status = HAL_STATUS_FAILED;
> + goto failed;
> + }
> +
> + status = HAL_STATUS_SUCCESS;
>
> +failed:
> ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_BLUETOOTH, HAL_OP_REMOVE_BOND,
> status);
> }
This is not handling dual mode devices correctly. Please ignore for now.
--
BR
Szymon Janc
^ permalink raw reply [flat|nested] 4+ messages in thread