GAP integration for connection and disconnection events

pull/6188/head
paul-szczepanek-arm 2018-02-09 16:35:16 +00:00
parent e7cf1529ec
commit 18062fc9de
3 changed files with 154 additions and 122 deletions

View File

@ -41,16 +41,16 @@ struct SecurityEntry_t {
SecurityEntry_t()
: handle(0),
encryption_key_size(0),
peer_address_public(false),
local_address_public(false),
peer_address_is_public(false),
local_address_is_public(false),
csrk_stored(false),
mitm_csrk(false),
csrk_mitm_protected(false),
ltk_stored(false),
mitm_ltk(false),
secure_connections(false),
ltk_mitm_protected(false),
secure_connections_paired(false),
connected(false),
authenticated(false),
master(false),
is_master(false),
encryption_requested(false),
encryption_failed(false),
encrypted(false),
@ -65,14 +65,20 @@ struct SecurityEntry_t {
* Reset state of the connection when disconnected.
*/
void reset() {
mitm_requested = false;
mitm_performed = false;
local_address = address_t();
connected = true;
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;
@ -80,21 +86,24 @@ struct SecurityEntry_t {
connection_handle_t handle;
address_t peer_address;
uint8_t encryption_key_size;
uint8_t peer_address_public:1;
uint8_t local_address_public:1;
uint8_t peer_address_is_public:1;
uint8_t local_address_is_public:1;
uint8_t csrk_stored:1;
uint8_t mitm_csrk:1;
uint8_t csrk_mitm_protected:1;
uint8_t ltk_stored:1;
uint8_t mitm_ltk:1;
uint8_t secure_connections:1;
uint8_t ltk_mitm_protected:1;
uint8_t secure_connections_paired:1;
/* do not store in NVM */
address_t local_address; /**< address used for connection, possibly different from identity */
uint8_t connected:1;
uint8_t authenticated:1; /**< have we turned encryption on during this connection */
uint8_t master:1;
uint8_t is_master:1;
uint8_t encryption_requested:1;
uint8_t encryption_failed:1;
@ -444,8 +453,9 @@ public:
*/
virtual SecurityEntry_t* connect_entry(
connection_handle_t connection,
connection_peer_address_type_t::type peer_address_type,
const address_t& peer_address
BLEProtocol::AddressType_t peer_address_type,
const address_t& peer_address,
const address_t& local_address
) = 0;
/**
@ -830,17 +840,18 @@ public:
virtual SecurityEntry_t* connect_entry(
connection_handle_t connection,
connection_peer_address_type_t::type peer_address_type,
const address_t& peer_address
BLEProtocol::AddressType_t peer_address_type,
const address_t& peer_address,
const address_t& local_address
) {
const bool peer_address_public =
(peer_address_type == connection_peer_address_type_t::PUBLIC_ADDRESS);
(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_public == peer_address_public) {
&& _db[i].entry.peer_address_is_public == peer_address_public) {
return &_db[i].entry;
}
}
@ -850,8 +861,9 @@ public:
if (!_db[i].entry.connected) {
_db[i] = db_store_t();
_identities[i] = SecurityEntryIdentity_t();
_identities[i].identity_address = peer_address;
_db[i].entry.peer_address_public = peer_address_public;
_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;
}
}
@ -878,7 +890,7 @@ public:
virtual void generate_whitelist_from_bond_table(WhitelistDbCb_t cb, Gap::Whitelist_t *whitelist) {
for (size_t i = 0; i < MAX_ENTRIES && i < whitelist->capacity; i++) {
if (_db[i].entry.peer_address_public) {
if (_db[i].entry.peer_address_is_public) {
whitelist->addresses[i].type = BLEProtocol::AddressType::PUBLIC;
} else {
whitelist->addresses[i].type = BLEProtocol::AddressType::RANDOM_STATIC;

View File

@ -21,6 +21,7 @@
#include "ble/BLETypes.h"
#include "ble/generic/GenericSecurityDb.h"
#include "Callback.h"
#include "ble/Gap.h"
namespace ble {
namespace generic {
@ -47,39 +48,6 @@ class GenericSecurityManagerEventHandler;
class GenericSecurityManager : public SecurityManager,
public ble::pal::SecurityManagerEventHandler {
public:
////////////////////////////////////////////////////////////////////////////
// GAP integration
//
/**
* Inform the security manager that a device has been disconnected and its
* entry can be put in NVM storage. Called by GAP.
*
* @param[in] connectionHandle Handle to identify the connection.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual void disconnected(
connection_handle_t connection
);
/**
* Inform the Security manager of a new connection. This will create
* or retrieve an existing security manager entry for the connected device.
* Called by GAP.
*
* @param[in] connectionHandle Handle to identify the connection.
* @param[in] is_master True if device is the master.
* @param[in] peer_address_type type of address
* @param[in] peer_address Address of the connected device.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
virtual void connected(
connection_handle_t connection,
bool is_master,
connection_peer_address_type_t::type peer_address_type,
const address_t &peer_address
);
/* implements SecurityManager */
////////////////////////////////////////////////////////////////////////////
@ -270,9 +238,10 @@ public:
/* ends implements SecurityManager */
protected:
GenericSecurityManager(ble::pal::SecurityManager& palImpl, GenericSecurityDb& dbImpl)
GenericSecurityManager(ble::pal::SecurityManager& palImpl, GenericSecurityDb& dbImpl, Gap& gapImpl)
: _pal(palImpl),
_db(dbImpl),
_gap(gapImpl),
_default_authentication(0),
_default_key_distribution(KeyDistribution::KEY_DISTRIBUTION_ALL),
_pairing_authorisation_required(false),
@ -394,9 +363,48 @@ private:
);
#endif
/**
* Inform the security manager that a device has been disconnected and its
* entry can be put in NVM storage. Called by GAP.
*
* @param[in] connectionHandle Handle to identify the connection.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
void on_disconnected(
connection_handle_t connection
);
/**
* Inform the Security manager of a new connection. This will create
* or retrieve an existing security manager entry for the connected device.
* Called by GAP.
*
* @param[in] connectionHandle Handle to identify the connection.
* @param[in] is_master True if device is the master.
* @param[in] peer_address_type type of address
* @param[in] peer_address Address of the connected device.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
void on_connected(
connection_handle_t connection,
bool is_master,
BLEProtocol::AddressType_t peer_address_type,
const address_t &peer_address,
const address_t &local_address
);
void connection_callback(
const Gap::ConnectionCallbackParams_t* params
);
void disconnection_callback(
const Gap::DisconnectionCallbackParams_t* params
);
private:
ble::pal::SecurityManager& _pal;
GenericSecurityDb& _db;
Gap& _gap;
AuthenticationMask _default_authentication;
KeyDistribution _default_key_distribution;

View File

@ -26,39 +26,6 @@ namespace generic {
/* Implements SecurityManager */
////////////////////////////////////////////////////////////////////////////
// GAP integration
//
void GenericSecurityManager::disconnected(connection_handle_t connection) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
return;
}
entry->connected = false;
_db.sync();
}
void GenericSecurityManager::connected(
connection_handle_t connection,
bool is_master,
connection_peer_address_type_t::type peer_address_type,
const address_t &peer_address
) {
SecurityEntry_t *entry = _db.connect_entry(
connection,
peer_address_type,
peer_address
);
if (!entry) {
return;
}
entry->reset();
entry->master = is_master;
}
////////////////////////////////////////////////////////////////////////////
// SM lifecycle management
//
@ -88,6 +55,9 @@ ble_error_t GenericSecurityManager::init(
init_signing();
}
_gap.onConnection(this, &GenericSecurityManager::connection_callback);
_gap.onDisconnection(this, &GenericSecurityManager::disconnection_callback);
_pal.generate_public_key();
return BLE_ERROR_NONE;
@ -135,10 +105,6 @@ ble_error_t GenericSecurityManager::requestPairing(connection_handle_t connectio
return BLE_ERROR_INVALID_PARAM;
}
/* TODO: remove */
_db.get_entry(connection)->master = true;
/* end temp code */
if (!_legacy_pairing_allowed && !_default_authentication.get_secure_connections()) {
return BLE_ERROR_OPERATION_NOT_PERMITTED;
}
@ -291,7 +257,7 @@ ble_error_t GenericSecurityManager::enableSigning(
}
if (!entry->csrk_stored && entry->signing_requested) {
init_signing();
if (entry->master) {
if (entry->is_master) {
return requestPairing(connection);
} else {
return slave_security_request(connection);
@ -321,7 +287,7 @@ ble_error_t GenericSecurityManager::getLinkEncryption(
}
if (entry->encrypted) {
if (entry->mitm_ltk) {
if (entry->ltk_mitm_protected) {
*encryption = link_encryption_t::ENCRYPTED_WITH_MITM;
} else {
*encryption = link_encryption_t::ENCRYPTED;
@ -373,7 +339,7 @@ ble_error_t GenericSecurityManager::setLinkEncryption(
} else if (encryption == link_encryption_t::ENCRYPTED_WITH_MITM) {
if (entry->mitm_ltk && !entry->encrypted) {
if (entry->ltk_mitm_protected && !entry->encrypted) {
entry->encryption_requested = true;
return enable_encryption(connection);
} else {
@ -418,7 +384,7 @@ ble_error_t GenericSecurityManager::getSigningKey(connection_handle_t connection
return BLE_ERROR_INVALID_PARAM;
}
if (entry->csrk_stored && (entry->mitm_csrk || !authenticated)) {
if (entry->csrk_stored && (entry->csrk_mitm_protected || !authenticated)) {
/* we have a key that is either authenticated or we don't care if it is
* so retrieve it from the db now */
_db.get_entry_peer_csrk(
@ -432,7 +398,7 @@ ble_error_t GenericSecurityManager::getSigningKey(connection_handle_t connection
* keys exchange will create the signingKey event */
if (authenticated) {
return requestAuthentication(connection);
} else if (entry->master) {
} else if (entry->is_master) {
return requestPairing(connection);
} else {
return slave_security_request(connection);
@ -458,7 +424,7 @@ ble_error_t GenericSecurityManager::requestAuthentication(connection_handle_t co
return BLE_ERROR_INVALID_PARAM;
}
if (entry->mitm_ltk) {
if (entry->ltk_mitm_protected) {
if (entry->authenticated) {
return BLE_ERROR_NONE;
} else {
@ -467,7 +433,7 @@ ble_error_t GenericSecurityManager::requestAuthentication(connection_handle_t co
}
} else {
entry->mitm_requested = true;
if (entry->master) {
if (entry->is_master) {
return requestPairing(connection);
} else {
return slave_security_request(connection);
@ -612,7 +578,7 @@ ble_error_t GenericSecurityManager::enable_encryption(connection_handle_t connec
if (!entry) {
return BLE_ERROR_INVALID_PARAM;
}
if (entry->master) {
if (entry->is_master) {
if (entry->ltk_stored) {
_db.get_entry_peer_keys(
mbed::callback(this, &GenericSecurityManager::enable_encryption_cb),
@ -661,7 +627,7 @@ void GenericSecurityManager::return_csrk_cb(
eventHandler->signingKey(
connection,
csrk,
entry->mitm_csrk
entry->csrk_mitm_protected
);
}
@ -669,11 +635,13 @@ void GenericSecurityManager::return_csrk_cb(
void GenericSecurityManager::generate_secure_connections_oob(
connection_handle_t connection
) {
address_t local_address;
oob_confirm_t confirm;
oob_rand_t random;
/*TODO: get local address*/
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
return;
}
ble_error_t ret = get_random_data(random.buffer(), random.size());
if (ret != BLE_ERROR_NONE) {
@ -688,7 +656,7 @@ void GenericSecurityManager::generate_secure_connections_oob(
);
_app_event_handler->oobGenerated(
&local_address,
&entry->local_address,
&random,
&confirm
);
@ -748,6 +716,54 @@ bool GenericSecurityManager::crypto_toolbox_f4(
}
#endif
void GenericSecurityManager::on_disconnected(connection_handle_t connection) {
SecurityEntry_t *entry = _db.get_entry(connection);
if (!entry) {
return;
}
entry->connected = false;
_db.sync();
}
void GenericSecurityManager::on_connected(
connection_handle_t connection,
bool is_master,
BLEProtocol::AddressType_t peer_address_type,
const address_t &peer_address,
const address_t &local_address
) {
SecurityEntry_t *entry = _db.connect_entry(
connection,
peer_address_type,
peer_address,
local_address
);
if (!entry) {
return;
}
entry->reset();
entry->is_master = is_master;
}
void GenericSecurityManager::connection_callback(
const Gap::ConnectionCallbackParams_t* params
) {
on_connected(
params->handle,
(params->role == Gap::CENTRAL),
params->peerAddrType,
address_t(params->peerAddr),
address_t(params->ownAddr)
);
}
void GenericSecurityManager::disconnection_callback(
const Gap::DisconnectionCallbackParams_t* params
) {
on_disconnected(params->handle);
}
/* Implements ble::pal::SecurityManagerEventHandler */
////////////////////////////////////////////////////////////////////////////
@ -761,10 +777,6 @@ void GenericSecurityManager::on_pairing_request(
KeyDistribution initiator_dist,
KeyDistribution responder_dist
) {
/* TODO: remove */
_db.get_entry(connection)->master = false;
/* end temp code */
/* cancel pairing if secure connection paring is not possible */
if (!_legacy_pairing_allowed && !authentication.get_secure_connections()) {
canceltPairingRequest(connection);
@ -816,8 +828,8 @@ void GenericSecurityManager::on_pairing_completed(connection_handle_t connection
}
/* sc doesn't need to exchange ltk */
if (entry->secure_connections) {
entry->mitm_ltk = entry->mitm_performed;
if (entry->secure_connections_paired) {
entry->ltk_mitm_protected = entry->mitm_performed;
}
}
@ -846,12 +858,12 @@ void GenericSecurityManager::on_slave_security_request(
if (authentication.get_secure_connections()
&& _default_authentication.get_secure_connections()
&& !entry->secure_connections) {
&& !entry->secure_connections_paired) {
requestPairing(connection);
}
if (authentication.get_mitm()
&& !entry->mitm_ltk) {
&& !entry->ltk_mitm_protected) {
entry->mitm_requested = true;
requestPairing(connection);
}
@ -1006,8 +1018,8 @@ void GenericSecurityManager::on_secure_connections_ltk_generated(
return;
}
entry->mitm_ltk = entry->mitm_performed;
entry->secure_connections = true;
entry->ltk_mitm_protected = entry->mitm_performed;
entry->secure_connections_paired = true;
_db.set_entry_peer_ltk(connection, ltk);
}
@ -1027,8 +1039,8 @@ void GenericSecurityManager::on_keys_distributed(
return;
}
entry->mitm_ltk = entry->mitm_performed;
entry->mitm_csrk = entry->mitm_performed;
entry->ltk_mitm_protected = entry->mitm_performed;
entry->csrk_mitm_protected = entry->mitm_performed;
_db.set_entry_peer(
connection,
@ -1044,7 +1056,7 @@ void GenericSecurityManager::on_keys_distributed(
eventHandler->signingKey(
connection,
csrk,
entry->mitm_csrk
entry->csrk_mitm_protected
);
}
@ -1056,7 +1068,7 @@ void GenericSecurityManager::on_keys_distributed_ltk(
if (!entry) {
return;
}
entry->mitm_ltk = entry->mitm_performed;
entry->ltk_mitm_protected = entry->mitm_performed;
_db.set_entry_peer_ltk(connection, ltk);
}
@ -1111,14 +1123,14 @@ void GenericSecurityManager::on_keys_distributed_csrk(
return;
}
entry->mitm_csrk = entry->mitm_performed;
entry->csrk_mitm_protected = entry->mitm_performed;
_db.set_entry_peer_csrk(connection, csrk);
eventHandler->signingKey(
connection,
csrk,
entry->mitm_csrk
entry->csrk_mitm_protected
);
}