zephyr/subsys/bluetooth/host/settings.c
Joakim Andersson a34d4afe7d Bluetooth: Host: Fix issues with host IRK handling
Fix multiple issues related to the way the host handles
Identity Information related to privacy

1. If the controller provided a public address the IRK
   for this identity would be randomly generated but not
   stored persistenly.

2. Fix the handling of the above issue which was fixed
   for the random address but would initiate settings save
   ID on every boot.

3. Fix the host not using the Vendor Specific HCI commands
   related to retrieving the Identity Root (IR) from the
   controller and using the key diversified function d1
   to generate an IRK as specified in the BT Core spec.

Make sure that a Host generated ID is only saved when it is first
generated.

Signed-off-by: Joakim Andersson <joakim.andersson@nordicsemi.no>
2019-12-20 15:45:34 +01:00

286 lines
6.1 KiB
C

/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <zephyr.h>
#include <settings/settings.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/conn.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_SETTINGS)
#define LOG_MODULE_NAME bt_settings
#include "common/log.h"
#include "hci_core.h"
#include "settings.h"
#if defined(CONFIG_BT_SETTINGS_USE_PRINTK)
void bt_settings_encode_key(char *path, size_t path_size, const char *subsys,
bt_addr_le_t *addr, const char *key)
{
if (key) {
snprintk(path, path_size,
"bt/%s/%02x%02x%02x%02x%02x%02x%u/%s", subsys,
addr->a.val[5], addr->a.val[4], addr->a.val[3],
addr->a.val[2], addr->a.val[1], addr->a.val[0],
addr->type, key);
} else {
snprintk(path, path_size,
"bt/%s/%02x%02x%02x%02x%02x%02x%u", subsys,
addr->a.val[5], addr->a.val[4], addr->a.val[3],
addr->a.val[2], addr->a.val[1], addr->a.val[0],
addr->type);
}
BT_DBG("Encoded path %s", log_strdup(path));
}
#else
void bt_settings_encode_key(char *path, size_t path_size, const char *subsys,
bt_addr_le_t *addr, const char *key)
{
size_t len = 3;
/* Skip if path_size is less than 3; strlen("bt/") */
if (len < path_size) {
/* Key format:
* "bt/<subsys>/<addr><type>/<key>", "/<key>" is optional
*/
strcpy(path, "bt/");
strncpy(&path[len], subsys, path_size - len);
len = strlen(path);
if (len < path_size) {
path[len] = '/';
len++;
}
for (s8_t i = 5; i >= 0 && len < path_size; i--) {
len += bin2hex(&addr->a.val[i], 1, &path[len],
path_size - len);
}
if (len < path_size) {
/* Type can be either BT_ADDR_LE_PUBLIC or
* BT_ADDR_LE_RANDOM (value 0 or 1)
*/
path[len] = '0' + addr->type;
len++;
}
if (key && len < path_size) {
path[len] = '/';
len++;
strncpy(&path[len], key, path_size - len);
len += strlen(&path[len]);
}
if (len >= path_size) {
/* Truncate string */
path[path_size - 1] = '\0';
}
} else if (path_size > 0) {
*path = '\0';
}
BT_DBG("Encoded path %s", log_strdup(path));
}
#endif
int bt_settings_decode_key(const char *key, bt_addr_le_t *addr)
{
if (settings_name_next(key, NULL) != 13) {
return -EINVAL;
}
if (key[12] == '0') {
addr->type = BT_ADDR_LE_PUBLIC;
} else if (key[12] == '1') {
addr->type = BT_ADDR_LE_RANDOM;
} else {
return -EINVAL;
}
for (u8_t i = 0; i < 6; i++) {
hex2bin(&key[i * 2], 2, &addr->a.val[5 - i], 1);
}
BT_DBG("Decoded %s as %s", log_strdup(key), bt_addr_le_str(addr));
return 0;
}
static int set(const char *name, size_t len_rd, settings_read_cb read_cb,
void *cb_arg)
{
ssize_t len;
const char *next;
if (!name) {
BT_ERR("Insufficient number of arguments");
return -ENOENT;
}
len = settings_name_next(name, &next);
if (!strncmp(name, "id", len)) {
/* Any previously provided identities supersede flash */
if (atomic_test_bit(bt_dev.flags, BT_DEV_PRESET_ID)) {
BT_WARN("Ignoring identities stored in flash");
return 0;
}
len = read_cb(cb_arg, &bt_dev.id_addr, sizeof(bt_dev.id_addr));
if (len < sizeof(bt_dev.id_addr[0])) {
if (len < 0) {
BT_ERR("Failed to read ID address from storage"
" (err %zu)", len);
} else {
BT_ERR("Invalid length ID address in storage");
BT_HEXDUMP_DBG(&bt_dev.id_addr, len,
"data read");
}
(void)memset(bt_dev.id_addr, 0,
sizeof(bt_dev.id_addr));
bt_dev.id_count = 0U;
} else {
int i;
bt_dev.id_count = len / sizeof(bt_dev.id_addr[0]);
for (i = 0; i < bt_dev.id_count; i++) {
BT_DBG("ID[%d] %s", i,
bt_addr_le_str(&bt_dev.id_addr[i]));
}
}
return 0;
}
#if defined(CONFIG_BT_DEVICE_NAME_DYNAMIC)
if (!strncmp(name, "name", len)) {
len = read_cb(cb_arg, &bt_dev.name, sizeof(bt_dev.name) - 1);
if (len < 0) {
BT_ERR("Failed to read device name from storage"
" (err %zu)", len);
} else {
bt_dev.name[len] = '\0';
BT_DBG("Name set to %s", log_strdup(bt_dev.name));
}
return 0;
}
#endif
#if defined(CONFIG_BT_PRIVACY)
if (!strncmp(name, "irk", len)) {
len = read_cb(cb_arg, bt_dev.irk, sizeof(bt_dev.irk));
if (len < sizeof(bt_dev.irk[0])) {
if (len < 0) {
BT_ERR("Failed to read IRK from storage"
" (err %zu)", len);
} else {
BT_ERR("Invalid length IRK in storage");
(void)memset(bt_dev.irk, 0, sizeof(bt_dev.irk));
}
} else {
int i, count;
count = len / sizeof(bt_dev.irk[0]);
for (i = 0; i < count; i++) {
BT_DBG("IRK[%d] %s", i,
bt_hex(bt_dev.irk[i], 16));
}
}
return 0;
}
#endif /* CONFIG_BT_PRIVACY */
return -ENOENT;
}
#define ID_DATA_LEN(array) (bt_dev.id_count * sizeof(array[0]))
static void save_id(struct k_work *work)
{
int err;
BT_INFO("Saving ID");
err = settings_save_one("bt/id", &bt_dev.id_addr,
ID_DATA_LEN(bt_dev.id_addr));
if (err) {
BT_ERR("Failed to save ID (err %d)", err);
}
#if defined(CONFIG_BT_PRIVACY)
err = settings_save_one("bt/irk", bt_dev.irk, ID_DATA_LEN(bt_dev.irk));
if (err) {
BT_ERR("Failed to save IRK (err %d)", err);
}
#endif
}
K_WORK_DEFINE(save_id_work, save_id);
void bt_settings_save_id(void)
{
k_work_submit(&save_id_work);
}
static int commit(void)
{
BT_DBG("");
#if defined(CONFIG_BT_DEVICE_NAME_DYNAMIC)
if (bt_dev.name[0] == '\0') {
bt_set_name(CONFIG_BT_DEVICE_NAME);
}
#endif
if (!bt_dev.id_count) {
bt_setup_public_id_addr();
}
if (!bt_dev.id_count) {
int err;
err = bt_setup_random_id_addr();
if (err) {
BT_ERR("Unable to setup an identity address");
return err;
}
}
if (!atomic_test_bit(bt_dev.flags, BT_DEV_READY)) {
bt_finalize_init();
}
/* If any part of the Identity Information of the device has been
* generated this Identity needs to be saved persistently.
*/
if (atomic_test_and_clear_bit(bt_dev.flags, BT_DEV_STORE_ID)) {
BT_DBG("Storing Identity Information");
bt_settings_save_id();
}
return 0;
}
SETTINGS_STATIC_HANDLER_DEFINE(bt, "bt", NULL, set, commit, NULL);
int bt_settings_init(void)
{
int err;
BT_DBG("");
err = settings_subsys_init();
if (err) {
BT_ERR("settings_subsys_init failed (err %d)", err);
return err;
}
return 0;
}