noble / bleno

A Node.js module for implementing BLE (Bluetooth Low Energy) peripherals
MIT License
2.13k stars 451 forks source link

Secure Read with iOS 9.3.1 #187

Open bradfol opened 8 years ago

bradfol commented 8 years ago

I'm having difficulty completing a secure read between an iPad Air running iOS 9.3.1 and a Raspberry Pi running Node 4.2.6 and Bleno 0.4.0.

The iPad first attempts a read request after connecting and receives this response.

Error Domain=CBATTErrorDomain Code=15 "Encryption is insufficient." UserInfo={NSLocalizedDescription=Encryption is insufficient.}

At this point the iPad displays a system prompt asking the user if it would like to pair with the Raspberry Pi, and I tap "Pair". My understanding is this is the expected protocol, and now the iPad and Pi should be paired.

But on the next read request to the same characteristic I receive another error:

Error Domain=CBATTErrorDomain Code=5 "Authentication is insufficient." UserInfo={NSLocalizedDescription=Authentication is insufficient.}

All further read requests will continue to respond with this second error.

Here is how I'm defining the characteristic with Bleno:

new bleno.Characteristic({
  uuid: "uuid here",
  properties: ["read"],
  secure: ["read"],
  onReadRequest: function (offset, callback) {
    callback(bleno.Characteristic.RESULT_SUCCESS, Buffer(message));
  }
});
robotastic commented 8 years ago

I think I have run into the problem in #185 Did you have this working before and it just stopped? I am also using iOS 9.3.1 and running on a Raspberry Pi. I wonder if there have been changes to Raspbian or iOS that might be triggering it? Are you using a RPi3? I wonder if the switch to a 64bit chip is messing anything up.

bradfol commented 8 years ago

@robotastic I am actually just beginning implementation, so I don't have anything to compare against. I'm using a RPi 2 with a USB bluetooth adapter. I have come across some information that suggests there were changes in iOS 9 that might be causing this:

iOS 9 is now using the new LE Secure Connections pairing model, and the SC bit is set to 1 in the pairing request.

https://forums.developer.apple.com/message/71488#71488

bradfol commented 8 years ago

Also might be relevant:

In the currently latest iOS version (9.2) bonding is mandatory with pairing.

https://forums.developer.apple.com/message/119075#119075

robotastic commented 8 years ago

I am pretty sure that bonding is attempted. From what I am seeing, the Long Term Key is not being correctly written to the bluetooth drivers, so when iOS requests the long term key, it gets a reply that there is none.

That is interesting about the SC bit. I will take a look at the code and see if that is being checked somewhere. https://piratecomm.wordpress.com/2014/01/19/ble-pairing-vs-bonding/

bradfol commented 8 years ago

@robotastic According to the Apple engineer linked above, bonding is now a requirement as of iOS 9.2.

So if the LTK is not being stored, then it sounds like bonding is failing. Therefore the secure connection is failing, resulting in the "Authentication is insufficient" error message.

bradfol commented 8 years ago

@sandeepmistry @robotastic here's hcidump output: https://gist.github.com/bradfol/13a26a6375192c4331584f972a59ff9d

robotastic commented 8 years ago

If you look on line 67, a Negative LTK Request Reply is being sent back. When I some additional debug statements, it looks like it was failing to push the keys to the bluetooth driver. https://gist.github.com/bradfol/13a26a6375192c4331584f972a59ff9d#file-hcidump-log-L67

bradfol commented 8 years ago

@sandeepmistry @robotastic What does "Negative LTK Request Reply" mean in this context? It looks like that is the HCI command being sent, not a response... (The next log entry shows HCI Event: Command Complete)

I see from running sudo hciconfig hci0 commands that the following are listed:

'LE Long Term Key Request Reply' 
'LE Long Term Key Request Negative Reply'

Maybe the wrong HCI command is being sent?

bradfol commented 8 years ago

Here is also logs from btmon for the secure read request: https://gist.github.com/bradfol/8e8fbab9ede434948fd9fc431c82e546

robotastic commented 8 years ago

Try setting the DEBUG environment: DEBUG=* It will cause the debug message to be printed out. I am getting the following right after secure connection is made and the LTK key is trying to be sent to the driver:

mgmt writing -> 1300000026000100428fe8c5b6470200100000000000000000000025ca78999b3b3beed475554ebc42406700 Length: 38 +1ms mgmt on data ->02000000030013000d +1ms

as best I can determine the write is failing, I traced the code but kind find out why: https://github.com/sandeepmistry/bleno/issues/185

bradfol commented 8 years ago

@robotastic where do you think the root cause for this issue is?

Rmannn commented 8 years ago

Same here with ios 9.2

ricky26 commented 7 years ago

Just dug into this a bit, it looks like the check that's failing (in my case) is in the kernel:

         case BDADDR_LE_RANDOM:
                 /* Two most significant bits shall be set */
                 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
                         return false;
                 return true;
         }

The last byte of the MAC we were sending was the /first/ byte when displayed (I guess the address has to be reversed for the BT protocol, but not the Linux management protocol). Reversing iat in the addLongTermKey call in SMP gives a 'command completed' for the load long term keys but the pairing still fails.