Merge pull request #7210 from pan-/fix-nordic-security-cancellation

Fix nordic security cancellation
pull/7113/merge
Cruz Monrreal 2018-06-25 10:12:23 -05:00 committed by GitHub
commit 2e233a96d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 245 additions and 47 deletions

View File

@ -104,7 +104,8 @@ nRF5xGap::nRF5xGap() : Gap(),
_privacy_enabled(false),
_peripheral_privacy_configuration(default_peripheral_privacy_configuration),
_central_privacy_configuration(default_central_privacy_configuration),
_non_private_address_type(LegacyAddressType::RANDOM_STATIC)
_non_private_address_type(LegacyAddressType::RANDOM_STATIC),
_connections_role()
{
m_connectionHandle = BLE_CONN_HANDLE_INVALID;
}
@ -682,6 +683,8 @@ ble_error_t nRF5xGap::reset(void)
/* Clear the internal whitelist */
whitelistAddressesSize = 0;
/* Reset existing mapping between a connection and its role */
release_all_connections_role();
return BLE_ERROR_NONE;
}
@ -1195,6 +1198,8 @@ void nRF5xGap::processDisconnectionEvent(
Handle_t handle,
DisconnectionReason_t reason
) {
release_connection_role(handle);
if (_connection_event_handler) {
_connection_event_handler->on_disconnected(
handle,
@ -1214,6 +1219,9 @@ void nRF5xGap::on_connection(Gap::Handle_t handle, const ble_gap_evt_connected_t
// set the new connection handle as the _default_ handle in gap
setConnectionHandle(handle);
// add the connection and the role of the device in the local table
allocate_connection_role(handle, static_cast<Role_t>(evt.role));
// deal with own address
LegacyAddressType_t own_addr_type;
Address_t own_address;
@ -1375,5 +1383,45 @@ void nRF5xGap::on_advertising_packet(const ble_gap_evt_adv_report_t &evt) {
);
}
ble_error_t nRF5xGap::get_role(ble::connection_handle_t connection, Role_t& role) {
for (size_t i = 0; i < max_connections_count; ++i) {
connection_role_t& c = _connections_role[i];
if (c.is_allocated && c.connection == connection) {
role = c.is_peripheral ? PERIPHERAL : CENTRAL;
return BLE_ERROR_NONE;
}
}
return BLE_ERROR_INVALID_PARAM;
}
void nRF5xGap::allocate_connection_role(
ble::connection_handle_t connection,
Role_t role
) {
for (size_t i = 0; i < max_connections_count; ++i) {
connection_role_t& c = _connections_role[i];
if (c.is_allocated == false) {
c.connection = connection;
c.is_peripheral = (role == Gap::PERIPHERAL);
c.is_allocated = true;
return;
}
}
}
void nRF5xGap::release_connection_role(ble::connection_handle_t connection) {
for (size_t i = 0; i < max_connections_count; ++i) {
connection_role_t& c = _connections_role[i];
if (c.is_allocated && c.connection == connection) {
c.is_allocated = false;
return;
}
}
}
void nRF5xGap::release_all_connections_role() {
for (size_t i = 0; i < max_connections_count; ++i) {
_connections_role[i].is_allocated = false;
}
}

View File

@ -259,12 +259,26 @@ public:
DisconnectionReason_t reason
);
/**
* Return the role of the local peripheral for a given connection.
*
* @param[in] connection The connection queried.
* @param[out] role The role of the local device in the connection.
*
* @return BLE_ERROR_NONE in case of success or an appropriate error code.
*/
ble_error_t get_role(ble::connection_handle_t connection, Role_t& role);
private:
friend void btle_handler(ble_evt_t *p_ble_evt);
void on_connection(Handle_t handle, const ble_gap_evt_connected_t& evt);
void on_advertising_packet(const ble_gap_evt_adv_report_t &evt);
void allocate_connection_role(ble::connection_handle_t, Role_t);
void release_connection_role(ble::connection_handle_t);
void release_all_connections_role();
uint16_t m_connectionHandle;
ConnectionEventMonitor::EventHandler* _connection_event_handler;
@ -275,6 +289,23 @@ private:
AddressType_t _non_private_address_type;
Address_t _non_private_address;
struct connection_role_t {
connection_role_t() :
connection(),
is_peripheral(false),
is_allocated(false)
{ }
ble::connection_handle_t connection;
uint8_t is_peripheral:1;
uint8_t is_allocated:1;
};
static const size_t max_connections_count =
NRF_SDH_BLE_PERIPHERAL_LINK_COUNT + NRF_SDH_BLE_CENTRAL_LINK_COUNT;
connection_role_t _connections_role[max_connections_count];
/*
* Allow instantiation from nRF5xn when required.
*/

View File

@ -16,6 +16,9 @@
#include <stdint.h>
#include "nRF5xPalSecurityManager.h"
#include "nRF5xn.h"
#include "ble/Gap.h"
#include "nRF5xGap.h"
#include "nrf_ble.h"
#include "nrf_ble_gap.h"
#include "nrf_soc.h"
@ -297,6 +300,9 @@ ble_error_t nRF5xSecurityManager::send_pairing_response(
) {
pairing_control_block_t* pairing_cb = allocate_pairing_cb(connection);
if (!pairing_cb) {
// not enough memory; try to reject the pairing request instead of
// waiting for timeout.
cancel_pairing(connection, pairing_failure_t::UNSPECIFIED_REASON);
return BLE_ERROR_NO_MEM;
}
pairing_cb->role = PAIRING_RESPONDER;
@ -339,22 +345,33 @@ ble_error_t nRF5xSecurityManager::send_pairing_response(
ble_error_t nRF5xSecurityManager::cancel_pairing(
connection_handle_t connection, pairing_failure_t reason
) {
// this is the default path except when a key is expected to be entered by
// the user.
uint32_t err = sd_ble_gap_sec_params_reply(
connection,
reason.value() | 0x80,
/* sec params */ NULL,
/* keyset */ NULL
);
uint32_t err = 0;
if (!err) {
return BLE_ERROR_NONE;
}
pairing_control_block_t* pairing_cb = get_pairing_cb(connection);
// Failed because we're in the wrong state; try to cancel pairing with
// sd_ble_gap_auth_key_reply
if (err == NRF_ERROR_INVALID_STATE) {
// If there is no control block yet then if the local device is a central
// then we must reject the security request otherwise it is a response to
// a pairing feature exchange from a central.
if (!pairing_cb) {
::Gap::Role_t current_role;
if (nRF5xn::Instance().getGap().get_role(connection, current_role) != BLE_ERROR_NONE) {
return BLE_ERROR_INVALID_PARAM;
}
if (current_role == ::Gap::PERIPHERAL) {
// response to a pairing feature request
err = sd_ble_gap_sec_params_reply(
connection,
reason.value() | 0x80,
/* sec params */ NULL,
/* keyset */ NULL
);
} else {
// response to a peripheral security request
err = sd_ble_gap_authenticate(connection, NULL);
}
} else {
// At this point this must be a response to a key
err = sd_ble_gap_auth_key_reply(
connection,
/* key type */ BLE_GAP_AUTH_KEY_TYPE_NONE,

View File

@ -55,7 +55,7 @@ public:
* always needed in a BLE application. Therefore it is allocated
* statically.
*/
virtual Gap &getGap() {
virtual nRF5xGap &getGap() {
return gapInstance;
};
@ -134,7 +134,7 @@ public:
virtual void processEvents();
public:
static nRF5xn& Instance(BLE::InstanceID_t instanceId);
static nRF5xn& Instance(BLE::InstanceID_t instanceId = BLE::DEFAULT_INSTANCE);
private:
bool initialized;

View File

@ -133,7 +133,8 @@ nRF5xGap::nRF5xGap() : Gap(),
_privacy_enabled(false),
_peripheral_privacy_configuration(default_peripheral_privacy_configuration),
_central_privacy_configuration(default_central_privacy_configuration),
_non_private_address_type(LegacyAddressType::RANDOM_STATIC)
_non_private_address_type(LegacyAddressType::RANDOM_STATIC),
_connections_role()
{
m_connectionHandle = BLE_CONN_HANDLE_INVALID;
}
@ -243,7 +244,7 @@ ble_error_t nRF5xGap::startAdvertising(const GapAdvertisingParams &params)
{
uint32_t err;
ble_gap_adv_params_t adv_para = {0};
/* Make sure we support the advertising type */
if (params.getAdvertisingType() == GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) {
/* ToDo: This requires a propery security implementation, etc. */
@ -295,7 +296,7 @@ ble_error_t nRF5xGap::startAdvertising(const GapAdvertisingParams &params)
return error;
}
}
if (_privacy_enabled) {
if (_peripheral_privacy_configuration.resolution_strategy != PeripheralPrivacyConfiguration_t::DO_NOT_RESOLVE) {
ArrayView<resolving_list_entry_t> entries = get_sm().get_resolving_list();
@ -335,7 +336,7 @@ ble_error_t nRF5xGap::startAdvertising(const GapAdvertisingParams &params)
}
#endif
/* For NRF_SD_BLE_API_VERSION >= 3 nRF5xGap::setWhitelist setups the whitelist. */
/* Start Advertising */
@ -344,7 +345,7 @@ ble_error_t nRF5xGap::startAdvertising(const GapAdvertisingParams &params)
adv_para.fp = advertisingPolicyMode;
adv_para.interval = params.getIntervalInADVUnits(); // advertising interval (in units of 0.625 ms)
adv_para.timeout = params.getTimeout();
#if (NRF_SD_BLE_API_VERSION >= 5)
err = sd_ble_gap_adv_start(&adv_para, NRF_CONNECTION_TAG);
#else
@ -364,9 +365,9 @@ ble_error_t nRF5xGap::startAdvertising(const GapAdvertisingParams &params)
#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110)
ble_error_t nRF5xGap::startRadioScan(const GapScanningParams &scanningParams)
{
ble_gap_scan_params_t scanParams;
#if (NRF_SD_BLE_API_VERSION <= 2)
/* Allocate the stack's whitelist statically */
ble_gap_whitelist_t whitelist;
@ -385,17 +386,17 @@ ble_error_t nRF5xGap::startRadioScan(const GapScanningParams &scanningParams)
return error;
}
}
// FIXME: fill the irk list once addresses are resolved by the softdevice.
scanParams.selective = scanningPolicyMode; /**< If 1, ignore unknown devices (non whitelisted). */
scanParams.p_whitelist = &whitelist; /**< Pointer to whitelist, NULL if none is given. */
#else
/* For NRF_SD_BLE_API_VERSION >= 3 nRF5xGap::setWhitelist setups the whitelist. */
scanParams.use_whitelist = scanningPolicyMode;
scanParams.adv_dir_report = 0;
#endif
scanParams.active = scanningParams.getActiveScanning(); /**< If 1, perform active scanning (scan requests). */
scanParams.interval = scanningParams.getInterval(); /**< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s). */
@ -544,7 +545,7 @@ ble_error_t nRF5xGap::connect(
}
ble_gap_scan_params_t scanParams ={0};
#if (NRF_SD_BLE_API_VERSION <= 2)
/* Allocate the stack's whitelist statically */
ble_gap_whitelist_t whitelist;
@ -563,7 +564,7 @@ ble_error_t nRF5xGap::connect(
return error;
}
}
scanParams.selective = scanningPolicyMode; /**< If 1, ignore unknown devices (non whitelisted). */
scanParams.p_whitelist = &whitelist; /**< Pointer to whitelist, NULL if none is given. */
if (_privacy_enabled) {
@ -596,7 +597,7 @@ ble_error_t nRF5xGap::connect(
}
#else
/* For NRF_SD_BLE_API_VERSION >= 3 nRF5xGap::setWhitelist setups the whitelist. */
scanParams.use_whitelist = (whitelistAddressesSize) ? 1 : 0;
if (_privacy_enabled) {
@ -743,6 +744,9 @@ ble_error_t nRF5xGap::reset(void)
/* Clear the internal whitelist */
whitelistAddressesSize = 0;
/* Reset existing mapping between a connection and its role */
release_all_connections_role();
return BLE_ERROR_NONE;
}
@ -793,7 +797,7 @@ ble_error_t nRF5xGap::setAddress(LegacyAddressType_t type, const Address_t addre
if (_privacy_enabled) {
return BLE_ERROR_INVALID_STATE;
}
ble_gap_addr_t dev_addr;
memcpy(dev_addr.addr, address, ADDR_LEN);
if (type == LegacyAddressType::PUBLIC) {
@ -1278,6 +1282,8 @@ void nRF5xGap::processDisconnectionEvent(
Handle_t handle,
DisconnectionReason_t reason
) {
release_connection_role(handle);
if (_connection_event_handler) {
_connection_event_handler->on_disconnected(
handle,
@ -1326,6 +1332,9 @@ void nRF5xGap::on_connection(Gap::Handle_t handle, const ble_gap_evt_connected_t
// set the new connection handle as the _default_ handle in gap
setConnectionHandle(handle);
// add the connection and the role of the device in the local table
allocate_connection_role(handle, static_cast<Role_t>(evt.role));
// deal with own address
LegacyAddressType_t own_addr_type;
ble::address_t own_address;
@ -1457,3 +1466,47 @@ void nRF5xGap::on_advertising_packet(const ble_gap_evt_adv_report_t &evt) {
);
}
ble_error_t nRF5xGap::get_role(ble::connection_handle_t connection, Role_t& role) {
for (size_t i = 0; i < max_connections_count; ++i) {
connection_role_t& c = _connections_role[i];
if (c.is_allocated && c.connection == connection) {
role = c.is_peripheral ? PERIPHERAL : CENTRAL;
return BLE_ERROR_NONE;
}
}
return BLE_ERROR_INVALID_PARAM;
}
void nRF5xGap::allocate_connection_role(
ble::connection_handle_t connection,
Role_t role
) {
for (size_t i = 0; i < max_connections_count; ++i) {
connection_role_t& c = _connections_role[i];
if (c.is_allocated == false) {
c.connection = connection;
c.is_peripheral = (role == Gap::PERIPHERAL);
c.is_allocated = true;
return;
}
}
}
void nRF5xGap::release_connection_role(ble::connection_handle_t connection) {
for (size_t i = 0; i < max_connections_count; ++i) {
connection_role_t& c = _connections_role[i];
if (c.is_allocated && c.connection == connection) {
c.is_allocated = false;
return;
}
}
}
void nRF5xGap::release_all_connections_role() {
for (size_t i = 0; i < max_connections_count; ++i) {
_connections_role[i].is_allocated = false;
}
}

View File

@ -265,6 +265,16 @@ public:
DisconnectionReason_t reason
);
/**
* Return the role of the local peripheral for a given connection.
*
* @param[in] connection The connection queried.
* @param[out] role The role of the local device in the connection.
*
* @return BLE_ERROR_NONE in case of success or an appropriate error code.
*/
ble_error_t get_role(ble::connection_handle_t connection, Role_t& role);
private:
friend void btle_handler(const ble_evt_t *p_ble_evt);
friend void btle_handler(const ble_evt_t *p_ble_evt, void *p_context);
@ -272,6 +282,11 @@ private:
ble_error_t update_identities_list(bool resolution_enabled);
void on_connection(Handle_t handle, const ble_gap_evt_connected_t& evt);
void on_advertising_packet(const ble_gap_evt_adv_report_t &evt);
void allocate_connection_role(ble::connection_handle_t, Role_t);
void release_connection_role(ble::connection_handle_t);
void release_all_connections_role();
uint16_t m_connectionHandle;
ConnectionEventMonitor::EventHandler* _connection_event_handler;
@ -281,6 +296,23 @@ private:
AddressType_t _non_private_address_type;
Address_t _non_private_address;
struct connection_role_t {
connection_role_t() :
connection(),
is_peripheral(false),
is_allocated(false)
{ }
ble::connection_handle_t connection;
uint8_t is_peripheral:1;
uint8_t is_allocated:1;
};
static const size_t max_connections_count =
NRF_SDH_BLE_PERIPHERAL_LINK_COUNT + NRF_SDH_BLE_CENTRAL_LINK_COUNT;
connection_role_t _connections_role[max_connections_count];
/*
* Allow instantiation from nRF5xn when required.
*/

View File

@ -16,6 +16,9 @@
#include <stdint.h>
#include "nRF5xPalSecurityManager.h"
#include "nRF5xn.h"
#include "ble/Gap.h"
#include "nRF5xGap.h"
#include "nrf_ble.h"
#include "ble_gap.h"
#include "nrf_soc.h"
@ -274,6 +277,9 @@ ble_error_t nRF5xSecurityManager::send_pairing_response(
) {
pairing_control_block_t* pairing_cb = allocate_pairing_cb(connection);
if (!pairing_cb) {
// not enough memory; try to reject the pairing request instead of
// waiting for timeout.
cancel_pairing(connection, pairing_failure_t::UNSPECIFIED_REASON);
return BLE_ERROR_NO_MEM;
}
pairing_cb->role = PAIRING_RESPONDER;
@ -316,22 +322,33 @@ ble_error_t nRF5xSecurityManager::send_pairing_response(
ble_error_t nRF5xSecurityManager::cancel_pairing(
connection_handle_t connection, pairing_failure_t reason
) {
// this is the default path except when a key is expected to be entered by
// the user.
uint32_t err = sd_ble_gap_sec_params_reply(
connection,
reason.value() | 0x80,
/* sec params */ NULL,
/* keyset */ NULL
);
uint32_t err = 0;
if (!err) {
return BLE_ERROR_NONE;
}
pairing_control_block_t* pairing_cb = get_pairing_cb(connection);
// Failed because we're in the wrong state; try to cancel pairing with
// sd_ble_gap_auth_key_reply
if (err == NRF_ERROR_INVALID_STATE) {
// If there is no control block yet then if the local device is a central
// then we must reject the security request otherwise it is a response to
// a pairing feature exchange from a central.
if (!pairing_cb) {
::Gap::Role_t current_role;
if (nRF5xn::Instance().getGap().get_role(connection, current_role) != BLE_ERROR_NONE) {
return BLE_ERROR_INVALID_PARAM;
}
if (current_role == ::Gap::PERIPHERAL) {
// response to a pairing feature request
err = sd_ble_gap_sec_params_reply(
connection,
reason.value() | 0x80,
/* sec params */ NULL,
/* keyset */ NULL
);
} else {
// response to a peripheral security request
err = sd_ble_gap_authenticate(connection, NULL);
}
} else {
// At this point this must be a response to a key
err = sd_ble_gap_auth_key_reply(
connection,
/* key type */ BLE_GAP_AUTH_KEY_TYPE_NONE,

View File

@ -54,7 +54,7 @@ public:
* always needed in a BLE application. Therefore it is allocated
* statically.
*/
virtual Gap &getGap() {
virtual nRF5xGap &getGap() {
return gapInstance;
};
@ -133,7 +133,7 @@ public:
virtual void processEvents();
public:
static nRF5xn& Instance(BLE::InstanceID_t instanceId);
static nRF5xn& Instance(BLE::InstanceID_t instanceId = BLE::DEFAULT_INSTANCE);
private:
bool initialized;