This article introduces the Bluetooth security features and terms then summarizes the practical usage of GATT permissions and pairing processes using the Silicon Labs Bluetooth SDK.
The most common threats in wireless communications are:
Bluetooth defines 5 distinct security features against these threats:
These features implemented in different layers of the Bluetooth stack. Let's have a quick look on these.
Bluetooth uses Secure Simple Pairing (SSP) pairing model. The actual pairing process depends on the device I/O capabilities and the security requirements defined by the application.
More details can be found here in the Pairing Processes KBA.
A characteristic may be allowed to be read by any device, but only written by an authenticated device. Similarly, if a characteristic can be written, it does not mean the characteristic can also be read. Each individual characteristic could have different security properties.
Notice: No encryption of broadcast data
Security level is a property of a connection. Using different security features can lead to different security levels per connection. The different levels summarized below.
|Level 1||No security|
|Level 2||Unauthenticated pairing with encryption (paired with just work method)|
|Level 3||Authenticated pairing with encryption (paired with legacy pairing)|
|Level 4||Authenticated Secure Connections pairing with encryption using a 128-bit strength encryption key (Paired with LE secure pairing which is Bluetooth 4.2 feature)|
Public address is fixed and unique to a device Random address can change over time and hides the public address from unwanted devices Bonded devices can resolve the public address
New LE Secure connections feature using Elliptic Curve Diffie-Hellman (ECDH) public-private key pairs for numeric comparison paring method
New numeric comparison paring method. In this pairing method both devices will display a 6-digit passkey. The user must confirm, that the two devices display the same passkey by pressing a button.
Passkey entry and OOB has updated LE Secure Connection variant. But there is no change from application perspective.
LE privacy 1.2 — Identity resolving moved from host to controller for faster and lower power operation
To use the security features you need to do the following steps:
The characteristics access and security properties are defined in the gatt.xml file by the XML attribute properties and its parameters, which must be used inside the characteristic XML attribute tags. Alternatively, Visual GATT Editor can be also used for defining the GATT elements and their permissions. The table below describes the parameters that can be used for defining attribute permissions.
|read||Characteristic can be read by a remote device|
|write||Characteristic can be written by a remote device|
|bonded_read||Reading the characteristic value requires an encrypted link. Devices must also be bonded at least with Just Works pairing|
|bonded_write||Writing the characteristic value requires an encrypted link. Devices must also be bonded at least with Just Works pairing|
|authenticated_read||Reading the characteristic value requires an authentication. In order to read the characteristic with this property the remote device has to be bonded using MITM protection and the connection must be also encrypted|
|authenticated_write||Writing the characteristic value requires an authentication. In order to write the characteristic with this property the remote device has to be bonded using MITM protection and the connection must be also encrypted|
|encrypted_read||Reading the characteristic value requires an encrypted link. iOS 9.1 and newer devices must also be bonded|
|encrypted_write||Writing the characteristic value requires an encrypted link. iOS 9.1 and newer devices must also be bonded|
Here we have 3 example for setting up attribute permissions for a characteristic.
In this case properties ensure that reading and writing the characteristic is without any restriction. It does not require authentication or encrypted link. Any GATT client can read or write it.
Now let's set up the characteristic differently
In this case reading the characteristic is without any restriction. But writing the characteristic requires encrypted link. Characteristics which requires encryption cannot be accessed without pairing. So writing this characteristic in the first time will trigger the pairing process. The pairing can be just works so it is allowed to not have MITM protection.
Now let's modify the characteristic properties again.
In this case reading the reading the characteristic is without any restriction. But writing requires authentication. It means the remote device must be bonded with man in the middle (MITM) protection enabled. So the characteristic cannot be accessed in case of just works pairing used. Writing this characteristic in the first time will trigger the pairing process.
The application shall use the gecko_cmd_sm_configure(flags, io_capabilities) API to set up the security configuration. The io_capabilities and flagsparameters affect the security level with which the devices will use in connection and leads to different pairing mechanisms.
The io_capabilities parameter informs the stack about the possible user input and output method that is available on the device. See the available options here below:
|1||sm_io_capability_displayyesno||Display with Yes/No-buttons|
|3||sm_io_capability_noinputnooutput||No Input and No Output|
|4||sm_io_capability_keyboarddisplay||Display with Keyboard|
The flags parameter controls different application specific security requirements. This parameter gives flexibility to the application to decide how strictly use or not use at all the Bluetooth security features. The table below shows the different options:
|bit 0||0: Allow bonding without MITM protection|
|1: Bonding requires MITM protection|
|bit 1||0: Allow encryption without bonding|
|1: Encryption requires bonding. Note that this setting will also enable bonding.|
|bit 2||0: Allow bonding with legacy pairing|
|1: Secure connections only|
|bit 3||0: Bonding request does not need to be confirmed|
|1: Bonding requests need to be confirmed. Received bonding requests are notified with sm_confirm_bonding events.|
|bit 4 to 7||Reserved|
If the flags parameter is 0, so no application specific requirement set, the pairing method depends only on the IO capabilities of the initiator and the responder device (shown as I and R on the table below).
|Responder/Initiator IO capabilities||Display Only||DisplayYesNo||KeyboardOnly||NoInputNoOutput||KeyboardDisplay|
|Display only||Just Works||Just Works||Passkey Entry(R displays,I inputs)||Just Works||Passkey Entry (R displays,I inputs)|
|DisplayYesNo||Just Works||Numeric Comparison||Passkey Entry (R displays, I inputs)||Just Works||Numeric Comparison|
|KeyboardOnly||Passkey Entry (I displays, R inputs)||Passkey Entry (I displays, R inputs)||Passkey Entry (R and I inputs)||Just Works||Passkey Entry(I displays, R inputs)|
|NoInputNoOutput||Just Works||Just Works||Just Works||Just Works||Just Works|
|KeyboardDisplay||Passkey Entry (I displays, R inputs)||Numeric Comparison||Passkey Entry(R displays, I inputs)||Just Works||Numeric Comparison|
If a device has application specific security requirements (flags parameter is not 0) then the used pairing method and security level of the connection will be different.
Setting the bit 0 forces the MITM protection. In practice it means that our devices will not bond with devices which don't have the io capabilities at least for legacy pairing.
Setting the bit 1 forces link encryption. In practice it means that our devices will always use encrypted link with bonded devices. Note if the bonding table is full therefore the device can't save the new bond.
If both devices support LE Secure Connections, then the value of then bit 2 doesn’t matter. If either one of the devices doesn’t support secure connections i.e. it supports legacy pairing only, then bit 2 comes into play.
If bit 2 set to 1, secure connection is enforced, and the pairing attempt will fail with error code 0x303 (pairing_fail_authentication_requirements error). This is essentially saying that we don’t want to pair with legacy devices. If bit 2 set to 0, the pairing will fall back to legacy pairing methods.
If bit 3 is set then bonding requests need to be confirmed by the application too. This feature gives additional control over incoming bond requests. So the application can reject devices which otherwise could bond. The application notified about the received bonding request by the sm_confirm_bondingstack event.
The application shall accept or reject the bonding request with the cmd_sm_bonding_confirm command.
To enable secure connection (Security Level 2 and above) the application need to allow bonding. The stack provides the gecko_cmd_sm_set_bondable_mode API function to enable or disable the bonding.
Please note if gecko_cmd_sm_configure(flags, io_capabilities) called with flags parameter where bit 1 is set then the bonding enabled automatically.
During application development sometimes it is useful to delete all the bondings to trigger and test the pairing processes. It can be done by the cmd_sm_delete_bondings API.
There are use cases when the application has to manage the bonding table directly. This is out of scope of this article. You can read more about this in a separate KBA.
If the GATT attribute permissions are set correctly the application don't have to increase the security level manually. The security level of the connection will be increased once there is access demand for GATT elements which requires higher security level. If the 2 devices not bonded yet the pairing process also triggered.
However there can be use cases where the application handles the security level of the connections. In those cases it makes sense to call the cmd_sm_increase_security API function in the evt_le_connection_opened event handler.
During the pairing process there are few stack events that the application has to handle otherwise the pairing and bonding will fail. These events are the following.
The evt_sm_passkey_display event indicates a request by stack to display the passkey to the user during the pairing process. The application shall write the passkey to a display given by the event as passkey parameter. This event only can happen if the device has a display. It is defined in its io capabilities. See [the Setting up the security manager](### Setting up the security manager) chapter above.
The evt_sm_passkey_request event indicates a request for the user to enter the passkey displayed on the remote device. The application has to read the passkey then push it to stack by the sm_enter_passkey command.
If the passkey was valid and the bonding completed the stack raise a evt_sm_bonded event. If the passkey was invalid or the bonding failed because of any other reason the stack will raise a evt_sm_bonding_failed event.
This event can happen when the stack is using numeric comparison pairing method. Its indicates a request to display the passkey to the user then asks to confirm that displayed passkey is the same what is displayed on the remote device. The cmd_sm_passkey_confirm has to be called by the application to accept or reject the displayed passkey depending on the users answer.
This event is triggered after the pairing or bonding procedure has been successfully completed.
This event indicates that new bonding request has been received. The application has to call sm_bonding_confirm to accept or reject the incoming bonding request. This feature can be activated by calling the gecko_cmd_sm_configure(flags, io_capabilities) where the bit 2 of the flag parameter is set to 1.