This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Pairing & Bonding happens even when the client's iocap is no_io_caps

I have a ble server with display developed for passkey security.  It works fine when the Master (i.e. client) is set to have Keyboard input capability, which is good.

The problem is that when the client is set to have no_io_caps, the pairing and bonding still happens successfully.  That means the client may bypass the security without needing to enter the passkey.  I am wondering where in code would I need to change in order for the server to stop pairing with client devices without entering the correct passkey.

Note that the following are the security settings I used:

#define SEC_PARAM_BOND                  1                                       /**< Perform bonding. */
#define SEC_PARAM_MITM                  1                                       /**< Man In The Middle protection not required. */
#define SEC_PARAM_LESC                  0                                       /**< LE Secure Connections not enabled. */
#define SEC_PARAM_KEYPRESS              0                                       /**< Keypress notifications not enabled. */
#define SEC_PARAM_IO_CAPABILITIES       BLE_GAP_IO_CAPS_DISPLAY_ONLY            /**< No I/O capabilities. */
#define SEC_PARAM_OOB                   0                                       /**< Out Of Band data not available. */
#define SEC_PARAM_MIN_KEY_SIZE          7                                       /**< Minimum encryption key size. */
#define SEC_PARAM_MAX_KEY_SIZE          16                                      /**< Maximum encryption key size. */

Also, I had made sure that the bonds on both the client and the server are removed before all my tests.

Your help will be greatly appreciated.

Parents
  • Hi Joseph, 

    Yes, if one of the peers do not have IO capabilities, then Just Works pairing will be used, see table 2.8 in the BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part H, page 2313. 

    When the Central ( Link Master) initiates the Pairing process by sending a Pairing request, you will receive a BLE_GAP_EVT_SEC_PARAMS_REQUEST event on the Peripheral side. With this event you will get an  ble_gap_sec_params_t event struct that contains the IO caps of the central . 

    So you could examine the io_caps field upon receiving the event in the the BLE event handler in main.c and see it its set to BLE_GAP_IO_CAPS_NONE. If the IO caps are set to BLE_GAP_IO_CAPS_NONE, then you can reject pairing by calling  sd_ble_gap_sec_params_reply with sec_status set to BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP.

    I would also like to add that you can set the a security level requirement for each characteristic to security level 3 so that even though a device is able to pair and bond using Just works (Security Level 2), the central will not be able to write /read the characeristics unless it re-pairs with the appropriate security level. See BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part C, page 2019 , table 5.8.

    In the nRF5x SDK, this is done by setting the ble_gap_conn_sec_mode_t read_perm/ write_perm fields in the ble_gatts_attr_md_t struct that is passed to sd_ble_gatts_characteristic_add() to the desired security level 

    /**@brief GAP connection security modes.
     *
     * Security Mode 0 Level 0: No access permissions at all (this level is not defined by the Bluetooth Core specification).\n
     * Security Mode 1 Level 1: No security is needed (aka open link).\n
     * Security Mode 1 Level 2: Encrypted link required, MITM protection not necessary.\n
     * Security Mode 1 Level 3: MITM protected encrypted link required.\n
     * Security Mode 1 Level 4: LESC MITM protected encrypted link using a 128-bit strength encryption key required.\n
     * Security Mode 2 Level 1: Signing or encryption required, MITM protection not necessary.\n
     * Security Mode 2 Level 2: MITM protected signing required, unless link is MITM protected encrypted.\n
     */
    typedef struct
    {
      uint8_t sm : 4;                     /**< Security Mode (1 or 2), 0 for no permissions at all. */
      uint8_t lv : 4;                     /**< Level (1, 2, 3 or 4), 0 for no permissions at all. */
    
    } ble_gap_conn_sec_mode_t;
    

    Best regards
    Bjørn

  • Great.  This is exactly the answer I am looking for.

    But, there is still a problem.  Even though I replied to the client with BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, the client may still choose to ignore the rejection, and continue retrieving services and characteristics, etc.  Wouldn't it be better if I close the connection immediately at the point of replying to secure parameters?

    I tried adding these lines immediately after the reply:

                err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                APP_ERROR_CHECK(err_code);

    This closes the connection fine, but after that, the pm event handler gets a PM_EVT_CONN_SEC_FAILED event.  And, the firmware dies in the "if" statement below:

                err_code = sd_ble_gap_disconnect(m_conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                if (err_code != NRF_ERROR_INVALID_STATE)
                {
                    APP_ERROR_CHECK(err_code);
                }

    It return an error code of 0x3002.  I guess you are not supposed to call sd_ble_gap_disconnect() when we don't have a connection.  I could probably ignore this error.  But, it would be good to know the proper way to handle this.

    Thanks,

    Joseph

Reply
  • Great.  This is exactly the answer I am looking for.

    But, there is still a problem.  Even though I replied to the client with BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, the client may still choose to ignore the rejection, and continue retrieving services and characteristics, etc.  Wouldn't it be better if I close the connection immediately at the point of replying to secure parameters?

    I tried adding these lines immediately after the reply:

                err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                APP_ERROR_CHECK(err_code);

    This closes the connection fine, but after that, the pm event handler gets a PM_EVT_CONN_SEC_FAILED event.  And, the firmware dies in the "if" statement below:

                err_code = sd_ble_gap_disconnect(m_conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                if (err_code != NRF_ERROR_INVALID_STATE)
                {
                    APP_ERROR_CHECK(err_code);
                }

    It return an error code of 0x3002.  I guess you are not supposed to call sd_ble_gap_disconnect() when we don't have a connection.  I could probably ignore this error.  But, it would be good to know the proper way to handle this.

    Thanks,

    Joseph

Children
  • Hi Joseph, 

    the 0x3002 error code is BLE_ERROR_INVALID_CONN_HANDLE,  which is listed in the function brief of sd_ble_gap_disconnect() in ble_gap.h 

    /**@brief Disconnect (GAP Link Termination).
     *
     * @details This call initiates the disconnection procedure, and its completion will be communicated to the application
     *          with a @ref BLE_GAP_EVT_DISCONNECTED event.
     *
     * @events
     * @event{@ref BLE_GAP_EVT_DISCONNECTED, Generated when disconnection procedure is complete.}
     * @endevents
     *
     * @mscs
     * @mmsc{@ref BLE_GAP_CONN_MSC}
     * @endmscs
     *
     * @param[in] conn_handle Connection handle.
     * @param[in] hci_status_code HCI status code, see @ref BLE_HCI_STATUS_CODES (accepted values are @ref BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION and @ref BLE_HCI_CONN_INTERVAL_UNACCEPTABLE).
     *
     * @retval ::NRF_SUCCESS The disconnection procedure has been started successfully.
     * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
     * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
     * @retval ::NRF_ERROR_INVALID_STATE Disconnection in progress or link has not been established.
     */
    SVCALL(SD_BLE_GAP_DISCONNECT, uint32_t, sd_ble_gap_disconnect(uint16_t conn_handle, uint8_t hci_status_code));

    You solve the issue by wrapping the code in the PM_EVT_CONN_SEC_FAILED case in a if statment that checks if the conn_handle is valid, i.e.

    if(m_conn_handle !=BLE_CONN_HANDLE_INVALID)
    {
        err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
        if (err_code != NRF_ERROR_INVALID_STATE)
        {
            APP_ERROR_CHECK(err_code);
        }
    }

    It is possible to block connection requests at the Link Layer, i.e. that the SoftDevice rejects connection request, but this requires that a white-list is used, see sd_ble_gap_whitelist_set in the SD API doc. 

    As for the security level, as stated in the comments Security Level 4 requires support for LESC (LE Secure Connections)on both sides of the link, i.e. both sides must be Bluetooth v4.2 or higher. So if you set the security level requirement to 4 for the characteristics, then a smartphone with a BLE v4.1 stack or below will not be able to access the characteristics. Level 4 is of course more secure, but the con is that not all smartphones support it. With level 3 you should not have any issues with the Bluetooth version. 

Related