-
Pairing and bonding are forced with the request from the master (AuthReq with the bonding flag set to 0x01) but the Pixl doesn't reply with LESC or MITM as per the
NRF.setSecurity
configuration. In fact it adheres exactly to the definition just above the links you provide in the bluetooth.c code:static ble_gap_sec_params_t get_gap_sec_params() { ble_gap_sec_params_t sec_param; memset(&sec_param, 0, sizeof(ble_gap_sec_params_t)); // Security parameters to be used for all security procedures. // All set to 0 beforehand, so sec_param.bond = 1; /**< Perform bonding. */ //sec_param.mitm = 0; /**< Man In The Middle protection not required. */ //sec_param.lesc = 0; /**< LE Secure Connections not enabled. */ //sec_param.keypress = 0; /**< Keypress notifications not enabled. */ sec_param.io_caps = BLE_GAP_IO_CAPS_NONE; /**< No I/O capabilities. */ //sec_param.oob = 0; /**< Out Of Band data not available. */ sec_param.min_key_size = 7; /**< Minimum encryption key size. */ sec_param.max_key_size = 16;
This is the exact configuration proposed by the Pixl to the central as seen in the trace.
I haven't got a build environment set up - any chance you could supply a build with the following parameter definitions for me to test in case it's the update process that isn't working?
static ble_gap_sec_params_t get_gap_sec_params() { ble_gap_sec_params_t sec_param; memset(&sec_param, 0, sizeof(ble_gap_sec_params_t)); // Security parameters to be used for all security procedures. // All set to 0 beforehand, so sec_param.bond = 1; /**< Perform bonding. */ sec_param.mitm = 1; /**< Man In The Middle protection required. */ sec_param.lesc = 1; /**< LE Secure Connections enabled. */ //sec_param.keypress = 0; /**< Keypress notifications not enabled. */ sec_param.io_caps = BLE_GAP_IO_CAPS_NONE; /**< No I/O capabilities. */ //sec_param.oob = 0; /**< Out Of Band data not available. */ sec_param.min_key_size = 7; /**< Minimum encryption key size. */ sec_param.max_key_size = 16;
-
Hi @Vlad,
Bluez was used in Android before 4.2 but now it uses Bluedroid as I understand. In any case, I repeated the test with iOS which definitely does not use Bluez as I couldn't get the it working as an alternative to CoreBlueTooth.
There is no way to manually(or programatically - the system decides) initiate bonding on iOS (in Android there invariably is but I'm only using that as a control for iOS, not developing on it).
It does appear that it is not related to the characteristic security as it is the system level that fails to respond with the appropriate Auth Response (the Insufficient Auth message does not contain any info on the required Auth - that is the responsibility of the AuthReq sequence). Looking to @Gordon for an update on the
NRF.setSecurity
configs not working.I still think having a simply security yes/no at the characteristic level is the right approach. If the settings there are declarative (cannot influence the bonding) because the system handles the bonding, having options that have no effect will result in failures where there are mismatches.
-
Hi Vlad,
Secure Connection is LESC - it's the 5th bit in the AuthReq byte (see screenshot). I'm not using Bluez and peripheral advertisement packets do not include anything about the security capabilities. But, yes, this is the security association desired by the central (Android and iOS).
So here the central is requesting Bonding, MITM and LESC. The response from the Pixl only indicates Bonding (screenshot is of the Pixl response), so it proceeds without the other two.
I have re-run with the following configuration to exactly the same result - no success.
NRF.setSecurity({lesc: 1}); NRF.setServices({ 0xBCDE : { 0xABCD : { value : "Hello", // optional maxLen : 5, // optional (otherwise is length of initial value) readable : true, // optional, default is false writable : true, // optional, default is false // notify : true, // optional, default is false security: { // optional read: { // optional encrypted: false, // optional, default is false mitm: false, // optional, default is false lesc: false, // optional, default is false signed: false // optional, default is false }, write: { // optional encrypted: false, // optional, default is false mitm: false, // optional, default is false lesc: true, // optional, default is false signed: false // optional, default is false } }, onWrite : function(evt) { // optional print("Got ", evt.data); // an ArrayBuffer } } // more characteristics allowed } // more services allowed });
-
Hi Gordon,
Yes, I've reset on both sides (on Pixl, wiping the flash and hard booting before pushing a new config; on the phones, deleting the pairing and powering bluetooth off/on). It's usually pretty clear in the WireShark trace when an existing pairing relationship is present so I'm confident it's forgotten.Do I understand you correctly that the security configuration in the characteristic is passive (i.e. not used in determining the bonding requirements)? If that's the case then having the possibility to indicate different sets of requirements per characteristics seems over the top as it can never influence the setup.
I've tried using
NRF.setSecurity({passkey:"123456", mitm:1, display:1});
and combinations thereof to no avail. As I mentioned it doesn't even appear in adump()
once it is pushed so I'm not sure what's happening. -
Hi @Vlad,
I assumed that this was to indicate capabilities as is with network protocols - my mistake. I've re-run with this config though and get exactly the same result:
security: { // optional read: { // optional encrypted: true, // optional, default is false mitm: true, // optional, default is false lesc: false, // optional, default is false signed: false // optional, default is false },
The Encrypted and MITM options are ignored.
The iPhone and Android indicate support for LESC with MITM (see this article for a discussion of the weakness of LESC without MITM Protection - https://devzone.nordicsemi.com/f/nordic-q-a/35856/questions-about-lesc-mitm-and-passkey/138216#138216 .)
I had also assumed that, as this is in the Espruino API documentation, the Pixl supported the options available. @Gordon can you comment on the features that should work with the Pixl?
As to the comment on the use case, I can agree that a device could be required to support protected and un-protected characteristics. So the be able to say per characteristic and per action (read/write) whether it is secure or not seems like a great feature to have.
However, this still seems to be something that should be device wide, not per characteristic. It would not work to require encrypted+mitm for one characteristic and LESC for another - the bonding process can only result in one outcome.
On the issue of reading encrypted packets, any device that is eavesdropping during the bonding process can get the keys and decrypt the packets, especially if it is LESC without a Random PIN and MITM. Even with MITM protection and a static PIN, the sniffer can easily decode the packets (you can see the passkey/OOB Key field in the screenshot I sent earlier).
-
I'm having some problems with this in practice using 2v02. What I'm seeing with a Pixl as a peripheral is that the it (the Pixl) ignores the security values in the services when negotiating with the central. It manages to bond with the central but without the security association required by the characteristic. As a result, subsequent reads or writes fail due to insufficient authentication.
Here are the test configs and traces. The JS is below is the only config on the Pixl and I hard reset between test. I also delete bonding information and turn Bluetooth off/on to reset the phones before each test.
Config 1: No security on read, security on write.
NRF.setServices({ 0xBCDE : { 0xABCD : { value : "Hello", // optional maxLen : 5, // optional (otherwise is length of initial value) readable : true, // optional, default is false writable : true, // optional, default is false security: { // optional read: { // optional encrypted: false, // optional, default is false mitm: false, // optional, default is false lesc: false, // optional, default is false signed: false // optional, default is false }, write: { // optional encrypted: true, // optional, default is false mitm: true, // optional, default is false lesc: true, // optional, default is false signed: false // optional, default is false } }, onWrite : function(evt) { // optional print("Got ", evt.data); // an ArrayBuffer } } // more characteristics allowed } // more services allowed });
I tested with both Android (Oreo 8.1) and iOS (12.2) and had the same results. When trying to write, they get a failure due to insufficient authorisation (as you would expect) and so requests to bond (SecureConnection, MITM & Bonding parameters). The Pixl replies omitting MITM and SecureConnection and the bonding completes without these.
Another write request is then attempted but again fails due to insufficient auth. The WireShark trace for the Android test is included below. Read works fine before and after bonding.
Config 2: No security on write, security on read.
NRF.setServices({ 0xBCDE : { 0xABCD : { value : "Hello", // optional maxLen : 5, // optional (otherwise is length of initial value) readable : true, // optional, default is false writable : true, // optional, default is false // notify : true, // optional, default is false security: { // optional read: { // optional encrypted: true, // optional, default is false mitm: true, // optional, default is false lesc: true, // optional, default is false signed: false // optional, default is false }, write: { // optional encrypted: false, // optional, default is false mitm: false, // optional, default is false lesc: false, // optional, default is false signed: false // optional, default is false } }, onWrite : function(evt) { // optional print("Got ", evt.data); // an ArrayBuffer } } // more characteristics allowed } // more services allowed });
With this config, the write works without security and the read fails (as expected). This failure leads to bonding but then fails again due to the insufficient authentication. The trace for this is also below. I include a screenshot of the negotiation trace for ease of access to show the Pixl failing to match the Pairing Request parameters.
I've also tried adding
NRF.setSecurity({passkey:"123456", mitm:1, display:1});
but it doesn't make any difference. In fact it doesn't seem to register in the config at all after being pushed to the Pixl (see screen shot of IDE).
I believe that the Pixl is expected to propose it's security parameters in the Pairing Response frame. Having different potential security associations for each characteristic seems like a problematic approach to me. The bonding is for the device and must converge on a single common set of security associations so you couldn't have one characteristic that requires MITM and another that doesn't want it - they either all get it or none do.
It might work in cases where the device only pairs (effectively forgetting the security association after each connection), but that would still pose a problem until the connection is torn down. I think the security association needs to be at a system level. Each characteristic can then either implement security or not, which works fine as the traces show.
Edit 1: Just to confirm, if I leave the MITM and LESC set to false, everything works fine.
-
This is really difficult to pin down. It's occurs when an NRF.updateServices is called while there is a queued BLE restart. It doesn't seem to be a problem with one or two characteristics, but the heavier the load the more it occurs. I've tried moving the updates out of init() but it seems not to make a difference.
-
-
Sorry, been trying to recreate it for the last hour but can't. This is strange as I was even resorting to erasing entirely the flash before loading code to ensure there was no residual old code interfering with the setup and still I was getting the multiple identical services and the BLE Data Size error.
I've removed the NRF.setServices({}) from init() and will monitor to see if it happens again. -
Here's a complication to the issue that I stumbled into. I'm saving code to RAM (Pixl 2v01) and in the code I have block setting the NRF services (with 4 characteristics using the short hex UUIDs), just as in the example in the API documentation. I then update the services when a button is pressed using NRF.updateServices which works as expected, until the device is restarted.
On restarting it adds a second instance of the same service (as seen by nRF Connect and LightBlue). Restarting again (e.g. by running a load() command) I get a third instance of the same service at which point I'm running into BLE Data Size errors when I try to update the service.I've resolved it by putting a NRF.setServices({}) in the init() function, blanking the services and setting the services again right afterwards but it seems wrong that the peripheral can advertise multiple instances of the same service (same name, same characteristics). It also makes updating the code tricky as you have to make sure that there is no definition of the services in RAM that might be appended to the new code when it is saved.
I can understand that where you want to change the characteristics of a service you need to delete and re-instantiate it but should there not be a check that prevents the same service being advertised multiple times?
-
Sorry about the delay in replying and thanks for the pointer to GitHub. I'll work a bit more on it next week when hopefully I'll have a bluetooth dongle to sniff the packets with WireShark.
iOS takes the approach that it's up to the peripheral to decide if it wants to implement any security - there's no way to force it from that side. -
Thanks for this post. I was also struggling to see the new services I was adding until I read this a second time and 'saw' the iOS qualifier. I was so focused on the Pixl that I forgot about the iPhone's bluetooth 'memory'. My bluetooth scanner (nRF Connect) is also on the phone so it didn't 'see' any change and kept reporting the service I deleted.
-
-
-
-
I managed to corrupt the flash on my Pixl by pulling the power during a save (got too careless/impatient). I've managed to connect with NRF Toolbox and update the firmware, so DFU works fine. The Pixl boots and shows the Pixl.js v2.01 screen with the MAC and then nothing. The device is not advertised after booting.
Is there any way to wipe the flash or otherwise recover the situation?
OK, thanks. I'll give it a go next week when I get some time.