From d6a5bd28252d8280aed89ff0fc69c914baeaa22c Mon Sep 17 00:00:00 2001 From: Paul Szczeanek Date: Wed, 3 Jun 2020 17:07:47 +0100 Subject: [PATCH 1/8] make number of db entries configurable --- features/FEATURE_BLE/ble/generic/FileSecurityDb.h | 4 +--- features/FEATURE_BLE/ble/generic/MemorySecurityDb.h | 8 +++----- features/FEATURE_BLE/mbed_lib.json | 5 +++++ features/FEATURE_BLE/source/generic/FileSecurityDb.cpp | 6 +++--- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/features/FEATURE_BLE/ble/generic/FileSecurityDb.h b/features/FEATURE_BLE/ble/generic/FileSecurityDb.h index 4c57d67005..82361a7c4e 100644 --- a/features/FEATURE_BLE/ble/generic/FileSecurityDb.h +++ b/features/FEATURE_BLE/ble/generic/FileSecurityDb.h @@ -34,8 +34,6 @@ private: size_t file_offset; }; - static const size_t MAX_ENTRIES = 5; - static entry_t* as_entry(entry_handle_t db_handle) { return reinterpret_cast(db_handle); } @@ -146,7 +144,7 @@ private: static FILE* erase_db_file(FILE* db_file); private: - entry_t _entries[MAX_ENTRIES]; + entry_t _entries[BLE_SECURITY_DATABASE_MAX_ENTRIES]; FILE *_db_file; uint8_t _buffer[sizeof(SecurityEntryKeys_t)]; }; diff --git a/features/FEATURE_BLE/ble/generic/MemorySecurityDb.h b/features/FEATURE_BLE/ble/generic/MemorySecurityDb.h index 6ca9c3b3b0..6ae94ed01c 100644 --- a/features/FEATURE_BLE/ble/generic/MemorySecurityDb.h +++ b/features/FEATURE_BLE/ble/generic/MemorySecurityDb.h @@ -34,8 +34,6 @@ private: SecurityEntrySigning_t peer_signing; }; - static const size_t MAX_ENTRIES = 5; - static entry_t* as_entry(entry_handle_t db_handle) { return reinterpret_cast(db_handle); @@ -150,11 +148,11 @@ public: private: virtual uint8_t get_entry_count() { - return MAX_ENTRIES; + return BLE_SECURITY_DATABASE_MAX_ENTRIES; } virtual SecurityDistributionFlags_t* get_entry_handle_by_index(uint8_t index) { - if (index < MAX_ENTRIES) { + if (index < BLE_SECURITY_DATABASE_MAX_ENTRIES) { return &_entries[index].flags; } else { return NULL; @@ -187,7 +185,7 @@ private: }; private: - entry_t _entries[MAX_ENTRIES]; + entry_t _entries[BLE_SECURITY_DATABASE_MAX_ENTRIES]; }; } /* namespace pal */ diff --git a/features/FEATURE_BLE/mbed_lib.json b/features/FEATURE_BLE/mbed_lib.json index efae862cad..64601cec01 100644 --- a/features/FEATURE_BLE/mbed_lib.json +++ b/features/FEATURE_BLE/mbed_lib.json @@ -71,6 +71,11 @@ "help": "Include periodic advertising support, depends on the extended advertising feature.", "value": true, "macro_name": "BLE_FEATURE_PERIODIC_ADVERTISING" + }, + "ble-security-database-max-entries": { + "help": "How many entries can be stored in the db, depends on security manager.", + "value": 5, + "macro_name": "BLE_SECURITY_DATABASE_MAX_ENTRIES" } } } \ No newline at end of file diff --git a/features/FEATURE_BLE/source/generic/FileSecurityDb.cpp b/features/FEATURE_BLE/source/generic/FileSecurityDb.cpp index 4b0db269e0..8e4b226278 100644 --- a/features/FEATURE_BLE/source/generic/FileSecurityDb.cpp +++ b/features/FEATURE_BLE/source/generic/FileSecurityDb.cpp @@ -54,7 +54,7 @@ const uint16_t DB_VERSION = 1; ) #define DB_SIZE_STORES \ - (FileSecurityDb::MAX_ENTRIES * DB_SIZE_STORE) + (BLE_SECURITY_DATABASE_MAX_ENTRIES * DB_SIZE_STORE) #define DB_OFFSET_VERSION (0) #define DB_OFFSET_RESTORE (DB_OFFSET_VERSION + sizeof(DB_VERSION)) @@ -308,11 +308,11 @@ void FileSecurityDb::set_restore(bool reload) { /* helper functions */ uint8_t FileSecurityDb::get_entry_count() { - return MAX_ENTRIES; + return BLE_SECURITY_DATABASE_MAX_ENTRIES; } SecurityDistributionFlags_t* FileSecurityDb::get_entry_handle_by_index(uint8_t index) { - if (index < MAX_ENTRIES) { + if (index < BLE_SECURITY_DATABASE_MAX_ENTRIES) { return &_entries[index].flags; } else { return NULL; From 94a6cac838feb70aa5ccabaffa101961b0a82a6d Mon Sep 17 00:00:00 2001 From: Paul Szczeanek Date: Wed, 3 Jun 2020 17:24:11 +0100 Subject: [PATCH 2/8] expose identity address used by controller --- .../FEATURE_BLE/ble/pal/PalSecurityManager.h | 16 ++++++++++++++++ .../TARGET_CORDIO/CordioPalSecurityManager.h | 5 +++++ .../source/CordioPalSecurityManager.tpp | 14 ++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/features/FEATURE_BLE/ble/pal/PalSecurityManager.h b/features/FEATURE_BLE/ble/pal/PalSecurityManager.h index 85c024f8e6..f7e064ce84 100644 --- a/features/FEATURE_BLE/ble/pal/PalSecurityManager.h +++ b/features/FEATURE_BLE/ble/pal/PalSecurityManager.h @@ -967,6 +967,22 @@ public: return impl()->set_private_address_timeout(timeout_in_seconds); } + /** + * Retrieve the identity address used by the controller + * + * @param address Will contain the address retrieved. + * @param public_address will be true if the address is public and false + * otherwise. + * @return BLE_ERROR_NONE On success, else an error code indicating the reason + * of the failure + */ + ble_error_t get_identity_address( + address_t& address, + bool& public_address + ) { + return impl()->get_identity_address_(address, public_address); + } + //////////////////////////////////////////////////////////////////////////// // Keys // diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioPalSecurityManager.h b/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioPalSecurityManager.h index dcef01a39e..c75bc86000 100644 --- a/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioPalSecurityManager.h +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioPalSecurityManager.h @@ -212,6 +212,11 @@ public: */ ble_error_t set_private_address_timeout_(uint16_t timeout_in_seconds); + /** + * @see ::ble::pal::SecurityManager::get_identity_address + */ + ble_error_t get_identity_address_(address_t& address, bool& public_address); + //////////////////////////////////////////////////////////////////////////// // Keys // diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalSecurityManager.tpp b/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalSecurityManager.tpp index b159561fca..479a847708 100644 --- a/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalSecurityManager.tpp +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalSecurityManager.tpp @@ -279,6 +279,20 @@ ble_error_t CordioSecurityManager::set_private_address_timeout_( return BLE_ERROR_NONE; } +/** + * @see ::ble::pal::SecurityManager::get_identity_address + */ +template +ble_error_t CordioSecurityManager::get_identity_address_( + address_t& address, + bool& public_address +) { + // On cordio, the public address is hardcoded as the identity address. + address = address_t(HciGetBdAddr()); + public_address = true; + return BLE_ERROR_NONE; +} + //////////////////////////////////////////////////////////////////////////// // Keys // From 05f7685a79088f809a018b82ea51ea18d9accaae Mon Sep 17 00:00:00 2001 From: Paul Szczeanek Date: Wed, 3 Jun 2020 17:27:26 +0100 Subject: [PATCH 3/8] store local csrk and identity in the security db --- .../FEATURE_BLE/ble/generic/FileSecurityDb.h | 15 +++++++++++++++ features/FEATURE_BLE/ble/generic/SecurityDb.h | 16 ++++++++++++++++ .../source/generic/FileSecurityDb.cpp | 17 +++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/features/FEATURE_BLE/ble/generic/FileSecurityDb.h b/features/FEATURE_BLE/ble/generic/FileSecurityDb.h index 82361a7c4e..2dcdb05843 100644 --- a/features/FEATURE_BLE/ble/generic/FileSecurityDb.h +++ b/features/FEATURE_BLE/ble/generic/FileSecurityDb.h @@ -116,6 +116,21 @@ public: sign_count_t sign_counter ); + /* local csrk and identity */ + + virtual void set_local_csrk( + const csrk_t &csrk + ); + + virtual void set_local_identity( + const irk_t &irk, + const address_t &identity_address, + bool public_address + ); + + /* I am not overriding set_local_sign_counter to avoid constant filesystem writes, + * instead this is synced by sync (which is called on disconnection) */ + /* saving and loading from nvm */ virtual void restore(); diff --git a/features/FEATURE_BLE/ble/generic/SecurityDb.h b/features/FEATURE_BLE/ble/generic/SecurityDb.h index 9228dbd39d..f2243e5f49 100644 --- a/features/FEATURE_BLE/ble/generic/SecurityDb.h +++ b/features/FEATURE_BLE/ble/generic/SecurityDb.h @@ -425,6 +425,22 @@ public: _local_sign_counter = sign_counter; } + /* local identity */ + /** + * Update the local identity. + * + * @param[in] csrk new CSRK value + */ + virtual void 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; + } + /* list management */ /** diff --git a/features/FEATURE_BLE/source/generic/FileSecurityDb.cpp b/features/FEATURE_BLE/source/generic/FileSecurityDb.cpp index 8e4b226278..abefb7f209 100644 --- a/features/FEATURE_BLE/source/generic/FileSecurityDb.cpp +++ b/features/FEATURE_BLE/source/generic/FileSecurityDb.cpp @@ -265,6 +265,22 @@ void FileSecurityDb::set_entry_peer_sign_counter( } } +void FileSecurityDb::set_local_csrk( + const csrk_t &csrk +) { + this->SecurityDb::set_local_csrk(csrk); + db_write(&_local_csrk, DB_OFFSET_LOCAL_CSRK); +} + +void FileSecurityDb::set_local_identity( + const irk_t &irk, + const address_t &identity_address, + bool public_address +) { + this->SecurityDb::set_local_identity(irk, identity_address, public_address); + db_write(&_local_identity, DB_OFFSET_LOCAL_IDENTITY); +} + /* saving and loading from nvm */ void FileSecurityDb::restore() { @@ -299,6 +315,7 @@ void FileSecurityDb::sync(entry_handle_t db_handle) { db_write(&entry->peer_sign_counter, entry->file_offset + DB_STORE_OFFSET_PEER_SIGNING_COUNT); db_write(&entry->flags, entry->file_offset + DB_STORE_OFFSET_FLAGS); + db_write(&_local_sign_counter, DB_OFFSET_LOCAL_SIGN_COUNT); } void FileSecurityDb::set_restore(bool reload) { From fff0247ae5905f3ec8a235332403ce8a6496d610 Mon Sep 17 00:00:00 2001 From: Paul Szczeanek Date: Wed, 3 Jun 2020 17:29:20 +0100 Subject: [PATCH 4/8] fix infinite recursive call --- features/FEATURE_BLE/ble/pal/PalSecurityManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/FEATURE_BLE/ble/pal/PalSecurityManager.h b/features/FEATURE_BLE/ble/pal/PalSecurityManager.h index f7e064ce84..31d6643209 100644 --- a/features/FEATURE_BLE/ble/pal/PalSecurityManager.h +++ b/features/FEATURE_BLE/ble/pal/PalSecurityManager.h @@ -964,7 +964,7 @@ public: ble_error_t set_private_address_timeout( uint16_t timeout_in_seconds ) { - return impl()->set_private_address_timeout(timeout_in_seconds); + return impl()->set_private_address_timeout_(timeout_in_seconds); } /** From bfdbcc7b4a0709b2ebf9daba5ef7ab6377d61a99 Mon Sep 17 00:00:00 2001 From: Paul Szczeanek Date: Wed, 3 Jun 2020 17:29:51 +0100 Subject: [PATCH 5/8] add accessor for local irk --- features/FEATURE_BLE/ble/generic/SecurityDb.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/features/FEATURE_BLE/ble/generic/SecurityDb.h b/features/FEATURE_BLE/ble/generic/SecurityDb.h index f2243e5f49..5045634c80 100644 --- a/features/FEATURE_BLE/ble/generic/SecurityDb.h +++ b/features/FEATURE_BLE/ble/generic/SecurityDb.h @@ -441,6 +441,15 @@ public: _local_identity.identity_address_is_public = public_address; } + /** + * Return local irk. + * + * @return irk + */ + virtual irk_t get_local_irk() { + return _local_identity.irk; + } + /* list management */ /** From 73b4bebee025170ef6fffc3bbe9c0953669b98ba Mon Sep 17 00:00:00 2001 From: Paul Szczeanek Date: Wed, 3 Jun 2020 17:30:21 +0100 Subject: [PATCH 6/8] add connection addresses to whitelist --- features/FEATURE_BLE/ble/generic/SecurityDb.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/features/FEATURE_BLE/ble/generic/SecurityDb.h b/features/FEATURE_BLE/ble/generic/SecurityDb.h index 5045634c80..358e5224dc 100644 --- a/features/FEATURE_BLE/ble/generic/SecurityDb.h +++ b/features/FEATURE_BLE/ble/generic/SecurityDb.h @@ -617,6 +617,21 @@ public: 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; From 110b190b387fb066ee53e54e478b31704a3cb96e Mon Sep 17 00:00:00 2001 From: Paul Szczeanek Date: Wed, 3 Jun 2020 17:35:23 +0100 Subject: [PATCH 7/8] fix privacy initialisation and give access to local identity Initialises identity addres when privacy is enabled. Stores the identity. Retrieves local identity if previously stored. --- features/FEATURE_BLE/ble/SecurityManager.h | 28 ++++++++ .../ble/generic/GenericSecurityManager.h | 11 ++++ .../source/generic/GenericSecurityManager.tpp | 64 ++++++++++++++++++- 3 files changed, 101 insertions(+), 2 deletions(-) diff --git a/features/FEATURE_BLE/ble/SecurityManager.h b/features/FEATURE_BLE/ble/SecurityManager.h index 2e6280e80d..56313ec71d 100644 --- a/features/FEATURE_BLE/ble/SecurityManager.h +++ b/features/FEATURE_BLE/ble/SecurityManager.h @@ -285,6 +285,22 @@ public: (void)result; } + /** + * Indicate that a peer address has been saved by the security manager or if we are + * bonded to the peer the identity has been retrieved from the database on connection. + * + * @param[in] connectionHandle Connection handle. + * @param[in] peer_address Peer address that has been saved by the security database, NULL it not found. + * @param[in] address_is_public Address type, true if public. Invalid if peer_address NULL. + */ + virtual void peerIdentity(ble::connection_handle_t connectionHandle, + const address_t *peer_address, + bool address_is_public) { + (void)connectionHandle; + (void)peer_address; + (void)address_is_public; + } + //////////////////////////////////////////////////////////////////////////// // Security // @@ -561,6 +577,14 @@ public: */ ble_error_t setPairingRequestAuthorisation(bool required = true); + /** + * Retrieve identity address for the peer on the given connection. + * + * @param[in] connectionHandle Handle to identify the connection. + * @return BLE_ERROR_NONE or appropriate error code indicating the failure reason. + */ + ble_error_t getPeerIdentity(ble::connection_handle_t connectionHandle); + //////////////////////////////////////////////////////////////////////////// // Feature support // @@ -899,6 +923,10 @@ protected: ble::connection_handle_t connectionHandle ); + ble_error_t getPeerIdentity_( + ble::connection_handle_t connectionHandle + ); + ble_error_t setPairingRequestAuthorisation_( bool required ); diff --git a/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h b/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h index 6f23d078f5..cc94b97b0b 100644 --- a/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h +++ b/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h @@ -124,6 +124,10 @@ public: bool required = true ); + ble_error_t getPeerIdentity_( + connection_handle_t connection + ); + //////////////////////////////////////////////////////////////////////////// // Feature support // @@ -321,6 +325,13 @@ private: */ ble_error_t init_signing(); + /** + * Generate the IRK if needed. + * + * @return BLE_ERROR_NONE or appropriate error code indicating the failure reason. + */ + ble_error_t init_identity(); + /** * Fills the buffer with the specified number of bytes of random data * produced by the link controller diff --git a/features/FEATURE_BLE/source/generic/GenericSecurityManager.tpp b/features/FEATURE_BLE/source/generic/GenericSecurityManager.tpp index b18ef4fd44..26f34675cb 100644 --- a/features/FEATURE_BLE/source/generic/GenericSecurityManager.tpp +++ b/features/FEATURE_BLE/source/generic/GenericSecurityManager.tpp @@ -102,13 +102,19 @@ ble_error_t GenericSecurityManager::init_( result = init_resolving_list(); #endif +#if BLE_FEATURE_PRIVACY + // set the local identity address and irk + if (result != BLE_ERROR_NONE) { + result = init_identity(); + } +#endif // BLE_FEATURE_PRIVACY + if (result != BLE_ERROR_NONE) { delete _db; _db = NULL; - return result; } - return BLE_ERROR_NONE; + return result; } template class TPalSecurityManager, template class SigningMonitor> @@ -309,6 +315,33 @@ ble_error_t GenericSecurityManager::setPair return BLE_ERROR_NONE; } +template class TPalSecurityManager, template class SigningMonitor> +ble_error_t GenericSecurityManager::getPeerIdentity_(connection_handle_t connection) { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; + if (eventHandler) { + ControlBlock_t *cb = get_control_block(connection); + if (!cb) { + return BLE_ERROR_INVALID_PARAM; + } + + _db->get_entry_identity( + [connection,this](SecurityDb::entry_handle_t handle, const SecurityEntryIdentity_t* identity) { + if (eventHandler) { + eventHandler->peerIdentity( + connection, + identity ? &identity->identity_address : nullptr, + identity ? identity->identity_address_is_public : false + ); + } + }, + cb->db_entry + ); + return BLE_ERROR_NONE; + } else { + return BLE_ERROR_INVALID_STATE; + } +} + //////////////////////////////////////////////////////////////////////////// // Feature support // @@ -901,6 +934,33 @@ ble_error_t GenericSecurityManager::init_si return _pal.set_csrk(*pcsrk, local_sign_counter); } +template class TPalSecurityManager, template class SigningMonitor> +ble_error_t GenericSecurityManager::init_identity() { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; + const irk_t *pirk = nullptr; + + irk_t irk = _db->get_local_irk(); + if (irk != irk_t()) { + pirk = &irk; + } else { + ble_error_t ret = get_random_data(irk.data(), irk.size()); + if (ret != BLE_ERROR_NONE) { + return ret; + } + + pirk = &irk; + address_t identity_address; + bool public_address; + ret = _pal.get_identity_address(identity_address, public_address); + if (ret != BLE_ERROR_NONE) { + return ret; + } + _db->set_local_identity(irk, identity_address, public_address); + } + + return _pal.set_irk(*pirk); +} + template class TPalSecurityManager, template class SigningMonitor> ble_error_t GenericSecurityManager::get_random_data(uint8_t *buffer, size_t size) { byte_array_t<8> random_data; From 9d54c565622e08f87b59df218a37f933f971d2ef Mon Sep 17 00:00:00 2001 From: Paul Szczeanek Date: Wed, 3 Jun 2020 17:36:06 +0100 Subject: [PATCH 8/8] reinitialise identity and signing when bond table reset --- .../source/generic/GenericSecurityManager.tpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/features/FEATURE_BLE/source/generic/GenericSecurityManager.tpp b/features/FEATURE_BLE/source/generic/GenericSecurityManager.tpp index 26f34675cb..e08a6f575c 100644 --- a/features/FEATURE_BLE/source/generic/GenericSecurityManager.tpp +++ b/features/FEATURE_BLE/source/generic/GenericSecurityManager.tpp @@ -167,7 +167,21 @@ template class TPalSecurityManager, template class Signin ble_error_t GenericSecurityManager::purgeAllBondingState_(void) { if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; _db->clear_entries(); - return BLE_ERROR_NONE; + + ble_error_t ret = BLE_ERROR_NONE; + +#if BLE_FEATURE_SIGNING + // generate new csrk and irk + ret = init_signing(); + if (ret) { + return ret; + } +#endif // BLE_FEATURE_SIGNING +#if BLE_FEATURE_PRIVACY + ret = init_identity(); +#endif // BLE_FEATURE_PRIVACY + + return ret; } template class TPalSecurityManager, template class SigningMonitor>