Restricting some GATT characteristics to a bonded device

Hi,

I'm implementing a BLE GATT peripheral that has no display but it does have a button.

I'd like to make some characteristics only available to devices that are BONDED but all of the docs I've read so far talk about pairing, or what I think are equivalent words like "encryption" or "authentication".

E.g. I've found flags like BT_GATT_PERM_WRITE_LESC|BT_GATT_PERM_WRITE_ENCRYPT and some doc about whitelisting, but the descriptions of both suggest they're only looking at the current connection, not whether the connection is to a device from the bond list. And I can't add BT_GATT_PERM_WRITE_AUTHEN because it's got no display.

Anyone have any pointers how to do this? Or am I just misunderstanding the doc?

Seems like I should say why, in case there's another way to do a similar thing.

I don't actually care about MITM for this - it's a wearable and I really only want to make it harder for some random to flatten the battery. Sure MITM could do that but it'd be noticed and they'd have to follow the person constantly.

So really I only care whether whether I'm currently connected to the phone (or potentially MITM) the nRF was bonded to. Plan is to use JustWorks but only allow a bonding to occur for a short period after the button was pressed.

But let's say I've already been through the bonding process with some phone but that phone's now out of range and disconnected. If another device comes along I believe it could initiate a pair and create a link with encryption (but not authentication) but stop before bonding without the user even knowing it happened. It sounds like this would be a gap in the security, even though it doesn't seem actual phones do this.

Thanks,

Bill

Parents
  • Hi Hieu,

    Thanks for the response. Yes I did wonder if I was overthinking this, seems like something that should be solved already.

    I am a little confused why you don't limit connection establishment and pairing entirely, but just bonding.

    Well I thought that would also prevent a previously bonded device from reconnecting, e.g. if it was out of range and comes back?
    This is why I was looking at whitelisting, but best I can tell that's only looking at the MAC, which is spoofable (IRK doesn't prevent that).

    Definitely open to trying ideas like this though - what is the usual way to block all pairing?
    E.g. I've been experimenting with 
    struct bt_conn_auth_cb but not sure which is the best option.

    Can you not also setup the device to ask for user's explicit permission before accepting a pairing request?

    Well there's no display or other output that seems usable to inform the user that there's a pairing request. 
    So ideally I'd like to let the bonded device back in without user interaction.

    try using the read and write callbacks

    Yeah, I wondered if there might be a way to check the connection state (is it bonded) during the callback, I'll look into it some more.

  • Hi Bill,

    BillB said:
    Well I thought that would also prevent a previously bonded device from reconnecting, e.g. if it was out of range and comes back?
    This is why I was looking at whitelisting, but best I can tell that's only looking at the MAC, which is spoofable (IRK doesn't prevent that).

    Right, if you want the bonded peer to always be able to reconnect, it's best to have white-list advertising after the "pairable" window.

    BillB said:
    I can tell that's only looking at the MAC, which is spoofable (IRK doesn't prevent that).

    Yes, this is true but only with Just Works pairing. You mentioned the device not having a display, but does it have any other IO capabilities for an Out-of-Band method? Refer to Bluetooth spec, Vol 3, Part H, Section 2.3.5.1, Selecting key generation method:

    BillB said:
    Definitely open to trying ideas like this though - what is the usual way to block all pairing?
    E.g. I've been experimenting with 
    struct bt_conn_auth_cb but not sure which is the best option.

    It actually seems like the best option to me. Do you find something unfitting about it?

    BillB said:
    Yeah, I wondered if there might be a way to check the connection state (is it bonded) during the callback, I'll look into it some more.

    There is. You can check if the current peer address is in the list of bonded devices.

    See:

    https://docs.nordicsemi.com/bundle/ncs-2.6.1/page/zephyr/connectivity/bluetooth/api/connection_mgmt.html#c.bt_conn_get_dst
    https://docs.nordicsemi.com/bundle/ncs-2.6.1/page/zephyr/connectivity/bluetooth/api/gap.html#c.bt_foreach_bond

  • Hi Hieu,

    E.g. I've been experimenting with struct bt_conn_auth_cb but not sure which is the best
    It actually seems like the best option to me.

    Just that there's a lot of callbacks in the structs and which ones are set seems to determine the IO capabilities and therefore the auth procedure and I find the wording in the doc a but vague on the implications.

    I think maybe pairing_accept() is the right one, but pairing_confirm() seems interesting too?
    And then there's the 
    BT_CONN_CB_DEFINE() ones, if I can rely on only one device being connected at a time.

    Anyway I'll do some more experiments in the next couple of days and get back to you.

    but does it have any other IO capabilities for an Out-of-Band method

    Nothing obvious that I can see, e.g. there's no NFC or other way to talk to a phone except something crazy like pointing the phone camera at a LED. But I'll have a think.

    You can check if the current peer address is in the list of bonded devices.

    But that's the key question that's driving this - the doc is only talking about addresses, which can be faked easily.
    What's harder to fake (especially in LE secure connections) is the actual encryption key in use, but I haven't read anything that says the stack is checking that key matches the one in the bond list and the links you've given don't have a way for me to check that in my own app.
    I.e. I can't see anything that would prevent an attacker (that wasn't present at the initial bonding) from just spoofing the MAC and then negotiating a new key for the session.

    The only thing I can think of is that key negotiation is probably considered a "pair" and might still trigger one or more of the bt_conn_auth_cb calls even in JustWorks, and it those calls are _not_ triggered when a bonded device reuses the bond key (i.e. if a previously bonded device coming back in range is not a "pair") then we might be OK. But the doc isn't explicit on this so I'll still be nervous about it even if my experiments look good.

    I might end up having to read the full BLE spec, stack source, and maybe pentesting it, but it just feels like what I'm trying to do here must have been done before and that if it was actually a problem there'd be papers written on it already. I mean the UI is basically the BLE equivalent of one of the Bluetooth Classic dongles or hands-free and those _do_ have issues but I thought BLE was supposed to have fixed them?

  • Hi Bill,

    BillB said:
    What's harder to fake (especially in LE secure connections) is the actual encryption key in use, but I haven't read anything that says the stack is checking that key matches the one in the bond list and the links you've given don't have a way for me to check that in my own app.

    But if your device is advertising with Resolvable Random Private Address, then only the bonded peer with the agreed Identity Resolving Key can identify it and initiate a connection.

    BillB said:
    I.e. I can't see anything that would prevent an attacker (that wasn't present at the initial bonding) from just spoofing the MAC and then negotiating a new key for the session.

    Using Just Works, there is also nothing stopping a MITM from getting the agreed key. They don't even have to fake being the device and getting a new key.

    At the end of the day, vulnerability to MITM is an inherent issue when you use Just Works pairing. There is simply no way around it. Some secrets must be agreed on a different physical channel to defend against the MITM.

    I discussed some alternatives in a recent ticket:  Using Just Works mode with MITM protection

Reply
  • Hi Bill,

    BillB said:
    What's harder to fake (especially in LE secure connections) is the actual encryption key in use, but I haven't read anything that says the stack is checking that key matches the one in the bond list and the links you've given don't have a way for me to check that in my own app.

    But if your device is advertising with Resolvable Random Private Address, then only the bonded peer with the agreed Identity Resolving Key can identify it and initiate a connection.

    BillB said:
    I.e. I can't see anything that would prevent an attacker (that wasn't present at the initial bonding) from just spoofing the MAC and then negotiating a new key for the session.

    Using Just Works, there is also nothing stopping a MITM from getting the agreed key. They don't even have to fake being the device and getting a new key.

    At the end of the day, vulnerability to MITM is an inherent issue when you use Just Works pairing. There is simply no way around it. Some secrets must be agreed on a different physical channel to defend against the MITM.

    I discussed some alternatives in a recent ticket:  Using Just Works mode with MITM protection

Children
  • Hi Hieu,

    I really appreciate your time, thank you.

    Some of this isn't adding up with experience I've had in other protos (I'm new to BLE, but have just enough experience with crypto to be skeptical/terrified of everything ;-) )

    Anyway I tried out pairing_accept() and it seems to do roughly the right thing, so I think I'm going hope this is all implemented correctly and close this ticket off for now.

    Then later in the project I'll decide if I care enough and if so do the deep dive, if I find anything I can post again.

    Cheers!

    P.S. the things still scaring me are:

    • In my mind there's a huge difference between a MITM attacker injecting themselves in possibly controlled conditions during the bond procedure (which I agree can't be helped in JustWorks) vs the attacker following the victim around 24/7 to keep up the charade (which could be detected as soon as they screw up)
      So the question is "Would it be detected?" and I think the answer might turn out to be "only if the stack enforces Diffie-Hellman and does some additional checks"
    • Right now I don't think the attacker needs the IRK to connect - they can just try connecting to every device in range - but there could be a detail in the proto I'm missing
    • It's hard to be sure that the stack is always going to call the API hooks in the right way no matter what tricks they're pulling, need to read the code
Related