Caching bluetooth pairing keys, core bluetooth

Hi!

We have created an app that communicates with devices over BLE, and it is currently out in Testflight. It works as expected for almost everyone, but for some users we get a strange behaviour. We start by scanning for devices with

scanForPeripherals(withServices:options:), 

then connect, and finally initiate pairing by subscribing and writing to a pair of characteristics, which both require encryption.

The issue is that for these users, the following code:

func peripheral(
        _ peripheral: CBPeripheral,
        didDiscoverCharacteristicsFor service: CBService,
        error: Error?
    ) {
        guard error == nil else {
            LogManager.shared.log(
                "❌ Error discovering characteristics: \(error!)"
            )
            return
        }

        for characteristic in service.characteristics ?? [] {
            if characteristic.uuid == controlPointUUID {
                controlPointCharacteristic = characteristic
                LogManager.shared.debugLog(
                    "Control Point characteristic found."
                )
            } else if characteristic.uuid == statusUUID {
                statusCharacteristic = characteristic
                LogManager.shared.debugLog("Notify characteristic found.")
            }
        }

        if statusCharacteristic != nil {
            LogManager.shared.debugLog("Call Set notify.")
            peripheral.setNotifyValue(true, for: statusCharacteristic!)
        }
    }

func peripheral(
        _ peripheral: CBPeripheral,
        didUpdateNotificationStateFor characteristic: CBCharacteristic,
        error: Error?
    ) {
        if error != nil {
            LogManager.shared.log(
                "❌ Failed to subscribe to \(characteristic.uuid): \(error.debugDescription)"
            )

produces this error:

> > [22:31:34.632] ❌ Failed to subscribe to F1D0FFF2-DEAA-ECEE-B42F-C9BA7ED623BB: Optional(Error Domain=CBATTErrorDomain Code=15 "Encryption is insufficient." UserInfo={NSLocalizedDescription=Encryption is insufficient.})

So in essence, we can't perform pairing and enable encryption, because we have insufficient encryption.

I know that the system caches some key material after pairing. When I do "Forget device" and then pair again, I don't need to put my device in pairing mode for the pairing pin to appear, which is not the case for devices that have not been paired before.

Given that I can't reproduce the problem locally, it's hard to debug using the console. What I've been trying to do is figure out how to reset Bluetooth, which should hopefully remove old keys and whatever else might be there.

The top hit when searching for 'clear corebluetooth cache macos' is on stackexchange, and writes:

  • Turn off Bluetooth
  • Delete com.apple.Bluetooth.plist from /Library/Preferences
  • Delete files named com.apple.Bluetooth.somehexuuidstuff.plist from ~/Library/Preferences/ByHost (note that this is the user preference folder, not the system one)
  • Turn on Bluetooth

The answer is from December 2013, so it's not surpising that things don't work out of the box, but anyways:

My ByHost folder does not contain any plist files with Bluetooth in them, and deleting the one in /Library/Preferences did not do anything, and judging from the content, it does not contain anything valuable.

I have tried "sudo grep -r 'Bluetooth' ." in both /Library/Preferences/ and ~/Library/Preferences/ and looked at the resulting hits, but I can't seem to find anything meaningful.

As a sidenote, does anyone know what is going on with Apple's entitlement service? We applied for an entitlement in August and have yet to receive a response.

Caching bluetooth pairing keys, core bluetooth
 
 
Q