diff --git a/features/FEATURE_BLE/ble/SecurityManager.h b/features/FEATURE_BLE/ble/SecurityManager.h index dd6c4b3865..80b34705c1 100644 --- a/features/FEATURE_BLE/ble/SecurityManager.h +++ b/features/FEATURE_BLE/ble/SecurityManager.h @@ -417,6 +417,9 @@ public: * support out-of-band exchanges of security data. * @param[in] passkey To specify a static passkey. * @param[in] signing Generate and distribute signing key during pairing + * @param[in] dbPath Path to the folder used to store keys in the filesystem, + * if NULL keys will be only stored in memory + * * * @return BLE_ERROR_NONE on success. */ @@ -424,12 +427,14 @@ public: bool requireMITM = true, SecurityIOCapabilities_t iocaps = IO_CAPS_NONE, const Passkey_t passkey = NULL, - bool signing = true) { + bool signing = true, + const char *dbPath = NULL) { /* Avoid compiler warnings about unused variables. */ (void)enableBonding; (void)requireMITM; (void)iocaps; (void)passkey; + (void)dbPath; return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */ } diff --git a/features/FEATURE_BLE/ble/generic/FileSecurityDb.h b/features/FEATURE_BLE/ble/generic/FileSecurityDb.h new file mode 100644 index 0000000000..4c57d67005 --- /dev/null +++ b/features/FEATURE_BLE/ble/generic/FileSecurityDb.h @@ -0,0 +1,157 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * + * 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. + */ + +#ifndef GENERIC_FILE_SECURITY_DB_H_ +#define GENERIC_FILE_SECURITY_DB_H_ + +#include "SecurityDb.h" + +#include + +namespace ble { +namespace generic { + +/** Filesystem implementation */ +class FileSecurityDb : public SecurityDb { +private: + + struct entry_t { + SecurityDistributionFlags_t flags; + sign_count_t peer_sign_counter; + 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); + } + + template + void db_read(T *value, long int offset) { + fseek(_db_file, offset, SEEK_SET); + fread(value, sizeof(T), 1, _db_file); + } + + template + void db_write(T *value, long int offset) { + fseek(_db_file, offset, SEEK_SET); + fwrite(value, sizeof(T), 1, _db_file); + } + +public: + FileSecurityDb(FILE *db_file); + virtual ~FileSecurityDb(); + + /** + * Validates or creates a file for the security database. + * @param db_path path to the file + * @return FILE handle open and ready for use by the database or NULL if unavailable + */ + static FILE* open_db_file(const char *db_path); + + virtual SecurityDistributionFlags_t* get_distribution_flags( + entry_handle_t db_handle + ); + + + /* local keys */ + + /* set */ + virtual void set_entry_local_ltk( + entry_handle_t db_handle, + const ltk_t <k + ); + + virtual void set_entry_local_ediv_rand( + entry_handle_t db_handle, + const ediv_t &ediv, + const rand_t &rand + ); + + /* peer's keys */ + + /* set */ + + virtual void set_entry_peer_ltk( + entry_handle_t db_handle, + const ltk_t <k + ); + + virtual void set_entry_peer_ediv_rand( + entry_handle_t db_handle, + const ediv_t &ediv, + const rand_t &rand + ); + + virtual void set_entry_peer_irk( + entry_handle_t db_handle, + const irk_t &irk + ); + + virtual void set_entry_peer_bdaddr( + entry_handle_t db_handle, + bool address_is_public, + const address_t &peer_address + ); + + virtual void set_entry_peer_csrk( + entry_handle_t db_handle, + const csrk_t &csrk + ); + + virtual void set_entry_peer_sign_counter( + entry_handle_t db_handle, + sign_count_t sign_counter + ); + + /* saving and loading from nvm */ + + virtual void restore(); + + virtual void sync(entry_handle_t db_handle); + + virtual void set_restore(bool reload); + +private: + virtual uint8_t get_entry_count(); + + virtual SecurityDistributionFlags_t* get_entry_handle_by_index(uint8_t index); + + virtual void reset_entry(entry_handle_t db_handle); + + virtual SecurityEntryIdentity_t* read_in_entry_peer_identity(entry_handle_t db_handle); + virtual SecurityEntryKeys_t* read_in_entry_peer_keys(entry_handle_t db_handle); + virtual SecurityEntryKeys_t* read_in_entry_local_keys(entry_handle_t db_handle); + virtual SecurityEntrySigning_t* read_in_entry_peer_signing(entry_handle_t db_handle); + + /** + * Zero the db file. + * @param db_file filehandle for file to erase + * @return filehandle when successful, otherwise NULL + */ + static FILE* erase_db_file(FILE* db_file); + +private: + entry_t _entries[MAX_ENTRIES]; + FILE *_db_file; + uint8_t _buffer[sizeof(SecurityEntryKeys_t)]; +}; + +} /* namespace pal */ +} /* namespace ble */ + +#endif /*GENERIC_FILE_SECURITY_DB_H_*/ diff --git a/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h b/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h index c242b7cba6..f5f060a5e6 100644 --- a/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h +++ b/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h @@ -19,7 +19,7 @@ #include "ble/pal/GapTypes.h" #include "ble/BLETypes.h" -#include "ble/pal/SecurityDb.h" +#include "ble/generic/SecurityDb.h" #include "platform/Callback.h" #include "ble/pal/ConnectionEventMonitor.h" #include "ble/pal/SigningEventMonitor.h" @@ -37,8 +37,6 @@ class GenericSecurityManager : public SecurityManager, public pal::ConnectionEventMonitor::EventHandler, public pal::SigningEventMonitor::EventHandler { public: - typedef ble::pal::SecurityDistributionFlags_t SecurityDistributionFlags_t; - typedef ble::pal::SecurityEntryKeys_t SecurityEntryKeys_t; /* implements SecurityManager */ @@ -51,7 +49,8 @@ public: bool mitm = true, SecurityIOCapabilities_t iocaps = IO_CAPS_NONE, const Passkey_t passkey = NULL, - bool signing = true + bool signing = true, + const char* db_path = NULL ); virtual ble_error_t reset(); @@ -236,13 +235,12 @@ public: public: GenericSecurityManager( pal::SecurityManager &palImpl, - pal::SecurityDb &dbImpl, pal::ConnectionEventMonitor &connMonitorImpl, pal::SigningEventMonitor &signingMonitorImpl ) : _pal(palImpl), - _db(dbImpl), _connection_monitor(connMonitorImpl), _signing_monitor(signingMonitorImpl), + _db(NULL), _default_authentication(0), _default_key_distribution(pal::KeyDistribution::KEY_DISTRIBUTION_ALL), _pairing_authorisation_required(false), @@ -256,6 +254,10 @@ public: _oob_local_random[0] = 1; } + ~GenericSecurityManager() { + delete _db; + } + //////////////////////////////////////////////////////////////////////////// // Helper functions // @@ -308,7 +310,7 @@ private: * @param[in] entryKeys security entry containing keys. */ void enable_encryption_cb( - pal::SecurityDb::entry_handle_t entry, + SecurityDb::entry_handle_t entry, const SecurityEntryKeys_t* entryKeys ); @@ -319,7 +321,7 @@ private: * @param[in] entryKeys security entry containing keys. */ void set_ltk_cb( - pal::SecurityDb::entry_handle_t entry, + SecurityDb::entry_handle_t entry, const SecurityEntryKeys_t* entryKeys ); @@ -327,24 +329,22 @@ private: * Returns the CSRK for the connection. Called by the security db. * * @param[in] connectionHandle Handle to identify the connection. - * @param[in] csrk connection signature resolving key. + * @param[in] signing connection signature resolving key and counter. */ void return_csrk_cb( - pal::SecurityDb::entry_handle_t connection, - const csrk_t *csrk, - sign_count_t sign_counter + SecurityDb::entry_handle_t connection, + const SecurityEntrySigning_t *signing ); /** * Set the peer CSRK for the connection. Called by the security db. * * @param[in] connectionHandle Handle to identify the connection. - * @param[in] csrk connection signature resolving key. + * @param[in] signing connection signature resolving key and counter. */ void set_peer_csrk_cb( - pal::SecurityDb::entry_handle_t connection, - const csrk_t *csrk, - sign_count_t sign_counter + SecurityDb::entry_handle_t connection, + const SecurityEntrySigning_t *signing ); /** @@ -407,8 +407,8 @@ private: * @param identity The identity associated with the entry; may be NULL. */ void on_security_entry_retrieved( - pal::SecurityDb::entry_handle_t entry, - const pal::SecurityEntryIdentity_t* identity + SecurityDb::entry_handle_t entry, + const SecurityEntryIdentity_t* identity ); /** @@ -421,12 +421,12 @@ private: * @param count Number of identities entries retrieved. */ void on_identity_list_retrieved( - ble::ArrayView& identity_list, + ble::ArrayView& identity_list, size_t count ); private: - struct ControlBlock_t : public pal::SecurityDistributionFlags_t { + struct ControlBlock_t { ControlBlock_t(); pal::KeyDistribution get_initiator_key_distribution() { @@ -443,7 +443,7 @@ private: }; connection_handle_t connection; - pal::SecurityDb::entry_handle_t db_entry; + SecurityDb::entry_handle_t db_entry; address_t local_address; /**< address used for connection, possibly different from identity */ @@ -473,10 +473,11 @@ private: }; pal::SecurityManager &_pal; - pal::SecurityDb &_db; pal::ConnectionEventMonitor &_connection_monitor; pal::SigningEventMonitor &_signing_monitor; + SecurityDb *_db; + /* OOB data */ address_t _oob_local_address; address_t _oob_peer_address; @@ -718,7 +719,7 @@ public: ControlBlock_t* get_control_block(const address_t &peer_address); - ControlBlock_t* get_control_block(pal::SecurityDb::entry_handle_t db_entry); + ControlBlock_t* get_control_block(SecurityDb::entry_handle_t db_entry); void release_control_block(ControlBlock_t* entry); }; diff --git a/features/FEATURE_BLE/ble/generic/MemorySecurityDb.h b/features/FEATURE_BLE/ble/generic/MemorySecurityDb.h new file mode 100644 index 0000000000..6ca9c3b3b0 --- /dev/null +++ b/features/FEATURE_BLE/ble/generic/MemorySecurityDb.h @@ -0,0 +1,196 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * + * 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. + */ + +#ifndef GENERIC_MEMORY_SECURITY_DB_H_ +#define GENERIC_MEMORY_SECURITY_DB_H_ + +#include "SecurityDb.h" + +namespace ble { +namespace generic { + +/** Naive memory implementation for verification. */ +class MemorySecurityDb : public SecurityDb { +private: + struct entry_t { + entry_t() { }; + SecurityDistributionFlags_t flags; + SecurityEntryKeys_t local_keys; + SecurityEntryKeys_t peer_keys; + SecurityEntryIdentity_t peer_identity; + 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); + } + +public: + MemorySecurityDb() : SecurityDb() { } + virtual ~MemorySecurityDb() { } + + virtual SecurityDistributionFlags_t* get_distribution_flags( + entry_handle_t db_handle + ) { + return reinterpret_cast(db_handle); + } + + /* local keys */ + + /* set */ + virtual void set_entry_local_ltk( + entry_handle_t db_handle, + const ltk_t <k + ) { + entry_t *entry = as_entry(db_handle); + if (entry) { + entry->flags.ltk_sent = true; + entry->local_keys.ltk = ltk; + } + } + + virtual void 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) { + entry->local_keys.ediv = ediv; + entry->local_keys.rand = rand; + } + } + + /* peer's keys */ + + /* set */ + + virtual void set_entry_peer_ltk( + entry_handle_t db_handle, + const ltk_t <k + ) { + entry_t *entry = as_entry(db_handle); + if (entry) { + entry->peer_keys.ltk = ltk; + entry->flags.ltk_stored = true; + } + } + + virtual void 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) { + entry->peer_keys.ediv = ediv; + entry->peer_keys.rand = rand; + } + } + + virtual void set_entry_peer_irk( + entry_handle_t db_handle, + const irk_t &irk + ) { + entry_t *entry = as_entry(db_handle); + if (entry) { + entry->peer_identity.irk = irk; + entry->flags.irk_stored = true; + } + } + + virtual void 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) { + entry->peer_identity.identity_address = peer_address; + entry->peer_identity.identity_address_is_public = address_is_public; + } + } + + virtual void set_entry_peer_csrk( + entry_handle_t db_handle, + const csrk_t &csrk + ) { + entry_t *entry = as_entry(db_handle); + if (entry) { + entry->flags.csrk_stored = true; + entry->peer_signing.csrk = csrk; + } + } + + virtual void set_entry_peer_sign_counter( + entry_handle_t db_handle, + sign_count_t sign_counter + ) { + entry_t *entry = as_entry(db_handle); + if (entry) { + entry->peer_signing.counter = sign_counter; + } + } + +private: + virtual uint8_t get_entry_count() { + return MAX_ENTRIES; + } + + virtual SecurityDistributionFlags_t* get_entry_handle_by_index(uint8_t index) { + if (index < MAX_ENTRIES) { + return &_entries[index].flags; + } else { + return NULL; + } + } + + virtual void reset_entry(entry_handle_t db_entry) { + entry_t *entry = reinterpret_cast(db_entry); + *entry = entry_t(); + } + + virtual SecurityEntryIdentity_t* read_in_entry_peer_identity(entry_handle_t db_entry) { + entry_t *entry = reinterpret_cast(db_entry); + return &entry->peer_identity; + }; + + virtual SecurityEntryKeys_t* read_in_entry_peer_keys(entry_handle_t db_entry) { + entry_t *entry = reinterpret_cast(db_entry); + return &entry->peer_keys; + }; + + virtual SecurityEntryKeys_t* read_in_entry_local_keys(entry_handle_t db_entry) { + entry_t *entry = reinterpret_cast(db_entry); + return &entry->local_keys; + }; + + virtual SecurityEntrySigning_t* read_in_entry_peer_signing(entry_handle_t db_entry) { + entry_t *entry = reinterpret_cast(db_entry); + return &entry->peer_signing; + }; + +private: + entry_t _entries[MAX_ENTRIES]; +}; + +} /* namespace pal */ +} /* namespace ble */ + +#endif /*GENERIC_MEMORY_SECURITY_DB_H_*/ diff --git a/features/FEATURE_BLE/ble/generic/SecurityDb.h b/features/FEATURE_BLE/ble/generic/SecurityDb.h new file mode 100644 index 0000000000..009d769554 --- /dev/null +++ b/features/FEATURE_BLE/ble/generic/SecurityDb.h @@ -0,0 +1,752 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * + * 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. + */ + +#ifndef GENERIC_SECURITY_MANAGER_DB_H__ +#define GENERIC_SECURITY_MANAGER_DB_H__ + +#include "platform/Callback.h" +#include "ble/pal/GapTypes.h" +#include "ble/BLETypes.h" +#include "ble/Gap.h" +#include + +namespace ble { +namespace generic { + + +/** + * Security flags associated with a bond. + */ +struct SecurityDistributionFlags_t { + SecurityDistributionFlags_t() : + peer_address(), + encryption_key_size(0), + peer_address_is_public(false), + csrk_stored(false), + ltk_stored(false), + ltk_sent(false), + irk_stored(false), + csrk_mitm_protected(false), + ltk_mitm_protected(false), + secure_connections_paired(false), + connected(false) { + } + + /** peer address */ + address_t peer_address; + + /** encryption key size */ + uint8_t encryption_key_size; + /** true if peer address is public, false if it's static random */ + uint8_t peer_address_is_public:1; + + /** CSRK (Connection Signature Resolving Key) has been distributed and stored */ + uint8_t csrk_stored:1; + /** LTK (Long Term Key) has been distributed and stored */ + uint8_t ltk_stored:1; + uint8_t ltk_sent:1; + /** the security entry has been distributed and stored */ + uint8_t irk_stored:1; + + /** CSRK that is stored has MITM protection */ + uint8_t csrk_mitm_protected:1; + /** LTK that is stored has MITM protection */ + uint8_t ltk_mitm_protected:1; + /** the current pairing was done using Secure Connections */ + uint8_t secure_connections_paired:1; + uint8_t connected:1; +}; + +/** Long Term Key and data used to identify it */ +struct SecurityEntryKeys_t { + /** Long Term Key */ + ltk_t ltk; + /** EDIV (Encryption diversifier) used to identify LTK during legacy pairing */ + ediv_t ediv; + /** Rand (random number) used to identify LTK during legacy pairing */ + rand_t rand; +}; + +/** CSRK and sign counter used to verify messages */ +struct SecurityEntrySigning_t { + SecurityEntrySigning_t() : counter(0) { }; + /** Signing key */ + csrk_t csrk; + /** counter used to verify message to guard from replay attacks */ + sign_count_t counter; +}; + +/** Data for resolving random resolvable addresses */ +struct SecurityEntryIdentity_t { + /** identity address */ + address_t identity_address; + /** Identity Resolving Key */ + irk_t irk; + /** true if peer identity address is public, false if it's static random */ + uint8_t identity_address_is_public:1; +}; + +/** + * SecurityDb holds the state for active connections and bonded devices. + * Keys can be stored in NVM and are returned via callbacks. + * SecurityDb is responsible for serialising any requests and keeping + * the store in a consistent state. + * Active connections state must be returned immediately. + */ +class SecurityDb { +public: + /** + * Opaque type representing a handle to a database entry. + */ + typedef void* entry_handle_t; + + /* callbacks for asynchronous data retrieval from the security db */ + + typedef mbed::Callback + SecurityEntryKeysDbCb_t; + typedef mbed::Callback + SecurityEntrySigningDbCb_t; + typedef mbed::Callback + SecurityEntryIdentityDbCb_t; + typedef mbed::Callback&, size_t count)> + IdentitylistDbCb_t; + typedef mbed::Callback + WhitelistDbCb_t; + + SecurityDb() : _local_sign_counter(0) { }; + virtual ~SecurityDb() { }; + + /** + * Return immediately security flags associated to a db entry. + * + * @param[in] db_handle Entry of the database queried. + * @return pointer to the flags or NULL if the entry do not have any + * associated flags. + */ + virtual SecurityDistributionFlags_t* get_distribution_flags( + entry_handle_t db_handle + ) = 0; + + /** + * Set the distribution flags of a DB entry. + * + * @param[in] db_handle Entry of the database that will store the flags. + * @param[in] flags Distribution flags to store in @p db_handle. + */ + 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 */ + + /** + * Retrieve stored LTK based on passed in EDIV and RAND values. + * + * @param[in] cb callback that will receive the LTK struct + * @param[in] db_handle handle of the entry being queried. + * @param[in] ediv one of the values used to identify the LTK + * @param[in] rand one of the values used to identify the LTK + */ + virtual void 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 { + cb(db_handle, NULL); + } + } + + /** + * Retrieve stored LTK generated during secure connections pairing. + * + * @param[in] cb callback that will receive the LTK struct + * @param[in] db_handle handle of the entry being queried. + */ + 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. + * + * @param[in] db_handle handle of the entry being updated. + * @param[in] ltk the new LTK, if the device is slave, this is the LTK that + * will be used when link is encrypted + */ + virtual void set_entry_local_ltk( + entry_handle_t db_handle, + const ltk_t <k + ) = 0; + + /** + * Update EDIV and RAND used to identify the LTK. + * + * @param[in] db_handle handle of the entry being updated. + * @param[in] ediv new EDIV value + * @param[in] rand new RAND value + */ + virtual void set_entry_local_ediv_rand( + entry_handle_t db_handle, + const ediv_t &ediv, + const rand_t &rand + ) = 0; + + /* peer's keys */ + + /** + * Return asynchronously the peer signing key through a callback + * so that signed packets can be verified. + * + * @param[in] cb callback which will receive the key + * @param[in] db_handle handle of the entry being queried. + */ + 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 + * so that encryption can be enabled. + * + * @param[in] cb callback which will receive the key + * @param[in] db_handle handle of the entry being queried. + */ + 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. + * + * @param[in] db_handle handle of the entry being updated. + * @param[in] ltk the new LTK, if the peer device is slave, this is the LTK + * that will be used when link is encrypted + */ + virtual void set_entry_peer_ltk( + entry_handle_t db_handle, + const ltk_t <k + ) = 0; + + /** + * Update EDIV and RAND used to identify the LTK sent by the peer. + * + * @param[in] db_handle handle of the entry being updated. + * @param[in] ediv new EDIV value + * @param[in] rand new RAND value + */ + virtual void set_entry_peer_ediv_rand( + entry_handle_t db_handle, + const ediv_t &ediv, + const rand_t &rand + ) = 0; + + /** + * Update IRK for this connection. + * + * @param[in] db_handle handle of the entry being updated. + * @param[in] irk new IRK value + */ + virtual void set_entry_peer_irk( + entry_handle_t db_handle, + const irk_t &irk + ) = 0; + + /** + * Update the identity address of the peer. + * + * @param[in] db_handle handle of the entry being updated. + * @param[in] address_is_public is the identity address public or private + * @param[in] peer_address the new address + */ + virtual void set_entry_peer_bdaddr( + entry_handle_t db_handle, + bool address_is_public, + const address_t &peer_address + ) = 0; + + /** + * Retrieve stored identity address and IRK. + * + * @param[in] cb callback that will receive the SecurityEntryIdentity_t struct + * @param[in] db_handle handle of the entry being queried. + */ + 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. + * Function takes ownership of the memory. The identity list and the + * ownership will be returned in the callback. + * + * @param[in] cb callback that will receive the whitelist + * @param[in] identity_list preallocated identity_list that will be filled + * in. + */ + virtual void get_identity_list( + IdentitylistDbCb_t cb, + ArrayView& identity_list + ) { + size_t count = 0; + for (size_t i = 0; i < get_entry_count() && count < 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. + * + * @param[in] db_handle handle of the entry being updated. + * @param[in] csrk new CSRK value + */ + virtual void set_entry_peer_csrk( + entry_handle_t db_handle, + const csrk_t &csrk + ) = 0; + + /** + * Update peer signing counter. + * + * @param[in] db_handle handle of the entry being updated. + * @param[in] sign_counter new signing counter value + */ + virtual void set_entry_peer_sign_counter( + entry_handle_t db_handle, + sign_count_t sign_counter + ) = 0; + + /* local csrk */ + + /** + * Return local signing key used for signing packets. + * + * @return pointer to local CSRK + */ + virtual const csrk_t* get_local_csrk() { + return &_local_csrk; + } + + /** + * Return local signing counter. + * + * @return signing counter + */ + virtual sign_count_t get_local_sign_counter() { + return _local_sign_counter; + } + + /** + * Update local signing key. + * + * @param[in] csrk new CSRK value + */ + virtual void set_local_csrk( + const csrk_t &csrk + ) { + _local_csrk = csrk; + } + + /** + * Update local signing counter. + * + * @param[in] sign_counter new signing counter value + */ + virtual void set_local_sign_counter( + sign_count_t sign_counter + ) { + _local_sign_counter = sign_counter; + } + + /* list management */ + + /** + * Open a database entry. + * + * While this entry is opened; it can be queried and updated with the help + * of the database setter and getter functions. + * + * @param[in] peer_address_type type of address + * @param[in] peer_address this address will be used to locate an existing + * entry. + * + * @return A handle to the entry. + */ + virtual entry_handle_t open_entry( + BLEProtocol::AddressType_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) { + return db_handle; + } + + SecurityDistributionFlags_t* flags = get_free_entry_flags(); + if (flags) { + const bool peer_address_public = + (peer_address_type == BLEProtocol::AddressType::PUBLIC) || + (peer_address_type == BLEProtocol::AddressType::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; + return flags; + } + + return NULL; + } + + /** + * Find a database entry based on peer address. + * + * @param[in] peer_address_type type of address + * @param[in] peer_address this address will be used to locate an existing entry. + * + * @return A handle to the entry. + */ + virtual entry_handle_t find_entry_by_peer_address( + BLEProtocol::AddressType_t peer_address_type, + const address_t &peer_address + ) { + const bool peer_address_public = + (peer_address_type == BLEProtocol::AddressType::PUBLIC) || + (peer_address_type == BLEProtocol::AddressType::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 == BLEProtocol::AddressType::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 NULL; + } + + /** + * Close a connection entry. + * + * @param[in] db_handle this handle will be freed up from the security db. + */ + virtual void close_entry(entry_handle_t db_handle) { + SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle); + if (flags) { + flags->connected = false; + } + sync(db_handle); + } + + /** + * Remove entry for this peer from NVM. + * + * @param[in] peer_address_type type of address + * @param[in] peer_address this address will be used to locate an existing + * entry. + * + * @return A handle to the entry. + */ + virtual void remove_entry( + BLEProtocol::AddressType_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) { + reset_entry(db_handle); + } + } + + /** + * Remove all entries from the security DB. + */ + virtual void clear_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(); + } + + /** + * Asynchronously return the whitelist stored in NVM through a callback. + * Function takes ownership of the memory. The whitelist and the ownership + * will be returned in the callback. + * + * @param[in] cb callback that will receive the whitelist + * @param[in] whitelist preallocated whitelist that will be filled in + */ + virtual void get_whitelist( + WhitelistDbCb_t cb, + ::Gap::Whitelist_t *whitelist + ) { + /*TODO: fill whitelist*/ + cb(whitelist); + } + + /** + * Asynchronously return a whitelist through a callback, generated from the + * bond table. + * + * @param[in] cb callback that will receive the whitelist + * @param[in] whitelist preallocated whitelist that will be filled in + */ + virtual void generate_whitelist_from_bond_table( + WhitelistDbCb_t cb, + ::Gap::Whitelist_t *whitelist + ) { + for (size_t i = 0; i < get_entry_count() && i < whitelist->capacity; i++) { + entry_handle_t db_handle = get_entry_handle_by_index(i); + SecurityDistributionFlags_t* flags = get_distribution_flags(db_handle); + + if (!flags) { + continue; + } + + if (flags->peer_address_is_public) { + whitelist->addresses[i].type = BLEProtocol::AddressType::PUBLIC; + } else { + whitelist->addresses[i].type = BLEProtocol::AddressType::RANDOM_STATIC; + } + + SecurityEntryIdentity_t* identity = read_in_entry_peer_identity(db_handle); + if (identity) { + memcpy( + whitelist->addresses[i].address, + identity->identity_address.data(), + sizeof(BLEProtocol::AddressBytes_t) + ); + } + } + + cb(whitelist); + } + + /** + * Update the whitelist stored in NVM by replacing it with new one. + * + * @param[in] whitelist + */ + virtual void set_whitelist(const ::Gap::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) { }; + + /** + * Remove whitelist entry from NVM. + * + * @param[in] address entry to be removed + */ + virtual void remove_whitelist_entry(const address_t &address) { }; + + /** + *Remove all whitelist entries stored in the NVM. + */ + virtual void clear_whitelist() { }; + + /* saving and loading from nvm */ + + /** + * Read values from storage. + */ + virtual void restore() { }; + + /** + * Flush all values which might be stored in memory into NVM. + */ + 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) { }; + +private: + /** + * Get an entry for a new connection not present in the db yet. This will find a free entry + * 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 */ + SecurityDistributionFlags_t* match = NULL; + 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*/ + break; + } + } + } + + if (match) { + reset_entry(match); + } + + return match; + } + + /** + * How many entries can be stored in the databes. + * @return max number of entries + */ + virtual uint8_t get_entry_count() = 0; + + /** + * Return database entry based on its index. + * @param index index from 0 to get_entry_count() + * @return databse entry stored at index + */ + virtual SecurityDistributionFlags_t* get_entry_handle_by_index(uint8_t index) = 0; + + /** + * Delete all the information. + * @param db_handle handle for the entry to be reset + */ + virtual void reset_entry(entry_handle_t db_handle) = 0; + + /** + * This will read in the requested information into a buffer that will remain valid + * until another read_in call is made. + * @param db_handle handle of the entry to be read + * @return pointer to buffer holding the query result, NULL when not found + */ + virtual SecurityEntryIdentity_t* read_in_entry_peer_identity(entry_handle_t db_handle) = 0; + + /** + * This will read in the requested information into a buffer that will remain valid + * until another read_in call is made. + * @param db_handle handle of the entry to be read + * @return pointer to buffer holding the query result, NULL when not found + */ + virtual SecurityEntryKeys_t* read_in_entry_peer_keys(entry_handle_t db_handle) = 0; + + /** + * This will read in the requested information into a buffer that will remain valid + * until another read_in call is made. + * @param db_handle handle of the entry to be read + * @return pointer to buffer holding the query result, NULL when not found + */ + virtual SecurityEntryKeys_t* read_in_entry_local_keys(entry_handle_t db_handle) = 0; + + /** + * This will read in the requested information into a buffer that will remain valid + * until another read_in call is made. + * @param db_handle handle of the entry to be read + * @return pointer to buffer holding the query result, NULL when not found + */ + virtual SecurityEntrySigning_t* read_in_entry_peer_signing(entry_handle_t db_handle) = 0; + +protected: + SecurityEntryIdentity_t _local_identity; + csrk_t _local_csrk; + sign_count_t _local_sign_counter; +}; + +} /* namespace pal */ +} /* namespace ble */ + +#endif /*GENERIC_SECURITY_MANAGER_DB_H__*/ diff --git a/features/FEATURE_BLE/ble/pal/MemorySecurityDb.h b/features/FEATURE_BLE/ble/pal/MemorySecurityDb.h deleted file mode 100644 index 7616597d6e..0000000000 --- a/features/FEATURE_BLE/ble/pal/MemorySecurityDb.h +++ /dev/null @@ -1,446 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018 ARM Limited - * - * 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. - */ - -#ifndef PAL_MEMORY_SECURITY_DB_H_ -#define PAL_MEMORY_SECURITY_DB_H_ - -#include "SecurityDb.h" - -namespace ble { -namespace pal { - -/** Naive memory implementation for verification. */ -class MemorySecurityDb : public SecurityDb { -private: - enum state_t { - ENTRY_FREE, - ENTRY_RESERVED, - ENTRY_WRITTEN - }; - - struct entry_t { - entry_t() : sign_counter(0), state(ENTRY_FREE) { }; - SecurityDistributionFlags_t flags; - SecurityEntryKeys_t peer_keys; - SecurityEntryKeys_t local_keys; - SecurityEntryIdentity_t peer_identity; - csrk_t csrk; - sign_count_t sign_counter; - state_t state; - }; - static const size_t MAX_ENTRIES = 5; - - static entry_t* as_entry(entry_handle_t entry_handle) - { - return reinterpret_cast(entry_handle); - } - -public: - MemorySecurityDb() : _local_sign_counter(0) { } - virtual ~MemorySecurityDb() { } - - virtual const SecurityDistributionFlags_t* get_distribution_flags( - entry_handle_t entry_handle - ) { - entry_t* entry = as_entry(entry_handle); - if (!entry) { - return NULL; - } - - return &entry->flags; - } - - /** - * Set the distribution flags of the DB entry - */ - virtual void set_distribution_flags( - entry_handle_t entry_handle, - const SecurityDistributionFlags_t& flags - ) { - entry_t* entry = as_entry(entry_handle); - if (!entry) { - return; - } - - entry->state = ENTRY_WRITTEN; - entry->flags = flags; - } - - /* local keys */ - - /* get */ - virtual void get_entry_local_keys( - SecurityEntryKeysDbCb_t cb, - entry_handle_t entry_handle, - const ediv_t &ediv, - const rand_t &rand - ) { - entry_t* entry = as_entry(entry_handle); - if (!entry) { - return; - } - - /* validate we have the correct key */ - if (ediv == entry->local_keys.ediv && rand == entry->local_keys.rand) { - cb(entry_handle, &entry->local_keys); - } else { - cb(entry_handle, NULL); - } - } - - virtual void get_entry_local_keys( - SecurityEntryKeysDbCb_t cb, - entry_handle_t entry_handle - ) { - entry_t* entry = as_entry(entry_handle); - if (!entry) { - return; - } - - /* validate we have the correct key */ - if (entry->flags.secure_connections_paired) { - cb(entry_handle, &entry->local_keys); - } else { - cb(entry_handle, NULL); - } - } - - - /* set */ - virtual void set_entry_local_ltk( - entry_handle_t entry_handle, - const ltk_t <k - ) { - entry_t *entry = as_entry(entry_handle); - if (entry) { - entry->state = ENTRY_WRITTEN; - entry->local_keys.ltk = ltk; - } - } - - virtual void set_entry_local_ediv_rand( - entry_handle_t entry_handle, - const ediv_t &ediv, - const rand_t &rand - ) { - entry_t *entry = as_entry(entry_handle); - if (entry) { - entry->state = ENTRY_WRITTEN; - entry->local_keys.ediv = ediv; - entry->local_keys.rand = rand; - } - } - - /* peer's keys */ - - /* get */ - virtual void get_entry_peer_csrk( - SecurityEntryCsrkDbCb_t cb, - entry_handle_t entry_handle - ) { - csrk_t csrk; - sign_count_t sign_counter = 0; - entry_t *entry = as_entry(entry_handle); - if (entry) { - csrk = entry->csrk; - sign_counter = entry->sign_counter; - } - cb(entry_handle, &csrk, sign_counter); - } - - virtual void get_entry_peer_keys( - SecurityEntryKeysDbCb_t cb, - entry_handle_t entry_handle - ) { - SecurityEntryKeys_t *key = NULL; - entry_t *entry = as_entry(entry_handle); - if (entry) { - key = &entry->peer_keys; - } - cb(entry_handle, key); - } - - virtual void get_entry_identity( - SecurityEntryIdentityDbCb_t cb, - entry_handle_t entry_handle - ) { - entry_t *entry = as_entry(entry_handle); - if (entry && entry->flags.irk_stored) { - cb(entry_handle, &entry->peer_identity); - } else { - cb(entry_handle, NULL); - } - } - - virtual void get_identity_list( - IdentitylistDbCb_t cb, - ArrayView& entries - ) { - size_t count = 0; - for (size_t i = 0; i < MAX_ENTRIES && count < entries.size(); ++i) { - entry_t& e = _entries[i]; - - if (e.state == ENTRY_WRITTEN && e.flags.irk_stored) { - entries[count] = &e.peer_identity; - ++count; - } - } - - cb(entries, count); - } - - /* set */ - - virtual void set_entry_peer_ltk( - entry_handle_t entry_handle, - const ltk_t <k - ) { - entry_t *entry = as_entry(entry_handle); - if (entry) { - entry->state = ENTRY_WRITTEN; - entry->peer_keys.ltk = ltk; - } - } - - virtual void set_entry_peer_ediv_rand( - entry_handle_t entry_handle, - const ediv_t &ediv, - const rand_t &rand - ) { - entry_t *entry = as_entry(entry_handle); - if (entry) { - entry->state = ENTRY_WRITTEN; - entry->peer_keys.ediv = ediv; - entry->peer_keys.rand = rand; - } - } - - virtual void set_entry_peer_irk( - entry_handle_t entry_handle, - const irk_t &irk - ) { - entry_t *entry = as_entry(entry_handle); - if (entry) { - entry->state = ENTRY_WRITTEN; - entry->peer_identity.irk = irk; - entry->flags.irk_stored = true; - } - } - - virtual void set_entry_peer_bdaddr( - entry_handle_t entry_handle, - bool address_is_public, - const address_t &peer_address - ) { - entry_t *entry = as_entry(entry_handle); - if (entry) { - entry->state = ENTRY_WRITTEN; - entry->peer_identity.identity_address = peer_address; - entry->peer_identity.identity_address_is_public = address_is_public; - } - } - - virtual void set_entry_peer_csrk( - entry_handle_t entry_handle, - const csrk_t &csrk - ) { - entry_t *entry = as_entry(entry_handle); - if (entry) { - entry->state = ENTRY_WRITTEN; - entry->csrk = csrk; - } - } - - virtual void set_entry_peer_sign_counter( - entry_handle_t entry_handle, - sign_count_t sign_counter - ) { - entry_t *entry = as_entry(entry_handle); - if (entry) { - entry->state = ENTRY_WRITTEN; - entry->sign_counter = sign_counter; - } - } - - /* local csrk */ - - virtual const csrk_t* get_local_csrk() { - return &_local_csrk; - } - - virtual void set_local_csrk(const csrk_t &csrk) { - _local_csrk = csrk; - } - - virtual sign_count_t get_local_sign_counter() { - return _local_sign_counter; - } - - virtual void set_local_sign_counter( - sign_count_t sign_counter - ) { - _local_sign_counter = sign_counter; - } - - /* list management */ - - virtual entry_handle_t open_entry( - BLEProtocol::AddressType_t peer_address_type, - const address_t &peer_address - ) { - const bool peer_address_public = - (peer_address_type == BLEProtocol::AddressType::PUBLIC) || - (peer_address_type == BLEProtocol::AddressType::PUBLIC_IDENTITY); - - for (size_t i = 0; i < MAX_ENTRIES; i++) { - entry_t& e = _entries[i]; - - if (e.state == ENTRY_FREE) { - continue; - } else { - if (peer_address_type == BLEProtocol::AddressType::PUBLIC_IDENTITY && - e.flags.irk_stored == false - ) { - continue; - } - - // lookup for the identity address then the connection address. - if (e.flags.irk_stored && - e.peer_identity.identity_address == peer_address && - e.peer_identity.identity_address_is_public == peer_address_public - ) { - return &e; - // lookup for connection address used during bonding - } else if (e.flags.peer_address == peer_address && - e.flags.peer_address_is_public == peer_address_public - ) { - return &e; - } - } - } - - // determine if the address in input is private or not. - bool is_private_address = false; - if (peer_address_type == BLEProtocol::AddressType::RANDOM) { - ::Gap::RandomAddressType_t random_type(::Gap::RandomAddressType_t::STATIC); - ble_error_t err = ::Gap::getRandomAddressType(peer_address.data(), &random_type); - if (err) { - return NULL; - } - if (random_type != ::Gap::RandomAddressType_t::STATIC) { - is_private_address = true; - } - } - - /* if we din't find one grab the first disconnected slot*/ - for (size_t i = 0; i < MAX_ENTRIES; i++) { - if (_entries[i].state == ENTRY_FREE) { - _entries[i] = entry_t(); - // do not store private addresses in the flags; just store public - // or random static address so it can be reused latter. - if (is_private_address == false) { - _entries[i].flags.peer_address = peer_address; - _entries[i].flags.peer_address_is_public = peer_address_public; - } else { - _entries[i].flags.peer_address = address_t(); - } - _entries[i].state = ENTRY_RESERVED; - return &_entries[i]; - } - } - - return NULL; - } - - virtual void close_entry(entry_handle_t entry_handle) - { - entry_t *entry = as_entry(entry_handle); - if (entry && entry->state == ENTRY_RESERVED) { - entry->state = ENTRY_FREE; - } - } - - virtual void remove_entry(const address_t peer_identity_address) - { - for (size_t i = 0; i < MAX_ENTRIES; i++) { - if (_entries[i].state == ENTRY_FREE) { - continue; - } else if (peer_identity_address == _entries[i].peer_identity.identity_address) { - _entries[i] = entry_t(); - _entries[i].state = ENTRY_FREE; - return; - } - } - } - - virtual void clear_entries() { - for (size_t i = 0; i < MAX_ENTRIES; i++) { - _entries[i] = entry_t(); - } - _local_identity = SecurityEntryIdentity_t(); - _local_csrk = csrk_t(); - } - - virtual void get_whitelist(WhitelistDbCb_t cb, ::Gap::Whitelist_t *whitelist) { - /*TODO: fill whitelist*/ - cb(whitelist); - } - - virtual void generate_whitelist_from_bond_table(WhitelistDbCb_t cb, ::Gap::Whitelist_t *whitelist) { - for (size_t i = 0; i < MAX_ENTRIES && i < whitelist->capacity; i++) { - if (_entries[i].flags.peer_address_is_public) { - whitelist->addresses[i].type = BLEProtocol::AddressType::PUBLIC; - } else { - whitelist->addresses[i].type = BLEProtocol::AddressType::RANDOM_STATIC; - } - - memcpy( - whitelist->addresses[i].address, - _entries[i].peer_identity.identity_address.data(), - sizeof(BLEProtocol::AddressBytes_t) - ); - } - - cb(whitelist); - } - - virtual void set_whitelist(const ::Gap::Whitelist_t &whitelist) { }; - - virtual void add_whitelist_entry(const address_t &address) { } - - virtual void remove_whitelist_entry(const address_t &address) { } - - virtual void clear_whitelist() { } - - /* saving and loading from nvm */ - - virtual void restore() { } - - virtual void sync() { } - - virtual void set_restore(bool reload) { } - -private: - entry_t _entries[MAX_ENTRIES]; - SecurityEntryIdentity_t _local_identity; - csrk_t _local_csrk; - sign_count_t _local_sign_counter; -}; - -} /* namespace pal */ -} /* namespace ble */ - -#endif /*PAL_MEMORY_SECURITY_DB_H_*/ diff --git a/features/FEATURE_BLE/ble/pal/SecurityDb.h b/features/FEATURE_BLE/ble/pal/SecurityDb.h deleted file mode 100644 index 3df5f5b9a9..0000000000 --- a/features/FEATURE_BLE/ble/pal/SecurityDb.h +++ /dev/null @@ -1,462 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2018 ARM Limited - * - * 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. - */ - -#ifndef PAL_SECURITY_MANAGER_DB_H__ -#define PAL_SECURITY_MANAGER_DB_H__ - -#include "platform/Callback.h" -#include "ble/pal/GapTypes.h" -#include "ble/BLETypes.h" -#include "ble/Gap.h" -#include - -namespace ble { -namespace pal { - - -/** - * Security flags associated with a bond. - */ -struct SecurityDistributionFlags_t { - SecurityDistributionFlags_t() : - peer_address(), - encryption_key_size(0), - peer_address_is_public(false), - csrk_stored(false), - csrk_mitm_protected(false), - ltk_stored(false), - ltk_mitm_protected(false), - secure_connections_paired(false), - irk_stored(false) { - } - - /** peer address */ - address_t peer_address; - - /** encryption key size */ - uint8_t encryption_key_size; - /** true if peer address is public, false if it's static random */ - uint8_t peer_address_is_public:1; - - /** CSRK (Connection Signature Resolving Key) has been distributed and stored */ - uint8_t csrk_stored:1; - /** CSRK that is stored has MITM protection */ - uint8_t csrk_mitm_protected:1; - /** LTK (Long Term Key) has been distributed and stored */ - uint8_t ltk_stored:1; - /** LTK that is stored has MITM protection */ - uint8_t ltk_mitm_protected:1; - /** the current pairing was done using Secure Connections */ - uint8_t secure_connections_paired:1; - /** the security entry has been distributed and stored */ - uint8_t irk_stored:1; -}; - -/** Long Term Key and data used to identify it */ -struct SecurityEntryKeys_t { - /** Long Term Key */ - ltk_t ltk; - /** EDIV (Encryption diversifier) used to identify LTK during legacy pairing */ - ediv_t ediv; - /** Rand (random number) used to identify LTK during legacy pairing */ - rand_t rand; -}; - -/** Data for resolving random resolvable addresses */ -struct SecurityEntryIdentity_t { - /** identity address */ - address_t identity_address; - /** Identity Resolving Key */ - irk_t irk; - /** true if peer identity address is public, false if it's static random */ - uint8_t identity_address_is_public:1; -}; - -/** - * SecurityDb holds the state for active connections and bonded devices. - * Keys can be stored in NVM and are returned via callbacks. - * SecurityDb is responsible for serialising any requests and keeping - * the store in a consistent state. - * Active connections state must be returned immediately. - */ -class SecurityDb { -public: - /** - * Opaque type representing a handle to a database entry. - */ - typedef void* entry_handle_t; - - /* callbacks for asynchronous data retrieval from the security db */ - - typedef mbed::Callback - SecurityEntryKeysDbCb_t; - typedef mbed::Callback - SecurityEntryCsrkDbCb_t; - typedef mbed::Callback - SecurityEntryIdentityDbCb_t; - typedef mbed::Callback&, size_t count)> - IdentitylistDbCb_t; - typedef mbed::Callback - WhitelistDbCb_t; - - SecurityDb() { }; - virtual ~SecurityDb() { }; - - /** - * Return immediately security flags associated to a db entry. - * - * @param[in] db_entry Entry of the database queried. - * @return pointer to the flags or NULL if the entry do not have any - * associated flags. - */ - virtual const SecurityDistributionFlags_t* get_distribution_flags( - entry_handle_t db_entry - ) = 0; - - /** - * Set the distribution flags of a DB entry. - * - * @param[in] db_entry Entry of the database that will store the flags. - * @param[in] flags Distribution flags to store in @p db_entry. - */ - virtual void set_distribution_flags( - entry_handle_t db_entry, - const SecurityDistributionFlags_t& flags - ) = 0; - - /* local keys */ - - /** - * Retrieve stored LTK based on passed in EDIV and RAND values. - * - * @param[in] cb callback that will receive the LTK struct - * @param[in] db_entry handle of the entry being queried. - * @param[in] ediv one of the values used to identify the LTK - * @param[in] rand one of the values used to identify the LTK - */ - virtual void get_entry_local_keys( - SecurityEntryKeysDbCb_t cb, - entry_handle_t db_entry, - const ediv_t &ediv, - const rand_t &rand - ) = 0; - - /** - * Retrieve stored LTK generated during secure connections pairing. - * - * @param[in] cb callback that will receive the LTK struct - * @param[in] db_entry handle of the entry being queried. - */ - virtual void get_entry_local_keys( - SecurityEntryKeysDbCb_t cb, - entry_handle_t db_entry - ) = 0; - - /** - * Save new local LTK for a connection. - * - * @param[in] db_entry handle of the entry being updated. - * @param[in] ltk the new LTK, if the device is slave, this is the LTK that - * will be used when link is encrypted - */ - virtual void set_entry_local_ltk( - entry_handle_t db_entry, - const ltk_t <k - ) = 0; - - /** - * Update EDIV and RAND used to identify the LTK. - * - * @param[in] db_entry handle of the entry being updated. - * @param[in] ediv new EDIV value - * @param[in] rand new RAND value - */ - virtual void set_entry_local_ediv_rand( - entry_handle_t db_entry, - const ediv_t &ediv, - const rand_t &rand - ) = 0; - - /* peer's keys */ - - /** - * Return asynchronously the peer signing key through a callback - * so that signed packets can be verified. - * - * @param[in] cb callback which will receive the key - * @param[in] db_entry handle of the entry being queried. - */ - virtual void get_entry_peer_csrk( - SecurityEntryCsrkDbCb_t cb, - entry_handle_t db_entry - ) = 0; - - /** - * Return asynchronously the peer encryption key through a callback - * so that encryption can be enabled. - * - * @param[in] cb callback which will receive the key - * @param[in] db_entry handle of the entry being queried. - */ - virtual void get_entry_peer_keys( - SecurityEntryKeysDbCb_t cb, - entry_handle_t db_entry - ) = 0; - - /** - * Save new LTK received from the peer. - * - * @param[in] db_entry handle of the entry being updated. - * @param[in] ltk the new LTK, if the peer device is slave, this is the LTK - * that will be used when link is encrypted - */ - virtual void set_entry_peer_ltk( - entry_handle_t db_entry, - const ltk_t <k - ) = 0; - - /** - * Update EDIV and RAND used to identify the LTK sent by the peer. - * - * @param[in] db_entry handle of the entry being updated. - * @param[in] ediv new EDIV value - * @param[in] rand new RAND value - */ - virtual void set_entry_peer_ediv_rand( - entry_handle_t db_entry, - const ediv_t &ediv, - const rand_t &rand - ) = 0; - - /** - * Update IRK for this connection. - * - * @param[in] db_entry handle of the entry being updated. - * @param[in] irk new IRK value - */ - virtual void set_entry_peer_irk( - entry_handle_t db_entry, - const irk_t &irk - ) = 0; - - /** - * Update the identity address of the peer. - * - * @param[in] db_entry handle of the entry being updated. - * @param[in] address_is_public is the identity address public or private - * @param[in] peer_address the new address - */ - virtual void set_entry_peer_bdaddr( - entry_handle_t db_entry, - bool address_is_public, - const address_t &peer_address - ) = 0; - - /** - * Retrieve stored identity address and IRK. - * - * @param[in] cb callback that will receive the SecurityEntryIdentity_t struct - * @param[in] db_entry handle of the entry being queried. - */ - virtual void get_entry_identity( - SecurityEntryIdentityDbCb_t cb, - entry_handle_t db_entry - ) = 0; - - /** - * Asynchronously return the identity list stored in NVM through a callback. - * Function takes ownership of the memory. The identity list and the - * ownership will be returned in the callback. - * - * @param[in] cb callback that will receive the whitelist - * @param[in] identity_list preallocated identity_list that will be filled - * in. - */ - virtual void get_identity_list( - IdentitylistDbCb_t cb, - ArrayView& identity_list - ) = 0; - - /** - * Update peer signing key. - * - * @param[in] db_entry handle of the entry being updated. - * @param[in] csrk new CSRK value - */ - virtual void set_entry_peer_csrk( - entry_handle_t db_entry, - const csrk_t &csrk - ) = 0; - - /** - * Update peer signing counter. - * - * @param[in] db_entry handle of the entry being updated. - * @param[in] sign_counter new signing counter value - */ - virtual void set_entry_peer_sign_counter( - entry_handle_t db_entry, - sign_count_t sign_counter - ) = 0; - - /* local csrk */ - - /** - * Return local signing key used for signing packets. - * - * @return pointer to local CSRK - */ - virtual const csrk_t* get_local_csrk() = 0; - - /** - * Return local signing counter. - * - * @return signing counter - */ - virtual sign_count_t get_local_sign_counter() = 0; - - /** - * Update local signing key. - * - * @param[in] csrk new CSRK value - */ - virtual void set_local_csrk( - const csrk_t &csrk - ) = 0; - - /** - * Update local signing counter. - * - * @param[in] sign_counter new signing counter value - */ - virtual void set_local_sign_counter( - sign_count_t sign_counter - ) = 0; - - /* list management */ - - /** - * Open a database entry. - * - * While this entry is opened; it can be queried and updated with the help - * of the database setter and getter functions. - * - * @param[in] peer_address_type type of address - * @param[in] peer_address this address will be used to locate an existing - * entry. - * - * @return A handle to the entry. - */ - virtual entry_handle_t open_entry( - BLEProtocol::AddressType_t peer_address_type, - const address_t &peer_address - ) = 0; - - /** - * Close a connection entry. - * - * @param[in] db_entry this handle will be freed up from the security db. - */ - virtual void close_entry(entry_handle_t db_entry) = 0; - - /** - * Remove entry for this peer from NVM. - * - * @param[in] peer_identity_address peer address that no longer needs NVM - * storage. - */ - virtual void remove_entry(const address_t peer_identity_address) = 0; - - /** - * Remove all entries from the security DB. - */ - virtual void clear_entries() = 0; - - /** - * Asynchronously return the whitelist stored in NVM through a callback. - * Function takes ownership of the memory. The whitelist and the ownership - * will be returned in the callback. - * - * @param[in] cb callback that will receive the whitelist - * @param[in] whitelist preallocated whitelist that will be filled in - */ - virtual void get_whitelist( - WhitelistDbCb_t cb, - ::Gap::Whitelist_t *whitelist - ) = 0; - - /** - * Asynchronously return a whitelist through a callback, generated from the - * bond table. - * - * @param[in] cb callback that will receive the whitelist - * @param[in] whitelist preallocated whitelist that will be filled in - */ - virtual void generate_whitelist_from_bond_table( - WhitelistDbCb_t cb, - ::Gap::Whitelist_t *whitelist - ) = 0; - - /** - * Update the whitelist stored in NVM by replacing it with new one. - * - * @param[in] whitelist - */ - virtual void set_whitelist(const ::Gap::Whitelist_t &whitelist) = 0; - - /** - * 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) = 0; - - /** - * Remove whitelist entry from NVM. - * - * @param[in] address entry to be removed - */ - virtual void remove_whitelist_entry(const address_t &address) = 0; - - /** - *Remove all whitelist entries stored in the NVM. - */ - virtual void clear_whitelist() = 0; - - /* saving and loading from nvm */ - - /** - * Read values from storage. - */ - virtual void restore() = 0; - - /** - * Flush all values which might be stored in memory into NVM. - */ - virtual void sync() = 0; - - /** - * 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) = 0; -}; - -} /* namespace pal */ -} /* namespace ble */ - -#endif /*PAL_SECURITY_MANAGER_DB_H__*/ diff --git a/features/FEATURE_BLE/source/generic/FileSecurityDb.cpp b/features/FEATURE_BLE/source/generic/FileSecurityDb.cpp new file mode 100644 index 0000000000..7796a3d715 --- /dev/null +++ b/features/FEATURE_BLE/source/generic/FileSecurityDb.cpp @@ -0,0 +1,393 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018 ARM Limited + * + * 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 "FileSecurityDb.h" + +namespace ble { +namespace generic { + +const uint16_t DB_VERSION = 1; + +#define DB_STORE_OFFSET_LOCAL_KEYS (0) +#define DB_STORE_OFFSET_PEER_KEYS (DB_STORE_OFFSET_LOCAL_KEYS + sizeof(SecurityEntryKeys_t)) +#define DB_STORE_OFFSET_PEER_IDENTITY (DB_STORE_OFFSET_PEER_KEYS + sizeof(SecurityEntryKeys_t)) +#define DB_STORE_OFFSET_PEER_SIGNING (DB_STORE_OFFSET_PEER_IDENTITY + sizeof(SecurityEntryIdentity_t)) + +#define DB_STORE_OFFSET_LOCAL_KEYS_LTK (DB_STORE_OFFSET_LOCAL_KEYS) +#define DB_STORE_OFFSET_LOCAL_KEYS_EDIV (DB_STORE_OFFSET_LOCAL_KEYS_LTK + sizeof(ltk_t)) +#define DB_STORE_OFFSET_LOCAL_KEYS_RAND (DB_STORE_OFFSET_LOCAL_KEYS_EDIV + sizeof(ediv_t)) + +#define DB_STORE_OFFSET_PEER_KEYS_LTK (DB_STORE_OFFSET_PEER_KEYS) +#define DB_STORE_OFFSET_PEER_KEYS_EDIV (DB_STORE_OFFSET_PEER_KEYS_LTK + sizeof(ltk_t)) +#define DB_STORE_OFFSET_PEER_KEYS_RAND (DB_STORE_OFFSET_PEER_KEYS_EDIV + sizeof(ediv_t)) + +#define DB_STORE_OFFSET_PEER_IDENTITY_ADDRESS (DB_STORE_OFFSET_PEER_IDENTITY) +#define DB_STORE_OFFSET_PEER_IDENTITY_IRK (DB_STORE_OFFSET_PEER_IDENTITY + sizeof(address_t)) +#define DB_STORE_OFFSET_PEER_IDENTITY_ADDRESS_IS_PUBLIC (DB_STORE_OFFSET_PEER_IDENTITY_IRK + sizeof(irk_t)) + +#define DB_STORE_OFFSET_PEER_SIGNING_COUNT (DB_STORE_OFFSET_PEER_SIGNING + sizeof(csrk_t)) + +/* make size multiple of 4 */ +#define PAD4(value) ((((value - 1) / 4) * 4) + 4) + +#define DB_SIZE_STORE \ + PAD4(sizeof(SecurityEntryKeys_t) + \ + sizeof(SecurityEntryKeys_t) + \ + sizeof(SecurityEntryIdentity_t) + \ + sizeof(SecurityEntrySigning_t) + \ + sizeof(sign_count_t)) + +/* without the size of the file offset as we don't store it */ +#define DB_SIZE_ENTRY \ + (sizeof(SecurityDistributionFlags_t) + sizeof(sign_count_t)) + +#define DB_SIZE_ENTRIES \ + (FileSecurityDb::MAX_ENTRIES * DB_SIZE_ENTRY) + +#define DB_SIZE_STORES \ + (FileSecurityDb::MAX_ENTRIES * DB_SIZE_STORE) + +#define DB_OFFSET_VERSION (0) +#define DB_OFFSET_RESTORE (DB_OFFSET_VERSION + sizeof(DB_VERSION)) +#define DB_OFFSET_LOCAL_IDENTITY (DB_OFFSET_RESTORE + sizeof(bool)) +#define DB_OFFSET_LOCAL_CSRK (DB_OFFSET_LOCAL_IDENTITY + sizeof(SecurityEntryIdentity_t)) +#define DB_OFFSET_LOCAL_SIGN_COUNT (DB_OFFSET_LOCAL_CSRK + sizeof(csrk_t)) +#define DB_OFFSET_ENTRIES (DB_OFFSET_LOCAL_SIGN_COUNT + sizeof(sign_count_t)) +#define DB_OFFSET_STORES (DB_OFFSET_ENTRIES + DB_SIZE_ENTRIES) +#define DB_OFFSET_MAX (DB_OFFSET_STORES + DB_SIZE_STORES) +#define DB_SIZE PAD4(DB_OFFSET_MAX) + +typedef SecurityDb::entry_handle_t entry_handle_t; + +FileSecurityDb::FileSecurityDb(FILE *db_file) + : SecurityDb(), + _db_file(db_file) { + /* init the offset in entries so they point to file positions */ + for (size_t i = 0; i < get_entry_count(); i++) { + _entries[i].file_offset = DB_OFFSET_STORES + i * DB_SIZE_STORE; + } +} + +FileSecurityDb::~FileSecurityDb() { + fclose(_db_file); +} + +FILE* FileSecurityDb::open_db_file(const char *db_path) { + if (!db_path) { + return NULL; + } + + FILE *db_file = fopen(db_path, "wb+"); + + if (!db_file) { + return NULL; + } + + /* we will check the db file and if the version or size doesn't match + * what we expect we will blank it */ + bool init = false; + uint16_t version; + + fseek(db_file, DB_OFFSET_VERSION, SEEK_SET); + + if ((fread(&version, sizeof(version), 1, db_file) == 1) && + (version == DB_VERSION)) { + /* version checks out, try the size */ + fseek(db_file, DB_SIZE - 1, SEEK_SET); + /* read one byte and expect to hit EOF */ + if ((fread(&version, 1, 1, db_file) != 1) || !feof(db_file)) { + init = true; + } + } else { + init = true; + } + + if (init) { + return erase_db_file(db_file); + } + + return db_file; +} + +FILE* FileSecurityDb::erase_db_file(FILE* db_file) { + fseek(db_file, 0, SEEK_SET); + + /* zero the file */ + const uint32_t zero = 0; + size_t count = DB_SIZE / 4; + while (count--) { + if (fwrite(&zero, sizeof(zero), 1, db_file) != 1) { + fclose(db_file); + return NULL; + } + } + + if (fflush(db_file)) { + fclose(db_file); + return NULL; + } + + return db_file; +} + +SecurityDistributionFlags_t* FileSecurityDb::get_distribution_flags( + entry_handle_t db_handle +) { + return reinterpret_cast(db_handle); +} + +/* local keys */ + +/* set */ +void FileSecurityDb::set_entry_local_ltk( + entry_handle_t db_handle, + const ltk_t <k +) { + entry_t *entry = as_entry(db_handle); + if (!entry) { + return; + } + + entry->flags.ltk_sent = true; + + db_write(<k, entry->file_offset + DB_STORE_OFFSET_LOCAL_KEYS_LTK); +} + +void FileSecurityDb::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) { + return; + } + + db_write(&ediv, entry->file_offset + DB_STORE_OFFSET_LOCAL_KEYS_EDIV); + db_write(&rand, entry->file_offset + DB_STORE_OFFSET_LOCAL_KEYS_RAND); +} + +/* peer's keys */ + +/* set */ + +void FileSecurityDb::set_entry_peer_ltk( + entry_handle_t db_handle, + const ltk_t <k +) { + entry_t *entry = as_entry(db_handle); + if (!entry) { + return; + } + + entry->flags.ltk_stored = true; + + db_write(<k, entry->file_offset + DB_STORE_OFFSET_PEER_KEYS_LTK); +} + +void FileSecurityDb::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) { + return; + } + + db_write(&ediv, entry->file_offset + DB_STORE_OFFSET_PEER_KEYS_EDIV); + db_write(&rand, entry->file_offset + DB_STORE_OFFSET_PEER_KEYS_RAND); +} + +void FileSecurityDb::set_entry_peer_irk( + entry_handle_t db_handle, + const irk_t &irk +) { + entry_t *entry = as_entry(db_handle); + if (!entry) { + return; + } + + entry->flags.irk_stored = true; + + db_write(&irk, entry->file_offset + DB_STORE_OFFSET_PEER_IDENTITY_IRK); +} + +void FileSecurityDb::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) { + return; + } + + db_write(&peer_address, entry->file_offset + DB_STORE_OFFSET_PEER_IDENTITY_ADDRESS); + db_write(&address_is_public, entry->file_offset + DB_STORE_OFFSET_PEER_IDENTITY_ADDRESS_IS_PUBLIC); +} + +void FileSecurityDb::set_entry_peer_csrk( + entry_handle_t db_handle, + const csrk_t &csrk +) { + entry_t *entry = as_entry(db_handle); + if (!entry) { + return; + } + + entry->flags.csrk_stored = true; + + db_write(&csrk, entry->file_offset + DB_STORE_OFFSET_PEER_SIGNING); +} + +void FileSecurityDb::set_entry_peer_sign_counter( + entry_handle_t db_handle, + sign_count_t sign_counter +) { + entry_t *entry = as_entry(db_handle); + if (entry) { + entry->peer_sign_counter = sign_counter; + } +} + +/* saving and loading from nvm */ + +void FileSecurityDb::restore() { + + fseek(_db_file, DB_OFFSET_RESTORE, SEEK_SET); + + /* restore if requested */ + bool restore_toggle; + if (fread(&restore_toggle, sizeof(bool), 1, _db_file) == 1) { + if (!restore_toggle) { + erase_db_file(_db_file); + return; + } + } + + db_read(&_local_identity, DB_OFFSET_LOCAL_IDENTITY); + db_read(&_local_csrk, DB_OFFSET_LOCAL_CSRK); + db_read(&_local_sign_counter, DB_OFFSET_LOCAL_SIGN_COUNT); + + fseek(_db_file, DB_OFFSET_ENTRIES, SEEK_SET); + /* we read the entries partially and fill the offsets ourselves*/ + for (size_t i = 0; i < get_entry_count(); i++) { + fread(&_entries[i], DB_SIZE_ENTRY, 1, _db_file); + } + +} + +void FileSecurityDb::sync(entry_handle_t db_handle) { + entry_t *entry = as_entry(db_handle); + if (!entry) { + return; + } + + db_write(&entry->peer_sign_counter, entry->file_offset + DB_STORE_OFFSET_PEER_SIGNING_COUNT); +} + +void FileSecurityDb::set_restore(bool reload) { + db_write(&reload, DB_OFFSET_RESTORE); +} + +/* helper functions */ + +uint8_t FileSecurityDb::get_entry_count() { + return MAX_ENTRIES; +} + +SecurityDistributionFlags_t* FileSecurityDb::get_entry_handle_by_index(uint8_t index) { + if (index < MAX_ENTRIES) { + return &_entries[index].flags; + } else { + return NULL; + } +} + +void FileSecurityDb::reset_entry(entry_handle_t db_entry) { + entry_t *entry = as_entry(db_entry); + if (!entry) { + return; + } + + fseek(_db_file, entry->file_offset, SEEK_SET); + const uint32_t zero = 0; + size_t count = DB_SIZE_STORE / 4; + while (count--) { + fwrite(&zero, sizeof(zero), 1, _db_file); + } + + entry->flags = SecurityDistributionFlags_t(); + entry->peer_sign_counter = 0; +} + +SecurityEntryIdentity_t* FileSecurityDb::read_in_entry_peer_identity(entry_handle_t db_entry) { + entry_t *entry = as_entry(db_entry); + if (!entry) { + return NULL; + } + + SecurityEntryIdentity_t* identity = reinterpret_cast(_buffer); + db_read(identity, entry->file_offset + DB_STORE_OFFSET_PEER_IDENTITY); + + return identity; +}; + +SecurityEntryKeys_t* FileSecurityDb::read_in_entry_peer_keys(entry_handle_t db_entry) { + entry_t *entry = as_entry(db_entry); + if (!entry) { + return NULL; + } + + SecurityEntryKeys_t* keys = reinterpret_cast(_buffer); + db_read(keys, entry->file_offset + DB_STORE_OFFSET_PEER_KEYS); + + return keys; +}; + +SecurityEntryKeys_t* FileSecurityDb::read_in_entry_local_keys(entry_handle_t db_entry) { + entry_t *entry = as_entry(db_entry); + if (!entry) { + return NULL; + } + + SecurityEntryKeys_t* keys = reinterpret_cast(_buffer); + db_read(keys, entry->file_offset + DB_STORE_OFFSET_LOCAL_KEYS); + + return keys; +}; + +SecurityEntrySigning_t* FileSecurityDb::read_in_entry_peer_signing(entry_handle_t db_entry) { + entry_t *entry = as_entry(db_entry); + if (!entry) { + return NULL; + } + + /* only read in the csrk */ + csrk_t* csrk = reinterpret_cast(_buffer); + db_read(csrk, entry->file_offset + DB_STORE_OFFSET_PEER_SIGNING); + + + /* use the counter held in memory */ + SecurityEntrySigning_t* signing = reinterpret_cast(_buffer); + signing->counter = entry->peer_sign_counter; + + return signing; +}; + +} /* namespace pal */ +} /* namespace ble */ diff --git a/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp b/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp index 8e4effaa90..bb03c2f548 100644 --- a/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp +++ b/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp @@ -17,6 +17,8 @@ #include "ble/SecurityManager.h" #include "ble/pal/PalSecurityManager.h" #include "ble/generic/GenericSecurityManager.h" +#include "ble/generic/MemorySecurityDb.h" +#include "ble/generic/FileSecurityDb.h" using ble::pal::advertising_peer_address_type_t; using ble::pal::AuthenticationMask; @@ -37,14 +39,33 @@ ble_error_t GenericSecurityManager::init( bool mitm, SecurityIOCapabilities_t iocaps, const Passkey_t passkey, - bool signing + bool signing, + const char* db_path ) { + ble_error_t err = _pal.initialize(); if (err) { return err; } - _db.restore(); + if (_db) { + delete _db; + } + + FILE* db_file = FileSecurityDb::open_db_file(db_path); + + if (db_file) { + _db = new (std::nothrow) FileSecurityDb(db_file); + } else { + _db = new (std::nothrow) MemorySecurityDb(); + } + + if (!_db) { + return BLE_ERROR_NO_MEM; + } + + _db->restore(); + _pal.set_io_capability((io_capability_t::type) iocaps); if (passkey) { @@ -76,16 +97,16 @@ ble_error_t GenericSecurityManager::init( _pal.set_event_handler(this); uint8_t resolving_list_capacity = _pal.read_resolving_list_capacity(); - pal::SecurityEntryIdentity_t** identity_list_p = - new (std::nothrow) pal::SecurityEntryIdentity_t*[resolving_list_capacity]; + SecurityEntryIdentity_t* identity_list_p = + new (std::nothrow) SecurityEntryIdentity_t[resolving_list_capacity]; if (identity_list_p) { - ArrayView identity_list( + ArrayView identity_list( identity_list_p, resolving_list_capacity ); - _db.get_identity_list( + _db->get_identity_list( mbed::callback(this, &GenericSecurityManager::on_identity_list_retrieved), identity_list ); @@ -95,7 +116,6 @@ ble_error_t GenericSecurityManager::init( } ble_error_t GenericSecurityManager::reset(void) { - _db.sync(); _pal.reset(); SecurityManager::reset(); @@ -103,7 +123,8 @@ ble_error_t GenericSecurityManager::reset(void) { } ble_error_t GenericSecurityManager::preserveBondingStateOnReset(bool enabled) { - _db.set_restore(enabled); + MBED_ASSERT(_db); + _db->set_restore(enabled); return BLE_ERROR_NONE; } @@ -112,13 +133,15 @@ ble_error_t GenericSecurityManager::preserveBondingStateOnReset(bool enabled) { // ble_error_t GenericSecurityManager::purgeAllBondingState(void) { - _db.clear_entries(); + MBED_ASSERT(_db); + _db->clear_entries(); return BLE_ERROR_NONE; } ble_error_t GenericSecurityManager::generateWhitelistFromBondTable(Gap::Whitelist_t *whitelist) const { + MBED_ASSERT(_db); if (eventHandler) { - _db.generate_whitelist_from_bond_table( + _db->generate_whitelist_from_bond_table( mbed::callback(eventHandler, &::SecurityManager::EventHandler::whitelistFromBondTable), whitelist ); @@ -333,18 +356,24 @@ ble_error_t GenericSecurityManager::enableSigning( connection_handle_t connection, bool enabled ) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (!cb) { return BLE_ERROR_INVALID_PARAM; } + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { + return BLE_ERROR_INVALID_PARAM; + } + cb->signing_override_default = true; if (enabled && !cb->signing_requested && !_default_key_distribution.get_signing()) { cb->signing_requested = true; - if (cb->csrk_stored) { + if (flags->csrk_stored) { /* used the stored ones when available */ - _db.get_entry_peer_csrk( + _db->get_entry_peer_csrk( mbed::callback(this, &GenericSecurityManager::set_peer_csrk_cb), cb->db_entry ); @@ -377,15 +406,20 @@ ble_error_t GenericSecurityManager::getLinkEncryption( connection_handle_t connection, link_encryption_t *encryption ) { - + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (!cb) { return BLE_ERROR_INVALID_PARAM; } + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { + return BLE_ERROR_INVALID_PARAM; + } + if (cb->encrypted) { - if (cb->ltk_mitm_protected || cb->mitm_performed) { - if (cb->secure_connections_paired) { + if (flags->ltk_mitm_protected || cb->mitm_performed) { + if (flags->secure_connections_paired) { *encryption = link_encryption_t::ENCRYPTED_WITH_SC_AND_MITM; } else { *encryption = link_encryption_t::ENCRYPTED_WITH_MITM; @@ -406,11 +440,17 @@ ble_error_t GenericSecurityManager::setLinkEncryption( connection_handle_t connection, link_encryption_t encryption ) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (!cb) { return BLE_ERROR_INVALID_PARAM; } + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { + return BLE_ERROR_INVALID_PARAM; + } + link_encryption_t current_encryption(link_encryption_t::NOT_ENCRYPTED); getLinkEncryption(connection, ¤t_encryption); @@ -437,7 +477,7 @@ ble_error_t GenericSecurityManager::setLinkEncryption( } else if (encryption == link_encryption_t::ENCRYPTED_WITH_MITM) { - if (cb->ltk_mitm_protected && !cb->encrypted) { + if (flags->ltk_mitm_protected && !cb->encrypted) { cb->encryption_requested = true; return enable_encryption(connection); } else { @@ -447,8 +487,8 @@ ble_error_t GenericSecurityManager::setLinkEncryption( } else if (encryption == link_encryption_t::ENCRYPTED_WITH_SC_AND_MITM) { - if (cb->ltk_mitm_protected && - cb->secure_connections_paired && + if (flags->ltk_mitm_protected && + flags->secure_connections_paired && !cb->encrypted ) { cb->encryption_requested = true; @@ -471,13 +511,19 @@ ble_error_t GenericSecurityManager::getEncryptionKeySize( connection_handle_t connection, uint8_t *size ) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); - if (cb) { - *size = cb->encryption_key_size; - return BLE_ERROR_NONE; - } else { + if (!cb) { return BLE_ERROR_INVALID_PARAM; } + + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { + return BLE_ERROR_INVALID_PARAM; + } + + *size = flags->encryption_key_size; + return BLE_ERROR_NONE; } ble_error_t GenericSecurityManager::setEncryptionKeyRequirements( @@ -492,15 +538,21 @@ ble_error_t GenericSecurityManager::setEncryptionKeyRequirements( // ble_error_t GenericSecurityManager::getSigningKey(connection_handle_t connection, bool authenticated) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (!cb) { return BLE_ERROR_INVALID_PARAM; } - if (cb->csrk_stored && (cb->csrk_mitm_protected || !authenticated)) { + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { + return BLE_ERROR_INVALID_PARAM; + } + + if (flags->csrk_stored && (flags->csrk_mitm_protected || !authenticated)) { /* we have a key that is either authenticated or we don't care if it is * so retrieve it from the db now */ - _db.get_entry_peer_csrk( + _db->get_entry_peer_csrk( mbed::callback(this, &GenericSecurityManager::return_csrk_cb), cb->db_entry ); @@ -532,12 +584,18 @@ ble_error_t GenericSecurityManager::setPrivateAddressTimeout(uint16_t timeout_in // ble_error_t GenericSecurityManager::requestAuthentication(connection_handle_t connection) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (!cb) { return BLE_ERROR_INVALID_PARAM; } - if (cb->ltk_mitm_protected) { + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { + return BLE_ERROR_INVALID_PARAM; + } + + if (flags->ltk_mitm_protected) { if (cb->authenticated) { return BLE_ERROR_NONE; } else { @@ -643,16 +701,22 @@ ble_error_t GenericSecurityManager::legacyPairingOobReceived( const address_t *address, const oob_tk_t *tk ) { + MBED_ASSERT(_db); if (address && tk) { ControlBlock_t *cb = get_control_block(*address); if (!cb) { return BLE_ERROR_INVALID_PARAM; } + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { + return BLE_ERROR_INVALID_PARAM; + } + _oob_temporary_key = *tk; _oob_temporary_key_creator_address = *address; - if (cb->peer_address == _oob_temporary_key_creator_address) { + if (flags->peer_address == _oob_temporary_key_creator_address) { cb->attempt_oob = true; } @@ -687,8 +751,9 @@ ble_error_t GenericSecurityManager::oobReceived( // ble_error_t GenericSecurityManager::init_signing() { - const csrk_t *pcsrk = _db.get_local_csrk(); - sign_count_t local_sign_counter = _db.get_local_sign_counter(); + MBED_ASSERT(_db); + const csrk_t *pcsrk = _db->get_local_csrk(); + sign_count_t local_sign_counter = _db->get_local_sign_counter(); if (!pcsrk) { csrk_t csrk; @@ -699,8 +764,8 @@ ble_error_t GenericSecurityManager::init_signing() { } pcsrk = &csrk; - _db.set_local_csrk(csrk); - _db.set_local_sign_counter(local_sign_counter); + _db->set_local_csrk(csrk); + _db->set_local_sign_counter(local_sign_counter); } return _pal.set_csrk(*pcsrk, local_sign_counter); @@ -736,13 +801,20 @@ ble_error_t GenericSecurityManager::slave_security_request(connection_handle_t c } ble_error_t GenericSecurityManager::enable_encryption(connection_handle_t connection) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (!cb) { return BLE_ERROR_INVALID_PARAM; } + + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { + return BLE_ERROR_INVALID_PARAM; + } + if (cb->is_master) { - if (cb->ltk_stored) { - _db.get_entry_peer_keys( + if (flags->ltk_stored) { + _db->get_entry_peer_keys( mbed::callback(this, &GenericSecurityManager::enable_encryption_cb), cb->db_entry ); @@ -756,90 +828,121 @@ ble_error_t GenericSecurityManager::enable_encryption(connection_handle_t connec } void GenericSecurityManager::enable_encryption_cb( - pal::SecurityDb::entry_handle_t db_entry, + SecurityDb::entry_handle_t db_entry, const SecurityEntryKeys_t* entryKeys ) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(db_entry); + if (!cb) { + return; + } - if (cb && entryKeys) { - if (cb->secure_connections_paired) { - _pal.enable_encryption(cb->connection, entryKeys->ltk, cb->ltk_mitm_protected); + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { + return; + } + + if (entryKeys) { + if (flags->secure_connections_paired) { + _pal.enable_encryption(cb->connection, entryKeys->ltk, flags->ltk_mitm_protected); } else { - _pal.enable_encryption(cb->connection, entryKeys->ltk, entryKeys->rand, entryKeys->ediv, cb->ltk_mitm_protected); + _pal.enable_encryption(cb->connection, entryKeys->ltk, entryKeys->rand, entryKeys->ediv, flags->ltk_mitm_protected); } } } void GenericSecurityManager::set_ltk_cb( - pal::SecurityDb::entry_handle_t db_entry, + SecurityDb::entry_handle_t db_entry, const SecurityEntryKeys_t* entryKeys ) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(db_entry); + if (!cb) { + return; + } - if (cb) { - if (entryKeys) { - _pal.set_ltk( - cb->connection, - entryKeys->ltk, - cb->ltk_mitm_protected, - cb->secure_connections_paired - ); - } else { - _pal.set_ltk_not_found(cb->connection); - } + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { + return; + } + + if (entryKeys) { + _pal.set_ltk( + cb->connection, + entryKeys->ltk, + flags->ltk_mitm_protected, + flags->secure_connections_paired + ); + } else { + _pal.set_ltk_not_found(cb->connection); } } void GenericSecurityManager::set_peer_csrk_cb( - pal::SecurityDb::entry_handle_t db_entry, - const csrk_t *csrk, - sign_count_t sign_counter + SecurityDb::entry_handle_t db_entry, + const SecurityEntrySigning_t* signing ) { ControlBlock_t *cb = get_control_block(db_entry); - if (!cb) { + if (!cb || !signing) { + return; + } + + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { return; } _pal.set_peer_csrk( cb->connection, - *csrk, - cb->csrk_mitm_protected, - sign_counter + signing->csrk, + flags->csrk_mitm_protected, + signing->counter ); } void GenericSecurityManager::return_csrk_cb( - pal::SecurityDb::entry_handle_t db_entry, - const csrk_t *csrk, - sign_count_t sign_counter + SecurityDb::entry_handle_t db_entry, + const SecurityEntrySigning_t *signing ) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(db_entry); - if (!cb) { + if (!cb || !signing) { + return; + } + + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { return; } eventHandler->signingKey( cb->connection, - csrk, - cb->csrk_mitm_protected + &signing->csrk, + flags->csrk_mitm_protected ); } void GenericSecurityManager::update_oob_presence(connection_handle_t connection) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (!cb) { return; } + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { + return; + } + /* if we support secure connection we only care about secure connections oob data */ if (_default_authentication.get_secure_connections()) { - cb->oob_present = (cb->peer_address == _oob_peer_address); + cb->oob_present = (flags->peer_address == _oob_peer_address); } else { /* otherwise for legacy pairing we first set the oob based on set preference */ cb->oob_present = cb->attempt_oob; /* and also turn it on if we have oob data for legacy pairing */ - if (cb->peer_address == _oob_temporary_key_creator_address + if (flags->peer_address == _oob_temporary_key_creator_address || cb->local_address == _oob_temporary_key_creator_address) { cb->oob_present = true; } @@ -867,34 +970,30 @@ void GenericSecurityManager::on_connected( const BLEProtocol::AddressBytes_t local_address, const Gap::ConnectionParams_t *connection_params ) { + MBED_ASSERT(_db); ControlBlock_t *cb = acquire_control_block(connection); if (!cb) { return; } // setup the control block - cb->peer_address = peer_address; cb->local_address = local_address; - cb->peer_address_is_public = - (peer_address_type == BLEProtocol::AddressType::PUBLIC); cb->is_master = (role == Gap::CENTRAL); // get the associated db handle and the distribution flags if any - cb->db_entry = _db.open_entry(peer_address_type, peer_address); + cb->db_entry = _db->open_entry(peer_address_type, peer_address); - const pal::SecurityDistributionFlags_t* dist_flags = - _db.get_distribution_flags(cb->db_entry); + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); - if (dist_flags) { - *static_cast(cb) = *dist_flags; - } + flags->peer_address = peer_address; + flags->peer_address_is_public = (peer_address_type == BLEProtocol::AddressType::PUBLIC); const bool signing = cb->signing_override_default ? cb->signing_requested : _default_key_distribution.get_signing(); - if (signing && cb->csrk_stored) { - _db.get_entry_peer_csrk( + if (signing && flags->csrk_stored) { + _db->get_entry_peer_csrk( mbed::callback(this, &GenericSecurityManager::set_peer_csrk_cb), cb->db_entry ); @@ -905,6 +1004,7 @@ void GenericSecurityManager::on_disconnected( connection_handle_t connection, Gap::DisconnectionReason_t reason ) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (!cb) { return; @@ -912,15 +1012,13 @@ void GenericSecurityManager::on_disconnected( _pal.remove_peer_csrk(connection); - _db.close_entry(cb->db_entry); + _db->close_entry(cb->db_entry); release_control_block(cb); - - _db.sync(); } void GenericSecurityManager::on_security_entry_retrieved( - pal::SecurityDb::entry_handle_t entry, - const pal::SecurityEntryIdentity_t* identity + SecurityDb::entry_handle_t entry, + const SecurityEntryIdentity_t* identity ) { if (!identity) { return; @@ -938,7 +1036,7 @@ void GenericSecurityManager::on_security_entry_retrieved( } void GenericSecurityManager::on_identity_list_retrieved( - ble::ArrayView& identity_list, + ble::ArrayView& identity_list, size_t count ) { typedef advertising_peer_address_type_t address_type_t; @@ -946,11 +1044,11 @@ void GenericSecurityManager::on_identity_list_retrieved( _pal.clear_resolving_list(); for (size_t i = 0; i < count; ++i) { _pal.add_device_to_resolving_list( - identity_list[i]->identity_address_is_public ? + identity_list[i].identity_address_is_public ? address_type_t::PUBLIC_ADDRESS : address_type_t::RANDOM_ADDRESS, - identity_list[i]->identity_address, - identity_list[i]->irk + identity_list[i].identity_address, + identity_list[i].irk ); } @@ -1025,11 +1123,10 @@ void GenericSecurityManager::on_pairing_timed_out(connection_handle_t connection } void GenericSecurityManager::on_pairing_completed(connection_handle_t connection) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (cb) { - // set the distribution flags in the db - _db.set_distribution_flags(cb->db_entry, *cb); - _db.get_entry_identity( + _db->get_entry_identity( mbed::callback(this, &GenericSecurityManager::on_security_entry_retrieved), cb->db_entry ); @@ -1053,11 +1150,12 @@ void GenericSecurityManager::on_signed_write_received( connection_handle_t connection, sign_count_t sign_counter ) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (!cb) { return; } - _db.set_entry_peer_sign_counter(cb->db_entry, sign_counter); + _db->set_entry_peer_sign_counter(cb->db_entry, sign_counter); } void GenericSecurityManager::on_signed_write_verification_failure( @@ -1086,26 +1184,33 @@ void GenericSecurityManager::on_signed_write_verification_failure( } void GenericSecurityManager::on_signed_write() { - _db.set_local_sign_counter(_db.get_local_sign_counter() + 1); + MBED_ASSERT(_db); + _db->set_local_sign_counter(_db->get_local_sign_counter() + 1); } void GenericSecurityManager::on_slave_security_request( connection_handle_t connection, AuthenticationMask authentication ) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (!cb) { return; } + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { + return; + } + bool pairing_required = false; - if (authentication.get_secure_connections() && !cb->secure_connections_paired + if (authentication.get_secure_connections() && !flags->secure_connections_paired && _default_authentication.get_secure_connections()) { pairing_required = true; } - if (authentication.get_mitm() && !cb->ltk_mitm_protected) { + if (authentication.get_mitm() && !flags->ltk_mitm_protected) { pairing_required = true; cb->mitm_requested = true; } @@ -1210,7 +1315,12 @@ void GenericSecurityManager::on_secure_connections_oob_request(connection_handle return; } - if (cb->peer_address == _oob_peer_address) { + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { + return; + } + + if (flags->peer_address == _oob_peer_address) { _pal.secure_connections_oob_request_reply(connection, _oob_local_random, _oob_peer_random, _oob_peer_confirm); /* do not re-use peer OOB */ set_all_zeros(_oob_peer_address); @@ -1220,19 +1330,25 @@ void GenericSecurityManager::on_secure_connections_oob_request(connection_handle } void GenericSecurityManager::on_legacy_pairing_oob_request(connection_handle_t connection) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (!cb) { return; } - if (cb->peer_address == _oob_temporary_key_creator_address + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { + return; + } + + if (flags->peer_address == _oob_temporary_key_creator_address || cb->local_address == _oob_temporary_key_creator_address) { set_mitm_performed(connection); _pal.legacy_pairing_oob_request_reply(connection, _oob_temporary_key); /* do not re-use peer OOB */ - if (cb->peer_address == _oob_temporary_key_creator_address) { + if (flags->peer_address == _oob_temporary_key_creator_address) { set_all_zeros(_oob_temporary_key_creator_address); } @@ -1260,29 +1376,41 @@ void GenericSecurityManager::on_secure_connections_ltk_generated( connection_handle_t connection, const ltk_t <k ) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (!cb) { return; } - cb->ltk_mitm_protected = cb->mitm_performed; - cb->secure_connections_paired = true; - cb->ltk_stored = true; + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { + return; + } - _db.set_entry_peer_ltk(cb->db_entry, ltk); + flags->ltk_mitm_protected = cb->mitm_performed; + flags->secure_connections_paired = true; + + _db->set_entry_peer_ltk(cb->db_entry, ltk); } void GenericSecurityManager::on_keys_distributed_ltk( connection_handle_t connection, const ltk_t <k ) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (!cb) { return; } - cb->ltk_mitm_protected = cb->mitm_performed; - cb->ltk_stored = true; - _db.set_entry_peer_ltk(cb->db_entry, ltk); + + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { + return; + } + + flags->ltk_mitm_protected = cb->mitm_performed; + + _db->set_entry_peer_ltk(cb->db_entry, ltk); } void GenericSecurityManager::on_keys_distributed_ediv_rand( @@ -1290,24 +1418,31 @@ void GenericSecurityManager::on_keys_distributed_ediv_rand( const ediv_t &ediv, const rand_t &rand ) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (!cb) { return; } - _db.set_entry_peer_ediv_rand(cb->db_entry, ediv, rand); + _db->set_entry_peer_ediv_rand(cb->db_entry, ediv, rand); } void GenericSecurityManager::on_keys_distributed_local_ltk( connection_handle_t connection, const ltk_t <k ) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (!cb) { return; } - _db.set_entry_local_ltk(cb->db_entry, ltk); + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { + return; + } + + _db->set_entry_local_ltk(cb->db_entry, ltk); } void GenericSecurityManager::on_keys_distributed_local_ediv_rand( @@ -1315,24 +1450,31 @@ void GenericSecurityManager::on_keys_distributed_local_ediv_rand( const ediv_t &ediv, const rand_t &rand ) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (!cb) { return; } - _db.set_entry_local_ediv_rand(cb->db_entry, ediv, rand); + _db->set_entry_local_ediv_rand(cb->db_entry, ediv, rand); } void GenericSecurityManager::on_keys_distributed_irk( connection_handle_t connection, const irk_t &irk ) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (!cb) { return; } - _db.set_entry_peer_irk(cb->db_entry, irk); + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { + return; + } + + _db->set_entry_peer_irk(cb->db_entry, irk); } void GenericSecurityManager::on_keys_distributed_bdaddr( @@ -1340,12 +1482,13 @@ void GenericSecurityManager::on_keys_distributed_bdaddr( advertising_peer_address_type_t peer_address_type, const address_t &peer_identity_address ) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (!cb) { return; } - _db.set_entry_peer_bdaddr( + _db->set_entry_peer_bdaddr( cb->db_entry, (peer_address_type == advertising_peer_address_type_t::PUBLIC_ADDRESS), peer_identity_address @@ -1356,20 +1499,24 @@ void GenericSecurityManager::on_keys_distributed_csrk( connection_handle_t connection, const csrk_t &csrk ) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (!cb) { return; } - cb->csrk_mitm_protected = cb->mitm_performed; - cb->csrk_stored = true; + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { + return; + } - _db.set_entry_peer_csrk(cb->db_entry, csrk); + flags->csrk_mitm_protected = cb->mitm_performed; + _db->set_entry_peer_csrk(cb->db_entry, csrk); eventHandler->signingKey( connection, &csrk, - cb->csrk_mitm_protected + flags->csrk_mitm_protected ); } @@ -1378,23 +1525,30 @@ void GenericSecurityManager::on_ltk_request( const ediv_t &ediv, const rand_t &rand ) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (!cb) { return; } - _db.get_entry_local_keys( - mbed::callback(this, &GenericSecurityManager::set_ltk_cb), - cb->db_entry, - ediv, - rand - ); + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (!flags) { + return; + } + + if (flags->ltk_stored) { + _db->get_entry_local_keys( + mbed::callback(this, &GenericSecurityManager::set_ltk_cb), + cb->db_entry, + ediv, + rand + ); + } } /* control blocks list management */ GenericSecurityManager::ControlBlock_t::ControlBlock_t() : - pal::SecurityDistributionFlags_t(), connection(0), db_entry(0), local_address(), @@ -1416,12 +1570,13 @@ GenericSecurityManager::ControlBlock_t::ControlBlock_t() : void GenericSecurityManager::on_ltk_request(connection_handle_t connection) { + MBED_ASSERT(_db); ControlBlock_t *cb = get_control_block(connection); if (!cb) { return; } - _db.get_entry_local_keys( + _db->get_entry_local_keys( mbed::callback(this, &GenericSecurityManager::set_ltk_cb), cb->db_entry ); @@ -1459,18 +1614,21 @@ GenericSecurityManager::ControlBlock_t* GenericSecurityManager::get_control_bloc GenericSecurityManager::ControlBlock_t* GenericSecurityManager::get_control_block( const address_t &peer_address ) { + MBED_ASSERT(_db); for (size_t i = 0; i < MAX_CONTROL_BLOCKS; i++) { - if (!_control_blocks[i].connected) { - continue; - } else if (peer_address == _control_blocks[i].peer_address) { - return &_control_blocks[i]; + ControlBlock_t *cb = &_control_blocks[i]; + if (cb->connected) { + SecurityDistributionFlags_t* flags = _db->get_distribution_flags(cb->db_entry); + if (flags && (flags->peer_address == peer_address)) { + return cb; + } } } return NULL; } GenericSecurityManager::ControlBlock_t* GenericSecurityManager::get_control_block( - pal::SecurityDb::entry_handle_t db_entry + SecurityDb::entry_handle_t db_entry ) { for (size_t i = 0; i < MAX_CONTROL_BLOCKS; i++) { if (!_control_blocks[i].connected) { diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioBLE.h b/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioBLE.h index 2d56c98f3e..e4eeafba1d 100644 --- a/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioBLE.h +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioBLE.h @@ -30,7 +30,6 @@ #include "CordioPalGenericAccessService.h" #include "ble/generic/GenericGap.h" #include "ble/generic/GenericSecurityManager.h" -#include "ble/pal/MemorySecurityDb.h" #include "ble/pal/SimpleEventQueue.h" namespace ble { diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioBLE.cpp b/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioBLE.cpp index 10bd791c84..85c46aaa57 100644 --- a/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioBLE.cpp +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioBLE.cpp @@ -204,11 +204,9 @@ generic::GenericGattClient& BLE::getGattClient() SecurityManager& BLE::getSecurityManager() { - static pal::MemorySecurityDb m_db; static SigningEventMonitorProxy signing_event_monitor(*this); static generic::GenericSecurityManager m_instance( pal::vendor::cordio::CordioSecurityManager::get_security_manager(), - m_db, getGap(), signing_event_monitor ); diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/nRF5xn.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/nRF5xn.cpp index e79e962ba0..0b2eda1f80 100644 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/nRF5xn.cpp +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/nRF5xn.cpp @@ -208,7 +208,6 @@ SecurityManager& nRF5xn::getSecurityManager() const SecurityManager& nRF5xn::getSecurityManager() const { - static ble::pal::MemorySecurityDb m_db; ble::pal::vendor::nordic::nRF5xSecurityManager &m_pal = ble::pal::vendor::nordic::nRF5xSecurityManager::get_security_manager(); static struct : ble::pal::SigningEventMonitor { @@ -217,7 +216,6 @@ const SecurityManager& nRF5xn::getSecurityManager() const static ble::generic::GenericSecurityManager m_instance( m_pal, - m_db, const_cast(getGap()), dummy_signing_event_monitor ); diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/nRF5xn.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/nRF5xn.h index dfaf59cc26..8829d72347 100644 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/nRF5xn.h +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5/source/nRF5xn.h @@ -22,7 +22,6 @@ #include "ble/BLEInstanceBase.h" #include "ble/generic/GenericGattClient.h" #include "ble/generic/GenericSecurityManager.h" -#include "ble/pal/MemorySecurityDb.h" #include "ble/pal/SimpleEventQueue.h" #include "nRF5xPalSecurityManager.h" diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/source/nRF5xn.cpp b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/source/nRF5xn.cpp index c9225df634..e8e463a0c5 100644 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/source/nRF5xn.cpp +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/source/nRF5xn.cpp @@ -214,7 +214,6 @@ SecurityManager& nRF5xn::getSecurityManager() const SecurityManager& nRF5xn::getSecurityManager() const { - static ble::pal::MemorySecurityDb m_db; ble::pal::vendor::nordic::nRF5xSecurityManager &m_pal = ble::pal::vendor::nordic::nRF5xSecurityManager::get_security_manager(); static struct : ble::pal::SigningEventMonitor { @@ -223,7 +222,6 @@ const SecurityManager& nRF5xn::getSecurityManager() const static ble::generic::GenericSecurityManager m_instance( m_pal, - m_db, const_cast(getGap()), dummy_signing_event_monitor ); diff --git a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/source/nRF5xn.h b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/source/nRF5xn.h index b78c77a9f0..38ee87ec8e 100644 --- a/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/source/nRF5xn.h +++ b/features/FEATURE_BLE/targets/TARGET_NORDIC/TARGET_NRF5x/source/nRF5xn.h @@ -22,7 +22,6 @@ #include "ble/BLEInstanceBase.h" #include "ble/generic/GenericGattClient.h" #include "ble/generic/GenericSecurityManager.h" -#include "ble/pal/MemorySecurityDb.h" #include "ble/pal/SimpleEventQueue.h" #include "nRF5xPalSecurityManager.h"