From 957486e0ebb57522301a82ed73ec885892e08b74 Mon Sep 17 00:00:00 2001 From: Vincent Coubard Date: Wed, 27 Jan 2021 13:58:59 +0000 Subject: [PATCH] BLE: Move traces out of header file to avoid collisions. This change required the creation of the implementation files of SecurityDb classes. --- .../source/cordio/source/PalAttClientImpl.cpp | 2 + .../source/generic/FileSecurityDb.cpp | 8 + .../source/generic/FileSecurityDb.h | 11 +- .../source/generic/KVStoreSecurityDb.cpp | 8 + .../source/generic/KVStoreSecurityDb.h | 11 - .../source/generic/MemorySecurityDb.cpp | 196 ++++++++ .../source/generic/MemorySecurityDb.h | 142 +----- .../FEATURE_BLE/source/generic/SecurityDb.cpp | 428 ++++++++++++++++++ .../FEATURE_BLE/source/generic/SecurityDb.h | 339 ++------------ 9 files changed, 695 insertions(+), 450 deletions(-) create mode 100644 connectivity/FEATURE_BLE/source/generic/MemorySecurityDb.cpp create mode 100644 connectivity/FEATURE_BLE/source/generic/SecurityDb.cpp diff --git a/connectivity/FEATURE_BLE/source/cordio/source/PalAttClientImpl.cpp b/connectivity/FEATURE_BLE/source/cordio/source/PalAttClientImpl.cpp index b9ff561980..dd9a3c2746 100644 --- a/connectivity/FEATURE_BLE/source/cordio/source/PalAttClientImpl.cpp +++ b/connectivity/FEATURE_BLE/source/cordio/source/PalAttClientImpl.cpp @@ -27,6 +27,8 @@ #include "att_api.h" #include "att_defs.h" +#include "mbed-trace/mbed_trace.h" + #define TRACE_GROUP "BLAT" namespace ble { diff --git a/connectivity/FEATURE_BLE/source/generic/FileSecurityDb.cpp b/connectivity/FEATURE_BLE/source/generic/FileSecurityDb.cpp index 7e2bf46a55..6ad4fd45b0 100644 --- a/connectivity/FEATURE_BLE/source/generic/FileSecurityDb.cpp +++ b/connectivity/FEATURE_BLE/source/generic/FileSecurityDb.cpp @@ -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(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) { diff --git a/connectivity/FEATURE_BLE/source/generic/FileSecurityDb.h b/connectivity/FEATURE_BLE/source/generic/FileSecurityDb.h index f0cdd42be6..1ed0741e2f 100644 --- a/connectivity/FEATURE_BLE/source/generic/FileSecurityDb.h +++ b/connectivity/FEATURE_BLE/source/generic/FileSecurityDb.h @@ -24,9 +24,6 @@ #include #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(db_handle); - if (!entry) { - tr_error("Invalid security DB handle used"); - } - return entry; - } + static entry_t* as_entry(entry_handle_t db_handle); template void db_read(T *value, long int offset) { diff --git a/connectivity/FEATURE_BLE/source/generic/KVStoreSecurityDb.cpp b/connectivity/FEATURE_BLE/source/generic/KVStoreSecurityDb.cpp index 6590e83279..68c5a16ff0 100644 --- a/connectivity/FEATURE_BLE/source/generic/KVStoreSecurityDb.cpp +++ b/connectivity/FEATURE_BLE/source/generic/KVStoreSecurityDb.cpp @@ -62,6 +62,14 @@ KVStoreSecurityDb::~KVStoreSecurityDb() { } +KVStoreSecurityDb::entry_t *KVStoreSecurityDb::as_entry(entry_handle_t db_handle) { + entry_t* entry = reinterpret_cast(db_handle); + if (!entry) { + tr_error("Invalid security DB handle used"); + } + return entry; +} + bool KVStoreSecurityDb::open_db() { uint8_t version = 0; diff --git a/connectivity/FEATURE_BLE/source/generic/KVStoreSecurityDb.h b/connectivity/FEATURE_BLE/source/generic/KVStoreSecurityDb.h index b4c560c969..49b6ed77cc 100644 --- a/connectivity/FEATURE_BLE/source/generic/KVStoreSecurityDb.h +++ b/connectivity/FEATURE_BLE/source/generic/KVStoreSecurityDb.h @@ -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(db_handle); - if (!entry) { - tr_error("Invalid security DB handle used"); - } - return entry; - } - template static void db_read(T *value, const char* key) { char db_key[DB_FULL_KEY_SIZE]; diff --git a/connectivity/FEATURE_BLE/source/generic/MemorySecurityDb.cpp b/connectivity/FEATURE_BLE/source/generic/MemorySecurityDb.cpp new file mode 100644 index 0000000000..58c7359e7d --- /dev/null +++ b/connectivity/FEATURE_BLE/source/generic/MemorySecurityDb.cpp @@ -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(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(db_handle); +} + +/* local keys */ + +/* set */ +void MemorySecurityDb::set_entry_local_ltk( + entry_handle_t db_handle, + const ltk_t <k +) { + 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 <k +) { + 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(db_entry); + *entry = entry_t(); +} + +SecurityEntryIdentity_t *MemorySecurityDb::read_in_entry_peer_identity(entry_handle_t db_entry) { + auto *entry = reinterpret_cast(db_entry); + return &entry->peer_identity; +} + +SecurityEntryKeys_t *MemorySecurityDb::read_in_entry_peer_keys(entry_handle_t db_entry) { + auto *entry = reinterpret_cast(db_entry); + return &entry->peer_keys; +} + +SecurityEntryKeys_t *MemorySecurityDb::read_in_entry_local_keys(entry_handle_t db_entry) { + auto *entry = reinterpret_cast(db_entry); + return &entry->local_keys; +} + +SecurityEntrySigning_t *MemorySecurityDb::read_in_entry_peer_signing(entry_handle_t db_entry) { + auto *entry = reinterpret_cast(db_entry); + return &entry->peer_signing; +} + +uint8_t MemorySecurityDb::get_index(const entry_handle_t db_handle) const +{ + return reinterpret_cast(db_handle) - _entries; +} + +} /* namespace ble */ \ No newline at end of file diff --git a/connectivity/FEATURE_BLE/source/generic/MemorySecurityDb.h b/connectivity/FEATURE_BLE/source/generic/MemorySecurityDb.h index 6ef1b46290..9fff9620a4 100644 --- a/connectivity/FEATURE_BLE/source/generic/MemorySecurityDb.h +++ b/connectivity/FEATURE_BLE/source/generic/MemorySecurityDb.h @@ -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(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(db_handle); - } + ) override; /* local keys */ @@ -73,27 +52,13 @@ public: void set_entry_local_ltk( entry_handle_t db_handle, const ltk_t <k - ) 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 <k - ) 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(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(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(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(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(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(db_handle) - _entries; - } + uint8_t get_index(const entry_handle_t db_handle) const; private: entry_t _entries[BLE_SECURITY_DATABASE_MAX_ENTRIES]; diff --git a/connectivity/FEATURE_BLE/source/generic/SecurityDb.cpp b/connectivity/FEATURE_BLE/source/generic/SecurityDb.cpp new file mode 100644 index 0000000000..b72fbb8369 --- /dev/null +++ b/connectivity/FEATURE_BLE/source/generic/SecurityDb.cpp @@ -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& 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 */ \ No newline at end of file diff --git a/connectivity/FEATURE_BLE/source/generic/SecurityDb.h b/connectivity/FEATURE_BLE/source/generic/SecurityDb.h index 94e23a3705..8decd154c1 100644 --- a/connectivity/FEATURE_BLE/source/generic/SecurityDb.h +++ b/connectivity/FEATURE_BLE/source/generic/SecurityDb.h @@ -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 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& 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.