BLE: Move security DB into PAL.

pull/6188/head
Vincent Coubard 2018-02-19 14:43:56 +00:00
parent c7672994d2
commit 15cfcba16a
3 changed files with 428 additions and 397 deletions

View File

@ -19,7 +19,7 @@
#include "ble/pal/GapTypes.h"
#include "ble/BLETypes.h"
#include "ble/generic/GenericSecurityDb.h"
#include "ble/pal/SecurityDb.h"
#include "platform/Callback.h"
#include "ble/Gap.h"
#include "ble/pal/PalSecurityManager.h"
@ -39,6 +39,9 @@ class GenericSecurityManagerEventHandler;
class GenericSecurityManager : public SecurityManager,
public pal::SecurityManagerEventHandler {
public:
typedef ble::pal::SecurityEntry_t SecurityEntry_t;
typedef ble::pal::SecurityEntryKeys_t SecurityEntryKeys_t;
/* implements SecurityManager */
////////////////////////////////////////////////////////////////////////////
@ -231,7 +234,7 @@ public:
public:
GenericSecurityManager(
ble::pal::SecurityManager &palImpl,
GenericSecurityDb &dbImpl,
ble::pal::SecurityDb &dbImpl,
Gap &gapImpl
) : _pal(palImpl),
_db(dbImpl),
@ -424,7 +427,7 @@ private:
private:
ble::pal::SecurityManager &_pal;
GenericSecurityDb &_db;
ble::pal::SecurityDb &_db;
Gap &_gap;
AuthenticationMask _default_authentication;

View File

@ -0,0 +1,414 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef PAL_MEMORY_SECURITY_MANAGER_DB_H__
#define PAL_MEMORY_SECURITY_MANAGER_DB_H__
#include "SecurityDB.h"
namespace ble {
namespace pal {
/* naive memory implementation for verification
* TODO: make thread safe */
class MemorySecurityDb : public SecurityDb {
private:
struct db_store_t {
db_store_t() { };
SecurityEntry_t entry;
SecurityEntryKeys_t peer_keys;
SecurityEntryKeys_t local_keys;
csrk_t csrk;
};
static const size_t MAX_ENTRIES = 5;
public:
MemorySecurityDb() { };
virtual ~MemorySecurityDb() { };
virtual SecurityEntry_t* get_entry(
connection_handle_t connection
) {
SecurityEntry_t *entry = NULL;
db_store_t *store = get_store(connection);
if (store) {
entry = &store->entry;
}
return entry;
}
virtual SecurityEntry_t* get_entry(
const address_t &peer_address
) {
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;
}
}
return entry;
}
/* local keys */
/* get */
virtual void get_entry_local_keys(
SecurityEntryKeysDbCb_t cb,
connection_handle_t connection,
const ediv_t &ediv,
const rand_t &rand
) {
SecurityEntry_t *entry = NULL;
db_store_t *store = get_store(connection);
if (store) {
entry = &store->entry;
}
/* validate we have the correct key */
if (ediv == store->local_keys.ediv
&& rand == store->local_keys.rand) {
cb(entry, &store->local_keys);
} else {
cb(entry, NULL);
}
}
virtual void get_entry_local_keys(
SecurityEntryKeysDbCb_t cb,
connection_handle_t connection
) {
SecurityEntry_t *entry = NULL;
db_store_t *store = get_store(connection);
if (store) {
entry = &store->entry;
}
/* validate we have the correct key */
if (entry->secure_connections_paired) {
cb(entry, &store->local_keys);
} else {
cb(entry, NULL);
}
}
/* set */
virtual void set_entry_local_ltk(
connection_handle_t connection,
const ltk_t &ltk
) {
db_store_t *store = get_store(connection);
if (store) {
store->local_keys.ltk = ltk;
}
}
virtual void set_entry_local_ediv_rand(
connection_handle_t connection,
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;
}
}
/* peer's keys */
/* get */
virtual void get_entry_peer_csrk(
SecurityEntryCsrkDbCb_t cb,
connection_handle_t connection
) {
SecurityEntry_t *entry = NULL;
csrk_t csrk;
db_store_t *store = get_store(connection);
if (store) {
entry = &store->entry;
csrk = store->csrk;
}
cb(entry->handle, &csrk);
}
virtual void get_entry_peer_keys(
SecurityEntryKeysDbCb_t cb,
connection_handle_t connection
) {
SecurityEntry_t *entry = NULL;
SecurityEntryKeys_t *key = NULL;
db_store_t *store = get_store(connection);
if (store) {
entry = &store->entry;
key = &store->peer_keys;
}
cb(entry, key);
}
/* set */
virtual void set_entry_peer_ltk(
connection_handle_t connection,
const ltk_t &ltk
) {
db_store_t *store = get_store(connection);
if (store) {
store->peer_keys.ltk = ltk;
}
}
virtual void set_entry_peer_ediv_rand(
connection_handle_t connection,
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;
}
}
virtual void set_entry_peer_irk(
connection_handle_t connection,
const irk_t &irk
) {
db_store_t *store = get_store(connection);
if (store) {
size_t index = store - _db;
_identities[index].irk = irk;
}
}
virtual void set_entry_peer_bdaddr(
connection_handle_t connection,
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;
}
}
virtual void set_entry_peer_csrk(
connection_handle_t connection,
const csrk_t &csrk
) {
db_store_t *store = get_store(connection);
if (store) {
store->csrk = csrk;
}
}
/* local csrk */
virtual const csrk_t* get_local_csrk() {
return &_local_csrk;
}
virtual void set_local_csrk(const csrk_t &csrk) {
_local_csrk = csrk;
}
/* public key */
virtual const public_key_t& get_public_key_x() {
return _public_key_x;
}
virtual const public_key_t& get_public_key_y() {
return _public_key_y;
}
virtual void set_public_key(
const public_key_t &public_key_x,
const public_key_t &public_key_y
) {
_public_key_x = public_key_x;
_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,
BLEProtocol::AddressType_t peer_address_type,
const address_t &peer_address,
const address_t &local_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) {
continue;
} else if (peer_address == _identities[i].identity_address
&& _db[i].entry.peer_address_is_public == peer_address_public) {
return &_db[i].entry;
}
}
/* 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;
}
}
return NULL;
}
virtual void disconnect_entry(connection_handle_t connection) { }
virtual void remove_entry(address_t peer_identity_address) { }
virtual void clear_entries() {
for (size_t i = 0; i < MAX_ENTRIES; i++) {
_db[i] = db_store_t();
}
_local_identity = SecurityEntryIdentity_t();
_local_csrk = csrk_t();
}
virtual void get_whitelist(WhitelistDbCb_t cb, Gap::Whitelist_t *whitelist) {
/*TODO: fill whitelist*/
cb(whitelist);
}
virtual void generate_whitelist_from_bond_table(WhitelistDbCb_t cb, Gap::Whitelist_t *whitelist) {
for (size_t i = 0; i < MAX_ENTRIES && i < whitelist->capacity; i++) {
if (_db[i].entry.peer_address_is_public) {
whitelist->addresses[i].type = BLEProtocol::AddressType::PUBLIC;
} else {
whitelist->addresses[i].type = BLEProtocol::AddressType::RANDOM_STATIC;
}
memcpy(
whitelist->addresses[i].address,
_identities[i].identity_address.data(),
sizeof(BLEProtocol::AddressBytes_t)
);
}
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) { }
virtual void remove_whitelist_entry(const address_t &address) { }
virtual void clear_whitelist() { }
/* saving and loading from nvm */
virtual void restore() { }
virtual void sync() { }
virtual void set_restore(bool reload) { }
private:
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;
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__*/

View File

@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef __GENERIC_SECURITY_MANAGER_DB_H__
#define __GENERIC_SECURITY_MANAGER_DB_H__
#ifndef PAL_SECURITY_MANAGER_DB_H__
#define PAL_SECURITY_MANAGER_DB_H__
#include "platform/Callback.h"
#include "ble/pal/GapTypes.h"
@ -23,7 +23,7 @@
#include <stdlib.h>
namespace ble {
namespace generic {
namespace pal {
using pal::connection_peer_address_type_t;
@ -136,10 +136,10 @@ typedef mbed::Callback<void(Gap::Whitelist_t*)> WhitelistDbCb_t;
* the store in a consistent state.
* Active connections state must be returned immediately.
*/
class GenericSecurityDb {
class SecurityDb {
public:
GenericSecurityDb() { };
virtual ~GenericSecurityDb() { };
SecurityDb() { };
virtual ~SecurityDb() { };
/**
* Return immediately security entry containing the state
@ -543,393 +543,7 @@ public:
virtual void set_restore(bool reload) = 0;
};
/* naive memory implementation for verification
* TODO: make thread safe */
class MemoryGenericSecurityDb : public GenericSecurityDb {
private:
struct db_store_t {
db_store_t() { };
SecurityEntry_t entry;
SecurityEntryKeys_t peer_keys;
SecurityEntryKeys_t local_keys;
csrk_t csrk;
};
static const size_t MAX_ENTRIES = 5;
public:
MemoryGenericSecurityDb() { };
virtual ~MemoryGenericSecurityDb() { };
virtual SecurityEntry_t* get_entry(
connection_handle_t connection
) {
SecurityEntry_t *entry = NULL;
db_store_t *store = get_store(connection);
if (store) {
entry = &store->entry;
}
return entry;
}
virtual SecurityEntry_t* get_entry(
const address_t &peer_address
) {
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;
}
}
return entry;
}
/* local keys */
/* get */
virtual void get_entry_local_keys(
SecurityEntryKeysDbCb_t cb,
connection_handle_t connection,
const ediv_t &ediv,
const rand_t &rand
) {
SecurityEntry_t *entry = NULL;
db_store_t *store = get_store(connection);
if (store) {
entry = &store->entry;
}
/* validate we have the correct key */
if (ediv == store->local_keys.ediv
&& rand == store->local_keys.rand) {
cb(entry, &store->local_keys);
} else {
cb(entry, NULL);
}
}
virtual void get_entry_local_keys(
SecurityEntryKeysDbCb_t cb,
connection_handle_t connection
) {
SecurityEntry_t *entry = NULL;
db_store_t *store = get_store(connection);
if (store) {
entry = &store->entry;
}
/* validate we have the correct key */
if (entry->secure_connections_paired) {
cb(entry, &store->local_keys);
} else {
cb(entry, NULL);
}
}
/* set */
virtual void set_entry_local_ltk(
connection_handle_t connection,
const ltk_t &ltk
) {
db_store_t *store = get_store(connection);
if (store) {
store->local_keys.ltk = ltk;
}
}
virtual void set_entry_local_ediv_rand(
connection_handle_t connection,
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;
}
}
/* peer's keys */
/* get */
virtual void get_entry_peer_csrk(
SecurityEntryCsrkDbCb_t cb,
connection_handle_t connection
) {
SecurityEntry_t *entry = NULL;
csrk_t csrk;
db_store_t *store = get_store(connection);
if (store) {
entry = &store->entry;
csrk = store->csrk;
}
cb(entry->handle, &csrk);
}
virtual void get_entry_peer_keys(
SecurityEntryKeysDbCb_t cb,
connection_handle_t connection
) {
SecurityEntry_t *entry = NULL;
SecurityEntryKeys_t *key = NULL;
db_store_t *store = get_store(connection);
if (store) {
entry = &store->entry;
key = &store->peer_keys;
}
cb(entry, key);
}
/* set */
virtual void set_entry_peer_ltk(
connection_handle_t connection,
const ltk_t &ltk
) {
db_store_t *store = get_store(connection);
if (store) {
store->peer_keys.ltk = ltk;
}
}
virtual void set_entry_peer_ediv_rand(
connection_handle_t connection,
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;
}
}
virtual void set_entry_peer_irk(
connection_handle_t connection,
const irk_t &irk
) {
db_store_t *store = get_store(connection);
if (store) {
size_t index = store - _db;
_identities[index].irk = irk;
}
}
virtual void set_entry_peer_bdaddr(
connection_handle_t connection,
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;
}
}
virtual void set_entry_peer_csrk(
connection_handle_t connection,
const csrk_t &csrk
) {
db_store_t *store = get_store(connection);
if (store) {
store->csrk = csrk;
}
}
/* local csrk */
virtual const csrk_t* get_local_csrk() {
return &_local_csrk;
}
virtual void set_local_csrk(const csrk_t &csrk) {
_local_csrk = csrk;
}
/* public key */
virtual const public_key_t& get_public_key_x() {
return _public_key_x;
}
virtual const public_key_t& get_public_key_y() {
return _public_key_y;
}
virtual void set_public_key(
const public_key_t &public_key_x,
const public_key_t &public_key_y
) {
_public_key_x = public_key_x;
_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,
BLEProtocol::AddressType_t peer_address_type,
const address_t &peer_address,
const address_t &local_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) {
continue;
} else if (peer_address == _identities[i].identity_address
&& _db[i].entry.peer_address_is_public == peer_address_public) {
return &_db[i].entry;
}
}
/* 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;
}
}
return NULL;
}
virtual void disconnect_entry(connection_handle_t connection) { }
virtual void remove_entry(address_t peer_identity_address) { }
virtual void clear_entries() {
for (size_t i = 0; i < MAX_ENTRIES; i++) {
_db[i] = db_store_t();
}
_local_identity = SecurityEntryIdentity_t();
_local_csrk = csrk_t();
}
virtual void get_whitelist(WhitelistDbCb_t cb, Gap::Whitelist_t *whitelist) {
/*TODO: fill whitelist*/
cb(whitelist);
}
virtual void generate_whitelist_from_bond_table(WhitelistDbCb_t cb, Gap::Whitelist_t *whitelist) {
for (size_t i = 0; i < MAX_ENTRIES && i < whitelist->capacity; i++) {
if (_db[i].entry.peer_address_is_public) {
whitelist->addresses[i].type = BLEProtocol::AddressType::PUBLIC;
} else {
whitelist->addresses[i].type = BLEProtocol::AddressType::RANDOM_STATIC;
}
memcpy(
whitelist->addresses[i].address,
_identities[i].identity_address.data(),
sizeof(BLEProtocol::AddressBytes_t)
);
}
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) { }
virtual void remove_whitelist_entry(const address_t &address) { }
virtual void clear_whitelist() { }
/* saving and loading from nvm */
virtual void restore() { }
virtual void sync() { }
virtual void set_restore(bool reload) { }
private:
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;
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 generic */
} /* namespace pal */
} /* namespace ble */
#endif /*__GENERIC_SECURITY_MANAGER_DB_H__*/
#endif /*PAL_SECURITY_MANAGER_DB_H__*/