Merge branch 'nordicpalsm' of https://github.com/donatieng/mbed-os into sc-cordio

pull/6932/head
Vincent Coubard 2018-03-12 10:15:18 +00:00
commit eb8ec9c22d
11 changed files with 1223 additions and 1386 deletions

View File

@ -38,11 +38,9 @@
extern "C" {
#if (IS_LEGACY_DEVICE_MANAGER_ENABLED)
#include "pstorage.h"
#include "device_manager.h"
#else
#include "fstorage.h"
#include "fds.h"
#include "peer_manager.h"
#include "ble_conn_state.h"
#endif
@ -53,7 +51,7 @@ extern "C" {
#include "nrf_ble_hci.h"
#include "nRF5XPalGattClient.h"
#include "nRF5XPalSecurityManager.h"
bool isEventsSignaled = false;
@ -145,9 +143,6 @@ error_t btle_init(void)
return ERROR_INVALID_PARAM;
}
// Peer Manger must been initialised prior any other call to its API (this file and btle_security_pm.cpp)
pm_init();
#if (NRF_SD_BLE_API_VERSION <= 2)
ble_gap_addr_t addr;
if (sd_ble_gap_address_get(&addr) != NRF_SUCCESS) {
@ -157,9 +152,7 @@ error_t btle_init(void)
return ERROR_INVALID_PARAM;
}
#else
ble_gap_privacy_params_t privacy_params = {0};
privacy_params.privacy_mode = BLE_GAP_PRIVACY_MODE_OFF;
pm_privacy_set(&privacy_params);
#endif
ASSERT_STATUS( softdevice_ble_evt_handler_set(btle_handler));
@ -171,6 +164,7 @@ error_t btle_init(void)
static void btle_handler(ble_evt_t *p_ble_evt)
{
using ble::pal::vendor::nordic::nRF5XGattClient;
using ble::pal::vendor::nordic::nRF5xSecurityManager;
/* Library service handlers */
#if SDK_CONN_PARAMS_MODULE_ENABLE
@ -178,14 +172,10 @@ static void btle_handler(ble_evt_t *p_ble_evt)
#endif
#if (IS_LEGACY_DEVICE_MANAGER_ENABLED)
dm_ble_evt_handler(p_ble_evt);
#else
// Forward BLE events to the Connection State module.
// This must be called before any event handler that uses this module.
ble_conn_state_on_ble_evt(p_ble_evt);
// Forward BLE events to the Peer Manager
pm_on_ble_evt(p_ble_evt);
#endif
#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110)
@ -265,10 +255,6 @@ static void btle_handler(ble_evt_t *p_ble_evt)
break;
}
case BLE_GAP_EVT_PASSKEY_DISPLAY:
securityManager.processPasskeyDisplayEvent(p_ble_evt->evt.gap_evt.conn_handle, p_ble_evt->evt.gap_evt.params.passkey_display.passkey);
break;
case BLE_GAP_EVT_TIMEOUT:
gap.processTimeoutEvent(static_cast<Gap::TimeoutSource_t>(p_ble_evt->evt.gap_evt.params.timeout.src));
break;
@ -296,6 +282,9 @@ static void btle_handler(ble_evt_t *p_ble_evt)
break;
}
// Process security manager events
securityManager.sm_handler(p_ble_evt);
gattServer.hwCallback(p_ble_evt);
}

View File

@ -1,326 +0,0 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 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.
*/
#if defined(S110)
#include "btle.h"
#include "nRF5xn.h"
extern "C" {
#include "pstorage.h"
#include "device_manager.h"
#include "id_manager.h"
}
#include "btle_security.h"
static dm_application_instance_t applicationInstance;
static bool initialized = false;
static ret_code_t dm_handler(dm_handle_t const *p_handle, dm_event_t const *p_event, ret_code_t event_result);
// default security parameters. Avoid "holes" between member assigments in order to compile by gcc++11.
static ble_gap_sec_params_t securityParameters = {
.bond = true, /**< Perform bonding. */
.mitm = true, /**< Man In The Middle protection required. */
.lesc = false, /**< Enable LE Secure Connection pairing. */
.keypress = false, /**< Enable generation of keypress notifications. */
.io_caps = SecurityManager::IO_CAPS_NONE, /**< IO capabilities, see @ref BLE_GAP_IO_CAPS. */
.oob = 0, /**< Out Of Band data available. */
.min_key_size = 16, /**< Minimum encryption key size in octets between 7 and 16. If 0 then not applicable in this instance. */
.max_key_size = 16, /**< Maximum encryption key size in octets between min_key_size and 16. */
.kdist_own = {
.enc = 0, /**< Long Term Key and Master Identification. */
.id = 0, /**< Identity Resolving Key and Identity Address Information. */
.sign = 0, /**< Connection Signature Resolving Key. */
.link = 0 /**< Derive the Link Key from the LTK. */
}, /**< Key distribution bitmap: keys that the local device will distribute. */
.kdist_peer = {
.enc = 1, /**< Long Term Key and Master Identification. */
.id = 1, /**< Identity Resolving Key and Identity Address Information. */
.sign = 1, /**< Connection Signature Resolving Key. */
.link = 0 /**< Derive the Link Key from the LTK. */
} /**< Key distribution bitmap: keys that the peripheral device will distribute. */
};
bool
btle_hasInitializedSecurity(void)
{
return initialized;
}
ble_error_t
btle_initializeSecurity(bool enableBonding,
bool requireMITM,
SecurityManager::SecurityIOCapabilities_t iocaps,
const SecurityManager::Passkey_t passkey)
{
/* guard against multiple initializations */
if (initialized) {
return BLE_ERROR_NONE;
}
if (pstorage_init() != NRF_SUCCESS) {
return BLE_ERROR_UNSPECIFIED;
}
ret_code_t rc;
if (passkey) {
ble_opt_t opts;
opts.gap_opt.passkey.p_passkey = const_cast<uint8_t *>(passkey);
if ((rc = sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &opts)) != NRF_SUCCESS) {
switch (rc) {
case BLE_ERROR_INVALID_CONN_HANDLE:
case NRF_ERROR_INVALID_ADDR:
case NRF_ERROR_INVALID_PARAM:
default:
return BLE_ERROR_INVALID_PARAM;
case NRF_ERROR_INVALID_STATE:
return BLE_ERROR_INVALID_STATE;
case NRF_ERROR_BUSY:
return BLE_STACK_BUSY;
}
}
}
dm_init_param_t dm_init_param = {
.clear_persistent_data = false /* Set to true in case the module should clear all persistent data. */
};
if (dm_init(&dm_init_param) != NRF_SUCCESS) {
return BLE_ERROR_UNSPECIFIED;
}
// update default security parameters with function call parameters
securityParameters.bond = enableBonding;
securityParameters.mitm = requireMITM;
securityParameters.io_caps = iocaps;
const dm_application_param_t dm_param = {
.evt_handler = dm_handler,
.service_type = DM_PROTOCOL_CNTXT_GATT_CLI_ID,
.sec_param = securityParameters
};
if ((rc = dm_register(&applicationInstance, &dm_param)) != NRF_SUCCESS) {
switch (rc) {
case NRF_ERROR_INVALID_STATE:
return BLE_ERROR_INVALID_STATE;
case NRF_ERROR_NO_MEM:
return BLE_ERROR_NO_MEM;
default:
return BLE_ERROR_UNSPECIFIED;
}
}
initialized = true;
return BLE_ERROR_NONE;
}
ble_error_t
btle_purgeAllBondingState(void)
{
ret_code_t rc;
if ((rc = dm_device_delete_all(&applicationInstance)) == NRF_SUCCESS) {
return BLE_ERROR_NONE;
}
switch (rc) {
case NRF_ERROR_INVALID_STATE:
return BLE_ERROR_INVALID_STATE;
case NRF_ERROR_NO_MEM:
return BLE_ERROR_NO_MEM;
default:
return BLE_ERROR_UNSPECIFIED;
}
}
ble_error_t
btle_getLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::LinkSecurityStatus_t *securityStatusP)
{
ret_code_t rc;
dm_handle_t dmHandle = {
.appl_id = applicationInstance,
};
if ((rc = dm_handle_get(connectionHandle, &dmHandle)) != NRF_SUCCESS) {
if (rc == NRF_ERROR_NOT_FOUND) {
return BLE_ERROR_INVALID_PARAM;
} else {
return BLE_ERROR_UNSPECIFIED;
}
}
if ((rc = dm_security_status_req(&dmHandle, reinterpret_cast<dm_security_status_t *>(securityStatusP))) != NRF_SUCCESS) {
switch (rc) {
case NRF_ERROR_INVALID_STATE:
return BLE_ERROR_INVALID_STATE;
case NRF_ERROR_NO_MEM:
return BLE_ERROR_NO_MEM;
default:
return BLE_ERROR_UNSPECIFIED;
}
}
return BLE_ERROR_NONE;
}
ble_error_t
btle_setLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::SecurityMode_t securityMode)
{
// use default and updated parameters as starting point
// and modify structure based on security mode.
ble_gap_sec_params_t params = securityParameters;
switch (securityMode) {
case SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK:
/**< Require no protection, open link. */
securityParameters.bond = false;
securityParameters.mitm = false;
break;
case SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM:
/**< Require encryption, but no MITM protection. */
securityParameters.bond = true;
securityParameters.mitm = false;
break;
// not yet implemented security modes
case SecurityManager::SECURITY_MODE_NO_ACCESS:
case SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM:
/**< Require encryption and MITM protection. */
case SecurityManager::SECURITY_MODE_SIGNED_NO_MITM:
/**< Require signing or encryption, but no MITM protection. */
case SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM:
/**< Require signing or encryption, and MITM protection. */
default:
return BLE_ERROR_NOT_IMPLEMENTED;
}
// update security settings for given connection
uint32_t result = sd_ble_gap_authenticate(connectionHandle, &params);
if (result == NRF_SUCCESS) {
return BLE_ERROR_NONE;
} else {
return BLE_ERROR_UNSPECIFIED;
}
}
ret_code_t
dm_handler(dm_handle_t const *p_handle, dm_event_t const *p_event, ret_code_t event_result)
{
nRF5xn &ble = nRF5xn::Instance(BLE::DEFAULT_INSTANCE);
nRF5xSecurityManager &securityManager = (nRF5xSecurityManager &) ble.getSecurityManager();
switch (p_event->event_id) {
case DM_EVT_SECURITY_SETUP: /* started */ {
const ble_gap_sec_params_t *peerParams = &p_event->event_param.p_gap_param->params.sec_params_request.peer_params;
securityManager.processSecuritySetupInitiatedEvent(p_event->event_param.p_gap_param->conn_handle,
peerParams->bond,
peerParams->mitm,
(SecurityManager::SecurityIOCapabilities_t)peerParams->io_caps);
break;
}
case DM_EVT_SECURITY_SETUP_COMPLETE:
securityManager.
processSecuritySetupCompletedEvent(p_event->event_param.p_gap_param->conn_handle,
(SecurityManager::SecurityCompletionStatus_t)(p_event->event_param.p_gap_param->params.auth_status.auth_status));
break;
case DM_EVT_LINK_SECURED: {
unsigned securityMode = p_event->event_param.p_gap_param->params.conn_sec_update.conn_sec.sec_mode.sm;
unsigned level = p_event->event_param.p_gap_param->params.conn_sec_update.conn_sec.sec_mode.lv;
SecurityManager::SecurityMode_t resolvedSecurityMode = SecurityManager::SECURITY_MODE_NO_ACCESS;
switch (securityMode) {
case 1:
switch (level) {
case 1:
resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK;
break;
case 2:
resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM;
break;
case 3:
resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM;
break;
}
break;
case 2:
switch (level) {
case 1:
resolvedSecurityMode = SecurityManager::SECURITY_MODE_SIGNED_NO_MITM;
break;
case 2:
resolvedSecurityMode = SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM;
break;
}
break;
}
securityManager.processLinkSecuredEvent(p_event->event_param.p_gap_param->conn_handle, resolvedSecurityMode);
break;
}
case DM_EVT_DEVICE_CONTEXT_STORED:
securityManager.processSecurityContextStoredEvent(p_event->event_param.p_gap_param->conn_handle);
break;
default:
break;
}
return NRF_SUCCESS;
}
ble_error_t
btle_createWhitelistFromBondTable(ble_gap_whitelist_t *p_whitelist)
{
if (!btle_hasInitializedSecurity()) {
return BLE_ERROR_INITIALIZATION_INCOMPLETE;
}
ret_code_t err = dm_whitelist_create(&applicationInstance, p_whitelist);
if (err == NRF_SUCCESS) {
return BLE_ERROR_NONE;
} else if (err == NRF_ERROR_NULL) {
return BLE_ERROR_PARAM_OUT_OF_RANGE;
} else {
return BLE_ERROR_INVALID_STATE;
}
}
bool
btle_matchAddressAndIrk(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk)
{
/*
* Use a helper function from the Nordic SDK to test whether the BLE
* address can be generated using the IRK.
*/
return im_address_resolve(p_addr, p_irk);
}
void
btle_generateResolvableAddress(const ble_gap_irk_t &irk, ble_gap_addr_t &address)
{
/* Set type to resolvable */
address.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE;
/*
* Assign a random number to the most significant 3 bytes
* of the address.
*/
address.addr[BLE_GAP_ADDR_LEN - 3] = 0x8E;
address.addr[BLE_GAP_ADDR_LEN - 2] = 0x4F;
address.addr[BLE_GAP_ADDR_LEN - 1] = 0x7C;
/* Calculate the hash and store it in the top half of the address */
ah(irk.irk, &address.addr[BLE_GAP_ADDR_LEN - 3], address.addr);
}
#endif

View File

@ -1,146 +0,0 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 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 _BTLE_SECURITY_H_
#define _BTLE_SECURITY_H_
#include "ble/Gap.h"
#include "ble/SecurityManager.h"
/**
* Function to test whether the SecurityManager has been initialized.
* Possible by a call to @ref btle_initializeSecurity().
*
* @return True if the SecurityManager was previously initialized, false
* otherwise.
*/
bool btle_hasInitializedSecurity(void);
/**
* Enable Nordic's Device Manager, which brings in functionality from the
* stack's Security Manager. The Security Manager implements the actual
* cryptographic algorithms and protocol exchanges that allow two devices to
* securely exchange data and privately detect each other.
*
* @param[in] enableBonding Allow for bonding.
* @param[in] requireMITM Require protection for man-in-the-middle attacks.
* @param[in] iocaps To specify IO capabilities of this peripheral,
* such as availability of a display or keyboard to
* support out-of-band exchanges of security data.
* @param[in] passkey To specify a static passkey.
*
* @return BLE_ERROR_NONE on success.
*/
ble_error_t btle_initializeSecurity(bool enableBonding = true,
bool requireMITM = true,
SecurityManager::SecurityIOCapabilities_t iocaps = SecurityManager::IO_CAPS_NONE,
const SecurityManager::Passkey_t passkey = NULL);
/**
* Get the security status of a link.
*
* @param[in] connectionHandle
* Handle to identify the connection.
* @param[out] securityStatusP
* security status.
*
* @return BLE_ERROR_NONE Or appropriate error code indicating reason for failure.
*/
ble_error_t btle_getLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::LinkSecurityStatus_t *securityStatusP);
/**
* Set the security mode on a connection. Useful for elevating the security mode
* once certain conditions are met, e.g., a particular service is found.
*
* @param[in] connectionHandle
* Handle to identify the connection.
* @param[in] securityMode
* security mode.
*
* @return BLE_ERROR_NONE Or appropriate error code indicating reason for failure.
*/
ble_error_t btle_setLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::SecurityMode_t securityMode);
/**
* Function for deleting all peer device context and all related bonding
* information from the database.
*
* @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure.
* @retval BLE_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
*/
ble_error_t btle_purgeAllBondingState(void);
#if (NRF_SD_BLE_API_VERSION <= 2)
/**
* Query the SoftDevice bond table to extract a whitelist containing the BLE
* addresses and IRKs of bonded devices.
*
* @param[in/out] p_whitelist
* (on input) p_whitelist->addr_count and
* p_whitelist->irk_count specify the maximum number of
* addresses and IRKs added to the whitelist structure.
* (on output) *p_whitelist is a whitelist containing the
* addresses and IRKs of the bonded devices.
*
* @return BLE_ERROR_NONE Or appropriate error code indicating reason for failure.
*/
ble_error_t btle_createWhitelistFromBondTable(ble_gap_whitelist_t *p_whitelist);
#endif
/**
* Function to test whether a BLE address is generated using an IRK.
*
* @param[in] p_addr
* Pointer to a BLE address.
* @param[in] p_irk
* Pointer to an IRK.
*
* @return True if p_addr can be generated using p_irk, false otherwise.
*/
bool btle_matchAddressAndIrk(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk);
/**
* Function to generate a private resolvable BLE address.
*
* @param[out] p_addr
* The output address.
* @param[in] p_irk
* A reference to a IRK.
*
* @note This function does not generate a secure address since the prand number in the
* resolvable address is not truly random. Therefore, the output of this function
* is only meant to be used by the application internally but never exported.
*/
void btle_generateResolvableAddress(const ble_gap_irk_t &irk, ble_gap_addr_t &address);
#if (NRF_SD_BLE_API_VERSION >= 3)
/**
* @brief Returns a list of addresses from peers in the stacks bond table.
*
* @param[in/out] addresses
* (on input) @ref Gap::Whitelist_t structure where at
* most addresses.capacity addresses from bonded peers will
* be stored.
* (on output) A copy of the addresses from bonded peers.
*
* @retval BLE_ERROR_NONE if successful.
* @retval BLE_ERROR_UNSPECIFIED Bond data could not be found in flash or is inconsistent.
*/
ble_error_t btle_getAddressesFromBondTable(Gap::Whitelist_t &addrList);
#endif
#endif /* _BTLE_SECURITY_H_ */

View File

@ -1,486 +0,0 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 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.
*/
#if defined(S130) || defined(S132) || defined(S140)
#include "btle.h"
#include "nRF5xn.h"
extern "C" {
#include "peer_manager.h"
#include "id_manager.h"
#include "fds.h"
}
#include "btle_security.h"
static bool initialized = false;
static void pm_handler(pm_evt_t const *p_event);
static bool _enc_in_progress = false; // helper flag for distinguish between state of link connected and link connected in progres of encryption establishing.
volatile static uint32_t async_ret_code; // busy loop support variable for asyncronous API.
// default security parameters. Avoid "holes" between member assigments in order to compile by gcc++11.
static ble_gap_sec_params_t securityParameters = {
.bond = true, /**< Perform bonding. */
.mitm = true, /**< Man In The Middle protection required. */
.lesc = false, /**< Enable LE Secure Connection pairing. */
.keypress = false, /**< Enable generation of keypress notifications. */
.io_caps = SecurityManager::IO_CAPS_NONE, /**< IO capabilities, see @ref BLE_GAP_IO_CAPS. */
.oob = 0, /**< Out Of Band data available. */
.min_key_size = 16, /**< Minimum encryption key size in octets between 7 and 16. If 0 then not applicable in this instance. */
.max_key_size = 16, /**< Maximum encryption key size in octets between min_key_size and 16. */
.kdist_own = {
.enc = 0, /**< Long Term Key and Master Identification. */
.id = 0, /**< Identity Resolving Key and Identity Address Information. */
.sign = 0, /**< Connection Signature Resolving Key. */
.link = 0 /**< Derive the Link Key from the LTK. */
}, /**< Key distribution bitmap: keys that the local device will distribute. */
.kdist_peer = {
.enc = 1, /**< Long Term Key and Master Identification. */
.id = 1, /**< Identity Resolving Key and Identity Address Information. */
.sign = 0, /**< Connection Signature Resolving Key. */
.link = 0 /**< Derive the Link Key from the LTK. */
} /**< Key distribution bitmap: keys that the peripheral device will distribute. */
};
bool
btle_hasInitializedSecurity(void)
{
return initialized;
}
ble_error_t
btle_initializeSecurity(bool enableBonding,
bool requireMITM,
SecurityManager::SecurityIOCapabilities_t iocaps,
const SecurityManager::Passkey_t passkey)
{
/* guard against multiple initializations */
if (initialized) {
return BLE_ERROR_NONE;
}
ret_code_t rc;
if (passkey) {
ble_opt_t opts;
opts.gap_opt.passkey.p_passkey = const_cast<uint8_t *>(passkey);
if ((rc = sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &opts)) != NRF_SUCCESS) {
switch (rc) {
case BLE_ERROR_INVALID_CONN_HANDLE:
case NRF_ERROR_INVALID_ADDR:
case NRF_ERROR_INVALID_PARAM:
default:
return BLE_ERROR_INVALID_PARAM;
case NRF_ERROR_INVALID_STATE:
return BLE_ERROR_INVALID_STATE;
case NRF_ERROR_BUSY:
return BLE_STACK_BUSY;
}
}
}
// update default security parameters with function call parameters
securityParameters.bond = enableBonding;
securityParameters.mitm = requireMITM;
securityParameters.io_caps = iocaps;
if (enableBonding) {
securityParameters.kdist_own.enc = 1;
securityParameters.kdist_own.id = 1;
} else {
securityParameters.kdist_own.enc = 0;
securityParameters.kdist_own.id = 0;
}
rc = pm_sec_params_set(&securityParameters);
if (rc == NRF_SUCCESS) {
rc = pm_register(pm_handler);
}
switch (rc) {
case NRF_SUCCESS:
initialized = true;
return BLE_ERROR_NONE;
case NRF_ERROR_INVALID_STATE:
return BLE_ERROR_INVALID_STATE;
case NRF_ERROR_INVALID_PARAM:
return BLE_ERROR_INVALID_PARAM;
default:
return BLE_ERROR_UNSPECIFIED;
}
initialized = true;
return BLE_ERROR_NONE;
}
ble_error_t
btle_purgeAllBondingState(void)
{
ret_code_t rc;
async_ret_code = NRF_ERROR_BUSY;
rc = pm_peers_delete(); // it is asynhronous API
if (rc == NRF_SUCCESS)
{
// waiting for respond from pm_handler
while (async_ret_code == NRF_ERROR_BUSY) {
// busy-loop
}
rc = async_ret_code;
}
switch (rc) {
case NRF_SUCCESS:
return BLE_ERROR_NONE;
case NRF_ERROR_INVALID_STATE:
return BLE_ERROR_INVALID_STATE;
default:
return BLE_ERROR_UNSPECIFIED;
}
}
ble_error_t
btle_getLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::LinkSecurityStatus_t *securityStatusP)
{
ret_code_t rc;
pm_conn_sec_status_t conn_sec_status;
rc = pm_conn_sec_status_get(connectionHandle, &conn_sec_status);
if (rc == NRF_SUCCESS)
{
if (conn_sec_status.encrypted) {
*securityStatusP = SecurityManager::ENCRYPTED;
}
else if (conn_sec_status.connected) {
if (_enc_in_progress) {
*securityStatusP = SecurityManager::ENCRYPTION_IN_PROGRESS;
}
else {
*securityStatusP = SecurityManager::NOT_ENCRYPTED;
}
}
return BLE_ERROR_NONE;
}
switch (rc) {
case BLE_ERROR_INVALID_CONN_HANDLE:
return BLE_ERROR_INVALID_PARAM;
case NRF_ERROR_INVALID_STATE:
return BLE_ERROR_INVALID_STATE;
default:
return BLE_ERROR_UNSPECIFIED;
}
}
ble_error_t
btle_setLinkSecurity(Gap::Handle_t connectionHandle, SecurityManager::SecurityMode_t securityMode)
{
// use default and updated parameters as starting point
// and modify structure based on security mode.
ret_code_t rc;
switch (securityMode) {
case SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK:
/**< Require no protection, open link. */
securityParameters.bond = false;
securityParameters.mitm = false;
securityParameters.kdist_own.enc = 0;
break;
case SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM:
/**< Require encryption, but no MITM protection. */
securityParameters.bond = true;
securityParameters.mitm = false;
securityParameters.kdist_own.enc = 1;
break;
// not yet implemented security modes
case SecurityManager::SECURITY_MODE_NO_ACCESS:
case SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM:
/**< Require encryption and MITM protection. */
case SecurityManager::SECURITY_MODE_SIGNED_NO_MITM:
/**< Require signing or encryption, but no MITM protection. */
case SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM:
/**< Require signing or encryption, and MITM protection. */
default:
return BLE_ERROR_NOT_IMPLEMENTED;
}
// update security settings for given connection
rc = pm_sec_params_set(&securityParameters);
if (rc == NRF_SUCCESS) {
rc = pm_conn_secure(connectionHandle, false);
}
switch (rc) {
case NRF_SUCCESS:
initialized = true;
return BLE_ERROR_NONE;
case NRF_ERROR_INVALID_STATE:
return BLE_ERROR_INVALID_STATE;
case NRF_ERROR_INVALID_PARAM:
return BLE_ERROR_INVALID_PARAM;
default:
return BLE_ERROR_UNSPECIFIED;
}
}
void pm_handler(pm_evt_t const *p_event)
{
nRF5xn &ble = nRF5xn::Instance(BLE::DEFAULT_INSTANCE);
nRF5xSecurityManager &securityManager = (nRF5xSecurityManager &) ble.getSecurityManager();
ret_code_t err_code;
SecurityManager::SecurityMode_t resolvedSecurityMode;
switch (p_event->evt_id) {
case PM_EVT_CONN_SEC_START: /* started */ {
const ble_gap_sec_params_t *peerParams = &securityParameters;
securityManager.processSecuritySetupInitiatedEvent(p_event->conn_handle,
peerParams->bond,
peerParams->mitm,
(SecurityManager::SecurityIOCapabilities_t)peerParams->io_caps);
_enc_in_progress = true;
break;
}
case PM_EVT_CONN_SEC_SUCCEEDED:
// Update the rank of the peer.
if (p_event->params.conn_sec_succeeded.procedure == PM_LINK_SECURED_PROCEDURE_BONDING)
{
err_code = pm_peer_rank_highest(p_event->peer_id);
}
securityManager.
processSecuritySetupCompletedEvent(p_event->conn_handle,
SecurityManager::SEC_STATUS_SUCCESS);// SEC_STATUS_SUCCESS of SecurityCompletionStatus_t
ble_gap_conn_sec_t conn_sec;
sd_ble_gap_conn_sec_get(p_event->conn_handle, &conn_sec);
resolvedSecurityMode = SecurityManager::SECURITY_MODE_NO_ACCESS;
switch (conn_sec.sec_mode.sm) {
case 1:
switch (conn_sec.sec_mode.lv) {
case 1:
resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK;
break;
case 2:
resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM;
break;
case 3:
resolvedSecurityMode = SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM;
break;
}
break;
case 2:
switch (conn_sec.sec_mode.lv) {
case 1:
resolvedSecurityMode = SecurityManager::SECURITY_MODE_SIGNED_NO_MITM;
break;
case 2:
resolvedSecurityMode = SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM;
break;
}
break;
}
securityManager.processLinkSecuredEvent(p_event->conn_handle, resolvedSecurityMode);
_enc_in_progress = false;
break;
case PM_EVT_CONN_SEC_FAILED:
SecurityManager::SecurityCompletionStatus_t securityCompletionStatus;
if ((uint32_t)p_event->params.conn_sec_failed.error >= PM_CONN_SEC_ERROR_BASE ) {
securityCompletionStatus = SecurityManager::SEC_STATUS_UNSPECIFIED;
} else {
securityCompletionStatus =
(SecurityManager::SecurityCompletionStatus_t)p_event->params.conn_sec_failed.error;
}
securityManager.
processSecuritySetupCompletedEvent(p_event->conn_handle, securityCompletionStatus);
_enc_in_progress = false;
break;
case PM_EVT_BONDED_PEER_CONNECTED:
pm_peer_rank_highest(p_event->peer_id);
break;
case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
if (p_event->params.peer_data_update_succeeded.action == PM_PEER_DATA_OP_UPDATE)
{
securityManager.processSecurityContextStoredEvent(p_event->conn_handle);
}
break;
case PM_EVT_PEER_DATA_UPDATE_FAILED:
break;
case PM_EVT_PEERS_DELETE_SUCCEEDED:
async_ret_code = NRF_SUCCESS; // respond SUCCESS to the busy-loop in f. btle_purgeAllBondingState
break;
case PM_EVT_PEERS_DELETE_FAILED:
async_ret_code = NRF_ERROR_INTERNAL; // respond FAILURE to the busy-loop in f. btle_purgeAllBondingState
break;
case PM_EVT_STORAGE_FULL:
// Run garbage collection on the flash.
err_code = fds_gc();
if (err_code == FDS_ERR_BUSY || err_code == FDS_ERR_NO_SPACE_IN_QUEUES)
{
// Retry.
}
else
{
APP_ERROR_CHECK(err_code);
}
break;//PM_EVT_STORAGE_FULL
case PM_EVT_CONN_SEC_CONFIG_REQ:{
// A connected peer (central) is trying to pair, but the Peer Manager already has a bond
// for that peer. Setting allow_repairing to false rejects the pairing request.
// If this event is ignored (pm_conn_sec_config_reply is not called in the event
// handler), the Peer Manager assumes allow_repairing to be false.
pm_conn_sec_config_t conn_sec_config = {.allow_repairing = true};
pm_conn_sec_config_reply(p_event->conn_handle, &conn_sec_config);
}
break;//PM_EVT_CONN_SEC_CONFIG_REQ
default:
break;
}
}
#if (NRF_SD_BLE_API_VERSION <= 2)
ble_error_t
btle_createWhitelistFromBondTable(ble_gap_whitelist_t *p_whitelist)
{
if (!btle_hasInitializedSecurity()) {
return BLE_ERROR_INITIALIZATION_INCOMPLETE;
}
ret_code_t err = pm_whitelist_create( NULL, BLE_GAP_WHITELIST_ADDR_MAX_COUNT, p_whitelist);
if (err == NRF_SUCCESS) {
return BLE_ERROR_NONE;
} else if (err == NRF_ERROR_NULL) {
return BLE_ERROR_PARAM_OUT_OF_RANGE;
} else {
return BLE_ERROR_INVALID_STATE;
}
}
#endif
bool
btle_matchAddressAndIrk(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk)
{
/*
* Use a helper function from the Nordic SDK to test whether the BLE
* address can be generated using the IRK.
*/
return im_address_resolve(p_addr, p_irk);
}
void
btle_generateResolvableAddress(const ble_gap_irk_t &irk, ble_gap_addr_t &address)
{
/* Set type to resolvable */
address.addr_type = BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE;
/*
* Assign a random number to the most significant 3 bytes
* of the address.
*/
address.addr[BLE_GAP_ADDR_LEN - 3] = 0x8E;
address.addr[BLE_GAP_ADDR_LEN - 2] = 0x4F;
address.addr[BLE_GAP_ADDR_LEN - 1] = 0x7C;
/* Calculate the hash and store it in the top half of the address */
ah(irk.irk, &address.addr[BLE_GAP_ADDR_LEN - 3], address.addr);
}
#if (NRF_SD_BLE_API_VERSION >= 3)
ble_error_t btle_getAddressesFromBondTable(Gap::Whitelist_t &addrList)
{
pm_peer_id_t peer_id;
ret_code_t ret;
pm_peer_data_bonding_t bond_data;
addrList.size = 0;
peer_id = pm_next_peer_id_get(PM_PEER_ID_INVALID);
/**
* Fill addresses list:
* Copy addresses from bond table, or
* for every private resolvable address in the bond table generate the resolvable address.
*/
while ((peer_id != PM_PEER_ID_INVALID) && (addrList.capacity > addrList.size)) {
memset(&bond_data, 0x00, sizeof(bond_data));
// Read peer data from flash.
ret = pm_peer_data_bonding_load(peer_id, &bond_data);
if ((ret == NRF_ERROR_NOT_FOUND) || (ret == NRF_ERROR_INVALID_PARAM)) {
// Peer data could not be found in flash or peer ID is not valid.
return BLE_ERROR_UNSPECIFIED;
}
if (bond_data.peer_ble_id.id_addr_info.addr_type == BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE) {
btle_generateResolvableAddress(bond_data.peer_ble_id.id_info,
(ble_gap_addr_t &) addrList.addresses[addrList.size].address);
} else {
memcpy(&addrList.addresses[addrList.size].address,
&bond_data.peer_ble_id.id_addr_info.addr,
sizeof(addrList.addresses[0].address));
}
addrList.addresses[addrList.size].type = static_cast<BLEProtocol::AddressType_t> (bond_data.peer_ble_id.id_addr_info.addr_type);
addrList.size++;
// get next peer id
peer_id = pm_next_peer_id_get(peer_id);
}
return BLE_ERROR_NONE;
}
#endif
#endif // defined(S130) || defined(S132) || defined(S140)

View File

@ -26,17 +26,21 @@
#include "ble_advdata.h"
#include "headers/nrf_ble_hci.h"
#if (NRF_SD_BLE_API_VERSION >= 3)
#include "peer_manager.h"
#include "peer_data_storage.h"
#endif
void radioNotificationStaticCallback(bool param) {
nRF5xGap &gap = (nRF5xGap &) nRF5xn::Instance(BLE::DEFAULT_INSTANCE).getGap();
gap.processRadioNotificationEvent(param);
}
nRF5xGap::nRF5xGap() : Gap(),
advertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST),
scanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST),
whitelistAddressesSize(0),
_connection_event_handler(NULL)
{
m_connectionHandle = BLE_CONN_HANDLE_INVALID;
}
/**************************************************************************/
/*!
@brief Sets the advertising parameters and payload for the device
@ -936,100 +940,24 @@ Gap::InitiatorPolicyMode_t nRF5xGap::getInitiatorPolicyMode(void) const
/*!
@brief Helper function used to populate the ble_gap_whitelist_t that
will be used by the SoftDevice for filtering requests.
@returns \ref ble_error_t
@retval BLE_ERROR_NONE
Everything executed properly
@retval BLE_ERROR_INVALID_STATE
The internal stack was not initialized correctly.
@note Both the SecurityManager and Gap must initialize correctly for
this function to succeed.
@note This function is needed because for the BLE API the whitelist
is just a collection of keys, but for the stack it also includes
the IRK table.
@section EXAMPLE
@code
@endcode
*/
/**************************************************************************/
ble_error_t nRF5xGap::generateStackWhitelist(ble_gap_whitelist_t &whitelist)
{
ble_gap_whitelist_t whitelistFromBondTable;
ble_gap_addr_t *addressPtr[1];
ble_gap_irk_t *irkPtr[YOTTA_CFG_IRK_TABLE_MAX_SIZE];
nRF5xSecurityManager& securityManager = (nRF5xSecurityManager&) nRF5xn::Instance(0).getSecurityManager();
if (securityManager.hasInitialized()) {
/* We do not care about the addresses, set the count to 0 */
whitelistFromBondTable.addr_count = 0;
/* The Nordic SDK will return a failure if we set pp_addr to NULL */
whitelistFromBondTable.pp_addrs = addressPtr;
/* We want all the IRKs we can get because we do not know which ones match the addresses */
whitelistFromBondTable.irk_count = YOTTA_CFG_IRK_TABLE_MAX_SIZE;
whitelistFromBondTable.pp_irks = irkPtr;
/* Use the security manager to get the IRKs from the bond table */
ble_error_t error = securityManager.createWhitelistFromBondTable(whitelistFromBondTable);
if (error != BLE_ERROR_NONE) {
return error;
}
} else {
/**
* If there is no security manager then we cannot access the bond table,
* so disable IRK matching
*/
whitelistFromBondTable.addr_count = 0;
whitelistFromBondTable.irk_count = 0;
}
/**
* For every private resolvable address in the local whitelist check if
* there is an IRK for said address in the bond table and add it to the
* local IRK list.
*/
whitelist.irk_count = 0;
whitelist.addr_count = 0;
for (uint8_t i = 0; i < whitelistAddressesSize; ++i) {
if (whitelistAddresses[i].addr_type == BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE) {
/* Test if there is a matching IRK for this private resolvable address */
for (uint8_t j = 0; j < whitelistFromBondTable.irk_count; ++j) {
if (securityManager.matchAddressAndIrk(&whitelistAddresses[i], whitelistFromBondTable.pp_irks[j])) {
/* Found the corresponding IRK, add it to our local whitelist */
whitelist.pp_irks[whitelist.irk_count] = whitelistFromBondTable.pp_irks[j];
whitelist.irk_count++;
/* Make sure we do not look at this IRK again */
if (j != whitelistFromBondTable.irk_count - 1) {
/**
* This is not the last IRK, so replace the pointer
* with the last pointer in the array
*/
whitelistFromBondTable.pp_irks[j] =
whitelistFromBondTable.pp_irks[whitelistFromBondTable.irk_count - 1];
}
/**
* If the IRK is the last pointer in the array simply
* decrement the total IRK count
*/
whitelistFromBondTable.irk_count--;
break;
}
}
} else {
/* Include the address into the whitelist */
whitelist.pp_addrs[whitelist.addr_count] = &whitelistAddresses[i];
whitelist.addr_count++;
}
}
return BLE_ERROR_NONE;
return BLE_ERROR_NOT_IMPLEMENTED;
}
#endif
@ -1048,86 +976,7 @@ ble_error_t nRF5xGap::generateStackWhitelist(ble_gap_whitelist_t &whitelist)
ble_error_t nRF5xGap::getStackWhiteIdentityList(GapWhiteAndIdentityList_t &gapAdrHelper)
{
pm_peer_id_t peer_id;
ret_code_t ret;
pm_peer_data_bonding_t bond_data;
uint8_t irk_found[YOTTA_CFG_WHITELIST_MAX_SIZE];
memset(irk_found, 0x00, sizeof(irk_found));
gapAdrHelper.identities_cnt = 0;
peer_id = pm_next_peer_id_get(PM_PEER_ID_INVALID);
nRF5xSecurityManager& securityManager = (nRF5xSecurityManager&) nRF5xn::Instance(0).getSecurityManager();
/**
* Build identities list:
* For every private resolvable address in the bond table check if
* there is maching address in th provided whitelist.
*/
while (peer_id != PM_PEER_ID_INVALID)
{
memset(&bond_data, 0x00, sizeof(bond_data));
// Read peer data from flash.
ret = pm_peer_data_bonding_load(peer_id, &bond_data);
if ((ret == NRF_ERROR_NOT_FOUND) || (ret == NRF_ERROR_INVALID_PARAM))
{
// Peer data could not be found in flash or peer ID is not valid.
return BLE_ERROR_UNSPECIFIED;
}
if ( bond_data.peer_ble_id.id_addr_info.addr_type == BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE)
{
for (uint8_t i = 0; i < whitelistAddressesSize; ++i)
{
if (!irk_found[i])
{
if (whitelistAddresses[i].addr_type == BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE)
{
//ble_gap_irk_t *p_dfg = &bond_data.peer_ble_id.id_info;
if (securityManager.matchAddressAndIrk(&whitelistAddresses[i], &bond_data.peer_ble_id.id_info))
{
// Copy data to the buffer.
memcpy(&gapAdrHelper.identities[i], &bond_data.peer_ble_id, sizeof(ble_gap_id_key_t));
gapAdrHelper.identities_cnt++;
irk_found[i] = 1; // don't look at this address again
}
}
}
}
}
// get next peer id
peer_id = pm_next_peer_id_get(peer_id);
}
gapAdrHelper.addrs_cnt = 0;
/**
* Build whitelist from the rest of addresses (explicit addresses)
*/
for (uint8_t i = 0; i < whitelistAddressesSize; ++i)
{
if (!irk_found[i])
{
memcpy(&gapAdrHelper.addrs[i], &whitelistAddresses[i], sizeof(ble_gap_addr_t));
gapAdrHelper.addrs[i].addr_id_peer = 0;
gapAdrHelper.addrs_cnt++;
}
}
return BLE_ERROR_NONE;
BLE_ERROR_NOT_IMPLEMENTED;
}
ble_error_t nRF5xGap::applyWhiteIdentityList(GapWhiteAndIdentityList_t &gapAdrHelper)
@ -1195,3 +1044,57 @@ ble_error_t nRF5xGap::updateWhiteAndIdentityListInStack()
return applyWhiteIdentityList(whiteAndIdentityList);
}
#endif
void nRF5xGap::set_connection_event_handler(ble::pal::ConnectionEventHandler *connection_event_handler)
{
_connection_event_handler = connection_event_handler;
}
void nRF5xGap::processConnectionEvent(
Handle_t handle,
Role_t role,
BLEProtocol::AddressType_t peerAddrType,
const BLEProtocol::AddressBytes_t peerAddr,
BLEProtocol::AddressType_t ownAddrType,
const BLEProtocol::AddressBytes_t ownAddr,
const ConnectionParams_t *connectionParams
) {
if (_connection_event_handler) {
_connection_event_handler->on_connected(
handle,
role,
peerAddrType,
peerAddr,
ownAddrType,
ownAddr,
connectionParams
);
}
::Gap::processConnectionEvent(
handle,
role,
peerAddrType,
peerAddr,
ownAddrType,
ownAddr,
connectionParams
);
}
void nRF5xGap::processDisconnectionEvent(
Handle_t handle,
DisconnectionReason_t reason
) {
if (_connection_event_handler) {
_connection_event_handler->on_disconnected(
handle,
reason
);
}
::Gap::processDisconnectionEvent(
handle,
reason
);
}

View File

@ -44,6 +44,7 @@
#include "ble/GapAdvertisingData.h"
#include "ble/Gap.h"
#include "ble/GapScanningParams.h"
#include "ble/pal/ConnectionEventMonitor.h"
#include "nrf_soc.h"
@ -52,19 +53,20 @@ extern "C" {
#include "app_util_platform.h"
}
#include "btle_security.h"
void radioNotificationStaticCallback(bool param);
namespace ble { namespace pal { class ConnectionEventHandler; }}
/**************************************************************************/
/*!
\brief
*/
/**************************************************************************/
class nRF5xGap : public Gap
{
class nRF5xGap : public ::Gap, public ble::pal::ConnectionEventMonitor {
public:
nRF5xGap();
/* Functions that must be implemented from Gap */
virtual ble_error_t setAddress(AddressType_t type, const Address_t address);
virtual ble_error_t getAddress(AddressType_t *typeP, Address_t address);
@ -254,21 +256,42 @@ private:
}
friend void radioNotificationStaticCallback(bool param); /* allow invocations of processRadioNotificationEvent() */
private:
public:
/** @note Implements ConnectionEventMonitor.
* @copydoc ConnectionEventMonitor::set_connection_event_handler
*/
void set_connection_event_handler(ble::pal::ConnectionEventHandler *_connection_event_handler);
/**
* @copydoc ::Gap::processConnectionEvent
*/
void processConnectionEvent(
Handle_t handle,
Role_t role,
BLEProtocol::AddressType_t peerAddrType,
const BLEProtocol::AddressBytes_t peerAddr,
BLEProtocol::AddressType_t ownAddrType,
const BLEProtocol::AddressBytes_t ownAddr,
const ConnectionParams_t *connectionParams
);
/**
* @copydoc ::Gap::processDisconnectionEvent
*/
void processDisconnectionEvent(
Handle_t handle,
DisconnectionReason_t reason
);
uint16_t m_connectionHandle;
ble::pal::ConnectionEventHandler* _connection_event_handler;
/*
* Allow instantiation from nRF5xn when required.
*/
friend class nRF5xn;
nRF5xGap() :
advertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST),
scanningPolicyMode(Gap::SCAN_POLICY_IGNORE_WHITELIST),
whitelistAddressesSize(0) {
m_connectionHandle = BLE_CONN_HANDLE_INVALID;
}
nRF5xGap(nRF5xGap const &);
void operator=(nRF5xGap const &);
};

View File

@ -0,0 +1,742 @@
/* mbed Microcontroller Library
* Copyright (c) 2018-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.
*/
#include "nRF5xPalSecurityManager.h"
#include "nrf_ble.h"
#include "nrf_ble_gap.h"
#include "nrf_soc.h"
namespace ble {
namespace pal {
namespace vendor {
namespace nordic {
namespace {
static ble_error_t convert_sd_error(uint32_t err) {
// TODO: implementation
return err ? BLE_ERROR_UNSPECIFIED : BLE_ERROR_NONE;
}
}
nRF5xSecurityManager::nRF5xSecurityManager()
: ::ble::pal::SecurityManager(),
_use_legacy_pairing(true),
_use_secure_connections(true),
_use_default_passkey(false),
_default_passkey(0),
_io_capability(io_capability_t::NO_INPUT_NO_OUTPUT),
_min_encryption_key_size(7),
_max_encryption_key_size(16)
{
}
nRF5xSecurityManager::~nRF5xSecurityManager()
{
}
////////////////////////////////////////////////////////////////////////////
// SM lifecycle management
//
ble_error_t nRF5xSecurityManager::initialize()
{
return BLE_ERROR_NONE;
}
ble_error_t nRF5xSecurityManager::terminate()
{
return BLE_ERROR_NONE;
}
ble_error_t nRF5xSecurityManager::reset()
{
return BLE_ERROR_NONE;
}
////////////////////////////////////////////////////////////////////////////
// Resolving list management
//
// FIXME: on nordic, the irk is passed in sd_ble_gap_scan_start where whitelist
// and resolving list are all mixed up.
uint8_t nRF5xSecurityManager::read_resolving_list_capacity()
{
// FIXME: implement
return 0;
}
ble_error_t nRF5xSecurityManager::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
) {
return BLE_ERROR_NOT_IMPLEMENTED;
}
ble_error_t nRF5xSecurityManager::remove_device_from_resolving_list(
advertising_peer_address_type_t peer_identity_address_type,
const address_t &peer_identity_address
) {
return BLE_ERROR_NOT_IMPLEMENTED;
}
ble_error_t nRF5xSecurityManager::clear_resolving_list()
{
return BLE_ERROR_NOT_IMPLEMENTED;
}
////////////////////////////////////////////////////////////////////////////
// Feature support
//
ble_error_t nRF5xSecurityManager::set_secure_connections_support(
bool enabled, bool secure_connections_only
) {
_use_secure_connections = enabled;
_use_legacy_pairing = !enabled || (enabled && !secure_connections_only);
return BLE_ERROR_NONE;
}
ble_error_t nRF5xSecurityManager::get_secure_connections_support(
bool &enabled
) {
// NRF5x platforms support secure connections
_use_secure_connections = true;
return BLE_ERROR_NONE;
}
////////////////////////////////////////////////////////////////////////////
// Security settings
//
ble_error_t nRF5xSecurityManager::set_authentication_timeout(
connection_handle_t connection, uint16_t timeout_in_10ms
) {
// NOTE: Nothing in the Nordic API to manipulate the authentication timeout
return BLE_ERROR_NOT_IMPLEMENTED;
}
ble_error_t nRF5xSecurityManager::get_authentication_timeout(
connection_handle_t connection, uint16_t &timeout_in_10ms
) {
return BLE_ERROR_NOT_IMPLEMENTED;
}
ble_error_t nRF5xSecurityManager::slave_security_request(
connection_handle_t connection,
AuthenticationMask authentication
) {
// In the peripheral role, only the bond, mitm, lesc and keypress fields of this structure are used.
ble_gap_sec_params_t security_params = {
/* bond */ authentication.get_bondable(),
/* mitm */ authentication.get_mitm(),
/* lesc */ authentication.get_secure_connections(),
/* keypress */ authentication.get_keypress_notification(),
0
};
uint32_t err = sd_ble_gap_authenticate(
connection,
&security_params
);
return convert_sd_error(err);
}
////////////////////////////////////////////////////////////////////////////
// Encryption
//
ble_error_t nRF5xSecurityManager::enable_encryption(
connection_handle_t connection,
const ltk_t &ltk,
const rand_t &rand,
const ediv_t &ediv,
bool mitm
)
{
ble_gap_master_id_t master_id;
ble_gap_enc_info_t enc_info;
memcpy(master_id.rand, rand.data(), rand.size());
memcpy(&master_id.ediv, ediv.data(), ediv.size());
memcpy(enc_info.ltk, ltk.data(), ltk.size());
enc_info.lesc = false;
enc_info.auth = mitm;
enc_info.ltk_len = ltk.size();
uint32_t err = sd_ble_gap_encrypt(
connection,
&master_id,
&enc_info
);
return convert_sd_error(err);
}
ble_error_t nRF5xSecurityManager::enable_encryption(
connection_handle_t connection,
const ltk_t &ltk,
bool mitm
)
{
ble_gap_master_id_t master_id = {0};
ble_gap_enc_info_t enc_info;
memcpy(enc_info.ltk, ltk.data(), ltk.size());
enc_info.lesc = true;
enc_info.auth = mitm;
enc_info.ltk_len = ltk.size();
uint32_t err = sd_ble_gap_encrypt(
connection,
&master_id,
&enc_info
);
return convert_sd_error(err);
}
ble_error_t nRF5xSecurityManager::encrypt_data(
const byte_array_t<16> &key,
encryption_block_t &data
) {
// NO FUNCTION to disable encryption
return BLE_ERROR_NOT_IMPLEMENTED;
}
////////////////////////////////////////////////////////////////////////////
// Privacy
//
ble_error_t nRF5xSecurityManager::set_private_address_timeout(
uint16_t timeout_in_seconds
) {
return BLE_ERROR_NOT_IMPLEMENTED;
}
////////////////////////////////////////////////////////////////////////////
// Keys
//
ble_error_t nRF5xSecurityManager::set_ltk(
connection_handle_t connection,
const ltk_t& ltk,
bool mitm,
bool secure_connections
) {
ble_gap_enc_info_t enc_info;
memcpy(enc_info.ltk, ltk.data(), ltk.size());
enc_info.lesc = secure_connections;
enc_info.auth = mitm;
enc_info.ltk_len = ltk.size();
uint32_t err = sd_ble_gap_sec_info_reply(
connection,
&enc_info,
NULL,
NULL // Not supported
);
return convert_sd_error(err);
}
ble_error_t nRF5xSecurityManager::set_ltk_not_found(
connection_handle_t connection
) {
uint32_t err = sd_ble_gap_sec_info_reply(
connection,
NULL,
NULL,
NULL // Not supported
);
return convert_sd_error(err);
}
ble_error_t nRF5xSecurityManager::set_irk(const irk_t& irk)
{
// TODO
return BLE_ERROR_NOT_IMPLEMENTED;
}
ble_error_t nRF5xSecurityManager::set_csrk(const csrk_t& csrk)
{
// TODO
return BLE_ERROR_NOT_IMPLEMENTED;
}
ble_error_t nRF5xSecurityManager::generate_public_key()
{
// FIXME
return BLE_ERROR_NOT_IMPLEMENTED;
}
////////////////////////////////////////////////////////////////////////////
// Global parameters
//
ble_error_t nRF5xSecurityManager::set_display_passkey(passkey_num_t passkey)
{
if (passkey) {
_use_default_passkey = true;
_default_passkey = passkey;
} else {
_use_default_passkey = false;
}
return BLE_ERROR_NONE;
}
ble_error_t nRF5xSecurityManager::set_io_capability(io_capability_t io_capability)
{
_io_capability = io_capability;
return BLE_ERROR_NONE;
}
ble_error_t nRF5xSecurityManager::set_encryption_key_requirements(
uint8_t min_encryption_key_size,
uint8_t max_encryption_key_size
) {
if ((min_encryption_key_size < 7) || (min_encryption_key_size > 16) ||
(min_encryption_key_size > max_encryption_key_size)) {
return BLE_ERROR_INVALID_PARAM;
}
_min_encryption_key_size = min_encryption_key_size;
_max_encryption_key_size = max_encryption_key_size;
return BLE_ERROR_NONE;
}
////////////////////////////////////////////////////////////////////////////
// Authentication
//
ble_error_t nRF5xSecurityManager::send_pairing_request(
connection_handle_t connection,
bool oob_data_flag,
AuthenticationMask authentication_requirements,
KeyDistribution initiator_dist,
KeyDistribution responder_dist
) {
ble_gap_sec_params_t security_params = {
/* bond */ authentication_requirements.get_bondable(),
/* mitm */ authentication_requirements.get_mitm(),
/* lesc */ authentication_requirements.get_secure_connections(),
/* keypress */ authentication_requirements.get_keypress_notification(),
/* io_caps */ _io_capability.value(),
/* oob */ oob_data_flag,
/* min_key_size */ _min_encryption_key_size,
/* max_key_size */ _max_encryption_key_size,
/* kdist_periph */ {
/* enc */ responder_dist.get_encryption(),
/* id */ responder_dist.get_identity(),
/* sign */ responder_dist.get_signing(),
/* link */ responder_dist.get_link()
},
/* kdist_central */ {
/* enc */ initiator_dist.get_encryption(),
/* id */ initiator_dist.get_identity(),
/* sign */ initiator_dist.get_signing(),
/* link */ initiator_dist.get_link()
}
};
uint32_t err = sd_ble_gap_authenticate(
connection,
&security_params
);
return convert_sd_error(err);
}
ble_error_t nRF5xSecurityManager::send_pairing_response(
connection_handle_t connection,
bool oob_data_flag,
AuthenticationMask authentication_requirements,
KeyDistribution initiator_dist,
KeyDistribution responder_dist
) {
ble_gap_sec_params_t security_params = {
/* bond */ authentication_requirements.get_bondable(),
/* mitm */ authentication_requirements.get_mitm(),
/* lesc */ authentication_requirements.get_secure_connections(),
/* keypress */ authentication_requirements.get_keypress_notification(),
/* io_caps */ _io_capability.value(),
/* oob */ oob_data_flag,
/* min_key_size */ _min_encryption_key_size,
/* max_key_size */ _max_encryption_key_size,
/* kdist_periph */ {
/* enc */ responder_dist.get_encryption(),
/* id */ responder_dist.get_identity(),
/* sign */ responder_dist.get_signing(),
/* link */ responder_dist.get_link()
},
/* kdist_central */ {
/* enc */ initiator_dist.get_encryption(),
/* id */ initiator_dist.get_identity(),
/* sign */ initiator_dist.get_signing(),
/* link */ initiator_dist.get_link()
}
};
ble_gap_sec_keyset_t keyset = {
/* keys_own */ {
/* encryption key */ &_sp_own_enc_key,
/* id key */ &_sp_own_id_key,
/* signing key */ &_sp_own_sign_key,
/* P-256 Public Key */ &_sp_own_pk
},
/* keys_peer */ {
/* encryption key */ &_sp_peer_enc_key,
/* id key */ &_sp_peer_id_key,
/* signing key */ &_sp_peer_sign_key,
/* P-256 Public Key */ &_sp_peer_pk
}
};
uint32_t err = sd_ble_gap_sec_params_reply(
connection,
/* status */ BLE_GAP_SEC_STATUS_SUCCESS,
/* params */ &security_params,
/* keys ... */ &keyset
);
return convert_sd_error(err);
}
ble_error_t nRF5xSecurityManager::cancel_pairing(
connection_handle_t connection, pairing_failure_t reason
) {
// FIXME: there is no fixed function that can be used to cancel pairing all
// the time. However sd_ble_gap_sec_params_reply should be used to cancel a
// pairing after a pairing request.
// sd_ble_gap_auth_key_reply should be used to cancel pairing when a key
// entered by the user is required.
return BLE_ERROR_NOT_IMPLEMENTED;
}
ble_error_t nRF5xSecurityManager::get_random_data(byte_array_t<8> &random_data)
{
uint32_t err = sd_rand_application_vector_get(random_data.buffer(), random_data.size());
return convert_sd_error(err);
}
////////////////////////////////////////////////////////////////////////////
// MITM
//
ble_error_t nRF5xSecurityManager::passkey_request_reply(
connection_handle_t connection, const passkey_num_t passkey
) {
PasskeyAscii pkasc(passkey);
uint32_t err = sd_ble_gap_auth_key_reply(
connection,
BLE_GAP_AUTH_KEY_TYPE_PASSKEY,
pkasc.value()
);
return convert_sd_error(err);
}
ble_error_t nRF5xSecurityManager::legacy_pairing_oob_data_request_reply(
connection_handle_t connection,
const oob_tk_t& oob_data
) {
uint32_t err = sd_ble_gap_auth_key_reply(
connection,
BLE_GAP_AUTH_KEY_TYPE_OOB,
oob_data.data()
);
return convert_sd_error(err);
}
ble_error_t nRF5xSecurityManager::confirmation_entered(
connection_handle_t connection, bool confirmation
) {
uint32_t err;
if(confirmation) {
// Accept
err = sd_ble_gap_auth_key_reply(
connection,
BLE_GAP_AUTH_KEY_TYPE_PASSKEY,
NULL
);
}
else {
// Reject
err = sd_ble_gap_auth_key_reply(
connection,
BLE_GAP_AUTH_KEY_TYPE_NONE,
NULL
);
}
return convert_sd_error(err);
}
ble_error_t nRF5xSecurityManager::send_keypress_notification(
connection_handle_t connection, Keypress_t keypress
) {
uint8_t kp_not = static_cast<uint8_t>(keypress);
uint32_t err = sd_ble_gap_keypress_notify(
connection,
kp_not
);
return convert_sd_error(err);
}
ble_error_t nRF5xSecurityManager::oob_data_verified(
connection_handle_t connection,
const oob_lesc_value_t &local_random,
const oob_lesc_value_t &peer_random
) {
return BLE_ERROR_NOT_IMPLEMENTED;
}
nRF5xSecurityManager& nRF5xSecurityManager::get_security_manager()
{
static nRF5xSecurityManager _security_manager;
return _security_manager;
}
bool nRF5xSecurityManager::sm_handler(const ble_evt_t *evt)
{
SecurityManager::EventHandler* handler =
get_security_manager().get_event_handler();
nRF5xSecurityManager* inst = &nRF5xSecurityManager::get_security_manager();
if ((evt == NULL) || (handler == NULL)) {
return false;
}
const ble_gap_evt_t& gap_evt = evt->evt.gap_evt;
uint16_t connection = gap_evt.conn_handle;
switch (evt->header.evt_id) {
case BLE_GAP_EVT_SEC_PARAMS_REQUEST: {
const ble_gap_sec_params_t& params =
gap_evt.params.sec_params_request.peer_params;
AuthenticationMask authentication_requirements(
params.bond,
params.mitm,
params.lesc,
params.keypress
);
KeyDistribution initiator_dist(
params.kdist_peer.enc,
params.kdist_peer.id,
params.kdist_peer.sign,
params.kdist_peer.link
);
KeyDistribution responder_dist(
params.kdist_own.enc,
params.kdist_own.id,
params.kdist_own.sign,
params.kdist_own.link
);
// FIXME: pass min key size
handler->on_pairing_request(
connection,
params.oob,
authentication_requirements,
initiator_dist,
responder_dist
);
return true;
}
case BLE_GAP_EVT_SEC_INFO_REQUEST: {
const ble_gap_evt_sec_info_request_t& req =
gap_evt.params.sec_info_request;
handler->on_ltk_request(
connection,
ediv_t((uint8_t*)(&req.master_id.ediv)),
rand_t(req.master_id.rand)
);
return true;
}
case BLE_GAP_EVT_PASSKEY_DISPLAY: {
const ble_gap_evt_passkey_display_t& req =
gap_evt.params.passkey_display;
if (req.match_request == 0) {
handler->on_passkey_display(
connection,
PasskeyAscii::to_num(req.passkey)
);
} else {
// handle this case for secure pairing
}
return true;
}
case BLE_GAP_EVT_KEY_PRESSED: {
const ble_gap_evt_key_pressed_t& notf = gap_evt.params.key_pressed;
handler->on_keypress_notification(
connection,
(Keypress_t)notf.kp_not
);
return true;
}
case BLE_GAP_EVT_AUTH_KEY_REQUEST: {
uint8_t key_type = gap_evt.params.auth_key_request.key_type;
switch (key_type) {
case BLE_GAP_AUTH_KEY_TYPE_NONE: // Illegal
break;
case BLE_GAP_AUTH_KEY_TYPE_PASSKEY:
handler->on_passkey_request(connection);
break;
case BLE_GAP_AUTH_KEY_TYPE_OOB:
handler->on_legacy_pairing_oob_request(connection);
break;
}
return true;
}
case BLE_GAP_EVT_LESC_DHKEY_REQUEST:
// TODO: Add with LESC support
return true;
case BLE_GAP_EVT_AUTH_STATUS: {
const ble_gap_evt_auth_status_t& status =
gap_evt.params.auth_status;
switch (status.auth_status) {
case BLE_GAP_SEC_STATUS_SUCCESS:
// Keys stored (_sp*) are valid
handler->on_keys_distributed_local_ltk(
connection,
ltk_t(inst->_sp_own_enc_key.enc_info.ltk)
);
handler->on_keys_distributed_local_ediv_rand(
connection,
ediv_t(reinterpret_cast<uint8_t*>(&inst->_sp_own_enc_key.master_id.ediv)),
inst->_sp_own_enc_key.master_id.rand
);
handler->on_keys_distributed_ltk(
connection,
ltk_t(inst->_sp_peer_enc_key.enc_info.ltk)
);
handler->on_keys_distributed_ediv_rand(
connection,
ediv_t(reinterpret_cast<uint8_t*>(&inst->_sp_peer_enc_key.master_id.ediv)),
inst->_sp_peer_enc_key.master_id.rand
);
break;
// TODO add signing & privacy keys here
case BLE_GAP_SEC_STATUS_TIMEOUT:
handler->on_pairing_timed_out(connection);
break;
case BLE_GAP_SEC_STATUS_PASSKEY_ENTRY_FAILED:
case BLE_GAP_SEC_STATUS_OOB_NOT_AVAILABLE:
case BLE_GAP_SEC_STATUS_AUTH_REQ:
case BLE_GAP_SEC_STATUS_CONFIRM_VALUE:
case BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP:
case BLE_GAP_SEC_STATUS_ENC_KEY_SIZE:
case BLE_GAP_SEC_STATUS_SMP_CMD_UNSUPPORTED:
case BLE_GAP_SEC_STATUS_UNSPECIFIED:
case BLE_GAP_SEC_STATUS_REPEATED_ATTEMPTS:
case BLE_GAP_SEC_STATUS_INVALID_PARAMS:
case BLE_GAP_SEC_STATUS_DHKEY_FAILURE:
case BLE_GAP_SEC_STATUS_NUM_COMP_FAILURE:
case BLE_GAP_SEC_STATUS_BR_EDR_IN_PROG:
case BLE_GAP_SEC_STATUS_X_TRANS_KEY_DISALLOWED:
handler->on_pairing_error(
connection,
(pairing_failure_t::type) (status.auth_status & 0xF)
);
break;
default:
break;
}
return true;
}
case BLE_GAP_EVT_CONN_SEC_UPDATE:
{
const ble_gap_evt_conn_sec_update_t& req =
gap_evt.params.conn_sec_update;
if( (req.conn_sec.sec_mode.sm == 1) && (req.conn_sec.sec_mode.lv >= 2) )
{
handler->on_link_encryption_result(connection, link_encryption_t::ENCRYPTED);
}
else
{
handler->on_link_encryption_result(connection, link_encryption_t::NOT_ENCRYPTED);
}
return true;
}
case BLE_GAP_EVT_TIMEOUT:
// FIXME: forward event when available
return true;
case BLE_GAP_EVT_SEC_REQUEST:
{
const ble_gap_evt_sec_request_t& req =
gap_evt.params.sec_request;
AuthenticationMask auth_mask(req.bond, req.mitm, req.lesc, req.keypress);
handler->on_slave_security_request(
connection,
auth_mask
);
return true;
}
default:
return false;
}
}
} // nordic
} // vendor
} // pal
} // ble

View File

@ -0,0 +1,342 @@
/* mbed Microcontroller Library
* Copyright (c) 2018-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 NRF5X_PAL_SECURITY_MANAGER_
#define NRF5X_PAL_SECURITY_MANAGER_
#include "ble/BLETypes.h"
#include "ble/pal/PalSecurityManager.h"
#include "nrf_ble.h"
namespace ble {
namespace pal {
namespace vendor {
namespace nordic {
class nRF5xSecurityManager : public ::ble::pal::SecurityManager {
public:
nRF5xSecurityManager();
virtual ~nRF5xSecurityManager();
////////////////////////////////////////////////////////////////////////////
// SM lifecycle management
//
/**
* @see ::ble::pal::SecurityManager::initialize
*/
virtual ble_error_t initialize();
/**
* @see ::ble::pal::SecurityManager::terminate
*/
virtual ble_error_t terminate();
/**
* @see ::ble::pal::SecurityManager::reset
*/
virtual ble_error_t reset() ;
////////////////////////////////////////////////////////////////////////////
// Resolving list management
//
/**
* @see ::ble::pal::SecurityManager::read_resolving_list_capacity
*/
virtual uint8_t read_resolving_list_capacity();
/**
* @see ::ble::pal::SecurityManager::add_device_to_resolving_list
*/
virtual ble_error_t 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
);
/**
* @see ::ble::pal::SecurityManager::remove_device_from_resolving_list
*/
virtual ble_error_t remove_device_from_resolving_list(
advertising_peer_address_type_t peer_identity_address_type,
const address_t &peer_identity_address
);
/**
* @see ::ble::pal::SecurityManager::clear_resolving_list
*/
virtual ble_error_t clear_resolving_list();
////////////////////////////////////////////////////////////////////////////
// Feature support
//
/**
* @see ::ble::pal::SecurityManager::set_secure_connections_support
*/
virtual ble_error_t set_secure_connections_support(
bool enabled, bool secure_connections_only = false
);
/**
* @see ::ble::pal::SecurityManager::get_secure_connections_support
*/
virtual ble_error_t get_secure_connections_support(
bool &enabled
);
////////////////////////////////////////////////////////////////////////////
// Security settings
//
/**
* @see ::ble::pal::SecurityManager::set_authentication_timeout
*/
virtual ble_error_t set_authentication_timeout(
connection_handle_t, uint16_t timeout_in_10ms
);
/**
* @see ::ble::pal::SecurityManager::get_authentication_timeout
*/
virtual ble_error_t get_authentication_timeout(
connection_handle_t, uint16_t &timeout_in_10ms
);
virtual ble_error_t slave_security_request(
connection_handle_t connection,
AuthenticationMask authentication
);
////////////////////////////////////////////////////////////////////////////
// Encryption
//
/**
* @see ::ble::pal::SecurityManager::enable_encryption
*/
virtual ble_error_t enable_encryption(
connection_handle_t connection,
const ltk_t &ltk,
const rand_t &rand,
const ediv_t &ediv,
bool mitm
);
/**
* @see ::ble::pal::SecurityManager::enable_encryption
*/
virtual ble_error_t enable_encryption(
connection_handle_t connection,
const ltk_t &ltk,
bool mitm
) ;
/**
* @see ::ble::pal::SecurityManager::encrypt_data
*/
virtual ble_error_t encrypt_data(
const byte_array_t<16> &key,
encryption_block_t &data
);
////////////////////////////////////////////////////////////////////////////
// Privacy
//
/**
* @see ::ble::pal::SecurityManager::set_private_address_timeout
*/
virtual ble_error_t set_private_address_timeout(uint16_t timeout_in_seconds);
////////////////////////////////////////////////////////////////////////////
// Keys
//
/**
* @see ::ble::pal::SecurityManager::set_ltk
*/
virtual ble_error_t set_ltk(
connection_handle_t connection,
const ltk_t &ltk,
bool mitm,
bool secure_connections
);
/**
* @see ::ble::pal::SecurityManager::set_ltk_not_found
*/
virtual ble_error_t set_ltk_not_found(
connection_handle_t connection
);
/**
* @see ::ble::pal::SecurityManager::set_irk
*/
virtual ble_error_t set_irk(const irk_t &irk);
/**
* @see ::ble::pal::SecurityManager::set_csrk
*/
virtual ble_error_t set_csrk(const csrk_t &csrk);
/**
* @see ::ble::pal::SecurityManager::generate_public_key
*/
virtual ble_error_t generate_public_key();
////////////////////////////////////////////////////////////////////////////
// Global parameters
//
/**
* @see ::ble::pal::SecurityManager::set_display_passkey
*/
virtual ble_error_t set_display_passkey(passkey_num_t passkey);
/**
* @see ::ble::pal::SecurityManager::set_io_capability
*/
virtual ble_error_t set_io_capability(io_capability_t io_capability);
/**
* @see ::ble::pal::SecurityManager::set_encryption_key_requirements
*/
virtual ble_error_t set_encryption_key_requirements(
uint8_t min_encryption_key_size,
uint8_t max_encryption_key_size
);
////////////////////////////////////////////////////////////////////////////
// Authentication
//
/**
* @see ::ble::pal::SecurityManager::send_pairing_request
*/
virtual ble_error_t send_pairing_request(
connection_handle_t connection,
bool oob_data_flag,
AuthenticationMask authentication_requirements,
KeyDistribution initiator_dist,
KeyDistribution responder_dist
);
/**
* @see ::ble::pal::SecurityManager::send_pairing_response
*/
virtual ble_error_t send_pairing_response(
connection_handle_t connection,
bool oob_data_flag,
AuthenticationMask authentication_requirements,
KeyDistribution initiator_dist,
KeyDistribution responder_dist
);
/**
* @see ::ble::pal::SecurityManager::cancel_pairing
*/
virtual ble_error_t cancel_pairing(
connection_handle_t connection, pairing_failure_t reason
);
/**
* @see ::ble::pal::SecurityManager::get_random_data
*/
virtual ble_error_t get_random_data(byte_array_t<8> &random_data);
////////////////////////////////////////////////////////////////////////////
// MITM
//
/**
* @see ::ble::pal::SecurityManager::passkey_request_reply
*/
virtual ble_error_t passkey_request_reply(
connection_handle_t connection,
passkey_num_t passkey
);
/**
* @see ::ble::pal::SecurityManager::legacy_pairing_oob_data_request_reply
*/
virtual ble_error_t legacy_pairing_oob_data_request_reply(
connection_handle_t connection,
const oob_tk_t &oob_data
);
/**
* @see ::ble::pal::SecurityManager::confirmation_entered
*/
virtual ble_error_t confirmation_entered(
connection_handle_t connection, bool confirmation
);
/**
* @see ::ble::pal::SecurityManager::send_keypress_notification
*/
virtual ble_error_t send_keypress_notification(
connection_handle_t connection, Keypress_t keypress
);
/**
* @see ::ble::pal::SecurityManager::oob_data_verified
*/
virtual ble_error_t oob_data_verified(
connection_handle_t connection,
const oob_lesc_value_t &local_random,
const oob_lesc_value_t &peer_random
);
// singleton of nordic Security Manager
static nRF5xSecurityManager& get_security_manager();
// Event handler
bool sm_handler(const ble_evt_t *evt);
private:
bool _use_legacy_pairing;
bool _use_secure_connections;
bool _use_default_passkey;
passkey_num_t _default_passkey;
irk_t _irk;
csrk_t _csrk;
io_capability_t _io_capability;
uint8_t _min_encryption_key_size;
uint8_t _max_encryption_key_size;
// The softdevice requires us to manage memory for these keys
ble_gap_enc_key_t _sp_own_enc_key;
ble_gap_id_key_t _sp_own_id_key;
ble_gap_sign_info_t _sp_own_sign_key;
ble_gap_lesc_p256_pk_t _sp_own_pk;
ble_gap_enc_key_t _sp_peer_enc_key;
ble_gap_id_key_t _sp_peer_id_key;
ble_gap_sign_info_t _sp_peer_sign_key;
ble_gap_lesc_p256_pk_t _sp_peer_pk;
};
} // nordic
} // vendor
} // pal
} // ble
#endif /* NRF5X_PAL_SECURITY_MANAGER_ */

View File

@ -1,194 +0,0 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 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 __NRF51822_SECURITY_MANAGER_H__
#define __NRF51822_SECURITY_MANAGER_H__
#include <stddef.h>
#include "nRF5xGap.h"
#include "ble/SecurityManager.h"
#include "btle_security.h"
class nRF5xSecurityManager : public SecurityManager
{
public:
/* Functions that must be implemented from SecurityManager */
virtual ble_error_t init(bool enableBonding,
bool requireMITM,
SecurityIOCapabilities_t iocaps,
const Passkey_t passkey) {
return btle_initializeSecurity(enableBonding, requireMITM, iocaps, passkey);
}
virtual ble_error_t getLinkSecurity(Gap::Handle_t connectionHandle, LinkSecurityStatus_t *securityStatusP) {
return btle_getLinkSecurity(connectionHandle, securityStatusP);
}
virtual ble_error_t setLinkSecurity(Gap::Handle_t connectionHandle, SecurityMode_t securityMode) {
return btle_setLinkSecurity(connectionHandle, securityMode);
}
virtual ble_error_t purgeAllBondingState(void) {
return btle_purgeAllBondingState();
}
#if (NRF_SD_BLE_API_VERSION <= 2)
/**
* @brief Returns a list of addresses from peers in the stacks bond table.
*
* @param[in/out] addresses
* (on input) @ref Gap::Whitelist_t structure where at
* most addresses.capacity addresses from bonded peers will
* be stored.
* (on output) A copy of the addresses from bonded peers.
*
* @return
* BLE_ERROR_NONE if successful.
*/
virtual ble_error_t getAddressesFromBondTable(Gap::Whitelist_t &addresses) const {
uint8_t i;
ble_gap_whitelist_t whitelistFromBondTable;
ble_gap_addr_t *addressPtr[YOTTA_CFG_WHITELIST_MAX_SIZE];
ble_gap_irk_t *irkPtr[YOTTA_CFG_IRK_TABLE_MAX_SIZE];
/* Initialize the structure so that we get as many addreses as the whitelist can hold */
whitelistFromBondTable.addr_count = YOTTA_CFG_IRK_TABLE_MAX_SIZE;
whitelistFromBondTable.pp_addrs = addressPtr;
whitelistFromBondTable.irk_count = YOTTA_CFG_IRK_TABLE_MAX_SIZE;
whitelistFromBondTable.pp_irks = irkPtr;
ble_error_t error = createWhitelistFromBondTable(whitelistFromBondTable);
if (error != BLE_ERROR_NONE) {
addresses.size = 0;
return error;
}
/* Put all the addresses in the structure */
for (i = 0; i < whitelistFromBondTable.addr_count; ++i) {
if (i >= addresses.capacity) {
/* Ran out of space in the output Gap::Whitelist_t */
addresses.size = i;
return BLE_ERROR_NONE;
}
memcpy(&addresses.addresses[i], whitelistFromBondTable.pp_addrs[i], sizeof(BLEProtocol::Address_t));
}
/* Update the current address count */
addresses.size = i;
/* The assumption here is that the underlying implementation of
* createWhitelistFromBondTable() will not return the private resolvable
* addresses (which is the case in the SoftDevice). Rather it returns the
* IRKs, so we need to generate the private resolvable address by ourselves.
*/
for (i = 0; i < whitelistFromBondTable.irk_count; ++i) {
if (i + addresses.size >= addresses.capacity) {
/* Ran out of space in the output Gap::Whitelist_t */
addresses.size += i;
return BLE_ERROR_NONE;
}
btle_generateResolvableAddress(
*whitelistFromBondTable.pp_irks[i],
(ble_gap_addr_t &) addresses.addresses[i + addresses.size]
);
}
/* Update the current address count */
addresses.size += i;
return BLE_ERROR_NONE;
}
#else // -> NRF_SD_BLE_API_VERSION >= 3
/**
* @brief Returns a list of addresses from peers in the stacks bond table.
*
* @param[in/out] addresses
* (on input) @ref Gap::Whitelist_t structure where at
* most addresses.capacity addresses from bonded peers will
* be stored.
* (on output) A copy of the addresses from bonded peers.
*
* @retval BLE_ERROR_NONE if successful.
* @retval BLE_ERROR_UNSPECIFIED Bond data could not be found in flash or is inconsistent.
*/
virtual ble_error_t getAddressesFromBondTable(Gap::Whitelist_t &addresses) const {
return btle_getAddressesFromBondTable(addresses);
}
#endif // #if (NRF_SD_BLE_API_VERSION <= 2)
/**
* @brief Clear nRF5xSecurityManager's state.
*
* @return
* BLE_ERROR_NONE if successful.
*/
virtual ble_error_t reset(void)
{
if (SecurityManager::reset() != BLE_ERROR_NONE) {
return BLE_ERROR_INVALID_STATE;
}
return BLE_ERROR_NONE;
}
bool hasInitialized(void) const {
return btle_hasInitializedSecurity();
}
public:
/*
* Allow instantiation from nRF5xn when required.
*/
friend class nRF5xn;
nRF5xSecurityManager() {
/* empty */
}
private:
nRF5xSecurityManager(const nRF5xSecurityManager &);
const nRF5xSecurityManager& operator=(const nRF5xSecurityManager &);
#if (NRF_SD_BLE_API_VERSION <= 2)
/*
* Expose an interface that allows us to query the SoftDevice bond table
* and extract a whitelist.
*/
ble_error_t createWhitelistFromBondTable(ble_gap_whitelist_t &whitelistFromBondTable) const {
return btle_createWhitelistFromBondTable(&whitelistFromBondTable);
}
#endif
/*
* Given a BLE address and a IRK this function check whether the address
* can be generated from the IRK. To do so, this function uses the hash
* function and algorithm described in the Bluetooth low Energy
* Specification. Internally, Nordic SDK functions are used.
*/
bool matchAddressAndIrk(ble_gap_addr_t *address, ble_gap_irk_t *irk) const {
return btle_matchAddressAndIrk(address, irk);
}
/*
* Give nRF5xGap access to createWhitelistFromBondTable() and
* matchAddressAndIrk()
*/
friend class nRF5xGap;
};
#endif // ifndef __NRF51822_SECURITY_MANAGER_H__

View File

@ -62,8 +62,7 @@ nRF5xn::nRF5xn(void) :
instanceID(BLE::DEFAULT_INSTANCE),
gapInstance(),
gattServerInstance(NULL),
gattClient(&(ble::pal::vendor::nordic::nRF5XGattClient::get_client())),
securityManagerInstance(NULL)
gattClient(&(ble::pal::vendor::nordic::nRF5XGattClient::get_client()))
{
}
@ -171,7 +170,6 @@ ble_error_t nRF5xn::shutdown(void)
return BLE_STACK_BUSY;
}
/* Shutdown the BLE API and nRF51 glue code */
ble_error_t error;
@ -182,13 +180,6 @@ ble_error_t nRF5xn::shutdown(void)
}
}
if (securityManagerInstance != NULL) {
error = securityManagerInstance->reset();
if (error != BLE_ERROR_NONE) {
return error;
}
}
/* S110 does not support BLE client features, nothing to reset. */
#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110)
error = getGattClient().reset();
@ -209,6 +200,25 @@ ble_error_t nRF5xn::shutdown(void)
return BLE_ERROR_NONE;
}
SecurityManager& nRF5xn::getSecurityManager()
{
const nRF5xn* self = this;
return const_cast<SecurityManager&>(self->getSecurityManager());
}
const SecurityManager& nRF5xn::getSecurityManager() const
{
static ble::pal::MemorySecurityDb m_db;
ble::pal::vendor::nordic::nRF5xSecurityManager &m_pal = ble::pal::vendor::nordic::nRF5xSecurityManager::get_security_manager();
static ble::generic::GenericSecurityManager m_instance(
m_pal,
m_db,
const_cast<nRF5xGap&>(getGap())
);
return m_instance;
}
void
nRF5xn::waitForEvent(void)
{

View File

@ -21,10 +21,14 @@
#include "ble/blecommon.h"
#include "ble/BLEInstanceBase.h"
#include "ble/generic/GenericGattClient.h"
#include "ble/generic/GenericSecurityManager.h"
#include "ble/pal/MemorySecurityDB.h"
#include "ble/pal/SimpleEventQueue.h"
#include "nRF5xPalSecurityManager.h"
#include "nRF5xGap.h"
#include "nRF5xGattServer.h"
#include "nRF5xSecurityManager.h"
#include "btle.h"
@ -82,18 +86,14 @@ public:
}
/**
* Accessors to Security Manager. This function checks whether a SecurityManager
* object was previously instantiated. If such object does not exist, then
* it is created before returning.
*
* @return A reference to GattServer.
* @see BLEInstanceBase::getSecurityManager
*/
virtual nRF5xSecurityManager &getSecurityManager() {
if (securityManagerInstance == NULL) {
securityManagerInstance = new nRF5xSecurityManager();
}
return *securityManagerInstance;
}
virtual SecurityManager &getSecurityManager();
/**
* @see BLEInstanceBase::getSecurityManager
*/
virtual const SecurityManager &getSecurityManager() const;
/**
* Accessors to GAP. This function checks whether gapInstance points to an
@ -130,23 +130,6 @@ public:
return *gattServerInstance;
};
/**
* Accessors to Security Manager. This function checks whether a SecurityManager
* object was previously instantiated. If such object does not exist, then
* it is created before returning.
*
* @return A const reference to GattServer.
*
* @note The accessor is able to modify the object's state because the
* internal pointer has been declared mutable.
*/
virtual const nRF5xSecurityManager &getSecurityManager() const {
if (securityManagerInstance == NULL) {
securityManagerInstance = new nRF5xSecurityManager();
}
return *securityManagerInstance;
}
virtual void waitForEvent(void);
virtual void processEvents();
@ -170,10 +153,7 @@ private:
* it can be assigned inside a 'const' function. */
ble::generic::GenericGattClient gattClient;
mutable nRF5xSecurityManager *securityManagerInstance; /**< Pointer to the SecurityManager object instance.
* If NULL, then SecurityManager has not been initialized.
* The pointer has been declared as 'mutable' so that
* it can be assigned inside a 'const' function. */
};
#endif