Skip to content

Commit e23b225

Browse files
authored
feature(BLE): Update NimBLE, BleGattServer, and GfpsService to support Passkey Injection (#258)
* feat(ble): Support passkey injection via esp-nimble-cpp * Update `espp::BleGattServer` for breaking API changes to esp-nimble-cpp which add support for passkey injection * Update `espp::GfpsService` to use new esp-nimble-cpp APIs to perform passkey injection as part of the GFPS pairing / security process * update examples * submodule: update esp-nimble-cpp submodule for asynchronous pin injections
1 parent e8500c9 commit e23b225

File tree

8 files changed

+41
-46
lines changed

8 files changed

+41
-46
lines changed

components/ble_gatt_server/example/main/ble_gatt_server_example.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ extern "C" void app_main(void) {
2727
.disconnect_callback = [&](auto &conn_info,
2828
auto reason) { logger.info("Device disconnected: {}", reason); },
2929
.authentication_complete_callback =
30-
[&](NimBLEConnInfo &conn_info) { logger.info("Device authenticated"); },
30+
[&](const NimBLEConnInfo &conn_info) { logger.info("Device authenticated"); },
3131
// NOTE: this is optional, if you don't provide this callback, it will
3232
// perform the exactly function as below:
3333
.get_passkey_callback =
@@ -38,9 +38,10 @@ extern "C" void app_main(void) {
3838
// NOTE: this is optional, if you don't provide this callback, it will
3939
// perform the exactly function as below:
4040
.confirm_passkey_callback =
41-
[&](uint32_t passkey) {
41+
[&](const NimBLEConnInfo &conn_info, uint32_t passkey) {
4242
logger.info("Confirming passkey: {}", passkey);
43-
return passkey == NimBLEDevice::getSecurityPasskey();
43+
NimBLEDevice::injectConfirmPIN(conn_info,
44+
passkey == NimBLEDevice::getSecurityPasskey());
4445
},
4546
});
4647
ble_gatt_server.init(device_name);

components/ble_gatt_server/include/ble_gatt_server.hpp

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,16 @@ class BleGattServer : public BaseComponent {
6666

6767
/// @brief Callback for when a device completes authentication.
6868
/// @param conn_info The connection information for the device.
69-
typedef std::function<void(NimBLEConnInfo &)> authentication_complete_callback_t;
69+
typedef std::function<void(const NimBLEConnInfo &)> authentication_complete_callback_t;
7070

71-
/// @brief Callback for the passkey.
71+
/// @brief Callback to retrieve the passkey for the device.
7272
/// @return The passkey for the device.
7373
typedef std::function<uint32_t(void)> get_passkey_callback_t;
7474

7575
/// @brief Callback for confirming the passkey.
76+
/// @param conn_info The connection information for the device.
7677
/// @param passkey The passkey for the device.
77-
/// @return Whether the passkey is confirmed.
78-
typedef std::function<bool(uint32_t)> confirm_passkey_callback_t;
78+
typedef std::function<void(const NimBLEConnInfo &conn_info, uint32_t)> confirm_passkey_callback_t;
7979

8080
#if CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
8181
/// @brief Callback for when advertising is stopped.
@@ -131,11 +131,18 @@ class BleGattServer : public BaseComponent {
131131
authentication_complete_callback_t authentication_complete_callback =
132132
nullptr; ///< Callback for when a device completes authentication.
133133
get_passkey_callback_t get_passkey_callback =
134-
nullptr; ///< Callback for getting the passkey. If not set, will simply
135-
/// return NimBLEDevice::getSecurityPasskey().
134+
nullptr; ///< Callback for getting the passkey.
135+
/// @note If not provided, will simply return
136+
/// NimBLEDevice::getSecurityPasskey().
136137
confirm_passkey_callback_t confirm_passkey_callback =
137-
nullptr; ///< Callback for confirming the passkey. If not set, will
138-
/// simply compare the passkey to NimBLEDevice::getSecurityPasskey().
138+
nullptr; ///< Callback for confirming the passkey.
139+
/// @note Within this function or some point after this call,
140+
/// the user should call
141+
/// NimBLEDevice::injectConfirmPIN(conn_info, true/false) to
142+
/// confirm or reject the passkey.
143+
/// @note If not provided, will simply call
144+
/// NimBLEDevice::injectConfirmPIN(conn_info, passkey ==
145+
/// NimBLEDevice::getSecurityPasskey()).
139146
#if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
140147
advertisement_complete_callback_t advertisement_complete_callback =
141148
nullptr; ///< Callback for when advertising is complete.

components/ble_gatt_server/include/ble_gatt_server_callbacks.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ class BleGattServerCallbacks : public NimBLEServerCallbacks {
1515
public:
1616
virtual void onConnect(NimBLEServer *server, NimBLEConnInfo &conn_info) override;
1717
virtual void onDisconnect(NimBLEServer *server, NimBLEConnInfo &conn_info, int reason) override;
18-
virtual void onAuthenticationComplete(NimBLEConnInfo &conn_info) override;
19-
virtual uint32_t onPassKeyRequest() override;
20-
virtual bool onConfirmPIN(uint32_t pass_key) override;
18+
virtual void onAuthenticationComplete(const NimBLEConnInfo &conn_info) override;
19+
virtual uint32_t onPassKeyDisplay() override;
20+
virtual void onConfirmPIN(const NimBLEConnInfo &conn_info, uint32_t pass_key) override;
2121

2222
protected:
2323
friend class BleGattServer;

components/ble_gatt_server/src/ble_gatt_server_callbacks.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,23 +52,23 @@ void BleGattServerCallbacks::onDisconnect(NimBLEServer *server, NimBLEConnInfo &
5252
}
5353
}
5454

55-
void BleGattServerCallbacks::onAuthenticationComplete(NimBLEConnInfo &conn_info) {
55+
void BleGattServerCallbacks::onAuthenticationComplete(const NimBLEConnInfo &conn_info) {
5656
if (server_ && server_->callbacks_.authentication_complete_callback) {
5757
server_->callbacks_.authentication_complete_callback(conn_info);
5858
}
5959
}
60-
uint32_t BleGattServerCallbacks::onPassKeyRequest() {
60+
uint32_t BleGattServerCallbacks::onPassKeyDisplay() {
6161
if (server_ && server_->callbacks_.get_passkey_callback) {
6262
return server_->callbacks_.get_passkey_callback();
6363
} else {
6464
return NimBLEDevice::getSecurityPasskey();
6565
}
6666
}
67-
bool BleGattServerCallbacks::onConfirmPIN(uint32_t pass_key) {
67+
void BleGattServerCallbacks::onConfirmPIN(const NimBLEConnInfo &conn_info, uint32_t pass_key) {
6868
if (server_ && server_->callbacks_.confirm_passkey_callback) {
69-
return server_->callbacks_.confirm_passkey_callback(pass_key);
69+
server_->callbacks_.confirm_passkey_callback(conn_info, pass_key);
7070
} else {
71-
return pass_key == NimBLEDevice::getSecurityPasskey();
71+
NimBLEDevice::injectConfirmPIN(conn_info, pass_key == NimBLEDevice::getSecurityPasskey());
7272
}
7373
}
7474

components/gfps_service/example/main/gfps_service_example.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,13 @@ extern "C" void app_main(void) {
2525
.disconnect_callback = [&](auto &conn_info,
2626
auto reason) { logger.info("Device disconnected: {}", reason); },
2727
.authentication_complete_callback =
28-
[&](NimBLEConnInfo &conn_info) { logger.info("Device authenticated"); },
28+
[&](const NimBLEConnInfo &conn_info) { logger.info("Device authenticated"); },
2929
.get_passkey_callback = [&]() { return NimBLEDevice::getSecurityPasskey(); },
3030
.confirm_passkey_callback =
31-
[&](uint32_t passkey) {
32-
// NOTE: right now we have no way to do asynchronous passkey injection
33-
// (see: https://github.com/h2zero/esp-nimble-cpp/pull/117), so we
34-
// have to blindly return true here AND set the passkey since it will
35-
// be used by the GFPS BLE stack through the side channel.
31+
[&](const NimBLEConnInfo &conn_info, uint32_t passkey) {
32+
// set the passkey here, so that GFPS can later compare against it
33+
// and inject confirmation/rejection
3634
NimBLEDevice::setSecurityPasskey(passkey);
37-
return true;
3835
},
3936
});
4037
ble_gatt_server.init(device_name);

components/gfps_service/src/nearby_ble.cpp

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,6 @@ int espp::gfps::ble_gap_event_handler(ble_gap_event *event, void *arg) {
7979
NimBLEDevice::setSecurityIOCap(BLE_HS_IO_NO_INPUT_OUTPUT);
8080
break;
8181
}
82-
case BLE_GAP_EVENT_PASSKEY_ACTION: {
83-
logger.info("BLE_GAP_EVENT_PASSKEY_ACTION");
84-
if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
85-
// this is the kind of event that GFPS should expect but for some reason
86-
// it doesn't seem to be triggering (no BLE_GAP_EVENT_PASSKEY_ACTION
87-
// events are being triggered, only the ones in the NimBLEServer class are
88-
// triggered...)
89-
}
90-
break;
91-
}
9282
default:
9383
break;
9484
}
@@ -273,12 +263,11 @@ void nearby_platform_SetRemotePasskey(uint32_t passkey) {
273263
} else {
274264
logger.error("Declining pairing request, passkey does not match");
275265
}
276-
// TODO: in the original implementation we set the pairing success/failure
277-
// here, but our current esp-nimble-cpp NimBLEServer doesn't have a
278-
// mechanism right now which would allow us to respond success/failure here
279-
// without responding within the onConfirmPIN callback.
280-
logger.info("TODO: implement pairing success/failure here after esp-nimble-ble adds support for "
281-
"asynchronous pin injections");
266+
// get the connection info for the remote party (assume only one, so first
267+
// index)
268+
auto conn_info = NimBLEDevice::getServer()->getPeerInfo(0);
269+
// Now actually respond to the pairing request
270+
NimBLEDevice::injectConfirmPIN(conn_info, accept);
282271
#endif // CONFIG_BT_NIMBLE_ENABLED
283272
}
284273

components/hid_service/example/main/hid_service_example.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ extern "C" void app_main(void) {
2727
.disconnect_callback = [&](auto &conn_info,
2828
auto reason) { logger.info("Device disconnected: {}", reason); },
2929
.authentication_complete_callback =
30-
[&](NimBLEConnInfo &conn_info) { logger.info("Device authenticated"); },
30+
[&](const NimBLEConnInfo &conn_info) { logger.info("Device authenticated"); },
3131
// NOTE: this is optional, if you don't provide this callback, it will
3232
// perform the exactly function as below:
3333
.get_passkey_callback =
@@ -38,9 +38,10 @@ extern "C" void app_main(void) {
3838
// NOTE: this is optional, if you don't provide this callback, it will
3939
// perform the exactly function as below:
4040
.confirm_passkey_callback =
41-
[&](uint32_t passkey) {
41+
[&](const NimBLEConnInfo &conn_info, uint32_t passkey) {
4242
logger.info("Confirming passkey: {}", passkey);
43-
return passkey == NimBLEDevice::getSecurityPasskey();
43+
NimBLEDevice::injectConfirmPIN(conn_info,
44+
passkey == NimBLEDevice::getSecurityPasskey());
4445
},
4546
});
4647
ble_gatt_server.init(device_name);

0 commit comments

Comments
 (0)