MicroBit as BLE gamepad
Fork of nRF51822 by
Diff: source/btle/btle_security.cpp
- Revision:
- 615:65ea2acfc6a2
- Parent:
- 613:cbc548e9df98
- Child:
- 616:a8f9b022d8fd
--- a/source/btle/btle_security.cpp Tue Jan 12 19:58:02 2016 +0000 +++ b/source/btle/btle_security.cpp Wed Apr 06 22:38:43 2016 +0100 @@ -1,316 +1,209 @@ -/* 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. - */ - -#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 -static ble_gap_sec_params_t securityParameters = { - .bond = true, /**< Perform bonding. */ - .mitm = true, /**< Man In The Middle protection required. */ - .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_periph = { - .enc = 1, /**< Long Term Key and Master Identification. */ - .id = 1, /**< Identity Resolving Key and Identity Address Information. */ - .sign = 1, /**< Connection Signature Resolving Key. */ - }, /**< 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, ¶ms); - - 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); +/* 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. + */ + +#include "btle.h" +#include "pstorage.h" + +#include "nRF5xGap.h" +#include "nRF5xSecurityManager.h" + +#include "device_manager.h" +#include "btle_security.h" + +static dm_application_instance_t applicationInstance; +static ret_code_t dm_handler(dm_handle_t const *p_handle, dm_event_t const *p_event, ret_code_t event_result); + +ble_error_t +btle_initializeSecurity(bool enableBonding, + bool requireMITM, + SecurityManager::SecurityIOCapabilities_t iocaps, + const SecurityManager::Passkey_t passkey) +{ + /* guard against multiple initializations */ + static bool initialized = false; + 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; + } + + const dm_application_param_t dm_param = { + .evt_handler = dm_handler, + .service_type = DM_PROTOCOL_CNTXT_GATT_CLI_ID, + .sec_param = { + .bond = enableBonding,/**< Perform bonding. */ + .mitm = requireMITM, /**< Man In The Middle protection required. */ + .io_caps = iocaps, /**< 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_periph = { + .enc = 1, /**< Long Term Key and Master Identification. */ + .id = 1, /**< Identity Resolving Key and Identity Address Information. */ + .sign = 1, /**< Connection Signature Resolving Key. */ + }, /**< Key distribution bitmap: keys that the peripheral device will distribute. */ + } + }; + + 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; +} + +ret_code_t +dm_handler(dm_handle_t const *p_handle, dm_event_t const *p_event, ret_code_t event_result) +{ + 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; + nRF5xSecurityManager::getInstance().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: + nRF5xSecurityManager::getInstance(). + 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; + } + + nRF5xSecurityManager::getInstance().processLinkSecuredEvent(p_event->event_param.p_gap_param->conn_handle, resolvedSecurityMode); + break; + } + case DM_EVT_DEVICE_CONTEXT_STORED: + nRF5xSecurityManager::getInstance().processSecurityContextStoredEvent(p_event->event_param.p_gap_param->conn_handle); + break; + default: + break; + } + + return NRF_SUCCESS; } \ No newline at end of file