h2zero / NimBLE-Arduino

A fork of the NimBLE library structured for compilation with Arduino, for use with ESP32, nRF5x.
https://h2zero.github.io/NimBLE-Arduino/
Apache License 2.0
672 stars 138 forks source link

All ESP32 Nimble peripherals have the same IRK when using RPA? #539

Open jangellx opened 1 year ago

jangellx commented 1 year ago

I've hit a problem where I am trying to have an iPhone connect to multiple ESP32 NimBLE devices acting as peripherals using RPA and encryption. All ESP32s are running the same Arduino sketch.

This is the authentication I'm using on the ESP32:

NimBLEDevice::setSecurityAuth(  true, true, true);       // Bonding, man-in-the-middle protection, secure connection pairing
NimBLEDevice::setSecurityIOCap( BLE_HS_IO_DISPLAY_ONLY );    // We have a display for the passcode
NimBLEDevice::setOwnAddrType(   BLE_OWN_ADDR_RANDOM, false );    // Random Private Address support, as required for iPhone bonding

I've found that the iPhone can connect and bond to the first device, and everything works. I can then bond to the second ESP32, and everything works. They both work as long as the iPhone remains connected.

The problem comes when I disconnect and try to reconnect. I can only connect to the most recently bonded ESP32. Attempting to reconnect to the first bonded ESP32 fails with an authentication error. If I boot up a third ESP32, the iPhone will try to reconnect to that one even though it isn't bonded with it and has never seen it before, and will fail with an authentication error.

A significant amount of Googling eventually led me to this post: https://github.com/espressif/esp-nimble/issues/24 It suggests that the problem is that all ESP32 NimBLE devices have the same Identity Resolving Key.

As I understand it, this means that the iPhone is effectively overwriting the encryption keys it stored from Device 1 with those of the newly-bonded Device 2, because it thinks they're the same device because the IRKs are the same. When Device 3 is booted, the iPhone thinks it's Device 1 as well.

The above link also notes that while there is a private API function to change the IRK, doing so erases all bonded devices, meaning that every time you restart the ESP32 you'll have to pair everything again.

The link also points to this patch, which provides a way to use a custom function to set the default IRK without erasing the bonding information. https://github.com/Blockstream/Jade/commit/2227d290f474447782b0703aca16cfc631ff8964 IMO, the IRK should be randomly generated on startup if there are no bonded devices, but I may not understand the specifics of how BLE works here.

As it stands, I do not believe it is possible to have a single device like an iPhone connect to two or more ESP32 NimBLE devices at the same time due to the IRK conflicts, which is a rather significant limitation.

I've also come across posts like this, but it's for the core ESP32 NimBLE implementation, not the Arduino one, and it's not clear how I could apply it here: https://esp32.com/viewtopic.php?t=14966

Does Arduino NimBLE need this patch, or some other method to improve IRK handling to resolve this? Or is there simply something that I'm doing wrong?

Thanks!

h2zero commented 1 year ago

Yes, the issue in https://github.com/espressif/esp-nimble/issues/24 applies here as well sadly. Until this is fixed upstream it will be a problem sadly. There is a patch available in that issue thread that my work if you want to try it.

jangellx commented 1 year ago

Thanks -- I'm just glad to know that I'm not doing something wrong. I'll give the patch a try.

I have another weird issue where I stop being able to connect to the ESP32 after some time, which varies from minutes to hours, and seems related to the phone moving in and out of Bluetooth range, or being right at the edge of it. I "solved" this by rebooting the ESP32 a short while after the last disconnect, but that's awful hacky. I'd open an issue on it, but while it's reasonably common, it's extremely difficult to reproduce intentionally, so there's not much useful information to put in an issue.

Anyway, I'll keep an eye out for Espresif or Apache or whoever to actually fix the IRK. Thanks again!

h2zero commented 1 month ago

I know this is old but have you been able to resolve this at all?

jangellx commented 1 month ago

Sorry, I haven't been able to work on this project in a while, and when I have I've just been limping along with one IRK for now. I keep meaning back to, but get distracted by other projects.

Thanks to your prompt, I checked and saw that https://github.com/espressif/esp-nimble/issues/24 is marked as closed as of February, so it sounds like nimble-1.5.0-idf has the fix. I have no idea what would be involved in updating NimBLE-Arduino to use that, though.

h2zero commented 1 month ago

@jangellx Take a look at #679

jangellx commented 1 month ago

Ah, well that seems like it would do the trick! Thanks!