Bluetooth: Keys: add key overwrite feature for key storage.
Key overwrite feature allows to overwrite old pairing key records when key storage is full and a new pairing request occurs, or new keys are distributed. If enabled when key storage is full and a keys storage slot is requested, the oldest keys added will be removed. So new devices can be paired with no limitations and no need to determine, which devices should be unpaired to free key storage space explicitly in application. To enable the feature set CONFIG_BT_KEYS_OVERWRITE_OLDEST=y. Oldest keys are determined by minimum value of up-counting aging counter. If you set CONFIG_BT_KEYS_SAVE_AGING_COUNTER_ON_PAIRING=y aging counter values will be updated each time the secure connection is established. This might increase flash wear out if at least two secure connections are established and shut down periodically. When the option disabled aging counter is still updated on each new secure connection, but not stored to flash. Signed-off-by: Sergiy Nikolayenko <sergiy_nikolayenko@jabil.com>
This commit is contained in:
parent
e5d7b2bc51
commit
25164654dd
5 changed files with 111 additions and 6 deletions
|
@ -16,6 +16,7 @@ CONFIG_BT_DEVICE_APPEARANCE=833
|
|||
CONFIG_BT_DEVICE_NAME_DYNAMIC=y
|
||||
CONFIG_BT_DEVICE_NAME_MAX=65
|
||||
|
||||
CONFIG_BT_KEYS_OVERWRITE_OLDEST=y
|
||||
CONFIG_BT_SETTINGS=y
|
||||
CONFIG_FLASH=y
|
||||
CONFIG_FLASH_PAGE_LAYOUT=y
|
||||
|
|
|
@ -351,6 +351,21 @@ config BT_OOB_DATA_FIXED
|
|||
value. This option should only be enabled for debugging and should
|
||||
never be used in production.
|
||||
|
||||
config BT_KEYS_OVERWRITE_OLDEST
|
||||
bool "Overwrite oldest keys with new ones if key storage is full"
|
||||
help
|
||||
With this option enabled, if a pairing attempt occurs and the key storage
|
||||
is full, then the oldest keys in storage will be removed to free space
|
||||
for the new pairing keys.
|
||||
|
||||
config BT_KEYS_SAVE_AGING_COUNTER_ON_PAIRING
|
||||
bool "Store aging counter every time a successful paring occurs"
|
||||
depends on BT_SETTINGS && BT_KEYS_OVERWRITE_OLDEST
|
||||
help
|
||||
With this option enabled, aging counter will be stored in settings every
|
||||
time a successful pairing occurs. This increases flash wear out but offers
|
||||
a more correct finding of the oldest unused paiting info.
|
||||
|
||||
endif # BT_SMP
|
||||
|
||||
source "subsys/bluetooth/host/Kconfig.l2cap"
|
||||
|
|
|
@ -1007,6 +1007,11 @@ void bt_conn_security_changed(struct bt_conn *conn, enum bt_security_err err)
|
|||
cb->security_changed(conn, conn->sec_level, err);
|
||||
}
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
||||
if (!err && conn->sec_level >= BT_SECURITY_L2) {
|
||||
bt_keys_update_usage(conn->id, bt_conn_get_dst(conn));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int start_security(struct bt_conn *conn)
|
||||
|
|
|
@ -31,6 +31,13 @@
|
|||
|
||||
static struct bt_keys key_pool[CONFIG_BT_MAX_PAIRED];
|
||||
|
||||
#define BT_KEYS_STORAGE_LEN_COMPAT (BT_KEYS_STORAGE_LEN - sizeof(uint32_t))
|
||||
|
||||
#if IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
||||
static u32_t aging_counter_val;
|
||||
static struct bt_keys *last_keys_updated;
|
||||
#endif /* CONFIG_BT_KEYS_OVERWRITE_OLDEST */
|
||||
|
||||
struct bt_keys *bt_keys_get_addr(u8_t id, const bt_addr_le_t *addr)
|
||||
{
|
||||
struct bt_keys *keys;
|
||||
|
@ -47,18 +54,43 @@ struct bt_keys *bt_keys_get_addr(u8_t id, const bt_addr_le_t *addr)
|
|||
}
|
||||
|
||||
if (first_free_slot == ARRAY_SIZE(key_pool) &&
|
||||
!bt_addr_le_cmp(&keys->addr, BT_ADDR_LE_ANY)) {
|
||||
(!bt_addr_le_cmp(&keys->addr, BT_ADDR_LE_ANY) ||
|
||||
!keys->enc_size)) {
|
||||
first_free_slot = i;
|
||||
}
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
||||
if (first_free_slot == ARRAY_SIZE(key_pool)) {
|
||||
struct bt_keys *oldest = &key_pool[0];
|
||||
|
||||
for (i = 1; i < ARRAY_SIZE(key_pool); i++) {
|
||||
struct bt_keys *current = &key_pool[i];
|
||||
|
||||
if (current->aging_counter < oldest->aging_counter) {
|
||||
oldest = current;
|
||||
}
|
||||
}
|
||||
|
||||
bt_unpair(oldest->id, &oldest->addr);
|
||||
if (!bt_addr_le_cmp(&oldest->addr, BT_ADDR_LE_ANY)) {
|
||||
first_free_slot = oldest - &key_pool[0];
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_KEYS_OVERWRITE_OLDEST */
|
||||
if (first_free_slot < ARRAY_SIZE(key_pool)) {
|
||||
keys = &key_pool[first_free_slot];
|
||||
keys->id = id;
|
||||
bt_addr_le_copy(&keys->addr, addr);
|
||||
#if IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
||||
keys->aging_counter = ++aging_counter_val;
|
||||
last_keys_updated = keys;
|
||||
#endif /* CONFIG_BT_KEYS_OVERWRITE_OLDEST */
|
||||
BT_DBG("created %p for %s", keys, bt_addr_le_str(addr));
|
||||
return keys;
|
||||
}
|
||||
|
||||
BT_DBG("unable to create keys for %s", bt_addr_le_str(addr));
|
||||
|
||||
return NULL;
|
||||
|
@ -335,17 +367,35 @@ static int keys_set(const char *name, size_t len_rd, settings_read_cb read_cb,
|
|||
BT_ERR("Failed to allocate keys for %s", bt_addr_le_str(&addr));
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (len != BT_KEYS_STORAGE_LEN) {
|
||||
do {
|
||||
/* Load shorter structure for compatibility with old
|
||||
* records format with no counter.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST) &&
|
||||
len == BT_KEYS_STORAGE_LEN_COMPAT) {
|
||||
BT_WARN("Keys for %s have no aging counter",
|
||||
bt_addr_le_str(&addr));
|
||||
memcpy(keys->storage_start, val, len);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len_rd != BT_KEYS_STORAGE_LEN) {
|
||||
BT_ERR("Invalid key length %zu != %zu", len,
|
||||
BT_KEYS_STORAGE_LEN);
|
||||
bt_keys_clear(keys);
|
||||
return -EINVAL;
|
||||
BT_ERR("Invalid key length %zu != %zu", len,
|
||||
BT_KEYS_STORAGE_LEN);
|
||||
bt_keys_clear(keys);
|
||||
|
||||
return -EINVAL;
|
||||
} while (0);
|
||||
} else {
|
||||
memcpy(keys->storage_start, val, len);
|
||||
}
|
||||
|
||||
BT_DBG("Successfully restored keys for %s", bt_addr_le_str(&addr));
|
||||
#if IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
||||
if (aging_counter_val < keys->aging_counter) {
|
||||
aging_counter_val = keys->aging_counter;
|
||||
}
|
||||
#endif /* CONFIG_BT_KEYS_OVERWRITE_OLDEST */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -371,3 +421,29 @@ SETTINGS_STATIC_HANDLER_DEFINE(bt_keys, "bt/keys", NULL, keys_set, keys_commit,
|
|||
NULL);
|
||||
|
||||
#endif /* CONFIG_BT_SETTINGS */
|
||||
|
||||
#if IS_ENABLED(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
|
||||
void bt_keys_update_usage(u8_t id, const bt_addr_le_t *addr)
|
||||
{
|
||||
struct bt_keys *keys = bt_keys_find_addr(id, addr);
|
||||
|
||||
if (!keys) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (last_keys_updated == keys) {
|
||||
return;
|
||||
}
|
||||
|
||||
keys->aging_counter = ++aging_counter_val;
|
||||
last_keys_updated = keys;
|
||||
|
||||
BT_DBG("Aging counter for %s is set to %u", bt_addr_le_str(addr),
|
||||
keys->aging_counter);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_KEYS_SAVE_AGING_COUNTER_ON_PAIRING)) {
|
||||
bt_keys_store(keys);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_KEYS_OVERWRITE_OLDEST */
|
||||
|
|
|
@ -59,6 +59,9 @@ struct bt_keys {
|
|||
#if !defined(CONFIG_BT_SMP_SC_PAIR_ONLY)
|
||||
struct bt_ltk slave_ltk;
|
||||
#endif /* CONFIG_BT_SMP_SC_PAIR_ONLY */
|
||||
#if (defined(CONFIG_BT_KEYS_OVERWRITE_OLDEST))
|
||||
u32_t aging_counter;
|
||||
#endif /* CONFIG_BT_KEYS_OVERWRITE_OLDEST */
|
||||
};
|
||||
|
||||
#define BT_KEYS_STORAGE_LEN (sizeof(struct bt_keys) - \
|
||||
|
@ -102,3 +105,8 @@ struct bt_keys_link_key *bt_keys_get_link_key(const bt_addr_t *addr);
|
|||
struct bt_keys_link_key *bt_keys_find_link_key(const bt_addr_t *addr);
|
||||
void bt_keys_link_key_clear(struct bt_keys_link_key *link_key);
|
||||
void bt_keys_link_key_clear_addr(const bt_addr_t *addr);
|
||||
|
||||
/* This function is used to signal that the key has been used for paring */
|
||||
/* It updates the aging counter and saves it to flash if configuration option */
|
||||
/* BT_KEYS_SAVE_AGING_COUNTER_ON_PAIRING is enabled */
|
||||
void bt_keys_update_usage(u8_t id, const bt_addr_le_t *addr);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue