Initial implementation of the Security Manager's Privacy feature for Cordio

pull/6932/head
Donatien Garnier 2018-05-11 18:20:39 +01:00
parent b95da8d8c4
commit 3ca3c2db2c
2 changed files with 254 additions and 10 deletions

View File

@ -322,10 +322,35 @@ public:
static bool sm_handler(const wsfMsgHdr_t* msg);
private:
struct PrivacyControlBlock;
struct PrivacyClearResListControlBlock;
struct PrivacyAddDevToResListControlBlock;
struct PrivacyRemoveDevFromResListControlBlock;
void queue_add_device_to_resolving_list(
advertising_peer_address_type_t peer_identity_address_type,
const address_t &peer_identity_address,
const irk_t &peer_irk
);
void queue_remove_device_from_resolving_list(
advertising_peer_address_type_t peer_identity_address_type,
const address_t &peer_identity_address
);
void queue_clear_resolving_list();
void clear_privacy_control_blocks();
void queue_privacy_control_block(PrivacyControlBlock* block);
void process_privacy_control_blocks(bool cb_completed);
bool _use_default_passkey;
passkey_num_t _default_passkey;
bool _lesc_keys_generated;
uint8_t _public_key_x[SEC_ECC_KEY_LEN];
PrivacyControlBlock* _pending_privacy_control_blocks;
bool _processing_privacy_control_block;
};
} // cordio

View File

@ -22,6 +22,7 @@
#include "att_api.h"
#include "smp_api.h"
#include "wsf_os.h"
#include "hci_core.h"
namespace ble {
namespace pal {
@ -33,14 +34,16 @@ CordioSecurityManager::CordioSecurityManager() :
_use_default_passkey(false),
_default_passkey(0),
_lesc_keys_generated(false),
_public_key_x()
_public_key_x(),
_pending_privacy_control_blocks(NULL),
_processing_privacy_control_block(false)
{
}
CordioSecurityManager::~CordioSecurityManager()
{
clear_privacy_control_blocks();
}
////////////////////////////////////////////////////////////////////////////
@ -80,31 +83,57 @@ ble_error_t CordioSecurityManager::reset()
uint8_t CordioSecurityManager::read_resolving_list_capacity()
{
// FIXME: Implement with privacy support.
return 0;
// The Cordio stack requests this from the controller during initialization
return hciCoreCb.resListSize;
}
// As the Cordio stack can only handle one of these methods at a time, we need to create a list of control blocks
// that are dequeued one after the other on completion of the previous one
ble_error_t CordioSecurityManager::add_device_to_resolving_list(
advertising_peer_address_type_t peer_identity_address_type,
const address_t &peer_identity_address,
const irk_t &peer_irk
) {
// FIXME: Implement with privacy support.
return BLE_ERROR_NOT_IMPLEMENTED;
if( read_resolving_list_capacity() == 0 )
{
// If 0 is returned as capacity, it means the controller does not support resolving addresses
return BLE_ERROR_NOT_IMPLEMENTED;
}
// Queue control block
queue_add_device_to_resolving_list(peer_identity_address_type, peer_identity_address, peer_irk);
return BLE_ERROR_NONE;
}
ble_error_t CordioSecurityManager::remove_device_from_resolving_list(
advertising_peer_address_type_t peer_identity_address_type,
const address_t& peer_identity_address
) {
// FIXME: Implement with privacy support.
return BLE_ERROR_NOT_IMPLEMENTED;
if( read_resolving_list_capacity() == 0 )
{
// If 0 is returned as capacity, it means the controller does not support resolving addresses
return BLE_ERROR_NOT_IMPLEMENTED;
}
// Queue control block
queue_remove_device_from_resolving_list(peer_identity_address_type, peer_identity_address);
return BLE_ERROR_NONE;
}
ble_error_t CordioSecurityManager::clear_resolving_list()
{
// FIXME: Implement with privacy support.
return BLE_ERROR_NOT_IMPLEMENTED;
if( read_resolving_list_capacity() == 0 )
{
// If 0 is returned as capacity, it means the controller does not support resolving addresses
return BLE_ERROR_NOT_IMPLEMENTED;
}
// Queue control block
queue_clear_resolving_list();
return BLE_ERROR_NONE;
}
////////////////////////////////////////////////////////////////////////////
@ -686,11 +715,201 @@ bool CordioSecurityManager::sm_handler(const wsfMsgHdr_t* msg) {
return true;
}
// Privacy
case DM_PRIV_ADD_DEV_TO_RES_LIST_IND: // Device added to resolving list
case DM_PRIV_REM_DEV_FROM_RES_LIST_IND: // Device removed from resolving list
case DM_PRIV_CLEAR_RES_LIST_IND: // Resolving list cleared
{
// Previous command completed, we can move to the next control block
self.process_privacy_control_blocks(true);
return true;
}
default:
return false;
}
}
struct CordioSecurityManager::PrivacyControlBlock
{
PrivacyControlBlock() : _next(NULL) {}
virtual ~PrivacyControlBlock() {}
virtual void execute() = 0;
void set_next(PrivacyControlBlock* next) {
_next = next;
}
PrivacyControlBlock* next() const {
return _next;
}
private:
PrivacyControlBlock* _next;
};
struct CordioSecurityManager::PrivacyClearResListControlBlock : CordioSecurityManager::PrivacyControlBlock
{
PrivacyClearResListControlBlock() : PrivacyControlBlock()
{}
virtual ~PrivacyClearResListControlBlock() {}
virtual void execute() {
// Execute command
DmPrivClearResList();
}
};
struct CordioSecurityManager::PrivacyAddDevToResListControlBlock : CordioSecurityManager::PrivacyControlBlock
{
PrivacyAddDevToResListControlBlock(
advertising_peer_address_type_t peer_identity_address_type,
const address_t &peer_identity_address,
const irk_t &peer_irk
) : PrivacyControlBlock(),
_peer_identity_address_type(peer_identity_address_type),
_peer_identity_address(peer_identity_address),
_peer_irk(peer_irk)
{}
virtual ~PrivacyAddDevToResListControlBlock() {}
virtual void execute() {
// Check whether we need to enable resolution in LL
bool enable_ll_resolving = DmLlPrivEnabled();
// Execute command
DmPrivAddDevToResList(_peer_identity_address_type.value(), _peer_identity_address.data(), _peer_irk.data(), DmSecGetLocalIrk(), enable_ll_resolving, 0);
}
private:
advertising_peer_address_type_t _peer_identity_address_type;
address_t _peer_identity_address;
irk_t _peer_irk;
};
struct CordioSecurityManager::PrivacyRemoveDevFromResListControlBlock : CordioSecurityManager::PrivacyControlBlock
{
PrivacyRemoveDevFromResListControlBlock(
advertising_peer_address_type_t peer_identity_address_type,
const address_t &peer_identity_address
) : PrivacyControlBlock(),
_peer_identity_address_type(peer_identity_address_type),
_peer_identity_address(peer_identity_address)
{
}
virtual ~PrivacyRemoveDevFromResListControlBlock() {}
virtual void execute() {
// Execute command
DmPrivRemDevFromResList(_peer_identity_address_type.value(), _peer_identity_address.data(), 0);
}
private:
advertising_peer_address_type_t _peer_identity_address_type;
address_t _peer_identity_address;
};
// Helper functions for privacy
void CordioSecurityManager::queue_add_device_to_resolving_list(
advertising_peer_address_type_t peer_identity_address_type,
const address_t &peer_identity_address,
const irk_t &peer_irk
)
{
PrivacyAddDevToResListControlBlock* cb =
new (std::nothrow) PrivacyAddDevToResListControlBlock(peer_identity_address_type, peer_identity_address, peer_irk);
if( cb == NULL )
{
return;
}
queue_privacy_control_block(cb);
}
void CordioSecurityManager::queue_remove_device_from_resolving_list(
advertising_peer_address_type_t peer_identity_address_type,
const address_t &peer_identity_address
)
{
PrivacyRemoveDevFromResListControlBlock* cb =
new (std::nothrow) PrivacyRemoveDevFromResListControlBlock(peer_identity_address_type, peer_identity_address);
if( cb == NULL )
{
return;
}
queue_privacy_control_block(cb);
}
void CordioSecurityManager::queue_clear_resolving_list() {
// Remove any pending control blocks, there's no point executing them as we're about to queue the list
clear_privacy_control_blocks();
PrivacyClearResListControlBlock* cb =
new (std::nothrow) PrivacyClearResListControlBlock();
if( cb == NULL )
{
return;
}
queue_privacy_control_block(cb);
}
void CordioSecurityManager::clear_privacy_control_blocks() {
while(_pending_privacy_control_blocks != NULL)
{
PrivacyControlBlock* next = _pending_privacy_control_blocks->next();
delete _pending_privacy_control_blocks;
_pending_privacy_control_blocks = next;
}
}
void CordioSecurityManager::queue_privacy_control_block(PrivacyControlBlock* block)
{
if( _pending_privacy_control_blocks == NULL ) {
_pending_privacy_control_blocks = block;
}
else {
PrivacyControlBlock* node = _pending_privacy_control_blocks;
while(node->next() != NULL) {
node = node->next();
}
node->set_next(block);
}
process_privacy_control_blocks(false);
}
// Can be called with msg set to NULL
void CordioSecurityManager::process_privacy_control_blocks(bool cb_completed)
{
if( (_processing_privacy_control_block == true) && !cb_completed )
{
// Busy, cannot process next control block for now
return;
}
PrivacyControlBlock* cb = _pending_privacy_control_blocks;
if(cb == NULL) {
// All control blocks processed
_processing_privacy_control_block = false;
return;
}
// Process next block and free it
_processing_privacy_control_block = true;
PrivacyControlBlock* next = cb->next();
cb->execute();
delete cb;
_pending_privacy_control_blocks = next;
}
} // cordio
} // vendor