More secure Bluetooth LE pairing method

eriksl
Posts: 116
Joined: Thu Dec 14, 2023 3:23 pm
Location: Netherlands

Re: More secure Bluetooth LE pairing method

Postby eriksl » Thu Jul 11, 2024 7:51 am

As I said, there actually is more or less secure method of pairing in Nimble and it works too (tested myself).

The problem is that a "password" consisting of only 5 numeric digits is far too weak to be secure.

There is a more secure way of pairing, using a passphrase, but Nimble doesn't implement it.

I get the impression you're confusing pairing with connecting.

Pairing is the act of authentication both ways. If the pairing has succeeded, a connection can be made. On your headphone this occurs transparently, but here you need to do both steps explictly.

The result of the pairing can be stored for a future connection, it's called a bond. In the idf configuration you can select bonds to be saved to NVR and how many of them. For me one will be sufficient, but you can choose to store more of them. If you get to the point where you need to pair/bond a new device and all slots are used, no problem, the new one will be stored and the oldest one will be discarded.

If you're connecting and there is a bond available, this will be used and no pairing is required. If there is no bond available, pairing is required. Normally this procedure will be done automatically by the client. When pairing is required and the peripheral requires a pin code, the client will ask the user for one.

So in my case, I only need to pair once to all my devices. After that they're open for business. As the pairing isn't fully secure (too weak password), I require the client to authenticate itself further after each connection is made, so that's completely isolated from the bond.

The amount of allowed connections in parallel (as opposed to bonds, as I described above) is also configurable. I think in most cases one simultaneous connection works best. That also allows for all other active connections to be closed when a new connection comes in, ensuring your device is always ready for action (not being hung up by some dodgy client).

BTW I already complained about the lack of documentation regarding Nimble and the ESP32-S3 specifics. There is no Nimble documentation from Espressif and the documentation from the Nimble project itself is very poor. The supplied examples only cover very simple cases. The documentation of the IDF Nimble component configuration options is also very poor, sometimes completely non-existent. Maybe the Bluedroid documentation is better, but I thought it would be overkill as the S3 doesn't support Bluetooth Classic anyway (which I had to find out the hard way, through unclear crashes).

MikeCode
Posts: 14
Joined: Wed Apr 20, 2022 10:25 am

Re: More secure Bluetooth LE pairing method

Postby MikeCode » Fri Jul 12, 2024 6:25 am

Thank you, eriksl, that makes a lot of sense!

So wouldn't it be possible to allow pairing only for 30 seconds when pressing a button? So that a 5 digit pin would be secure enough if you only have 30 seconds to pair?

An once a device is paired, you disable pairing except when you press the button again?

So the procedure would be:
1. Press button to enable pairing for 30 seconds
2. Pair the ESP32-S3 with your phone
3. Bond the phone with the ESP32-S3
4. Disable pairing until you press the button

So the question is, how can I disable pairing in Nimble and only enable it, when pressing a button?

And is it still possible for an already bonded device to connect if pairing is disabled?

Another problem is, that in the example code it says, that bonding is not persistent across reboots:
https://github.com/espressif/esp-idf/tr ... le/bleprph
"NVS support is not yet integrated to bonding. So, for now, bonding is not persistent across reboot."

So this still has to be solved to make this method work across reboots.

eriksl
Posts: 116
Joined: Thu Dec 14, 2023 3:23 pm
Location: Netherlands

Re: More secure Bluetooth LE pairing method

Postby eriksl » Fri Jul 12, 2024 6:47 am

The remark in the example is obsolete. I can confirm that bonding does survive a reboot. The information is stored in the NVS partition (you will need to have one and initialise it properly).

Don't you just want to disable bluetooth completely and only enable it when the button is pressed?

MikeCode
Posts: 14
Joined: Wed Apr 20, 2022 10:25 am

Re: More secure Bluetooth LE pairing method

Postby MikeCode » Fri Jul 12, 2024 7:07 am

Good to hear that storing bonding in NVS is already working.

I don't want to disable bluetooth completely as it should be available for an already bonded device at any time.

It should not be possible for any other device to connect to the ESP32-S3 without pressing the pairing-button first.

An already bonded device should still be possible to communicate with the ESP32-S3 at any time.

This is how security works with my bluetooth speaker. You have to press the paring button first and have 30 seconds to pair your phone with the speaker. Once paired the phone can always connect to the speaker, but no other device can pair with the speaker, unless you press the pairing button again.

eriksl
Posts: 116
Joined: Thu Dec 14, 2023 3:23 pm
Location: Netherlands

Re: More secure Bluetooth LE pairing method

Postby eriksl » Fri Jul 12, 2024 7:12 am

Ah ok, I understand.

BTW you need to configure (idf.py menuconfig) how many bonds are saved across reboots.

In that case I think it's easiest to not disable pairing at all (which I honestly would not know how to do), but to simply make the pairing process fail if not within the button timespan. Nimble will call an event handler (your code) for a lot of GAP (service discovery) and GATT (service handling) events, pairing is one of them, and afaik, you can return a non-zero value to signify the pairing failed.

That's all I know, given I have taken another approach, where pairing is always enabled, connecting is always enabled, just for actual communication you need an extra key.

MikeCode
Posts: 14
Joined: Wed Apr 20, 2022 10:25 am

Re: More secure Bluetooth LE pairing method

Postby MikeCode » Fri Jul 12, 2024 8:40 am

Thanks I've tried bonding with the ESP32-S3 using the
https://www.nordicsemi.com/Products/Dev ... for-mobile
app.

The app shows that the ESP32-S3 was bonded, but the output of ESP32-S3 sill shows bonded=0:
I (173106) NimBLE: connection established; status=0
I (173106) NimBLE: handle=1 our_ota_addr_type=0 our_ota_addr=
I (173106) NimBLE: 60:55:f9:f5:c9:3e
I (173116) NimBLE: our_id_addr_type=0 our_id_addr=
I (173116) NimBLE: 60:55:f9:f5:c9:3e
I (173126) NimBLE: peer_ota_addr_type=1 peer_ota_addr=
I (173126) NimBLE: 72:2c:6d:91:4a:2b
I (173136) NimBLE: peer_id_addr_type=1 peer_id_addr=
I (173136) NimBLE: 72:2c:6d:91:4a:2b
I (173146) NimBLE: conn_itvl=39 conn_latency=0 supervision_timeout=500 encrypted=0 authenticated=0 bonded=0

I also could not find a pairing event in the Nimble source code.

The only event I could find was: BLE_GAP_EVENT_REPEAT_PAIRING but that never gets called.

Additionally it seems that the nordic app is not pairing with the ESP32-S3 at all but it is just "connecting".

Maybe I'm connecting to the ESP32-S3 in the so called "Just Works" mode without encryption, so that no pairing is needed?

Overall the whole Nimble security process is not easy to understand.

eriksl
Posts: 116
Joined: Thu Dec 14, 2023 3:23 pm
Location: Netherlands

Re: More secure Bluetooth LE pairing method

Postby eriksl » Fri Jul 12, 2024 8:58 am

The repeat pairing event is only called in some situations. If the other party is known but the authentication information is gone.

Which pairing mode is acceptable is something you decide. If you use a button, the "just works" method may be acceptable, but I don't think it's wise here.

This is what I did:

Code: Select all

    ble_hs_cfg.sm_io_cap = BLE_HS_IO_DISPLAY_ONLY;
    ble_hs_cfg.sm_bonding = 1;
    ble_hs_cfg.sm_mitm = 1;
    ble_hs_cfg.sm_sc = 1;
    ble_hs_cfg.sm_our_key_dist = BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID;
    ble_hs_cfg.sm_their_key_dist = BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID;
In the init code. This makes the event handler to be called for entry of the pin code:

Code: Select all

        case(BLE_GAP_EVENT_PASSKEY_ACTION):
        {
            log("bt: GAP EVENT passkey action");

             if(event->passkey.params.action == BLE_SM_IOACT_DISP)
             {
                struct ble_sm_io pkey = {0};

                pkey.action = BLE_SM_IOACT_DISP;
                pkey.passkey = bt_pair_pin;

                if((rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey)) != 0)
                    log_format("bt: passkey error: ble_sm_inject_io result: %d", rc);
            }
            else
                log_format("bt: passkey: unknown op: %d", event->passkey.params.action);

            //ble_gap_terminate(event->connect.conn_handle, BLE_ERR_CONN_LIMIT); // FIXME does this need to be here?

            break;
        }
I think you could sabotage the process here (when pairing is not appropriate) by either not calling ble_sm_inject_io or by return non-zero from the event handler. You'd have to try.

MikeCode
Posts: 14
Joined: Wed Apr 20, 2022 10:25 am

Re: More secure Bluetooth LE pairing method

Postby MikeCode » Mon Jul 15, 2024 9:57 am

I've configured ble_hs_cfg with your settings, and now I'm asked to enter a PIN when I'm training to bond with the ESP32-S3.

BUT the strange thing is, I'm still able to connect to the ESP32-S3 (without bonding) and I can use the Service-Characteristics (read/write values) of the ESP32-S3 through the Nordic-nRF Connect app withouth ever being asked for the PIN.

So it seems, that connecting and accessing the ESP32-S3 is still possible without entering a PIN. The PIN is only needed when bonding with the device.

This does not seem like the expected behaviour. I'm I missing something here?

Is here a setting to allow access to Characteristics only when bonded?

MikeCode
Posts: 14
Joined: Wed Apr 20, 2022 10:25 am

Re: More secure Bluetooth LE pairing method

Postby MikeCode » Tue Jul 16, 2024 11:23 am

Ok, i found a way to restrict access to characteristics only for paired devices:

You have to set the characteristics flags to:
BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC
(you have to use BOTH to make it work)

One Question still remains:
You said that you allow every device to connect to you ESP32 and use your one encryption method afterwards.

But if someone else is connecting to your ESP32 wouldn't this prevent you from connecting? (with the bleperph only one connection is possible at a time)

So even if this unauthorized person cannot control your ESP32 it still can block you from connecting to your own device?

eriksl
Posts: 116
Joined: Thu Dec 14, 2023 3:23 pm
Location: Netherlands

Re: More secure Bluetooth LE pairing method

Postby eriksl » Thu Aug 08, 2024 10:33 am

Yes a DoS attack would be possible, but that's something I worry about less. It's easy for me to reset the device and simply connect first after reset. The only thing I can't do, is gain physical access, so something like USB access isn't a possibility (otherwise it would be great).

BTW you can configure Nimble to allow more than one connection. But it won't fully solve this issue and also it will make everything a lot more complex, as you need to maintain the information of all parallel connections separate.

Who is online

Users browsing this forum: MicroController and 131 guests