From dcfdd26ba998f52cf08ac69b595773c0aa117bd8 Mon Sep 17 00:00:00 2001 From: chegewara Date: Mon, 18 Dec 2017 20:04:50 +0100 Subject: [PATCH] Introduced BLE security --- cpp_utils/BLECharacteristic.cpp | 27 ++++-- cpp_utils/BLECharacteristic.h | 4 + cpp_utils/BLEClient.cpp | 50 +++++++++++ cpp_utils/BLEClient.h | 4 + cpp_utils/BLESecurity.cpp | 91 ++++++++++++++++++++ cpp_utils/BLESecurity.h | 60 +++++++++++++ cpp_utils/BLEServer.cpp | 64 +++++++++++++- cpp_utils/BLEServer.h | 8 ++ cpp_utils/SampleSecureClient.cpp | 141 +++++++++++++++++++++++++++++++ cpp_utils/SampleSecureServer.cpp | 88 +++++++++++++++++++ 10 files changed, 529 insertions(+), 8 deletions(-) create mode 100644 cpp_utils/BLESecurity.cpp create mode 100644 cpp_utils/BLESecurity.h create mode 100644 cpp_utils/SampleSecureClient.cpp create mode 100644 cpp_utils/SampleSecureServer.cpp diff --git a/cpp_utils/BLECharacteristic.cpp b/cpp_utils/BLECharacteristic.cpp index 5754c488..9e9aa5c6 100644 --- a/cpp_utils/BLECharacteristic.cpp +++ b/cpp_utils/BLECharacteristic.cpp @@ -107,7 +107,7 @@ void BLECharacteristic::executeCreate(BLEService* pService) { esp_err_t errRc = ::esp_ble_gatts_add_char( m_pService->getHandle(), getUUID().getNative(), - static_cast(ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE), + static_cast(m_permissions), getProperties(), //&value, nullptr, @@ -163,6 +163,9 @@ uint16_t BLECharacteristic::getHandle() { return m_handle; } // getHandle +void BLECharacteristic::setAccessPermissions(esp_gatt_perm_t perm) { + m_permissions = perm; +} esp_gatt_char_prop_t BLECharacteristic::getProperties() { return m_properties; @@ -348,12 +351,17 @@ void BLECharacteristic::handleGATTServerEvent( // The following code has deliberately not been factored to make it fewer statements because this would cloud the // the logic flow comprehension. // + uint16_t maxOffset = m_mtu - 1; + if (m_mtu > 512) + maxOffset = 512; + ESP_LOGI(LOG_TAG, "%d", m_mtu); + ESP_LOGI(LOG_TAG, "%d", maxOffset); if (param->read.need_rsp) { ESP_LOGD(LOG_TAG, "Sending a response (esp_ble_gatts_send_response)"); esp_gatt_rsp_t rsp; std::string value = m_value.getValue(); if (param->read.is_long) { - if (value.length() - m_value.getReadOffset() < 22) { + if (value.length() - m_value.getReadOffset() < maxOffset) { // This is the last in the chain rsp.attr_value.len = value.length() - m_value.getReadOffset(); rsp.attr_value.offset = m_value.getReadOffset(); @@ -361,16 +369,16 @@ void BLECharacteristic::handleGATTServerEvent( m_value.setReadOffset(0); } else { // There will be more to come. - rsp.attr_value.len = 22; + rsp.attr_value.len = maxOffset; rsp.attr_value.offset = m_value.getReadOffset(); memcpy(rsp.attr_value.value, value.data() + rsp.attr_value.offset, rsp.attr_value.len); - m_value.setReadOffset(rsp.attr_value.offset + 22); + m_value.setReadOffset(rsp.attr_value.offset + maxOffset); } } else { - if (value.length() > 21) { + if (value.length()+1 > maxOffset) { // Too big for a single shot entry. - m_value.setReadOffset(22); - rsp.attr_value.len = 22; + m_value.setReadOffset(maxOffset); + rsp.attr_value.len = maxOffset; rsp.attr_value.offset = 0; memcpy(rsp.attr_value.value, value.data(), rsp.attr_value.len); } else { @@ -412,6 +420,7 @@ void BLECharacteristic::handleGATTServerEvent( } case ESP_GATTS_CONNECT_EVT: + m_mtu = 23; m_semaphoreConfEvt.give(); break; @@ -419,6 +428,10 @@ void BLECharacteristic::handleGATTServerEvent( m_semaphoreConfEvt.give(); break; + case ESP_GATTS_MTU_EVT : + m_mtu = param->mtu.mtu; + break; + default: { break; } // default diff --git a/cpp_utils/BLECharacteristic.h b/cpp_utils/BLECharacteristic.h index 7bb54c64..a65bf121 100644 --- a/cpp_utils/BLECharacteristic.h +++ b/cpp_utils/BLECharacteristic.h @@ -13,6 +13,7 @@ #include #include "BLEUUID.h" #include +#include #include "BLEDescriptor.h" #include "BLEValue.h" #include "FreeRTOS.h" @@ -78,6 +79,7 @@ class BLECharacteristic { void setWriteNoResponseProperty(bool value); std::string toString(); uint16_t getHandle(); + void setAccessPermissions(esp_gatt_perm_t perm); static const uint32_t PROPERTY_READ = 1<<0; static const uint32_t PROPERTY_WRITE = 1<<1; @@ -100,6 +102,8 @@ class BLECharacteristic { BLECharacteristicCallbacks* m_pCallbacks; BLEService* m_pService; BLEValue m_value; + esp_gatt_perm_t m_permissions = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE; + uint16_t m_mtu = 23; void handleGATTServerEvent( esp_gatts_cb_event_t event, diff --git a/cpp_utils/BLEClient.cpp b/cpp_utils/BLEClient.cpp index f3987d08..3db0be64 100644 --- a/cpp_utils/BLEClient.cpp +++ b/cpp_utils/BLEClient.cpp @@ -168,6 +168,14 @@ void BLEClient::gattClientEventHandler( break; } // ESP_GATTC_DISCONNECT_EVT + case ESP_GATTS_CONNECT_EVT: { + //m_connId = param->connect.conn_id; // Save the connection id. + if(m_securityLevel){ + esp_ble_set_encryption(evtParam->connect.remote_bda, m_securityLevel); + //memcpy(m_remote_bda, param->connect.remote_bda, sizeof(m_remote_bda)); + } + break; + } // ESP_GATTS_CONNECT_EVT // // ESP_GATTC_OPEN_EVT @@ -411,6 +419,41 @@ void BLEClient::handleGAPEvent( break; } // ESP_GAP_BLE_READ_RSSI_COMPLETE_EVT + case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */ + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PASSKEY_REQ_EVT: "); + // esp_log_buffer_hex(LOG_TAG, m_remote_bda, sizeof(m_remote_bda)); + assert(m_securityCallbacks!=nullptr); + // esp_ble_passkey_reply(m_remote_bda, true, m_securityCallbacks->onPassKeyRequest()); + break; + + /* + * TODO should we add white/black list comparison? + */ + case ESP_GAP_BLE_SEC_REQ_EVT: + /* send the positive(true) security response to the peer device to accept the security request. + If not accept the security request, should sent the security response with negative(false) accept value*/ + if(m_securityCallbacks!=nullptr) + esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, m_securityCallbacks->onSecurityRequest()); + else + esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, false); + break; + /* + * + */ + case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: ///the app will receive this evt when the IO has Output capability and the peer device IO has Input capability. + ///show the passkey number to the user to input it in the peer deivce. + if(m_securityCallbacks!=nullptr) + m_securityCallbacks->onPassKeyNotify(param->ble_security.key_notif.passkey); + break; + case ESP_GAP_BLE_KEY_EVT: + //shows the ble key info share with peer device to the user. + ESP_LOGI(LOG_TAG, "key type = %s", BLESecurity::esp_key_type_to_str(param->ble_security.ble_key.key_type)); + break; + case ESP_GAP_BLE_AUTH_CMPL_EVT: + if(m_securityCallbacks!=nullptr) + m_securityCallbacks->onAuthenticationComplete(param->ble_security.auth_cmpl); + break; + default: break; } @@ -448,6 +491,13 @@ void BLEClient::setValue(BLEUUID serviceUUID, BLEUUID characteristicUUID, std::s ESP_LOGD(LOG_TAG, "<< setValue"); } // setValue +void BLEClient::setEncryptionLevel(esp_ble_sec_act_t level) { + m_securityLevel = level; +} + +void BLEClient::setSecurityCallbacks(BLESecurityCallbacks* callbacks) { + m_securityCallbacks = callbacks; +} /** * @brief Return a string representation of this client. diff --git a/cpp_utils/BLEClient.h b/cpp_utils/BLEClient.h index a60ed102..1a630dfe 100644 --- a/cpp_utils/BLEClient.h +++ b/cpp_utils/BLEClient.h @@ -49,6 +49,8 @@ class BLEClient { void setClientCallbacks(BLEClientCallbacks *pClientCallbacks); void setValue(BLEUUID serviceUUID, BLEUUID characteristicUUID, std::string value); // Set the value of a given characteristic at a given service. + void setEncryptionLevel(esp_ble_sec_act_t level); + void setSecurityCallbacks(BLESecurityCallbacks* pCallbacks); std::string toString(); // Return a string representation of this client. @@ -80,6 +82,8 @@ class BLEClient { FreeRTOS::Semaphore m_semaphoreRssiCmplEvt = FreeRTOS::Semaphore("RssiCmplEvt"); std::map m_servicesMap; void clearServices(); // Clear any existing services. + esp_ble_sec_act_t m_securityLevel = (esp_ble_sec_act_t)0; + BLESecurityCallbacks* m_securityCallbacks = 0; }; // class BLEDevice diff --git a/cpp_utils/BLESecurity.cpp b/cpp_utils/BLESecurity.cpp new file mode 100644 index 00000000..f3e5bbe9 --- /dev/null +++ b/cpp_utils/BLESecurity.cpp @@ -0,0 +1,91 @@ +/* + * BLESecurity.cpp + * + * Created on: Dec 17, 2017 + * Author: chegewara + */ + +#include + +BLESecurity::BLESecurity() { +} + +BLESecurity::~BLESecurity() { +} +/* + * @brief Set requested authentication mode + */ +void BLESecurity::setAuthenticationMode(esp_ble_auth_req_t auth_req) { + m_authReq = auth_req; + esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &m_authReq, sizeof(uint8_t)); // <--- setup requested authentication mode +} +/* + * @brief Set our device IO capability to let end user perform authorization + * either by displaying or entering generated 6-digits pin code + */ +void BLESecurity::setCapability(esp_ble_io_cap_t iocap) { + m_iocap = iocap; + esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t)); +} +/* + * @brief Init encryption key by server + * @param key_size is value between 7 and 16 + */ +void BLESecurity::setInitEncryptionKey(uint8_t init_key, uint8_t key_size) { + m_initKey = init_key; + m_keySize = key_size; + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &m_initKey, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t)); // <--- setup encryption key max size +} + +/* + * @brief Init encryption key by client + * @param key_size is value between 7 and 16 + */ +void BLESecurity::setRespEncryptionKey(uint8_t resp_key, uint8_t key_size) { + m_respKey = resp_key; + m_keySize = key_size; + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &m_respKey, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t)); // <--- setup encryption key max size +} +/* + * @brief Debug function to display what keys are exchanged by peers + */ +char* BLESecurity::esp_key_type_to_str(esp_ble_key_type_t key_type) +{ + char *key_str = NULL; + switch(key_type) { + case ESP_LE_KEY_NONE: + key_str = (char*)"ESP_LE_KEY_NONE"; + break; + case ESP_LE_KEY_PENC: + key_str = (char*)"ESP_LE_KEY_PENC"; + break; + case ESP_LE_KEY_PID: + key_str = (char*)"ESP_LE_KEY_PID"; + break; + case ESP_LE_KEY_PCSRK: + key_str = (char*)"ESP_LE_KEY_PCSRK"; + break; + case ESP_LE_KEY_PLK: + key_str = (char*)"ESP_LE_KEY_PLK"; + break; + case ESP_LE_KEY_LLK: + key_str = (char*)"ESP_LE_KEY_LLK"; + break; + case ESP_LE_KEY_LENC: + key_str = (char*)"ESP_LE_KEY_LENC"; + break; + case ESP_LE_KEY_LID: + key_str = (char*)"ESP_LE_KEY_LID"; + break; + case ESP_LE_KEY_LCSRK: + key_str = (char*)"ESP_LE_KEY_LCSRK"; + break; + default: + key_str = (char*)"INVALID BLE KEY TYPE"; + break; + + } + return key_str; +} diff --git a/cpp_utils/BLESecurity.h b/cpp_utils/BLESecurity.h new file mode 100644 index 00000000..494a1b7c --- /dev/null +++ b/cpp_utils/BLESecurity.h @@ -0,0 +1,60 @@ +/* + * BLESecurity.h + * + * Created on: Dec 17, 2017 + * Author: chegewara + */ + +#ifndef COMPONENTS_CPP_UTILS_BLESECURITY_H_ +#define COMPONENTS_CPP_UTILS_BLESECURITY_H_ +#include + +class BLESecurity { +public: + BLESecurity(); + virtual ~BLESecurity(); + void setAuthenticationMode(esp_ble_auth_req_t auth_req); + void setCapability(esp_ble_io_cap_t iocap); + void setInitEncryptionKey(uint8_t init_key, uint8_t key_size = 16); + void setRespEncryptionKey(uint8_t resp_key, uint8_t key_size = 16); + static char* esp_key_type_to_str(esp_ble_key_type_t key_type); + +private: + esp_ble_auth_req_t m_authReq; + esp_ble_io_cap_t m_iocap; + uint8_t m_initKey; + uint8_t m_respKey; + uint8_t m_keySize; +}; + +/* + * @brief Callbacks to handle GAP events related to authorization + */ +class BLESecurityCallbacks { +public: + virtual ~BLESecurityCallbacks() {}; + + /* + * @brief Its request from peer device to input authentication pin code displayed on peer device. + * It requires that our device is capable to input 6-digits code by end user + * @return Return 6-digits integer value from input device + */ + virtual uint32_t onPassKeyRequest() = 0; + /* + * @brief Provide us 6-digits code to perform authentication. + * It requires that our device is capable to display this code to end user + * @param + */ + virtual void onPassKeyNotify(uint32_t pass_key); + /* + * @brief Here we can make decision if we want to let negotiate authorization with peer device or not + * return Return true if we accept this peer device request + */ + virtual bool onSecurityRequest(); + /* + * Provide us information when authentication process is completed + */ + virtual void onAuthenticationComplete(esp_ble_auth_cmpl_t); +}; + +#endif /* COMPONENTS_CPP_UTILS_BLESECURITY_H_ */ diff --git a/cpp_utils/BLEServer.cpp b/cpp_utils/BLEServer.cpp index 75805135..a3ea7681 100644 --- a/cpp_utils/BLEServer.cpp +++ b/cpp_utils/BLEServer.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +//#include #include "BLEDevice.h" #include "BLEServer.h" #include "BLEService.h" @@ -151,6 +151,53 @@ void BLEServer::handleGAPEvent( */ break; } + case ESP_GAP_BLE_OOB_REQ_EVT: /* OOB request event */ + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_OOB_REQ_EVT"); + break; + case ESP_GAP_BLE_LOCAL_IR_EVT: /* BLE local IR event */ + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_LOCAL_IR_EVT"); + break; + case ESP_GAP_BLE_LOCAL_ER_EVT: /* BLE local ER event */ + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_LOCAL_ER_EVT"); + break; + case ESP_GAP_BLE_NC_REQ_EVT: + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_NC_REQ_EVT"); + break; + case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */ + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PASSKEY_REQ_EVT: "); + esp_log_buffer_hex(LOG_TAG, m_remote_bda, sizeof(m_remote_bda)); + assert(m_securityCallbacks!=nullptr); + esp_ble_passkey_reply(m_remote_bda, true, m_securityCallbacks->onPassKeyRequest()); + break; + + /* + * TODO should we add white/black list comparison? + */ + case ESP_GAP_BLE_SEC_REQ_EVT: + /* send the positive(true) security response to the peer device to accept the security request. + If not accept the security request, should sent the security response with negative(false) accept value*/ + if(m_securityCallbacks!=nullptr) + esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, m_securityCallbacks->onSecurityRequest()); + else + esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, false); + break; + /* + * + */ + case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: ///the app will receive this evt when the IO has Output capability and the peer device IO has Input capability. + ///show the passkey number to the user to input it in the peer deivce. + if(m_securityCallbacks!=nullptr) + m_securityCallbacks->onPassKeyNotify(param->ble_security.key_notif.passkey); + break; + case ESP_GAP_BLE_KEY_EVT: + //shows the ble key info share with peer device to the user. + ESP_LOGI(LOG_TAG, "key type = %s", BLESecurity::esp_key_type_to_str(param->ble_security.ble_key.key_type)); + break; + case ESP_GAP_BLE_AUTH_CMPL_EVT: + if(m_securityCallbacks!=nullptr) + m_securityCallbacks->onAuthenticationComplete(param->ble_security.auth_cmpl); + break; + default: break; } @@ -198,6 +245,10 @@ void BLEServer::handleGATTServerEvent( // case ESP_GATTS_CONNECT_EVT: { m_connId = param->connect.conn_id; // Save the connection id. + if(m_securityLevel){ + esp_ble_set_encryption(param->connect.remote_bda, m_securityLevel); + memcpy(m_remote_bda, param->connect.remote_bda, sizeof(m_remote_bda)); + } if (m_pServerCallbacks != nullptr) { m_pServerCallbacks->onConnect(this); } @@ -334,6 +385,17 @@ void BLEServer::startAdvertising() { ESP_LOGD(LOG_TAG, "<< startAdvertising"); } // startAdvertising +void BLEServer::setEncryptionLevel(esp_ble_sec_act_t level) { + m_securityLevel = level; +} + +uint32_t BLEServer::getPassKey() { + return m_securityPassKey; +} + +void BLEServer::setSecurityCallbacks(BLESecurityCallbacks* callbacks) { + m_securityCallbacks = callbacks; +} void BLEServerCallbacks::onConnect(BLEServer* pServer) { ESP_LOGD("BLEServerCallbacks", ">> onConnect(): Default"); diff --git a/cpp_utils/BLEServer.h b/cpp_utils/BLEServer.h index 524e88f3..8d4554d2 100644 --- a/cpp_utils/BLEServer.h +++ b/cpp_utils/BLEServer.h @@ -18,6 +18,7 @@ #include "BLEAdvertising.h" #include "BLECharacteristic.h" #include "BLEService.h" +#include "BLESecurity.h" #include "FreeRTOS.h" class BLEServerCallbacks; @@ -57,6 +58,9 @@ class BLEServer { BLEAdvertising* getAdvertising(); void setCallbacks(BLEServerCallbacks* pCallbacks); void startAdvertising(); + void setEncryptionLevel(esp_ble_sec_act_t level); + uint32_t getPassKey(); + void setSecurityCallbacks(BLESecurityCallbacks* pCallbacks); private: @@ -74,6 +78,10 @@ class BLEServer { FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt"); BLEServiceMap m_serviceMap; BLEServerCallbacks* m_pServerCallbacks; + esp_ble_sec_act_t m_securityLevel = (esp_ble_sec_act_t)0; + esp_bd_addr_t m_remote_bda; + uint32_t m_securityPassKey; + BLESecurityCallbacks* m_securityCallbacks; void createApp(uint16_t appId); uint16_t getConnId(); diff --git a/cpp_utils/SampleSecureClient.cpp b/cpp_utils/SampleSecureClient.cpp new file mode 100644 index 00000000..457988ed --- /dev/null +++ b/cpp_utils/SampleSecureClient.cpp @@ -0,0 +1,141 @@ +/** + * Create a sample BLE client that connects to a BLE server and then retrieves the current + * characteristic value. It will then periodically update the value of the characteristic on the + * remote server with the current time since boot. + */ +#include +#include +#include +#include +#include "BLEDevice.h" + +#include "BLEAdvertisedDevice.h" +#include "BLEClient.h" +#include "BLEScan.h" +#include "BLEUtils.h" +#include "Task.h" + +#include "sdkconfig.h" + +static const char* LOG_TAG = "SampleClient"; + +// See the following for generating UUIDs: +// https://www.uuidgenerator.net/ +// The remote service we wish to connect to. +static BLEUUID serviceUUID("91bad492-b950-4226-aa2b-4ede9fa42f59"); +// The characteristic of the remote service we are interested in. +static BLEUUID charUUID("0d563a58-196a-48ce-ace2-dfec78acc814"); + +class MySecurity : public BLESecurityCallbacks { + + uint32_t onPassKeyRequest(){ + return 123456; + } + void onPassKeyNotify(uint32_t pass_key){ + ESP_LOGE(LOG_TAG, "The passkey Notify number:%d", pass_key); + } + bool onSecurityRequest(){ + return true; + } + void onAuthenticationComplete(esp_ble_auth_cmpl_t auth_cmpl){ + if(auth_cmpl.success){ + ESP_LOGI(LOG_TAG, "remote BD_ADDR:"); + esp_log_buffer_hex(LOG_TAG, auth_cmpl.bd_addr, sizeof(auth_cmpl.bd_addr)); + ESP_LOGI(LOG_TAG, "address type = %d", auth_cmpl.addr_type); + } + ESP_LOGI(LOG_TAG, "pair status = %s", auth_cmpl.success ? "success" : "fail"); + } +}; + + +/** + * Become a BLE client to a remote BLE server. We are passed in the address of the BLE server + * as the input parameter when the task is created. + */ +class MyClient: public Task { + void run(void* data) { + BLESecurity *pSecurity = new BLESecurity(); + pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_MITM); + pSecurity->setCapability(ESP_IO_CAP_OUT); + pSecurity->setRespEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK); + + BLEAddress* pAddress = (BLEAddress*)data; + BLEClient* pClient = BLEDevice::createClient(); + pClient->setEncryptionLevel(ESP_BLE_SEC_ENCRYPT); + pClient->setSecurityCallbacks(new MySecurity()); + + // Connect to the remove BLE Server. + pClient->connect(*pAddress); + + // Obtain a reference to the service we are after in the remote BLE server. + BLERemoteService* pRemoteService = pClient->getService(serviceUUID); + if (pRemoteService == nullptr) { + ESP_LOGD(LOG_TAG, "Failed to find our service UUID: %s", serviceUUID.toString().c_str()); + return; + } + + + // Obtain a reference to the characteristic in the service of the remote BLE server. + BLERemoteCharacteristic* pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID); + if (pRemoteCharacteristic == nullptr) { + ESP_LOGD(LOG_TAG, "Failed to find our characteristic UUID: %s", charUUID.toString().c_str()); + return; + } + + // Read the value of the characteristic. + std::string value = pRemoteCharacteristic->readValue(); + ESP_LOGD(LOG_TAG, "The characteristic value was: %s", value.c_str()); + + while(1) { + // Set a new value of the characteristic + ESP_LOGD(LOG_TAG, "Setting the new value"); + std::ostringstream stringStream; + struct timeval tv; + gettimeofday(&tv, nullptr); + stringStream << "Time since boot: " << tv.tv_sec; + pRemoteCharacteristic->writeValue(stringStream.str()); + + FreeRTOS::sleep(1000); + } + + pClient->disconnect(); + + ESP_LOGD(LOG_TAG, "%s", pClient->toString().c_str()); + ESP_LOGD(LOG_TAG, "-- End of task"); + } // run +}; // MyClient + + +/** + * Scan for BLE servers and find the first one that advertises the service we are looking for. + */ +class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { + /** + * Called for each advertising BLE server. + */ + void onResult(BLEAdvertisedDevice advertisedDevice) { + ESP_LOGD(LOG_TAG, "Advertised Device: %s", advertisedDevice.toString().c_str()); + + if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) { + advertisedDevice.getScan()->stop(); + + ESP_LOGD(LOG_TAG, "Found our device! address: %s", advertisedDevice.getAddress().toString().c_str()); + MyClient* pMyClient = new MyClient(); + pMyClient->setStackSize(18000); + pMyClient->start(new BLEAddress(*advertisedDevice.getAddress().getNative())); + } // Found our server + } // onResult +}; // MyAdvertisedDeviceCallbacks + + +/** + * Perform the work of a sample BLE client. + */ +void SampleSecureClient(void) { + ESP_LOGD(LOG_TAG, "Scanning sample starting"); + BLEDevice::init(""); + BLEScan *pBLEScan = BLEDevice::getScan(); + pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); + pBLEScan->setActiveScan(true); + pBLEScan->start(15); +} // SampleClient diff --git a/cpp_utils/SampleSecureServer.cpp b/cpp_utils/SampleSecureServer.cpp new file mode 100644 index 00000000..97c9037f --- /dev/null +++ b/cpp_utils/SampleSecureServer.cpp @@ -0,0 +1,88 @@ +/** + * Create a new BLE server. + */ +#include "BLEDevice.h" +#include "BLEServer.h" +#include "BLEUtils.h" +#include "BLE2902.h" +#include +#include +#include + + +#include "sdkconfig.h" + +static char LOG_TAG[] = "SampleServer"; + +class MySecurity : public BLESecurityCallbacks { + + uint32_t onPassKeyRequest(){ + return 123456; + } + void onPassKeyNotify(uint32_t pass_key){ + ESP_LOGE(LOG_TAG, "The passkey Notify number:%d", pass_key); + } + bool onSecurityRequest(){ + return true; + } + void onAuthenticationComplete(esp_ble_auth_cmpl_t auth_cmpl){ + if(auth_cmpl.success){ + ESP_LOGI(LOG_TAG, "remote BD_ADDR:"); + esp_log_buffer_hex(LOG_TAG, auth_cmpl.bd_addr, sizeof(auth_cmpl.bd_addr)); + ESP_LOGI(LOG_TAG, "address type = %d", auth_cmpl.addr_type); + } + ESP_LOGI(LOG_TAG, "pair status = %s", auth_cmpl.success ? "success" : "fail"); + } +}; + +class MainBLEServer: public Task { + void run(void *data) { + ESP_LOGD(LOG_TAG, "Starting BLE work!"); + + BLEDevice::init("ESP32"); + BLEServer* pServer = BLEDevice::createServer(); + pServer->setEncryptionLevel(ESP_BLE_SEC_ENCRYPT); + pServer->setSecurityCallbacks(new MySecurity()); + + BLEService* pService = pServer->createService("91bad492-b950-4226-aa2b-4ede9fa42f59"); + + BLECharacteristic* pCharacteristic = pService->createCharacteristic( + BLEUUID("0d563a58-196a-48ce-ace2-dfec78acc814"), + BLECharacteristic::PROPERTY_BROADCAST | BLECharacteristic::PROPERTY_READ | + BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_WRITE | + BLECharacteristic::PROPERTY_INDICATE + ); + pCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED); + + pCharacteristic->setValue("Hello World!"); + + BLE2902* p2902Descriptor = new BLE2902(); + p2902Descriptor->setNotifications(true); + pCharacteristic->addDescriptor(p2902Descriptor); + + pService->start(); + + BLEAdvertising* pAdvertising = pServer->getAdvertising(); + pAdvertising->addServiceUUID(BLEUUID(pService->getUUID())); + + BLESecurity *pSecurity = new BLESecurity(); + pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_BOND); + pSecurity->setCapability(ESP_IO_CAP_NONE); + pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK); + + pAdvertising->start(); + + ESP_LOGD(LOG_TAG, "Advertising started!"); + delay(1000000); + } +}; + + +void SampleSecureServer(void) +{ + //esp_log_level_set("*", ESP_LOG_DEBUG); + MainBLEServer* pMainBleServer = new MainBLEServer(); + pMainBleServer->setStackSize(20000); + pMainBleServer->start(); + +} // app_main