Merge pull request #17 from pan-/security-db-rework

Security db rework
pull/6188/head
Paul Szczepanek 2018-02-23 13:24:15 +00:00 committed by GitHub
commit 268655a028
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 827 additions and 706 deletions

View File

@ -435,7 +435,7 @@ public:
* @param[in] connectionHandle Handle to identify the connection.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t canceltPairingRequest(connection_handle_t connectionHandle) {
virtual ble_error_t cancelPairingRequest(connection_handle_t connectionHandle) {
(void) connectionHandle;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */
}
@ -447,7 +447,7 @@ public:
* @param[in] required If set to true, pairingRequest in the event handler will
* will be called and will require an action from the application
* to continue with pairing by calling acceptPairingRequest
* or canceltPairingRequest if the user wishes to reject it.
* or cancelPairingRequest if the user wishes to reject it.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual ble_error_t setPairingRequestAuthorisation(bool required = true) {

View File

@ -41,7 +41,7 @@ class GenericSecurityManager : public SecurityManager,
public pal::SecurityManagerEventHandler,
public pal::ConnectionEventHandler {
public:
typedef ble::pal::SecurityEntry_t SecurityEntry_t;
typedef ble::pal::SecurityDistributionFlags_t SecurityDistributionFlags_t;
typedef ble::pal::SecurityEntryKeys_t SecurityEntryKeys_t;
/* implements SecurityManager */
@ -86,7 +86,7 @@ public:
connection_handle_t connection
);
virtual ble_error_t canceltPairingRequest(
virtual ble_error_t cancelPairingRequest(
connection_handle_t connection
);
@ -302,7 +302,7 @@ private:
* @param[in] entryKeys security entry containing keys.
*/
void enable_encryption_cb(
const SecurityEntry_t* entry,
pal::SecurityDb::entry_handle_t entry,
const SecurityEntryKeys_t* entryKeys
);
@ -313,7 +313,7 @@ private:
* @param[in] entryKeys security entry containing keys.
*/
void set_ltk_cb(
const SecurityEntry_t* entry,
pal::SecurityDb::entry_handle_t entry,
const SecurityEntryKeys_t* entryKeys
);
@ -324,7 +324,7 @@ private:
* @param[in] entryKeys security entry containing keys.
*/
void return_csrk_cb(
connection_handle_t connection,
pal::SecurityDb::entry_handle_t connection,
const csrk_t *csrk
);
@ -431,6 +431,31 @@ private:
);
private:
struct ControlBlock_t : public pal::SecurityDistributionFlags_t {
ControlBlock_t();
connection_handle_t connection;
pal::SecurityDb::entry_handle_t db_entry;
address_t local_address; /**< address used for connection, possibly different from identity */
uint8_t connected:1;
uint8_t authenticated:1; /**< have we turned encryption on during this connection */
uint8_t is_master:1;
uint8_t encryption_requested:1;
uint8_t encryption_failed:1;
uint8_t encrypted:1;
uint8_t signing_requested:1;
uint8_t mitm_requested:1;
uint8_t mitm_performed:1; /**< keys exchange will have MITM protection */
uint8_t attempt_oob:1;
uint8_t oob_mitm_protection:1;
uint8_t oob_present:1;
};
pal::SecurityManager &_pal;
pal::SecurityDb &_db;
pal::ConnectionEventMonitor &_connection_monitor;
@ -443,6 +468,14 @@ private:
bool _master_sends_keys;
bool _public_keys_generated;
/** There is always only one OOB data set stored at a time (for now) */
address_t _peer_sc_oob_address;
oob_rand_t _peer_sc_oob_random;
oob_confirm_t _peer_sc_oob_confirm;
oob_rand_t _local_sc_oob_random;
static const size_t MAX_CONTROL_BLOCKS = 5;
ControlBlock_t _control_blocks[MAX_CONTROL_BLOCKS];
/* implements ble::pal::SecurityManagerEventHandler */
public:
@ -642,6 +675,18 @@ public:
);
/* end implements ble::pal::SecurityManagerEventHandler */
/* list management */
ControlBlock_t* acquire_control_block(connection_handle_t connection);
ControlBlock_t* get_control_block(connection_handle_t connection);
ControlBlock_t* get_control_block(const address_t &peer_address);
ControlBlock_t* get_control_block(pal::SecurityDb::entry_handle_t db_entry);
void release_control_block(ControlBlock_t* entry);
};

View File

@ -17,17 +17,9 @@
#ifndef MBED_BLE_CONNECTION_EVENT_MONITOR
#define MBED_BLE_CONNECTION_EVENT_MONITOR
#include <algorithm>
#include "ble/BLE.h"
#include "ble/BLEProtocol.h"
#include "ble/Gap.h"
#include "ble/pal/PalGap.h"
#include "ble/pal/GapEvents.h"
#include "ble/pal/GapTypes.h"
#include "ble/BLETypes.h"
#include "ble/pal/GenericAccessService.h"
#include "ble/pal/EventQueue.h"
namespace ble {
namespace pal {

View File

@ -14,11 +14,10 @@
* limitations under the License.
*/
#ifndef PAL_MEMORY_SECURITY_MANAGER_DB_H__
#define PAL_MEMORY_SECURITY_MANAGER_DB_H__
#ifndef PAL_MEMORY_SECURITY_MANAGER_entries_H__
#define PAL_MEMORY_SECURITY_MANAGER_entries_H__
#include "SecurityDB.h"
#include "Gap.h"
namespace ble {
namespace pal {
@ -27,42 +26,57 @@ namespace pal {
* TODO: make thread safe */
class MemorySecurityDb : public SecurityDb {
private:
struct db_store_t {
db_store_t() { };
SecurityEntry_t entry;
enum state_t {
ENTRY_FREE,
ENTRY_RESERVED,
ENTRY_WRITTEN
};
struct entry_t {
entry_t() : state(ENTRY_FREE) { };
SecurityDistributionFlags_t flags;
SecurityEntryKeys_t peer_keys;
SecurityEntryKeys_t local_keys;
SecurityEntryIdentity_t peer_identity;
csrk_t csrk;
state_t state;
};
static const size_t MAX_ENTRIES = 5;
static entry_t* as_entry(entry_handle_t entry_handle)
{
return reinterpret_cast<entry_t*>(entry_handle);
}
public:
MemorySecurityDb() { };
virtual ~MemorySecurityDb() { };
virtual SecurityEntry_t* get_entry(
connection_handle_t connection
virtual const SecurityDistributionFlags_t* get_distribution_flags(
entry_handle_t entry_handle
) {
SecurityEntry_t *entry = NULL;
db_store_t *store = get_store(connection);
if (store) {
entry = &store->entry;
}
return entry;
entry_t* entry = as_entry(entry_handle);
if (!entry) {
return NULL;
}
virtual SecurityEntry_t* get_entry(
const address_t &peer_address
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
) {
SecurityEntry_t *entry = NULL;
for (size_t i = 0; i < MAX_ENTRIES; i++) {
if (!_db[i].entry.connected) {
continue;
} else if (peer_address == _db[i].entry.peer_address) {
entry = &_db[i].entry;
entry_t* entry = as_entry(entry_handle);
if (!entry) {
return;
}
}
return entry;
entry->state = ENTRY_WRITTEN;
entry->flags = flags;
}
/* local keys */
@ -70,64 +84,63 @@ public:
/* get */
virtual void get_entry_local_keys(
SecurityEntryKeysDbCb_t cb,
connection_handle_t connection,
entry_handle_t entry_handle,
const ediv_t &ediv,
const rand_t &rand
) {
SecurityEntry_t *entry = NULL;
db_store_t *store = get_store(connection);
if (store) {
entry = &store->entry;
entry_t* entry = as_entry(entry_handle);
if (!entry) {
return;
}
/* validate we have the correct key */
if (ediv == store->local_keys.ediv
&& rand == store->local_keys.rand) {
cb(entry, &store->local_keys);
if (ediv == entry->local_keys.ediv && rand == entry->local_keys.rand) {
cb(entry_handle, &entry->local_keys);
} else {
cb(entry, NULL);
cb(entry_handle, NULL);
}
}
virtual void get_entry_local_keys(
SecurityEntryKeysDbCb_t cb,
connection_handle_t connection
entry_handle_t entry_handle
) {
SecurityEntry_t *entry = NULL;
db_store_t *store = get_store(connection);
if (store) {
entry = &store->entry;
entry_t* entry = as_entry(entry_handle);
if (!entry) {
return;
}
/* validate we have the correct key */
if (entry->secure_connections_paired) {
cb(entry, &store->local_keys);
if (entry->flags.secure_connections_paired) {
cb(entry_handle, &entry->local_keys);
} else {
cb(entry, NULL);
cb(entry_handle, NULL);
}
}
/* set */
virtual void set_entry_local_ltk(
connection_handle_t connection,
entry_handle_t entry_handle,
const ltk_t &ltk
) {
db_store_t *store = get_store(connection);
if (store) {
store->local_keys.ltk = ltk;
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(
connection_handle_t connection,
entry_handle_t entry_handle,
const ediv_t &ediv,
const rand_t &rand
) {
db_store_t *store = get_store(connection);
if (store) {
store->local_keys.ediv = ediv;
store->local_keys.rand = rand;
entry_t *entry = as_entry(entry_handle);
if (entry) {
entry->state = ENTRY_WRITTEN;
entry->local_keys.ediv = ediv;
entry->local_keys.rand = rand;
}
}
@ -136,86 +149,85 @@ public:
/* get */
virtual void get_entry_peer_csrk(
SecurityEntryCsrkDbCb_t cb,
connection_handle_t connection
entry_handle_t entry_handle
) {
SecurityEntry_t *entry = NULL;
csrk_t csrk;
db_store_t *store = get_store(connection);
if (store) {
entry = &store->entry;
csrk = store->csrk;
entry_t *entry = as_entry(entry_handle);
if (entry) {
csrk = entry->csrk;
}
cb(entry->handle, &csrk);
cb(entry_handle, &csrk);
}
virtual void get_entry_peer_keys(
SecurityEntryKeysDbCb_t cb,
connection_handle_t connection
entry_handle_t entry_handle
) {
SecurityEntry_t *entry = NULL;
SecurityEntryKeys_t *key = NULL;
db_store_t *store = get_store(connection);
if (store) {
entry = &store->entry;
key = &store->peer_keys;
entry_t *entry = as_entry(entry_handle);
if (entry) {
key = &entry->peer_keys;
}
cb(entry, key);
cb(entry_handle, key);
}
/* set */
virtual void set_entry_peer_ltk(
connection_handle_t connection,
entry_handle_t entry_handle,
const ltk_t &ltk
) {
db_store_t *store = get_store(connection);
if (store) {
store->peer_keys.ltk = ltk;
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(
connection_handle_t connection,
entry_handle_t entry_handle,
const ediv_t &ediv,
const rand_t &rand
) {
db_store_t *store = get_store(connection);
if (store) {
store->peer_keys.ediv = ediv;
store->peer_keys.rand = 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(
connection_handle_t connection,
entry_handle_t entry_handle,
const irk_t &irk
) {
db_store_t *store = get_store(connection);
if (store) {
size_t index = store - _db;
_identities[index].irk = irk;
entry_t *entry = as_entry(entry_handle);
if (entry) {
entry->state = ENTRY_WRITTEN;
entry->peer_identity.irk = irk;
}
}
virtual void set_entry_peer_bdaddr(
connection_handle_t connection,
entry_handle_t entry_handle,
bool address_is_public,
const address_t &peer_address
) {
db_store_t *store = get_store(connection);
if (store) {
size_t index = store - _db;
_identities[index].identity_address = peer_address;
entry_t *entry = as_entry(entry_handle);
if (entry) {
entry->state = ENTRY_WRITTEN;
entry->peer_identity.identity_address = peer_address;
}
}
virtual void set_entry_peer_csrk(
connection_handle_t connection,
entry_handle_t entry_handle,
const csrk_t &csrk
) {
db_store_t *store = get_store(connection);
if (store) {
store->csrk = csrk;
entry_t *entry = as_entry(entry_handle);
if (entry) {
entry->state = ENTRY_WRITTEN;
entry->csrk = csrk;
}
}
@ -247,96 +259,62 @@ public:
_public_key_y = public_key_y;
}
/* oob data */
/** There is always only one OOB data set stored at a time */
virtual const address_t& get_peer_sc_oob_address() {
return _peer_sc_oob_address;
}
virtual const oob_rand_t& get_peer_sc_oob_random() {
return _peer_sc_oob_random;
}
virtual const oob_confirm_t& get_peer_sc_oob_confirm() {
return _peer_sc_oob_confirm;
}
virtual void get_sc_oob_data(
address_t &peer_address,
oob_rand_t &peer_random,
oob_confirm_t &peer_confirm,
oob_rand_t &local_random
) {
peer_address = _peer_sc_oob_address;
peer_random = _peer_sc_oob_random;
peer_confirm = _peer_sc_oob_confirm;
local_random = _local_sc_oob_random;
}
virtual const oob_rand_t& get_local_sc_oob_random() {
return _local_sc_oob_random;
}
virtual void set_peer_sc_oob_data(
const address_t &address,
const oob_rand_t &random,
const oob_confirm_t &confirm
) {
_peer_sc_oob_address = address;
_peer_sc_oob_random = random;
_peer_sc_oob_confirm = confirm;
}
virtual void set_local_sc_oob_random(
const oob_rand_t &random
) {
_local_sc_oob_random = random;
}
/* list management */
virtual SecurityEntry_t* connect_entry(
connection_handle_t connection,
virtual entry_handle_t open_entry(
BLEProtocol::AddressType_t peer_address_type,
const address_t &peer_address,
const address_t &local_address
const address_t &peer_address
) {
const bool peer_address_public =
(peer_address_type == BLEProtocol::AddressType::PUBLIC);
for (size_t i = 0; i < MAX_ENTRIES; i++) {
if (_db[i].entry.connected) {
if (_entries[i].state == ENTRY_FREE) {
continue;
} else if (peer_address == _identities[i].identity_address
&& _db[i].entry.peer_address_is_public == peer_address_public) {
return &_db[i].entry;
} else if (peer_address == _entries[i].peer_identity.identity_address
&& _entries[i].flags.peer_address_is_public == peer_address_public) {
return &_entries[i];
}
}
/* if we din't find one grab the first disconnected slot*/
for (size_t i = 0; i < MAX_ENTRIES; i++) {
if (!_db[i].entry.connected) {
_db[i] = db_store_t();
_identities[i] = SecurityEntryIdentity_t();
_db[i].entry.peer_address = peer_address;
_db[i].entry.local_address = local_address;
_db[i].entry.peer_address_is_public = peer_address_public;
return &_db[i].entry;
if (_entries[i].state == ENTRY_FREE) {
_entries[i] = entry_t();
_entries[i].flags.peer_address = peer_address;
_entries[i].flags.peer_address_is_public = peer_address_public;
_entries[i].state = ENTRY_RESERVED;
return &_entries[i];
}
}
return NULL;
}
virtual void disconnect_entry(connection_handle_t connection) { }
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(address_t peer_identity_address) { }
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++) {
_db[i] = db_store_t();
_entries[i] = entry_t();
}
_local_identity = SecurityEntryIdentity_t();
_local_csrk = csrk_t();
@ -349,7 +327,7 @@ public:
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 (_db[i].entry.peer_address_is_public) {
if (_entries[i].flags.peer_address_is_public) {
whitelist->addresses[i].type = BLEProtocol::AddressType::PUBLIC;
} else {
whitelist->addresses[i].type = BLEProtocol::AddressType::RANDOM_STATIC;
@ -357,7 +335,7 @@ public:
memcpy(
whitelist->addresses[i].address,
_identities[i].identity_address.data(),
_entries[i].peer_identity.identity_address.data(),
sizeof(BLEProtocol::AddressBytes_t)
);
}
@ -365,8 +343,6 @@ public:
cb(whitelist);
}
virtual void update_whitelist(::Gap::Whitelist_t &whitelist) { }
virtual void set_whitelist(const ::Gap::Whitelist_t &whitelist) { };
virtual void add_whitelist_entry(const address_t &address) { }
@ -384,32 +360,14 @@ public:
virtual void set_restore(bool reload) { }
private:
virtual db_store_t* get_store(connection_handle_t connection) {
for (size_t i = 0; i < MAX_ENTRIES; i++) {
if (!_db[i].entry.connected) {
continue;
} else if (connection == _db[i].entry.handle) {
return &_db[i];
}
}
return NULL;
}
db_store_t _db[MAX_ENTRIES];
SecurityEntryIdentity_t _identities[MAX_ENTRIES];
entry_t _entries[MAX_ENTRIES];
SecurityEntryIdentity_t _local_identity;
csrk_t _local_csrk;
public_key_t _public_key_x;
public_key_t _public_key_y;
address_t _peer_sc_oob_address;
oob_rand_t _peer_sc_oob_random;
oob_confirm_t _peer_sc_oob_confirm;
oob_rand_t _local_sc_oob_random;
};
} /* namespace pal */
} /* namespace ble */
#endif /*PAL_MEMORY_SECURITY_MANAGER_DB_H__*/
#endif /*PAL_MEMORY_SECURITY_MANAGER_entries_H__*/

View File

@ -26,13 +26,10 @@
namespace ble {
namespace pal {
/* separate structs for keys to allow db implementation
* to minimise memory usage, only holding live connection
* state in memory */
struct SecurityEntry_t {
SecurityEntry_t()
: handle(0),
struct SecurityDistributionFlags_t {
SecurityDistributionFlags_t() :
peer_address(),
encryption_key_size(0),
peer_address_is_public(false),
local_address_is_public(false),
@ -40,44 +37,9 @@ struct SecurityEntry_t {
csrk_mitm_protected(false),
ltk_stored(false),
ltk_mitm_protected(false),
secure_connections_paired(false),
connected(false),
authenticated(false),
is_master(false),
encryption_requested(false),
encryption_failed(false),
encrypted(false),
signing_requested(false),
mitm_requested(false),
mitm_performed(false),
attempt_oob(false),
oob_mitm_protection(false),
oob_present(false) { }
/**
* Reset state of the connection when disconnected.
*/
void reset() {
local_address = address_t();
connected = false;
authenticated = false;
is_master = false;
encryption_requested = false;
encryption_failed = false;
encrypted = false;
signing_requested = false;
mitm_requested = false;
mitm_performed = false;
attempt_oob = false;
oob_mitm_protection = false;
oob_present = false;
secure_connections_paired(false) {
}
connection_handle_t handle;
address_t peer_address;
uint8_t encryption_key_size;
@ -89,26 +51,6 @@ struct SecurityEntry_t {
uint8_t ltk_stored:1;
uint8_t ltk_mitm_protected:1;
uint8_t secure_connections_paired:1;
/* do not store in NVM */
address_t local_address; /**< address used for connection, possibly different from identity */
uint8_t connected:1;
uint8_t authenticated:1; /**< have we turned encryption on during this connection */
uint8_t is_master:1;
uint8_t encryption_requested:1;
uint8_t encryption_failed:1;
uint8_t encrypted:1;
uint8_t signing_requested:1;
uint8_t mitm_requested:1;
uint8_t mitm_performed:1; /**< keys exchange will have MITM protection */
uint8_t attempt_oob:1;
uint8_t oob_mitm_protection:1;
uint8_t oob_present:1;
};
struct SecurityEntryKeys_t {
@ -122,12 +64,6 @@ struct SecurityEntryIdentity_t {
irk_t irk;
};
/* callbacks for asynchronous data retrieval from the security db */
typedef mbed::Callback<void(const SecurityEntry_t*, const SecurityEntryKeys_t*)> SecurityEntryKeysDbCb_t;
typedef mbed::Callback<void(connection_handle_t, const csrk_t*)> SecurityEntryCsrkDbCb_t;
typedef mbed::Callback<void(::Gap::Whitelist_t*)> WhitelistDbCb_t;
/**
* SecurityDB holds the state for active connections and bonded devices.
* Keys can be stored in NVM and are returned via callbacks.
@ -137,6 +73,20 @@ typedef mbed::Callback<void(::Gap::Whitelist_t*)> WhitelistDbCb_t;
*/
class SecurityDb {
public:
/**
* Opaque type representing an handle to a database entry.
*/
typedef void* entry_handle_t;
/* callbacks for asynchronous data retrieval from the security db */
typedef mbed::Callback<void(entry_handle_t, const SecurityEntryKeys_t*)>
SecurityEntryKeysDbCb_t;
typedef mbed::Callback<void(entry_handle_t, const csrk_t*)>
SecurityEntryCsrkDbCb_t;
typedef mbed::Callback<void(::Gap::Whitelist_t*)>
WhitelistDbCb_t;
SecurityDb() { };
virtual ~SecurityDb() { };
@ -147,19 +97,16 @@ public:
* @param[in] handle valid connection handle
* @return pointer to security entry, NULL if handle was invalid
*/
virtual SecurityEntry_t* get_entry(
connection_handle_t connection
virtual const SecurityDistributionFlags_t* get_distribution_flags(
entry_handle_t db_entry
) = 0;
/**
* Return immediately security entry containing the state
* information for active connection.
*
* @param[in] peer_address peer address in the entry being requested
* @return pointer to security entry, NULL if no entry was fined
* Set the distribution flags of the DB entry
*/
virtual SecurityEntry_t* get_entry(
const address_t &peer_address
virtual void set_distribution_flags(
entry_handle_t db_entry,
const SecurityDistributionFlags_t& flags
) = 0;
/* local keys */
@ -174,7 +121,7 @@ public:
*/
virtual void get_entry_local_keys(
SecurityEntryKeysDbCb_t cb,
connection_handle_t connection,
entry_handle_t db_entry,
const ediv_t &ediv,
const rand_t &rand
) = 0;
@ -187,7 +134,7 @@ public:
*/
virtual void get_entry_local_keys(
SecurityEntryKeysDbCb_t cb,
connection_handle_t connection
entry_handle_t db_entry
) = 0;
/**
@ -198,7 +145,7 @@ public:
* be used when link is encrypted
*/
virtual void set_entry_local_ltk(
connection_handle_t connection,
entry_handle_t db_entry,
const ltk_t &ltk
) = 0;
@ -210,7 +157,7 @@ public:
* @param[in] rand new RAND value
*/
virtual void set_entry_local_ediv_rand(
connection_handle_t connection,
entry_handle_t db_entry,
const ediv_t &ediv,
const rand_t &rand
) = 0;
@ -226,7 +173,7 @@ public:
*/
virtual void get_entry_peer_csrk(
SecurityEntryCsrkDbCb_t cb,
connection_handle_t connection
entry_handle_t db_entry
) = 0;
/**
@ -238,7 +185,7 @@ public:
*/
virtual void get_entry_peer_keys(
SecurityEntryKeysDbCb_t cb,
connection_handle_t connection
entry_handle_t db_entry
) = 0;
/**
@ -249,7 +196,7 @@ public:
* be used when link is encrypted
*/
virtual void set_entry_peer_ltk(
connection_handle_t connection,
entry_handle_t db_entry,
const ltk_t &ltk
) = 0;
@ -261,7 +208,7 @@ public:
* @param[in] rand new RAND value
*/
virtual void set_entry_peer_ediv_rand(
connection_handle_t connection,
entry_handle_t db_entry,
const ediv_t &ediv,
const rand_t &rand
) = 0;
@ -273,7 +220,7 @@ public:
* @param[in] irk new IRK value
*/
virtual void set_entry_peer_irk(
connection_handle_t connection,
entry_handle_t db_entry,
const irk_t &irk
) = 0;
@ -285,7 +232,7 @@ public:
* @param[in] peer_address the new address
*/
virtual void set_entry_peer_bdaddr(
connection_handle_t connection,
entry_handle_t db_entry,
bool address_is_public,
const address_t &peer_address
) = 0;
@ -297,7 +244,7 @@ public:
* @param[in] csrk new CSRK value
*/
virtual void set_entry_peer_csrk(
connection_handle_t connection,
entry_handle_t db_entry,
const csrk_t &csrk
) = 0;
@ -315,9 +262,7 @@ public:
*
* @param[in] csrk new CSRK value
*/
virtual void set_local_csrk(
const csrk_t &csrk
) = 0;
virtual void set_local_csrk(const csrk_t &csrk) = 0;
/* public keys */
@ -346,118 +291,38 @@ public:
const public_key_t &public_key_y
) = 0;
/* oob data */
/** There is always only one OOB data set stored at a time */
/**
* Return peer address the OOB data belongs to.
*
* @return peer address
*/
virtual const address_t& get_peer_sc_oob_address() = 0;
/**
* Return random number from the peer received in OOB data.
*
* @return random number the peer chose
*/
virtual const oob_rand_t& get_peer_sc_oob_random() = 0;
/**
* Return confirm number from the peer received in OOB data.
*
* @return confirm value calculated by peer based
* on the random number, its public key and address
*/
virtual const oob_confirm_t& get_peer_sc_oob_confirm() = 0;
/**
* Return OOB data in a single transaction.
*
* @param[out] peer_address peer address OOB data belongs to
* @param[out] peer_random random number the peer chose
* @param[out] peer_confirm confirm value calculated by peer based
* on the random number, its public key and address
* @param[out] local_random random number chosen by the local device
*/
virtual void get_sc_oob_data(
address_t &peer_address,
oob_rand_t &peer_random,
oob_confirm_t &peer_confirm,
oob_rand_t &local_random
) = 0;
/**
* Return random number used by the local device to calculate
* the confirm value sent the peer in OOB data.
*
* @return random number chosen by local device
*/
virtual const oob_rand_t& get_local_sc_oob_random() = 0;
/**
* Store the OOB data received from the peer.
*
* @param address peer address OOB data belongs to
* @param random random number the peer chose
* @param confirm confirm value calculated by peer based
* on the random number, its public key and address
*/
virtual void set_peer_sc_oob_data(
const address_t &address,
const oob_rand_t &random,
const oob_confirm_t &confirm
) = 0;
/**
* Set random number used for OOB data calculation on the local device.
*
* @param random random number chosen by the local device
*/
virtual void set_local_sc_oob_random(
const oob_rand_t &random
) = 0;
/* list management */
/**
* Create a new entry or retrieve existing stored entry
* and put it in the live connections store to be retrieved
* synchronously through connection handle.
* Open a database entry.
*
* While this entry is opened; it can be queried and modified with the help
* of the database setter and getter functions.
*
* @param[in] connection this will be the index for live entries.
* @param[in] peer_address_type type of address
* @param[in] peer_address this address will be used to locate existing entry.
* @param[in] peer_address this address will be used to locate an existing
* entry.
*
* @return pointer to entry newly created or located existing entry.
* @return An handle to the entry.
*/
virtual SecurityEntry_t* connect_entry(
connection_handle_t connection,
virtual entry_handle_t open_entry(
BLEProtocol::AddressType_t peer_address_type,
const address_t &peer_address,
const address_t &local_address
const address_t &peer_address
) = 0;
/**
* Create a new entry or retrieve existing stored entry
* and put it in the live connections store to be retrieved
* synchronously through connection handle.
* Close a connection entry.
*
* @param[in] connection this handle will be freed up from the security db
* @param[in] entry this handle will be freed up from the security db.
*/
virtual void disconnect_entry(
connection_handle_t connection
) = 0;
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;
virtual void remove_entry(const address_t peer_identity_address) = 0;
/**
* Remove all entries from the security DB.
@ -495,27 +360,21 @@ public:
*
* @param[in] whitelist
*/
virtual void set_whitelist(
const ::Gap::Whitelist_t &whitelist
) = 0;
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;
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;
virtual void remove_whitelist_entry(const address_t &address) = 0;
/**
*Remove all whitelist entries stored in the NVM.

View File

@ -100,8 +100,8 @@ ble_error_t GenericSecurityManager::generateWhitelistFromBondTable(Gap::Whitelis
//
ble_error_t GenericSecurityManager::requestPairing(connection_handle_t connection) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return BLE_ERROR_INVALID_PARAM;
}
@ -113,15 +113,15 @@ ble_error_t GenericSecurityManager::requestPairing(connection_handle_t connectio
update_oob_presence(connection);
AuthenticationMask link_authentication(_default_authentication);
link_authentication.set_mitm(entry->mitm_requested);
link_authentication.set_mitm(cb->mitm_requested);
KeyDistribution link_key_distribution(_default_key_distribution);
link_key_distribution.set_signing(entry->signing_requested);
link_key_distribution.set_signing(cb->signing_requested);
link_key_distribution.set_encryption(_master_sends_keys);
return _pal.send_pairing_request(
connection,
entry->oob_present,
cb->oob_present,
link_authentication,
link_key_distribution,
link_key_distribution
@ -129,29 +129,29 @@ ble_error_t GenericSecurityManager::requestPairing(connection_handle_t connectio
}
ble_error_t GenericSecurityManager::acceptPairingRequest(connection_handle_t connection) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return BLE_ERROR_INVALID_PARAM;
}
update_oob_presence(connection);
AuthenticationMask link_authentication(_default_authentication);
link_authentication.set_mitm(entry->mitm_requested);
link_authentication.set_mitm(cb->mitm_requested);
KeyDistribution link_key_distribution(_default_key_distribution);
link_key_distribution.set_signing(entry->signing_requested);
link_key_distribution.set_signing(cb->signing_requested);
return _pal.send_pairing_response(
connection,
entry->oob_present,
cb->oob_present,
link_authentication,
link_key_distribution,
link_key_distribution
);
}
ble_error_t GenericSecurityManager::canceltPairingRequest(connection_handle_t connection) {
ble_error_t GenericSecurityManager::cancelPairingRequest(connection_handle_t connection) {
return _pal.cancel_pairing(connection, pairing_failure_t::UNSPECIFIED_REASON);
}
@ -206,12 +206,12 @@ ble_error_t GenericSecurityManager::setLinkSecurity(
connection_handle_t connection,
SecurityMode_t securityMode
) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return BLE_ERROR_INVALID_PARAM;
}
if (entry->encryption_requested) {
if (cb->encryption_requested) {
return BLE_ERROR_OPERATION_NOT_PERMITTED;
}
@ -245,19 +245,19 @@ ble_error_t GenericSecurityManager::enableSigning(
connection_handle_t connection,
bool enabled
) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return BLE_ERROR_INVALID_PARAM;
}
entry->signing_requested = enabled;
cb->signing_requested = enabled;
if (entry->encrypted) {
if (cb->encrypted) {
return BLE_ERROR_INVALID_STATE;
}
if (!entry->csrk_stored && entry->signing_requested) {
if (!cb->csrk_stored && cb->signing_requested) {
init_signing();
if (entry->is_master) {
if (cb->is_master) {
return requestPairing(connection);
} else {
return slave_security_request(connection);
@ -281,18 +281,18 @@ ble_error_t GenericSecurityManager::getLinkEncryption(
link_encryption_t *encryption
) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return BLE_ERROR_INVALID_PARAM;
}
if (entry->encrypted) {
if (entry->ltk_mitm_protected || entry->mitm_performed) {
if (cb->encrypted) {
if (cb->ltk_mitm_protected || cb->mitm_performed) {
*encryption = link_encryption_t::ENCRYPTED_WITH_MITM;
} else {
*encryption = link_encryption_t::ENCRYPTED;
}
} else if (entry->encryption_requested) {
} else if (cb->encryption_requested) {
*encryption = link_encryption_t::ENCRYPTION_IN_PROGRESS;
} else {
*encryption = link_encryption_t::NOT_ENCRYPTED;
@ -305,8 +305,8 @@ ble_error_t GenericSecurityManager::setLinkEncryption(
connection_handle_t connection,
link_encryption_t encryption
) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return BLE_ERROR_INVALID_PARAM;
}
@ -324,7 +324,7 @@ ble_error_t GenericSecurityManager::setLinkEncryption(
if (encryption == link_encryption_t::NOT_ENCRYPTED) {
if (entry->encrypted) {
if (cb->encrypted) {
return _pal.disable_encryption(connection);
}
@ -334,16 +334,16 @@ ble_error_t GenericSecurityManager::setLinkEncryption(
if (current_encryption == link_encryption_t::ENCRYPTED_WITH_MITM) {
return BLE_ERROR_NONE;
}
entry->encryption_requested = true;
cb->encryption_requested = true;
return enable_encryption(connection);
} else if (encryption == link_encryption_t::ENCRYPTED_WITH_MITM) {
if (entry->ltk_mitm_protected && !entry->encrypted) {
entry->encryption_requested = true;
if (cb->ltk_mitm_protected && !cb->encrypted) {
cb->encryption_requested = true;
return enable_encryption(connection);
} else {
entry->encryption_requested = true;
cb->encryption_requested = true;
return requestAuthentication(connection);
}
@ -358,9 +358,9 @@ ble_error_t GenericSecurityManager::getEncryptionKeySize(
connection_handle_t connection,
uint8_t *size
) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (entry) {
*size = entry->encryption_key_size;
ControlBlock_t *cb = get_control_block(connection);
if (cb) {
*size = cb->encryption_key_size;
return BLE_ERROR_NONE;
} else {
return BLE_ERROR_INVALID_PARAM;
@ -379,17 +379,17 @@ ble_error_t GenericSecurityManager::setEncryptionKeyRequirements(
//
ble_error_t GenericSecurityManager::getSigningKey(connection_handle_t connection, bool authenticated) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return BLE_ERROR_INVALID_PARAM;
}
if (entry->csrk_stored && (entry->csrk_mitm_protected || !authenticated)) {
if (cb->csrk_stored && (cb->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(
mbed::callback(this, &GenericSecurityManager::return_csrk_cb),
connection
cb->db_entry
);
return BLE_ERROR_NONE;
@ -398,7 +398,7 @@ ble_error_t GenericSecurityManager::getSigningKey(connection_handle_t connection
* keys exchange will create the signingKey event */
if (authenticated) {
return requestAuthentication(connection);
} else if (entry->is_master) {
} else if (cb->is_master) {
return requestPairing(connection);
} else {
return slave_security_request(connection);
@ -419,21 +419,21 @@ ble_error_t GenericSecurityManager::setPrivateAddressTimeout(uint16_t timeout_in
//
ble_error_t GenericSecurityManager::requestAuthentication(connection_handle_t connection) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return BLE_ERROR_INVALID_PARAM;
}
if (entry->ltk_mitm_protected) {
if (entry->authenticated) {
if (cb->ltk_mitm_protected) {
if (cb->authenticated) {
return BLE_ERROR_NONE;
} else {
entry->encryption_requested = true;
cb->encryption_requested = true;
return enable_encryption(connection);
}
} else {
entry->mitm_requested = true;
if (entry->is_master) {
cb->mitm_requested = true;
if (cb->is_master) {
return requestPairing(connection);
} else {
return slave_security_request(connection);
@ -450,13 +450,13 @@ ble_error_t GenericSecurityManager::setOOBDataUsage(
bool useOOB,
bool OOBProvidesMITM
) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return BLE_ERROR_INVALID_PARAM;
}
entry->attempt_oob = useOOB;
entry->oob_mitm_protection = OOBProvidesMITM;
cb->attempt_oob = useOOB;
cb->oob_mitm_protection = OOBProvidesMITM;
#if defined(MBEDTLS_CMAC_C)
if (_public_keys_generated) {
@ -496,12 +496,12 @@ ble_error_t GenericSecurityManager::legacyPairingOobReceived(
const oob_tk_t *tk
) {
if (address && tk) {
SecurityEntry_t *entry = _db.get_entry(*address);
if (!entry) {
ControlBlock_t *cb = get_control_block(*address);
if (!cb) {
return BLE_ERROR_INVALID_PARAM;
}
return _pal.legacy_pairing_oob_data_request_reply(entry->handle, *tk);
return _pal.legacy_pairing_oob_data_request_reply(cb->connection, *tk);
}
return BLE_ERROR_NONE;
}
@ -512,12 +512,9 @@ ble_error_t GenericSecurityManager::oobReceived(
const oob_confirm_t *confirm
) {
if (address && random && confirm) {
_db.set_peer_sc_oob_data(
*address,
*random,
*confirm
);
_peer_sc_oob_address = *address;
_peer_sc_oob_random = *random;
_peer_sc_oob_confirm = *confirm;
return BLE_ERROR_NONE;
}
@ -564,25 +561,25 @@ ble_error_t GenericSecurityManager::get_random_data(uint8_t *buffer, size_t size
}
ble_error_t GenericSecurityManager::slave_security_request(connection_handle_t connection) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return BLE_ERROR_INVALID_PARAM;
}
AuthenticationMask link_authentication(_default_authentication);
link_authentication.set_mitm(entry->mitm_requested);
link_authentication.set_mitm(cb->mitm_requested);
return _pal.slave_security_request(connection, link_authentication);
}
ble_error_t GenericSecurityManager::enable_encryption(connection_handle_t connection) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return BLE_ERROR_INVALID_PARAM;
}
if (entry->is_master) {
if (entry->ltk_stored) {
if (cb->is_master) {
if (cb->ltk_stored) {
_db.get_entry_peer_keys(
mbed::callback(this, &GenericSecurityManager::enable_encryption_cb),
connection
cb->db_entry
);
return BLE_ERROR_NONE;
} else {
@ -594,44 +591,48 @@ ble_error_t GenericSecurityManager::enable_encryption(connection_handle_t connec
}
void GenericSecurityManager::enable_encryption_cb(
const SecurityEntry_t* entry,
pal::SecurityDb::entry_handle_t db_entry,
const SecurityEntryKeys_t* entryKeys
) {
if (entry && entryKeys) {
if (entry->secure_connections_paired) {
_pal.enable_encryption(entry->handle, entryKeys->ltk);
ControlBlock_t *cb = get_control_block(db_entry);
if (cb && entryKeys) {
if (cb->secure_connections_paired) {
_pal.enable_encryption(cb->connection, entryKeys->ltk);
} else {
_pal.enable_encryption(entry->handle, entryKeys->ltk, entryKeys->rand, entryKeys->ediv);
_pal.enable_encryption(cb->connection, entryKeys->ltk, entryKeys->rand, entryKeys->ediv);
}
}
}
void GenericSecurityManager::set_ltk_cb(
const SecurityEntry_t* entry,
pal::SecurityDb::entry_handle_t db_entry,
const SecurityEntryKeys_t* entryKeys
) {
if (entry) {
ControlBlock_t *cb = get_control_block(db_entry);
if (cb) {
if (entryKeys) {
_pal.set_ltk(entry->handle, entryKeys->ltk);
_pal.set_ltk(cb->connection, entryKeys->ltk);
} else {
_pal.set_ltk_not_found(entry->handle);
_pal.set_ltk_not_found(cb->connection);
}
}
}
void GenericSecurityManager::return_csrk_cb(
connection_handle_t connection,
pal::SecurityDb::entry_handle_t db_entry,
const csrk_t *csrk
) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
ControlBlock_t *cb = get_control_block(db_entry);
if (!cb) {
return;
}
eventHandler->signingKey(
connection,
cb->connection,
csrk,
entry->csrk_mitm_protected
cb->csrk_mitm_protected
);
}
@ -642,8 +643,8 @@ void GenericSecurityManager::generate_secure_connections_oob(
oob_confirm_t confirm;
oob_rand_t random;
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return;
}
@ -660,31 +661,31 @@ void GenericSecurityManager::generate_secure_connections_oob(
);
eventHandler->oobGenerated(
&entry->local_address,
&cb->local_address,
&random,
&confirm
);
_db.set_local_sc_oob_random(random);
_local_sc_oob_random = random;
}
#endif
void GenericSecurityManager::update_oob_presence(connection_handle_t connection) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return;
}
/* only update the oob state if we support secure connections,
* otherwise follow the user set preference for providing legacy
* pairing oob data */
entry->oob_present = entry->attempt_oob;
cb->oob_present = cb->attempt_oob;
if (_default_authentication.get_secure_connections()) {
entry->oob_present = false;
cb->oob_present = false;
#if defined(MBEDTLS_CMAC_C)
if (entry->peer_address == _db.get_peer_sc_oob_address()) {
entry->oob_present = true;
if (cb->peer_address == _peer_sc_oob_address) {
cb->oob_present = true;
}
#endif
}
@ -721,9 +722,9 @@ bool GenericSecurityManager::crypto_toolbox_f4(
#endif
void GenericSecurityManager::set_mitm_performed(connection_handle_t connection, bool enable) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (entry) {
entry->mitm_performed = true;
ControlBlock_t *cb = get_control_block(connection);
if (cb) {
cb->mitm_performed = true;
}
}
@ -736,33 +737,41 @@ void GenericSecurityManager::on_connected(
const BLEProtocol::AddressBytes_t local_address,
const Gap::ConnectionParams_t *connection_params
) {
SecurityEntry_t *entry = _db.connect_entry(
connection,
peer_address_type,
address_t(peer_address),
address_t(local_address)
);
if (!entry) {
ControlBlock_t *cb = acquire_control_block(connection);
if (!cb) {
return;
}
entry->reset();
// 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);
entry->is_master = (role == Gap::CENTRAL);
entry->handle = connection;
entry->connected = true;
// get the associated db handle and the distribution flags if any
cb->db_entry = _db.open_entry(peer_address_type, peer_address);
const pal::SecurityDistributionFlags_t* dist_flags =
_db.get_distribution_flags(cb->db_entry);
if (dist_flags) {
*static_cast<pal::SecurityDistributionFlags_t*>(cb) = *dist_flags;
}
}
void GenericSecurityManager::on_disconnected(
connection_handle_t connection,
Gap::DisconnectionReason_t reason
) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return;
}
entry->connected = false;
_db.close_entry(cb->db_entry);
release_control_block(cb);
_db.sync();
}
@ -781,7 +790,7 @@ void GenericSecurityManager::on_pairing_request(
) {
/* cancel pairing if secure connection paring is not possible */
if (!_legacy_pairing_allowed && !authentication.get_secure_connections()) {
canceltPairingRequest(connection);
cancelPairingRequest(connection);
}
set_mitm_performed(connection, false);
@ -804,8 +813,8 @@ void GenericSecurityManager::on_pairing_error(
/* if this pairing was triggered by a failed encryption attempt
* inform the application of the encryption failure */
SecurityEntry_t *entry = _db.get_entry(connection);
if (entry && entry->encryption_requested && entry->encryption_failed) {
ControlBlock_t *cb = get_control_block(connection);
if (cb && cb->encryption_requested && cb->encryption_failed) {
eventHandler->linkEncryptionResult(
connection,
link_encryption_t::NOT_ENCRYPTED
@ -823,18 +832,21 @@ void GenericSecurityManager::on_pairing_timed_out(connection_handle_t connection
}
void GenericSecurityManager::on_pairing_completed(connection_handle_t connection) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (entry) {
if (entry->encryption_requested) {
ControlBlock_t *cb = get_control_block(connection);
if (cb) {
if (cb->encryption_requested) {
enable_encryption(connection);
}
/* sc doesn't need to exchange ltk */
if (entry->secure_connections_paired) {
entry->ltk_mitm_protected = entry->mitm_performed;
if (cb->secure_connections_paired) {
cb->ltk_mitm_protected = cb->mitm_performed;
}
}
// set the distribution flags in the db
_db.set_distribution_flags(cb->db_entry, *cb);
eventHandler->pairingResult(
connection,
SecurityManager::SEC_STATUS_SUCCESS
@ -853,20 +865,20 @@ void GenericSecurityManager::on_slave_security_request(
connection_handle_t connection,
AuthenticationMask authentication
) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return;
}
if (authentication.get_secure_connections()
&& _default_authentication.get_secure_connections()
&& !entry->secure_connections_paired) {
&& !cb->secure_connections_paired) {
requestPairing(connection);
}
if (authentication.get_mitm()
&& !entry->ltk_mitm_protected) {
entry->mitm_requested = true;
&& !cb->ltk_mitm_protected) {
cb->mitm_requested = true;
requestPairing(connection);
}
}
@ -880,30 +892,30 @@ void GenericSecurityManager::on_link_encryption_result(
link_encryption_t result
) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return;
}
if (result == link_encryption_t::ENCRYPTED) {
entry->encryption_requested = false;
entry->encryption_failed = false;
cb->encryption_requested = false;
cb->encryption_failed = false;
} else if (result == link_encryption_t::ENCRYPTED_WITH_MITM) {
entry->encryption_requested = false;
entry->encryption_failed = false;
entry->authenticated = true;
cb->encryption_requested = false;
cb->encryption_failed = false;
cb->authenticated = true;
} else if (result == link_encryption_t::NOT_ENCRYPTED
&& entry->encryption_requested
&& !entry->encryption_failed) {
&& cb->encryption_requested
&& !cb->encryption_failed) {
/* if we failed encryption for the first time
* retry repairing in case slave lost LTK */
requestPairing(entry->handle);
entry->encryption_failed = true;
requestPairing(cb->connection);
cb->encryption_failed = true;
/* don't return an event yet since we are retrying */
return;
}
@ -961,31 +973,20 @@ void GenericSecurityManager::on_oob_data_verification_request(
const public_key_t &peer_public_key_y
) {
#if defined(MBEDTLS_CMAC_C)
SecurityEntry_t *entry = _db.get_entry(connection);
ControlBlock_t *cb = get_control_block(connection);
oob_confirm_t confirm_verify;
address_t peer_oob_address;
oob_rand_t peer_oob_random;
oob_confirm_t peer_oob_confirm;
oob_rand_t local_oob_random;
_db.get_sc_oob_data(
peer_oob_address,
peer_oob_random,
peer_oob_confirm,
local_oob_random
);
crypto_toolbox_f4(
peer_public_key_x,
peer_public_key_y,
peer_oob_random,
_peer_oob_random,
confirm_verify
);
if (entry && (entry->peer_address == peer_oob_address)
&& (confirm_verify == peer_oob_confirm)) {
_pal.oob_data_verified(connection, local_oob_random, peer_oob_random);
if (cb && (cb->peer_address == _peer_oob_address)
&& (confirm_verify == _peer_oob_confirm)) {
_pal.oob_data_verified(connection, _local_oob_random, _peer_oob_random);
} else {
_pal.cancel_pairing(connection, pairing_failure_t::CONFIRM_VALUE_FAILED);
}
@ -1008,27 +1009,27 @@ void GenericSecurityManager::on_secure_connections_ltk_generated(
connection_handle_t connection,
const ltk_t &ltk
) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return;
}
entry->ltk_mitm_protected = entry->mitm_performed;
entry->secure_connections_paired = true;
cb->ltk_mitm_protected = cb->mitm_performed;
cb->secure_connections_paired = true;
_db.set_entry_peer_ltk(connection, ltk);
_db.set_entry_peer_ltk(cb->db_entry, ltk);
}
void GenericSecurityManager::on_keys_distributed_ltk(
connection_handle_t connection,
const ltk_t &ltk
) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return;
}
entry->ltk_mitm_protected = entry->mitm_performed;
_db.set_entry_peer_ltk(connection, ltk);
cb->ltk_mitm_protected = cb->mitm_performed;
_db.set_entry_peer_ltk(cb->db_entry, ltk);
}
void GenericSecurityManager::on_keys_distributed_ediv_rand(
@ -1036,14 +1037,24 @@ void GenericSecurityManager::on_keys_distributed_ediv_rand(
const ediv_t &ediv,
const rand_t &rand
) {
_db.set_entry_peer_ediv_rand(connection, ediv, rand);
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return;
}
_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 &ltk
) {
_db.set_entry_local_ltk(connection, ltk);
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return;
}
_db.set_entry_local_ltk(cb->db_entry, ltk);
}
void GenericSecurityManager::on_keys_distributed_local_ediv_rand(
@ -1051,14 +1062,24 @@ void GenericSecurityManager::on_keys_distributed_local_ediv_rand(
const ediv_t &ediv,
const rand_t &rand
) {
_db.set_entry_local_ediv_rand(connection, ediv, rand);
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return;
}
_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
) {
_db.set_entry_peer_irk(connection, irk);
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return;
}
_db.set_entry_peer_irk(cb->db_entry, irk);
}
void GenericSecurityManager::on_keys_distributed_bdaddr(
@ -1066,8 +1087,13 @@ void GenericSecurityManager::on_keys_distributed_bdaddr(
advertising_peer_address_type_t peer_address_type,
const address_t &peer_identity_address
) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return;
}
_db.set_entry_peer_bdaddr(
connection,
cb->db_entry,
(peer_address_type == advertising_peer_address_type_t::PUBLIC_ADDRESS),
peer_identity_address
);
@ -1077,19 +1103,19 @@ void GenericSecurityManager::on_keys_distributed_csrk(
connection_handle_t connection,
const csrk_t &csrk
) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return;
}
entry->csrk_mitm_protected = entry->mitm_performed;
cb->csrk_mitm_protected = cb->mitm_performed;
_db.set_entry_peer_csrk(connection, csrk);
_db.set_entry_peer_csrk(cb->db_entry, csrk);
eventHandler->signingKey(
connection,
&csrk,
entry->csrk_mitm_protected
cb->csrk_mitm_protected
);
}
@ -1098,22 +1124,111 @@ void GenericSecurityManager::on_ltk_request(
const ediv_t &ediv,
const rand_t &rand
) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return;
}
_db.get_entry_local_keys(
mbed::callback(this, &GenericSecurityManager::set_ltk_cb),
connection,
cb->db_entry,
ediv,
rand
);
}
void GenericSecurityManager::on_ltk_request(
connection_handle_t connection
) {
/* control blocks list management */
GenericSecurityManager::ControlBlock_t::ControlBlock_t() :
pal::SecurityDistributionFlags_t(),
connection(0),
local_address(),
db_entry(0),
connected(false),
authenticated(false),
is_master(false),
encryption_requested(false),
encryption_failed(false),
encrypted(false),
signing_requested(false),
mitm_requested(false),
mitm_performed(false),
attempt_oob(false),
oob_mitm_protection(false),
oob_present(false) { }
void GenericSecurityManager::on_ltk_request(connection_handle_t connection)
{
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return;
}
_db.get_entry_local_keys(
mbed::callback(this, &GenericSecurityManager::set_ltk_cb),
connection
cb->db_entry
);
}
GenericSecurityManager::ControlBlock_t*
GenericSecurityManager::acquire_control_block(connection_handle_t connection)
{
/* grab the first disconnected slot*/
for (size_t i = 0; i < MAX_CONTROL_BLOCKS; i++) {
if (!_control_blocks[i].connected) {
ControlBlock_t* cb = &_control_blocks[i];
cb->connected = true;
cb->connection = connection;
return cb;
}
}
return NULL;
}
GenericSecurityManager::ControlBlock_t* GenericSecurityManager::get_control_block(
connection_handle_t connection
) {
for (size_t i = 0; i < MAX_CONTROL_BLOCKS; i++) {
if (!_control_blocks[i].connected) {
continue;
} else if (connection == _control_blocks[i].connection) {
return &_control_blocks[i];
}
}
return NULL;
}
GenericSecurityManager::ControlBlock_t* GenericSecurityManager::get_control_block(
const address_t &peer_address
) {
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];
}
}
return NULL;
}
GenericSecurityManager::ControlBlock_t* GenericSecurityManager::get_control_block(
pal::SecurityDb::entry_handle_t db_entry
) {
for (size_t i = 0; i < MAX_CONTROL_BLOCKS; i++) {
if (!_control_blocks[i].connected) {
continue;
} else if (db_entry == _control_blocks[i].db_entry) {
return &_control_blocks[i];
}
}
return NULL;
}
void GenericSecurityManager::release_control_block(ControlBlock_t* cb)
{
*cb = ControlBlock_t();
}
} /* namespace generic */
} /* namespace ble */

View File

@ -94,6 +94,8 @@ add_executable(security-manager-tests
mbed_os_stub/mbed_assert.c
generic/SecurityManager/mock/MockPalSecurityManager.cpp
generic/SecurityManager/mock/MockPalSecurityDb.cpp
generic/SecurityManager/mock/MockConnectionEventMonitor.cpp
generic/SecurityManager/mock/MockSecurityManagerEventHandler.cpp
${PROJECT_SOURCE_DIR}/../source/generic/GenericSecurityManager.cpp
)

View File

@ -0,0 +1,35 @@
/* 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 "MockConnectionEventMonitor.h"
namespace ble {
namespace pal {
namespace vendor {
namespace mock {
////////////////////////////////////////////////////////////////////////////////
// Constructor implementation of the mocked pal connection event monitor
//
// WARNING: Do not remove; it speedup compile time.
MockPalConnectionEventMonitor::MockPalConnectionEventMonitor() { }
MockPalConnectionEventMonitor::~MockPalConnectionEventMonitor() { }
} // namespace ble
} // namespace pal
} // namespace vendor
} // namespace mock

View File

@ -0,0 +1,45 @@
/* 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 TESTS_GENERIC_SECURITYMANAGER_MOCK_MOCKPALCONENCTIONEVENTMONITOR_H_
#define TESTS_GENERIC_SECURITYMANAGER_MOCK_MOCKPALCONENCTIONEVENTMONITOR_H_
#include "gmock/gmock.h"
#include "ble/pal/ConnectionEventMonitor.h"
namespace ble {
namespace pal {
namespace vendor {
namespace mock {
/*
* Mock of ble::pal::ConnectionEventMonitor
*/
class MockPalConnectionEventMonitor : public ble::pal::ConnectionEventMonitor {
public:
MockPalConnectionEventMonitor();
virtual ~MockPalConnectionEventMonitor();
MOCK_METHOD1(set_connection_event_handler, void(ConnectionEventHandler *));
};
} // namespace ble
} // namespace pal
} // namespace vendor
} // namespace mock
#endif /* TESTS_GENERIC_SECURITYMANAGER_MOCK_MOCKPALCONENCTIONEVENTMONITOR_H_ */

View File

@ -34,154 +34,68 @@ public:
virtual ~MockPalSecurityDb();
MOCK_METHOD1(get_entry, SecurityEntry_t*(connection_handle_t));
MOCK_METHOD1(get_entry, SecurityEntry_t*(const address_t &));
MOCK_METHOD4(
get_entry_local_keys,
void(
SecurityEntryKeysDbCb_t,
connection_handle_t,
const ediv_t &,
const rand_t &
)
);
MOCK_METHOD2(
get_entry_local_keys,
void(SecurityEntryKeysDbCb_t, connection_handle_t)
);
MOCK_METHOD2(
set_entry_local_ltk,
void(connection_handle_t, const ltk_t &)
);
MOCK_METHOD3(
set_entry_local_ediv_rand,
void(connection_handle_t, const ediv_t &, const rand_t &)
);
MOCK_METHOD2(
get_entry_peer_csrk,
void(SecurityEntryCsrkDbCb_t, connection_handle_t)
);
MOCK_METHOD2(
get_entry_peer_keys,
void(SecurityEntryKeysDbCb_t, connection_handle_t)
);
MOCK_METHOD2(
set_entry_peer_ltk,
void(connection_handle_t, const ltk_t &)
);
MOCK_METHOD3(
set_entry_peer_ediv_rand,
void(connection_handle_t, const ediv_t &, const rand_t &)
);
MOCK_METHOD2(
set_entry_peer_irk,
void(connection_handle_t, const irk_t &)
);
MOCK_METHOD3(
set_entry_peer_bdaddr,
void(connection_handle_t, bool, const address_t &)
);
MOCK_METHOD2(
set_entry_peer_csrk,
void(connection_handle_t, const csrk_t &)
);
MOCK_METHOD0(get_local_csrk, const csrk_t*());
MOCK_METHOD1(set_local_csrk, void(const csrk_t &));
MOCK_METHOD0(get_public_key_x, const public_key_t&());
MOCK_METHOD0(get_public_key_y, const public_key_t&());
MOCK_METHOD2(set_public_key, void(const public_key_t &, const public_key_t &));
MOCK_METHOD0(get_peer_sc_oob_address, const address_t&());
MOCK_METHOD0(get_peer_sc_oob_random, const oob_rand_t&());
MOCK_METHOD0(get_peer_sc_oob_confirm, const oob_confirm_t&());
MOCK_METHOD4(
get_sc_oob_data,
void(
address_t &,
oob_rand_t &,
oob_confirm_t &,
oob_rand_t &
)
);
MOCK_METHOD0(get_local_sc_oob_random, const oob_rand_t&());
MOCK_METHOD3(
set_peer_sc_oob_data,
void(
const address_t &,
const oob_rand_t &,
const oob_confirm_t &
)
);
MOCK_METHOD1(set_local_sc_oob_random, void(const oob_rand_t&));
MOCK_METHOD4(
connect_entry,
SecurityEntry_t*(
connection_handle_t,
BLEProtocol::AddressType_t,
const address_t &,
const address_t &
)
);
MOCK_METHOD1(disconnect_entry, void(connection_handle_t));
MOCK_METHOD1(remove_entry, void(const address_t));
MOCK_METHOD0(clear_entries, void());
MOCK_METHOD2(get_whitelist, void(WhitelistDbCb_t, Gap::Whitelist_t *));
MOCK_METHOD2(
generate_whitelist_from_bond_table,
void(WhitelistDbCb_t, Gap::Whitelist_t *)
);
MOCK_METHOD2(
set_whitelist,
void(WhitelistDbCb_t, const Gap::Whitelist_t &)
);
MOCK_METHOD1(
add_whitelist_entry,
void(const address_t &)
);
MOCK_METHOD1(
remove_whitelist_entry,
void(const address_t &)
);
MOCK_METHOD0(clear_whitelist, void());
MOCK_METHOD0(restore, void());
MOCK_METHOD0(sync, void());
MOCK_METHOD1(set_restore, void(bool));
MOCK_METHOD1(get_distribution_flags,
const SecurityDistributionFlags_t*(entry_handle_t db_entry));
MOCK_METHOD2(set_distribution_flags,
void(entry_handle_t db_entry, const SecurityDistributionFlags_t& flags));
MOCK_METHOD4(get_entry_local_keys,
void(SecurityEntryKeysDbCb_t cb, entry_handle_t db_entry, const ediv_t &ediv, const rand_t &rand));
MOCK_METHOD2(get_entry_local_keys,
void(SecurityEntryKeysDbCb_t cb, entry_handle_t db_entry));
MOCK_METHOD2(set_entry_local_ltk,
void(entry_handle_t db_entry, const ltk_t &ltk));
MOCK_METHOD3(set_entry_local_ediv_rand,
void(entry_handle_t db_entry, const ediv_t &ediv, const rand_t &rand));
MOCK_METHOD2(get_entry_peer_csrk,
void(SecurityEntryCsrkDbCb_t cb, entry_handle_t db_entry));
MOCK_METHOD2(get_entry_peer_keys,
void(SecurityEntryKeysDbCb_t cb, entry_handle_t db_entry));
MOCK_METHOD2(set_entry_peer_ltk,
void(entry_handle_t db_entry, const ltk_t &ltk));
MOCK_METHOD3(set_entry_peer_ediv_rand,
void(entry_handle_t db_entry, const ediv_t &ediv, const rand_t &rand));
MOCK_METHOD2(set_entry_peer_irk,
void(entry_handle_t db_entry, const irk_t &irk));
MOCK_METHOD3(set_entry_peer_bdaddr,
void(entry_handle_t db_entry, bool address_is_public, const address_t &peer_address));
MOCK_METHOD2(set_entry_peer_csrk,
void(entry_handle_t db_entry, const csrk_t &csrk));
MOCK_METHOD0(get_local_csrk,
const csrk_t*());
MOCK_METHOD1(set_local_csrk,
void(const csrk_t &csrk));
MOCK_METHOD0(get_public_key_x,
const public_key_t&());
MOCK_METHOD0(get_public_key_y,
const public_key_t&());
MOCK_METHOD2(set_public_key,
void(const public_key_t &public_key_x, const public_key_t &public_key_y));
MOCK_METHOD2(open_entry,
entry_handle_t(BLEProtocol::AddressType_t peer_address_type, const address_t &peer_address));
MOCK_METHOD1(close_entry,
void(entry_handle_t db_entry));
MOCK_METHOD1(remove_entry,
void(const address_t peer_identity_address));
MOCK_METHOD0(clear_entries,
void());
MOCK_METHOD2(get_whitelist,
void(WhitelistDbCb_t cb, ::Gap::Whitelist_t *whitelist));
MOCK_METHOD2(generate_whitelist_from_bond_table,
void(WhitelistDbCb_t cb, ::Gap::Whitelist_t *whitelist));
MOCK_METHOD1(set_whitelist,
void(const ::Gap::Whitelist_t &whitelist));
MOCK_METHOD1(add_whitelist_entry,
void(const address_t &address));
MOCK_METHOD1(remove_whitelist_entry,
void(const address_t &address));
MOCK_METHOD0(clear_whitelist,
void());
MOCK_METHOD0(restore,
void());
MOCK_METHOD0(sync,
void());
MOCK_METHOD1(set_restore,
void(bool reload));
};
} // namespace ble

View File

@ -0,0 +1,35 @@
/* 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 "MockSecurityManagerEventHandler.h"
namespace ble {
namespace pal {
namespace vendor {
namespace mock {
////////////////////////////////////////////////////////////////////////////////
// Constructor implementation of the mocked pal security manager
//
// WARNING: Do not remove; it speedup compile time.
MockSecurityManagerEventHandler::MockSecurityManagerEventHandler() { }
MockSecurityManagerEventHandler::~MockSecurityManagerEventHandler() { }
} // namespace ble
} // namespace pal
} // namespace vendor
} // namespace mock

View File

@ -0,0 +1,72 @@
/* 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 TESTS_GENERIC_SECURITYMANAGER_MOCK_MOCKSECURITYMANAGEREVENTHANDLER_H_
#define TESTS_GENERIC_SECURITYMANAGER_MOCK_MOCKSECURITYMANAGEREVENTHANDLER_H_
#include "gmock/gmock.h"
#include "ble/SecurityManager.h"
namespace ble {
namespace pal {
namespace vendor {
namespace mock {
/*
* Mock of ble::pal::SecurityManager
*/
class MockSecurityManagerEventHandler :
public ::SecurityManager::SecurityManagerEventHandler {
public:
MockSecurityManagerEventHandler();
virtual ~MockSecurityManagerEventHandler();
MOCK_METHOD1(pairingRequest, void(connection_handle_t));
MOCK_METHOD2(pairingResult, void(connection_handle_t, SecurityManager::SecurityCompletionStatus_t));
MOCK_METHOD1(validMicTimeout, void(connection_handle_t));
MOCK_METHOD1(whitelistFromBondTable, void(Gap::Whitelist_t*));
MOCK_METHOD2(whitelistFromBondTable, void(connection_handle_t, link_encryption_t));
MOCK_METHOD2(passkeyDisplay, void(connection_handle_t, const SecurityManager::Passkey_t));
MOCK_METHOD1(confirmationRequest, void(connection_handle_t));
MOCK_METHOD1(passkeyRequest, void(connection_handle_t));
MOCK_METHOD2(keypressNotification, void(connection_handle_t, SecurityManager::Keypress_t));
MOCK_METHOD1(legacyPairingOobRequest, void(connection_handle_t));
MOCK_METHOD1(oobRequest, void(connection_handle_t));
MOCK_METHOD2(legacyPairingOobGenerated, void(const address_t *, const oob_tk_t *));
MOCK_METHOD3(oobGenerated, void(const address_t *, const oob_rand_t *, const oob_confirm_t *));
MOCK_METHOD3(signingKey, void(connection_handle_t, const csrk_t *, bool));
};
} // namespace ble
} // namespace pal
} // namespace vendor
} // namespace mock
#endif /* TESTS_GENERIC_SECURITYMANAGER_MOCK_MOCKSECURITYMANAGEREVENTHANDLER_H_ */

View File

@ -0,0 +1,49 @@
/* 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 TESTS_GENERIC_SECURITYMANAGER_MOCK_STUBCONNECTIONEVENTMONITOR_H_
#define TESTS_GENERIC_SECURITYMANAGER_MOCK_STUBCONNECTIONEVENTMONITOR_H_
#include "gmock/gmock.h"
#include "ble/pal/ConnectionEventMonitor.h"
namespace ble {
namespace pal {
namespace vendor {
namespace mock {
/*
* Stub of ble::pal::ConnectionEventMonitor
*/
struct StubPalConnectionEventMonitor : public ble::pal::ConnectionEventMonitor {
StubPalConnectionEventMonitor() : event_handler(nullptr) { }
virtual ~StubPalConnectionEventMonitor() { }
void set_connection_event_handler(pal::ConnectionEventHandler *connection_event_handler)
{
event_handler = connection_event_handler;
}
pal::ConnectionEventHandler *event_handler;
};
} // namespace mock
} // namespace vendor
} // namespace pal
} // namespace ble
#endif /* TESTS_GENERIC_SECURITYMANAGER_MOCK_STUBCONNECTIONEVENTMONITOR_H_ */