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

  • And, about security permission of the characteristics, would you not recommend level 4 instead of level 3?  What is the difference?

  • I am using an ESP32 as BLE client.  Trying to get level 4 security (LE security) to work.  Even though I set:

    #define SEC_PARAM_LESC                  1 

    It seems like my ESP32 is still authenticated without LE SC.  Using peer manager, are there some extra code I have to add to enable LE Secure Connection on NRF side?

    Thanks again,

    Joseph

  • Both sides must state that they support LESC, otherwise the paring will be performed with the common denominator in terms of supported features. So we need to verify if the ESP32 sets LESC as a suppported feature during the connection preocedure. 

    Could you use the nRF Sniffer v2 to capture a on-air-trace of the communication between the ESP32 and the nRF52? 

  • Regarding LESC connection, thanks for the useful suggestion of using nRF Sniffer to capture the connection.  It looks like towards the end, after Key Exchange, the MASTER (i.e. ESP32 as client) sends a LL_CONNECTION_UPDATE_REQ.  But, the nrf device (Server) doesn't respond with anything. Until 28 seconds later, the nrf sends a LL_TERMINATE_IND.

    Is the nRF device supposed to respond to a LL_CONNECTION_UPDATE_REQ command, or not?  Can you tell what the problem may be?

    I have attached the capture from nRF Sniffer.  You may use this as filter to see the essential packets:

             btle.length!=0 && !btle.advertising_header

    LeSecureConnectFail.pcapng

Reply
  • Regarding LESC connection, thanks for the useful suggestion of using nRF Sniffer to capture the connection.  It looks like towards the end, after Key Exchange, the MASTER (i.e. ESP32 as client) sends a LL_CONNECTION_UPDATE_REQ.  But, the nrf device (Server) doesn't respond with anything. Until 28 seconds later, the nrf sends a LL_TERMINATE_IND.

    Is the nRF device supposed to respond to a LL_CONNECTION_UPDATE_REQ command, or not?  Can you tell what the problem may be?

    I have attached the capture from nRF Sniffer.  You may use this as filter to see the essential packets:

             btle.length!=0 && !btle.advertising_header

    LeSecureConnectFail.pcapng

Children
  • I took a look at the trace and in terms of LESC support its all good, both sides states that they support LESC in the pairing request/response. 

    Which SDK version are you using ?

    At least in SDK v15.2.0 you will need to respond to the BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST event by adding the following snippet to ble_evt_handler

     case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
    {
        NRF_LOG_DEBUG("Received BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST");
    
        err_code = sd_ble_gap_conn_param_update(m_conn_handle,
            &p_gap->params.conn_param_update_request.conn_params);
    
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Failure to update connection parameter request: 0x%x", err_code);
        }
    
        APP_ERROR_CHECK(err_code);
    } break;

    You can also add handling of the BLE_GAP_EVT_CONN_PARAM_UPDATE event, which is generated when the update is finished. 

     case BLE_GAP_EVT_CONN_PARAM_UPDATE:
    {
        NRF_LOG_DEBUG("Received BLE_GAP_EVT_CONN_PARAM_UPDATE");
    
        ble_gap_conn_params_t const * p_conn =
            &p_gap->params.conn_param_update.conn_params;
    
        NRF_LOG_DEBUG("max_conn_interval: %d", p_conn->max_conn_interval);
        NRF_LOG_DEBUG("min_conn_interval: %d", p_conn->min_conn_interval);
        NRF_LOG_DEBUG("slave_latency: %d",     p_conn->slave_latency);
        NRF_LOG_DEBUG("conn_sup_timeout: %d",  p_conn->conn_sup_timeout);
    } break;

    Best regards

    Bjørn

  • Thanks for the additional info.  Added what you suggested, but it didn't help.

    After further investigation, I now believe the problem is caused by ESP32 (i.e. BLE client)'s request for "DH Key Check", which translates to BLE_GAP_EVT_LESC_DHKEY_REQUEST in nRF.  The process dies because nRF side didn't respond to this DH Key request.

    A few questions:

    1. Am I supposed to handle the request explicitly myself?

    2. For comparison, I traced connection to the NRF using nRF connect from my iPhone.  It worked fine.  But strangely, I did not see any DHKEY Request during the handshake.  Why is it different?

    Based on the client about BLE_GAP_EVT_LESC_DHKEY_REQUEST, I found some code from one of the NFC examples that generates a reply to the DH Key request that look something like this:

            case BLE_GAP_EVT_LESC_DHKEY_REQUEST:
            {
                // Buffer peer Public Key because ECC module arguments must be word aligned.
                memcpy(&m_lesc_peer_pk.pk[0],
                       &p_ble_evt->evt.gap_evt.params.lesc_dhkey_request.p_pk_peer->pk[0],
                       BLE_GAP_LESC_P256_PK_LEN);
    
                // Compute D-H key.
                err_code = ecc_p256_shared_secret_compute(&m_lesc_sk.pk[0],
                                                          &m_lesc_peer_pk.pk[0],
                                                          &m_lesc_dhkey.key[0]);
                APP_ERROR_CHECK(err_code);
    
                // Reply with obtained result.
                err_code = sd_ble_gap_lesc_dhkey_reply(m_conn_handle, &m_lesc_dhkey);
                APP_ERROR_CHECK(err_code);
            } break;

    However, I have yet to be able to try it yet, as it requires me to build the external micro-ecc library, which seems really complicated. It's getting late, I will probably try it more tomorrow.  But, before I sink more time into this, I want to make sure I am on the right track.

    Thanks,

    Joseph

Related