Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 9a127fc

Browse files
Merge pull request #11681 from lucasssvaz/fix/bt_component
fix(ble): Fix BLESecurity and add examples
2 parents 259c2ff + 586e497 commit 9a127fc

21 files changed

+1034
-166
lines changed
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
/*
2+
Secure client with static passkey
3+
4+
This example demonstrates how to create a secure BLE client that connects to
5+
a secure BLE server using a static passkey without prompting the user.
6+
The client will automatically use the same passkey (123456) as the server.
7+
8+
This client is designed to work with the Server_secure_static_passkey example.
9+
10+
Note that ESP32 uses Bluedroid by default and the other SoCs use NimBLE.
11+
Bluedroid initiates security on-connect, while NimBLE initiates security on-demand.
12+
This means that in NimBLE you can read the insecure characteristic without entering
13+
the passkey. This is not possible in Bluedroid.
14+
15+
Also, the SoC stores the authentication info in the NVS memory. After a successful
16+
connection it is possible that a passkey change will be ineffective.
17+
To avoid this, clear the memory of the SoC's between security tests.
18+
19+
Based on examples from Neil Kolban and h2zero.
20+
Created by lucasssvaz.
21+
*/
22+
23+
#include "BLEDevice.h"
24+
#include "BLESecurity.h"
25+
26+
// The remote service we wish to connect to.
27+
static BLEUUID serviceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
28+
// The characteristics of the remote service we are interested in.
29+
static BLEUUID insecureCharUUID("beb5483e-36e1-4688-b7f5-ea07361b26a8");
30+
static BLEUUID secureCharUUID("ff1d2614-e2d6-4c87-9154-6625d39ca7f8");
31+
32+
// This must match the server's passkey
33+
#define CLIENT_PIN 123456
34+
35+
static boolean doConnect = false;
36+
static boolean connected = false;
37+
static boolean doScan = false;
38+
static BLERemoteCharacteristic *pRemoteInsecureCharacteristic;
39+
static BLERemoteCharacteristic *pRemoteSecureCharacteristic;
40+
static BLEAdvertisedDevice *myDevice;
41+
42+
// Callback function to handle notifications
43+
static void notifyCallback(BLERemoteCharacteristic *pBLERemoteCharacteristic, uint8_t *pData, size_t length, bool isNotify) {
44+
Serial.print("Notify callback for characteristic ");
45+
Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str());
46+
Serial.print(" of data length ");
47+
Serial.println(length);
48+
Serial.print("data: ");
49+
Serial.write(pData, length);
50+
Serial.println();
51+
}
52+
53+
class MyClientCallback : public BLEClientCallbacks {
54+
void onConnect(BLEClient *pclient) {
55+
Serial.println("Connected to secure server");
56+
}
57+
58+
void onDisconnect(BLEClient *pclient) {
59+
connected = false;
60+
Serial.println("Disconnected from server");
61+
}
62+
};
63+
64+
bool connectToServer() {
65+
Serial.print("Forming a secure connection to ");
66+
Serial.println(myDevice->getAddress().toString().c_str());
67+
68+
BLEClient *pClient = BLEDevice::createClient();
69+
Serial.println(" - Created client");
70+
71+
pClient->setClientCallbacks(new MyClientCallback());
72+
73+
// Connect to the remote BLE Server.
74+
pClient->connect(myDevice);
75+
Serial.println(" - Connected to server");
76+
77+
// Set MTU to maximum for better performance
78+
pClient->setMTU(517);
79+
80+
// Obtain a reference to the service we are after in the remote BLE server.
81+
BLERemoteService *pRemoteService = pClient->getService(serviceUUID);
82+
if (pRemoteService == nullptr) {
83+
Serial.print("Failed to find our service UUID: ");
84+
Serial.println(serviceUUID.toString().c_str());
85+
pClient->disconnect();
86+
return false;
87+
}
88+
Serial.println(" - Found our service");
89+
90+
// Obtain a reference to the insecure characteristic
91+
pRemoteInsecureCharacteristic = pRemoteService->getCharacteristic(insecureCharUUID);
92+
if (pRemoteInsecureCharacteristic == nullptr) {
93+
Serial.print("Failed to find insecure characteristic UUID: ");
94+
Serial.println(insecureCharUUID.toString().c_str());
95+
pClient->disconnect();
96+
return false;
97+
}
98+
Serial.println(" - Found insecure characteristic");
99+
100+
// Obtain a reference to the secure characteristic
101+
pRemoteSecureCharacteristic = pRemoteService->getCharacteristic(secureCharUUID);
102+
if (pRemoteSecureCharacteristic == nullptr) {
103+
Serial.print("Failed to find secure characteristic UUID: ");
104+
Serial.println(secureCharUUID.toString().c_str());
105+
pClient->disconnect();
106+
return false;
107+
}
108+
Serial.println(" - Found secure characteristic");
109+
110+
// Read the value of the insecure characteristic (should work without authentication)
111+
if (pRemoteInsecureCharacteristic->canRead()) {
112+
String value = pRemoteInsecureCharacteristic->readValue();
113+
Serial.print("Insecure characteristic value: ");
114+
Serial.println(value.c_str());
115+
}
116+
117+
// For Bluedroid, we need to set the authentication request type for the secure characteristic
118+
// This is not needed for NimBLE and will be ignored.
119+
pRemoteSecureCharacteristic->setAuth(ESP_GATT_AUTH_REQ_NO_MITM);
120+
121+
// Try to read the secure characteristic (this will trigger security negotiation in NimBLE)
122+
if (pRemoteSecureCharacteristic->canRead()) {
123+
Serial.println("Attempting to read secure characteristic...");
124+
String value = pRemoteSecureCharacteristic->readValue();
125+
Serial.print("Secure characteristic value: ");
126+
Serial.println(value.c_str());
127+
}
128+
129+
// Register for notifications on both characteristics if they support it
130+
if (pRemoteInsecureCharacteristic->canNotify()) {
131+
pRemoteInsecureCharacteristic->registerForNotify(notifyCallback);
132+
Serial.println(" - Registered for insecure characteristic notifications");
133+
}
134+
135+
if (pRemoteSecureCharacteristic->canNotify()) {
136+
pRemoteSecureCharacteristic->registerForNotify(notifyCallback);
137+
Serial.println(" - Registered for secure characteristic notifications");
138+
}
139+
140+
connected = true;
141+
return true;
142+
}
143+
144+
/**
145+
* Scan for BLE servers and find the first one that advertises the service we are looking for.
146+
*/
147+
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
148+
/**
149+
* Called for each advertising BLE server.
150+
*/
151+
void onResult(BLEAdvertisedDevice advertisedDevice) {
152+
Serial.print("BLE Advertised Device found: ");
153+
Serial.println(advertisedDevice.toString().c_str());
154+
155+
// We have found a device, let us now see if it contains the service we are looking for.
156+
if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) {
157+
Serial.println("Found our secure server!");
158+
BLEDevice::getScan()->stop();
159+
myDevice = new BLEAdvertisedDevice(advertisedDevice);
160+
doConnect = true;
161+
doScan = true;
162+
}
163+
}
164+
};
165+
166+
void setup() {
167+
Serial.begin(115200);
168+
Serial.println("Starting Secure BLE Client application...");
169+
170+
BLEDevice::init("Secure BLE Client");
171+
172+
// Set up security with the same passkey as the server
173+
BLESecurity *pSecurity = new BLESecurity();
174+
175+
// Set security parameters
176+
// Default parameters:
177+
// - IO capability is set to NONE
178+
// - Initiator and responder key distribution flags are set to both encryption and identity keys.
179+
// - Passkey is set to BLE_SM_DEFAULT_PASSKEY (123456). It will warn if you don't change it.
180+
// - Max key size is set to 16 bytes
181+
182+
// Set the same static passkey as the server
183+
// The first argument defines if the passkey is static or random.
184+
// The second argument is the passkey (ignored when using a random passkey).
185+
pSecurity->setPassKey(true, CLIENT_PIN);
186+
187+
// Set authentication mode to match server requirements
188+
// Enable secure connection only for this example
189+
pSecurity->setAuthenticationMode(false, false, true);
190+
191+
// Retrieve a Scanner and set the callback we want to use to be informed when we
192+
// have detected a new device. Specify that we want active scanning and start the
193+
// scan to run for 5 seconds.
194+
BLEScan *pBLEScan = BLEDevice::getScan();
195+
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
196+
pBLEScan->setInterval(1349);
197+
pBLEScan->setWindow(449);
198+
pBLEScan->setActiveScan(true);
199+
pBLEScan->start(5, false);
200+
}
201+
202+
void loop() {
203+
// If the flag "doConnect" is true then we have scanned for and found the desired
204+
// BLE Server with which we wish to connect. Now we connect to it.
205+
if (doConnect == true) {
206+
if (connectToServer()) {
207+
Serial.println("We are now connected to the secure BLE Server.");
208+
} else {
209+
Serial.println("We have failed to connect to the server; there is nothing more we will do.");
210+
}
211+
doConnect = false;
212+
}
213+
214+
// If we are connected to a peer BLE Server, demonstrate secure communication
215+
if (connected) {
216+
// Write to the insecure characteristic
217+
String insecureValue = "Client time: " + String(millis() / 1000);
218+
if (pRemoteInsecureCharacteristic->canWrite()) {
219+
pRemoteInsecureCharacteristic->writeValue(insecureValue.c_str(), insecureValue.length());
220+
Serial.println("Wrote to insecure characteristic: " + insecureValue);
221+
}
222+
223+
// Write to the secure characteristic
224+
String secureValue = "Secure client time: " + String(millis() / 1000);
225+
if (pRemoteSecureCharacteristic->canWrite()) {
226+
pRemoteSecureCharacteristic->writeValue(secureValue.c_str(), secureValue.length());
227+
Serial.println("Wrote to secure characteristic: " + secureValue);
228+
}
229+
} else if (doScan) {
230+
// Restart scanning if we're disconnected
231+
BLEDevice::getScan()->start(0);
232+
}
233+
234+
delay(2000); // Delay 2 seconds between loops
235+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"fqbn_append": "PartitionScheme=huge_app",
3+
"requires": [
4+
"CONFIG_SOC_BLE_SUPPORTED=y"
5+
]
6+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
Secure server with static passkey
3+
4+
This example demonstrates how to create a secure BLE server with no
5+
IO capability using a static passkey.
6+
The server will accept connections from devices that have the same passkey set.
7+
The example passkey is set to 123456.
8+
The server will create a service and a secure and an insecure characteristic
9+
to be used as example.
10+
11+
This server is designed to be used with the Client_secure_static_passkey example.
12+
13+
Note that ESP32 uses Bluedroid by default and the other SoCs use NimBLE.
14+
Bluedroid initiates security on-connect, while NimBLE initiates security on-demand.
15+
This means that in NimBLE you can read the insecure characteristic without entering
16+
the passkey. This is not possible in Bluedroid.
17+
18+
Also, the SoC stores the authentication info in the NVS memory. After a successful
19+
connection it is possible that a passkey change will be ineffective.
20+
To avoid this, clear the memory of the SoC's between security tests.
21+
22+
Based on examples from Neil Kolban and h2zero.
23+
Created by lucasssvaz.
24+
*/
25+
26+
#include <BLEDevice.h>
27+
#include <BLEUtils.h>
28+
#include <BLEServer.h>
29+
#include <BLESecurity.h>
30+
#include <string>
31+
32+
// See the following for generating UUIDs:
33+
// https://www.uuidgenerator.net/
34+
35+
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
36+
#define Insecure_CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
37+
#define SECURE_CHARACTERISTIC_UUID "ff1d2614-e2d6-4c87-9154-6625d39ca7f8"
38+
39+
// This is an example passkey. You should use a different or random passkey.
40+
#define SERVER_PIN 123456
41+
42+
void setup() {
43+
Serial.begin(115200);
44+
Serial.println("Starting BLE work!");
45+
46+
Serial.print("Using BLE stack: ");
47+
Serial.println(BLEDevice::getBLEStackString());
48+
49+
BLEDevice::init("Secure BLE Server");
50+
51+
BLESecurity *pSecurity = new BLESecurity();
52+
53+
// Set security parameters
54+
// Default parameters:
55+
// - IO capability is set to NONE
56+
// - Initiator and responder key distribution flags are set to both encryption and identity keys.
57+
// - Passkey is set to BLE_SM_DEFAULT_PASSKEY (123456). It will warn if you don't change it.
58+
// - Max key size is set to 16 bytes
59+
60+
// Set static passkey
61+
// The first argument defines if the passkey is static or random.
62+
// The second argument is the passkey (ignored when using a random passkey).
63+
pSecurity->setPassKey(true, SERVER_PIN);
64+
65+
// Set authentication mode
66+
// Require secure connection only for this example
67+
pSecurity->setAuthenticationMode(false, false, true);
68+
69+
BLEServer *pServer = BLEDevice::createServer();
70+
pServer->advertiseOnDisconnect(true);
71+
72+
BLEService *pService = pServer->createService(SERVICE_UUID);
73+
74+
uint32_t insecure_properties = BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE;
75+
uint32_t secure_properties = insecure_properties;
76+
77+
// NimBLE uses properties to secure characteristics.
78+
// These special permission properties are not supported by Bluedroid and will be ignored.
79+
// This can be removed if only using Bluedroid (ESP32).
80+
// Check the BLECharacteristic.h file for more information.
81+
secure_properties |= BLECharacteristic::PROPERTY_READ_ENC | BLECharacteristic::PROPERTY_WRITE_ENC;
82+
83+
BLECharacteristic *pSecureCharacteristic = pService->createCharacteristic(SECURE_CHARACTERISTIC_UUID, secure_properties);
84+
BLECharacteristic *pInsecureCharacteristic = pService->createCharacteristic(Insecure_CHARACTERISTIC_UUID, insecure_properties);
85+
86+
// Bluedroid uses permissions to secure characteristics.
87+
// This is the same as using the properties above.
88+
// NimBLE does not use permissions and will ignore these calls.
89+
// This can be removed if only using NimBLE (any SoC except ESP32).
90+
pSecureCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED);
91+
pInsecureCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE);
92+
93+
// Set value for secure characteristic
94+
pSecureCharacteristic->setValue("Secure Hello World!");
95+
96+
// Set value for insecure characteristic
97+
// When using NimBLE you will be able to read this characteristic without entering the passkey.
98+
pInsecureCharacteristic->setValue("Insecure Hello World!");
99+
100+
pService->start();
101+
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
102+
pAdvertising->addServiceUUID(SERVICE_UUID);
103+
pAdvertising->setScanResponse(true);
104+
pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
105+
pAdvertising->setMinPreferred(0x12);
106+
BLEDevice::startAdvertising();
107+
Serial.println("Characteristic defined! Now you can read it in your phone!");
108+
}
109+
110+
void loop() {
111+
delay(2000);
112+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"fqbn_append": "PartitionScheme=huge_app",
3+
"requires": [
4+
"CONFIG_SOC_BLE_SUPPORTED=y"
5+
]
6+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /