Mistake on this page?
Report an issue in GitHub or email us


SecurityManager deals with authentication and encryption for the Bluetooth Low Energy link. The pairing and optionally bonding processes provide this. The SecurityManager achieves bonding by saving the pairing information and reusing it on subsequent reconnections. This saves time because the pairing does not have to be performed again.

The pairing process may produce a set of keys to be used during current or later connections. The SecurityManager handles these, and they include the Long Term Encryption Key (LTK), the Identity Resolving Key (IRK) and the Connection Signature Resolving Key (CSRK). The SecurityManager uses the LTK to encrypt subsequent connections without having to pair again. The Link Controller uses IRK to identify peers who use random resolvable addresses. The application uses CSRK to sign and authenticate signed data.

The pairing process may provide man-in-the-middle protection (MITM). The SecurityManager achieves this through various means, including out of band communication, depending on the capabilities of the local and peer device.

The SecurityManager stores the keys, permanently if possible, to speed security requests on subsequent connections.

Security requests may come explicitly from the user application or implicitly from the GATT server based on attribute requirements.


There are several ways to provide different levels of security during pairing depending on your requirements and the facilities the application provides. The process starts with initializing the SecurityManager with default options for new connections. You can later change some settings per link or globally.

The important settings in the init() function are the MITM requirement and IO capabilities. MITM protection prevents an attack where one device can impersonate another device by pairing with both devices at the same time. You can achieve this protection by sharing information between the devices through an independent channel. The IO capabilities of both devices dictate what algorithm is used. For details, see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part H - You can change the IO capabilities after initialization with setIoCapability(). This takes effect for all subsequent pairings.

Secure Connections, which relies on elliptical curve cryptography, provides the most secure pairing. Support for Secure Connections depends on both the stack and controller on both sides supporting it. If either side doesn't support it, legacy pairing is used. This is an older standard of pairing. If you require higher security, you can disable legacy pairing by calling allowLegacyPairing(false);.

Out of band (OOB) data used in pairing

Sharing this information through IO capabilities means user interaction, which limits the degree of protection due to the limit of the amount of data that you can expect to transfer. Another solution is using out of band (OOB) communication to transfer this data. OOB communication can send more data and make MITM attacks less likely to succeed. The application must exchange OOB data and provide it to the SecurityManager. Use setOOBDataUsage() to indicate you want to use it. With this same call, you can set whether the communication channel you are using to transmit the OOB data is itself secure against MITM protection - this sets the level of the link security achieved using pairing that uses this data.


Applications may require a level of security providing confidence that data transfers are coming from a trusted source. You can achieve this by encrypting the link, which also provides added confidentiality. Encryption is a good choice when a device stays connected but introduces latency due to the need for encrypting the link if the device only connects periodically to transfer data. If you do not require confidentiality, the GATT server may allow writes to happen over an unencrypted link but authenticated by a signature present in each packet. This signature relies on having sent a signing key to the peer during pairing prior to sending any signed packets.

Persistence of security information

SecurityManager stores all the data required for its operation on active links. Depending on resources available on the device, it also stores data for disconnected devices, which have bonded to be reused when reconnected. If the application has initialized a file system and the SecurityManager has received a file path during the init() call, SecurityManager may also provide data persistence across resets. You must enable this by calling preserveBondingStateOnReset(). Persistence may fail if abnormally terminated. SecurityManager may also fall back to a nonpersistent implementation if the resources are too limited.

How to use

Call init() with your chosen settings before calling any other SecurityManager functions.

The SecurityManager communicates with your application through events. These trigger calls in the EventHandler that you must provide by calling the setSecurityManagerEventHandler() function.

The most important process is pairing. You may trigger this manually by calling requestPairing(). Pairing may also result from the application requiring encryption by calling setLinkEncryption() or the application requiring MITM protection through requestAuthentication().

You can call all of these implicitly by using setLinkSecurity() to set the required security for the link. The SecurityManager triggers the process required to achieve the set security level. You can only escalate the security level; asking the SecurityManager for a lower security level than the existing one does not fail, but results in an event informing the application through linkEncryptionResult() of the current level (which remains unchanged).

The chosen pairing algorithms depend on the IO capabilities and OOB use settings. They produce appropriate events, which your EventHandler must handle. If your event handler doesn't support all the calls, you must not set IO capabilities or set OOB use in such a way that would trigger them, or else the pairing fails (usually by timing out).

The simplest example is a pairing of a device with no IO capabilities and no OOB data available. This does not provide any MITM protection. The pairing (triggered implicitly or called explicitly) results in the generation of an event on the peer calling pairingRequest(). The event handler must make a decision (either in the application itself or based on user interaction) whether to accept the pairing and call acceptPairing() or cancelPairing(). An event calling pairingResult() in the EventHandler communicates te result on both peers.

SecurityManager class reference

Data Structures
class  EventHandler
 The stack will use these functions to signal events to the application, subclass to override handlers. More...
Public Types
typedef uint8_t Passkey_t[PASSKEY_LEN]
 6-digit passkey in ASCII ('0'-'9' digits only). More...
Public Member Functions
virtual ble_error_t init (bool enableBonding=true, bool requireMITM=true, SecurityIOCapabilities_t iocaps=IO_CAPS_NONE, const Passkey_t passkey=NULL, bool signing=true, const char *dbFilepath=NULL)
 Enable the BLE stack's Security Manager. More...
virtual ble_error_t setDatabaseFilepath (const char *dbFilepath=NULL)
 Change the file used for the security database. More...
virtual ble_error_t reset (void)
 Notify all registered onShutdown callbacks that the SecurityManager is about to be shutdown and clear all SecurityManager state of the associated object. More...
virtual ble_error_t preserveBondingStateOnReset (bool enable)
 Normally all bonding information is lost when device is reset, this requests that the stack attempts to save the information and reload it during initialisation. More...
virtual ble_error_t purgeAllBondingState (void)
 Delete all peer device context and all related bonding information from the database within the security manager. More...
virtual ble_error_t generateWhitelistFromBondTable (Gap::Whitelist_t *whitelist) const
 Create a list of addresses from all peers in the bond table and generate an event which returns it as a whitelist. More...
virtual ble_error_t requestPairing (ble::connection_handle_t connectionHandle)
 Request pairing with the peer. More...
virtual ble_error_t acceptPairingRequest (ble::connection_handle_t connectionHandle)
 Accept the pairing request. More...
virtual ble_error_t cancelPairingRequest (ble::connection_handle_t connectionHandle)
 Reject pairing request if the local device is the slave or cancel an outstanding pairing request if master. More...
virtual ble_error_t setPairingRequestAuthorisation (bool required=true)
 Tell the stack whether the application needs to authorise pairing requests or should they be automatically accepted. More...
virtual ble_error_t allowLegacyPairing (bool allow=true)
 Allow of disallow the use of legacy pairing in case the application only wants to force the use of Secure Connections. More...
virtual ble_error_t getSecureConnectionsSupport (bool *enabled)
 Check if the Secure Connections feature is supported by the stack and controller. More...
virtual ble_error_t setIoCapability (SecurityIOCapabilities_t iocaps)
 Set the IO capability of the local device. More...
virtual ble_error_t setDisplayPasskey (const Passkey_t passkey)
 Set the passkey that is displayed on the local device instead of using a randomly generated one. More...
virtual ble_error_t setLinkSecurity (ble::connection_handle_t connectionHandle, SecurityMode_t securityMode)
 Set the security mode on a connection. More...
virtual ble_error_t setKeypressNotification (bool enabled=true)
 Set whether or not we want to send and receive keypress notifications during passkey entry. More...
virtual ble_error_t enableSigning (ble::connection_handle_t connectionHandle, bool enabled=true)
 Request generation and exchange of signing keys so that packet signing can be utilised on this connection. More...
virtual ble_error_t setHintFutureRoleReversal (bool enable=true)
 Give a hint to the stack that the master/slave role might change in the future. More...
virtual ble_error_t getLinkEncryption (ble::connection_handle_t connectionHandle, ble::link_encryption_t *encryption)
 Current state of encryption on the link. More...
virtual ble_error_t setLinkEncryption (ble::connection_handle_t connectionHandle, ble::link_encryption_t encryption)
 Enabled or disable encryption on the link. More...
virtual ble_error_t setEncryptionKeyRequirements (uint8_t minimumByteSize, uint8_t maximumByteSize)
 Set the requirements for encryption key size. More...
virtual ble_error_t requestAuthentication (ble::connection_handle_t connectionHandle)
 Request that the link be authenticated (keys with MITM protection). More...
virtual ble_error_t generateOOB (const ble::address_t *address)
 Generate OOB data with the given address. More...
virtual ble_error_t setOOBDataUsage (ble::connection_handle_t connectionHandle, bool useOOB, bool OOBProvidesMITM=true)
 Enable OOB data usage during paring. More...
virtual ble_error_t confirmationEntered (ble::connection_handle_t connectionHandle, bool confirmation)
 Report to the stack if the passkey matches or not. More...
virtual ble_error_t passkeyEntered (ble::connection_handle_t connectionHandle, Passkey_t passkey)
 Supply the stack with the user entered passkey. More...
virtual ble_error_t sendKeypressNotification (ble::connection_handle_t connectionHandle, Keypress_t keypress)
 Send a notification to the peer that the user pressed a key on the local device. More...
virtual ble_error_t legacyPairingOobReceived (const ble::address_t *address, const ble::oob_tk_t *tk)
 Supply the stack with the OOB data for legacy connections. More...
virtual ble_error_t oobReceived (const ble::address_t *address, const ble::oob_lesc_value_t *random, const ble::oob_confirm_t *confirm)
 Supply the stack with the OOB data for secure connections. More...
virtual ble_error_t getSigningKey (ble::connection_handle_t connectionHandle, bool authenticated)
 Retrieves a signing key through a signingKey event. More...
void onShutdown (const SecurityManagerShutdownCallback_t &callback)
 Setup a callback to be invoked to notify the user application that the SecurityManager instance is about to shutdown (possibly as a result of a call to BLE::shutdown()). More...
SecurityManagerShutdownCallbackChain_tonShutdown ()
 Provide access to the callchain of shutdown event callbacks. More...
virtual void setSecurityManagerEventHandler (EventHandler *handler)
 Assign the event handler implementation that will be used by the stack to signal events back to the application. More...
virtual ble_error_t getAddressesFromBondTable (Gap::Whitelist_t &addresses) const
ble_error_t getLinkSecurity (ble::connection_handle_t connectionHandle, LinkSecurityStatus_t *securityStatus)
virtual void onSecuritySetupInitiated (SecuritySetupInitiatedCallback_t callback)
virtual void onSecuritySetupCompleted (SecuritySetupCompletedCallback_t callback)
virtual void onLinkSecured (LinkSecuredCallback_t callback)
virtual void onSecurityContextStored (HandleSpecificEvent_t callback)
virtual void onPasskeyDisplay (PasskeyDisplayCallback_t callback)
void processSecuritySetupInitiatedEvent (ble::connection_handle_t connectionHandle, bool allowBonding, bool requireMITM, SecurityIOCapabilities_t iocaps)
void processSecuritySetupCompletedEvent (ble::connection_handle_t connectionHandle, SecurityCompletionStatus_t status)
void processLinkSecuredEvent (ble::connection_handle_t connectionHandle, SecurityMode_t securityMode)
void processSecurityContextStoredEvent (ble::connection_handle_t connectionHandle)
void processPasskeyDisplayEvent (ble::connection_handle_t connectionHandle, const Passkey_t passkey)
Static Public Attributes
static const unsigned PASSKEY_LEN = 6
 Declaration of type containing a passkey to be used during pairing. More...

SecurityManager example

The SecurityManager example demonstrates both a central and a peripheral connecting, performing basic pairing and setting up link security.

/* mbed Microcontroller Library
 * Copyright (c) 2006-2013 ARM Limited
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * See the License for the specific language governing permissions and
 * limitations under the License.

#include <events/mbed_events.h>
#include <mbed.h>
#include "ble/BLE.h"
#include "SecurityManager.h"

#include "LittleFileSystem.h"
#include "HeapBlockDevice.h"

/** This example demonstrates all the basic setup required
 *  for pairing and setting up link security both as a central and peripheral
 *  The example is implemented as two classes, one for the peripheral and one
 *  for central inheriting from a common base. They are run in sequence and
 *  require a peer device to connect to. During the peripheral device demonstration
 *  a peer device is required to connect. In the central device demonstration
 *  this peer device will be scanned for and connected to - therefore it should
 *  be advertising with the same address as when it connected.
 *  During the test output is written on the serial connection to monitor its
 *  progress.

static const uint8_t DEVICE_NAME[] = "SM_device";

/* for demonstration purposes we will store the peer device address
 * of the device that connects to us in the first demonstration
 * so we can use its address to reconnect to it later */
static BLEProtocol::AddressBytes_t peer_address;

/** Base class for both peripheral and central. The same class that provides
 *  the logic for the application also implements the SecurityManagerEventHandler
 *  which is the interface used by the Security Manager to communicate events
 *  back to the applications. You can provide overrides for a selection of events
 *  your application is interested in.
class SMDevice : private mbed::NonCopyable<SMDevice>,
                 public SecurityManager::EventHandler
    SMDevice(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) :
        _led1(LED1, 0),
        _is_connecting(false) { };

    virtual ~SMDevice()
        if (_ble.hasInitialized()) {

    /** Start BLE interface initialisation */
    void run()
        ble_error_t error;

        /* to show we're running we'll blink every 500ms */
        _event_queue.call_every(500, this, &SMDevice::blink);

        if (_ble.hasInitialized()) {
            printf("Ble instance already initialised.\r\n");

        /* this will inform us off all events so we can schedule their handling
         * using our event queue */
            makeFunctionPointer(this, &SMDevice::schedule_ble_events)

        /* handle timeouts, for example when connection attempts fail */
            makeFunctionPointer(this, &SMDevice::on_timeout)

        error = _ble.init(this, &SMDevice::on_init_complete);

        if (error) {
            printf("Error returned by BLE::init.\r\n");

        /* this will not return until shutdown */

    /* event handler functions */

    /** Respond to a pairing request. This will be called by the stack
     * when a pairing request arrives and expects the application to
     * call acceptPairingRequest or cancelPairingRequest */
    virtual void pairingRequest(
        ble::connection_handle_t connectionHandle
    ) {
        printf("Pairing requested - authorising\r\n");

    /** Inform the application of a successful pairing. Terminate the demonstration. */
    virtual void pairingResult(
        ble::connection_handle_t connectionHandle,
        SecurityManager::SecurityCompletionStatus_t result
    ) {
        if (result == SecurityManager::SEC_STATUS_SUCCESS) {
            printf("Pairing successful\r\n");
        } else {
            printf("Pairing failed\r\n");

    /** Inform the application of change in encryption status. This will be
     * communicated through the serial port */
    virtual void linkEncryptionResult(
        ble::connection_handle_t connectionHandle,
        ble::link_encryption_t result
    ) {
        if (result == ble::link_encryption_t::ENCRYPTED) {
            printf("Link ENCRYPTED\r\n");
        } else if (result == ble::link_encryption_t::ENCRYPTED_WITH_MITM) {
            printf("Link ENCRYPTED_WITH_MITM\r\n");
        } else if (result == ble::link_encryption_t::NOT_ENCRYPTED) {
            printf("Link NOT_ENCRYPTED\r\n");

        /* disconnect in 2 s */
            2000, &_ble.gap(),
            &Gap::disconnect, _handle, Gap::REMOTE_USER_TERMINATED_CONNECTION

    /** Override to start chosen activity when initialisation completes */
    virtual void start() = 0;

    /** This is called when BLE interface is initialised and starts the demonstration */
    void on_init_complete(BLE::InitializationCompleteCallbackContext *event)
        ble_error_t error;

        if (event->error) {
            printf("Error during the initialisation\r\n");

        /* This path will be used to store bonding information but will fallback
         * to storing in memory if file access fails (for example due to lack of a filesystem) */
        const char* db_path = "/fs/bt_sec_db";
        /* If the security manager is required this needs to be called before any
         * calls to the Security manager happen. */
        error = _ble.securityManager().init(

        if (error) {
            printf("Error during init %d\r\n", error);

        error = _ble.securityManager().preserveBondingStateOnReset(true);

        if (error) {
            printf("Error during preserveBondingStateOnReset %d\r\n", error);

        /* Enable privacy so we can find the keys */
        error = _ble.gap().enablePrivacy(true);

        if (error) {
            printf("Error enabling privacy\r\n");

        Gap::PeripheralPrivacyConfiguration_t configuration_p = {
            /* use_non_resolvable_random_address */ false,

        Gap::CentralPrivacyConfiguration_t configuration_c = {
            /* use_non_resolvable_random_address */ false,

        /* this demo switches between being master and slave */

        /* Tell the security manager to use methods in this class to inform us
         * of any events. Class needs to implement SecurityManagerEventHandler. */

        /* print device address */
        Gap::AddressType_t addr_type;
        Gap::Address_t addr;
        _ble.gap().getAddress(&addr_type, addr);
        printf("Device address: %02x:%02x:%02x:%02x:%02x:%02x\r\n",
               addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);

        /* when scanning we want to connect to a peer device so we need to
         * attach callbacks that are used by Gap to notify us of events */
        _ble.gap().onConnection(this, &SMDevice::on_connect);
        _ble.gap().onDisconnection(this, &SMDevice::on_disconnect);

        /* start test in 500 ms */
        _event_queue.call_in(500, this, &SMDevice::start);

    /** This is called by Gap to notify the application we connected */
    virtual void on_connect(const Gap::ConnectionCallbackParams_t *connection_event) = 0;

    /** This is called by Gap to notify the application we disconnected,
     *  in our case it ends the demonstration. */
    void on_disconnect(const Gap::DisconnectionCallbackParams_t *event)

    /** End demonstration unexpectedly. Called if timeout is reached during advertising,
     * scanning or connection initiation */
    void on_timeout(const Gap::TimeoutSource_t source)
        printf("Unexpected timeout - aborting\r\n");

    /** Schedule processing of events from the BLE in the event queue. */
    void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context)
        _event_queue.call(mbed::callback(&context->ble, &BLE::processEvents));

    /** Blink LED to show we're running */
    void blink(void)
        _led1 = !_led1;

    DigitalOut _led1;

    BLE &_ble;
    events::EventQueue &_event_queue;
    BLEProtocol::AddressBytes_t &_peer_address;
    ble::connection_handle_t _handle;
    bool _is_connecting;

/** A peripheral device will advertise, accept the connection and request
 * a change in link security. */
class SMDevicePeripheral : public SMDevice {
    SMDevicePeripheral(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address)
        : SMDevice(ble, event_queue, peer_address) { }

    virtual void start()
        /* Set up and start advertising */

        ble_error_t error;
        GapAdvertisingData advertising_data;

        /* add advertising flags */
                                  | GapAdvertisingData::BREDR_NOT_SUPPORTED);

        /* add device name */

        error = _ble.gap().setAdvertisingPayload(advertising_data);

        if (error) {
            printf("Error during Gap::setAdvertisingPayload\r\n");

        /* advertise to everyone */
        /* how many milliseconds between advertisements, lower interval
         * increases the chances of being seen at the cost of more power */

        error = _ble.gap().startAdvertising();

        if (error) {
            printf("Error during Gap::startAdvertising.\r\n");

        printf("Please connect to device\r\n");

        /** This tells the stack to generate a pairingRequest event
         * which will require this application to respond before pairing
         * can proceed. Setting it to false will automatically accept
         * pairing. */

    /** This is called by Gap to notify the application we connected,
     *  in our case it immediately requests a change in link security */
    virtual void on_connect(const Gap::ConnectionCallbackParams_t *connection_event)
        ble_error_t error;

        /* remember the device that connects to us now so we can connect to it
         * during the next demonstration */
        memcpy(_peer_address, connection_event->peerAddr, sizeof(_peer_address));

        printf("Connected to: %02x:%02x:%02x:%02x:%02x:%02x\r\n",
                _peer_address[5], _peer_address[4], _peer_address[3],
                _peer_address[2], _peer_address[1], _peer_address[0]);

        /* store the handle for future Security Manager requests */
        _handle = connection_event->handle;

        /* Request a change in link security. This will be done
         * indirectly by asking the master of the connection to
         * change it. Depending on circumstances different actions
         * may be taken by the master which will trigger events
         * which the applications should deal with. */
        error = _ble.securityManager().setLinkSecurity(

        if (error) {
            printf("Error during SM::setLinkSecurity %d\r\n", error);

/** A central device will scan, connect to a peer and request pairing. */
class SMDeviceCentral : public SMDevice {
    SMDeviceCentral(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address)
        : SMDevice(ble, event_queue, peer_address) { }

    virtual void start()
        /* start scanning and attach a callback that will handle advertisements
         * and scan requests responses */
        ble_error_t error = _ble.gap().startScan(this, &SMDeviceCentral::on_scan);

        printf("Please advertise\r\n");

        printf("Scanning for: %02x:%02x:%02x:%02x:%02x:%02x\r\n",
               _peer_address[5], _peer_address[4], _peer_address[3],
               _peer_address[2], _peer_address[1], _peer_address[0]);

        if (error) {
            printf("Error during Gap::startScan %d\r\n", error);

    /** Look at scan payload to find a peer device and connect to it */
    void on_scan(const Gap::AdvertisementCallbackParams_t *params)
        /* don't bother with analysing scan result if we're already connecting */
        if (_is_connecting) {

        /* connect to the same device that connected to us */
        if (memcmp(params->peerAddr, _peer_address, sizeof(_peer_address)) == 0) {

            ble_error_t error = _ble.gap().connect(
                params->peerAddr, params->peerAddrType,
                NULL, NULL

            if (error) {
                printf("Error during Gap::connect %d\r\n", error);

            printf("Connecting... ");

            /* we may have already scan events waiting
             * to be processed so we need to remember
             * that we are already connecting and ignore them */
            _is_connecting = true;


    /** This is called by Gap to notify the application we connected,
     *  in our case it immediately request pairing */
    virtual void on_connect(const Gap::ConnectionCallbackParams_t *connection_event)
        ble_error_t error;

        /* store the handle for future Security Manager requests */
        _handle = connection_event->handle;

        /* in this example the local device is the master so we request pairing */
        error = _ble.securityManager().requestPairing(_handle);


        if (error) {
            printf("Error during SM::requestPairing %d\r\n", error);

        /* upon pairing success the application will disconnect */

bool create_filesystem()
    static LittleFileSystem fs("fs");

    /* replace this with any physical block device your board supports (like an SD card) */
    static HeapBlockDevice bd(4096, 256);

    int err = bd.init();

    if (err) {
        return false;

    err = bd.erase(0, bd.size());

    if (err) {
        return false;

    err = fs.mount(&bd);

    if (err) {
        /* Reformat if we can't mount the filesystem */
        printf("No filesystem found, formatting...\r\n");

        err = fs.reformat(&bd);

        if (err) {
            return false;

    return true;

int main()
    BLE& ble = BLE::Instance();
    events::EventQueue queue;

    /* if filesystem creation fails or there is no filesystem the security manager
     * will fallback to storing the security database in memory */
    if (!create_filesystem()) {
        printf("Filesystem creation failed, will use memory storage\r\n");

    while(1) {
            printf("\r\n PERIPHERAL \r\n\r\n");
            SMDevicePeripheral peripheral(ble, queue, peer_address);

            printf("\r\n CENTRAL \r\n\r\n");
            SMDeviceCentral central(ble, queue, peer_address);

    return 0;

Important Information for this Arm website

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.