From 2bb9fcaf26498a93915b00c9a0577f7c8e955e4c Mon Sep 17 00:00:00 2001 From: XuGuohui Date: Fri, 25 Dec 2020 22:39:48 +0800 Subject: [PATCH 1/9] BLE: supports LESC pairing. --- hal/inc/ble_hal.h | 31 +++- hal/inc/hal_dynalib_ble.h | 2 + hal/src/nRF52840/ble_hal.cpp | 266 ++++++++++++++++++++++++++------ wiring/inc/spark_wiring_ble.h | 11 +- wiring/src/spark_wiring_ble.cpp | 19 ++- 5 files changed, 278 insertions(+), 51 deletions(-) diff --git a/hal/inc/ble_hal.h b/hal/inc/ble_hal.h index 694dedaa52..d4a8ce63f5 100644 --- a/hal/inc/ble_hal.h +++ b/hal/inc/ble_hal.h @@ -42,7 +42,7 @@ extern "C" { * @{ */ -#define BLE_API_VERSION 1 +#define BLE_API_VERSION 2 // Particle's company ID #define PARTICLE_COMPANY_ID 0x0662 @@ -120,6 +120,12 @@ typedef enum hal_ble_pairing_io_caps_t { BLE_IO_CAPS_KEYBOARD_DISPLAY = 4 } hal_ble_pairing_io_caps_t; +typedef enum hal_ble_pairing_algorithm_t { + BLE_PAIRING_ALGORITHM_LEGACY_ONLY = 0, + BLE_PAIRING_ALGORITHM_LESC_ONLY = 1, + BLE_PAIRING_ALGORITHM_AUTO = 2 +} hal_ble_pairing_algorithm_t; + typedef enum hal_ble_evts_type_t { BLE_EVT_UNKNOWN = 0x00, BLE_EVT_ADV_STOPPED = 0x01, @@ -137,6 +143,7 @@ typedef enum hal_ble_evts_type_t { BLE_EVT_PAIRING_PASSKEY_DISPLAY = 0x0D, BLE_EVT_PAIRING_PASSKEY_INPUT = 0x0E, BLE_EVT_PAIRING_STATUS_UPDATED = 0x0F, + BLE_EVT_PAIRING_NUMERIC_COMPARISON = 0x10, BLE_EVT_MAX = 0x7FFFFFFF } hal_ble_evts_type_t; @@ -397,7 +404,8 @@ typedef struct hal_ble_pairing_config_t { uint16_t version; uint16_t size; hal_ble_pairing_io_caps_t io_caps; - uint8_t reserved[3]; + hal_ble_pairing_algorithm_t algorithm; + uint8_t reserved[2]; } hal_ble_pairing_config_t; /** @@ -833,6 +841,15 @@ int hal_ble_gap_get_rssi(hal_ble_conn_handle_t conn_handle, void* reserved); */ int hal_ble_gap_set_pairing_config(const hal_ble_pairing_config_t* config, void* reserved); +/** + * Get pairing configurations + * + * @param[in] config Pointer to where it stores the configuration. + * + * @returns 0 on success, system_error_t on error. + */ +int hal_ble_gap_get_pairing_config(hal_ble_pairing_config_t* config, void* reserved); + /** * Start pairing with the peer device. * @@ -860,6 +877,16 @@ int hal_ble_gap_reject_pairing(hal_ble_conn_handle_t conn_handle, void* reserved */ int hal_ble_gap_set_pairing_passkey(hal_ble_conn_handle_t conn_handle, const uint8_t* passkey, void* reserved); +/** + * Confirm the LESC numeric comparision result. + * + * @param[in] conn_handle BLE connection handle. + * @param[in] equal True if the numeric comparison is equal, otherwise, false. + * + * @returns 0 on success, system_error_t on error. + */ +int hal_ble_gap_set_lesc_numeric_comparison(hal_ble_conn_handle_t conn_handle, bool equal, void* reserved); + /** * Check if pairing with peer device is in progress * diff --git a/hal/inc/hal_dynalib_ble.h b/hal/inc/hal_dynalib_ble.h index a6a0d25348..08ca7546e5 100644 --- a/hal/inc/hal_dynalib_ble.h +++ b/hal/inc/hal_dynalib_ble.h @@ -103,6 +103,8 @@ DYNALIB_FN(68, hal_ble, hal_ble_gap_reject_pairing, int(hal_ble_conn_handle_t, v DYNALIB_FN(69, hal_ble, hal_ble_gap_set_pairing_passkey, int(hal_ble_conn_handle_t, const uint8_t*, void*)) DYNALIB_FN(70, hal_ble, hal_ble_gap_is_pairing, bool(hal_ble_conn_handle_t, void*)) DYNALIB_FN(71, hal_ble, hal_ble_gap_is_paired, bool(hal_ble_conn_handle_t, void*)) +DYNALIB_FN(72, hal_ble, hal_ble_gap_set_lesc_numeric_comparison, int(hal_ble_conn_handle_t, bool, void*)) +DYNALIB_FN(73, hal_ble, hal_ble_gap_get_pairing_config, int(hal_ble_pairing_config_t*, void*)) DYNALIB_END(hal_ble) diff --git a/hal/src/nRF52840/ble_hal.cpp b/hal/src/nRF52840/ble_hal.cpp index 847cea3c1f..41ab9bb46a 100644 --- a/hal/src/nRF52840/ble_hal.cpp +++ b/hal/src/nRF52840/ble_hal.cpp @@ -55,6 +55,9 @@ LOG_SOURCE_CATEGORY("hal.ble"); #include "check.h" #include "scope_guard.h" +#include "mbedtls/ecdh.h" +#include "mbedtls_util.h" + using namespace particle; #include "intrusive_list.h" @@ -69,6 +72,9 @@ using namespace particle::ble; #endif #define SUB1(X) (((X)>0) ? ((X)-1) : (X)) +#define BLE_API_VERSION_1 1 +#define BLE_API_VERSION_2 2 + //anonymous namespace namespace { @@ -405,8 +411,14 @@ class BleObject::ConnectionsManager { disconnectSemaphore_(nullptr), attMtuExchangeConnHandle_(BLE_INVALID_CONN_HANDLE), attMtuExchangeTimer_(nullptr), - ioCaps_(BLE_IO_CAPS_NONE) { + ecdhContextInit_(false) { connectingAddr_ = {}; + pairingConfig_ = { + .version = BLE_API_VERSION, + .size = sizeof(hal_ble_pairing_config_t), + .io_caps = BLE_IO_CAPS_NONE, + .algorithm = BLE_PAIRING_ALGORITHM_AUTO + }; } ~ConnectionsManager() = default; int init(); @@ -425,8 +437,10 @@ class BleObject::ConnectionsManager { int updateConnectionParams(hal_ble_conn_handle_t connHandle, const hal_ble_conn_params_t* params); int getConnectionInfo(hal_ble_conn_handle_t connHandle, hal_ble_conn_info_t* info); int setPairingConfig(const hal_ble_pairing_config_t* config); + int getPairingConfig(hal_ble_pairing_config_t* config) const; int startPairing(hal_ble_conn_handle_t connHandle); int rejectPairing(hal_ble_conn_handle_t connHandle); + int lescNumericComparison(hal_ble_conn_handle_t connHandle, bool equal); int setPairingPasskey(hal_ble_conn_handle_t connHandle, const uint8_t* passkey); bool isPairing(hal_ble_conn_handle_t connHandle); bool isPaired(hal_ble_conn_handle_t connHandle); @@ -454,7 +468,8 @@ class BleObject::ConnectionsManager { BLE_PAIRING_STATE_PASSKEY_DISPLAY, BLE_PAIRING_STATE_PASSKEY_INPUT, BLE_PAIRING_STATE_REJECTED, - BLE_PAIRING_STATE_PAIRED + BLE_PAIRING_STATE_PAIRED, + BLE_PAIRING_STATE_LESC_KEY_CONFIRMED, }; struct BleConnection { @@ -462,8 +477,13 @@ class BleObject::ConnectionsManager { BleLinkEventHandler handler; // It is used for central link only. bool isMtuExchanged; BlePairingState pairState; + std::shared_ptr peerPublicKey; }; + int initSecParams(const hal_ble_pairing_config_t& config, ble_gap_sec_params_t& params); + int generateEcdhKeyPair(void); + int publicKeysPrepare(BleConnection* connection); + int computeDhkey(const uint8_t peerPublicKey[BLE_GAP_LESC_P256_PK_LEN], uint8_t dhKey[BLE_GAP_LESC_DHKEY_LEN]); int configureAttMtu(hal_ble_conn_handle_t connHandle, size_t effective); bool attMtuExchanged(hal_ble_conn_handle_t connHandle); BleConnection* fetchConnection(hal_ble_conn_handle_t connHandle); @@ -494,11 +514,14 @@ class BleObject::ConnectionsManager { os_semaphore_t disconnectSemaphore_; /**< Semaphore to wait until connection disconnected. */ volatile hal_ble_conn_handle_t attMtuExchangeConnHandle_; /**< Current handle of the connection to execute ATT_MTU exchange procedure. */ os_timer_t attMtuExchangeTimer_; /**< Timer used for sending the exchanging ATT_MTU request after connection established. */ - hal_ble_pairing_io_caps_t ioCaps_; // GATT Server and GATT client share the same ATT_MTU. static size_t desiredAttMtu_; Vector connections_; Vector peripheralLinkEventHandlers_; /**< It is used for peripheral link only. */ + hal_ble_pairing_config_t pairingConfig_; + mbedtls_ecdh_context ecdhContext_; + bool ecdhContextInit_; + std::shared_ptr localPublicKey_; }; size_t BleObject::ConnectionsManager::desiredAttMtu_ = BLE_MAX_ATT_MTU_SIZE; @@ -741,6 +764,8 @@ os_thread_return_t BleObject::BleEventDispatcher::processBleEventFromThread(void case BLE_GATTC_EVT_HVX: { BleObject::getInstance().gattc()->processDataNotifiedEventFromThread(event); } + case BLE_GAP_EVT_SEC_INFO_REQUEST: + case BLE_GAP_EVT_LESC_DHKEY_REQUEST: case BLE_GAP_EVT_PASSKEY_DISPLAY: case BLE_GAP_EVT_AUTH_KEY_REQUEST: case BLE_GAP_EVT_SEC_REQUEST: @@ -1673,6 +1698,11 @@ int BleObject::ConnectionsManager::init() { LOG(ERROR, "os_timer_create() failed."); goto error; } + if (generateEcdhKeyPair() != SYSTEM_ERROR_NONE) { + LOG(ERROR, "generateEcdhKeyPair() failed."); + } else { + ecdhContextInit_ = true; + } connMgrImpl.instance = this; NRF_SDH_BLE_OBSERVER(bleConnectionManager, 1, processConnectionEvents, &connMgrImpl); connMgrInitialized_ = true; @@ -1883,9 +1913,89 @@ int BleObject::ConnectionsManager::getConnectionInfo(hal_ble_conn_handle_t connH return SYSTEM_ERROR_NONE; } +int BleObject::ConnectionsManager::initSecParams(const hal_ble_pairing_config_t& config, ble_gap_sec_params_t& secParams) { + if (config.io_caps == BLE_IO_CAPS_NONE) { + secParams.mitm = false; + } else { + secParams.mitm = true; + } + if (config.algorithm == BLE_PAIRING_ALGORITHM_LEGACY_ONLY) { + secParams.lesc = false; + } else { + secParams.lesc = true; + } + secParams.io_caps = toPlatformIoCaps(config.io_caps); + secParams.keypress = false; + secParams.bond = false; + secParams.oob = false; + secParams.min_key_size = BLE_ENC_MIN_KEY_SIZE; + secParams.max_key_size = BLE_ENC_MAX_KEY_SIZE; + secParams.kdist_own.enc = true; + secParams.kdist_own.id = true; + secParams.kdist_peer.enc = true; + secParams.kdist_peer.id = true; + return SYSTEM_ERROR_NONE; +} + +int BleObject::ConnectionsManager::generateEcdhKeyPair(void) { + mbedtls_ecdh_init(&ecdhContext_); + CHECK_MBEDTLS(mbedtls_ecdh_setup(&ecdhContext_, MBEDTLS_ECP_DP_SECP256R1)); + CHECK_MBEDTLS(mbedtls_ecdh_gen_public(&ecdhContext_.ctx.mbed_ecdh.grp, &ecdhContext_.ctx.mbed_ecdh.d, + &ecdhContext_.ctx.mbed_ecdh.Q, mbedtls_default_rng, nullptr)); + return SYSTEM_ERROR_NONE; +} + +int BleObject::ConnectionsManager::publicKeysPrepare(BleConnection* connection) { + CHECK_TRUE(ecdhContextInit_, SYSTEM_ERROR_INVALID_STATE); + int ret = SYSTEM_ERROR_CRYPTO; + SCOPE_GUARD ({ + if (localPublicKey_ && ret != SYSTEM_ERROR_NONE) { + localPublicKey_.reset(); + } + }); + // Local public key: won't be freed. + if (!localPublicKey_) { + localPublicKey_.reset((ble_gap_lesc_p256_pk_t*)malloc(sizeof(ble_gap_lesc_p256_pk_t))); + CHECK_TRUE(localPublicKey_, SYSTEM_ERROR_NO_MEMORY); + const uint8_t pointLen = BLE_GAP_LESC_P256_PK_LEN / 2; + CHECK_MBEDTLS(mbedtls_mpi_write_binary_le(&ecdhContext_.ctx.mbed_ecdh.Q.X, &(localPublicKey_.get()->pk[0]), pointLen)); + CHECK_MBEDTLS(mbedtls_mpi_write_binary_le(&ecdhContext_.ctx.mbed_ecdh.Q.Y, &(localPublicKey_.get()->pk[pointLen]), pointLen)); + } + ret = SYSTEM_ERROR_NONE; + // Peer public key: will be freed on authentication status updated or disconnected. + connection->peerPublicKey.reset((ble_gap_lesc_p256_pk_t*)malloc(sizeof(ble_gap_lesc_p256_pk_t))); + CHECK_TRUE(connection->peerPublicKey, SYSTEM_ERROR_NO_MEMORY); + memset(connection->peerPublicKey.get(), 0x00, BLE_GAP_LESC_P256_PK_LEN); + return ret; +} + +int BleObject::ConnectionsManager::computeDhkey(const uint8_t peerPublicKey[BLE_GAP_LESC_P256_PK_LEN], uint8_t dhKey[BLE_GAP_LESC_DHKEY_LEN]) { + CHECK_TRUE(ecdhContextInit_, SYSTEM_ERROR_INVALID_STATE); + const uint8_t pointLen = BLE_GAP_LESC_P256_PK_LEN / 2; + CHECK_MBEDTLS(mbedtls_mpi_read_binary_le(&ecdhContext_.ctx.mbed_ecdh.Qp.X, &peerPublicKey[0], pointLen)); + CHECK_MBEDTLS(mbedtls_mpi_read_binary_le(&ecdhContext_.ctx.mbed_ecdh.Qp.Y, &peerPublicKey[pointLen], pointLen)); + CHECK_MBEDTLS(mbedtls_mpi_lset(&ecdhContext_.ctx.mbed_ecdh.Qp.Z, 1)); + CHECK_MBEDTLS(mbedtls_ecdh_compute_shared(&ecdhContext_.ctx.mbed_ecdh.grp, &ecdhContext_.ctx.mbed_ecdh.z, + &ecdhContext_.ctx.mbed_ecdh.Qp, &ecdhContext_.ctx.mbed_ecdh.d, mbedtls_default_rng, nullptr)); + CHECK_MBEDTLS(mbedtls_mpi_write_binary_le(&ecdhContext_.ctx.mbed_ecdh.z, dhKey, BLE_GAP_LESC_DHKEY_LEN)); + return SYSTEM_ERROR_NONE; +} + int BleObject::ConnectionsManager::setPairingConfig(const hal_ble_pairing_config_t* config) { CHECK_TRUE(config, SYSTEM_ERROR_INVALID_ARGUMENT); - ioCaps_ = config->io_caps; + memcpy(&pairingConfig_, config, std::min(pairingConfig_.size, config->size)); + if (config->version < BLE_API_VERSION_2) { + // Without rebuilding the user application against the newer Device OS, device can support LESC as well. + pairingConfig_.algorithm = BLE_PAIRING_ALGORITHM_AUTO; + } + pairingConfig_.version = BLE_API_VERSION; + pairingConfig_.size = sizeof(hal_ble_pairing_config_t); + return SYSTEM_ERROR_NONE; +} + +int BleObject::ConnectionsManager::getPairingConfig(hal_ble_pairing_config_t* config) const { + CHECK_TRUE(config, SYSTEM_ERROR_INVALID_ARGUMENT); + memcpy(config, &pairingConfig_, std::min(pairingConfig_.size, config->size)); return SYSTEM_ERROR_NONE; } @@ -1896,19 +2006,7 @@ int BleObject::ConnectionsManager::startPairing(hal_ble_conn_handle_t connHandle connection->pairState == BLE_PAIRING_STATE_REJECTED || connection->pairState == BLE_PAIRING_STATE_SEC_REQ_RECEIVED, SYSTEM_ERROR_INVALID_STATE); ble_gap_sec_params_t secParams = {}; - if (ioCaps_ != BLE_IO_CAPS_NONE) { - secParams.mitm = true; - } - if (connection->info.role == BLE_ROLE_CENTRAL) { - secParams.io_caps = toPlatformIoCaps(ioCaps_); - secParams.oob = false; - secParams.min_key_size = BLE_ENC_MIN_KEY_SIZE; - secParams.max_key_size = BLE_ENC_MAX_KEY_SIZE; - secParams.kdist_own.enc = true; - secParams.kdist_own.id = true; - secParams.kdist_peer.enc = true; - secParams.kdist_peer.id = true; - } + initSecParams(pairingConfig_, secParams); LOG_DEBUG(TRACE, "Own security params: %d, %d, %d, %d, %d, %d", secParams.bond, secParams.mitm, secParams.lesc, secParams.io_caps, secParams.keypress, secParams.oob); int ret = sd_ble_gap_authenticate(connection->info.conn_handle, &secParams); if (ret != NRF_SUCCESS) { @@ -1960,6 +2058,24 @@ int BleObject::ConnectionsManager::rejectPairing(hal_ble_conn_handle_t connHandl return SYSTEM_ERROR_NONE; } +int BleObject::ConnectionsManager::lescNumericComparison(hal_ble_conn_handle_t connHandle, bool equal) { + BleConnection* connection = fetchConnection(connHandle); + CHECK_TRUE(connection, SYSTEM_ERROR_NOT_FOUND); + CHECK_TRUE(connection->pairState == BLE_PAIRING_STATE_PASSKEY_DISPLAY, SYSTEM_ERROR_INVALID_STATE); + int ret; + if (equal) { + ret = sd_ble_gap_auth_key_reply(connHandle, BLE_GAP_AUTH_KEY_TYPE_PASSKEY, nullptr); + } else { + ret = sd_ble_gap_auth_key_reply(connHandle, BLE_GAP_AUTH_KEY_TYPE_NONE/*reject*/, nullptr); + } + connection->pairState = BLE_PAIRING_STATE_LESC_KEY_CONFIRMED; + if (ret != NRF_SUCCESS) { + connection->pairState = BLE_PAIRING_STATE_NOT_INITIATED; + return nrf_system_error(ret); + } + return SYSTEM_ERROR_NONE; +} + int BleObject::ConnectionsManager::setPairingPasskey(hal_ble_conn_handle_t connHandle, const uint8_t* passkey) { BleConnection* connection = fetchConnection(connHandle); CHECK_TRUE(connection, SYSTEM_ERROR_NOT_FOUND); @@ -2296,7 +2412,7 @@ int BleObject::ConnectionsManager::processSecurityEventFromThread(const ble_evt_ CHECK_TRUE(connection, SYSTEM_ERROR_NOT_FOUND); CHECK_TRUE(connection->pairState != BLE_PAIRING_STATE_PAIRED, SYSTEM_ERROR_INVALID_STATE); if (event->header.evt_id == BLE_GAP_EVT_SEC_REQUEST) { - LOG_DEBUG(TRACE, "BLE event: BLE_GAP_EVT_SEC_REQUEST"); + LOG(ERROR, "BLE event: BLE_GAP_EVT_SEC_REQUEST"); if (connection->info.role == BLE_ROLE_CENTRAL) { connection->pairState = BLE_PAIRING_STATE_SEC_REQ_RECEIVED; hal_ble_link_evt_t linkEvent = {}; @@ -2305,18 +2421,22 @@ int BleObject::ConnectionsManager::processSecurityEventFromThread(const ble_evt_ notifyLinkEvent(linkEvent); // User application may call rejectPairing() to update the pairing state in event handler if (connection->pairState != BLE_PAIRING_STATE_REJECTED) { + const ble_gap_evt_sec_request_t& secRequest = event->evt.gap_evt.params.sec_request; + if (pairingConfig_.algorithm == BLE_PAIRING_ALGORITHM_LESC_ONLY) { + if (secRequest.lesc == false) { + rejectPairing(event->evt.gap_evt.conn_handle); + } + } return startPairing(event->evt.gap_evt.conn_handle); } } } else if (event->header.evt_id == BLE_GAP_EVT_SEC_PARAMS_REQUEST) { - LOG_DEBUG(TRACE, "BLE event: BLE_GAP_EVT_SEC_PARAMS_REQUEST"); - // const ble_gap_sec_params_t& peerSecParams = event->evt.gap_evt.params.sec_params_request.peer_params; - // LOG_DEBUG(TRACE, "Peer security params: %d, %d, %d, %d, %d, %d", peerSecParams.bond, peerSecParams.mitm, peerSecParams.lesc, peerSecParams.io_caps, peerSecParams.keypress, peerSecParams.oob); - + LOG(ERROR, "BLE event: BLE_GAP_EVT_SEC_PARAMS_REQUEST"); + const ble_gap_sec_params_t& peerSecParams = event->evt.gap_evt.params.sec_params_request.peer_params; + LOG(ERROR, "Peer bond:%d, mitm:%d, lesc:%d, iocaps:%d, keypress:%d, oob:%d", + peerSecParams.bond, peerSecParams.mitm, peerSecParams.lesc, toHalIoCaps(peerSecParams.io_caps), peerSecParams.keypress, peerSecParams.oob); int ret = NRF_SUCCESS; - if (connection->info.role == BLE_ROLE_CENTRAL) { - ret = sd_ble_gap_sec_params_reply(event->evt.gap_evt.conn_handle, BLE_GAP_SEC_STATUS_SUCCESS, nullptr, nullptr); - } else { + if (connection->info.role == BLE_ROLE_PERIPHERAL) { // If peripheral requests to pair, don't notify the event. if (connection->pairState != BLE_PAIRING_STATE_SEC_REQ_SENT) { connection->pairState = BLE_PAIRING_STATE_PAIRING_REQ_RECEIVED; @@ -2325,24 +2445,40 @@ int BleObject::ConnectionsManager::processSecurityEventFromThread(const ble_evt_ linkEvent.conn_handle = connection->info.conn_handle; notifyLinkEvent(linkEvent); } - // User application may call rejectPairing() to update the pairing state in event handler - if (connection->pairState != BLE_PAIRING_STATE_REJECTED) { - ble_gap_sec_params_t secParams = {}; - if (ioCaps_ != BLE_IO_CAPS_NONE) { - secParams.mitm = true; - } - secParams.io_caps = toPlatformIoCaps(ioCaps_); - secParams.oob = false; - secParams.min_key_size = BLE_ENC_MIN_KEY_SIZE; - secParams.max_key_size = BLE_ENC_MAX_KEY_SIZE; - secParams.kdist_own.enc = true; - secParams.kdist_own.id = true; - secParams.kdist_peer.enc = true; - secParams.kdist_peer.id = true; - ret = sd_ble_gap_sec_params_reply(event->evt.gap_evt.conn_handle, BLE_GAP_SEC_STATUS_SUCCESS, &secParams, nullptr); + } + // User application may call rejectPairing() to update the pairing state in event handler + if (connection->pairState == BLE_PAIRING_STATE_REJECTED) { + return ret; + } + ble_gap_sec_params_t secParams = {}; + ble_gap_sec_params_t* pSecParams = nullptr; // For central role, default it to nullptr, since we have set the secure parameters in startPairing(). + ble_gap_sec_keyset_t keyset = {}; + ble_gap_sec_keyset_t* pKeyset = nullptr; // nullptr for BLE legacy pairing + bool reject = false; + if (pairingConfig_.algorithm == BLE_PAIRING_ALGORITHM_LESC_ONLY) { + if (peerSecParams.lesc == false) { + reject = true; } } + if (!reject && pairingConfig_.algorithm != BLE_PAIRING_ALGORITHM_LEGACY_ONLY ) { + if (publicKeysPrepare(connection) != SYSTEM_ERROR_NONE) { + LOG(ERROR, "Failed to allocate memory for public keys."); + reject = true; + } else { + keyset.keys_own.p_pk = localPublicKey_.get(); + keyset.keys_peer.p_pk = connection->peerPublicKey.get(); + pKeyset = &keyset; + } + } + if (!reject && connection->info.role == BLE_ROLE_PERIPHERAL) { + initSecParams(pairingConfig_, secParams); + pSecParams = &secParams; + } + ret = sd_ble_gap_sec_params_reply(event->evt.gap_evt.conn_handle, reject ? BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP : BLE_GAP_SEC_STATUS_SUCCESS, pSecParams, pKeyset); if (ret != NRF_SUCCESS) { + connection->peerPublicKey.reset(); + // At this point, the BLE_GAP_EVT_AUTH_STATUS won't get triggered, + // But we need to notify user that the pairing has failed. connection->pairState = BLE_PAIRING_STATE_NOT_INITIATED; hal_ble_link_evt_t linkEvent = {}; linkEvent.type = BLE_EVT_PAIRING_STATUS_UPDATED; @@ -2352,16 +2488,20 @@ int BleObject::ConnectionsManager::processSecurityEventFromThread(const ble_evt_ LOG(ERROR, "sd_ble_gap_sec_params_reply() failed: %u", (unsigned)ret); } } else if (event->header.evt_id == BLE_GAP_EVT_PASSKEY_DISPLAY) { - LOG_DEBUG(TRACE, "BLE event: BLE_GAP_EVT_PASSKEY_DISPLAY"); + LOG(ERROR, "BLE event: BLE_GAP_EVT_PASSKEY_DISPLAY"); connection->pairState = BLE_PAIRING_STATE_PASSKEY_DISPLAY; const ble_gap_evt_passkey_display_t& passkeyDisplay = event->evt.gap_evt.params.passkey_display; hal_ble_link_evt_t linkEvent = {}; - linkEvent.type = BLE_EVT_PAIRING_PASSKEY_DISPLAY; + if (passkeyDisplay.match_request) { + linkEvent.type = BLE_EVT_PAIRING_NUMERIC_COMPARISON; + } else { + linkEvent.type = BLE_EVT_PAIRING_PASSKEY_DISPLAY; + } linkEvent.conn_handle = connection->info.conn_handle; linkEvent.params.passkey_display.passkey = passkeyDisplay.passkey; notifyLinkEvent(linkEvent); } else if (event->header.evt_id == BLE_GAP_EVT_AUTH_KEY_REQUEST) { - LOG_DEBUG(TRACE, "BLE event: BLE_GAP_EVT_AUTH_KEY_REQUEST"); + LOG(ERROR, "BLE event: BLE_GAP_EVT_AUTH_KEY_REQUEST"); connection->pairState = BLE_PAIRING_STATE_PASSKEY_INPUT; const ble_gap_evt_auth_key_request_t& keyRequest = event->evt.gap_evt.params.auth_key_request; if (keyRequest.key_type == BLE_GAP_AUTH_KEY_TYPE_PASSKEY) { @@ -2373,13 +2513,15 @@ int BleObject::ConnectionsManager::processSecurityEventFromThread(const ble_evt_ LOG(ERROR, "OOB data not supported!"); } } else if (event->header.evt_id == BLE_GAP_EVT_CONN_SEC_UPDATE) { - LOG_DEBUG(TRACE, "BLE event: BLE_GAP_EVT_CONN_SEC_UPDATE"); + LOG(ERROR, "BLE event: BLE_GAP_EVT_CONN_SEC_UPDATE"); // const ble_gap_evt_conn_sec_update_t& secUpdate = event->evt.gap_evt.params.conn_sec_update; // LOG_DEBUG(TRACE, "Secure mode: %d, level: %d", secUpdate.conn_sec.sec_mode.sm, secUpdate.conn_sec.sec_mode.lv); } else if (event->header.evt_id == BLE_GAP_EVT_AUTH_STATUS) { - LOG_DEBUG(TRACE, "BLE event: BLE_GAP_EVT_AUTH_STATUS"); + LOG(ERROR, "BLE event: BLE_GAP_EVT_AUTH_STATUS"); + // Now we can safely free the memory for peer public key + connection->peerPublicKey.reset(); const ble_gap_evt_auth_status_t& authStatus = event->evt.gap_evt.params.auth_status; - LOG_DEBUG(TRACE, "Authen status: 0x%02X, reason: %d, bond: %d, lesc: %d", authStatus.auth_status, authStatus.error_src, authStatus.bonded, authStatus.lesc); + LOG(ERROR, "Authen status: 0x%02X, reason: %d, bond: %d, lesc: %d", authStatus.auth_status, authStatus.error_src, authStatus.bonded, authStatus.lesc); if (authStatus.auth_status == BLE_GAP_SEC_STATUS_SUCCESS) { connection->pairState = BLE_PAIRING_STATE_PAIRED; } else { @@ -2392,6 +2534,22 @@ int BleObject::ConnectionsManager::processSecurityEventFromThread(const ble_evt_ linkEvent.params.pairing_status.bonded = authStatus.bonded; linkEvent.params.pairing_status.lesc = authStatus.lesc; notifyLinkEvent(linkEvent); + } else if (event->header.evt_id == BLE_GAP_EVT_LESC_DHKEY_REQUEST) { + LOG(ERROR, "BLE event: BLE_GAP_EVT_LESC_DHKEY_REQUEST"); + const ble_gap_evt_lesc_dhkey_request_t& dhkeyReq = event->evt.gap_evt.params.lesc_dhkey_request; + ble_gap_lesc_dhkey_t dhkey = {}; + if (computeDhkey(dhkeyReq.p_pk_peer->pk, dhkey.key) != SYSTEM_ERROR_NONE) { + LOG(ERROR, "Failed to compute DHKey."); + // Set an invalid DHKey to terminate the pairing progress. + mbedtls_default_rng(nullptr, dhkey.key, BLE_GAP_LESC_DHKEY_LEN); + } + int ret = sd_ble_gap_lesc_dhkey_reply(connection->info.conn_handle, &dhkey); + if (ret != NRF_SUCCESS) { + LOG(ERROR, "sd_ble_gap_lesc_dhkey_reply() failed: %d.", ret); + return nrf_system_error(ret); + } + } else { + LOG(ERROR, "Unhandled BLE security event: %d", event->header.evt_id); } return SYSTEM_ERROR_NONE; } @@ -2505,6 +2663,8 @@ void BleObject::ConnectionsManager::processConnectionEvents(const ble_evt_t* eve BleObject::getInstance().dispatcher()->enqueue(&connParamsUpdateEvent); break; } + case BLE_GAP_EVT_SEC_INFO_REQUEST: + case BLE_GAP_EVT_LESC_DHKEY_REQUEST: case BLE_GAP_EVT_PASSKEY_DISPLAY: case BLE_GAP_EVT_AUTH_KEY_REQUEST: case BLE_GAP_EVT_SEC_REQUEST: @@ -4060,6 +4220,13 @@ int hal_ble_gap_set_pairing_config(const hal_ble_pairing_config_t* config, void* return BleObject::getInstance().connMgr()->setPairingConfig(config); } +int hal_ble_gap_get_pairing_config(hal_ble_pairing_config_t* config, void* reserved) { + BleLock lk; + LOG_DEBUG(TRACE, "hal_ble_gap_get_pairing_config()."); + CHECK_TRUE(BleObject::getInstance().initialized(), SYSTEM_ERROR_INVALID_STATE); + return BleObject::getInstance().connMgr()->getPairingConfig(config); +} + int hal_ble_gap_start_pairing(hal_ble_conn_handle_t conn_handle, void* reserved) { BleLock lk; LOG_DEBUG(TRACE, "hal_ble_gap_start_pairing()."); @@ -4081,6 +4248,13 @@ int hal_ble_gap_set_pairing_passkey(hal_ble_conn_handle_t conn_handle, const uin return BleObject::getInstance().connMgr()->setPairingPasskey(conn_handle, passkey); } +int hal_ble_gap_set_lesc_numeric_comparison(hal_ble_conn_handle_t conn_handle, bool equal, void* reserved) { + BleLock lk; + LOG_DEBUG(TRACE, "hal_ble_gap_set_lesc_numeric_comparison()."); + CHECK_TRUE(BleObject::getInstance().initialized(), SYSTEM_ERROR_INVALID_STATE); + return BleObject::getInstance().connMgr()->lescNumericComparison(conn_handle, equal); +} + bool hal_ble_gap_is_pairing(hal_ble_conn_handle_t conn_handle, void* reserved) { BleLock lk; LOG_DEBUG(TRACE, "hal_ble_gap_is_pairing()."); diff --git a/wiring/inc/spark_wiring_ble.h b/wiring/inc/spark_wiring_ble.h index cc15944dbe..f889ddc830 100644 --- a/wiring/inc/spark_wiring_ble.h +++ b/wiring/inc/spark_wiring_ble.h @@ -155,11 +155,18 @@ enum class BlePairingIoCaps : uint8_t { KEYBOARD_DISPLAY = BLE_IO_CAPS_KEYBOARD_DISPLAY }; +enum class BlePairingAlgorithm : uint8_t { + LEGACY_ONLY = BLE_PAIRING_ALGORITHM_LEGACY_ONLY, + LESC_ONLY = BLE_PAIRING_ALGORITHM_LESC_ONLY, + AUTO = BLE_PAIRING_ALGORITHM_AUTO +}; + enum class BlePairingEventType : uint8_t { REQUEST_RECEIVED = BLE_EVT_PAIRING_REQUEST_RECEIVED, PASSKEY_DISPLAY = BLE_EVT_PAIRING_PASSKEY_DISPLAY, PASSKEY_INPUT = BLE_EVT_PAIRING_PASSKEY_INPUT, - STATUS_UPDATED = BLE_EVT_PAIRING_STATUS_UPDATED + STATUS_UPDATED = BLE_EVT_PAIRING_STATUS_UPDATED, + NUMERIC_COMPARISON = BLE_EVT_PAIRING_NUMERIC_COMPARISON }; struct BlePairingStatus { @@ -1043,8 +1050,10 @@ class BleLocalDevice { BlePeerDevice connect(const BleAddress& addr, bool automatic = true) const; int setPairingIoCaps(BlePairingIoCaps ioCaps) const; + int setPairingAlgorithm(BlePairingAlgorithm algorithm) const; int startPairing(const BlePeerDevice& peer) const; int rejectPairing(const BlePeerDevice& peer) const; + int setPairingNumericComparison(const BlePeerDevice& peer, bool equal) const; int setPairingPasskey(const BlePeerDevice& peer, const uint8_t* passkey) const; bool isPairing(const BlePeerDevice& peer) const; bool isPaired(const BlePeerDevice& peer) const; diff --git a/wiring/src/spark_wiring_ble.cpp b/wiring/src/spark_wiring_ble.cpp index f42cc45476..b24886abee 100644 --- a/wiring/src/spark_wiring_ble.cpp +++ b/wiring/src/spark_wiring_ble.cpp @@ -1194,7 +1194,8 @@ class BleLocalDeviceImpl { case BLE_EVT_PAIRING_REQUEST_RECEIVED: case BLE_EVT_PAIRING_PASSKEY_DISPLAY: case BLE_EVT_PAIRING_PASSKEY_INPUT: - case BLE_EVT_PAIRING_STATUS_UPDATED: { + case BLE_EVT_PAIRING_STATUS_UPDATED: + case BLE_EVT_PAIRING_NUMERIC_COMPARISON: { BlePeerDevice* peer = impl->findPeerDevice(event->conn_handle); if (peer) { if (impl->pairingEventCallback_) { @@ -1202,7 +1203,7 @@ class BleLocalDeviceImpl { .peer = *peer, .type = static_cast(event->type) }; - if (event->type == BLE_EVT_PAIRING_PASSKEY_DISPLAY) { + if (event->type == BLE_EVT_PAIRING_PASSKEY_DISPLAY || event->type == BLE_EVT_PAIRING_NUMERIC_COMPARISON) { pairingEvent.payload.passkey = event->params.passkey_display.passkey; pairingEvent.payloadLen = BLE_PAIRING_PASSKEY_LEN; } else if (event->type == BLE_EVT_PAIRING_STATUS_UPDATED) { @@ -2590,10 +2591,20 @@ int BleLocalDevice::setPairingIoCaps(BlePairingIoCaps ioCaps) const { hal_ble_pairing_config_t config = {}; config.version = BLE_API_VERSION; config.size = sizeof(hal_ble_pairing_config_t); + CHECK(hal_ble_gap_get_pairing_config(&config, nullptr)); config.io_caps = static_cast(ioCaps); return hal_ble_gap_set_pairing_config(&config, nullptr); } +int BleLocalDevice::setPairingAlgorithm(BlePairingAlgorithm algorithm) const { + hal_ble_pairing_config_t config = {}; + config.version = BLE_API_VERSION; + config.size = sizeof(hal_ble_pairing_config_t); + CHECK(hal_ble_gap_get_pairing_config(&config, nullptr)); + config.algorithm = static_cast(algorithm); + return hal_ble_gap_set_pairing_config(&config, nullptr); +} + int BleLocalDevice::startPairing(const BlePeerDevice& peer) const { return hal_ble_gap_start_pairing(peer.impl()->connHandle(), nullptr); } @@ -2602,6 +2613,10 @@ int BleLocalDevice::rejectPairing(const BlePeerDevice& peer) const { return hal_ble_gap_reject_pairing(peer.impl()->connHandle(), nullptr); } +int BleLocalDevice::setPairingNumericComparison(const BlePeerDevice& peer, bool equal) const { + return hal_ble_gap_set_lesc_numeric_comparison(peer.impl()->connHandle(), equal, nullptr); +} + int BleLocalDevice::setPairingPasskey(const BlePeerDevice& peer, const uint8_t* passkey) const { return hal_ble_gap_set_pairing_passkey(peer.impl()->connHandle(), passkey, nullptr); } From 3454d68ebb2b02aeaf9e6cddacedc47a777df178 Mon Sep 17 00:00:00 2001 From: XuGuohui Date: Tue, 29 Dec 2020 01:22:14 +0800 Subject: [PATCH 2/9] BLE: add test cases for LESC pairing. --- hal/src/nRF52840/ble_hal.cpp | 20 +- user/tests/wiring/api/ble.cpp | 13 +- .../ble_central/central.cpp | 207 +++++++----------- .../ble_peripheral/peripheral.cpp | 201 +++++++---------- 4 files changed, 180 insertions(+), 261 deletions(-) diff --git a/hal/src/nRF52840/ble_hal.cpp b/hal/src/nRF52840/ble_hal.cpp index 41ab9bb46a..12f75c4b7c 100644 --- a/hal/src/nRF52840/ble_hal.cpp +++ b/hal/src/nRF52840/ble_hal.cpp @@ -2412,7 +2412,7 @@ int BleObject::ConnectionsManager::processSecurityEventFromThread(const ble_evt_ CHECK_TRUE(connection, SYSTEM_ERROR_NOT_FOUND); CHECK_TRUE(connection->pairState != BLE_PAIRING_STATE_PAIRED, SYSTEM_ERROR_INVALID_STATE); if (event->header.evt_id == BLE_GAP_EVT_SEC_REQUEST) { - LOG(ERROR, "BLE event: BLE_GAP_EVT_SEC_REQUEST"); + LOG_DEBUG(TRACE, "BLE event: BLE_GAP_EVT_SEC_REQUEST"); if (connection->info.role == BLE_ROLE_CENTRAL) { connection->pairState = BLE_PAIRING_STATE_SEC_REQ_RECEIVED; hal_ble_link_evt_t linkEvent = {}; @@ -2431,9 +2431,9 @@ int BleObject::ConnectionsManager::processSecurityEventFromThread(const ble_evt_ } } } else if (event->header.evt_id == BLE_GAP_EVT_SEC_PARAMS_REQUEST) { - LOG(ERROR, "BLE event: BLE_GAP_EVT_SEC_PARAMS_REQUEST"); + LOG_DEBUG(TRACE, "BLE event: BLE_GAP_EVT_SEC_PARAMS_REQUEST"); const ble_gap_sec_params_t& peerSecParams = event->evt.gap_evt.params.sec_params_request.peer_params; - LOG(ERROR, "Peer bond:%d, mitm:%d, lesc:%d, iocaps:%d, keypress:%d, oob:%d", + LOG_DEBUG(TRACE, "Peer bond:%d, mitm:%d, lesc:%d, iocaps:%d, keypress:%d, oob:%d", peerSecParams.bond, peerSecParams.mitm, peerSecParams.lesc, toHalIoCaps(peerSecParams.io_caps), peerSecParams.keypress, peerSecParams.oob); int ret = NRF_SUCCESS; if (connection->info.role == BLE_ROLE_PERIPHERAL) { @@ -2488,7 +2488,7 @@ int BleObject::ConnectionsManager::processSecurityEventFromThread(const ble_evt_ LOG(ERROR, "sd_ble_gap_sec_params_reply() failed: %u", (unsigned)ret); } } else if (event->header.evt_id == BLE_GAP_EVT_PASSKEY_DISPLAY) { - LOG(ERROR, "BLE event: BLE_GAP_EVT_PASSKEY_DISPLAY"); + LOG_DEBUG(TRACE, "BLE event: BLE_GAP_EVT_PASSKEY_DISPLAY"); connection->pairState = BLE_PAIRING_STATE_PASSKEY_DISPLAY; const ble_gap_evt_passkey_display_t& passkeyDisplay = event->evt.gap_evt.params.passkey_display; hal_ble_link_evt_t linkEvent = {}; @@ -2501,7 +2501,7 @@ int BleObject::ConnectionsManager::processSecurityEventFromThread(const ble_evt_ linkEvent.params.passkey_display.passkey = passkeyDisplay.passkey; notifyLinkEvent(linkEvent); } else if (event->header.evt_id == BLE_GAP_EVT_AUTH_KEY_REQUEST) { - LOG(ERROR, "BLE event: BLE_GAP_EVT_AUTH_KEY_REQUEST"); + LOG_DEBUG(TRACE, "BLE event: BLE_GAP_EVT_AUTH_KEY_REQUEST"); connection->pairState = BLE_PAIRING_STATE_PASSKEY_INPUT; const ble_gap_evt_auth_key_request_t& keyRequest = event->evt.gap_evt.params.auth_key_request; if (keyRequest.key_type == BLE_GAP_AUTH_KEY_TYPE_PASSKEY) { @@ -2513,15 +2513,15 @@ int BleObject::ConnectionsManager::processSecurityEventFromThread(const ble_evt_ LOG(ERROR, "OOB data not supported!"); } } else if (event->header.evt_id == BLE_GAP_EVT_CONN_SEC_UPDATE) { - LOG(ERROR, "BLE event: BLE_GAP_EVT_CONN_SEC_UPDATE"); + LOG_DEBUG(TRACE, "BLE event: BLE_GAP_EVT_CONN_SEC_UPDATE"); // const ble_gap_evt_conn_sec_update_t& secUpdate = event->evt.gap_evt.params.conn_sec_update; // LOG_DEBUG(TRACE, "Secure mode: %d, level: %d", secUpdate.conn_sec.sec_mode.sm, secUpdate.conn_sec.sec_mode.lv); } else if (event->header.evt_id == BLE_GAP_EVT_AUTH_STATUS) { - LOG(ERROR, "BLE event: BLE_GAP_EVT_AUTH_STATUS"); + LOG_DEBUG(TRACE, "BLE event: BLE_GAP_EVT_AUTH_STATUS"); // Now we can safely free the memory for peer public key connection->peerPublicKey.reset(); const ble_gap_evt_auth_status_t& authStatus = event->evt.gap_evt.params.auth_status; - LOG(ERROR, "Authen status: 0x%02X, reason: %d, bond: %d, lesc: %d", authStatus.auth_status, authStatus.error_src, authStatus.bonded, authStatus.lesc); + LOG_DEBUG(TRACE, "Authen status: 0x%02X, reason: %d, bond: %d, lesc: %d", authStatus.auth_status, authStatus.error_src, authStatus.bonded, authStatus.lesc); if (authStatus.auth_status == BLE_GAP_SEC_STATUS_SUCCESS) { connection->pairState = BLE_PAIRING_STATE_PAIRED; } else { @@ -2535,7 +2535,7 @@ int BleObject::ConnectionsManager::processSecurityEventFromThread(const ble_evt_ linkEvent.params.pairing_status.lesc = authStatus.lesc; notifyLinkEvent(linkEvent); } else if (event->header.evt_id == BLE_GAP_EVT_LESC_DHKEY_REQUEST) { - LOG(ERROR, "BLE event: BLE_GAP_EVT_LESC_DHKEY_REQUEST"); + LOG_DEBUG(TRACE, "BLE event: BLE_GAP_EVT_LESC_DHKEY_REQUEST"); const ble_gap_evt_lesc_dhkey_request_t& dhkeyReq = event->evt.gap_evt.params.lesc_dhkey_request; ble_gap_lesc_dhkey_t dhkey = {}; if (computeDhkey(dhkeyReq.p_pk_peer->pk, dhkey.key) != SYSTEM_ERROR_NONE) { @@ -2549,7 +2549,7 @@ int BleObject::ConnectionsManager::processSecurityEventFromThread(const ble_evt_ return nrf_system_error(ret); } } else { - LOG(ERROR, "Unhandled BLE security event: %d", event->header.evt_id); + LOG_DEBUG(TRACE, "Unhandled BLE security event: %d", event->header.evt_id); } return SYSTEM_ERROR_NONE; } diff --git a/user/tests/wiring/api/ble.cpp b/user/tests/wiring/api/ble.cpp index f1fc6c8051..3ba8bcaaff 100644 --- a/user/tests/wiring/api/ble.cpp +++ b/user/tests/wiring/api/ble.cpp @@ -50,7 +50,7 @@ void pairingEventHandlerFunc(const BlePairingEvent& event, void* context) { (void)status; (void)bonded; (void)lesc; - } else if (event.type == BlePairingEventType::PASSKEY_DISPLAY) { + } else if (event.type == BlePairingEventType::PASSKEY_DISPLAY || event.type == BlePairingEventType::NUMERIC_COMPARISON) { uint8_t key = event.payload.passkey[0]; (void)key; } else if (event.type == BlePairingEventType::PASSKEY_INPUT) { @@ -170,6 +170,14 @@ test(ble_uuid_order) { (void)order; } +test(ble_pairing_algorithm) { + BlePairingAlgorithm algorithm; + API_COMPILE({ algorithm = BlePairingAlgorithm::LEGACY_ONLY; }); + API_COMPILE({ algorithm = BlePairingAlgorithm::LESC_ONLY; }); + API_COMPILE({ algorithm = BlePairingAlgorithm::AUTO; }); + (void)algorithm; +} + test(ble_pairing_io_caps) { BlePairingIoCaps ioCaps; API_COMPILE({ ioCaps = BlePairingIoCaps::NONE; }); @@ -186,6 +194,7 @@ test(ble_pairing_event_type) { API_COMPILE({ type = BlePairingEventType::PASSKEY_DISPLAY; }); API_COMPILE({ type = BlePairingEventType::PASSKEY_INPUT; }); API_COMPILE({ type = BlePairingEventType::STATUS_UPDATED; }); + API_COMPILE({ type = BlePairingEventType::NUMERIC_COMPARISON; }); (void)type; } @@ -787,9 +796,11 @@ test(ble_local_device_class) { API_COMPILE({ BLE.onDisconnected(std::bind(&Handlers::disconnectedHandler, &bleHandlerInstance, _1)); }); API_COMPILE({ int ret = BLE.setPairingIoCaps(BlePairingIoCaps::NONE); (void)ret; }); + API_COMPILE({ int ret = BLE.setPairingAlgorithm(BlePairingAlgorithm::AUTO); (void)ret; }); API_COMPILE({ int ret = BLE.startPairing(BlePeerDevice()); (void)ret; }); API_COMPILE({ int ret = BLE.rejectPairing(BlePeerDevice()); (void)ret; }); API_COMPILE({ uint8_t passkey[6]; int ret = BLE.setPairingPasskey(BlePeerDevice(), passkey); (void)ret; }); + API_COMPILE({ int ret = BLE.setPairingNumericComparison(BlePeerDevice(), true); (void)ret; }); API_COMPILE({ bool ret = BLE.isPairing(BlePeerDevice()); (void)ret; }); API_COMPILE({ bool ret = BLE.isPaired(BlePeerDevice()); (void)ret; }); API_COMPILE({ BLE.onPairingEvent(pairingEventHandlerFunc); }); diff --git a/user/tests/wiring/ble_central_peripheral/ble_central/central.cpp b/user/tests/wiring/ble_central_peripheral/ble_central/central.cpp index ef06fb8fa0..876dde80d2 100644 --- a/user/tests/wiring/ble_central_peripheral/ble_central/central.cpp +++ b/user/tests/wiring/ble_central_peripheral/ble_central/central.cpp @@ -275,8 +275,23 @@ test(BLE_22_Central_Pairing_Sync) { static bool pairingRequested = false; static int pairingStatus = -1; - -static void pairingTestRoutine(bool request) { +static bool lesc; +const BlePairingIoCaps pairingIoCaps[5] = { + BlePairingIoCaps::NONE, + BlePairingIoCaps::DISPLAY_ONLY, + BlePairingIoCaps::DISPLAY_YESNO, + BlePairingIoCaps::KEYBOARD_ONLY, + BlePairingIoCaps::KEYBOARD_DISPLAY +}; +const char* ioCapsStr[5] = { + "BlePairingIoCaps::NONE", + "BlePairingIoCaps::DISPLAY_ONLY", + "BlePairingIoCaps::DISPLAY_YESNO", + "BlePairingIoCaps::KEYBOARD_ONLY", + "BlePairingIoCaps::KEYBOARD_DISPLAY" +}; + +static void pairingTestRoutine(bool request, BlePairingAlgorithm algorithm) { peer = BLE.connect(peerAddr, false); assertTrue(peer.connected()); @@ -288,15 +303,30 @@ static void pairingTestRoutine(bool request) { pairingRequested = true; } else if (event.type == BlePairingEventType::STATUS_UPDATED) { pairingStatus = event.payload.status.status; + lesc = event.payload.status.lesc; // Serial.println("status updateed"); - } else if (event.type == BlePairingEventType::PASSKEY_DISPLAY) { - Serial.print("Please enter the following passkey on the other side: "); + } else if (event.type == BlePairingEventType::PASSKEY_DISPLAY || event.type == BlePairingEventType::NUMERIC_COMPARISON) { + Serial.print("Passkey display: "); for (uint8_t i = 0; i < BLE_PAIRING_PASSKEY_LEN; i++) { Serial.printf("%c", event.payload.passkey[i]); } Serial.println(""); + if (event.type == BlePairingEventType::NUMERIC_COMPARISON) { + while (Serial.available()) { + Serial.read(); + } + Serial.print("Please confirm if the passkey is identical (y/n): "); + while (!Serial.available()); + char c = Serial.read(); + Serial.write(c); + Serial.println(""); + BLE.setPairingNumericComparison(event.peer, (c == 'y') ? true : false); + } } else if (event.type == BlePairingEventType::PASSKEY_INPUT) { - Serial.print("Please enter 6-digits passkey displayed on the other side: "); + while (Serial.available()) { + Serial.read(); + } + Serial.print("Passkey input (must be identical to the peer's): "); uint8_t i = 0; uint8_t passkey[BLE_PAIRING_PASSKEY_LEN]; while (i < BLE_PAIRING_PASSKEY_LEN) { @@ -319,139 +349,62 @@ static void pairingTestRoutine(bool request) { assertTrue(waitFor([&]{ return !BLE.isPairing(peer); }, 20000)); assertTrue(BLE.isPaired(peer)); assertEqual(pairingStatus, (int)SYSTEM_ERROR_NONE); + if (algorithm != BlePairingAlgorithm::LEGACY_ONLY) { + assertTrue(lesc); + } else { + assertFalse(lesc); + } delay(500); - BLE.disconnect(peer); + assertEqual(BLE.disconnect(peer), (int)SYSTEM_ERROR_NONE); + assertFalse(BLE.connected()); delay(500); } -test(BLE_23_Central_Initiate_Pairing_Central_Io_Caps_None_Peripheral_Io_Caps_None) { - BLE.setPairingIoCaps(BlePairingIoCaps::NONE); - pairingTestRoutine(true); -} - -test(BLE_24_Central_Pairing_Receiption_Central_Io_Caps_None_Peripheral_Io_Caps_Dispaly_Only) { - BLE.setPairingIoCaps(BlePairingIoCaps::NONE); - pairingTestRoutine(false); -} - -test(BLE_25_Central_Initiate_Pairing_Central_Io_Caps_None_Peripheral_Io_Caps_Dispaly_Yesno) { - BLE.setPairingIoCaps(BlePairingIoCaps::NONE); - pairingTestRoutine(true); -} - -test(BLE_26_Central_Pairing_Receiption_Central_Io_Caps_None_Peripheral_Io_Caps_Keyboard_Only) { - BLE.setPairingIoCaps(BlePairingIoCaps::NONE); - pairingTestRoutine(false); -} - -test(BLE_27_Central_Initiate_Pairing_Central_Io_Caps_None_Peripheral_Io_Caps_Keyboard_Dispaly) { - BLE.setPairingIoCaps(BlePairingIoCaps::NONE); - pairingTestRoutine(true); -} - -test(BLE_28_Central_Pairing_Receiption_Central_Io_Caps_Dispaly_Only_Peripheral_Io_Caps_None) { - BLE.setPairingIoCaps(BlePairingIoCaps::DISPLAY_ONLY); - pairingTestRoutine(false); -} - -test(BLE_29_Central_Initiate_Pairing_Central_Io_Caps_Dispaly_Only_Peripheral_Io_Caps_Display_Only) { - BLE.setPairingIoCaps(BlePairingIoCaps::DISPLAY_ONLY); - pairingTestRoutine(true); -} - -test(BLE_30_Central_Pairing_Receiption_Central_Io_Caps_Dispaly_Only_Peripheral_Io_Caps_Display_Yesno) { - BLE.setPairingIoCaps(BlePairingIoCaps::DISPLAY_ONLY); - pairingTestRoutine(false); -} - -test(BLE_31_Central_Initiate_Pairing_Central_Io_Caps_Dispaly_Only_Peripheral_Io_Caps_Keyboard_Only) { - BLE.setPairingIoCaps(BlePairingIoCaps::DISPLAY_ONLY); - pairingTestRoutine(true); -} - -test(BLE_32_Central_Pairing_Receiption_Central_Io_Caps_Dispaly_Only_Peripheral_Io_Caps_Keyboard_Display) { - BLE.setPairingIoCaps(BlePairingIoCaps::DISPLAY_ONLY); - pairingTestRoutine(false); -} - -test(BLE_33_Central_Initiate_Pairing_Central_Io_Caps_Dispaly_Yesno_Peripheral_Io_Caps_None) { - BLE.setPairingIoCaps(BlePairingIoCaps::DISPLAY_YESNO); - pairingTestRoutine(true); -} - -test(BLE_34_Central_Pairing_Receiption_Central_Io_Caps_Dispaly_Yesno_Peripheral_Io_Caps_Display_Only) { - BLE.setPairingIoCaps(BlePairingIoCaps::DISPLAY_YESNO); - pairingTestRoutine(false); -} - -test(BLE_35_Central_Initiate_Pairing_Central_Io_Caps_Dispaly_Yesno_Peripheral_Io_Caps_Display_Yesno) { - BLE.setPairingIoCaps(BlePairingIoCaps::DISPLAY_YESNO); - pairingTestRoutine(true); -} - -test(BLE_36_Central_Pairing_Receiption_Central_Io_Caps_Dispaly_Yesno_Peripheral_Io_Caps_Keyboard_Only) { - BLE.setPairingIoCaps(BlePairingIoCaps::DISPLAY_YESNO); - pairingTestRoutine(false); -} - -test(BLE_37_Central_Initiate_Pairing_Central_Io_Caps_Dispaly_Yesno_Peripheral_Io_Caps_Keyboard_Display) { - BLE.setPairingIoCaps(BlePairingIoCaps::DISPLAY_YESNO); - pairingTestRoutine(true); -} - -test(BLE_38_Central_Pairing_Receiption_Central_Io_Caps_Keyboard_Only_Peripheral_Io_Caps_None) { - BLE.setPairingIoCaps(BlePairingIoCaps::KEYBOARD_ONLY); - pairingTestRoutine(false); -} - -test(BLE_39_Central_Initiate_Pairing_Central_Io_Caps_Keyboard_Only_Peripheral_Io_Caps_Display_Only) { - BLE.setPairingIoCaps(BlePairingIoCaps::KEYBOARD_ONLY); - pairingTestRoutine(true); -} - -test(BLE_40_Central_Pairing_Receiption_Central_Io_Caps_Keyboard_Only_Peripheral_Io_Caps_Display_Yesno) { - BLE.setPairingIoCaps(BlePairingIoCaps::KEYBOARD_ONLY); - pairingTestRoutine(false); -} - -test(BLE_41_Central_Initiate_Pairing_Central_Io_Caps_Keyboard_Only_Peripheral_Io_Caps_Keyboard_Only) { - BLE.setPairingIoCaps(BlePairingIoCaps::KEYBOARD_ONLY); - Serial.println("Please enter the same 6-digits key on each side"); - pairingTestRoutine(true); +test(BLE_24_Central_Pairing_Algorithm_Auto_Io_Caps) { + for (uint8_t l = 0; l < 5; l++) { // Local I/O capabilities + assertEqual(BLE.setPairingIoCaps(pairingIoCaps[l]), (int)SYSTEM_ERROR_NONE); + for (uint8_t p = 0; p < 5; p++) { // Peer I/O capabilities + Serial.printlnf("Local I/O Caps: %s", ioCapsStr[l]); + pairingTestRoutine(l % 2, BlePairingAlgorithm::AUTO); + } + } } -test(BLE_42_Central_Pairing_Receiption_Central_Io_Caps_Keyboard_Only_Peripheral_Io_Caps_Keyboard_Display) { - BLE.setPairingIoCaps(BlePairingIoCaps::KEYBOARD_ONLY); - pairingTestRoutine(false); +test(BLE_25_Central_Pairing_Algorithm_Legacy_Only) { + assertEqual(BLE.setPairingIoCaps(BlePairingIoCaps::NONE), (int)SYSTEM_ERROR_NONE); + assertEqual(BLE.setPairingAlgorithm(BlePairingAlgorithm::LEGACY_ONLY), (int)SYSTEM_ERROR_NONE); + pairingTestRoutine(true, BlePairingAlgorithm::LEGACY_ONLY); } -test(BLE_43_Central_Initiate_Pairing_Central_Io_Caps_Keyboard_Display_Peripheral_Io_Caps_None) { - BLE.setPairingIoCaps(BlePairingIoCaps::KEYBOARD_DISPLAY); - pairingTestRoutine(true); -} +test(BLE_26_Central_Pairing_Algorithm_Lesc_Only_Reject_Legacy) { + peer = BLE.connect(peerAddr, false); + assertTrue(peer.connected()); -test(BLE_44_Central_Pairing_Receiption_Central_Io_Caps_Keyboard_Display_Peripheral_Io_Caps_Display_Only) { - BLE.setPairingIoCaps(BlePairingIoCaps::KEYBOARD_DISPLAY); - pairingTestRoutine(false); -} + pairingStatus = -1; + BLE.onPairingEvent([&](const BlePairingEvent& event) { + if (event.type == BlePairingEventType::STATUS_UPDATED) { + pairingStatus = event.payload.status.status; + // Serial.println("status updateed"); + } + }); -test(BLE_45_Central_Initiate_Pairing_Central_Io_Caps_Keyboard_Display_Peripheral_Io_Caps_Display_Yesno) { - BLE.setPairingIoCaps(BlePairingIoCaps::KEYBOARD_DISPLAY); - pairingTestRoutine(true); -} + assertEqual(BLE.setPairingIoCaps(BlePairingIoCaps::NONE), (int)SYSTEM_ERROR_NONE); + assertEqual(BLE.setPairingAlgorithm(BlePairingAlgorithm::LESC_ONLY), (int)SYSTEM_ERROR_NONE); -test(BLE_46_Central_Pairing_Receiption_Central_Io_Caps_Keyboard_Display_Peripheral_Io_Caps_Keyboard_Only) { - BLE.setPairingIoCaps(BlePairingIoCaps::KEYBOARD_DISPLAY); - pairingTestRoutine(false); -} + assertEqual(BLE.startPairing(peer), (int)SYSTEM_ERROR_NONE); + assertTrue(BLE.isPairing(peer)); + assertTrue(waitFor([&]{ return !BLE.isPairing(peer); }, 20000)); + assertFalse(BLE.isPaired(peer)); + assertNotEqual(pairingStatus, (int)SYSTEM_ERROR_NONE); -test(BLE_47_Central_Initiate_Pairing_Central_Io_Caps_Keyboard_Display_Peripheral_Io_Caps_Keyboard_Display) { - BLE.setPairingIoCaps(BlePairingIoCaps::KEYBOARD_DISPLAY); - pairingTestRoutine(true); + delay(500); + assertEqual(BLE.disconnect(peer), (int)SYSTEM_ERROR_NONE); + assertFalse(BLE.connected()); + delay(500); } -test(BLE_48_Central_Initiate_Pairing_Peripheral_Being_Reject) { +test(BLE_27_Central_Initiate_Pairing_Peripheral_Being_Rejected) { peer = BLE.connect(peerAddr, false); assertTrue(peer.connected()); @@ -461,11 +414,12 @@ test(BLE_48_Central_Initiate_Pairing_Peripheral_Being_Reject) { assertFalse(BLE.isPaired(peer)); delay(500); - BLE.disconnect(peer); + assertEqual(BLE.disconnect(peer), (int)SYSTEM_ERROR_NONE); + assertFalse(BLE.connected()); delay(500); } -test(BLE_49_Central_Pairing_Receiption_Reject) { +test(BLE_28_Central_Pairing_Receiption_Reject) { pairingStatus = 0; BLE.onPairingEvent([&](const BlePairingEvent& event) { if (event.type == BlePairingEventType::REQUEST_RECEIVED) { @@ -482,7 +436,8 @@ test(BLE_49_Central_Pairing_Receiption_Reject) { assertTrue(waitFor([]{ return pairingStatus != 0; }, 5000)); delay(500); - BLE.disconnect(peer); + assertEqual(BLE.disconnect(peer), (int)SYSTEM_ERROR_NONE); + assertFalse(BLE.connected()); delay(500); } diff --git a/user/tests/wiring/ble_central_peripheral/ble_peripheral/peripheral.cpp b/user/tests/wiring/ble_central_peripheral/ble_peripheral/peripheral.cpp index 55213d5796..5b783dac3f 100644 --- a/user/tests/wiring/ble_central_peripheral/ble_peripheral/peripheral.cpp +++ b/user/tests/wiring/ble_central_peripheral/ble_peripheral/peripheral.cpp @@ -187,16 +187,31 @@ test(BLE_18_Peripheral_Notify_Characteristic_With_Notify_Indicate_Property_Nack) test(BLE_19_Peripheral_Pairing_Sync) { // The central will perform some service and characteristic discovery tests - // before starting thee pairing tests + // before starting the pairing tests assertTrue(waitFor([]{ return pairingStarted; }, 20000)); assertTrue(waitFor([]{ return !BLE.connected(); }, 5000)); } static bool pairingRequested = false; static int pairingStatus = -1; +static bool lesc; static BlePeerDevice peer; - -static void pairingTestRoutine(bool request) { +const BlePairingIoCaps pairingIoCaps[5] = { + BlePairingIoCaps::NONE, + BlePairingIoCaps::DISPLAY_ONLY, + BlePairingIoCaps::DISPLAY_YESNO, + BlePairingIoCaps::KEYBOARD_ONLY, + BlePairingIoCaps::KEYBOARD_DISPLAY +}; +const char* ioCapsStr[5] = { + "BlePairingIoCaps::NONE", + "BlePairingIoCaps::DISPLAY_ONLY", + "BlePairingIoCaps::DISPLAY_YESNO", + "BlePairingIoCaps::KEYBOARD_ONLY", + "BlePairingIoCaps::KEYBOARD_DISPLAY" +}; + +static void pairingTestRoutine(bool request, BlePairingAlgorithm algorithm) { pairingRequested = false; pairingStatus = -1; @@ -207,15 +222,30 @@ static void pairingTestRoutine(bool request) { // Serial.println("Request received"); } else if (event.type == BlePairingEventType::STATUS_UPDATED) { pairingStatus = event.payload.status.status; + lesc = event.payload.status.lesc; // Serial.println("status updateed"); - } else if (event.type == BlePairingEventType::PASSKEY_DISPLAY) { + } else if (event.type == BlePairingEventType::PASSKEY_DISPLAY || event.type == BlePairingEventType::NUMERIC_COMPARISON) { Serial.print("Passkey display: "); for (uint8_t i = 0; i < BLE_PAIRING_PASSKEY_LEN; i++) { Serial.printf("%c", event.payload.passkey[i]); } Serial.println(""); + if (event.type == BlePairingEventType::NUMERIC_COMPARISON) { + while (Serial.available()) { + Serial.read(); + } + Serial.print("Please confirm if the passkey is identical (y/n): "); + while (!Serial.available()); + char c = Serial.read(); + Serial.write(c); + Serial.println(""); + BLE.setPairingNumericComparison(event.peer, (c == 'y') ? true : false); + } } else if (event.type == BlePairingEventType::PASSKEY_INPUT) { - Serial.print("Passkey input: "); + while (Serial.available()) { + Serial.read(); + } + Serial.print("Passkey input (must be identical to the peer's): "); uint8_t i = 0; uint8_t passkey[BLE_PAIRING_PASSKEY_LEN]; while (i < BLE_PAIRING_PASSKEY_LEN) { @@ -241,137 +271,56 @@ static void pairingTestRoutine(bool request) { assertTrue(waitFor([&]{ return !BLE.isPairing(peer); }, 20000)); assertTrue(BLE.isPaired(peer)); assertEqual(pairingStatus, (int)SYSTEM_ERROR_NONE); + if (algorithm != BlePairingAlgorithm::LEGACY_ONLY) { + assertTrue(lesc); + } else { + assertFalse(lesc); + } assertTrue(waitFor([]{ return !BLE.connected(); }, 5000)); + assertFalse(BLE.connected()); } -test(BLE_20_Peripheral_Pairing_Receiption_Central_Io_Caps_None_Peripheral_Io_Caps_None) { - BLE.setPairingIoCaps(BlePairingIoCaps::NONE); - pairingTestRoutine(false); -} - -test(BLE_21_Peripheral_Initiate_Pairing_Central_Io_Caps_None_Peripheral_Io_Caps_Dispaly_Only) { - BLE.setPairingIoCaps(BlePairingIoCaps::DISPLAY_ONLY); - pairingTestRoutine(true); -} - -test(BLE_22_Peripheral_Pairing_Receiption_Cnetral_Io_Caps_None_Peripheral_Io_Caps_Dispaly_Yesno) { - BLE.setPairingIoCaps(BlePairingIoCaps::DISPLAY_YESNO); - pairingTestRoutine(false); -} - -test(BLE_23_Peripheral_Initiate_Pairing_Central_Io_Caps_None_Peripheral_Io_Caps_Keyboard_Only) { - BLE.setPairingIoCaps(BlePairingIoCaps::KEYBOARD_ONLY); - pairingTestRoutine(true); -} - -test(BLE_24_Peripheral_Pairing_Receiption_Central_Io_Caps_None_Peripheral_Io_Caps_Keyboard_Dispaly) { - BLE.setPairingIoCaps(BlePairingIoCaps::KEYBOARD_DISPLAY); - pairingTestRoutine(false); -} - -test(BLE_25_Peripheral_Initiate_Pairing_Central_Io_Caps_Display_Only_Peripheral_Io_Caps_None) { - BLE.setPairingIoCaps(BlePairingIoCaps::NONE); - pairingTestRoutine(true); -} - -test(BLE_26_Peripheral_Pairing_Receiption_Central_Io_Caps_Display_Only_Peripheral_Io_Caps_Dispaly_Only) { - BLE.setPairingIoCaps(BlePairingIoCaps::DISPLAY_ONLY); - pairingTestRoutine(false); -} - -test(BLE_27_Peripheral_Initiate_Pairing_Central_Io_Caps_Display_Only_Peripheral_Io_Caps_Display_Yesno) { - BLE.setPairingIoCaps(BlePairingIoCaps::DISPLAY_YESNO); - pairingTestRoutine(true); -} - -test(BLE_28_Peripheral_Pairing_Receiption_Central_Io_Caps_Display_Only_Peripheral_Io_Caps_Keyboard_Only) { - BLE.setPairingIoCaps(BlePairingIoCaps::KEYBOARD_ONLY); - pairingTestRoutine(false); -} - -test(BLE_29_Peripheral_Initiate_Pairing_Central_Io_Caps_Display_Only_Peripheral_Io_Caps_Keyboard_Display) { - BLE.setPairingIoCaps(BlePairingIoCaps::KEYBOARD_DISPLAY); - pairingTestRoutine(true); -} - -test(BLE_30_Peripheral_Pairing_Receiption_Central_Io_Caps_Display_Yesno_Peripheral_Io_Caps_None) { - BLE.setPairingIoCaps(BlePairingIoCaps::NONE); - pairingTestRoutine(false); -} - -test(BLE_31_Peripheral_Initiate_Pairing_Central_Io_Caps_Display_Yesno_Peripheral_Io_Caps_Display_Only) { - BLE.setPairingIoCaps(BlePairingIoCaps::DISPLAY_ONLY); - pairingTestRoutine(true); -} - -test(BLE_32_Peripheral_Pairing_Receiption_Central_Io_Caps_Display_Yesno_Peripheral_Io_Caps_Display_Yesno) { - BLE.setPairingIoCaps(BlePairingIoCaps::DISPLAY_YESNO); - pairingTestRoutine(false); -} - -test(BLE_33_Peripheral_Initiate_Pairing_Central_Io_Caps_Display_Yesno_Peripheral_Io_Caps_Keyboard_Only) { - BLE.setPairingIoCaps(BlePairingIoCaps::KEYBOARD_ONLY); - pairingTestRoutine(true); -} - -test(BLE_34_Peripheral_Pairing_Receiption_Central_Io_Caps_Display_Yesno_Peripheral_Io_Caps_Keyboard_Display) { - BLE.setPairingIoCaps(BlePairingIoCaps::KEYBOARD_DISPLAY); - pairingTestRoutine(false); -} - -test(BLE_35_Peripheral_Initiate_Pairing_Central_Io_Caps_Keyboard_Only_Peripheral_Io_Caps_None) { - BLE.setPairingIoCaps(BlePairingIoCaps::NONE); - pairingTestRoutine(true); -} - -test(BLE_36_Peripheral_Pairing_Receiption_Central_Io_Caps_Keyboard_Only_Peripheral_Io_Caps_Display_Only) { - BLE.setPairingIoCaps(BlePairingIoCaps::DISPLAY_ONLY); - pairingTestRoutine(false); -} - -test(BLE_37_Peripheral_Initiate_Pairing_Central_Io_Caps_Keyboard_Only_Peripheral_Io_Caps_Display_Yesno) { - BLE.setPairingIoCaps(BlePairingIoCaps::DISPLAY_YESNO); - pairingTestRoutine(true); -} - -test(BLE_38_Peripheral_Pairing_Receiption_Central_Io_Caps_Keyboard_Only_Peripheral_Io_Caps_Keyboard_Only) { - BLE.setPairingIoCaps(BlePairingIoCaps::KEYBOARD_ONLY); - Serial.println("Please enter the same 6-digits key on each side"); - pairingTestRoutine(false); -} - -test(BLE_39_Peripheral_Initiate_Pairing_Central_Io_Caps_Keyboard_Only_Peripheral_Io_Caps_Keyboard_Display) { - BLE.setPairingIoCaps(BlePairingIoCaps::KEYBOARD_DISPLAY); - pairingTestRoutine(true); +test(BLE_20_Peripheral_Pairing_Algorithm_Auto_Io_Caps) { + for (uint8_t p = 0; p < 5; p++) { // Peer I/O capabilities + for (uint8_t l = 0; l < 5; l++) { + assertEqual(BLE.setPairingIoCaps(pairingIoCaps[l]), (int)SYSTEM_ERROR_NONE); // Local I/O capabilities + Serial.printlnf("Local I/O Caps: %s", ioCapsStr[l]); + pairingTestRoutine(!(p % 2), BlePairingAlgorithm::AUTO); + } + } } -test(BLE_40_Peripheral_Pairing_Receiption_Central_Io_Caps_Keyboard_Display_Peripheral_Io_Caps_None) { - BLE.setPairingIoCaps(BlePairingIoCaps::NONE); - pairingTestRoutine(false); +test(BLE_21_Peripheral_Pairing_Algorithm_Legacy_Only) { + assertEqual(BLE.setPairingIoCaps(BlePairingIoCaps::NONE), (int)SYSTEM_ERROR_NONE); + assertEqual(BLE.setPairingAlgorithm(BlePairingAlgorithm::LEGACY_ONLY), (int)SYSTEM_ERROR_NONE); + pairingTestRoutine(false, BlePairingAlgorithm::LEGACY_ONLY); } -test(BLE_41_Peripheral_Initiate_Pairing_Central_Io_Caps_Keyboard_Display_Peripheral_Io_Caps_Display_Only) { - BLE.setPairingIoCaps(BlePairingIoCaps::DISPLAY_ONLY); - pairingTestRoutine(true); -} +test(BLE_22_Peripheral_Pairing_Algorithm_Legacy_Only_Being_Rejected) { + pairingRequested = false; + BLE.onPairingEvent([&](const BlePairingEvent& event) { + if (event.type == BlePairingEventType::REQUEST_RECEIVED) { + pairingRequested = true; + peer = event.peer; + // Serial.println("Request received"); + } + }); + assertEqual(BLE.setPairingIoCaps(BlePairingIoCaps::NONE), (int)SYSTEM_ERROR_NONE); + assertEqual(BLE.setPairingAlgorithm(BlePairingAlgorithm::LEGACY_ONLY), (int)SYSTEM_ERROR_NONE); -test(BLE_42_Peripheral_Pairing_Receiption_Central_Io_Caps_Keyboard_Display_Peripheral_Io_Caps_Display_Yesno) { - BLE.setPairingIoCaps(BlePairingIoCaps::DISPLAY_YESNO); - pairingTestRoutine(false); -} + assertTrue(waitFor(BLE.connected, 20000)); -test(BLE_43_Peripheral_Initiate_Pairing_Central_Io_Caps_Keyboard_Display_Peripheral_Io_Caps_Keyboard_Only) { - BLE.setPairingIoCaps(BlePairingIoCaps::KEYBOARD_ONLY); - pairingTestRoutine(true); -} + assertTrue(waitFor([&]{ return pairingRequested; }, 20000)); + assertTrue(BLE.isPairing(peer)); + assertTrue(waitFor([&]{ return !BLE.isPairing(peer); }, 20000)); + assertFalse(BLE.isPaired(peer)); -test(BLE_44_Peripheral_Pairing_Receiption_Central_Io_Caps_Keyboard_Display_Peripheral_Io_Caps_Keyboard_Display) { - BLE.setPairingIoCaps(BlePairingIoCaps::KEYBOARD_DISPLAY); - pairingTestRoutine(false); + assertTrue(waitFor([]{ return !BLE.connected(); }, 5000)); + assertFalse(BLE.connected()); } -test(BLE_45_Peripheral_Pairing_Receiption_Reject) { +test(BLE_23_Peripheral_Pairing_Receiption_Reject) { pairingStatus = 0; BLE.onPairingEvent([&](const BlePairingEvent& event) { if (event.type == BlePairingEventType::REQUEST_RECEIVED) { @@ -387,9 +336,10 @@ test(BLE_45_Peripheral_Pairing_Receiption_Reject) { assertTrue(waitFor([]{ return pairingStatus != 0; }, 5000)); assertTrue(waitFor([]{ return !BLE.connected(); }, 5000)); + assertFalse(BLE.connected()); } -test(BLE_46_Peripheral_Initiate_Pairing_Being_Rejected) { +test(BLE_24_Peripheral_Initiate_Pairing_Being_Rejected) { assertTrue(waitFor(BLE.connected, 20000)); peer = BLE.peerCentral(); @@ -398,6 +348,9 @@ test(BLE_46_Peripheral_Initiate_Pairing_Being_Rejected) { assertTrue(BLE.isPairing(peer)); assertTrue(waitFor([&]{ return !BLE.isPairing(peer); }, 20000)); assertFalse(BLE.isPaired(peer)); + + assertTrue(waitFor([]{ return !BLE.connected(); }, 5000)); + assertFalse(BLE.connected()); } #endif // #if Wiring_BLE == 1 From 4860d1241f2c695b47a2a21847858439f3e37dee Mon Sep 17 00:00:00 2001 From: XuGuohui Date: Tue, 29 Dec 2020 03:33:52 +0800 Subject: [PATCH 3/9] BLE: minor improvements. --- hal/src/nRF52840/ble_hal.cpp | 48 ++--- .../ble_central/central.cpp | 200 ++++++++++-------- .../ble_peripheral/peripheral.cpp | 94 ++++---- 3 files changed, 178 insertions(+), 164 deletions(-) diff --git a/hal/src/nRF52840/ble_hal.cpp b/hal/src/nRF52840/ble_hal.cpp index 12f75c4b7c..84d6a29e56 100644 --- a/hal/src/nRF52840/ble_hal.cpp +++ b/hal/src/nRF52840/ble_hal.cpp @@ -236,6 +236,7 @@ class BleObject::BleEventDispatcher { return evtDispatcherinitialized_; } void enqueue(ble_evt_t** event); + void enqueue(const ble_evt_t* event); void* allocEventData(size_t size) { return pool_.alloc(size); @@ -707,6 +708,16 @@ void BleObject::BleEventDispatcher::enqueue(ble_evt_t** event) { } } +void BleObject::BleEventDispatcher::enqueue(const ble_evt_t* event) { + ble_evt_t* pBleEvent = (ble_evt_t*)allocEventData(sizeof(ble_evt_t)); + if (!pBleEvent) { + LOG(ERROR, "Allocate memory for BLE event failed."); + SPARK_ASSERT(false); + } + memcpy(pBleEvent, event, sizeof(ble_evt_t)); + enqueue(&pBleEvent); +} + os_thread_return_t BleObject::BleEventDispatcher::processBleEventFromThread(void* param) { BleEventDispatcher* dispatcher = static_cast(param); while (1) { @@ -2632,15 +2643,7 @@ void BleObject::ConnectionsManager::processConnectionEvents(const ble_evt_t* eve } case BLE_GAP_EVT_DISCONNECTED: { LOG_DEBUG(TRACE, "BLE GAP event: disconnected."); - ble_evt_t* disconnectedEvent = (ble_evt_t*)BleObject::getInstance().dispatcher()->allocEventData(sizeof(ble_evt_t)); - if (!disconnectedEvent) { - LOG(ERROR, "Allocate memory for BLE event failed."); - // Assert it since the connection is cached but invalid for further reference. - SPARK_ASSERT(false); - break; - } - memcpy(disconnectedEvent, event, sizeof(ble_evt_t)); - BleObject::getInstance().dispatcher()->enqueue(&disconnectedEvent); + BleObject::getInstance().dispatcher()->enqueue(event); break; } case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: { @@ -2653,14 +2656,7 @@ void BleObject::ConnectionsManager::processConnectionEvents(const ble_evt_t* eve } case BLE_GAP_EVT_CONN_PARAM_UPDATE: { LOG_DEBUG(TRACE, "BLE GAP event: connection parameters updated."); - ble_evt_t* connParamsUpdateEvent = (ble_evt_t*)BleObject::getInstance().dispatcher()->allocEventData(sizeof(ble_evt_t)); - if (!connParamsUpdateEvent) { - LOG(ERROR, "Allocate memory for BLE event failed."); - SPARK_ASSERT(false); - break; - } - memcpy(connParamsUpdateEvent, event, sizeof(ble_evt_t)); - BleObject::getInstance().dispatcher()->enqueue(&connParamsUpdateEvent); + BleObject::getInstance().dispatcher()->enqueue(event); break; } case BLE_GAP_EVT_SEC_INFO_REQUEST: @@ -2671,14 +2667,7 @@ void BleObject::ConnectionsManager::processConnectionEvents(const ble_evt_t* eve case BLE_GAP_EVT_SEC_PARAMS_REQUEST: case BLE_GAP_EVT_CONN_SEC_UPDATE: case BLE_GAP_EVT_AUTH_STATUS: { - ble_evt_t* secEvent = (ble_evt_t*)BleObject::getInstance().dispatcher()->allocEventData(sizeof(ble_evt_t)); - if (!secEvent) { - LOG(ERROR, "Allocate memory for BLE event failed."); - SPARK_ASSERT(false); - break; - } - memcpy(secEvent, event, sizeof(ble_evt_t)); - BleObject::getInstance().dispatcher()->enqueue(&secEvent); + BleObject::getInstance().dispatcher()->enqueue(event); break; } case BLE_GAP_EVT_TIMEOUT: { @@ -2699,14 +2688,7 @@ void BleObject::ConnectionsManager::processConnectionEvents(const ble_evt_t* eve LOG_DEBUG(TRACE, "sd_ble_gatts_exchange_mtu_reply() failed: %d", ret); break; } - ble_evt_t* attMtuExchangeEvent = (ble_evt_t*)BleObject::getInstance().dispatcher()->allocEventData(sizeof(ble_evt_t)); - if (!attMtuExchangeEvent) { - LOG(ERROR, "Allocate memory for BLE event failed."); - SPARK_ASSERT(false); - break; - } - memcpy(attMtuExchangeEvent, event, sizeof(ble_evt_t)); - BleObject::getInstance().dispatcher()->enqueue(&attMtuExchangeEvent); + BleObject::getInstance().dispatcher()->enqueue(event); break; } case BLE_GATTC_EVT_EXCHANGE_MTU_RSP: { diff --git a/user/tests/wiring/ble_central_peripheral/ble_central/central.cpp b/user/tests/wiring/ble_central_peripheral/ble_central/central.cpp index 876dde80d2..e8882d28d4 100644 --- a/user/tests/wiring/ble_central_peripheral/ble_central/central.cpp +++ b/user/tests/wiring/ble_central_peripheral/ble_central/central.cpp @@ -294,71 +294,74 @@ const char* ioCapsStr[5] = { static void pairingTestRoutine(bool request, BlePairingAlgorithm algorithm) { peer = BLE.connect(peerAddr, false); assertTrue(peer.connected()); - - pairingStatus = -1; - pairingRequested = false; - BLE.onPairingEvent([&](const BlePairingEvent& event) { - if (event.type == BlePairingEventType::REQUEST_RECEIVED) { - // Serial.println("Request received"); - pairingRequested = true; - } else if (event.type == BlePairingEventType::STATUS_UPDATED) { - pairingStatus = event.payload.status.status; - lesc = event.payload.status.lesc; - // Serial.println("status updateed"); - } else if (event.type == BlePairingEventType::PASSKEY_DISPLAY || event.type == BlePairingEventType::NUMERIC_COMPARISON) { - Serial.print("Passkey display: "); - for (uint8_t i = 0; i < BLE_PAIRING_PASSKEY_LEN; i++) { - Serial.printf("%c", event.payload.passkey[i]); - } - Serial.println(""); - if (event.type == BlePairingEventType::NUMERIC_COMPARISON) { + { + SCOPE_GUARD ({ + delay(500); + assertEqual(BLE.disconnect(peer), (int)SYSTEM_ERROR_NONE); + assertFalse(BLE.connected()); + delay(500); + }); + + pairingStatus = -1; + pairingRequested = false; + BLE.onPairingEvent([&](const BlePairingEvent& event) { + if (event.type == BlePairingEventType::REQUEST_RECEIVED) { + // Serial.println("Request received"); + pairingRequested = true; + } else if (event.type == BlePairingEventType::STATUS_UPDATED) { + pairingStatus = event.payload.status.status; + lesc = event.payload.status.lesc; + // Serial.println("status updateed"); + } else if (event.type == BlePairingEventType::PASSKEY_DISPLAY || event.type == BlePairingEventType::NUMERIC_COMPARISON) { + Serial.print("Passkey display: "); + for (uint8_t i = 0; i < BLE_PAIRING_PASSKEY_LEN; i++) { + Serial.printf("%c", event.payload.passkey[i]); + } + Serial.println(""); + if (event.type == BlePairingEventType::NUMERIC_COMPARISON) { + while (Serial.available()) { + Serial.read(); + } + Serial.print("Please confirm if the passkey is identical (y/n): "); + while (!Serial.available()); + char c = Serial.read(); + Serial.write(c); + Serial.println(""); + BLE.setPairingNumericComparison(event.peer, (c == 'y') ? true : false); + } + } else if (event.type == BlePairingEventType::PASSKEY_INPUT) { while (Serial.available()) { Serial.read(); } - Serial.print("Please confirm if the passkey is identical (y/n): "); - while (!Serial.available()); - char c = Serial.read(); - Serial.write(c); - Serial.println(""); - BLE.setPairingNumericComparison(event.peer, (c == 'y') ? true : false); - } - } else if (event.type == BlePairingEventType::PASSKEY_INPUT) { - while (Serial.available()) { - Serial.read(); - } - Serial.print("Passkey input (must be identical to the peer's): "); - uint8_t i = 0; - uint8_t passkey[BLE_PAIRING_PASSKEY_LEN]; - while (i < BLE_PAIRING_PASSKEY_LEN) { - if (Serial.available()) { - passkey[i] = Serial.read(); - Serial.write(passkey[i++]); + Serial.print("Passkey input (must be identical to the peer's): "); + uint8_t i = 0; + uint8_t passkey[BLE_PAIRING_PASSKEY_LEN]; + while (i < BLE_PAIRING_PASSKEY_LEN) { + if (Serial.available()) { + passkey[i] = Serial.read(); + Serial.write(passkey[i++]); + } } + Serial.println(""); + BLE.setPairingPasskey(event.peer, passkey); } - Serial.println(""); - BLE.setPairingPasskey(event.peer, passkey); - } - }); + }); - if (request) { - assertEqual(BLE.startPairing(peer), (int)SYSTEM_ERROR_NONE); - } else { - assertTrue(waitFor([&]{ return pairingRequested; }, 5000)); - } - assertTrue(BLE.isPairing(peer)); - assertTrue(waitFor([&]{ return !BLE.isPairing(peer); }, 20000)); - assertTrue(BLE.isPaired(peer)); - assertEqual(pairingStatus, (int)SYSTEM_ERROR_NONE); - if (algorithm != BlePairingAlgorithm::LEGACY_ONLY) { - assertTrue(lesc); - } else { - assertFalse(lesc); + if (request) { + assertEqual(BLE.startPairing(peer), (int)SYSTEM_ERROR_NONE); + } else { + assertTrue(waitFor([&]{ return pairingRequested; }, 5000)); + } + assertTrue(BLE.isPairing(peer)); + assertTrue(waitFor([&]{ return !BLE.isPairing(peer); }, 20000)); + assertTrue(BLE.isPaired(peer)); + assertEqual(pairingStatus, (int)SYSTEM_ERROR_NONE); + if (algorithm != BlePairingAlgorithm::LEGACY_ONLY) { + assertTrue(lesc); + } else { + assertFalse(lesc); + } } - - delay(500); - assertEqual(BLE.disconnect(peer), (int)SYSTEM_ERROR_NONE); - assertFalse(BLE.connected()); - delay(500); } test(BLE_24_Central_Pairing_Algorithm_Auto_Io_Caps) { @@ -380,43 +383,49 @@ test(BLE_25_Central_Pairing_Algorithm_Legacy_Only) { test(BLE_26_Central_Pairing_Algorithm_Lesc_Only_Reject_Legacy) { peer = BLE.connect(peerAddr, false); assertTrue(peer.connected()); + { + SCOPE_GUARD ({ + delay(500); + assertEqual(BLE.disconnect(peer), (int)SYSTEM_ERROR_NONE); + assertFalse(BLE.connected()); + delay(500); + }); + + pairingStatus = -1; + BLE.onPairingEvent([&](const BlePairingEvent& event) { + if (event.type == BlePairingEventType::STATUS_UPDATED) { + pairingStatus = event.payload.status.status; + // Serial.println("status updateed"); + } + }); - pairingStatus = -1; - BLE.onPairingEvent([&](const BlePairingEvent& event) { - if (event.type == BlePairingEventType::STATUS_UPDATED) { - pairingStatus = event.payload.status.status; - // Serial.println("status updateed"); - } - }); + assertEqual(BLE.setPairingIoCaps(BlePairingIoCaps::NONE), (int)SYSTEM_ERROR_NONE); + assertEqual(BLE.setPairingAlgorithm(BlePairingAlgorithm::LESC_ONLY), (int)SYSTEM_ERROR_NONE); - assertEqual(BLE.setPairingIoCaps(BlePairingIoCaps::NONE), (int)SYSTEM_ERROR_NONE); - assertEqual(BLE.setPairingAlgorithm(BlePairingAlgorithm::LESC_ONLY), (int)SYSTEM_ERROR_NONE); - - assertEqual(BLE.startPairing(peer), (int)SYSTEM_ERROR_NONE); - assertTrue(BLE.isPairing(peer)); - assertTrue(waitFor([&]{ return !BLE.isPairing(peer); }, 20000)); - assertFalse(BLE.isPaired(peer)); - assertNotEqual(pairingStatus, (int)SYSTEM_ERROR_NONE); - - delay(500); - assertEqual(BLE.disconnect(peer), (int)SYSTEM_ERROR_NONE); - assertFalse(BLE.connected()); - delay(500); + assertEqual(BLE.startPairing(peer), (int)SYSTEM_ERROR_NONE); + assertTrue(BLE.isPairing(peer)); + assertTrue(waitFor([&]{ return !BLE.isPairing(peer); }, 20000)); + assertFalse(BLE.isPaired(peer)); + assertNotEqual(pairingStatus, (int)SYSTEM_ERROR_NONE); + } } test(BLE_27_Central_Initiate_Pairing_Peripheral_Being_Rejected) { peer = BLE.connect(peerAddr, false); assertTrue(peer.connected()); + { + SCOPE_GUARD ({ + delay(500); + assertEqual(BLE.disconnect(peer), (int)SYSTEM_ERROR_NONE); + assertFalse(BLE.connected()); + delay(500); + }); - assertEqual(BLE.startPairing(peer), (int)SYSTEM_ERROR_NONE); - assertTrue(BLE.isPairing(peer)); - assertTrue(waitFor([&]{ return !BLE.isPairing(peer); }, 20000)); - assertFalse(BLE.isPaired(peer)); - - delay(500); - assertEqual(BLE.disconnect(peer), (int)SYSTEM_ERROR_NONE); - assertFalse(BLE.connected()); - delay(500); + assertEqual(BLE.startPairing(peer), (int)SYSTEM_ERROR_NONE); + assertTrue(BLE.isPairing(peer)); + assertTrue(waitFor([&]{ return !BLE.isPairing(peer); }, 20000)); + assertFalse(BLE.isPaired(peer)); + } } test(BLE_28_Central_Pairing_Receiption_Reject) { @@ -432,13 +441,16 @@ test(BLE_28_Central_Pairing_Receiption_Reject) { peer = BLE.connect(peerAddr, false); assertTrue(peer.connected()); - - assertTrue(waitFor([]{ return pairingStatus != 0; }, 5000)); - - delay(500); - assertEqual(BLE.disconnect(peer), (int)SYSTEM_ERROR_NONE); - assertFalse(BLE.connected()); - delay(500); + { + SCOPE_GUARD ({ + delay(500); + assertEqual(BLE.disconnect(peer), (int)SYSTEM_ERROR_NONE); + assertFalse(BLE.connected()); + delay(500); + }); + + assertTrue(waitFor([]{ return pairingStatus != 0; }, 5000)); + } } #endif // #if Wiring_BLE == 1 diff --git a/user/tests/wiring/ble_central_peripheral/ble_peripheral/peripheral.cpp b/user/tests/wiring/ble_central_peripheral/ble_peripheral/peripheral.cpp index 5b783dac3f..67b80eac28 100644 --- a/user/tests/wiring/ble_central_peripheral/ble_peripheral/peripheral.cpp +++ b/user/tests/wiring/ble_central_peripheral/ble_peripheral/peripheral.cpp @@ -91,6 +91,13 @@ test(BLE_01_Peripheral_Advertising) { ret = BLE.advertise(&advData, &srData); assertEqual(ret, 0); + BLE.onConnected([](const BlePeerDevice& peer) { + Serial.println("Connected."); + }); + BLE.onDisconnected([](const BlePeerDevice& peer) { + Serial.println("Disconnected."); + }); + Serial.println("BLE starts advertising..."); assertTrue(BLE.advertising()); @@ -98,7 +105,6 @@ test(BLE_01_Peripheral_Advertising) { test(BLE_02_Peripheral_Connected) { assertTrue(waitFor(BLE.connected, 20000)); - Serial.println("BLE connected."); } // For the first data transmission, we need to wait longer to make sure @@ -260,25 +266,30 @@ static void pairingTestRoutine(bool request, BlePairingAlgorithm algorithm) { }); assertTrue(waitFor(BLE.connected, 20000)); + { + SCOPE_GUARD ({ + assertTrue(waitFor([]{ return !BLE.connected(); }, 5000)); + assertFalse(BLE.connected()); + }); + + if (request) { + peer = BLE.peerCentral(); + Serial.println("Start pairing..."); + assertEqual(BLE.startPairing(peer), (int)SYSTEM_ERROR_NONE); + } else { + assertTrue(waitFor([&]{ return pairingRequested; }, 20000)); + } + assertTrue(BLE.isPairing(peer)); + assertTrue(waitFor([&]{ return !BLE.isPairing(peer); }, 20000)); + assertTrue(BLE.isPaired(peer)); + assertEqual(pairingStatus, (int)SYSTEM_ERROR_NONE); + if (algorithm != BlePairingAlgorithm::LEGACY_ONLY) { + assertTrue(lesc); + } else { + assertFalse(lesc); + } - if (request) { - peer = BLE.peerCentral(); - assertEqual(BLE.startPairing(peer), (int)SYSTEM_ERROR_NONE); - } else { - assertTrue(waitFor([&]{ return pairingRequested; }, 20000)); - } - assertTrue(BLE.isPairing(peer)); - assertTrue(waitFor([&]{ return !BLE.isPairing(peer); }, 20000)); - assertTrue(BLE.isPaired(peer)); - assertEqual(pairingStatus, (int)SYSTEM_ERROR_NONE); - if (algorithm != BlePairingAlgorithm::LEGACY_ONLY) { - assertTrue(lesc); - } else { - assertFalse(lesc); } - - assertTrue(waitFor([]{ return !BLE.connected(); }, 5000)); - assertFalse(BLE.connected()); } test(BLE_20_Peripheral_Pairing_Algorithm_Auto_Io_Caps) { @@ -310,14 +321,17 @@ test(BLE_22_Peripheral_Pairing_Algorithm_Legacy_Only_Being_Rejected) { assertEqual(BLE.setPairingAlgorithm(BlePairingAlgorithm::LEGACY_ONLY), (int)SYSTEM_ERROR_NONE); assertTrue(waitFor(BLE.connected, 20000)); + { + SCOPE_GUARD ({ + assertTrue(waitFor([]{ return !BLE.connected(); }, 5000)); + assertFalse(BLE.connected()); + }); - assertTrue(waitFor([&]{ return pairingRequested; }, 20000)); - assertTrue(BLE.isPairing(peer)); - assertTrue(waitFor([&]{ return !BLE.isPairing(peer); }, 20000)); - assertFalse(BLE.isPaired(peer)); - - assertTrue(waitFor([]{ return !BLE.connected(); }, 5000)); - assertFalse(BLE.connected()); + assertTrue(waitFor([&]{ return pairingRequested; }, 20000)); + assertTrue(BLE.isPairing(peer)); + assertTrue(waitFor([&]{ return !BLE.isPairing(peer); }, 20000)); + assertFalse(BLE.isPaired(peer)); + } } test(BLE_23_Peripheral_Pairing_Receiption_Reject) { @@ -332,25 +346,31 @@ test(BLE_23_Peripheral_Pairing_Receiption_Reject) { }); assertTrue(waitFor(BLE.connected, 20000)); + { + SCOPE_GUARD ({ + assertTrue(waitFor([]{ return !BLE.connected(); }, 5000)); + assertFalse(BLE.connected()); + }); - assertTrue(waitFor([]{ return pairingStatus != 0; }, 5000)); - - assertTrue(waitFor([]{ return !BLE.connected(); }, 5000)); - assertFalse(BLE.connected()); + assertTrue(waitFor([]{ return pairingStatus != 0; }, 5000)); + } } test(BLE_24_Peripheral_Initiate_Pairing_Being_Rejected) { assertTrue(waitFor(BLE.connected, 20000)); + { + SCOPE_GUARD ({ + assertTrue(waitFor([]{ return !BLE.connected(); }, 5000)); + assertFalse(BLE.connected()); + }); - peer = BLE.peerCentral(); - assertEqual(BLE.startPairing(peer), (int)SYSTEM_ERROR_NONE); - - assertTrue(BLE.isPairing(peer)); - assertTrue(waitFor([&]{ return !BLE.isPairing(peer); }, 20000)); - assertFalse(BLE.isPaired(peer)); + peer = BLE.peerCentral(); + assertEqual(BLE.startPairing(peer), (int)SYSTEM_ERROR_NONE); - assertTrue(waitFor([]{ return !BLE.connected(); }, 5000)); - assertFalse(BLE.connected()); + assertTrue(BLE.isPairing(peer)); + assertTrue(waitFor([&]{ return !BLE.isPairing(peer); }, 20000)); + assertFalse(BLE.isPaired(peer)); + } } #endif // #if Wiring_BLE == 1 From 223ad2af377d8d22c0404a529f611a6ecd29f40c Mon Sep 17 00:00:00 2001 From: XuGuohui Date: Wed, 20 Jan 2021 23:33:02 +0800 Subject: [PATCH 4/9] [hal] BLE: minor fix. --- hal/inc/ble_hal.h | 6 ++--- hal/src/nRF52840/ble_hal.cpp | 44 ++++++++++++++--------------------- wiring/inc/spark_wiring_ble.h | 4 ++-- 3 files changed, 23 insertions(+), 31 deletions(-) diff --git a/hal/inc/ble_hal.h b/hal/inc/ble_hal.h index d4a8ce63f5..0af8229bc3 100644 --- a/hal/inc/ble_hal.h +++ b/hal/inc/ble_hal.h @@ -121,9 +121,9 @@ typedef enum hal_ble_pairing_io_caps_t { } hal_ble_pairing_io_caps_t; typedef enum hal_ble_pairing_algorithm_t { - BLE_PAIRING_ALGORITHM_LEGACY_ONLY = 0, - BLE_PAIRING_ALGORITHM_LESC_ONLY = 1, - BLE_PAIRING_ALGORITHM_AUTO = 2 + BLE_PAIRING_ALGORITHM_AUTO = 0, + BLE_PAIRING_ALGORITHM_LEGACY_ONLY = 1, + BLE_PAIRING_ALGORITHM_LESC_ONLY = 2 } hal_ble_pairing_algorithm_t; typedef enum hal_ble_evts_type_t { diff --git a/hal/src/nRF52840/ble_hal.cpp b/hal/src/nRF52840/ble_hal.cpp index 84d6a29e56..cf6521b6d7 100644 --- a/hal/src/nRF52840/ble_hal.cpp +++ b/hal/src/nRF52840/ble_hal.cpp @@ -478,18 +478,18 @@ class BleObject::ConnectionsManager { BleLinkEventHandler handler; // It is used for central link only. bool isMtuExchanged; BlePairingState pairState; - std::shared_ptr peerPublicKey; + std::unique_ptr peerPublicKey; }; int initSecParams(const hal_ble_pairing_config_t& config, ble_gap_sec_params_t& params); - int generateEcdhKeyPair(void); + int generateEcdhKeyPair(); int publicKeysPrepare(BleConnection* connection); int computeDhkey(const uint8_t peerPublicKey[BLE_GAP_LESC_P256_PK_LEN], uint8_t dhKey[BLE_GAP_LESC_DHKEY_LEN]); int configureAttMtu(hal_ble_conn_handle_t connHandle, size_t effective); bool attMtuExchanged(hal_ble_conn_handle_t connHandle); BleConnection* fetchConnection(hal_ble_conn_handle_t connHandle); BleConnection* fetchConnection(const hal_ble_addr_t* address); - int addConnection(const BleConnection& connection); + int addConnection(BleConnection& connection); void removeConnection(hal_ble_conn_handle_t connHandle); void initiateConnParamsUpdateIfNeeded(const BleConnection* connection); bool isConnParamsFeeded(const hal_ble_conn_params_t* params) const; @@ -522,7 +522,7 @@ class BleObject::ConnectionsManager { hal_ble_pairing_config_t pairingConfig_; mbedtls_ecdh_context ecdhContext_; bool ecdhContextInit_; - std::shared_ptr localPublicKey_; + std::unique_ptr localPublicKey_; }; size_t BleObject::ConnectionsManager::desiredAttMtu_ = BLE_MAX_ATT_MTU_SIZE; @@ -774,6 +774,7 @@ os_thread_return_t BleObject::BleEventDispatcher::processBleEventFromThread(void } case BLE_GATTC_EVT_HVX: { BleObject::getInstance().gattc()->processDataNotifiedEventFromThread(event); + break; } case BLE_GAP_EVT_SEC_INFO_REQUEST: case BLE_GAP_EVT_LESC_DHKEY_REQUEST: @@ -784,6 +785,7 @@ os_thread_return_t BleObject::BleEventDispatcher::processBleEventFromThread(void case BLE_GAP_EVT_AUTH_STATUS: case BLE_GAP_EVT_CONN_SEC_UPDATE: { BleObject::getInstance().connMgr()->processSecurityEventFromThread(event); + break; } default: { break; @@ -1958,26 +1960,20 @@ int BleObject::ConnectionsManager::generateEcdhKeyPair(void) { int BleObject::ConnectionsManager::publicKeysPrepare(BleConnection* connection) { CHECK_TRUE(ecdhContextInit_, SYSTEM_ERROR_INVALID_STATE); - int ret = SYSTEM_ERROR_CRYPTO; - SCOPE_GUARD ({ - if (localPublicKey_ && ret != SYSTEM_ERROR_NONE) { - localPublicKey_.reset(); - } - }); // Local public key: won't be freed. if (!localPublicKey_) { - localPublicKey_.reset((ble_gap_lesc_p256_pk_t*)malloc(sizeof(ble_gap_lesc_p256_pk_t))); - CHECK_TRUE(localPublicKey_, SYSTEM_ERROR_NO_MEMORY); + auto local = std::make_unique(); + CHECK_TRUE(local, SYSTEM_ERROR_NO_MEMORY); const uint8_t pointLen = BLE_GAP_LESC_P256_PK_LEN / 2; - CHECK_MBEDTLS(mbedtls_mpi_write_binary_le(&ecdhContext_.ctx.mbed_ecdh.Q.X, &(localPublicKey_.get()->pk[0]), pointLen)); - CHECK_MBEDTLS(mbedtls_mpi_write_binary_le(&ecdhContext_.ctx.mbed_ecdh.Q.Y, &(localPublicKey_.get()->pk[pointLen]), pointLen)); + CHECK_MBEDTLS(mbedtls_mpi_write_binary_le(&ecdhContext_.ctx.mbed_ecdh.Q.X, &(local.get()->pk[0]), pointLen)); + CHECK_MBEDTLS(mbedtls_mpi_write_binary_le(&ecdhContext_.ctx.mbed_ecdh.Q.Y, &(local.get()->pk[pointLen]), pointLen)); + localPublicKey_ = std::move(local); } - ret = SYSTEM_ERROR_NONE; // Peer public key: will be freed on authentication status updated or disconnected. - connection->peerPublicKey.reset((ble_gap_lesc_p256_pk_t*)malloc(sizeof(ble_gap_lesc_p256_pk_t))); + connection->peerPublicKey = std::make_unique(); CHECK_TRUE(connection->peerPublicKey, SYSTEM_ERROR_NO_MEMORY); memset(connection->peerPublicKey.get(), 0x00, BLE_GAP_LESC_P256_PK_LEN); - return ret; + return SYSTEM_ERROR_NONE; } int BleObject::ConnectionsManager::computeDhkey(const uint8_t peerPublicKey[BLE_GAP_LESC_P256_PK_LEN], uint8_t dhKey[BLE_GAP_LESC_DHKEY_LEN]) { @@ -1994,13 +1990,9 @@ int BleObject::ConnectionsManager::computeDhkey(const uint8_t peerPublicKey[BLE_ int BleObject::ConnectionsManager::setPairingConfig(const hal_ble_pairing_config_t* config) { CHECK_TRUE(config, SYSTEM_ERROR_INVALID_ARGUMENT); - memcpy(&pairingConfig_, config, std::min(pairingConfig_.size, config->size)); - if (config->version < BLE_API_VERSION_2) { - // Without rebuilding the user application against the newer Device OS, device can support LESC as well. - pairingConfig_.algorithm = BLE_PAIRING_ALGORITHM_AUTO; - } - pairingConfig_.version = BLE_API_VERSION; + pairingConfig_ = {}; pairingConfig_.size = sizeof(hal_ble_pairing_config_t); + memcpy(&pairingConfig_, config, std::min(pairingConfig_.size, config->size)); return SYSTEM_ERROR_NONE; } @@ -2079,11 +2071,11 @@ int BleObject::ConnectionsManager::lescNumericComparison(hal_ble_conn_handle_t c } else { ret = sd_ble_gap_auth_key_reply(connHandle, BLE_GAP_AUTH_KEY_TYPE_NONE/*reject*/, nullptr); } - connection->pairState = BLE_PAIRING_STATE_LESC_KEY_CONFIRMED; if (ret != NRF_SUCCESS) { connection->pairState = BLE_PAIRING_STATE_NOT_INITIATED; return nrf_system_error(ret); } + connection->pairState = BLE_PAIRING_STATE_LESC_KEY_CONFIRMED; return SYSTEM_ERROR_NONE; } @@ -2206,9 +2198,9 @@ BleObject::ConnectionsManager::BleConnection* BleObject::ConnectionsManager::fet return nullptr; } -int BleObject::ConnectionsManager::addConnection(const BleConnection& connection) { +int BleObject::ConnectionsManager::addConnection(BleConnection& connection) { CHECK_TRUE(fetchConnection(connection.info.conn_handle) == nullptr, SYSTEM_ERROR_INTERNAL); - CHECK_TRUE(connections_.append(connection), SYSTEM_ERROR_NO_MEMORY); + CHECK_TRUE(connections_.append(std::move(connection)), SYSTEM_ERROR_NO_MEMORY); return SYSTEM_ERROR_NONE; } diff --git a/wiring/inc/spark_wiring_ble.h b/wiring/inc/spark_wiring_ble.h index f889ddc830..24bdbb679b 100644 --- a/wiring/inc/spark_wiring_ble.h +++ b/wiring/inc/spark_wiring_ble.h @@ -156,9 +156,9 @@ enum class BlePairingIoCaps : uint8_t { }; enum class BlePairingAlgorithm : uint8_t { + AUTO = BLE_PAIRING_ALGORITHM_AUTO, LEGACY_ONLY = BLE_PAIRING_ALGORITHM_LEGACY_ONLY, - LESC_ONLY = BLE_PAIRING_ALGORITHM_LESC_ONLY, - AUTO = BLE_PAIRING_ALGORITHM_AUTO + LESC_ONLY = BLE_PAIRING_ALGORITHM_LESC_ONLY }; enum class BlePairingEventType : uint8_t { From 8068107fb919e4cba0e51dae410e47f6ea7f135c Mon Sep 17 00:00:00 2001 From: XuGuohui Date: Thu, 21 Jan 2021 01:30:12 +0800 Subject: [PATCH 5/9] [hal] BLE: re-generate local key pair after pairing. --- hal/src/nRF52840/ble_hal.cpp | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/hal/src/nRF52840/ble_hal.cpp b/hal/src/nRF52840/ble_hal.cpp index cf6521b6d7..b12025bf23 100644 --- a/hal/src/nRF52840/ble_hal.cpp +++ b/hal/src/nRF52840/ble_hal.cpp @@ -521,7 +521,7 @@ class BleObject::ConnectionsManager { Vector peripheralLinkEventHandlers_; /**< It is used for peripheral link only. */ hal_ble_pairing_config_t pairingConfig_; mbedtls_ecdh_context ecdhContext_; - bool ecdhContextInit_; + volatile bool ecdhContextInit_; std::unique_ptr localPublicKey_; }; @@ -1711,11 +1711,6 @@ int BleObject::ConnectionsManager::init() { LOG(ERROR, "os_timer_create() failed."); goto error; } - if (generateEcdhKeyPair() != SYSTEM_ERROR_NONE) { - LOG(ERROR, "generateEcdhKeyPair() failed."); - } else { - ecdhContextInit_ = true; - } connMgrImpl.instance = this; NRF_SDH_BLE_OBSERVER(bleConnectionManager, 1, processConnectionEvents, &connMgrImpl); connMgrInitialized_ = true; @@ -1951,24 +1946,28 @@ int BleObject::ConnectionsManager::initSecParams(const hal_ble_pairing_config_t& } int BleObject::ConnectionsManager::generateEcdhKeyPair(void) { + ecdhContextInit_ = false; mbedtls_ecdh_init(&ecdhContext_); CHECK_MBEDTLS(mbedtls_ecdh_setup(&ecdhContext_, MBEDTLS_ECP_DP_SECP256R1)); CHECK_MBEDTLS(mbedtls_ecdh_gen_public(&ecdhContext_.ctx.mbed_ecdh.grp, &ecdhContext_.ctx.mbed_ecdh.d, &ecdhContext_.ctx.mbed_ecdh.Q, mbedtls_default_rng, nullptr)); + ecdhContextInit_ = true; return SYSTEM_ERROR_NONE; } int BleObject::ConnectionsManager::publicKeysPrepare(BleConnection* connection) { + if (!ecdhContextInit_) { + generateEcdhKeyPair(); + } CHECK_TRUE(ecdhContextInit_, SYSTEM_ERROR_INVALID_STATE); // Local public key: won't be freed. if (!localPublicKey_) { - auto local = std::make_unique(); - CHECK_TRUE(local, SYSTEM_ERROR_NO_MEMORY); - const uint8_t pointLen = BLE_GAP_LESC_P256_PK_LEN / 2; - CHECK_MBEDTLS(mbedtls_mpi_write_binary_le(&ecdhContext_.ctx.mbed_ecdh.Q.X, &(local.get()->pk[0]), pointLen)); - CHECK_MBEDTLS(mbedtls_mpi_write_binary_le(&ecdhContext_.ctx.mbed_ecdh.Q.Y, &(local.get()->pk[pointLen]), pointLen)); - localPublicKey_ = std::move(local); + localPublicKey_ = std::make_unique(); + CHECK_TRUE(localPublicKey_, SYSTEM_ERROR_NO_MEMORY); } + const uint8_t pointLen = BLE_GAP_LESC_P256_PK_LEN / 2; + CHECK_MBEDTLS(mbedtls_mpi_write_binary_le(&ecdhContext_.ctx.mbed_ecdh.Q.X, &(localPublicKey_.get()->pk[0]), pointLen)); + CHECK_MBEDTLS(mbedtls_mpi_write_binary_le(&ecdhContext_.ctx.mbed_ecdh.Q.Y, &(localPublicKey_.get()->pk[pointLen]), pointLen)); // Peer public key: will be freed on authentication status updated or disconnected. connection->peerPublicKey = std::make_unique(); CHECK_TRUE(connection->peerPublicKey, SYSTEM_ERROR_NO_MEMORY); @@ -2537,6 +2536,15 @@ int BleObject::ConnectionsManager::processSecurityEventFromThread(const ble_evt_ linkEvent.params.pairing_status.bonded = authStatus.bonded; linkEvent.params.pairing_status.lesc = authStatus.lesc; notifyLinkEvent(linkEvent); + if (authStatus.lesc) { + /* To protect a device's private key, a device should implement a method to + * prevent an attacker from retrieving useful information about the device's private + * key. For this purpose, a device should change its private key after every pairing + * (successful or failed). Otherwise, it should change its private key whenever S + + * 3F > 8, where S is the number of successful pairings and F the number of + * failed attempts since the key was last changed. */ + generateEcdhKeyPair(); + } } else if (event->header.evt_id == BLE_GAP_EVT_LESC_DHKEY_REQUEST) { LOG_DEBUG(TRACE, "BLE event: BLE_GAP_EVT_LESC_DHKEY_REQUEST"); const ble_gap_evt_lesc_dhkey_request_t& dhkeyReq = event->evt.gap_evt.params.lesc_dhkey_request; From a3dab1fd4dbcf4e0dccbc66fbafcdf99cb0fff73 Mon Sep 17 00:00:00 2001 From: XuGuohui Date: Tue, 23 Feb 2021 15:38:09 +0800 Subject: [PATCH 6/9] [hal] BLE: minor --- hal/src/nRF52840/ble_hal.cpp | 6 +++--- .../wiring/ble_central_peripheral/ble_central/central.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hal/src/nRF52840/ble_hal.cpp b/hal/src/nRF52840/ble_hal.cpp index b12025bf23..6d8186f5dc 100644 --- a/hal/src/nRF52840/ble_hal.cpp +++ b/hal/src/nRF52840/ble_hal.cpp @@ -489,7 +489,7 @@ class BleObject::ConnectionsManager { bool attMtuExchanged(hal_ble_conn_handle_t connHandle); BleConnection* fetchConnection(hal_ble_conn_handle_t connHandle); BleConnection* fetchConnection(const hal_ble_addr_t* address); - int addConnection(BleConnection& connection); + int addConnection(BleConnection&& connection); void removeConnection(hal_ble_conn_handle_t connHandle); void initiateConnParamsUpdateIfNeeded(const BleConnection* connection); bool isConnParamsFeeded(const hal_ble_conn_params_t* params) const; @@ -2197,7 +2197,7 @@ BleObject::ConnectionsManager::BleConnection* BleObject::ConnectionsManager::fet return nullptr; } -int BleObject::ConnectionsManager::addConnection(BleConnection& connection) { +int BleObject::ConnectionsManager::addConnection(BleConnection&& connection) { CHECK_TRUE(fetchConnection(connection.info.conn_handle) == nullptr, SYSTEM_ERROR_INTERNAL); CHECK_TRUE(connections_.append(std::move(connection)), SYSTEM_ERROR_NO_MEMORY); return SYSTEM_ERROR_NONE; @@ -2326,7 +2326,7 @@ int BleObject::ConnectionsManager::processConnectedEventFromThread(const ble_evt connection.info.att_mtu = BLE_DEFAULT_ATT_MTU_SIZE; // Use the default ATT_MTU on connected. connection.isMtuExchanged = false; connection.pairState = BLE_PAIRING_STATE_NOT_INITIATED; - int ret = addConnection(connection); + int ret = addConnection(std::move(connection)); if (ret != SYSTEM_ERROR_NONE) { LOG(ERROR, "Add new connection failed. Disconnects from peer."); if (sd_ble_gap_disconnect(connection.info.conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION) != NRF_SUCCESS) { diff --git a/user/tests/wiring/ble_central_peripheral/ble_central/central.cpp b/user/tests/wiring/ble_central_peripheral/ble_central/central.cpp index e8882d28d4..586785671f 100644 --- a/user/tests/wiring/ble_central_peripheral/ble_central/central.cpp +++ b/user/tests/wiring/ble_central_peripheral/ble_central/central.cpp @@ -410,7 +410,7 @@ test(BLE_26_Central_Pairing_Algorithm_Lesc_Only_Reject_Legacy) { } } -test(BLE_27_Central_Initiate_Pairing_Peripheral_Being_Rejected) { +test(BLE_27_Central_Initiate_Pairing_Being_Rejected) { peer = BLE.connect(peerAddr, false); assertTrue(peer.connected()); { From 4dfe0b53d484ffa9605898a938f4804d84bdcc06 Mon Sep 17 00:00:00 2001 From: XuGuohui Date: Tue, 23 Feb 2021 19:55:58 +0800 Subject: [PATCH 7/9] [hal] BLE: generalize HAL API that sets authentication data. --- hal/inc/ble_hal.h | 25 ++++++++--- hal/inc/ble_hal_defines.h | 3 ++ hal/inc/hal_dynalib_ble.h | 4 +- hal/src/nRF52840/ble_hal.cpp | 78 ++++++++++++++------------------- wiring/src/spark_wiring_ble.cpp | 10 ++++- 5 files changed, 67 insertions(+), 53 deletions(-) diff --git a/hal/inc/ble_hal.h b/hal/inc/ble_hal.h index 0af8229bc3..3f1d14e433 100644 --- a/hal/inc/ble_hal.h +++ b/hal/inc/ble_hal.h @@ -126,6 +126,13 @@ typedef enum hal_ble_pairing_algorithm_t { BLE_PAIRING_ALGORITHM_LESC_ONLY = 2 } hal_ble_pairing_algorithm_t; +typedef enum hal_ble_pairing_auth_data_type_t { + BLE_PAIRING_AUTH_DATA_NUMERIC_COMPARISON = 0, + BLE_PAIRING_AUTH_DATA_PASSKEY = 1, + BLE_PAIRING_AUTH_DATA_LEGACY_OOB = 2, + BLE_PAIRING_AITH_DATA_LESC_OOB = 3 +} hal_ble_pairing_auth_data_type_t; + typedef enum hal_ble_evts_type_t { BLE_EVT_UNKNOWN = 0x00, BLE_EVT_ADV_STOPPED = 0x01, @@ -312,6 +319,14 @@ typedef struct hal_ble_pairing_status_updated_evt_t { uint8_t reserved[3]; } hal_ble_pairing_status_updated_evt_t; +typedef struct hal_ble_pairing_auth_data_t { + hal_ble_pairing_auth_data_type_t type; + union { + bool equal; //For numeric comparison result + const uint8_t* data; // For passkey and OOB data + } params; +} hal_ble_pairing_auth_data_t; + typedef struct hal_ble_link_evt_t { hal_ble_evts_type_t type; union { @@ -869,23 +884,23 @@ int hal_ble_gap_start_pairing(hal_ble_conn_handle_t conn_handle, void* reserved) int hal_ble_gap_reject_pairing(hal_ble_conn_handle_t conn_handle, void* reserved); /** - * Provide the 6-digits passkey that is observed from the peer's display. + * Set pairing authentication data. * * @param[in] conn_handle BLE connection handle. + * @param[in] auth Authentication data. * * @returns 0 on success, system_error_t on error. */ -int hal_ble_gap_set_pairing_passkey(hal_ble_conn_handle_t conn_handle, const uint8_t* passkey, void* reserved); +int hal_ble_gap_set_pairing_auth_data(hal_ble_conn_handle_t conn_handle, const hal_ble_pairing_auth_data_t* auth, void* reserved); /** - * Confirm the LESC numeric comparision result. + * Provide the 6-digits passkey that is observed from the peer's display. * * @param[in] conn_handle BLE connection handle. - * @param[in] equal True if the numeric comparison is equal, otherwise, false. * * @returns 0 on success, system_error_t on error. */ -int hal_ble_gap_set_lesc_numeric_comparison(hal_ble_conn_handle_t conn_handle, bool equal, void* reserved); +int hal_ble_gap_set_pairing_passkey_deprecated(hal_ble_conn_handle_t conn_handle, const uint8_t* passkey, void* reserved); /** * Check if pairing with peer device is in progress diff --git a/hal/inc/ble_hal_defines.h b/hal/inc/ble_hal_defines.h index 20dc342b3e..84e301674c 100644 --- a/hal/inc/ble_hal_defines.h +++ b/hal/inc/ble_hal_defines.h @@ -37,6 +37,9 @@ // BLE authentication passkey length #define BLE_PAIRING_PASSKEY_LEN (6) +// BLE legacy authentication OOB data length +#define BLE_PAIRING_OOB_DATA_LEN (16) + // BLE device address type typedef enum ble_sig_addr_type_t { BLE_SIG_ADDR_TYPE_PUBLIC = 0x00, /**< Public (identity) address.*/ diff --git a/hal/inc/hal_dynalib_ble.h b/hal/inc/hal_dynalib_ble.h index 08ca7546e5..cf7d8613ff 100644 --- a/hal/inc/hal_dynalib_ble.h +++ b/hal/inc/hal_dynalib_ble.h @@ -100,10 +100,10 @@ DYNALIB_FN(65, hal_ble, hal_ble_gatt_server_indicate_characteristic_value, ssize DYNALIB_FN(66, hal_ble, hal_ble_gap_set_pairing_config, int(const hal_ble_pairing_config_t*, void*)) DYNALIB_FN(67, hal_ble, hal_ble_gap_start_pairing, int(hal_ble_conn_handle_t, void*)) DYNALIB_FN(68, hal_ble, hal_ble_gap_reject_pairing, int(hal_ble_conn_handle_t, void*)) -DYNALIB_FN(69, hal_ble, hal_ble_gap_set_pairing_passkey, int(hal_ble_conn_handle_t, const uint8_t*, void*)) +DYNALIB_FN(69, hal_ble, hal_ble_gap_set_pairing_passkey_deprecated, int(hal_ble_conn_handle_t, const uint8_t*, void*)) DYNALIB_FN(70, hal_ble, hal_ble_gap_is_pairing, bool(hal_ble_conn_handle_t, void*)) DYNALIB_FN(71, hal_ble, hal_ble_gap_is_paired, bool(hal_ble_conn_handle_t, void*)) -DYNALIB_FN(72, hal_ble, hal_ble_gap_set_lesc_numeric_comparison, int(hal_ble_conn_handle_t, bool, void*)) +DYNALIB_FN(72, hal_ble, hal_ble_gap_set_pairing_auth_data, int(hal_ble_conn_handle_t, const hal_ble_pairing_auth_data_t*, void*)) DYNALIB_FN(73, hal_ble, hal_ble_gap_get_pairing_config, int(hal_ble_pairing_config_t*, void*)) DYNALIB_END(hal_ble) diff --git a/hal/src/nRF52840/ble_hal.cpp b/hal/src/nRF52840/ble_hal.cpp index 6d8186f5dc..38ef132012 100644 --- a/hal/src/nRF52840/ble_hal.cpp +++ b/hal/src/nRF52840/ble_hal.cpp @@ -441,8 +441,7 @@ class BleObject::ConnectionsManager { int getPairingConfig(hal_ble_pairing_config_t* config) const; int startPairing(hal_ble_conn_handle_t connHandle); int rejectPairing(hal_ble_conn_handle_t connHandle); - int lescNumericComparison(hal_ble_conn_handle_t connHandle, bool equal); - int setPairingPasskey(hal_ble_conn_handle_t connHandle, const uint8_t* passkey); + int setPairingAuthData(hal_ble_conn_handle_t connHandle, const hal_ble_pairing_auth_data_t* auth); bool isPairing(hal_ble_conn_handle_t connHandle); bool isPaired(hal_ble_conn_handle_t connHandle); bool valid(hal_ble_conn_handle_t connHandle); @@ -469,8 +468,7 @@ class BleObject::ConnectionsManager { BLE_PAIRING_STATE_PASSKEY_DISPLAY, BLE_PAIRING_STATE_PASSKEY_INPUT, BLE_PAIRING_STATE_REJECTED, - BLE_PAIRING_STATE_PAIRED, - BLE_PAIRING_STATE_LESC_KEY_CONFIRMED, + BLE_PAIRING_STATE_PAIRED }; struct BleConnection { @@ -2035,22 +2033,22 @@ int BleObject::ConnectionsManager::rejectPairing(hal_ble_conn_handle_t connHandl CHECK_TRUE(connection, SYSTEM_ERROR_NOT_FOUND); switch (connection->pairState) { case BLE_PAIRING_STATE_SEC_REQ_RECEIVED: { - connection->pairState = BLE_PAIRING_STATE_REJECTED; int ret = sd_ble_gap_authenticate(connection->info.conn_handle, nullptr); CHECK_NRF_RETURN(ret, nrf_system_error(ret)); + connection->pairState = BLE_PAIRING_STATE_REJECTED; break; } case BLE_PAIRING_STATE_PAIRING_REQ_RECEIVED: { - connection->pairState = BLE_PAIRING_STATE_REJECTED; int ret = sd_ble_gap_sec_params_reply(connHandle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, nullptr, nullptr); CHECK_NRF_RETURN(ret, nrf_system_error(ret)); + connection->pairState = BLE_PAIRING_STATE_REJECTED; break; } case BLE_GAP_EVT_PASSKEY_DISPLAY: case BLE_PAIRING_STATE_PASSKEY_INPUT: { - connection->pairState = BLE_PAIRING_STATE_REJECTED; int ret = sd_ble_gap_auth_key_reply(connHandle, BLE_GAP_AUTH_KEY_TYPE_NONE, nullptr); CHECK_NRF_RETURN(ret, nrf_system_error(ret)); + connection->pairState = BLE_PAIRING_STATE_REJECTED; break; } default: { @@ -2060,42 +2058,31 @@ int BleObject::ConnectionsManager::rejectPairing(hal_ble_conn_handle_t connHandl return SYSTEM_ERROR_NONE; } -int BleObject::ConnectionsManager::lescNumericComparison(hal_ble_conn_handle_t connHandle, bool equal) { +int BleObject::ConnectionsManager::setPairingAuthData(hal_ble_conn_handle_t connHandle, const hal_ble_pairing_auth_data_t* auth) { + CHECK_TRUE(auth, SYSTEM_ERROR_INVALID_ARGUMENT); BleConnection* connection = fetchConnection(connHandle); CHECK_TRUE(connection, SYSTEM_ERROR_NOT_FOUND); - CHECK_TRUE(connection->pairState == BLE_PAIRING_STATE_PASSKEY_DISPLAY, SYSTEM_ERROR_INVALID_STATE); int ret; - if (equal) { - ret = sd_ble_gap_auth_key_reply(connHandle, BLE_GAP_AUTH_KEY_TYPE_PASSKEY, nullptr); - } else { - ret = sd_ble_gap_auth_key_reply(connHandle, BLE_GAP_AUTH_KEY_TYPE_NONE/*reject*/, nullptr); - } - if (ret != NRF_SUCCESS) { - connection->pairState = BLE_PAIRING_STATE_NOT_INITIATED; - return nrf_system_error(ret); - } - connection->pairState = BLE_PAIRING_STATE_LESC_KEY_CONFIRMED; - return SYSTEM_ERROR_NONE; -} - -int BleObject::ConnectionsManager::setPairingPasskey(hal_ble_conn_handle_t connHandle, const uint8_t* passkey) { - BleConnection* connection = fetchConnection(connHandle); - CHECK_TRUE(connection, SYSTEM_ERROR_NOT_FOUND); - CHECK_TRUE(connection->pairState == BLE_PAIRING_STATE_PASSKEY_INPUT, SYSTEM_ERROR_INVALID_STATE); - for (uint8_t i = 0; i < 6; i++) { - if (!std::isdigit(passkey[i])) { - sd_ble_gap_auth_key_reply(connHandle, BLE_GAP_AUTH_KEY_TYPE_NONE/*reject*/, nullptr); - LOG(ERROR, "Invalid digits."); - connection->pairState = BLE_PAIRING_STATE_REJECTED; - return SYSTEM_ERROR_INVALID_ARGUMENT; + if (auth->type == BLE_PAIRING_AUTH_DATA_NUMERIC_COMPARISON) { + CHECK_TRUE(connection->pairState == BLE_PAIRING_STATE_PASSKEY_DISPLAY, SYSTEM_ERROR_INVALID_STATE); + if (auth->params.equal) { + ret = sd_ble_gap_auth_key_reply(connHandle, BLE_GAP_AUTH_KEY_TYPE_PASSKEY, nullptr); + } else { + return rejectPairing(connHandle); } + } else if (auth->type == BLE_PAIRING_AUTH_DATA_PASSKEY) { + CHECK_TRUE(connection->pairState == BLE_PAIRING_STATE_PASSKEY_INPUT, SYSTEM_ERROR_INVALID_STATE); + for (uint8_t i = 0; i < 6; i++) { + if (!std::isdigit(auth->params.data[i])) { + LOG(ERROR, "Invalid digits."); + return rejectPairing(connHandle); + } + } + ret = sd_ble_gap_auth_key_reply(connHandle, BLE_GAP_AUTH_KEY_TYPE_PASSKEY, auth->params.data); + } else { + return SYSTEM_ERROR_NOT_SUPPORTED; } - int ret = sd_ble_gap_auth_key_reply(connHandle, BLE_GAP_AUTH_KEY_TYPE_PASSKEY, passkey); - if (ret != NRF_SUCCESS) { - connection->pairState = BLE_PAIRING_STATE_NOT_INITIATED; - return nrf_system_error(ret); - } - return SYSTEM_ERROR_NONE; + return nrf_system_error(ret); } bool BleObject::ConnectionsManager::isPairing(hal_ble_conn_handle_t connHandle) { @@ -4223,18 +4210,21 @@ int hal_ble_gap_reject_pairing(hal_ble_conn_handle_t conn_handle, void* reserved return BleObject::getInstance().connMgr()->rejectPairing(conn_handle); } -int hal_ble_gap_set_pairing_passkey(hal_ble_conn_handle_t conn_handle, const uint8_t* passkey, void* reserved) { +int hal_ble_gap_set_pairing_auth_data(hal_ble_conn_handle_t conn_handle, const hal_ble_pairing_auth_data_t* auth, void* reserved) { BleLock lk; - LOG_DEBUG(TRACE, "hal_ble_gap_set_pairing_passkey()."); + LOG_DEBUG(TRACE, "hal_ble_gap_set_pairing_auth_data()."); CHECK_TRUE(BleObject::getInstance().initialized(), SYSTEM_ERROR_INVALID_STATE); - return BleObject::getInstance().connMgr()->setPairingPasskey(conn_handle, passkey); + return BleObject::getInstance().connMgr()->setPairingAuthData(conn_handle, auth); } -int hal_ble_gap_set_lesc_numeric_comparison(hal_ble_conn_handle_t conn_handle, bool equal, void* reserved) { +int hal_ble_gap_set_pairing_passkey_deprecated(hal_ble_conn_handle_t conn_handle, const uint8_t* passkey, void* reserved) { BleLock lk; - LOG_DEBUG(TRACE, "hal_ble_gap_set_lesc_numeric_comparison()."); + LOG_DEBUG(TRACE, "hal_ble_gap_set_pairing_passkey_deprecated()."); CHECK_TRUE(BleObject::getInstance().initialized(), SYSTEM_ERROR_INVALID_STATE); - return BleObject::getInstance().connMgr()->lescNumericComparison(conn_handle, equal); + hal_ble_pairing_auth_data_t auth = {}; + auth.type = BLE_PAIRING_AUTH_DATA_PASSKEY; + auth.params.data = passkey; + return BleObject::getInstance().connMgr()->setPairingAuthData(conn_handle, &auth); } bool hal_ble_gap_is_pairing(hal_ble_conn_handle_t conn_handle, void* reserved) { diff --git a/wiring/src/spark_wiring_ble.cpp b/wiring/src/spark_wiring_ble.cpp index b24886abee..9b5be88031 100644 --- a/wiring/src/spark_wiring_ble.cpp +++ b/wiring/src/spark_wiring_ble.cpp @@ -2614,11 +2614,17 @@ int BleLocalDevice::rejectPairing(const BlePeerDevice& peer) const { } int BleLocalDevice::setPairingNumericComparison(const BlePeerDevice& peer, bool equal) const { - return hal_ble_gap_set_lesc_numeric_comparison(peer.impl()->connHandle(), equal, nullptr); + hal_ble_pairing_auth_data_t auth = {}; + auth.type = BLE_PAIRING_AUTH_DATA_NUMERIC_COMPARISON; + auth.params.equal = equal; + return hal_ble_gap_set_pairing_auth_data(peer.impl()->connHandle(), &auth, nullptr); } int BleLocalDevice::setPairingPasskey(const BlePeerDevice& peer, const uint8_t* passkey) const { - return hal_ble_gap_set_pairing_passkey(peer.impl()->connHandle(), passkey, nullptr); + hal_ble_pairing_auth_data_t auth = {}; + auth.type = BLE_PAIRING_AUTH_DATA_PASSKEY; + auth.params.data = passkey; + return hal_ble_gap_set_pairing_auth_data(peer.impl()->connHandle(), &auth, nullptr); } bool BleLocalDevice::isPairing(const BlePeerDevice& peer) const { From 70f1dbec6e45982eff13343c2b16583cf7ce0d9c Mon Sep 17 00:00:00 2001 From: XuGuohui Date: Wed, 24 Feb 2021 14:43:48 +0800 Subject: [PATCH 8/9] [hal] BLE: minor --- hal/inc/ble_hal.h | 5 ++++- hal/src/nRF52840/ble_hal.cpp | 15 +++++++++------ wiring/src/spark_wiring_ble.cpp | 4 +++- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/hal/inc/ble_hal.h b/hal/inc/ble_hal.h index 3f1d14e433..634f296bf9 100644 --- a/hal/inc/ble_hal.h +++ b/hal/inc/ble_hal.h @@ -321,9 +321,12 @@ typedef struct hal_ble_pairing_status_updated_evt_t { typedef struct hal_ble_pairing_auth_data_t { hal_ble_pairing_auth_data_type_t type; + uint16_t size; // payload length of params union { bool equal; //For numeric comparison result - const uint8_t* data; // For passkey and OOB data + const uint8_t* passkey; // For passkey + const uint8_t* legacy_oob; // For legacy OOB data + const uint8_t* lesc_oob; // For LESC OOB data } params; } hal_ble_pairing_auth_data_t; diff --git a/hal/src/nRF52840/ble_hal.cpp b/hal/src/nRF52840/ble_hal.cpp index 38ef132012..46f803f528 100644 --- a/hal/src/nRF52840/ble_hal.cpp +++ b/hal/src/nRF52840/ble_hal.cpp @@ -2035,6 +2035,8 @@ int BleObject::ConnectionsManager::rejectPairing(hal_ble_conn_handle_t connHandl case BLE_PAIRING_STATE_SEC_REQ_RECEIVED: { int ret = sd_ble_gap_authenticate(connection->info.conn_handle, nullptr); CHECK_NRF_RETURN(ret, nrf_system_error(ret)); + // We should not tamper the pairing state to be out of sync with the SoftDevice. + // Only if the SD call returns success we then mark the pairing state as rejected. connection->pairState = BLE_PAIRING_STATE_REJECTED; break; } @@ -2063,22 +2065,22 @@ int BleObject::ConnectionsManager::setPairingAuthData(hal_ble_conn_handle_t conn BleConnection* connection = fetchConnection(connHandle); CHECK_TRUE(connection, SYSTEM_ERROR_NOT_FOUND); int ret; - if (auth->type == BLE_PAIRING_AUTH_DATA_NUMERIC_COMPARISON) { + if (auth->type == BLE_PAIRING_AUTH_DATA_NUMERIC_COMPARISON && auth->size == sizeof(bool)) { CHECK_TRUE(connection->pairState == BLE_PAIRING_STATE_PASSKEY_DISPLAY, SYSTEM_ERROR_INVALID_STATE); if (auth->params.equal) { ret = sd_ble_gap_auth_key_reply(connHandle, BLE_GAP_AUTH_KEY_TYPE_PASSKEY, nullptr); } else { return rejectPairing(connHandle); } - } else if (auth->type == BLE_PAIRING_AUTH_DATA_PASSKEY) { + } else if (auth->type == BLE_PAIRING_AUTH_DATA_PASSKEY && auth->size == BLE_PAIRING_PASSKEY_LEN) { CHECK_TRUE(connection->pairState == BLE_PAIRING_STATE_PASSKEY_INPUT, SYSTEM_ERROR_INVALID_STATE); - for (uint8_t i = 0; i < 6; i++) { - if (!std::isdigit(auth->params.data[i])) { + for (uint8_t i = 0; i < BLE_PAIRING_PASSKEY_LEN; i++) { + if (!std::isdigit(auth->params.passkey[i])) { LOG(ERROR, "Invalid digits."); return rejectPairing(connHandle); } } - ret = sd_ble_gap_auth_key_reply(connHandle, BLE_GAP_AUTH_KEY_TYPE_PASSKEY, auth->params.data); + ret = sd_ble_gap_auth_key_reply(connHandle, BLE_GAP_AUTH_KEY_TYPE_PASSKEY, auth->params.passkey); } else { return SYSTEM_ERROR_NOT_SUPPORTED; } @@ -4223,7 +4225,8 @@ int hal_ble_gap_set_pairing_passkey_deprecated(hal_ble_conn_handle_t conn_handle CHECK_TRUE(BleObject::getInstance().initialized(), SYSTEM_ERROR_INVALID_STATE); hal_ble_pairing_auth_data_t auth = {}; auth.type = BLE_PAIRING_AUTH_DATA_PASSKEY; - auth.params.data = passkey; + auth.size = BLE_PAIRING_PASSKEY_LEN; + auth.params.passkey = passkey; return BleObject::getInstance().connMgr()->setPairingAuthData(conn_handle, &auth); } diff --git a/wiring/src/spark_wiring_ble.cpp b/wiring/src/spark_wiring_ble.cpp index 9b5be88031..adf6f4a954 100644 --- a/wiring/src/spark_wiring_ble.cpp +++ b/wiring/src/spark_wiring_ble.cpp @@ -2616,6 +2616,7 @@ int BleLocalDevice::rejectPairing(const BlePeerDevice& peer) const { int BleLocalDevice::setPairingNumericComparison(const BlePeerDevice& peer, bool equal) const { hal_ble_pairing_auth_data_t auth = {}; auth.type = BLE_PAIRING_AUTH_DATA_NUMERIC_COMPARISON; + auth.size = sizeof(bool); auth.params.equal = equal; return hal_ble_gap_set_pairing_auth_data(peer.impl()->connHandle(), &auth, nullptr); } @@ -2623,7 +2624,8 @@ int BleLocalDevice::setPairingNumericComparison(const BlePeerDevice& peer, bool int BleLocalDevice::setPairingPasskey(const BlePeerDevice& peer, const uint8_t* passkey) const { hal_ble_pairing_auth_data_t auth = {}; auth.type = BLE_PAIRING_AUTH_DATA_PASSKEY; - auth.params.data = passkey; + auth.size = BLE_PAIRING_PASSKEY_LEN; + auth.params.passkey = passkey; return hal_ble_gap_set_pairing_auth_data(peer.impl()->connHandle(), &auth, nullptr); } From 0fb2394c0110c55ecfd5db8bb69ac4dac61234b8 Mon Sep 17 00:00:00 2001 From: XuGuohui Date: Wed, 24 Feb 2021 15:32:48 +0800 Subject: [PATCH 9/9] [hal] BLE: add version field for hal_ble_pairing_auth_data_t. --- hal/inc/ble_hal.h | 3 ++- hal/src/nRF52840/ble_hal.cpp | 7 ++++--- wiring/src/spark_wiring_ble.cpp | 6 ++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/hal/inc/ble_hal.h b/hal/inc/ble_hal.h index 634f296bf9..edbbc14ea5 100644 --- a/hal/inc/ble_hal.h +++ b/hal/inc/ble_hal.h @@ -320,8 +320,9 @@ typedef struct hal_ble_pairing_status_updated_evt_t { } hal_ble_pairing_status_updated_evt_t; typedef struct hal_ble_pairing_auth_data_t { + uint16_t version; + uint16_t size; hal_ble_pairing_auth_data_type_t type; - uint16_t size; // payload length of params union { bool equal; //For numeric comparison result const uint8_t* passkey; // For passkey diff --git a/hal/src/nRF52840/ble_hal.cpp b/hal/src/nRF52840/ble_hal.cpp index 46f803f528..c42a694c45 100644 --- a/hal/src/nRF52840/ble_hal.cpp +++ b/hal/src/nRF52840/ble_hal.cpp @@ -2065,14 +2065,14 @@ int BleObject::ConnectionsManager::setPairingAuthData(hal_ble_conn_handle_t conn BleConnection* connection = fetchConnection(connHandle); CHECK_TRUE(connection, SYSTEM_ERROR_NOT_FOUND); int ret; - if (auth->type == BLE_PAIRING_AUTH_DATA_NUMERIC_COMPARISON && auth->size == sizeof(bool)) { + if (auth->type == BLE_PAIRING_AUTH_DATA_NUMERIC_COMPARISON) { CHECK_TRUE(connection->pairState == BLE_PAIRING_STATE_PASSKEY_DISPLAY, SYSTEM_ERROR_INVALID_STATE); if (auth->params.equal) { ret = sd_ble_gap_auth_key_reply(connHandle, BLE_GAP_AUTH_KEY_TYPE_PASSKEY, nullptr); } else { return rejectPairing(connHandle); } - } else if (auth->type == BLE_PAIRING_AUTH_DATA_PASSKEY && auth->size == BLE_PAIRING_PASSKEY_LEN) { + } else if (auth->type == BLE_PAIRING_AUTH_DATA_PASSKEY) { CHECK_TRUE(connection->pairState == BLE_PAIRING_STATE_PASSKEY_INPUT, SYSTEM_ERROR_INVALID_STATE); for (uint8_t i = 0; i < BLE_PAIRING_PASSKEY_LEN; i++) { if (!std::isdigit(auth->params.passkey[i])) { @@ -4224,8 +4224,9 @@ int hal_ble_gap_set_pairing_passkey_deprecated(hal_ble_conn_handle_t conn_handle LOG_DEBUG(TRACE, "hal_ble_gap_set_pairing_passkey_deprecated()."); CHECK_TRUE(BleObject::getInstance().initialized(), SYSTEM_ERROR_INVALID_STATE); hal_ble_pairing_auth_data_t auth = {}; + auth.version = BLE_API_VERSION; + auth.size = sizeof(hal_ble_pairing_auth_data_t); auth.type = BLE_PAIRING_AUTH_DATA_PASSKEY; - auth.size = BLE_PAIRING_PASSKEY_LEN; auth.params.passkey = passkey; return BleObject::getInstance().connMgr()->setPairingAuthData(conn_handle, &auth); } diff --git a/wiring/src/spark_wiring_ble.cpp b/wiring/src/spark_wiring_ble.cpp index adf6f4a954..85d35c7882 100644 --- a/wiring/src/spark_wiring_ble.cpp +++ b/wiring/src/spark_wiring_ble.cpp @@ -2615,16 +2615,18 @@ int BleLocalDevice::rejectPairing(const BlePeerDevice& peer) const { int BleLocalDevice::setPairingNumericComparison(const BlePeerDevice& peer, bool equal) const { hal_ble_pairing_auth_data_t auth = {}; + auth.version = BLE_API_VERSION; + auth.size = sizeof(hal_ble_pairing_auth_data_t); auth.type = BLE_PAIRING_AUTH_DATA_NUMERIC_COMPARISON; - auth.size = sizeof(bool); auth.params.equal = equal; return hal_ble_gap_set_pairing_auth_data(peer.impl()->connHandle(), &auth, nullptr); } int BleLocalDevice::setPairingPasskey(const BlePeerDevice& peer, const uint8_t* passkey) const { hal_ble_pairing_auth_data_t auth = {}; + auth.version = BLE_API_VERSION; + auth.size = sizeof(hal_ble_pairing_auth_data_t); auth.type = BLE_PAIRING_AUTH_DATA_PASSKEY; - auth.size = BLE_PAIRING_PASSKEY_LEN; auth.params.passkey = passkey; return hal_ble_gap_set_pairing_auth_data(peer.impl()->connHandle(), &auth, nullptr); }