GAP Bond Manager and LE Secure Connections

The GAP Bond Manager is a configurable module that offloads most of the security mechanisms from the application. Table 11. lists the terminology.

Table 11. GAP Bond Manager Terminology
Term Description
Pairing The process of exchanging keys
Encryption Data is encrypted after pairing, or re-encryption (a subsequent connection where keys are looked up from nonvolatile memory).
Authentication The pairing process complete with MITM (Man in the Middle) protection.
Bonding Storing the keys in nonvolatile memory to use for the next encryption sequence.
Authorization An additional application level key exchange in addition to authentication
OOB Out of Band. Keys are not exchanged over the air, but rather over some other source such as serial port or NFC. This also provides MITM protection.
MITM Man in the Middle protection. This prevents an attacker from listening to the keys transferred over the air to break the encryption.
Just Works Pairing method where keys are transferred over the air without MITM

The general process that the GAPBondMgr uses is as follows.

  1. The pairing process exchanges keys through the following methods described in Selection of Pairing Mode.
  2. Encrypt the link with keys from Step 1.
  3. The bonding process stores keys in secure flash (SNV).
  4. Use the keys stored in SNV to encrypt the link when reconnecting.

Tip

Performing all of these steps is not necessary. For example, two devices may choose to pair but not bond.

Selection of Pairing Mode

Bluetooth Core Specification Version 5.0 has support for the Secure Connections feature to enable BLE pairing. For a detailed description of the algorithms used for Secure Connections, see the Security Architecture section ([Vol 1], Part A, Section 5.1) of the Bluetooth Core Specification Version 5.0. The previous pairing methods used in the Bluetooth Core Specification Versions 4.1 and 4.2 are still available, and are now defined as LE legacy pairing. The main difference is that Secure Connection uses Elliptic Curve Diffie-Hellman cryptography, while LE legacy pairing does not.

There are four types of pairing models, each of which are described in detail in GAPBondMgr Examples for Different Pairing Modes:

  • just works (Secure Connections or LE Legacy)
  • passkey entry (Secure Connections or LE Legacy)
  • numeric comparison (Secure Connections)
  • Out of Band (Secure Connections or LE Legacy)

The selection of the association model and whether or not pairing will succeed is based upon the following parameters. The tables below are from the Selecting Key Generation Method section ([Vol 3], Part H, Section 2.3.5.1) of the Bluetooth Core Specification Version 5.0. The GAPBondMgr parameters, as they map to the table parameters below are listed here. For more information on these parameters, see BLE Stack API Reference (GAPBondMgr section).

  • GAPBOND_LOCAL_OOB_SC_ENABLED: OOB Set / Not Set

  • GAPBOND_MITM_PROTECTION: MITM Set / Not Set

  • GAPBOND_IO_CAPABILITIES: IO Capabilities

  • GAPBOND_SECURE_CONNECTION: secure connections supported / not supported

    Beyond what the Bluetooth Core Specification Version 5.0 defines, this parameter also affects whether or not pairing succeeds, as described in BLE Stack API Reference (GAPBondMgr section).

If both devices support secure connections, use Figure 50. to decide upon the next step.

../_images/image136.jpeg

Figure 50. Parameters With Secure Connections.

If at least one device does not support secure connections, use Figure 51. to decide upon the next step.

../_images/image137.jpeg

Figure 51. Parameters Without Secure Connections.

If, based on one of the previous tables, IO capabilities are to be used to determine the association model, use Figure 52.

../_images/image138.jpeg

Figure 52. Parameters With IO Capabilities

Using GAPBondMgr

This section describes what the application must do to configure, start, and use the GAPBondMgr. The GAPRole handles some of the GAPBondMgr functionality. The GAPBondMgr is defined in gapbondmgr.c and gapbondmgr.h. BLE Stack API Reference (GAPBondMgr section) describes the full API including commands, configurable parameters, events, and callbacks.

The general steps to use the GAPBondMgr module are as follows:

  1. Configure the stack to include GAPBondMgr functionality and, if desired, secure connections. Define the following in build_config.opt in the stack project:
    • -DGAP_BOND_MGR
  2. The stack must also be configured to use 1 or 2 SNV pages, by defining OSAL_SNV=1 or OSAL_SNV=2 as a preprocessor-defined symbol in the stack project.
  3. If using Secure Connections, the PDU size must be >= 69. This can be set by defining the following preprocessor symbol in the application project: MAX_PDU_SIZE=69. Also, the minimum heap size that can be used with Secure Connections is 3690.
  4. Configure the GAPBondMgr by initializing its parameters as desired. See BLE Stack API Reference (GAPBondMgr section) for a complete list of parameters with functionality described. There are examples of this for the various pairing / bonding modes in GAPBondMgr Examples for Different Pairing Modes.
  5. Register application callbacks with the GAPBondMgr, so that the application can communicate with the GAPBondMgr and be notified of events.
// Register with bond manager after starting device
GAPBondMgr_Register(&bondmanager_callbacks);

Where bondmanager_callbacks is defined as a structure containing the GAPBondMgr Callbacks.

Note

This should also occur in the application initialization function after the GAPRole profile is started (that is, GAPCentralRole_StartDevice()).

  1. Once the GAPBondMgr is configured, it operates mostly autonomously from the perspective of the application. When a connection is established, it initiates pairing and bonding, depending on the configuration parameters set during initialization, and communicates with the application as needed through the defined callbacks.

    A few parameters can be set and functions called asynchronously at any time from the application. See BLE Stack API Reference (GAPBondMgr section) for more information.

    Most communication between the GAPBondMgr and the application at this point occurs through the callbacks which were registered in Step 5. Figure 53. is a flow diagram example of the GAPBondMgr notifying the application that pairing has been completed. The same method occurs for various other events and will be expanded upon in the following section.

@startuml
  participant Application
  participant Gapbondmgr as "GAPBondMgr"
  participant BLEStack as "BLE Stack"

  BLEStack -> Gapbondmgr : GAP_AUTHENTICATION_\nCOMPLETE_EVENT
  Gapbondmgr -> Application : Pairing state callback
  Application-> Application : SimpleBLECentral_pairStateCB
  Application-> Application : SimpleBLECentral_enqueueMsg
  Application-> Application : SimpleBLECentral_processAppMsg
  rnote over "Application"
    SBC_PAIRING_STATE_EVT
  end note
  Application-> Application : SimpleBLECentral_processPairState
  rnote over "Application"
    GAPBOND_PAIRING_STATE_COMPLETE
  end note

@enduml

Figure 53. GapBondMgr Callback Example.

GAPBondMgr Examples for Different Pairing Modes

This section provides message diagrams for the types of security that can be implemented. These modes assume acceptable I/O capabilities are available for the security mode, and that the selection of whether or not to support Secure Connections allows for the pairing mode. See the Selection of Pairing Mode on how these parameters affect pairing. These examples only consider the pairing aspect. Bonding can be added to each type of pairing in the same manner and is shown in the next section.

Caution

The code snippets here are not complete functioning examples, and are only intended for illustration purposes.

Pairing Disabled

With pairing set to FALSE, the BLE stack automatically rejects any attempt at pairing. Configure the GAPBondMgr as follows to disable pairing:

uint8 pairMode = GAPBOND_PAIRING_MODE_NO_PAIRING;
GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode);

Just Works Pairing

Just Works pairing allows encryption without MITM authentication and is vulnerable to MITM attacks. Just Works pairing can be LE Legacy or Secure Connections pairing. The GAPBondMgr does not need any additional input from the application for just works pairing. Configure the GAPBondMgr for Just Works pairing as follows.

uint8_t pairMode = GAPBOND_PAIRING_MODE_INITIATE;
uint8_t mitm = FALSE;
GAPBondMgr_SetParameter( GAPBOND_PAIRING_MODE, sizeof (uint8_t), &pairMode);
GAPBondMgr_SetParameter( GAPBOND_MITM_PROTECTION, sizeof (uint8_t), &mitm);

Figure 54. describes the interaction between the GAPBondMgr and the application for Just Works pairing. As shown, the application receives a GAPBOND_PAIRING_STATE_STARTED event once the pairing request has been sent, and a GAPBOND_PAIRING_STATE_COMPLETE event once the pairing process has been completed. At this time, the link is encrypted.

 @startuml

  participant Application
  participant GAPRole
  participant Gapbondmgr as "GAPBondMgr"
  participant BLEStack as "BLE Stack"

  BLEStack -> GAPRole : GAP_LINK_ESTABLISHED_EVENT
  GAPRole -> Gapbondmgr : GAPBondMgr_LinkEst()
  Gapbondmgr -> BLEStack : GAP_Authenticate()
  BLEStack -->] : Pairing req
  Gapbondmgr -> Application : Pairing state callback
  rnote over Application
  GAPBOND_PAIRING_
  STATE_STARTED
  end note

  BLEStack -->] : Encryption req
  BLEStack <--] : Encryption rsp
  BLEStack -> Gapbondmgr : GAP_AUTHENTICATION_\nCOMPLETE_EVENT
  Gapbondmgr -> Application : Pairing state callback
  rnote over Application
  GAPBOND_PAIRING_
  STATE_COMPLETE
  end note
@enduml

Figure 54. Just Works Pairing.

Passcode Entry

Passkey entry is a type of authenticated pairing that can prevent MITM attacks. It can be either LE Legacy pairing or Secure Connections pairing. In this pairing method, one device displays a 6-digit passcode, and the other device enters the passcode. As described in Selection of Pairing Mode, the IO capabilities decide which device performs which role. The passcode callback registered with the GAPBondMgr when it was started is used to enter or display the passcode. The following is an example of initiating Passcode Entry pairing where the passcode is displayed.

  1. Define passcode callback
Listing 67. Define passcode callback.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Bond Manager Callbacks
static gapBondCBs_t security_examples_central_bondCB =
{
  (pfnPasscodeCB_t)security_examples_central_passcodeCB, //Passcode callback
  security_examples_central_pairStateCB                  //Pairing state callback
};

static void security_examples_central_passcodeCB(uint8_t *deviceAddr, uint16_t connHandle, uint8_t uiInputs, uint8_t uiOutputs, uint32_t numComparison)
{
  gapPasskeyNeededEvent_t *pData; // Allocate space for the passcode event.

  if ((pData = ICall_malloc(sizeof(gapPasskeyNeededEvent_t))))
  {
    memcpy(pData->deviceAddr, deviceAddr, B_ADDR_LEN);
    pData->connectionHandle = connHandle;
    pData->uiInputs = uiInputs;
    pData->uiOutputs = uiOutputs;

    // Enqueue the event.
    security_examples_central_enqueueMsg(SEC_PASSCODE_NEEDED_EVT, 0, (uint8_t *) pData);
  }
}
  1. Configure GAPBondMgr
Listing 68. Configure GAPBondMgr for MITM.
1
2
3
4
uint8_t pairMode = GAPBOND_PAIRING_MODE_INITIATE;
uint8_t mitm = TRUE;
GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &uint8_t pairMode = GAPBOND_PAIRING_MODE_INITIATE;
GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &mitm);
  1. Process passcode callback and send response to stack
Listing 69. Process passcode and send the response.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
static void security_examples_central_processPasscode(uint16_t connectionHandle, gapPasskeyNeededEvent_t *pData)
{

  if (pData->uiInputs) // if we are to enter passkey
  {
    passcode = 111111;
    // Send passcode response
    GAPBondMgr_PasscodeRsp(connectionHandle, SUCCESS, passcode);
  }

  else if (pData->uiOutputs) // if we are to display passkey
  {
    passcode = 111111;
    DISPLAY_WRITE_STRING_VALUE("Passcode: %d", passcode, LCD_PAGE4);

    // Send passcode response
    GAPBondMgr_PasscodeRsp(connectionHandle, SUCCESS, passcode);
  }
}

Depending on what the uiInputs and uiOutputs returned from the GAPBondMgr, the passcode must either be displayed or entered. The passcode is then sent to the GAPBondMgr using GAPBondMgr_PasscodeRsp(), so that pairing can continue. In this case, the password is statically set to 111111. In a real product, the password will likely be randomly generated, and the device must expose a way for the user to enter the passcode, then send it to the GAPBondMgr using GAPBondMgr_PasscodeRsp(). An example interaction between the GAPBondMgr and the application is shown in Figure 55..

 @startuml
  participant Application
  participant GAPRole
  participant Gapbondmgr as "GAPBondMgr"
  participant BLEStack as "BLE Stack"

  BLEStack -> GAPRole : GAP_LINK_ESTABLISHED_EVENT
  GAPRole -> Gapbondmgr : GAPBondMgr_LinkEst()
  Gapbondmgr -> BLEStack : GAP_Authenticate()
  BLEStack -->] : Pairing req
  Gapbondmgr -> Application : Pairing state callback

  rnote over Application
  GAPBOND_PAIRING_
  STATE_STARTED
  end note

  BLEStack -> Gapbondmgr : GAP_PASSKEY_NEEDED_\nEVENT
  Gapbondmgr -> Application : Passcode callback
  [--> Application : Enter or display\npasscode
  Application -> Gapbondmgr : GAPBondMgr_PasscodeRsp()
  Gapbondmgr -> BLEStack : GAP_PasscodeUpdate()
  BLEStack -->] : Encryption req
  BLEStack <--] : Encryption rsp
  BLEStack -> Gapbondmgr : GAP_AUTHENTICATION_\nCOMPLETE_EVENT
  Gapbondmgr -> Application : Pairing state callback

  rnote over Application
  GAPBOND_PAIRING_
  STATE_COMPLETE
  end note
@enduml

Figure 55. Interaction Between the GAPBondMgr and the Application when exchanging passcode.

Numeric Comparison

Numeric comparison is a type of authenticated pairing that protects from MITM attacks. It is only possible as a Secure Connections pairing; not LE legacy. For numeric comparison pairing, both devices display a 6-digit code. Each device must then indicate, through a button press or some other yes-no input, whether the codes match. The passcode callback registered with the GAPBondMgr when it was started is used to display the 6-digit code. The following is an example of initiating Numeric Comparison pairing where the passcode is displayed. The IO capabilities must be set appropriately to select numeric comparison (that is, Display/Yes-No on both sides).

  1. Define passcode callback to display code.
Listing 70. Define passcode callback to display code.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// Bond Manager Callbacks
static gapBondCBs_t SimpleBLECentral_bondCB =
{
  (pfnPasscodeCB_t)SimpleBLECentral_passcodeCB, //Passcode callback
  SimpleBLECentral_pairStateCB                  //Pairing state callback
};

static void SimpleBLECentral_passcodeCB (uint8_t *deviceAddr, uint16_t connHandle, uint8_t uiInputs, uint8_t uiOutputs, uint32_t numComparison)
{
  gapPasskeyNeededEvent_t *pData;

  // Allocate space for the passcode event.
  if ((pData = ICall_malloc(sizeof(gapPasskeyNeededEvent_t))))
  {
    memcpy(pData->deviceAddr, deviceAddr, B_ADDR_LEN);
    pData->connectionHandle = connHandle;
    pData->numComparison = numComparison;

    // Enqueue the event.
    security_examples_central_enqueueMsg(SEC_PASSCODE_NEEDED_EVT, 0, (uint8_t *) pData);
  1. Configure GAPBondMgr
Listing 71. Configure GAPBondMgr For Secure Connections + Authentication.
1
2
3
4
5
6
7
8
9
uint8_t pairMode = GAPBOND_PAIRING_MODE_INITIATE;
uint8_t scMode = GAPBOND_SECURE_CONNECTION_ONLY;
uint8_t mitm = TRUE;
uint8_t ioCap = GAPBOND_IO_CAP_DISPLAY_YES_NO;

GAPBondMgr_SetParameter(GAPBOND_IO_CAPABILITIES, sizeof(uint8_t), &ioCap);
GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode);
GAPBondMgr_SetParameter(GAPBOND_MITM_PROTECTION, sizeof(uint8_t), &mitm);
GAPBondMgr_SetParameter(GAPBOND_SECURE_CONNECTION, sizeof(uint8_t), &scMode);
  1. Process passcode callback and display code.
Listing 72. Process passcode callback and display code.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
static void SimpleBLECentral_processPasscode (uint16_t connectionHandle, gapPasskeyNeededEvent_t *pData)
{

  if (pData->numComparison) //numeric comparison
  {

    //Display passcode
    DISPLAY_WRITE_STRING_VALUE("Num Cmp: %d", pData->numComparison, LCD_PAGE4);
  }
}
  1. Accept Yes-No input from user and send response to GAPBondMgr.
Listing 73. Accept Yes-No input from user and send response to GAPBondMgr.
1
2
3
4
5
6
if (keys & KEY_RIGHT)
{
  GAPBondMgr_PasscodeRsp(connHandle, SUCCESS, TRUE);
  DISPLAY_WRITE_STRING("Codes Match!", LCD_PAGE5);
  return;
}

In this case, the third parameter of GAPBondMgr_PasscodeRsp, which usually accepts a passcode, is overloaded to send TRUE to the stack to indicate that the codes match and to continue with pairing. The process of numeric comparison is illustrated in Figure 56..

 @startuml
  participant Application
  participant GAPRole
  participant Gapbondmgr as "GAPBondMgr"
  participant BLEStack as "BLE Stack"

  BLEStack -> GAPRole : GAP_LINK_ESTABLISHED_EVENT
  GAPRole -> Gapbondmgr : GAPBondMgr_LinkEst()
  Gapbondmgr -> BLEStack : GAP_Authenticate
  BLEStack -->] : Pairing req
  Gapbondmgr -> Application : Pairing state callback
  rnote over Application
  GAPBOND_PAIRING_
  STATE_STARTED
  end note

  BLEStack -> Gapbondmgr : GAP_PASSKEY_\nNEEDED_EVENT
  Gapbondmgr -> Application : Passcode callback

  [<-- Application : Display code
  [--> Application : Codes match

  Application -> Gapbondmgr : GAPBondMgr_PasscodeRsp()
  Gapbondmgr -> BLEStack : GAP_PasscodeUpdate()

  BLEStack -->] : Encryption req
  BLEStack <--] : Encryption rsp
  BLEStack -> Gapbondmgr : GAP_AUTHENTICATION_\nCOMPLETE_EVENT
  Gapbondmgr -> Application : Pairing state callback
  rnote over Application
  GAPBOND_PAIRING_
  STATE_COMPLETE
  end note
@enduml

Figure 56. Numeric Comparison.

GAPBondMgr Example With Bonding Enabled

Bonding can enabled or disabled for any type of pairing through the GAPBOND_BONDING_ENABLED parameter, and occurs after the pairing process is complete. To enable bonding, configure the GAPBondMgr as follows:

uint8_t bonding = TRUE;
GAPBondMgr_SetParameter(GAPBOND_BONDING_ENABLED, sizeof(uint8_t), &bonding);

With bonding enabled, the GAPBondMgr stores the long-term key transferred during the pairing process to SNV. See GAPBondMgr and SNV for more information. After this is completed, the application is notified through the GAPBOND_PAIRING_STATE_COMPLETE event. GAPBOND_PAIRING_STATE_BOND_SAVED is only passed to the application pair state callback when initially connecting, pairing, and bonding. For future connections to a bonded device, the security keys are loaded from flash, thus skipping the pairing process. In this case, only GAPBOND_PAIRING_STATE_BONDED is passed to the application pair state callback. This is illustrated in Figure 57.

 @startuml

  participant Application
  participant GAPRole
  participant Gapbondmgr as "GAPBondMgr"
  participant BLEStack as "BLE Stack"

  BLEStack -> GAPRole : GAP_LINK_ESTABLISHED_EVENT
  GAPRole -> Gapbondmgr : GAPBondMgr_LinkEst()
  Gapbondmgr -> BLEStack : GAP_Authenticate
  BLEStack -->] : Pairing req
  Gapbondmgr -> Application : Pairing state callback
  rnote over Application
  GAPBOND_PAIRING_
  STATE_STARTED
  end note

  == This section will vary depending on the pairing type.\nSee above examples for more information. ==

  BLEStack -->] : Encryption req
  BLEStack <--] : Encryption rsp
  BLEStack -> Gapbondmgr : GAP_AUTHENTICATION_\nCOMPLETE_EVENT

  rnote over Gapbondmgr
  Save bond info in SNV
  end note

  Gapbondmgr -> Application : Pairing state callback
  rnote over Application
  GAPBOND_PAIRING_
  STATE_COMPLETE
  end note

  rnote over Application
  GAPBOND_PAIRING_
  STATE_BOND_SAVED
  end note

  == Eventually the connection may be terminated and re-established. ==

  BLEStack -> GAPRole : GAP_LINK_ESTABLISHED_EVENT
  GAPRole -> Gapbondmgr : GAPBondMgr_LinkEst()

  rnote over Gapbondmgr
  Read bond info from SNV.
  end note

  Gapbondmgr -> BLEStack : GAP_Bond()
  BLEStack -->] : Encryption req
  BLEStack <--] : Encryption rsp
  BLEStack -> Gapbondmgr : GAP_BOND_COMPLETE_\nEVENT
  Gapbondmgr -> Application : Pairing state callback
  rnote over Application
  GAPBOND_PAIRING_
  STATE_BONDED
  end note


@enduml

Figure 57. GAPBondMgr Example With Bonding Enabled.

GAPBondMgr and SNV

This section describes how the GAPBondMgr uses the SNV flash area for storing bonding information. For more information on SNV itself, see Flash. The amount of bonds that can be stored is set by the GAP_BONDINGS_MAX definition, which is set to 10 by default in gapbondmgr.h. The functionality of the GAPBondMgr when there are no more available bonds varies based on whether the “least recently used” scheme is enabled. See BLE Stack API Reference (GAPBondMgr section) for more information on the GAPBOND_LRU_BOND_REPLACEMENT parameter. If this parameter is set to false, it is not possible to add any more bonds without manually deleting a bond. If the parameter is set to true, the least recently used bond is deleted to make room for the new bond.

The following components comprise one bonding entry:

  1. Bond Record: this consists of the peer’s address, address type, privacy reconnection address, and state flags. This comprises 14 bytes and is defined as such:
typedef struct
{
  uint8   publicAddr[B_ADDR_LEN];     // Peer's address
  uint8   publicAddrType;             // Peer's address type
  uint8   reconnectAddr[B_ADDR_LEN];  // Privacy Reconnection Address
  uint8   stateFlags;                 // State flags: @ref GAP_BONDED_STATE_FLAGS
} gapBondRec_t;
  1. Client Characteristic Configurations (CCC): the amount of CCCs stored in each entry are set by the GAP_CHAR_CFG_MAX define. This is set to 4 by default. Each CCC is comprised of 4-bytes and is defined as follows:
typedef struct
{
  uint16 attrHandle;  // attribute handle
  uint8  value;       // attribute value for this device
} gapBondCharCfg_t;
  1. Local Long Term Key (LTK) info: this stores the local device’s encryption information. This comprises 28 bytes and is composed as such:
typedef struct
{
  uint8   LTK[KEYLEN];              // Long Term Key (LTK)
  uint16  div;  //lint -e754        // LTK eDiv
  uint8   rand[B_RANDOM_NUM_SIZE];  // LTK random number
  uint8   keySize;                  // LTK key size
} gapBondLTK_t;
  1. Connected Device Long Term Key Info: this stores the connected device’s encryption information. This is also a gapBondLTK_t and comprises 28 bytes.
  2. Connected Device Identity Resolving Key (IRK): this stores the IRK generated during pairing. This is a 16-byte array.
  3. Connected Device Sign Resolving Key (SRK): this stores the SRK generated during pairing. This is a 16-byte array.
  4. Connected Device Sign counter: this stores the sign counter generated during pairing. This is a 4-byte word.

Privacy

BLE5-Stack supports the privacy feature as defined by the Bluetooth Core Specification Version 5.0 (Vol 6, Part B, Section 6) and is always compiled into the BLE5-Stack libraries. The privacy feature greatly reduces the ability for a scanner to track broadcasting Bluetooth low energy devices over a period of time. This is accomplished by allowing broadcasting devices to frequently change their advertising address (every 15 minutes is recommended).

The following terms are used throughout the Privacy section. It’s suggested to review these terms before continuing.

The privacy feature is hugely implemented in the Link Layer of the controller, however it requires interaction with the host to determine how the Link Layer should handle connection and scan requests. As described in the Bluetooth Core Specification Version 5.0 (Vol 1, Park A, Section 5.4.5), there are two modes of privacy: device privacy mode and network privacy mode:

In Device Privacy Mode, a local device is only concerned with its own privacy. This means that it will accept advertising/scan/connection packets from peer devices that use their Identity Address (IA) or a Resolvable Private Address (RPA) even if both devices have distributed their Identity Resolving Keys (IRK) with oneanother. A local device may use this mode with a peer device if the peer device does not have the Resolvable Private Address Only (RPAO) GATT characteristic.

In Network Privacy Mode, a local device respects the privacy of a bonded peer device. The local device shall only accept advertising/scan/connection packets from peer devices that contain a Resolvable Private Address (RPA) if both devices have distributed their Identity Resolving Keys (IRK). In Bluetooth Core Specification Version 5.0, Network Privacy Mode is the default privacy mode.

Resolvable Private Addresses

A Resolvable Private Address (RPA) is a device address that is generated using an Identity Resolving Key (IRK). This key is exchanged during Phase 3 of the bonding procedure along with the peer device’s Identity Address. From this point on, given that a peer has a valid IRK and supplies a Resolvable Private Address, the peer device can resolve this RPA into the associated Identity Address. The Resolvable Private Address of a peer device never known to the host of the local device. Instead, the host is only given the associated peer’s Identity Address.

A BLE5-Stack application can use a RPA device address by calling the GAP_ConfigDeviceAddr() function. This API must be called after the GAP layer has been initialized and before attempting to start discovery or advertising. See Listing 74.

Listing 74. Enabling peripheral role to use Resolvable Private Addresses
static void gapRole_processGAPMsg(gapEventHdr_t *pMsg)
{
  ...

  switch (pMsg->opcode)
  {
    case GAP_DEVICE_INIT_DONE_EVENT:
      {
        gapDeviceInitDoneEvent_t *pPkt = (gapDeviceInitDoneEvent_t *)pMsg;
        bStatus_t stat = pPkt->hdr.status;

        if (stat == SUCCESS)
        {
          ...

          gapRole_state = GAPROLE_STARTED;

          stat = GAP_ConfigDeviceAddr(ADDRMODE_PRIVATE_RESOLVE, NULL);

          if (stat != SUCCESS)
          {
              System_abort("Could not enable RPA!");
          }

          stat = GAP_SetParamValue( TGAP_PRIVATE_ADDR_INT , 5);

          if (stat != SUCCESS)
          {
              System_abort("Could not set private address timeout!");
          }

          // Update the advertising data
          stat = GAP_UpdateAdvertisingData(selfEntity,
                              TRUE, gapRole_AdvertDataLen, gapRole_AdvertData);
        }

        if (stat != SUCCESS)
        {
          gapRole_state = GAPROLE_ERROR;
        }

        notify = TRUE;
      }
      break;

      ...

Resolvable Private Address Timeout

When using an RPA, the Bluetooth Core Specification Version 5.0 recommends a timeout interval of 15 minutes before the device changes its device address. This can be changed via the TGAP_PRIVATE_ADDR_INT parameter in GAP_SetParamValue().

Listing 75. Changing the minimum time interval between RPA changes
static void gapRole_processGAPMsg(gapEventHdr_t *pMsg)
{
  ...

  switch (pMsg->opcode)
  {
    case GAP_DEVICE_INIT_DONE_EVENT:
      {
        gapDeviceInitDoneEvent_t *pPkt = (gapDeviceInitDoneEvent_t *)pMsg;
        bStatus_t stat = pPkt->hdr.status;

        if (stat == SUCCESS)
        {
          ...

          gapRole_state = GAPROLE_STARTED;

          stat = GAP_ConfigDeviceAddr(ADDRMODE_PRIVATE_RESOLVE, NULL);

          if (stat != SUCCESS)
          {
              System_abort("Could not enable RPA!");
          }

          stat = GAP_SetParamValue( TGAP_PRIVATE_ADDR_INT , 5);

          if (stat != SUCCESS)
          {
              System_abort("Could not set private address timeout!");
          }

          // Update the advertising data
          stat = GAP_UpdateAdvertisingData(selfEntity,
                              TRUE, gapRole_AdvertDataLen, gapRole_AdvertData);
        }

        if (stat != SUCCESS)
        {
          gapRole_state = GAPROLE_ERROR;
        }

        notify = TRUE;
      }
      break;

      ...

Resolving List

The privacy feature is only effective on devices that contain a valid bond with another device. Once bonded with a peer device, if the local device receives incoming Link Layer events from the peer device that is using a Resolvable Private Address, then the local device will try to resolve this address into an Identity Address. To do so, each device’s link layer maintains a Bluetooth Core Specification Version 5.0 defined table known as a Resolving List. Upon reset, the Resolving List is empty and it’s up to the host to add and remove devices from the Resolving List. This is automatically handled for the application when using the GAPBondMgr.

As defined by the Bluetooth Core Specification Version 5.0, a resolving list record entry consists of the following:

  • a Local IRK
  • a Peer IRK
  • an Identity Address
  • a RPAO flag

In the case in which a local device receive a link layer event from a peer device that used a Resolvable Private Address which is not in the Resolving List, then the link layer may pass such link events to the host for further resolution (if permitted by the White List).

Note

Some android and iOS devices use a Resolvable Private Address when initiating a connection to a device that it has never previously bonded with. Since the advertiser doesn’t have a valid IRK stored in its Resolving List, the advertiser cannot resolve the device address and it will defer to the host for further action.

White List

The host also has the option to configure a filter policy in a White List which is also in the controller’s link layer. When enabled, policies can be set to filter out Link Layer events after they were processed by the Resolving List. If the local device or peer device wishes, it can initiate a bonding sequence to exchange the IRKs as well as their Identity Addresses. If these are exchanged, the host can use those parameters to update the controller’s Resolving List and the White List so that the controller can automatically process future connection or scan events.

The intent for the White List mechanism is to reduce power consumption. By removing undesirable Link Layer events at the controller, the host can remain in low power modes.

Allowing GAPBondMgr to automatically add bonded devices into the White List

The GAPBondMgr can be configured to have bonded device automatically added to the controller’s White List as shown in Listing 76.

Listing 76. Automatically add bonded devices to the White List
// Setup the GAP Bond Manager
{
    uint32_t passkey = 0; // passkey "000000"
    uint8_t pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;
    uint8_t mitm = TRUE;
    uint8_t ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;
    uint8_t bonding = TRUE;
    uint8_t autoSyncWhiteList = TRUE;

    GAPBondMgr_SetParameter(GAPBOND_DEFAULT_PASSCODE, sizeof(uint32_t),
                            &passkey);
    GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode);
    GAPBondMgr_SetParameter(GAPBOND_MITM_PROTECTION, sizeof(uint8_t), &mitm);
    GAPBondMgr_SetParameter(GAPBOND_IO_CAPABILITIES, sizeof(uint8_t), &ioCap);
    GAPBondMgr_SetParameter(GAPBOND_BONDING_ENABLED, sizeof(uint8_t), &bonding);
    GAPBondMgr_SetParameter(GAPBOND_AUTO_SYNC_WL, sizeof(uint8_t), &autoSyncWhiteList);
}

Network Privacy Mode vs. Device Privacy Mode

A device can interact with a peer device exclusively in Network Privacy Mode or exclusively Device Privacy Mode, not both. The mode is determined during Phase 3 of the bonding procedure. After the devices exchange each others’ IRK, each local device will try to read peer’s Resolvable Private Address Only characteristic via a GATT_ReadUsingCharUUID(). If a GATT_MSG_EVENT with a ATT_READ_BY_TYPE_RSP is generated, then the local device understands that the peer device is in Network Privacy mode. However, if a GATT_MSG_EVENT response with a ATT_ERROR_RSP is generated, then the local device will interact with the device in Device Privacy Mode.

In Device Privacy Mode, a local device is only concerned in protecting its own privacy once the device has a valid bond with a peer device. Privacy in this mode is comparable to the privacy 1.2 in Bluetooth Core Specification 4.2. After a peer and local device have bonded, a local device can accept (given that white list filter policy allows it) connections with a peer using a Resolvable Private Address or its Identity Address as its device address.

In Bluetooth Core Specification Version 5.0, Network Privacy Mode has been added. In this mode, a device is concerned to respect the the privacy of peer. After a peer and local device have bonded, a local device will only accept (given that white list filter policy allow) connections with a peer device if uses a Resolvable Private Address as its device address.

For BLE5-Stack project to use Network Privacy Mode, the GAPBondMgr requires the stack’s GATT client to read the peer device’s Resolvable Private Address Only characteristic. In order to accomplish this, the stack must be built with GATT_NO_CLIENT compiler option disabled so that the GATT client is included.

Enabling Privacy in BLE5-Stack

1. Enable the GATT client.

The application must have the GATT client to read the Resolvable Private Address Only characteristic. If GATT_NO_CLIENT is defined in the project’s predefined symbols, remove it. See Accessing Preprocessor Symbols in CCS or Accessing Preprocessor Symbols in IAR on how to change predefined project symbols.

2. Configure device to use Resolvable Private Addresses.

Add the code snippet highlighted in Listing 74. on how to use a Resolvable Private Address.

Optionally, add the code snippet highlighted in Listing 75. to change the timeout interval in which the controller changes its Resolvable Private Address.