mirror of https://github.com/ARMmbed/mbed-os.git
GAP integration for connection and disconnection events
parent
e7cf1529ec
commit
18062fc9de
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue