Bluez: Setting Local Address to Be Private and Non-Resolvable

iOS Central with BlueZ Peripheral disconnect due to insufficient auth

This issue started occurring in Bluez v5.48 after the battery GATT characteristic was moved into the DBUS org.bluez.Battery1 interface. When a Pi and iOS device connect, the Pi attempts to read the iOS battery characteristic. A pair request is then triggered because either Apple has protected this characteristic from unpaired reads or something in Bluez erroneously determines that this characteristic is protected. I've found two different ways to fix this issue without recompiling Bluez.

  1. Easy Solution: Prevent the Bluez battery plugin from loading at boot. You will need to modify the bluetooth service file located at the following path: /lib/systemd/system/bluetooth.service . In this file, go to the line that begins with "ExecStart" and make sure that this line has "ExecStart=/usr/lib/bluetooth/bluetoothd -P battery" (without the surrounding quotes). This -P option prevents any listed plugins from loading.

  2. Custom Solution: Write your own custom agent that auto-accepts pairing requests. I used the Bluez simple-agent example and modified it so that the RequestPinCode function always returned successfully instead of asking for input. The downside of this type of approach is that this still asks the iOS user to pair. Although, this can be a positive outcome if you want to have the reliability and encryption access from a fully paired bluetooth connection.

Private vs public addresses in Bluetooth low energy on Android

Since nobody else seems to have an answer to offer I started testing on my own.

I tried making an app that creates a device from a string representation of an address and tried setting up my device with the 48 bit address alternating the public or private bit to see what the Android stack does.

private final BluetoothGattCallback leGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.i("Fisken", "Gatt connected " + gatt.getDevice().getAddress() + " status " + status);
if (status != BluetoothGatt.GATT_SUCCESS) {
Log.w("Fisken", "Disconnect and close");
gatt.disconnect();
gatt.close();
}
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i("Fisken", "Gatt disconnected " + gatt.getDevice().getAddress() + " status " + status);
if (status != BluetoothGatt.GATT_SUCCESS) {
Log.w("Fisken", "Disconnect and close");
gatt.disconnect();
}
gatt.close();
}
}
};

BluetoothAdapter mBluetoothAdapter = ((BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE)).getAdapter();
BluetoothDevice d = mBluetoothAdapter.getRemoteDevice("FF:55:44:33:22:11");
d.connectGatt(this, false, leGattCallback);

With this code, if I start my BLE peripheral with a random address everything works as expected. However, if I try running it with the same address with the public bit set, logcat says "Gatt connected", but that's just not true. And I'm never able to disconnect.

Update: I did some more testing to figure this out. The onConnectionStateChange event I get is just the connection attempt timing out. The status is set to either 133 (if I get STATE_CONNECTED) or 257 (if I get a STATE_DISCONNECTED) and I've seen both. In either case I should (and now do in the sample code) cancel the connection attempt and close the client.

I've also found out that if I do a scan first, so that the device I'm trying to connect to have been seen recently and then do a connect based solely on the device mac address then I am able to connect to both random and public addresses without any trouble.

So this seems to be a bug/and or missing feature in the Android API. It does not allow you to connect to a public address without first having scanned for it. It does however work for random addresses.

Android 5 static bluetooth MAC address for BLE advertising

The MAC Address is a physical address and does not change. In BLE terminology, it is the Public Device Address or BD_ADDR for BR/EDR. I haven't tried it, but reading it with readAddress() should return the same value each time.

What the Android's BLE framework does is NOT use that address when advertising. It rather enables privacy by using Private Resolvable Addresses which may change every few minutes or so but still allow bonded devices to recognize it using the IRK exchanged at bonding.

For obvious privacy reasons, Android's BLE framework does not allow you to set the Controller to use the public address when advertising. So you cannot disable the "address rotating".

Should one create a bond with a Bluetooth LE device

Short answer: the correct, common, and reliable scenario is to bond. Bonding means the connection is secure and the link is trusted. It means that your local device will usually find the remote device even if its address is changing. Pairing/bonding is recommended practice in Bluetooth for security and privacy reasons.


Long answer: since its introduction, incremental versions of the Bluetooth spec have added features to improve the security and privacy of Bluetooth devices. Many devices will not allow you to exchange data or properly track them unless you are paired/bonded (The difference between bonding and pairing is that with bonding, the exchanged keys are stored in the database.)

In Bluetooth Low Energy, the pairing/bonding process consists of three stages:-

Phase 1 - Pairing Feature Exchange

The two connected devices exchange their IO capabilities (e.g. does the device have a keyboard), authentication requirements (e.g. to bond or not to bond) and supported key sizes.

Phase 2 - Authentication and Encryption

Using encryption algorithms a key is generated and used to encrypt the link (this is different for legacy and LESC pairing, but it is beyond the scope of this question).

Phase 3 - Key distribution

Several keys are exchanged between the devices including the CSRK (Connection Signature Resolving Key), the IRK (Identity Resolving Key) and the static address.

Of particular importance to your question is the IRK and the address. Since Bluetooth v4.0, a feature known as LE Privacy allowed the device to continuously change its address to reduce its track-ability. Malicious devices would not be able to track the device implementing this feature, as it actually looks like a series of different devices. In order to resolve the address, the devices need to be previously paired/bonded. If the remote device contains the IRK then it can use that and the random resolvable address to derive the Bluetooth device's original address.


So, going over your criteria:-

  • The Bluetooth device is used frequently, but not continuously.

If you are going to disconnect/reconnect frequently, you can pair once with the device and store the keys (i.e. bond). Pairing is no longer needed afterwards as the same keys will be used to encrypt the connection upon disconnection/reconnection.

  • Reconnecting should happen as fast as possible

Connection and bonding are two different things. It will take the same amount of time to reconnect regardless of bonding being implemented. However, once the devices are reconnected, it will take some time for the connection to be re-encrypted.

  • Bluetooth address changes randomly when the device is powered down

This means that the device is utilising the LE privacy feature. Therefore your device should be bonded with it in order to resolve the private resolvable address.

  • The device's name is unknown, null or random

This is usually the case with BLE. The devices are usually identifiable via their address. As such if your devices have previously bonded you will be able to resolve the changing address and identify the remote device.

  • The connection is encrypted

You cannot achieve an encrypted connection without pairing first (as per the 3 phases above). With bonding you are storing the keys in your database, therefore ensuring that you can use them in the future to re-encrypt the connection without having to go over the pairing phases.

  • The connection uses an overlying API that requires a Bluetooth Device
    as parameter for connection.

I am not sure what this means, but is irrelevant to the requirement for bonding.


For further reading on the subject, I recommend visiting the Bluetooth Specification Version 5.0, Vol 3, Part H, Section 2 Security Manager (page 2295)



Related Topics



Leave a reply



Submit