Can someone suggest if it is possible in BLE communication to authenticate the central from peripherial before connection is established?
Example:
1) Peripherial Advertises continuously
2) Central discovers Peripherial and sends connection request
3) Connection is Established and Advertising stops
3) Peripherial authenticates central via AES or Pairing etc.
4) If authentication is succesful transfer data.
Either ways once this malicious central has connected to peripherial the Genuine Central will not be able to as each peripherial. If I have understood properly, Peripherial can not end connection or start connection and peripherial do not allow simultaneous connections.
How can I solve this problem? Even if some way of terminating connection from peripherial is made possible, the malicious central will keep reconnecting hence essentially performing DENIAL OF SERVICE(DOS) attack.
Thank You!
You have the sequence slightly wrong. It should be -
Peripheral advertises
Central discovers peripheral and attempts to connect
PIN is requested if central is not already paired
Connection completes if pairing is successful. If not return to state 1
If connection is successful advertising stops and data can be transferred.
So, the security is based on the PIN being kept a secret. If the PIN is well-known (i.e. defaults to 0000) or can be easily discovered (printed/displayed on the device and physical access is possible) then security is compromised.
In theory a DOS attack is also possible by making repeated connection attempts, but this does still leave an opportunity for the legitimate central to connect.
Okay, this is a little late, but anyway: from v515 upwards you can use the AT+TYPEx command to change the authentication behaviour.
x can be, according to the docs:
0:Not need PIN Code (default)
1:Auth not need PIN
2:Auth with PIN
3:Auth and bond
Related
I was looking at this BLE demo for Arduino:
https://github.com/dzindra/BLE-iOS-demo/blob/master/esp32blinky/esp32blinky.ino
I noticed that there is no "Authentication / Authorization" or explicit "Connection code".
The code consists of creating services and characteristics, and advertising them. At best you can see the following callbacks which are triggered when a client connects:
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
Serial.println("Connected");
};
void onDisconnect(BLEServer* pServer) {
Serial.println("Disconnected");
}
};
I was wondering what approach people follow for ensuring that users can connect to an Arduino's BLE only if they are the owner (for example, pressing a button to "trigger" connection mode) etc...
On deeper searching I found :
https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLETests/Arduino/security/BLE_server/BLE_server_passkey/BLE_server_passkey.ino
This other example shows how an ESP32 acting as a client would authenticate into a server:
https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLETests/Arduino/security/BLE_client/BLE_client_passkey/BLE_client_passkey.ino
Both seem to be good examples for how two ESP32's could act as a client / server and authenticate each other. But then how would I get my iPhone to authenticate ? I use the following iPhone example for simply connecting without authentication.
Things seem a bit "hacky", and was wondering if there is an authoritative answer on how to connect to an Arduino BLE with authentication ?
EDIT: Basically, I wan't to prevent random people from just connecting to my BLE Device. I do not need anything more than that (I don't need encryption). I just want to prevent random people from connecting to my device, and breaking my smartphones connection with my BLE Device.
It seems no matter what mechanism you use to verify a valid connection the problem remains that if your BLE device is actually using advertising packets to deliver data, then when someone trys to connect, until you disconnect an unauthorised connection the advertising packet transmission is interrupted.
I use a small window of opportunity to write a correct value to a register otherwise resetting the connection.
I believe I read that the peripheral side cannot terminate a connection?
terminate a connection CBPeripheralManager side
How then, can we authenticate a connection at the application level? We are making an iOS app connect to another iOS app, we only want them to connect to each other. After connection they exchange private-key-based challenge/response questions, and a failure should result in a refusal of the connection. This of course works fine on the central side, if it doesn't get the correct reply it closes the connection. But if the peripheral cant cancel the connection, then how do we prevent a different central from connecting, and staying connected to the peripheral?
When a central connects but does not authenticate correctly, do not respond to requests from it. Every CBATTRequest includes the requesting central, and updateValue(_for:onSubscribedCentrals:) lets you control which centrals you respond to.
If they're not authenticated. Don't talk to them. Or more correctly, send them .insufficientAuthentication to all their requests. If they are well behaved, they will disconnect. If they are badly behaved, there is nothing you can do about that (this is always true; even if you could disconnect them, they could still flood you with connection requests).
You cannot force them to disconnect, however. They may be communicating with another app, and you are not allowed to stop that. You can only refuse to talk to them yourself or send them errors.
I want to understand how the AP provisioning works on a headless device, specifically for IoT applications (I'm developing on a Texas Instruments CC3200). It seems that the universally accepted method of provisioning an IoT device is for the device to act as an AP then the user connects to it in order to send the Wifi AP credentials via smartphone. I'm assuming this could be done via UDP or TCP.
Most of these IoT modules can act as an Access Point OR a Station but not both at the same time. So how does the device know that the Wifi credentials are correct? It must have to shut down the AP that it creates to try and connect to the user's Wifi, right? If the credentials are NOT correct, how does it let the user know on the smartphone side? At this point, the device's AP doesn't exists and the user would have to jump back on it again. What's really happening there?
So how does the device know that the Wifi credentials are correct ?
It have to try if using those credentials AP association is possible. For successful connection SSID, passphrase, encryption type have to be provided. All or some of those information can be already in device memory ie. application can connect only to known SSID.
It must have to shut down the AP that it creates to try and connect to the user's Wifi, right?
Yes. In case of TI CC3200 you can switch mode while application is running.
If the credentials are NOT correct, how does it let the user know on the smartphone side?
It is highly implementation depending. For example, if your IoT device cannot obtain outside world it can switch back to AP mode, what can be detected on the smartphone side. Other solution is that you can send and receive data while in AP mode so it is possible to write server application that will inform smartphone application about the connection state.
At this point, the device's AP doesn't exists and the user would have to jump back on it again. What's really happening there?
Not sure if understand this question. As I mentioned above IoT device knows the state of AP association (TI CC3200 SDK return known values for wide range of errors), if IoT device cannot connected as station using provided credentials it should rollback to AP mode.
I want only trusted devices to connect to my peripheral. And I don't want anyone to be able to discover services and characteristics of my peripheral.
So before connecting to the peripheral I would like to show an alert with a pin code. Is it possible to do it and what is the easiest way?
I couldn't find the answer to this question and tried to implement encrypted characteristic by adding CBAttributePermissionsWriteEncryptionRequired to the permissions:
self.characteristic = [[CBMutableCharacteristic alloc] initWithType:[JUUIDBuilder uuidWith:#"1706"]
properties: CBCharacteristicPropertyWrite
value:nil permissions:CBAttributePermissionsWriteEncryptionRequired];
For some reason it didn't help because I'm able to write values from my second device all the time without any security checks. (Documentation for CBAttributePermissionsReadEncryptionRequired says:
...the characteristic is configured to allow only trusted devices to read or subscribe to its value. When a connected, remote central tries to read or subscribe to this characteristic’s value, Core Bluetooth tries to pair your local peripheral with the central to create a secure connection.
which doesn't make sense to me. What is "trusted devices" here?
Can anyone help me? What is the best practice to allow connections only from trusted devices with pin code confirmation?
You cannot prevent services and characteristics being discovered. You can advertise a primary service and have secondary services that aren't advertised, but once a connection is made all services and characteristics will be revealed.
If you specify that an attribute requires encryption, then a pairing (technically bonding) process will be initiated when you first try to read/write the characteristic. This process exchanges encryption keys and results in the devices 'trusting' each other.
If your peripheral and central are both iOS8 devices, then I have found that if both devices are configured with the same iCloud account then the trust is already established (presumably for functions such handoff) and you will never see the pairing dialog. This caused me quite a bit of confusion when I was trying to test encrypted characteristics.
If you test using devices with different iCloud accounts then you should see the pairing dialog.
Even the pairing process will not "protect" your service/characteristic if the "attacker" has control of both devices as they can simply complete the pairing process. Pairing/bonding does protect the data against eavesdropping as the transfer will be encrypted.
To actually protect the service you would need some form of challenge/response involving a characteristic before exposing data.
For example the central needs to read a value from characteristic "A" which is set at random by the peripheral. The central then needs to calculate the correct response to that value and write it back to "A". Only if this value is correct does the peripheral set values on the remaining characteristics (or accept inputs on the other characteristics from the central).
This solution is only secure as long as your challenge/response mechanism isn't compromised but will probably defeat non-determined attackers.
I have an app that acts as a Bluetooth LE peripheral. I have a single service with four characteristics. 2 out of the 4 are read and write only, the other two are configured as notify.
If I subscribe to one of the "notify" characteristics then the app will not disconnect until I do so manually, works well.
My issue is, If I read or write to the other characteristics, and the then am inactive for around 30 seconds, the BTLE connection disconnects from the peripheral. This may be a limitation set by apple, not sure.
Anyone know of a solution to keep the peripheral active even when there aren't any subscribers and no read or write command has been received in 30 seconds??
This is a by-product of the BLE 4.0 specs. Bluetooth Low Energy is explicitly designed to not maintain a connection for long periods which is what you are describing.
The only way to bypass this (beyond subscribing to a characteristic as you have found) would be to modify the implementation of the BLE stack on the peripheral you are connecting to and removing or elongating the interval of connection to a point that you find satisfactory.
Although this may not help you either as both sides of the BLE communication negotiate these values and iOS may impose a maximum below your requested threshold.
In my case reason was in a mismatch between characteristic properties. I wrote data to a characteristic with "waiting for response" option, but characteristic was in 'without response' state.
The symptom: write callback in delegate does not work when BLE peripheral did not write a response.