BLE: Move traces out of header file to avoid collisions.

This change required the creation of the implementation files of SecurityDb classes.
pull/14198/head
Vincent Coubard 2021-01-27 13:58:59 +00:00 committed by Paul Szczepanek
parent 6adaefd9f3
commit 957486e0eb
9 changed files with 695 additions and 450 deletions

View File

@ -27,6 +27,8 @@
#include "att_api.h"
#include "att_defs.h"
#include "mbed-trace/mbed_trace.h"
#define TRACE_GROUP "BLAT"
namespace ble {

View File

@ -90,6 +90,14 @@ FileSecurityDb::~FileSecurityDb()
fclose(_db_file);
}
FileSecurityDb::entry_t* FileSecurityDb::as_entry(entry_handle_t db_handle) {
entry_t* entry = reinterpret_cast<entry_t*>(db_handle);
if (!entry) {
tr_error("Invalid security DB handle used");
}
return entry;
}
FILE* FileSecurityDb::open_db_file(const char *db_path)
{
if (!db_path) {

View File

@ -24,9 +24,6 @@
#include <stdio.h>
#include "SecurityDb.h"
#include "mbed-trace/mbed_trace.h"
#define TRACE_GROUP "BLDB"
namespace ble {
@ -40,13 +37,7 @@ private:
size_t file_offset;
};
static entry_t* as_entry(entry_handle_t db_handle) {
entry_t* entry = reinterpret_cast<entry_t*>(db_handle);
if (!entry) {
tr_error("Invalid security DB handle used");
}
return entry;
}
static entry_t* as_entry(entry_handle_t db_handle);
template<class T>
void db_read(T *value, long int offset) {

View File

@ -62,6 +62,14 @@ KVStoreSecurityDb::~KVStoreSecurityDb()
{
}
KVStoreSecurityDb::entry_t *KVStoreSecurityDb::as_entry(entry_handle_t db_handle) {
entry_t* entry = reinterpret_cast<entry_t*>(db_handle);
if (!entry) {
tr_error("Invalid security DB handle used");
}
return entry;
}
bool KVStoreSecurityDb::open_db()
{
uint8_t version = 0;

View File

@ -25,13 +25,10 @@
#include "mbed_error.h"
#include "SecurityDb.h"
#include "mbed-trace/mbed_trace.h"
#define STR_EXPAND(tok) #tok
#define STR(tok) STR_EXPAND(tok)
#define TRACE_GROUP "BLDB"
namespace ble {
/** Filesystem implementation */
@ -66,14 +63,6 @@ private:
static constexpr char DB_VERSION[DB_KEY_SIZE] = { 'v','e','r' };
static constexpr char DB_RESTORE[DB_KEY_SIZE] = { 'r','e','s' };
static entry_t* as_entry(entry_handle_t db_handle) {
entry_t* entry = reinterpret_cast<entry_t*>(db_handle);
if (!entry) {
tr_error("Invalid security DB handle used");
}
return entry;
}
template<class T>
static void db_read(T *value, const char* key) {
char db_key[DB_FULL_KEY_SIZE];

View File

@ -0,0 +1,196 @@
/* mbed Microcontroller Library
* Copyright (c) 2021 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "MemorySecurityDb.h"
#include "mbed-trace/mbed_trace.h"
#include "common/ble_trace_helpers.h"
#define TRACE_GROUP "BLDB"
#define _STR(x) #x
#define STR(x) _STR(x)
namespace ble {
MemorySecurityDb::entry_t *MemorySecurityDb::as_entry(entry_handle_t db_handle)
{
entry_t* entry = reinterpret_cast<entry_t*>(db_handle);
if (!entry) {
tr_error("Invalid security DB handle used");
}
return entry;
}
MemorySecurityDb::MemorySecurityDb() : SecurityDb()
{
tr_info("Using memory security DB (capacity " STR(BLE_SECURITY_DATABASE_MAX_ENTRIES) " entries) - no persistence across reset");
}
SecurityDistributionFlags_t *MemorySecurityDb::get_distribution_flags(
entry_handle_t db_handle
) {
return reinterpret_cast<SecurityDistributionFlags_t*>(db_handle);
}
/* local keys */
/* set */
void MemorySecurityDb::set_entry_local_ltk(
entry_handle_t db_handle,
const ltk_t &ltk
) {
entry_t *entry = as_entry(db_handle);
if (entry) {
tr_info("Write DB entry %d: local ltk %s", get_index(db_handle), to_string(ltk));
entry->flags.ltk_sent = true;
entry->local_keys.ltk = ltk;
}
}
void MemorySecurityDb::set_entry_local_ediv_rand(
entry_handle_t db_handle,
const ediv_t &ediv,
const rand_t &rand
) {
entry_t *entry = as_entry(db_handle);
if (entry) {
tr_info("Write DB entry %d: local ediv %s rand %s", get_index(db_handle), to_string(ediv), to_string(rand));
entry->local_keys.ediv = ediv;
entry->local_keys.rand = rand;
}
}
void MemorySecurityDb::set_entry_peer_ltk(
entry_handle_t db_handle,
const ltk_t &ltk
) {
entry_t *entry = as_entry(db_handle);
if (entry) {
tr_info("Write DB entry %d: peer ltk %s", get_index(db_handle), to_string(ltk));
entry->peer_keys.ltk = ltk;
entry->flags.ltk_stored = true;
}
}
void MemorySecurityDb::set_entry_peer_ediv_rand(
entry_handle_t db_handle,
const ediv_t &ediv,
const rand_t &rand
) {
entry_t *entry = as_entry(db_handle);
if (entry) {
tr_info("Write DB entry %d: peer ediv %s rand %s", get_index(db_handle), to_string(ediv), to_string(rand));
entry->peer_keys.ediv = ediv;
entry->peer_keys.rand = rand;
}
}
void MemorySecurityDb::set_entry_peer_irk(
entry_handle_t db_handle,
const irk_t &irk
) {
entry_t *entry = as_entry(db_handle);
if (entry) {
tr_info("Write DB entry %d: peer irk %s", get_index(db_handle), to_string(irk));
entry->peer_identity.irk = irk;
entry->flags.irk_stored = true;
}
}
void MemorySecurityDb::set_entry_peer_bdaddr(
entry_handle_t db_handle,
bool address_is_public,
const address_t &peer_address
) {
entry_t *entry = as_entry(db_handle);
if (entry) {
tr_info("Write DB entry %d: %s peer address %s", get_index(db_handle), address_is_public? "public" : "private", to_string(peer_address));
entry->peer_identity.identity_address = peer_address;
entry->peer_identity.identity_address_is_public = address_is_public;
}
}
void MemorySecurityDb::set_entry_peer_csrk(
entry_handle_t db_handle,
const csrk_t &csrk
) {
entry_t *entry = as_entry(db_handle);
if (entry) {
tr_info("Write DB entry %d: peer csrk %s", get_index(db_handle), to_string(csrk));
entry->flags.csrk_stored = true;
entry->peer_signing.csrk = csrk;
}
}
void MemorySecurityDb::set_entry_peer_sign_counter(
entry_handle_t db_handle,
sign_count_t sign_counter
) {
entry_t *entry = as_entry(db_handle);
if (entry) {
tr_info("Write DB entry %d: sign counter %lu", get_index(db_handle), sign_counter);
entry->peer_signing.counter = sign_counter;
}
}
uint8_t MemorySecurityDb::get_entry_count() {
return BLE_SECURITY_DATABASE_MAX_ENTRIES;
}
SecurityDistributionFlags_t *MemorySecurityDb::get_entry_handle_by_index(uint8_t index) {
if (index < BLE_SECURITY_DATABASE_MAX_ENTRIES) {
return &_entries[index].flags;
} else {
return nullptr;
}
}
void MemorySecurityDb::reset_entry(entry_handle_t db_entry) {
auto *entry = reinterpret_cast<entry_t*>(db_entry);
*entry = entry_t();
}
SecurityEntryIdentity_t *MemorySecurityDb::read_in_entry_peer_identity(entry_handle_t db_entry) {
auto *entry = reinterpret_cast<entry_t*>(db_entry);
return &entry->peer_identity;
}
SecurityEntryKeys_t *MemorySecurityDb::read_in_entry_peer_keys(entry_handle_t db_entry) {
auto *entry = reinterpret_cast<entry_t*>(db_entry);
return &entry->peer_keys;
}
SecurityEntryKeys_t *MemorySecurityDb::read_in_entry_local_keys(entry_handle_t db_entry) {
auto *entry = reinterpret_cast<entry_t*>(db_entry);
return &entry->local_keys;
}
SecurityEntrySigning_t *MemorySecurityDb::read_in_entry_peer_signing(entry_handle_t db_entry) {
auto *entry = reinterpret_cast<entry_t*>(db_entry);
return &entry->peer_signing;
}
uint8_t MemorySecurityDb::get_index(const entry_handle_t db_handle) const
{
return reinterpret_cast<entry_t*>(db_handle) - _entries;
}
} /* namespace ble */

View File

@ -21,15 +21,6 @@
#include "SecurityDb.h"
#include "mbed-trace/mbed_trace.h"
#include "common/ble_trace_helpers.h"
#define TRACE_GROUP "BLDB"
#define _STR(x) #x
#define STR(x) _STR(x)
namespace ble {
/** Naive memory implementation for verification. */
@ -44,28 +35,16 @@ private:
SecurityEntrySigning_t peer_signing;
};
static entry_t* as_entry(entry_handle_t db_handle)
{
entry_t* entry = reinterpret_cast<entry_t*>(db_handle);
if (!entry) {
tr_error("Invalid security DB handle used");
}
return entry;
}
static entry_t *as_entry(entry_handle_t db_handle);
public:
MemorySecurityDb() : SecurityDb()
{
tr_info("Using memory security DB (capacity " STR(BLE_SECURITY_DATABASE_MAX_ENTRIES) " entries) - no persistence across reset");
}
MemorySecurityDb();
~MemorySecurityDb() override = default;
SecurityDistributionFlags_t* get_distribution_flags(
SecurityDistributionFlags_t *get_distribution_flags(
entry_handle_t db_handle
) override {
return reinterpret_cast<SecurityDistributionFlags_t*>(db_handle);
}
) override;
/* local keys */
@ -73,27 +52,13 @@ public:
void set_entry_local_ltk(
entry_handle_t db_handle,
const ltk_t &ltk
) override {
entry_t *entry = as_entry(db_handle);
if (entry) {
tr_info("Write DB entry %d: local ltk %s", get_index(db_handle), to_string(ltk));
entry->flags.ltk_sent = true;
entry->local_keys.ltk = ltk;
}
}
) override;
void set_entry_local_ediv_rand(
entry_handle_t db_handle,
const ediv_t &ediv,
const rand_t &rand
) override {
entry_t *entry = as_entry(db_handle);
if (entry) {
tr_info("Write DB entry %d: local ediv %s rand %s", get_index(db_handle), to_string(ediv), to_string(rand));
entry->local_keys.ediv = ediv;
entry->local_keys.rand = rand;
}
}
) override;
/* peer's keys */
@ -102,118 +67,51 @@ public:
void set_entry_peer_ltk(
entry_handle_t db_handle,
const ltk_t &ltk
) override {
entry_t *entry = as_entry(db_handle);
if (entry) {
tr_info("Write DB entry %d: peer ltk %s", get_index(db_handle), to_string(ltk));
entry->peer_keys.ltk = ltk;
entry->flags.ltk_stored = true;
}
}
) override;
void set_entry_peer_ediv_rand(
entry_handle_t db_handle,
const ediv_t &ediv,
const rand_t &rand
) override {
entry_t *entry = as_entry(db_handle);
if (entry) {
tr_info("Write DB entry %d: peer ediv %s rand %s", get_index(db_handle), to_string(ediv), to_string(rand));
entry->peer_keys.ediv = ediv;
entry->peer_keys.rand = rand;
}
}
) override;
void set_entry_peer_irk(
entry_handle_t db_handle,
const irk_t &irk
) override {
entry_t *entry = as_entry(db_handle);
if (entry) {
tr_info("Write DB entry %d: peer irk %s", get_index(db_handle), to_string(irk));
entry->peer_identity.irk = irk;
entry->flags.irk_stored = true;
}
}
) override;
void set_entry_peer_bdaddr(
entry_handle_t db_handle,
bool address_is_public,
const address_t &peer_address
) override {
entry_t *entry = as_entry(db_handle);
if (entry) {
tr_info("Write DB entry %d: %s peer address %s", get_index(db_handle), address_is_public? "public" : "private", to_string(peer_address));
entry->peer_identity.identity_address = peer_address;
entry->peer_identity.identity_address_is_public = address_is_public;
}
}
) override;
void set_entry_peer_csrk(
entry_handle_t db_handle,
const csrk_t &csrk
) override {
entry_t *entry = as_entry(db_handle);
if (entry) {
tr_info("Write DB entry %d: peer csrk %s", get_index(db_handle), to_string(csrk));
entry->flags.csrk_stored = true;
entry->peer_signing.csrk = csrk;
}
}
) override;
void set_entry_peer_sign_counter(
entry_handle_t db_handle,
sign_count_t sign_counter
) override {
entry_t *entry = as_entry(db_handle);
if (entry) {
tr_info("Write DB entry %d: sign counter %lu", get_index(db_handle), sign_counter);
entry->peer_signing.counter = sign_counter;
}
}
) override;
private:
uint8_t get_entry_count() override {
return BLE_SECURITY_DATABASE_MAX_ENTRIES;
}
uint8_t get_entry_count() override;
SecurityDistributionFlags_t* get_entry_handle_by_index(uint8_t index) override {
if (index < BLE_SECURITY_DATABASE_MAX_ENTRIES) {
return &_entries[index].flags;
} else {
return nullptr;
}
}
SecurityDistributionFlags_t *get_entry_handle_by_index(uint8_t index) override;
void reset_entry(entry_handle_t db_entry) override{
auto *entry = reinterpret_cast<entry_t*>(db_entry);
*entry = entry_t();
}
void reset_entry(entry_handle_t db_entry) override;
SecurityEntryIdentity_t* read_in_entry_peer_identity(entry_handle_t db_entry) override {
auto *entry = reinterpret_cast<entry_t*>(db_entry);
return &entry->peer_identity;
};
SecurityEntryIdentity_t *read_in_entry_peer_identity(entry_handle_t db_entry) override;
SecurityEntryKeys_t* read_in_entry_peer_keys(entry_handle_t db_entry) override {
auto *entry = reinterpret_cast<entry_t*>(db_entry);
return &entry->peer_keys;
};
SecurityEntryKeys_t *read_in_entry_peer_keys(entry_handle_t db_entry) override;
SecurityEntryKeys_t* read_in_entry_local_keys(entry_handle_t db_entry) override {
auto *entry = reinterpret_cast<entry_t*>(db_entry);
return &entry->local_keys;
};
SecurityEntryKeys_t *read_in_entry_local_keys(entry_handle_t db_entry) override;
SecurityEntrySigning_t* read_in_entry_peer_signing(entry_handle_t db_entry) override {
auto *entry = reinterpret_cast<entry_t*>(db_entry);
return &entry->peer_signing;
};
SecurityEntrySigning_t *read_in_entry_peer_signing(entry_handle_t db_entry) override;
uint8_t get_index(const entry_handle_t db_handle) const
{
return reinterpret_cast<entry_t*>(db_handle) - _entries;
}
uint8_t get_index(const entry_handle_t db_handle) const;
private:
entry_t _entries[BLE_SECURITY_DATABASE_MAX_ENTRIES];

View File

@ -0,0 +1,428 @@
/* mbed Microcontroller Library
* Copyright (c) 2021 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "SecurityDb.h"
#include "mbed-trace/mbed_trace.h"
#include "common/ble_trace_helpers.h"
#define TRACE_GROUP "BLDB"
namespace ble {
SecurityDb::SecurityDb() : _local_sign_counter(0) { };
void SecurityDb::set_distribution_flags(
entry_handle_t db_handle,
const SecurityDistributionFlags_t& new_flags
)
{
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
if (flags) {
*flags = new_flags;
}
}
void SecurityDb::get_entry_local_keys(
SecurityEntryKeysDbCb_t cb,
entry_handle_t* db_handle,
const ediv_t &ediv,
const rand_t &rand
)
{
SecurityEntryKeys_t* keys = read_in_entry_local_keys(*db_handle);
/* validate we have the correct key */
if (keys && ediv == keys->ediv && rand == keys->rand) {
cb(*db_handle, keys);
} else {
// Maybe this isn't the correct entry, try to find one that matches
entry_handle_t correct_handle = find_entry_by_peer_ediv_rand(ediv, rand);
if (!correct_handle) {
tr_warn("Failed to find ltk matching given ediv&rand");
cb(*db_handle, NULL);
return;
}
tr_warn("Found ltk matching given ediv&rand but it belonged to a different identity, update entry with new identity");
// Note: keys should never be null as a matching entry has been retrieved
SecurityEntryKeys_t* keys = read_in_entry_local_keys(correct_handle);
MBED_ASSERT(keys);
/* set flags connected */
SecurityDistributionFlags_t* flags = get_distribution_flags(correct_handle);
flags->connected = true;
/* update peer address */
SecurityDistributionFlags_t* old_flags = get_distribution_flags(*db_handle);
flags->peer_address = old_flags->peer_address;
flags->peer_address_is_public = old_flags->peer_address_is_public;
close_entry(*db_handle, false);
*db_handle = correct_handle;
cb(*db_handle, keys);
}
}
void SecurityDb::get_entry_local_keys(
SecurityEntryKeysDbCb_t cb,
entry_handle_t db_handle
)
{
SecurityEntryKeys_t* keys = read_in_entry_local_keys(db_handle);
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
/* validate we have the correct key */
if (flags && keys && flags->secure_connections_paired) {
cb(db_handle, keys);
} else {
cb(db_handle, NULL);
}
}
void SecurityDb::get_entry_peer_csrk(
SecurityEntrySigningDbCb_t cb,
entry_handle_t db_handle
)
{
SecurityEntrySigning_t* signing = read_in_entry_peer_signing(db_handle);
cb(db_handle, signing);
}
void SecurityDb::get_entry_peer_keys(
SecurityEntryKeysDbCb_t cb,
entry_handle_t db_handle
)
{
SecurityEntryKeys_t* keys = read_in_entry_peer_keys(db_handle);
cb(db_handle, keys);
}
void SecurityDb::get_entry_identity(
SecurityEntryIdentityDbCb_t cb,
entry_handle_t db_handle
)
{
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
if (flags && flags->irk_stored) {
SecurityEntryIdentity_t* peer_identity = read_in_entry_peer_identity(db_handle);
if (peer_identity) {
cb(db_handle, peer_identity);
return;
}
}
/* avoid duplicate else */
cb(db_handle, NULL);
}
void SecurityDb::get_identity_list(
IdentitylistDbCb_t cb,
Span<SecurityEntryIdentity_t>& identity_list
)
{
size_t count = 0;
for (size_t i = 0; i < get_entry_count() && count < (size_t) identity_list.size(); ++i) {
entry_handle_t db_handle = get_entry_handle_by_index(i);
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
if (flags && flags->irk_stored) {
SecurityEntryIdentity_t* peer_identity = read_in_entry_peer_identity(db_handle);
if (peer_identity) {
identity_list[count] = *peer_identity;
count++;
}
}
}
cb(identity_list, count);
}
const csrk_t *SecurityDb::get_local_csrk()
{
return &_local_csrk;
}
sign_count_t SecurityDb::get_local_sign_counter()
{
return _local_sign_counter;
}
void SecurityDb::set_local_csrk(const csrk_t &csrk)
{
_local_csrk = csrk;
}
void SecurityDb::set_local_sign_counter(
sign_count_t sign_counter
)
{
_local_sign_counter = sign_counter;
}
void SecurityDb::set_local_identity(
const irk_t &irk,
const address_t &identity_address,
bool public_address
)
{
_local_identity.irk = irk;
_local_identity.identity_address = identity_address;
_local_identity.identity_address_is_public = public_address;
}
irk_t SecurityDb::get_local_irk()
{
return _local_identity.irk;
}
const address_t &SecurityDb::get_local_identity_address()
{
return _local_identity.identity_address;
}
bool SecurityDb::is_local_identity_address_public()
{
return _local_identity.identity_address_is_public;
}
SecurityDb::entry_handle_t SecurityDb::open_entry(
peer_address_type_t peer_address_type,
const address_t &peer_address
)
{
entry_handle_t db_handle = find_entry_by_peer_address(peer_address_type, peer_address);
if (db_handle) {
tr_debug("Found old DB entry (connected to peer previously)");
((SecurityDistributionFlags_t*)db_handle)->connected = true;
return db_handle;
}
SecurityDistributionFlags_t* flags = get_free_entry_flags();
if (flags) {
const bool peer_address_public =
(peer_address_type == peer_address_type_t::PUBLIC) ||
(peer_address_type == peer_address_type_t::PUBLIC_IDENTITY);
/* we need some address to store, so we store even random ones
* this address will be used as an id, possibly replaced later
* by identity address */
flags->peer_address = peer_address;
flags->peer_address_is_public = peer_address_public;
flags->connected = true;
return flags;
}
return nullptr;
}
SecurityDb::entry_handle_t SecurityDb::find_entry_by_peer_address(
peer_address_type_t peer_address_type,
const address_t &peer_address
)
{
const bool peer_address_public =
(peer_address_type == peer_address_type_t::PUBLIC) ||
(peer_address_type == peer_address_type_t::PUBLIC_IDENTITY);
for (size_t i = 0; i < get_entry_count(); i++) {
entry_handle_t db_handle = get_entry_handle_by_index(i);
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
/* only look among disconnected entries */
if (flags && !flags->connected) {
if (peer_address_type == peer_address_type_t::PUBLIC_IDENTITY &&
flags->irk_stored == false) {
continue;
}
/* lookup for connection address used during bonding */
if (flags->peer_address == peer_address &&
flags->peer_address_is_public == peer_address_public) {
return flags;
}
/* look for the identity address if stored */
if (flags->irk_stored) {
SecurityEntryIdentity_t* identity = read_in_entry_peer_identity(db_handle);
if (identity &&
identity->identity_address == peer_address &&
identity->identity_address_is_public == peer_address_public) {
return flags;
}
}
}
}
return nullptr;
}
SecurityDb::entry_handle_t SecurityDb::find_entry_by_peer_ediv_rand(
const ediv_t &ediv,
const rand_t &rand
)
{
for (size_t i = 0; i < get_entry_count(); i++) {
entry_handle_t db_handle = get_entry_handle_by_index(i);
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
if (!flags || flags->connected) {
continue;
}
SecurityEntryKeys_t* keys = read_in_entry_local_keys(db_handle);
if (!keys) {
continue;
}
if (keys->ediv == ediv && keys->rand == rand) {
return db_handle;
}
}
return nullptr;
}
void SecurityDb::close_entry(entry_handle_t db_handle, bool require_sync) {
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
if (flags) {
flags->connected = false;
}
if (require_sync) {
sync(db_handle);
}
}
void SecurityDb::remove_entry(
peer_address_type_t peer_address_type,
const address_t &peer_address
) {
tr_info("Clearing entry for address %s", to_string(peer_address));
entry_handle_t db_handle = find_entry_by_peer_address(peer_address_type, peer_address);
if (db_handle) {
reset_entry(db_handle);
}
}
void SecurityDb::clear_entries()
{
tr_info("Clearing all entries");
for (size_t i = 0; i < get_entry_count(); i++) {
entry_handle_t db_handle = get_entry_handle_by_index(i);
reset_entry(db_handle);
}
_local_identity = SecurityEntryIdentity_t();
_local_csrk = csrk_t();
}
void SecurityDb::get_whitelist(
WhitelistDbCb_t cb,
::ble::whitelist_t *whitelist
) {
/*TODO: fill whitelist*/
cb(whitelist);
}
void SecurityDb::generate_whitelist_from_bond_table(
WhitelistDbCb_t cb,
::ble::whitelist_t *whitelist
) {
for (size_t i = 0; i < get_entry_count() && whitelist->size < whitelist->capacity; i++) {
entry_handle_t db_handle = get_entry_handle_by_index(i);
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
if (!flags || !flags->irk_stored) {
continue;
}
// Add the connection address
whitelist->addresses[whitelist->size].address = flags->peer_address.data();
if (flags->peer_address_is_public) {
whitelist->addresses[whitelist->size].type = peer_address_type_t::PUBLIC;
} else {
whitelist->addresses[whitelist->size].type = peer_address_type_t::RANDOM;
}
whitelist->size++;
if (whitelist->size == whitelist->capacity) {
break;
}
// Add the identity address
SecurityEntryIdentity_t* identity = read_in_entry_peer_identity(db_handle);
if (!identity) {
continue;
}
whitelist->addresses[whitelist->size].address = identity->identity_address;
if (identity->identity_address_is_public) {
whitelist->addresses[whitelist->size].type = peer_address_type_t::PUBLIC_IDENTITY;
} else {
whitelist->addresses[whitelist->size].type = peer_address_type_t::RANDOM_STATIC_IDENTITY;
}
whitelist->size++;
}
cb(whitelist);
}
void SecurityDb::set_whitelist(const ::ble::whitelist_t &whitelist) { };
void SecurityDb::add_whitelist_entry(const address_t &address) { };
void SecurityDb::remove_whitelist_entry(const address_t &address) { };
void SecurityDb::clear_whitelist() { };
void SecurityDb::restore() { };
void SecurityDb::sync(entry_handle_t db_handle) { };
void SecurityDb::set_restore(bool reload) { };
SecurityDistributionFlags_t* SecurityDb::get_free_entry_flags() {
/* get a free one if available */
tr_debug("Retrieve a disconnected entry to use as a new entry in DB.");
SecurityDistributionFlags_t* match = nullptr;
for (size_t i = 0; i < get_entry_count(); i++) {
entry_handle_t db_handle = get_entry_handle_by_index(i);
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
if (flags && !flags->connected) {
/* we settle for any disconnected if we don't find an empty one */
match = flags;
if (!flags->csrk_stored
&& !flags->ltk_stored
&& !flags->ltk_sent
&& !flags->irk_stored) {
/* empty one found, stop looking*/
tr_debug("Using a previously unused entry as a new entry in DB.");
break;
}
}
}
if (match) {
reset_entry(match);
}
return match;
}
} /* namespace ble */

View File

@ -25,11 +25,6 @@
#include "ble/common/BLETypes.h"
#include "ble/Gap.h"
#include "mbed-trace/mbed_trace.h"
#include "common/ble_trace_helpers.h"
#define TRACE_GROUP "BLDB"
namespace ble {
/**
@ -131,7 +126,7 @@ public:
typedef mbed::Callback<void(::ble::whitelist_t*)>
WhitelistDbCb_t;
SecurityDb() : _local_sign_counter(0) { };
SecurityDb();
virtual ~SecurityDb() = default;
/**
@ -154,12 +149,7 @@ public:
virtual void set_distribution_flags(
entry_handle_t db_handle,
const SecurityDistributionFlags_t& new_flags
) {
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
if (flags) {
*flags = new_flags;
}
}
);
/* local keys */
@ -176,38 +166,7 @@ public:
entry_handle_t* db_handle,
const ediv_t &ediv,
const rand_t &rand
) {
SecurityEntryKeys_t* keys = read_in_entry_local_keys(*db_handle);
/* validate we have the correct key */
if (keys && ediv == keys->ediv && rand == keys->rand) {
cb(*db_handle, keys);
} else {
// Maybe this isn't the correct entry, try to find one that matches
entry_handle_t correct_handle = find_entry_by_peer_ediv_rand(ediv, rand);
if (!correct_handle) {
tr_warn("Failed to find ltk matching given ediv&rand");
cb(*db_handle, NULL);
return;
}
tr_warn("Found ltk matching given ediv&rand but it belonged to a different identity, update entry with new identity");
// Note: keys should never be null as a matching entry has been retrieved
SecurityEntryKeys_t* keys = read_in_entry_local_keys(correct_handle);
MBED_ASSERT(keys);
/* set flags connected */
SecurityDistributionFlags_t* flags = get_distribution_flags(correct_handle);
flags->connected = true;
/* update peer address */
SecurityDistributionFlags_t* old_flags = get_distribution_flags(*db_handle);
flags->peer_address = old_flags->peer_address;
flags->peer_address_is_public = old_flags->peer_address_is_public;
close_entry(*db_handle, false);
*db_handle = correct_handle;
cb(*db_handle, keys);
}
}
);
/**
* Retrieve stored LTK generated during secure connections pairing.
@ -218,16 +177,7 @@ public:
virtual void get_entry_local_keys(
SecurityEntryKeysDbCb_t cb,
entry_handle_t db_handle
) {
SecurityEntryKeys_t* keys = read_in_entry_local_keys(db_handle);
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
/* validate we have the correct key */
if (flags && keys && flags->secure_connections_paired) {
cb(db_handle, keys);
} else {
cb(db_handle, NULL);
}
}
);
/**
* Save new local LTK for a connection.
@ -266,10 +216,7 @@ public:
virtual void get_entry_peer_csrk(
SecurityEntrySigningDbCb_t cb,
entry_handle_t db_handle
) {
SecurityEntrySigning_t* signing = read_in_entry_peer_signing(db_handle);
cb(db_handle, signing);
}
);
/**
* Return asynchronously the peer encryption key through a callback
@ -281,10 +228,7 @@ public:
virtual void get_entry_peer_keys(
SecurityEntryKeysDbCb_t cb,
entry_handle_t db_handle
) {
SecurityEntryKeys_t* keys = read_in_entry_peer_keys(db_handle);
cb(db_handle, keys);
}
);
/**
* Save new LTK received from the peer.
@ -344,18 +288,7 @@ public:
virtual void get_entry_identity(
SecurityEntryIdentityDbCb_t cb,
entry_handle_t db_handle
) {
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
if (flags && flags->irk_stored) {
SecurityEntryIdentity_t* peer_identity = read_in_entry_peer_identity(db_handle);
if (peer_identity) {
cb(db_handle, peer_identity);
return;
}
}
/* avoid duplicate else */
cb(db_handle, NULL);
}
);
/**
* Asynchronously return the identity list stored in NVM through a callback.
@ -369,25 +302,7 @@ public:
virtual void get_identity_list(
IdentitylistDbCb_t cb,
Span<SecurityEntryIdentity_t>& identity_list
) {
size_t count = 0;
for (size_t i = 0; i < get_entry_count() && count < (size_t) identity_list.size(); ++i) {
entry_handle_t db_handle = get_entry_handle_by_index(i);
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
if (flags && flags->irk_stored) {
SecurityEntryIdentity_t* peer_identity = read_in_entry_peer_identity(db_handle);
if (peer_identity) {
identity_list[count] = *peer_identity;
count++;
}
}
}
cb(identity_list, count);
}
);
/**
* Update peer signing key.
@ -418,18 +333,14 @@ public:
*
* @return pointer to local CSRK
*/
virtual const csrk_t* get_local_csrk() {
return &_local_csrk;
}
virtual const csrk_t* get_local_csrk();
/**
* Return local signing counter.
*
* @return signing counter
*/
virtual sign_count_t get_local_sign_counter() {
return _local_sign_counter;
}
virtual sign_count_t get_local_sign_counter();
/**
* Update local signing key.
@ -438,9 +349,7 @@ public:
*/
virtual void set_local_csrk(
const csrk_t &csrk
) {
_local_csrk = csrk;
}
);
/**
* Update local signing counter.
@ -449,9 +358,7 @@ public:
*/
virtual void set_local_sign_counter(
sign_count_t sign_counter
) {
_local_sign_counter = sign_counter;
}
);
/* local identity */
/**
@ -463,34 +370,24 @@ public:
const irk_t &irk,
const address_t &identity_address,
bool public_address
) {
_local_identity.irk = irk;
_local_identity.identity_address = identity_address;
_local_identity.identity_address_is_public = public_address;
}
);
/**
* Return local irk.
*
* @return irk
*/
virtual irk_t get_local_irk() {
return _local_identity.irk;
}
virtual irk_t get_local_irk();
/**
* Return local identity address.
*/
virtual const address_t& get_local_identity_address() {
return _local_identity.identity_address;
}
virtual const address_t& get_local_identity_address();
/**
* Return if the local identity address is public or not
*/
virtual bool is_local_identity_address_public() {
return _local_identity.identity_address_is_public;
}
virtual bool is_local_identity_address_public();
/* list management */
@ -509,30 +406,7 @@ public:
virtual entry_handle_t open_entry(
peer_address_type_t peer_address_type,
const address_t &peer_address
) {
entry_handle_t db_handle = find_entry_by_peer_address(peer_address_type, peer_address);
if (db_handle) {
tr_debug("Found old DB entry (connected to peer previously)");
((SecurityDistributionFlags_t*)db_handle)->connected = true;
return db_handle;
}
SecurityDistributionFlags_t* flags = get_free_entry_flags();
if (flags) {
const bool peer_address_public =
(peer_address_type == peer_address_type_t::PUBLIC) ||
(peer_address_type == peer_address_type_t::PUBLIC_IDENTITY);
/* we need some address to store, so we store even random ones
* this address will be used as an id, possibly replaced later
* by identity address */
flags->peer_address = peer_address;
flags->peer_address_is_public = peer_address_public;
flags->connected = true;
return flags;
}
return nullptr;
}
);
/**
* Find a database entry based on peer address.
@ -545,43 +419,7 @@ public:
virtual entry_handle_t find_entry_by_peer_address(
peer_address_type_t peer_address_type,
const address_t &peer_address
) {
const bool peer_address_public =
(peer_address_type == peer_address_type_t::PUBLIC) ||
(peer_address_type == peer_address_type_t::PUBLIC_IDENTITY);
for (size_t i = 0; i < get_entry_count(); i++) {
entry_handle_t db_handle = get_entry_handle_by_index(i);
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
/* only look among disconnected entries */
if (flags && !flags->connected) {
if (peer_address_type == peer_address_type_t::PUBLIC_IDENTITY &&
flags->irk_stored == false) {
continue;
}
/* lookup for connection address used during bonding */
if (flags->peer_address == peer_address &&
flags->peer_address_is_public == peer_address_public) {
return flags;
}
/* look for the identity address if stored */
if (flags->irk_stored) {
SecurityEntryIdentity_t* identity = read_in_entry_peer_identity(db_handle);
if (identity &&
identity->identity_address == peer_address &&
identity->identity_address_is_public == peer_address_public) {
return flags;
}
}
}
}
return nullptr;
}
);
/**
* Find a database entry based on ediv and rand.
@ -594,27 +432,7 @@ public:
virtual entry_handle_t find_entry_by_peer_ediv_rand(
const ediv_t &ediv,
const rand_t &rand
) {
for (size_t i = 0; i < get_entry_count(); i++) {
entry_handle_t db_handle = get_entry_handle_by_index(i);
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
if (!flags || flags->connected) {
continue;
}
SecurityEntryKeys_t* keys = read_in_entry_local_keys(db_handle);
if (!keys) {
continue;
}
if (keys->ediv == ediv && keys->rand == rand) {
return db_handle;
}
}
return nullptr;
}
);
/**
@ -622,15 +440,7 @@ public:
*
* @param[in] db_handle this handle will be freed up from the security db.
*/
virtual void close_entry(entry_handle_t db_handle, bool require_sync = true) {
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
if (flags) {
flags->connected = false;
}
if (require_sync) {
sync(db_handle);
}
}
virtual void close_entry(entry_handle_t db_handle, bool require_sync = true);
/**
* Remove entry for this peer from NVM.
@ -644,26 +454,12 @@ public:
virtual void remove_entry(
peer_address_type_t peer_address_type,
const address_t &peer_address
) {
tr_info("Clearing entry for address %s", to_string(peer_address));
entry_handle_t db_handle = find_entry_by_peer_address(peer_address_type, peer_address);
if (db_handle) {
reset_entry(db_handle);
}
}
);
/**
* Remove all entries from the security DB.
*/
virtual void clear_entries() {
tr_info("Clearing all entries");
for (size_t i = 0; i < get_entry_count(); i++) {
entry_handle_t db_handle = get_entry_handle_by_index(i);
reset_entry(db_handle);
}
_local_identity = SecurityEntryIdentity_t();
_local_csrk = csrk_t();
}
virtual void clear_entries();
/**
* Asynchronously return the whitelist stored in NVM through a callback.
@ -676,10 +472,7 @@ public:
virtual void get_whitelist(
WhitelistDbCb_t cb,
::ble::whitelist_t *whitelist
) {
/*TODO: fill whitelist*/
cb(whitelist);
}
);
/**
* Asynchronously return a whitelist through a callback, generated from the
@ -691,93 +484,52 @@ public:
virtual void generate_whitelist_from_bond_table(
WhitelistDbCb_t cb,
::ble::whitelist_t *whitelist
) {
for (size_t i = 0; i < get_entry_count() && whitelist->size < whitelist->capacity; i++) {
entry_handle_t db_handle = get_entry_handle_by_index(i);
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
if (!flags || !flags->irk_stored) {
continue;
}
// Add the connection address
whitelist->addresses[whitelist->size].address = flags->peer_address.data();
if (flags->peer_address_is_public) {
whitelist->addresses[whitelist->size].type = peer_address_type_t::PUBLIC;
} else {
whitelist->addresses[whitelist->size].type = peer_address_type_t::RANDOM;
}
whitelist->size++;
if (whitelist->size == whitelist->capacity) {
break;
}
// Add the identity address
SecurityEntryIdentity_t* identity = read_in_entry_peer_identity(db_handle);
if (!identity) {
continue;
}
whitelist->addresses[whitelist->size].address = identity->identity_address;
if (identity->identity_address_is_public) {
whitelist->addresses[whitelist->size].type = peer_address_type_t::PUBLIC_IDENTITY;
} else {
whitelist->addresses[whitelist->size].type = peer_address_type_t::RANDOM_STATIC_IDENTITY;
}
whitelist->size++;
}
cb(whitelist);
}
);
/**
* Update the whitelist stored in NVM by replacing it with new one.
*
* @param[in] whitelist
*/
virtual void set_whitelist(const ::ble::whitelist_t &whitelist) { };
virtual void set_whitelist(const ::ble::whitelist_t &whitelist);
/**
* Add a new entry to the whitelist in the NVM.
*
* @param[in] address new whitelist entry
*/
virtual void add_whitelist_entry(const address_t &address) { };
virtual void add_whitelist_entry(const address_t &address);
/**
* Remove whitelist entry from NVM.
*
* @param[in] address entry to be removed
*/
virtual void remove_whitelist_entry(const address_t &address) { };
virtual void remove_whitelist_entry(const address_t &address);
/**
*Remove all whitelist entries stored in the NVM.
*/
virtual void clear_whitelist() { };
virtual void clear_whitelist();
/* saving and loading from nvm */
/**
* Read values from storage.
*/
virtual void restore() { };
virtual void restore();
/**
* Flush all values which might be stored in memory into NVM.
*/
virtual void sync(entry_handle_t db_handle) { };
virtual void sync(entry_handle_t db_handle);
/**
* Toggle whether values should be preserved across resets.
*
* @param[in] reload if true values will be preserved across resets.
*/
virtual void set_restore(bool reload) { };
virtual void set_restore(bool reload);
private:
/**
@ -785,34 +537,7 @@ private:
* or use a disconnected entry by reseting all the stored information.
* @return empty entry for the new connection
*/
virtual SecurityDistributionFlags_t* get_free_entry_flags() {
/* get a free one if available */
tr_debug("Retrieve a disconnected entry to use as a new entry in DB.");
SecurityDistributionFlags_t* match = nullptr;
for (size_t i = 0; i < get_entry_count(); i++) {
entry_handle_t db_handle = get_entry_handle_by_index(i);
SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle);
if (flags && !flags->connected) {
/* we settle for any disconnected if we don't find an empty one */
match = flags;
if (!flags->csrk_stored
&& !flags->ltk_stored
&& !flags->ltk_sent
&& !flags->irk_stored) {
/* empty one found, stop looking*/
tr_debug("Using a previously unused entry as a new entry in DB.");
break;
}
}
}
if (match) {
reset_entry(match);
}
return match;
}
virtual SecurityDistributionFlags_t* get_free_entry_flags();
/**
* How many entries can be stored in the database.