All of lore.kernel.org
 help / color / mirror / Atom feed
* Getting the address type of a  BLE device
@ 2016-10-07 14:49 Jamie Mccrae
  2016-10-07 21:02 ` Emil Lenngren
  2016-10-08  6:04 ` Johan Hedberg
  0 siblings, 2 replies; 7+ messages in thread
From: Jamie Mccrae @ 2016-10-07 14:49 UTC (permalink / raw)
  To: linux-bluetooth

Hi,

One thing I've noticed that is lacking in BlueZ seems to be the inability to get the address type of the devices found in a scan for Bluetooth Low Energy scans (not Bluetooth Classic). This is a headache in frameworks like Qt. According to a BlueZ 4 -> 5 porting guide when a device is detected the Bluetooth daemon holds the address type for 3 minutes and you should be able to connect or pair with it without needing to set the address type (random or private) but this does not work at all from Qt. Also (assuming it worked) there is the problem of what if a user performs a scan and decides to connect in 5 minutes' time? The type of address will have been deleted.
I propose adding an additional field to the list of devices in a scan that will return nothing for BTC devices (or something to indicate it is not a BLE device, there is also the option to return something else if the device is both a BLE and BTC device combined) or the first byte of the BLE address if it is a BLE device. Right now in Qt it is purely guess work what type of address is received and it'd be nice to improve that to make the system workable. This means you can detect what type of device it is (great for logging), check if it also has  BTC service (and decide to connect with that) or check if it's using a random address that your device has a resolving key for - none of which is possible at the moment. It also helps out with a potential MITM issue whereby a device exists with a random address and someone clones the address but sets it as a static address: how do you know what device you are really pairing with? The correct device or the impersonation which could be decryp
 ting all data passing through it and passing it to the real device.

I'm interested to hear everyone's thoughts and suggestions regarding this addition.

Thanks,
Jamie

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Getting the address type of a BLE device
  2016-10-07 14:49 Getting the address type of a BLE device Jamie Mccrae
@ 2016-10-07 21:02 ` Emil Lenngren
  2016-10-08  6:04 ` Johan Hedberg
  1 sibling, 0 replies; 7+ messages in thread
From: Emil Lenngren @ 2016-10-07 21:02 UTC (permalink / raw)
  To: Jamie Mccrae, linux-bluetooth

You are so correct in almost everything you write.

A problem is that some people see the random/public type as a
"property" of the device or device address that isn't much to care
about, while it really should be seen as the 49th bit of the device
address.
For Bluetooth Low Energy, ALWAYS when a device address is passed
around, the address type MUST also be included.
Also if you want some kind of map of device address (key) to some
object (value), you need to include the address type in the key as
well, since there can be two devices having the same device address
but of different types. The probability that this would happen is very
small but can happen if, as you said, some malicious device comes
along.

Bluetooth stacks that only interacts with BLE devices and not classic
devices, normally handles this very well, and in other stacks that
were initially built for classic bluetooth where BLE was added later,
it seems to have been a great challenge to add an extra bit to the
device address. Just as an example, Android's bluetooth stack fails
brutally here on every point all the way from the lowest layers in the
stack up to the application layer. When connecting to a specific BLE
device by device address, you can only enter the 48 bits and not the
address type (and certainly not simply an IRK). Instead Android
maintains a list of "known" devices, where they basically map 48 bits
to a device record which contains if the address is public or random.
Known devices are either bonded devices or devices found in scans
since the latest bluetooth restart. If the device you want to connect
to is not in this map, the stack just makes a wild guess about the
address type. Versions up to Marshmallow tend to guess for a public
address while Nougat seems to guess for a random address, so it's
totally impossible to create a reliable app that connects to an
arbitrary address if you don't do a scan first, even if you know the
address type. An interesting bug is if you first initiate a connection
to a device (where it guesses this is a public address) and after that
you start a scan and have a peripheral that advertises this address
but with random type, Android adds this to its record. Later you
cancel the connection attempt. What it internally did now was to first
add the public address to the white list and later tried to remove the
random address from the white list (which obviously fails), leaving
the public address in the white list while Android thinks it's
empty...

In BLE we also have this problem with private addresses, and the fact
that devices may sometimes use a public address and sometimes a
private address that can be changed any time. Therefore, identifying a
BLE device only by a device address is not really a good idea. It's
first when you have bonded to a device you really know for sure that
you can identify it later, since it's at that point you learn the
IRK/Identity address, or that there is no IRK (which means you should
later identify it with the static/public address that was included in
the advertisement). Apple has made a quite smart approach in their
CoreBluetooth here by simply not exposing any device address but
rather a UUID it generates internally. That way you can always refer
to a device by its UUID and it will automatically take care of IRKs,
random address resolving etc. The only problem with this approach is
that you have to first scan a device before you can use it, and the
fact that you might want to actually use the device address for
something (like identification if you don't use random addresses in
the peripherals). A similar approach is used in Web Bluetooth (see
some discussion at
https://github.com/WebBluetoothCG/web-bluetooth/issues/138).

In either case, if a device you are not bonded to uses resolvable
private addresses, it is impossible to create a user flow to first
scan devices and connect 5 minutes later. With the default time of
changing address each 15 minutes it's pretty high chance that it has
changed after 5 minutes which means you will fail to later connect to
it. Therefore I wouldn't really recommend anyone that develops
peripherals to use resolvable private addresses when the goal is to
establish a connection to non-bonded devices.

This were my thoughts on the topic ;)

/Emil

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Getting the address type of a  BLE device
  2016-10-07 14:49 Getting the address type of a BLE device Jamie Mccrae
  2016-10-07 21:02 ` Emil Lenngren
@ 2016-10-08  6:04 ` Johan Hedberg
  2016-10-08 11:21   ` Jamie Mccrae
  1 sibling, 1 reply; 7+ messages in thread
From: Johan Hedberg @ 2016-10-08  6:04 UTC (permalink / raw)
  To: Jamie Mccrae; +Cc: linux-bluetooth

Hi Jamie,

On Fri, Oct 07, 2016, Jamie Mccrae wrote:
> One thing I've noticed that is lacking in BlueZ seems to be the
> inability to get the address type of the devices found in a scan for
> Bluetooth Low Energy scans (not Bluetooth Classic). This is a headache
> in frameworks like Qt. According to a BlueZ 4 -> 5 porting guide when
> a device is detected the Bluetooth daemon holds the address type for 3
> minutes and you should be able to connect or pair with it without
> needing to set the address type (random or private) but this does not
> work at all from Qt. Also (assuming it worked) there is the problem of
> what if a user performs a scan and decides to connect in 5 minutes'
> time? The type of address will have been deleted.

I'm not sure what exactly you're referring to here. There's no timeout
like that for the address type that I'm aware of. There *is* a timeout
for discovered but not connected device objects, that will be
auto-removed from D-Bus. I think that's 3 minutes - maybe what you're
referring to? As long as bluetoothd has a device object it has complete
tracking of the address type (BR/EDR, LE public or LE random).

The private addresses mentioned in the other reply are handled by the
kernel, user space (bluetoothd) always addresses the device using its
identity address and the kernel does the necessary translation based on
IRK availability.

> I propose adding an additional field to the list of devices in a scan
> that will return nothing for BTC devices (or something to indicate it
> is not a BLE device, there is also the option to return something else
> if the device is both a BLE and BTC device combined) or the first byte
> of the BLE address if it is a BLE device.

There's already an API for requesting an LE-only scan: the
SetDiscoveryFilter method on the Adapter interface (see
doc/adapter-api.txt for more info). I don't see how this is related to
the address type topic though (i.e. random vs public) but it does at
least give the BR/EDR vs LE separation.

There's been a proposal from Szymon earlier on this list to have
dediated D-Bus interfaces for BR/EDR and LE on device objects - I think
that would provide a clean way to see what transports a device supports.
Right now you're right that the D-Bus API is lacking and requires
unreliable heuristics, like checking the presence of the Appearance
property (only available for LE).

While we do expose the LE address type through mgmt and bluetoothd
tracks it, I realize that we don't expose that further. This is only
really an issue if you want to create e.g. an L2CAP socket yourself and
connect to the remote device (you provide the address type in the socket
address). That can however be worked around using the Profile D-Bus
interface (see doc/profile-api.txt) that can connect on your behalf and
give the resulting file-descriptor to you. We could either way export
the identity address type info as a property if we add an LE-specific
interface to device objects.

> Right now in Qt it is purely guess work what type of address is
> received and it'd be nice to improve that to make the system workable.
> This means you can detect what type of device it is (great for
> logging), check if it also has BTC service (and decide to connect with
> that) or check if it's using a random address that your device has a
> resolving key for - none of which is possible at the moment.

The main reason why these are not exposed by bluetoothd (they *are*
exposed by the mgmt kernel interface however) is that bluetoothd and the
kernel are supposed to take care of them so you don't have to care. The
kernel does all address resolution using IRKs and bluetoothd reloads the
list of known IRKs from previous pairings to the kernel upon startup.

> It also helps out with a potential MITM issue whereby a device exists
> with a random address and someone clones the address but sets it as a
> static address: how do you know what device you are really pairing
> with?

I'm not completely following this. Do you mean that the former is a
private address? Changing a private address to static type implies
changing two bits of the address value, meaning it's not the same
address anymore. As for devices spoofing others, that's one of the
reasons pairing exists - you connect to them and if authentication fails
you know something's wrong.

> The correct device or the impersonation which could be decrypting all
> data passing through it and passing it to the real device.

That would only work if the spoofing device has the LTK we share with
the "real" device. How would it have gotten it?

Johan

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Getting the address type of a  BLE device
  2016-10-08  6:04 ` Johan Hedberg
@ 2016-10-08 11:21   ` Jamie Mccrae
  2016-10-09 14:52     ` Johan Hedberg
  0 siblings, 1 reply; 7+ messages in thread
From: Jamie Mccrae @ 2016-10-08 11:21 UTC (permalink / raw)
  To: linux-bluetooth

Hi Johan,

> There *is* a timeout for discovered but not connected device
> objects, that will be auto-removed from D-Bus. I think that's 3
> minutes - maybe what you're referring to? 

Correct, this is what I am referring to. If someone creates an application which performs a scan, then they walk away for 10 minutes and come back then try to connect to a device in the list, as far as I understand it the type of the address would have been forgotten and a connection would not work unless the scan was restarted?

> There's already an API for requesting an LE-only scan: the
> SetDiscoveryFilter method on the Adapter interface (see
> doc/adapter-api.txt for more info).

If a scan is performed with no filtering and a dual mode device is found, how do you know what type has been returned (will it be the BTC device, the BLE device or an device indicating that both services are supported)? If it's not currently exposed then my idea would be to either have a bitmask value which indicates the type of device detected, e.g. 0x00 for BTC device, 0x01 for BLE random only, 0x02 for BLE public only, 0x03 for BTC and BLE random, 0x04 for BTC and BLE public - or just two separate fields e.g. BTCService: true/false, BLEService: null (none), 1 (random), 2 (public). That way applications can scan for devices and decide if it's best to connect via BLE or BTC.

> While we do expose the LE address type through mgmt and bluetoothd
> tracks it, I realize that we don't expose that further. This is only
> really an issue if you want to create e.g. an L2CAP socket yourself and
> connect to the remote device (you provide the address type in the socket
> address).

I do understand this is likely just a Qt issue due to how their API works: if a scan is performed and then you attempt to connect to a device without setting the address type it fails to connect and you cannot currently retrieve the address type, but if it was reported back then it could be stored with the address and solve this problem (I haven't looked at implementations in other languages but I assume some might also have this problem).

> I'm not completely following this. Do you mean that the former is a
> private address? Changing a private address to static type implies
> changing two bits of the address value, meaning it's not the same
> address anymore. As for devices spoofing others, that's one of the
> reasons pairing exists - you connect to them and if authentication fails
> you know something's wrong.

This is only true if you've bonded with the device, the benefit of BLE over BTC is that you can connect to a device and interact with it without needing to bond (unless encryption is required or a mandatory bond is required for a certain characteristic). If I get two BLE devices, one with the random address 01:00:11:22:33:44:55 and then set a public address on the other to 00:00:11:22:33:44:55, in the list of devices found in a search using BlueZ there is currently nothing to differentiate them via DBUS although yes the kernel will know the difference. Some devices will never bond, other devices will but it should work as the dire windows 10 implementation works whereby a bond is required to even connect to the device.

> That would only work if the spoofing device has the LTK we share with
> the "real" device. How would it have gotten it?

In the previous scenario by spoofing the address and changing the type to be opposite of what the real device is, if BlueZ connects and pairs with that device instead, that device can then initiate an outgoing connection and pair with the real device and any data passing through the MITM device can be dumped without knowledge of the BlueZ system. BLE is really pushing for the IoT sector and in my opinion a high level of security is essential for this, being unable to differentiate between two devices from a user's application is equivalent to having no security.

Thanks,
Jamie

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Getting the address type of a  BLE device
  2016-10-08 11:21   ` Jamie Mccrae
@ 2016-10-09 14:52     ` Johan Hedberg
  2016-10-14 12:54       ` Jamie Mccrae
  0 siblings, 1 reply; 7+ messages in thread
From: Johan Hedberg @ 2016-10-09 14:52 UTC (permalink / raw)
  To: Jamie Mccrae; +Cc: linux-bluetooth

Hi Jamie,

On Sat, Oct 08, 2016, Jamie Mccrae wrote:
> > There *is* a timeout for discovered but not connected device
> > objects, that will be auto-removed from D-Bus. I think that's 3
> > minutes - maybe what you're referring to? 
> 
> Correct, this is what I am referring to. If someone creates an
> application which performs a scan, then they walk away for 10 minutes
> and come back then try to connect to a device in the list, as far as I
> understand it the type of the address would have been forgotten and a
> connection would not work unless the scan was restarted?

Well, the device wouldn't be in the list anymore, so there'd be nothing
to try to connect to. So yes you'd need to restart the scan to
rediscover the device and recreate a device object for it. This is
intentional cleanup that bluetoothd does for found devices so that we
don't end up with a huge list of unused device objects (which would only
confuse the user when needing to select the right device to connect to).

> > There's already an API for requesting an LE-only scan: the
> > SetDiscoveryFilter method on the Adapter interface (see
> > doc/adapter-api.txt for more info).
> 
> If a scan is performed with no filtering and a dual mode device is
> found, how do you know what type has been returned (will it be the BTC
> device, the BLE device or an device indicating that both services are
> supported)? If it's not currently exposed then my idea would be to
> either have a bitmask value which indicates the type of device
> detected, e.g. 0x00 for BTC device, 0x01 for BLE random only, 0x02 for
> BLE public only, 0x03 for BTC and BLE random, 0x04 for BTC and BLE
> public - or just two separate fields e.g. BTCService: true/false,
> BLEService: null (none), 1 (random), 2 (public). That way applications
> can scan for devices and decide if it's best to connect via BLE or
> BTC.

The LE & BR/EDR D-Bus interface proposal from Szymon (that I mentioned
in my earlier email) would likely be the cleanest way to do this.

> > While we do expose the LE address type through mgmt and bluetoothd
> > tracks it, I realize that we don't expose that further. This is only
> > really an issue if you want to create e.g. an L2CAP socket yourself and
> > connect to the remote device (you provide the address type in the socket
> > address).
> 
> I do understand this is likely just a Qt issue due to how their API
> works: if a scan is performed and then you attempt to connect to a
> device without setting the address type it fails to connect and you
> cannot currently retrieve the address type, but if it was reported
> back then it could be stored with the address and solve this problem
> (I haven't looked at implementations in other languages but I assume
> some might also have this problem).

What API does Qt use to connect? The first connection to LE devices is
usually either through the Pair() or Connect() D-Bus method. Neither one
requires knowledge of the address type. After the initial connection
re-connections are typically done through passive background scanning by
the kernel, and in this case the application also doesn't need knowledge
of the address type.

> > I'm not completely following this. Do you mean that the former is a
> > private address? Changing a private address to static type implies
> > changing two bits of the address value, meaning it's not the same
> > address anymore. As for devices spoofing others, that's one of the
> > reasons pairing exists - you connect to them and if authentication fails
> > you know something's wrong.
> 
> This is only true if you've bonded with the device,

If you're not bonded there's no way to protect against other devices
spoofing the address of the real device,

> the benefit of BLE over BTC is that you can connect to a device and
> interact with it without needing to bond (unless encryption is
> required or a mandatory bond is required for a certain
> characteristic).

That's only true for BR/EDR Security Mode 4, and even that has some
exceptions like SDP.

> If I get two BLE devices, one with the random address
> 01:00:11:22:33:44:55 and then set a public address on the other to
> 00:00:11:22:33:44:55, in the list of devices found in a search using
> BlueZ there is currently nothing to differentiate them via DBUS
> although yes the kernel will know the difference.

I suppose you're referring to the Address property on the Device1
interface? It'd be help understand what exactly your concern is if you
could be more specific in this regard. I'll assume you're talking about
the Address property. This property was originally created for BR/EDR
devices and probably isn't that useful for LE where you need to know the
random vs public information. The new LE-specific D-Bus interface talked
about earlier would provide this missing info.

> > That would only work if the spoofing device has the LTK we share with
> > the "real" device. How would it have gotten it?
> 
> In the previous scenario by spoofing the address and changing the type
> to be opposite of what the real device is, if BlueZ connects and pairs
> with that device instead, that device can then initiate an outgoing
> connection and pair with the real device and any data passing through
> the MITM device can be dumped without knowledge of the BlueZ system.

It would still be a separate device object and shown as a separate entry
in the UI. Its Paired property would also start off as False. I'd expect
this already to provide a fairly good indication to the user that
there's another device around.

> BLE is really pushing for the IoT sector and in my opinion a high
> level of security is essential for this, being unable to differentiate
> between two devices from a user's application is equivalent to having
> no security.

Agreed, but I'm not sure I've fully understood the issue you're seeing,
since we'd still have two D-Bus objects. When these also map to two
entries in the UI, I think that's visually much more obvious to the user
that there are two devices (rather than one), compared to the user
having to look at the address details of each device.

The proposed LE-specific D-Bus interface would provide this information,
but I'd expect the greatest value of it to be for custom L2CAP channels
(where the address type is needed for the L2CAP socket address) rather
than a UI. Even for L2CAP the added value is a bit dubious thanks to the
Profile1 D-Bus interface.

Johan

^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: Getting the address type of a  BLE device
  2016-10-09 14:52     ` Johan Hedberg
@ 2016-10-14 12:54       ` Jamie Mccrae
  2016-10-14 14:58         ` Johan Hedberg
  0 siblings, 1 reply; 7+ messages in thread
From: Jamie Mccrae @ 2016-10-14 12:54 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth

Hi Johan,

> The LE & BR/EDR D-Bus interface proposal from Szymon (that I mentioned in my earlier email) would likely be the cleanest way to do this.

Do you have a link to this proposal?

> What API does Qt use to connect? The first connection to LE devices is usually either through the Pair() or Connect() D-Bus method. Neither one requires knowledge of the address type. After the initial connection re-connections are typically done through passive background scanning by the kernel, and in this case the application also doesn't need knowledge of the address type.

Qt is using the DBus API but it seems they don't store the device handles/IDs and instead when connecting to a device just require the Bluetooth address (which is why this would be failing as it's not using the kernels cached entries and is specifically setting if it's connecting to a random address or public address before passing it to BlueZ)

> If you're not bonded there's no way to protect against other devices spoofing the address of the real device,

True, I was just referring to at the moment being unable to extract the address type.

> That's only true for BR/EDR Security Mode 4, and even that has some exceptions like SDP.

I'm not sure I follow you? BLE does not require any bonding unless mandated by the service/characteristics. It's possible to have many BLE devices and have them all interacting without any of them ever bonding with another device, yes this means there is no encryption or security but in some instances it is not required.

> I suppose you're referring to the Address property on the Device1 interface? It'd be help understand what exactly your concern is if you could be more specific in this regard. I'll assume you're talking about the Address property. This property was originally created for BR/EDR devices and probably isn't that useful for LE where you need to know the random vs public information. The new LE-specific D-Bus interface talked about earlier would provide this missing info.

I think the confusion comes from how we envisage the address type. When I think of the address type I think of it as part of the BLE address itself and prepend it to the address so with 00:11:22:33:44:55:66 the 00 is indicating that it is a public address and with 01:11:22:33:44:55:66 the 01 is indicating that it is a random address.

Thanks,
Jamie

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Getting the address type of a  BLE device
  2016-10-14 12:54       ` Jamie Mccrae
@ 2016-10-14 14:58         ` Johan Hedberg
  0 siblings, 0 replies; 7+ messages in thread
From: Johan Hedberg @ 2016-10-14 14:58 UTC (permalink / raw)
  To: Jamie Mccrae; +Cc: linux-bluetooth

Hi Jamie,

On Fri, Oct 14, 2016, Jamie Mccrae wrote:
>> The LE & BR/EDR D-Bus interface proposal from Szymon (that I
>> mentioned in my earlier email) would likely be the cleanest way to do
>> this.
> 
> Do you have a link to this proposal?

http://thread.gmane.org/gmane.linux.bluez.kernel/67182

>> What API does Qt use to connect? The first connection to LE devices
>> is usually either through the Pair() or Connect() D-Bus method.
>> Neither one requires knowledge of the address type. After the
>> initial connection re-connections are typically done through passive
>> background scanning by the kernel, and in this case the application
>> also doesn't need knowledge of the address type.
> 
> Qt is using the DBus API but it seems they don't store the device
> handles/IDs and instead when connecting to a device just require the
> Bluetooth address (which is why this would be failing as it's not
> using the kernels cached entries and is specifically setting if it's
> connecting to a random address or public address before passing it to
> BlueZ)

The D-Bus API doesn't take addresses as input. The app selects a device
based on its object path. It might of course be doing matching against
the Address property, but when requesting to connect it's just based on
what object path you direct your call to.

Is Qt persistently caching something rather than just at run-time? That
sounds odd (i.e. unnecessary). If it's just run-time then the object
path would be the most reliable identifier.

>> That's only true for BR/EDR Security Mode 4, and even that has some
>> exceptions like SDP.
> 
> I'm not sure I follow you? BLE does not require any bonding unless
> mandated by the service/characteristics. It's possible to have many
> BLE devices and have them all interacting without any of them ever
> bonding with another device, yes this means there is no encryption or
> security but in some instances it is not required.

True. My comment above was about BR/EDR (which would have been cleared
if you had also quoted the text I was responding to).

>> I suppose you're referring to the Address property on the Device1
>> interface? It'd be help understand what exactly your concern is if
>> you could be more specific in this regard. I'll assume you're
>> talking about the Address property. This property was originally
>> created for BR/EDR devices and probably isn't that useful for LE
>> where you need to know the random vs public information. The new
>> LE-specific D-Bus interface talked about earlier would provide this
>> missing info.
> 
> I think the confusion comes from how we envisage the address type.
> When I think of the address type I think of it as part of the BLE
> address itself and prepend it to the address so with
> 00:11:22:33:44:55:66 the 00 is indicating that it is a public address
> and with 01:11:22:33:44:55:66 the 01 is indicating that it is a random
> address.

It's a fair point that we could consider extending the Address property
this way since it's just a string. I'm not sure we want to do that
however since it'd break compatibility with applications that rely on
the current format of this property.

Johan

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2016-10-14 14:58 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-07 14:49 Getting the address type of a BLE device Jamie Mccrae
2016-10-07 21:02 ` Emil Lenngren
2016-10-08  6:04 ` Johan Hedberg
2016-10-08 11:21   ` Jamie Mccrae
2016-10-09 14:52     ` Johan Hedberg
2016-10-14 12:54       ` Jamie Mccrae
2016-10-14 14:58         ` Johan Hedberg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.