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. * @param[in] connectionHandle Handle to identify the connection.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason. * @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; (void) connectionHandle;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */ 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 * @param[in] required If set to true, pairingRequest in the event handler will
* will be called and will require an action from the application * will be called and will require an action from the application
* to continue with pairing by calling acceptPairingRequest * 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. * @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/ */
virtual ble_error_t setPairingRequestAuthorisation(bool required = true) { virtual ble_error_t setPairingRequestAuthorisation(bool required = true) {

View File

@ -41,7 +41,7 @@ class GenericSecurityManager : public SecurityManager,
public pal::SecurityManagerEventHandler, public pal::SecurityManagerEventHandler,
public pal::ConnectionEventHandler { public pal::ConnectionEventHandler {
public: public:
typedef ble::pal::SecurityEntry_t SecurityEntry_t; typedef ble::pal::SecurityDistributionFlags_t SecurityDistributionFlags_t;
typedef ble::pal::SecurityEntryKeys_t SecurityEntryKeys_t; typedef ble::pal::SecurityEntryKeys_t SecurityEntryKeys_t;
/* implements SecurityManager */ /* implements SecurityManager */
@ -86,7 +86,7 @@ public:
connection_handle_t connection connection_handle_t connection
); );
virtual ble_error_t canceltPairingRequest( virtual ble_error_t cancelPairingRequest(
connection_handle_t connection connection_handle_t connection
); );
@ -302,7 +302,7 @@ private:
* @param[in] entryKeys security entry containing keys. * @param[in] entryKeys security entry containing keys.
*/ */
void enable_encryption_cb( void enable_encryption_cb(
const SecurityEntry_t* entry, pal::SecurityDb::entry_handle_t entry,
const SecurityEntryKeys_t* entryKeys const SecurityEntryKeys_t* entryKeys
); );
@ -313,7 +313,7 @@ private:
* @param[in] entryKeys security entry containing keys. * @param[in] entryKeys security entry containing keys.
*/ */
void set_ltk_cb( void set_ltk_cb(
const SecurityEntry_t* entry, pal::SecurityDb::entry_handle_t entry,
const SecurityEntryKeys_t* entryKeys const SecurityEntryKeys_t* entryKeys
); );
@ -324,7 +324,7 @@ private:
* @param[in] entryKeys security entry containing keys. * @param[in] entryKeys security entry containing keys.
*/ */
void return_csrk_cb( void return_csrk_cb(
connection_handle_t connection, pal::SecurityDb::entry_handle_t connection,
const csrk_t *csrk const csrk_t *csrk
); );
@ -431,6 +431,31 @@ private:
); );
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::SecurityManager &_pal;
pal::SecurityDb &_db; pal::SecurityDb &_db;
pal::ConnectionEventMonitor &_connection_monitor; pal::ConnectionEventMonitor &_connection_monitor;
@ -443,6 +468,14 @@ private:
bool _master_sends_keys; bool _master_sends_keys;
bool _public_keys_generated; 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 */ /* implements ble::pal::SecurityManagerEventHandler */
public: public:
@ -642,6 +675,18 @@ public:
); );
/* end implements ble::pal::SecurityManagerEventHandler */ /* 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 #ifndef MBED_BLE_CONNECTION_EVENT_MONITOR
#define MBED_BLE_CONNECTION_EVENT_MONITOR #define MBED_BLE_CONNECTION_EVENT_MONITOR
#include <algorithm>
#include "ble/BLE.h"
#include "ble/BLEProtocol.h" #include "ble/BLEProtocol.h"
#include "ble/Gap.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/BLETypes.h"
#include "ble/pal/GenericAccessService.h"
#include "ble/pal/EventQueue.h"
namespace ble { namespace ble {
namespace pal { namespace pal {

View File

@ -14,11 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
#ifndef PAL_MEMORY_SECURITY_MANAGER_DB_H__ #ifndef PAL_MEMORY_SECURITY_MANAGER_entries_H__
#define PAL_MEMORY_SECURITY_MANAGER_DB_H__ #define PAL_MEMORY_SECURITY_MANAGER_entries_H__
#include "SecurityDB.h" #include "SecurityDB.h"
#include "Gap.h"
namespace ble { namespace ble {
namespace pal { namespace pal {
@ -27,42 +26,57 @@ namespace pal {
* TODO: make thread safe */ * TODO: make thread safe */
class MemorySecurityDb : public SecurityDb { class MemorySecurityDb : public SecurityDb {
private: private:
struct db_store_t { enum state_t {
db_store_t() { }; ENTRY_FREE,
SecurityEntry_t entry; ENTRY_RESERVED,
ENTRY_WRITTEN
};
struct entry_t {
entry_t() : state(ENTRY_FREE) { };
SecurityDistributionFlags_t flags;
SecurityEntryKeys_t peer_keys; SecurityEntryKeys_t peer_keys;
SecurityEntryKeys_t local_keys; SecurityEntryKeys_t local_keys;
SecurityEntryIdentity_t peer_identity;
csrk_t csrk; csrk_t csrk;
state_t state;
}; };
static const size_t MAX_ENTRIES = 5; 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: public:
MemorySecurityDb() { }; MemorySecurityDb() { };
virtual ~MemorySecurityDb() { }; virtual ~MemorySecurityDb() { };
virtual SecurityEntry_t* get_entry( virtual const SecurityDistributionFlags_t* get_distribution_flags(
connection_handle_t connection entry_handle_t entry_handle
) { ) {
SecurityEntry_t *entry = NULL; entry_t* entry = as_entry(entry_handle);
db_store_t *store = get_store(connection); if (!entry) {
if (store) { return NULL;
entry = &store->entry;
}
return entry;
} }
virtual SecurityEntry_t* get_entry( return &entry->flags;
const address_t &peer_address }
/**
* 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; entry_t* entry = as_entry(entry_handle);
for (size_t i = 0; i < MAX_ENTRIES; i++) { if (!entry) {
if (!_db[i].entry.connected) { return;
continue;
} else if (peer_address == _db[i].entry.peer_address) {
entry = &_db[i].entry;
} }
}
return entry; entry->state = ENTRY_WRITTEN;
entry->flags = flags;
} }
/* local keys */ /* local keys */
@ -70,64 +84,63 @@ public:
/* get */ /* get */
virtual void get_entry_local_keys( virtual void get_entry_local_keys(
SecurityEntryKeysDbCb_t cb, SecurityEntryKeysDbCb_t cb,
connection_handle_t connection, entry_handle_t entry_handle,
const ediv_t &ediv, const ediv_t &ediv,
const rand_t &rand const rand_t &rand
) { ) {
SecurityEntry_t *entry = NULL; entry_t* entry = as_entry(entry_handle);
db_store_t *store = get_store(connection); if (!entry) {
if (store) { return;
entry = &store->entry;
} }
/* validate we have the correct key */ /* validate we have the correct key */
if (ediv == store->local_keys.ediv if (ediv == entry->local_keys.ediv && rand == entry->local_keys.rand) {
&& rand == store->local_keys.rand) { cb(entry_handle, &entry->local_keys);
cb(entry, &store->local_keys);
} else { } else {
cb(entry, NULL); cb(entry_handle, NULL);
} }
} }
virtual void get_entry_local_keys( virtual void get_entry_local_keys(
SecurityEntryKeysDbCb_t cb, SecurityEntryKeysDbCb_t cb,
connection_handle_t connection entry_handle_t entry_handle
) { ) {
SecurityEntry_t *entry = NULL; entry_t* entry = as_entry(entry_handle);
db_store_t *store = get_store(connection); if (!entry) {
if (store) { return;
entry = &store->entry;
} }
/* validate we have the correct key */ /* validate we have the correct key */
if (entry->secure_connections_paired) { if (entry->flags.secure_connections_paired) {
cb(entry, &store->local_keys); cb(entry_handle, &entry->local_keys);
} else { } else {
cb(entry, NULL); cb(entry_handle, NULL);
} }
} }
/* set */ /* set */
virtual void set_entry_local_ltk( virtual void set_entry_local_ltk(
connection_handle_t connection, entry_handle_t entry_handle,
const ltk_t &ltk const ltk_t &ltk
) { ) {
db_store_t *store = get_store(connection); entry_t *entry = as_entry(entry_handle);
if (store) { if (entry) {
store->local_keys.ltk = ltk; entry->state = ENTRY_WRITTEN;
entry->local_keys.ltk = ltk;
} }
} }
virtual void set_entry_local_ediv_rand( virtual void set_entry_local_ediv_rand(
connection_handle_t connection, entry_handle_t entry_handle,
const ediv_t &ediv, const ediv_t &ediv,
const rand_t &rand const rand_t &rand
) { ) {
db_store_t *store = get_store(connection); entry_t *entry = as_entry(entry_handle);
if (store) { if (entry) {
store->local_keys.ediv = ediv; entry->state = ENTRY_WRITTEN;
store->local_keys.rand = rand; entry->local_keys.ediv = ediv;
entry->local_keys.rand = rand;
} }
} }
@ -136,86 +149,85 @@ public:
/* get */ /* get */
virtual void get_entry_peer_csrk( virtual void get_entry_peer_csrk(
SecurityEntryCsrkDbCb_t cb, SecurityEntryCsrkDbCb_t cb,
connection_handle_t connection entry_handle_t entry_handle
) { ) {
SecurityEntry_t *entry = NULL;
csrk_t csrk; csrk_t csrk;
db_store_t *store = get_store(connection); entry_t *entry = as_entry(entry_handle);
if (store) { if (entry) {
entry = &store->entry; csrk = entry->csrk;
csrk = store->csrk;
} }
cb(entry->handle, &csrk); cb(entry_handle, &csrk);
} }
virtual void get_entry_peer_keys( virtual void get_entry_peer_keys(
SecurityEntryKeysDbCb_t cb, SecurityEntryKeysDbCb_t cb,
connection_handle_t connection entry_handle_t entry_handle
) { ) {
SecurityEntry_t *entry = NULL;
SecurityEntryKeys_t *key = NULL; SecurityEntryKeys_t *key = NULL;
db_store_t *store = get_store(connection); entry_t *entry = as_entry(entry_handle);
if (store) { if (entry) {
entry = &store->entry; key = &entry->peer_keys;
key = &store->peer_keys;
} }
cb(entry, key); cb(entry_handle, key);
} }
/* set */ /* set */
virtual void set_entry_peer_ltk( virtual void set_entry_peer_ltk(
connection_handle_t connection, entry_handle_t entry_handle,
const ltk_t &ltk const ltk_t &ltk
) { ) {
db_store_t *store = get_store(connection); entry_t *entry = as_entry(entry_handle);
if (store) { if (entry) {
store->peer_keys.ltk = ltk; entry->state = ENTRY_WRITTEN;
entry->peer_keys.ltk = ltk;
} }
} }
virtual void set_entry_peer_ediv_rand( virtual void set_entry_peer_ediv_rand(
connection_handle_t connection, entry_handle_t entry_handle,
const ediv_t &ediv, const ediv_t &ediv,
const rand_t &rand const rand_t &rand
) { ) {
db_store_t *store = get_store(connection); entry_t *entry = as_entry(entry_handle);
if (store) { if (entry) {
store->peer_keys.ediv = ediv; entry->state = ENTRY_WRITTEN;
store->peer_keys.rand = rand; entry->peer_keys.ediv = ediv;
entry->peer_keys.rand = rand;
} }
} }
virtual void set_entry_peer_irk( virtual void set_entry_peer_irk(
connection_handle_t connection, entry_handle_t entry_handle,
const irk_t &irk const irk_t &irk
) { ) {
db_store_t *store = get_store(connection); entry_t *entry = as_entry(entry_handle);
if (store) { if (entry) {
size_t index = store - _db; entry->state = ENTRY_WRITTEN;
_identities[index].irk = irk; entry->peer_identity.irk = irk;
} }
} }
virtual void set_entry_peer_bdaddr( virtual void set_entry_peer_bdaddr(
connection_handle_t connection, entry_handle_t entry_handle,
bool address_is_public, bool address_is_public,
const address_t &peer_address const address_t &peer_address
) { ) {
db_store_t *store = get_store(connection); entry_t *entry = as_entry(entry_handle);
if (store) { if (entry) {
size_t index = store - _db; entry->state = ENTRY_WRITTEN;
_identities[index].identity_address = peer_address; entry->peer_identity.identity_address = peer_address;
} }
} }
virtual void set_entry_peer_csrk( virtual void set_entry_peer_csrk(
connection_handle_t connection, entry_handle_t entry_handle,
const csrk_t &csrk const csrk_t &csrk
) { ) {
db_store_t *store = get_store(connection); entry_t *entry = as_entry(entry_handle);
if (store) { if (entry) {
store->csrk = csrk; entry->state = ENTRY_WRITTEN;
entry->csrk = csrk;
} }
} }
@ -247,96 +259,62 @@ public:
_public_key_y = public_key_y; _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 */ /* list management */
virtual SecurityEntry_t* connect_entry( virtual entry_handle_t open_entry(
connection_handle_t connection,
BLEProtocol::AddressType_t peer_address_type, BLEProtocol::AddressType_t peer_address_type,
const address_t &peer_address, const address_t &peer_address
const address_t &local_address
) { ) {
const bool peer_address_public = const bool peer_address_public =
(peer_address_type == BLEProtocol::AddressType::PUBLIC); (peer_address_type == BLEProtocol::AddressType::PUBLIC);
for (size_t i = 0; i < MAX_ENTRIES; i++) { for (size_t i = 0; i < MAX_ENTRIES; i++) {
if (_db[i].entry.connected) { if (_entries[i].state == ENTRY_FREE) {
continue; continue;
} else if (peer_address == _identities[i].identity_address } else if (peer_address == _entries[i].peer_identity.identity_address
&& _db[i].entry.peer_address_is_public == peer_address_public) { && _entries[i].flags.peer_address_is_public == peer_address_public) {
return &_db[i].entry; return &_entries[i];
} }
} }
/* if we din't find one grab the first disconnected slot*/ /* if we din't find one grab the first disconnected slot*/
for (size_t i = 0; i < MAX_ENTRIES; i++) { for (size_t i = 0; i < MAX_ENTRIES; i++) {
if (!_db[i].entry.connected) { if (_entries[i].state == ENTRY_FREE) {
_db[i] = db_store_t(); _entries[i] = entry_t();
_identities[i] = SecurityEntryIdentity_t(); _entries[i].flags.peer_address = peer_address;
_db[i].entry.peer_address = peer_address; _entries[i].flags.peer_address_is_public = peer_address_public;
_db[i].entry.local_address = local_address; _entries[i].state = ENTRY_RESERVED;
_db[i].entry.peer_address_is_public = peer_address_public; return &_entries[i];
return &_db[i].entry;
} }
} }
return NULL; 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() { virtual void clear_entries() {
for (size_t i = 0; i < MAX_ENTRIES; i++) { for (size_t i = 0; i < MAX_ENTRIES; i++) {
_db[i] = db_store_t(); _entries[i] = entry_t();
} }
_local_identity = SecurityEntryIdentity_t(); _local_identity = SecurityEntryIdentity_t();
_local_csrk = csrk_t(); _local_csrk = csrk_t();
@ -349,7 +327,7 @@ public:
virtual void generate_whitelist_from_bond_table(WhitelistDbCb_t cb, ::Gap::Whitelist_t *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++) { 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; whitelist->addresses[i].type = BLEProtocol::AddressType::PUBLIC;
} else { } else {
whitelist->addresses[i].type = BLEProtocol::AddressType::RANDOM_STATIC; whitelist->addresses[i].type = BLEProtocol::AddressType::RANDOM_STATIC;
@ -357,7 +335,7 @@ public:
memcpy( memcpy(
whitelist->addresses[i].address, whitelist->addresses[i].address,
_identities[i].identity_address.data(), _entries[i].peer_identity.identity_address.data(),
sizeof(BLEProtocol::AddressBytes_t) sizeof(BLEProtocol::AddressBytes_t)
); );
} }
@ -365,8 +343,6 @@ public:
cb(whitelist); cb(whitelist);
} }
virtual void update_whitelist(::Gap::Whitelist_t &whitelist) { }
virtual void set_whitelist(const ::Gap::Whitelist_t &whitelist) { }; virtual void set_whitelist(const ::Gap::Whitelist_t &whitelist) { };
virtual void add_whitelist_entry(const address_t &address) { } virtual void add_whitelist_entry(const address_t &address) { }
@ -384,32 +360,14 @@ public:
virtual void set_restore(bool reload) { } virtual void set_restore(bool reload) { }
private: private:
entry_t _entries[MAX_ENTRIES];
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];
SecurityEntryIdentity_t _local_identity; SecurityEntryIdentity_t _local_identity;
csrk_t _local_csrk; csrk_t _local_csrk;
public_key_t _public_key_x; public_key_t _public_key_x;
public_key_t _public_key_y; 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 pal */
} /* namespace ble */ } /* 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 ble {
namespace pal { namespace pal {
/* separate structs for keys to allow db implementation
* to minimise memory usage, only holding live connection
* state in memory */
struct SecurityEntry_t { struct SecurityDistributionFlags_t {
SecurityEntry_t() SecurityDistributionFlags_t() :
: handle(0), peer_address(),
encryption_key_size(0), encryption_key_size(0),
peer_address_is_public(false), peer_address_is_public(false),
local_address_is_public(false), local_address_is_public(false),
@ -40,44 +37,9 @@ struct SecurityEntry_t {
csrk_mitm_protected(false), csrk_mitm_protected(false),
ltk_stored(false), ltk_stored(false),
ltk_mitm_protected(false), ltk_mitm_protected(false),
secure_connections_paired(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;
} }
connection_handle_t handle;
address_t peer_address; address_t peer_address;
uint8_t encryption_key_size; uint8_t encryption_key_size;
@ -89,26 +51,6 @@ struct SecurityEntry_t {
uint8_t ltk_stored:1; uint8_t ltk_stored:1;
uint8_t ltk_mitm_protected:1; uint8_t ltk_mitm_protected:1;
uint8_t secure_connections_paired: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 { struct SecurityEntryKeys_t {
@ -122,12 +64,6 @@ struct SecurityEntryIdentity_t {
irk_t irk; 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. * SecurityDB holds the state for active connections and bonded devices.
* Keys can be stored in NVM and are returned via callbacks. * 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 { class SecurityDb {
public: 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() { }; SecurityDb() { };
virtual ~SecurityDb() { }; virtual ~SecurityDb() { };
@ -147,19 +97,16 @@ public:
* @param[in] handle valid connection handle * @param[in] handle valid connection handle
* @return pointer to security entry, NULL if handle was invalid * @return pointer to security entry, NULL if handle was invalid
*/ */
virtual SecurityEntry_t* get_entry( virtual const SecurityDistributionFlags_t* get_distribution_flags(
connection_handle_t connection entry_handle_t db_entry
) = 0; ) = 0;
/** /**
* Return immediately security entry containing the state * Set the distribution flags of the DB entry
* 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
*/ */
virtual SecurityEntry_t* get_entry( virtual void set_distribution_flags(
const address_t &peer_address entry_handle_t db_entry,
const SecurityDistributionFlags_t& flags
) = 0; ) = 0;
/* local keys */ /* local keys */
@ -174,7 +121,7 @@ public:
*/ */
virtual void get_entry_local_keys( virtual void get_entry_local_keys(
SecurityEntryKeysDbCb_t cb, SecurityEntryKeysDbCb_t cb,
connection_handle_t connection, entry_handle_t db_entry,
const ediv_t &ediv, const ediv_t &ediv,
const rand_t &rand const rand_t &rand
) = 0; ) = 0;
@ -187,7 +134,7 @@ public:
*/ */
virtual void get_entry_local_keys( virtual void get_entry_local_keys(
SecurityEntryKeysDbCb_t cb, SecurityEntryKeysDbCb_t cb,
connection_handle_t connection entry_handle_t db_entry
) = 0; ) = 0;
/** /**
@ -198,7 +145,7 @@ public:
* be used when link is encrypted * be used when link is encrypted
*/ */
virtual void set_entry_local_ltk( virtual void set_entry_local_ltk(
connection_handle_t connection, entry_handle_t db_entry,
const ltk_t &ltk const ltk_t &ltk
) = 0; ) = 0;
@ -210,7 +157,7 @@ public:
* @param[in] rand new RAND value * @param[in] rand new RAND value
*/ */
virtual void set_entry_local_ediv_rand( virtual void set_entry_local_ediv_rand(
connection_handle_t connection, entry_handle_t db_entry,
const ediv_t &ediv, const ediv_t &ediv,
const rand_t &rand const rand_t &rand
) = 0; ) = 0;
@ -226,7 +173,7 @@ public:
*/ */
virtual void get_entry_peer_csrk( virtual void get_entry_peer_csrk(
SecurityEntryCsrkDbCb_t cb, SecurityEntryCsrkDbCb_t cb,
connection_handle_t connection entry_handle_t db_entry
) = 0; ) = 0;
/** /**
@ -238,7 +185,7 @@ public:
*/ */
virtual void get_entry_peer_keys( virtual void get_entry_peer_keys(
SecurityEntryKeysDbCb_t cb, SecurityEntryKeysDbCb_t cb,
connection_handle_t connection entry_handle_t db_entry
) = 0; ) = 0;
/** /**
@ -249,7 +196,7 @@ public:
* be used when link is encrypted * be used when link is encrypted
*/ */
virtual void set_entry_peer_ltk( virtual void set_entry_peer_ltk(
connection_handle_t connection, entry_handle_t db_entry,
const ltk_t &ltk const ltk_t &ltk
) = 0; ) = 0;
@ -261,7 +208,7 @@ public:
* @param[in] rand new RAND value * @param[in] rand new RAND value
*/ */
virtual void set_entry_peer_ediv_rand( virtual void set_entry_peer_ediv_rand(
connection_handle_t connection, entry_handle_t db_entry,
const ediv_t &ediv, const ediv_t &ediv,
const rand_t &rand const rand_t &rand
) = 0; ) = 0;
@ -273,7 +220,7 @@ public:
* @param[in] irk new IRK value * @param[in] irk new IRK value
*/ */
virtual void set_entry_peer_irk( virtual void set_entry_peer_irk(
connection_handle_t connection, entry_handle_t db_entry,
const irk_t &irk const irk_t &irk
) = 0; ) = 0;
@ -285,7 +232,7 @@ public:
* @param[in] peer_address the new address * @param[in] peer_address the new address
*/ */
virtual void set_entry_peer_bdaddr( virtual void set_entry_peer_bdaddr(
connection_handle_t connection, entry_handle_t db_entry,
bool address_is_public, bool address_is_public,
const address_t &peer_address const address_t &peer_address
) = 0; ) = 0;
@ -297,7 +244,7 @@ public:
* @param[in] csrk new CSRK value * @param[in] csrk new CSRK value
*/ */
virtual void set_entry_peer_csrk( virtual void set_entry_peer_csrk(
connection_handle_t connection, entry_handle_t db_entry,
const csrk_t &csrk const csrk_t &csrk
) = 0; ) = 0;
@ -315,9 +262,7 @@ public:
* *
* @param[in] csrk new CSRK value * @param[in] csrk new CSRK value
*/ */
virtual void set_local_csrk( virtual void set_local_csrk(const csrk_t &csrk) = 0;
const csrk_t &csrk
) = 0;
/* public keys */ /* public keys */
@ -346,118 +291,38 @@ public:
const public_key_t &public_key_y const public_key_t &public_key_y
) = 0; ) = 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 */ /* list management */
/** /**
* Create a new entry or retrieve existing stored entry * Open a database entry.
* and put it in the live connections store to be retrieved *
* synchronously through connection handle. * 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_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( virtual entry_handle_t open_entry(
connection_handle_t connection,
BLEProtocol::AddressType_t peer_address_type, BLEProtocol::AddressType_t peer_address_type,
const address_t &peer_address, const address_t &peer_address
const address_t &local_address
) = 0; ) = 0;
/** /**
* Create a new entry or retrieve existing stored entry * Close a connection entry.
* and put it in the live connections store to be retrieved
* synchronously through connection handle.
* *
* @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( virtual void close_entry(entry_handle_t db_entry) = 0;
connection_handle_t connection
) = 0;
/** /**
* Remove entry for this peer from NVM. * Remove entry for this peer from NVM.
* *
* @param[in] peer_identity_address peer address that no longer needs NVM storage. * @param[in] peer_identity_address peer address that no longer needs NVM storage.
*/ */
virtual void remove_entry( virtual void remove_entry(const address_t peer_identity_address) = 0;
const address_t peer_identity_address
) = 0;
/** /**
* Remove all entries from the security DB. * Remove all entries from the security DB.
@ -495,27 +360,21 @@ public:
* *
* @param[in] whitelist * @param[in] whitelist
*/ */
virtual void set_whitelist( virtual void set_whitelist(const ::Gap::Whitelist_t &whitelist) = 0;
const ::Gap::Whitelist_t &whitelist
) = 0;
/** /**
* Add a new entry to the whitelist in the NVM. * Add a new entry to the whitelist in the NVM.
* *
* @param[in] address new whitelist entry * @param[in] address new whitelist entry
*/ */
virtual void add_whitelist_entry( virtual void add_whitelist_entry(const address_t &address) = 0;
const address_t &address
) = 0;
/** /**
* Remove whitelist entry from NVM. * Remove whitelist entry from NVM.
* *
* @param[in] address entry to be removed * @param[in] address entry to be removed
*/ */
virtual void remove_whitelist_entry( virtual void remove_whitelist_entry(const address_t &address) = 0;
const address_t &address
) = 0;
/** /**
*Remove all whitelist entries stored in the NVM. *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) { ble_error_t GenericSecurityManager::requestPairing(connection_handle_t connection) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (!entry) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; return BLE_ERROR_INVALID_PARAM;
} }
@ -113,15 +113,15 @@ ble_error_t GenericSecurityManager::requestPairing(connection_handle_t connectio
update_oob_presence(connection); update_oob_presence(connection);
AuthenticationMask link_authentication(_default_authentication); 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); 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); link_key_distribution.set_encryption(_master_sends_keys);
return _pal.send_pairing_request( return _pal.send_pairing_request(
connection, connection,
entry->oob_present, cb->oob_present,
link_authentication, link_authentication,
link_key_distribution, link_key_distribution,
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) { ble_error_t GenericSecurityManager::acceptPairingRequest(connection_handle_t connection) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (!entry) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; return BLE_ERROR_INVALID_PARAM;
} }
update_oob_presence(connection); update_oob_presence(connection);
AuthenticationMask link_authentication(_default_authentication); 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); 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( return _pal.send_pairing_response(
connection, connection,
entry->oob_present, cb->oob_present,
link_authentication, link_authentication,
link_key_distribution, link_key_distribution,
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); return _pal.cancel_pairing(connection, pairing_failure_t::UNSPECIFIED_REASON);
} }
@ -206,12 +206,12 @@ ble_error_t GenericSecurityManager::setLinkSecurity(
connection_handle_t connection, connection_handle_t connection,
SecurityMode_t securityMode SecurityMode_t securityMode
) { ) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (!entry) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; return BLE_ERROR_INVALID_PARAM;
} }
if (entry->encryption_requested) { if (cb->encryption_requested) {
return BLE_ERROR_OPERATION_NOT_PERMITTED; return BLE_ERROR_OPERATION_NOT_PERMITTED;
} }
@ -245,19 +245,19 @@ ble_error_t GenericSecurityManager::enableSigning(
connection_handle_t connection, connection_handle_t connection,
bool enabled bool enabled
) { ) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (!entry) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; return BLE_ERROR_INVALID_PARAM;
} }
entry->signing_requested = enabled; cb->signing_requested = enabled;
if (entry->encrypted) { if (cb->encrypted) {
return BLE_ERROR_INVALID_STATE; return BLE_ERROR_INVALID_STATE;
} }
if (!entry->csrk_stored && entry->signing_requested) { if (!cb->csrk_stored && cb->signing_requested) {
init_signing(); init_signing();
if (entry->is_master) { if (cb->is_master) {
return requestPairing(connection); return requestPairing(connection);
} else { } else {
return slave_security_request(connection); return slave_security_request(connection);
@ -281,18 +281,18 @@ ble_error_t GenericSecurityManager::getLinkEncryption(
link_encryption_t *encryption link_encryption_t *encryption
) { ) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (!entry) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; return BLE_ERROR_INVALID_PARAM;
} }
if (entry->encrypted) { if (cb->encrypted) {
if (entry->ltk_mitm_protected || entry->mitm_performed) { if (cb->ltk_mitm_protected || cb->mitm_performed) {
*encryption = link_encryption_t::ENCRYPTED_WITH_MITM; *encryption = link_encryption_t::ENCRYPTED_WITH_MITM;
} else { } else {
*encryption = link_encryption_t::ENCRYPTED; *encryption = link_encryption_t::ENCRYPTED;
} }
} else if (entry->encryption_requested) { } else if (cb->encryption_requested) {
*encryption = link_encryption_t::ENCRYPTION_IN_PROGRESS; *encryption = link_encryption_t::ENCRYPTION_IN_PROGRESS;
} else { } else {
*encryption = link_encryption_t::NOT_ENCRYPTED; *encryption = link_encryption_t::NOT_ENCRYPTED;
@ -305,8 +305,8 @@ ble_error_t GenericSecurityManager::setLinkEncryption(
connection_handle_t connection, connection_handle_t connection,
link_encryption_t encryption link_encryption_t encryption
) { ) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (!entry) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; return BLE_ERROR_INVALID_PARAM;
} }
@ -324,7 +324,7 @@ ble_error_t GenericSecurityManager::setLinkEncryption(
if (encryption == link_encryption_t::NOT_ENCRYPTED) { if (encryption == link_encryption_t::NOT_ENCRYPTED) {
if (entry->encrypted) { if (cb->encrypted) {
return _pal.disable_encryption(connection); return _pal.disable_encryption(connection);
} }
@ -334,16 +334,16 @@ ble_error_t GenericSecurityManager::setLinkEncryption(
if (current_encryption == link_encryption_t::ENCRYPTED_WITH_MITM) { if (current_encryption == link_encryption_t::ENCRYPTED_WITH_MITM) {
return BLE_ERROR_NONE; return BLE_ERROR_NONE;
} }
entry->encryption_requested = true; cb->encryption_requested = true;
return enable_encryption(connection); return enable_encryption(connection);
} else if (encryption == link_encryption_t::ENCRYPTED_WITH_MITM) { } else if (encryption == link_encryption_t::ENCRYPTED_WITH_MITM) {
if (entry->ltk_mitm_protected && !entry->encrypted) { if (cb->ltk_mitm_protected && !cb->encrypted) {
entry->encryption_requested = true; cb->encryption_requested = true;
return enable_encryption(connection); return enable_encryption(connection);
} else { } else {
entry->encryption_requested = true; cb->encryption_requested = true;
return requestAuthentication(connection); return requestAuthentication(connection);
} }
@ -358,9 +358,9 @@ ble_error_t GenericSecurityManager::getEncryptionKeySize(
connection_handle_t connection, connection_handle_t connection,
uint8_t *size uint8_t *size
) { ) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (entry) { if (cb) {
*size = entry->encryption_key_size; *size = cb->encryption_key_size;
return BLE_ERROR_NONE; return BLE_ERROR_NONE;
} else { } else {
return BLE_ERROR_INVALID_PARAM; 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) { ble_error_t GenericSecurityManager::getSigningKey(connection_handle_t connection, bool authenticated) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (!entry) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; 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 /* we have a key that is either authenticated or we don't care if it is
* so retrieve it from the db now */ * so retrieve it from the db now */
_db.get_entry_peer_csrk( _db.get_entry_peer_csrk(
mbed::callback(this, &GenericSecurityManager::return_csrk_cb), mbed::callback(this, &GenericSecurityManager::return_csrk_cb),
connection cb->db_entry
); );
return BLE_ERROR_NONE; return BLE_ERROR_NONE;
@ -398,7 +398,7 @@ ble_error_t GenericSecurityManager::getSigningKey(connection_handle_t connection
* keys exchange will create the signingKey event */ * keys exchange will create the signingKey event */
if (authenticated) { if (authenticated) {
return requestAuthentication(connection); return requestAuthentication(connection);
} else if (entry->is_master) { } else if (cb->is_master) {
return requestPairing(connection); return requestPairing(connection);
} else { } else {
return slave_security_request(connection); 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) { ble_error_t GenericSecurityManager::requestAuthentication(connection_handle_t connection) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (!entry) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; return BLE_ERROR_INVALID_PARAM;
} }
if (entry->ltk_mitm_protected) { if (cb->ltk_mitm_protected) {
if (entry->authenticated) { if (cb->authenticated) {
return BLE_ERROR_NONE; return BLE_ERROR_NONE;
} else { } else {
entry->encryption_requested = true; cb->encryption_requested = true;
return enable_encryption(connection); return enable_encryption(connection);
} }
} else { } else {
entry->mitm_requested = true; cb->mitm_requested = true;
if (entry->is_master) { if (cb->is_master) {
return requestPairing(connection); return requestPairing(connection);
} else { } else {
return slave_security_request(connection); return slave_security_request(connection);
@ -450,13 +450,13 @@ ble_error_t GenericSecurityManager::setOOBDataUsage(
bool useOOB, bool useOOB,
bool OOBProvidesMITM bool OOBProvidesMITM
) { ) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (!entry) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; return BLE_ERROR_INVALID_PARAM;
} }
entry->attempt_oob = useOOB; cb->attempt_oob = useOOB;
entry->oob_mitm_protection = OOBProvidesMITM; cb->oob_mitm_protection = OOBProvidesMITM;
#if defined(MBEDTLS_CMAC_C) #if defined(MBEDTLS_CMAC_C)
if (_public_keys_generated) { if (_public_keys_generated) {
@ -496,12 +496,12 @@ ble_error_t GenericSecurityManager::legacyPairingOobReceived(
const oob_tk_t *tk const oob_tk_t *tk
) { ) {
if (address && tk) { if (address && tk) {
SecurityEntry_t *entry = _db.get_entry(*address); ControlBlock_t *cb = get_control_block(*address);
if (!entry) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; 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; return BLE_ERROR_NONE;
} }
@ -512,12 +512,9 @@ ble_error_t GenericSecurityManager::oobReceived(
const oob_confirm_t *confirm const oob_confirm_t *confirm
) { ) {
if (address && random && confirm) { if (address && random && confirm) {
_db.set_peer_sc_oob_data( _peer_sc_oob_address = *address;
*address, _peer_sc_oob_random = *random;
*random, _peer_sc_oob_confirm = *confirm;
*confirm
);
return BLE_ERROR_NONE; 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) { ble_error_t GenericSecurityManager::slave_security_request(connection_handle_t connection) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (!entry) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; return BLE_ERROR_INVALID_PARAM;
} }
AuthenticationMask link_authentication(_default_authentication); 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); return _pal.slave_security_request(connection, link_authentication);
} }
ble_error_t GenericSecurityManager::enable_encryption(connection_handle_t connection) { ble_error_t GenericSecurityManager::enable_encryption(connection_handle_t connection) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (!entry) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; return BLE_ERROR_INVALID_PARAM;
} }
if (entry->is_master) { if (cb->is_master) {
if (entry->ltk_stored) { if (cb->ltk_stored) {
_db.get_entry_peer_keys( _db.get_entry_peer_keys(
mbed::callback(this, &GenericSecurityManager::enable_encryption_cb), mbed::callback(this, &GenericSecurityManager::enable_encryption_cb),
connection cb->db_entry
); );
return BLE_ERROR_NONE; return BLE_ERROR_NONE;
} else { } else {
@ -594,44 +591,48 @@ ble_error_t GenericSecurityManager::enable_encryption(connection_handle_t connec
} }
void GenericSecurityManager::enable_encryption_cb( void GenericSecurityManager::enable_encryption_cb(
const SecurityEntry_t* entry, pal::SecurityDb::entry_handle_t db_entry,
const SecurityEntryKeys_t* entryKeys const SecurityEntryKeys_t* entryKeys
) { ) {
if (entry && entryKeys) { ControlBlock_t *cb = get_control_block(db_entry);
if (entry->secure_connections_paired) {
_pal.enable_encryption(entry->handle, entryKeys->ltk); if (cb && entryKeys) {
if (cb->secure_connections_paired) {
_pal.enable_encryption(cb->connection, entryKeys->ltk);
} else { } 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( void GenericSecurityManager::set_ltk_cb(
const SecurityEntry_t* entry, pal::SecurityDb::entry_handle_t db_entry,
const SecurityEntryKeys_t* entryKeys const SecurityEntryKeys_t* entryKeys
) { ) {
if (entry) { ControlBlock_t *cb = get_control_block(db_entry);
if (cb) {
if (entryKeys) { if (entryKeys) {
_pal.set_ltk(entry->handle, entryKeys->ltk); _pal.set_ltk(cb->connection, entryKeys->ltk);
} else { } else {
_pal.set_ltk_not_found(entry->handle); _pal.set_ltk_not_found(cb->connection);
} }
} }
} }
void GenericSecurityManager::return_csrk_cb( void GenericSecurityManager::return_csrk_cb(
connection_handle_t connection, pal::SecurityDb::entry_handle_t db_entry,
const csrk_t *csrk const csrk_t *csrk
) { ) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(db_entry);
if (!entry) { if (!cb) {
return; return;
} }
eventHandler->signingKey( eventHandler->signingKey(
connection, cb->connection,
csrk, csrk,
entry->csrk_mitm_protected cb->csrk_mitm_protected
); );
} }
@ -642,8 +643,8 @@ void GenericSecurityManager::generate_secure_connections_oob(
oob_confirm_t confirm; oob_confirm_t confirm;
oob_rand_t random; oob_rand_t random;
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (!entry) { if (!cb) {
return; return;
} }
@ -660,31 +661,31 @@ void GenericSecurityManager::generate_secure_connections_oob(
); );
eventHandler->oobGenerated( eventHandler->oobGenerated(
&entry->local_address, &cb->local_address,
&random, &random,
&confirm &confirm
); );
_db.set_local_sc_oob_random(random); _local_sc_oob_random = random;
} }
#endif #endif
void GenericSecurityManager::update_oob_presence(connection_handle_t connection) { void GenericSecurityManager::update_oob_presence(connection_handle_t connection) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (!entry) { if (!cb) {
return; return;
} }
/* only update the oob state if we support secure connections, /* only update the oob state if we support secure connections,
* otherwise follow the user set preference for providing legacy * otherwise follow the user set preference for providing legacy
* pairing oob data */ * pairing oob data */
entry->oob_present = entry->attempt_oob; cb->oob_present = cb->attempt_oob;
if (_default_authentication.get_secure_connections()) { if (_default_authentication.get_secure_connections()) {
entry->oob_present = false; cb->oob_present = false;
#if defined(MBEDTLS_CMAC_C) #if defined(MBEDTLS_CMAC_C)
if (entry->peer_address == _db.get_peer_sc_oob_address()) { if (cb->peer_address == _peer_sc_oob_address) {
entry->oob_present = true; cb->oob_present = true;
} }
#endif #endif
} }
@ -721,9 +722,9 @@ bool GenericSecurityManager::crypto_toolbox_f4(
#endif #endif
void GenericSecurityManager::set_mitm_performed(connection_handle_t connection, bool enable) { void GenericSecurityManager::set_mitm_performed(connection_handle_t connection, bool enable) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (entry) { if (cb) {
entry->mitm_performed = true; cb->mitm_performed = true;
} }
} }
@ -736,33 +737,41 @@ void GenericSecurityManager::on_connected(
const BLEProtocol::AddressBytes_t local_address, const BLEProtocol::AddressBytes_t local_address,
const Gap::ConnectionParams_t *connection_params const Gap::ConnectionParams_t *connection_params
) { ) {
SecurityEntry_t *entry = _db.connect_entry( ControlBlock_t *cb = acquire_control_block(connection);
connection, if (!cb) {
peer_address_type,
address_t(peer_address),
address_t(local_address)
);
if (!entry) {
return; 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); // get the associated db handle and the distribution flags if any
entry->handle = connection; cb->db_entry = _db.open_entry(peer_address_type, peer_address);
entry->connected = true;
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( void GenericSecurityManager::on_disconnected(
connection_handle_t connection, connection_handle_t connection,
Gap::DisconnectionReason_t reason Gap::DisconnectionReason_t reason
) { ) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (!entry) { if (!cb) {
return; return;
} }
entry->connected = false;
_db.close_entry(cb->db_entry);
release_control_block(cb);
_db.sync(); _db.sync();
} }
@ -781,7 +790,7 @@ void GenericSecurityManager::on_pairing_request(
) { ) {
/* cancel pairing if secure connection paring is not possible */ /* cancel pairing if secure connection paring is not possible */
if (!_legacy_pairing_allowed && !authentication.get_secure_connections()) { if (!_legacy_pairing_allowed && !authentication.get_secure_connections()) {
canceltPairingRequest(connection); cancelPairingRequest(connection);
} }
set_mitm_performed(connection, false); set_mitm_performed(connection, false);
@ -804,8 +813,8 @@ void GenericSecurityManager::on_pairing_error(
/* if this pairing was triggered by a failed encryption attempt /* if this pairing was triggered by a failed encryption attempt
* inform the application of the encryption failure */ * inform the application of the encryption failure */
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (entry && entry->encryption_requested && entry->encryption_failed) { if (cb && cb->encryption_requested && cb->encryption_failed) {
eventHandler->linkEncryptionResult( eventHandler->linkEncryptionResult(
connection, connection,
link_encryption_t::NOT_ENCRYPTED 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) { void GenericSecurityManager::on_pairing_completed(connection_handle_t connection) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (entry) { if (cb) {
if (entry->encryption_requested) { if (cb->encryption_requested) {
enable_encryption(connection); enable_encryption(connection);
} }
/* sc doesn't need to exchange ltk */ /* sc doesn't need to exchange ltk */
if (entry->secure_connections_paired) { if (cb->secure_connections_paired) {
entry->ltk_mitm_protected = entry->mitm_performed; cb->ltk_mitm_protected = cb->mitm_performed;
} }
} }
// set the distribution flags in the db
_db.set_distribution_flags(cb->db_entry, *cb);
eventHandler->pairingResult( eventHandler->pairingResult(
connection, connection,
SecurityManager::SEC_STATUS_SUCCESS SecurityManager::SEC_STATUS_SUCCESS
@ -853,20 +865,20 @@ void GenericSecurityManager::on_slave_security_request(
connection_handle_t connection, connection_handle_t connection,
AuthenticationMask authentication AuthenticationMask authentication
) { ) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (!entry) { if (!cb) {
return; return;
} }
if (authentication.get_secure_connections() if (authentication.get_secure_connections()
&& _default_authentication.get_secure_connections() && _default_authentication.get_secure_connections()
&& !entry->secure_connections_paired) { && !cb->secure_connections_paired) {
requestPairing(connection); requestPairing(connection);
} }
if (authentication.get_mitm() if (authentication.get_mitm()
&& !entry->ltk_mitm_protected) { && !cb->ltk_mitm_protected) {
entry->mitm_requested = true; cb->mitm_requested = true;
requestPairing(connection); requestPairing(connection);
} }
} }
@ -880,30 +892,30 @@ void GenericSecurityManager::on_link_encryption_result(
link_encryption_t result link_encryption_t result
) { ) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (!entry) { if (!cb) {
return; return;
} }
if (result == link_encryption_t::ENCRYPTED) { if (result == link_encryption_t::ENCRYPTED) {
entry->encryption_requested = false; cb->encryption_requested = false;
entry->encryption_failed = false; cb->encryption_failed = false;
} else if (result == link_encryption_t::ENCRYPTED_WITH_MITM) { } else if (result == link_encryption_t::ENCRYPTED_WITH_MITM) {
entry->encryption_requested = false; cb->encryption_requested = false;
entry->encryption_failed = false; cb->encryption_failed = false;
entry->authenticated = true; cb->authenticated = true;
} else if (result == link_encryption_t::NOT_ENCRYPTED } else if (result == link_encryption_t::NOT_ENCRYPTED
&& entry->encryption_requested && cb->encryption_requested
&& !entry->encryption_failed) { && !cb->encryption_failed) {
/* if we failed encryption for the first time /* if we failed encryption for the first time
* retry repairing in case slave lost LTK */ * retry repairing in case slave lost LTK */
requestPairing(entry->handle); requestPairing(cb->connection);
entry->encryption_failed = true; cb->encryption_failed = true;
/* don't return an event yet since we are retrying */ /* don't return an event yet since we are retrying */
return; return;
} }
@ -961,31 +973,20 @@ void GenericSecurityManager::on_oob_data_verification_request(
const public_key_t &peer_public_key_y const public_key_t &peer_public_key_y
) { ) {
#if defined(MBEDTLS_CMAC_C) #if defined(MBEDTLS_CMAC_C)
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
oob_confirm_t confirm_verify; 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( crypto_toolbox_f4(
peer_public_key_x, peer_public_key_x,
peer_public_key_y, peer_public_key_y,
peer_oob_random, _peer_oob_random,
confirm_verify confirm_verify
); );
if (entry && (entry->peer_address == peer_oob_address) if (cb && (cb->peer_address == _peer_oob_address)
&& (confirm_verify == peer_oob_confirm)) { && (confirm_verify == _peer_oob_confirm)) {
_pal.oob_data_verified(connection, local_oob_random, peer_oob_random); _pal.oob_data_verified(connection, _local_oob_random, _peer_oob_random);
} else { } else {
_pal.cancel_pairing(connection, pairing_failure_t::CONFIRM_VALUE_FAILED); _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, connection_handle_t connection,
const ltk_t &ltk const ltk_t &ltk
) { ) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (!entry) { if (!cb) {
return; return;
} }
entry->ltk_mitm_protected = entry->mitm_performed; cb->ltk_mitm_protected = cb->mitm_performed;
entry->secure_connections_paired = true; 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( void GenericSecurityManager::on_keys_distributed_ltk(
connection_handle_t connection, connection_handle_t connection,
const ltk_t &ltk const ltk_t &ltk
) { ) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (!entry) { if (!cb) {
return; return;
} }
entry->ltk_mitm_protected = entry->mitm_performed; cb->ltk_mitm_protected = cb->mitm_performed;
_db.set_entry_peer_ltk(connection, ltk); _db.set_entry_peer_ltk(cb->db_entry, ltk);
} }
void GenericSecurityManager::on_keys_distributed_ediv_rand( void GenericSecurityManager::on_keys_distributed_ediv_rand(
@ -1036,14 +1037,24 @@ void GenericSecurityManager::on_keys_distributed_ediv_rand(
const ediv_t &ediv, const ediv_t &ediv,
const rand_t &rand 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( void GenericSecurityManager::on_keys_distributed_local_ltk(
connection_handle_t connection, connection_handle_t connection,
const ltk_t &ltk 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( 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 ediv_t &ediv,
const rand_t &rand 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( void GenericSecurityManager::on_keys_distributed_irk(
connection_handle_t connection, connection_handle_t connection,
const irk_t &irk 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( void GenericSecurityManager::on_keys_distributed_bdaddr(
@ -1066,8 +1087,13 @@ void GenericSecurityManager::on_keys_distributed_bdaddr(
advertising_peer_address_type_t peer_address_type, advertising_peer_address_type_t peer_address_type,
const address_t &peer_identity_address const address_t &peer_identity_address
) { ) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return;
}
_db.set_entry_peer_bdaddr( _db.set_entry_peer_bdaddr(
connection, cb->db_entry,
(peer_address_type == advertising_peer_address_type_t::PUBLIC_ADDRESS), (peer_address_type == advertising_peer_address_type_t::PUBLIC_ADDRESS),
peer_identity_address peer_identity_address
); );
@ -1077,19 +1103,19 @@ void GenericSecurityManager::on_keys_distributed_csrk(
connection_handle_t connection, connection_handle_t connection,
const csrk_t &csrk const csrk_t &csrk
) { ) {
SecurityEntry_t *entry = _db.get_entry(connection); ControlBlock_t *cb = get_control_block(connection);
if (!entry) { if (!cb) {
return; 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( eventHandler->signingKey(
connection, connection,
&csrk, &csrk,
entry->csrk_mitm_protected cb->csrk_mitm_protected
); );
} }
@ -1098,22 +1124,111 @@ void GenericSecurityManager::on_ltk_request(
const ediv_t &ediv, const ediv_t &ediv,
const rand_t &rand const rand_t &rand
) { ) {
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), mbed::callback(this, &GenericSecurityManager::set_ltk_cb),
connection, cb->db_entry,
ediv, ediv,
rand rand
); );
} }
void GenericSecurityManager::on_ltk_request( /* control blocks list management */
connection_handle_t connection
) { 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( _db.get_entry_local_keys(
mbed::callback(this, &GenericSecurityManager::set_ltk_cb), 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 generic */
} /* namespace ble */ } /* namespace ble */

View File

@ -94,6 +94,8 @@ add_executable(security-manager-tests
mbed_os_stub/mbed_assert.c mbed_os_stub/mbed_assert.c
generic/SecurityManager/mock/MockPalSecurityManager.cpp generic/SecurityManager/mock/MockPalSecurityManager.cpp
generic/SecurityManager/mock/MockPalSecurityDb.cpp generic/SecurityManager/mock/MockPalSecurityDb.cpp
generic/SecurityManager/mock/MockConnectionEventMonitor.cpp
generic/SecurityManager/mock/MockSecurityManagerEventHandler.cpp
${PROJECT_SOURCE_DIR}/../source/generic/GenericSecurityManager.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(); virtual ~MockPalSecurityDb();
MOCK_METHOD1(get_entry, SecurityEntry_t*(connection_handle_t)); MOCK_METHOD1(get_distribution_flags,
const SecurityDistributionFlags_t*(entry_handle_t db_entry));
MOCK_METHOD1(get_entry, SecurityEntry_t*(const address_t &)); MOCK_METHOD2(set_distribution_flags,
void(entry_handle_t db_entry, const SecurityDistributionFlags_t& flags));
MOCK_METHOD4( MOCK_METHOD4(get_entry_local_keys,
get_entry_local_keys, void(SecurityEntryKeysDbCb_t cb, entry_handle_t db_entry, const ediv_t &ediv, const rand_t &rand));
void( MOCK_METHOD2(get_entry_local_keys,
SecurityEntryKeysDbCb_t, void(SecurityEntryKeysDbCb_t cb, entry_handle_t db_entry));
connection_handle_t, MOCK_METHOD2(set_entry_local_ltk,
const ediv_t &, void(entry_handle_t db_entry, const ltk_t &ltk));
const rand_t & 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( MOCK_METHOD2(get_entry_peer_keys,
get_entry_local_keys, void(SecurityEntryKeysDbCb_t cb, entry_handle_t db_entry));
void(SecurityEntryKeysDbCb_t, connection_handle_t) MOCK_METHOD2(set_entry_peer_ltk,
); void(entry_handle_t db_entry, const ltk_t &ltk));
MOCK_METHOD3(set_entry_peer_ediv_rand,
MOCK_METHOD2( void(entry_handle_t db_entry, const ediv_t &ediv, const rand_t &rand));
set_entry_local_ltk, MOCK_METHOD2(set_entry_peer_irk,
void(connection_handle_t, const ltk_t &) 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_METHOD3( MOCK_METHOD2(set_entry_peer_csrk,
set_entry_local_ediv_rand, void(entry_handle_t db_entry, const csrk_t &csrk));
void(connection_handle_t, const ediv_t &, const rand_t &) MOCK_METHOD0(get_local_csrk,
); const csrk_t*());
MOCK_METHOD1(set_local_csrk,
MOCK_METHOD2( void(const csrk_t &csrk));
get_entry_peer_csrk, MOCK_METHOD0(get_public_key_x,
void(SecurityEntryCsrkDbCb_t, connection_handle_t) const public_key_t&());
); MOCK_METHOD0(get_public_key_y,
const public_key_t&());
MOCK_METHOD2( MOCK_METHOD2(set_public_key,
get_entry_peer_keys, void(const public_key_t &public_key_x, const public_key_t &public_key_y));
void(SecurityEntryKeysDbCb_t, connection_handle_t) MOCK_METHOD2(open_entry,
); entry_handle_t(BLEProtocol::AddressType_t peer_address_type, const address_t &peer_address));
MOCK_METHOD1(close_entry,
MOCK_METHOD2( void(entry_handle_t db_entry));
set_entry_peer_ltk, MOCK_METHOD1(remove_entry,
void(connection_handle_t, const ltk_t &) void(const address_t peer_identity_address));
); MOCK_METHOD0(clear_entries,
void());
MOCK_METHOD3( MOCK_METHOD2(get_whitelist,
set_entry_peer_ediv_rand, void(WhitelistDbCb_t cb, ::Gap::Whitelist_t *whitelist));
void(connection_handle_t, const ediv_t &, const rand_t &) MOCK_METHOD2(generate_whitelist_from_bond_table,
); void(WhitelistDbCb_t cb, ::Gap::Whitelist_t *whitelist));
MOCK_METHOD1(set_whitelist,
MOCK_METHOD2( void(const ::Gap::Whitelist_t &whitelist));
set_entry_peer_irk, MOCK_METHOD1(add_whitelist_entry,
void(connection_handle_t, const irk_t &) void(const address_t &address));
); MOCK_METHOD1(remove_whitelist_entry,
void(const address_t &address));
MOCK_METHOD3( MOCK_METHOD0(clear_whitelist,
set_entry_peer_bdaddr, void());
void(connection_handle_t, bool, const address_t &) MOCK_METHOD0(restore,
); void());
MOCK_METHOD0(sync,
MOCK_METHOD2( void());
set_entry_peer_csrk, MOCK_METHOD1(set_restore,
void(connection_handle_t, const csrk_t &) void(bool reload));
);
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));
}; };
} // namespace ble } // 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_ */