Search code examples
androidbluetoothbluetooth-lowenergyqualcomm

Android BLE pairing and BREDR key distribution


I'm a developer working on an bluetooth headset product using Qualcomm SoC for Bluetooth and audio processing. Our product uses BREDR Bluetooth for "classic" profiles (HFP/AVRCP/A2DP) and LE for a mobile app and OTAU.

The typical flow we expect our users to perform is:

  1. BREDR pairing using a smartphone's Bluetooth settings. This uses the legacy BREDR "simple pairing" method which produces a P192 encryption key.
  2. user opens our app which will trigger LE pairing when the app attempts to access our custom GATT service.

Our headset does not support Secure Connections over BREDR due to compatibility issues, but it does support LE Secure Connections. So typically what happens is after LE pairing completes, the BREDR link key is recomputed based on the LE long term key, this gives it P256 encryption capability. For example here is what the link keys in my headset's permanent storage look like after BREDR pairing:

Device #0: addr_type=PUBLIC
BDADDR = xxxx xx xxxxxx
BREDR key: bbb...b (AUTHENTICATED P192)

and after LE pairing:

Device #0: addr_type=PUBLIC 
BDADDR = xxxx xx xxxxxx
BREDR key: aaa...a (AUTHENTICATED P256)
LE CENTRAL Key : 0000 (EVID) 0000000000000000 (RAND) bbb...b (LTK)
LE IRK: ccc...c

Now, this isn't a problem for most platforms, but lately I've started seeing issues with certain Android devices running Android 10/11 and some devices running Android 9 with up to date security patches. Basically what happens is after LE pairing I cannot create any new BREDR ACL. The connection always fails at the LMP_rand_au -> sres response stage - essentially the mobile device did not recompute its BREDR link key after LE pairing, and now the device no longer agree on the LTK. I have Cross-Transport Key Derivation explicitly disabled in my headset device, but the BREDR key is still changed after LE key distribution. This doesn't seem to be an issue at all on iOS devices. Has anybody else run into this issue? Any advice on how to proceed? So far I've tried:

  1. Disabling LE link key distribution: this prevents the BREDR key from being recomputed, as there is no LE LTK/IRK. However as soon as the mobile phone changes its random LE address the user will be force to re-pair. This also causes my trusted device list on the headset device to inflate, and it's preciously limited
  2. Forcing LTK changes after LE security completes - there is an HCI command explicitly for re-deriving the LTK. However attempting this causes all sort of nasty strange behavior. Maybe it's not fully supported on my headset SoC
  3. Saving the BREDR LTK before LE pairing and resetting it after LE pairing. This allows BREDR connection, which makes me suspect the issue is on the mobile device. However this of course prevents the user from accessing the mobile app.

Solution

  • OK, I actually managed to get some tech support from Qualcomm about this issue. The issue was in the Android devices, so the solution was to forcefully disable CTKD in the headset even when BREDR Secure Connections are disabled. This was not possible with Qualcomm's API, I was forced to change a few files in the open-source Connection library which Qualcomm provides in the ADK.