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

Central can't properly encrypt to mode 1 lvl 3, pairing not supported

Hello!

I'm trying to read data off of a commercial blood pressure monitor (Qardio arm) using an nrf51822 with the nrf51 SDK v10.0.0 as the central role (s120). I am able to connect using sd_ble_gap_connect(), and when I tried to write to a characteristic using sd_ble_gattc_write(), I get back an "Authenticated Link Required" error. I assume that this implies I need security on my connection.

So next I attempted to use sd_ble_gap_authenticate(), which resulted in "Pairing Not Supported". It should be noted that I am able to write to the blood pressure monitor using nordic's "nRF Connect for Mobile" android app (I have a google pixel running Android 7.1.2).

Following these attempts, I turned to the device manager. Below shows the parameters I've set up for the DM, which are the same parameters I tried using with sd_ble_gap_authenticate().

static void device_manager_init(bool erase_bonds) {
  uint32_t               err_code;
  dm_init_param_t        init_param = {.clear_persistent_data = erase_bonds};
  dm_application_param_t register_param;

  err_code = pstorage_init();    //must be called before initializing any modules
  APP_ERROR_CHECK(err_code);

  err_code = dm_init(&init_param); //must be called before using any dm API
  APP_ERROR_CHECK(err_code);

  memset(&register_param.sec_param, 0, sizeof (ble_gap_sec_params_t)); //ZERO out the register_param.secparam

  // Event handler to be registered with the module.
  register_param.evt_handler            = device_manager_event_handler;

  // Service or protocol context for device manager to load, store and apply on behalf of application.
  // Here set to client as application is a GATT client.
  register_param.service_type           = DM_PROTOCOL_CNTXT_GATT_CLI_ID;

  // Secuirty parameters to be used for security procedures.
  register_param.sec_param.bond         = SEC_PARAM_BOND;            // bond    = 1
  register_param.sec_param.mitm         = SEC_PARAM_MITM;            // mitm    = 1
  register_param.sec_param.io_caps      = SEC_PARAM_IO_CAPABILITIES; // io cap  = 3  (none)
  register_param.sec_param.oob          = SEC_PARAM_OOB;             // oob     = 0
  register_param.sec_param.min_key_size = SEC_PARAM_MIN_KEY_SIZE;    // min key = 7
  register_param.sec_param.max_key_size = SEC_PARAM_MAX_KEY_SIZE;    // max key = 16
  //register_param.sec_param.kdist_central.enc  = 0;
  //register_param.sec_param.kdist_central.id   = 1;
  //register_param.sec_param.kdist_central.sign = 0;
  register_param.sec_param.kdist_periph.enc   = 1;
  register_param.sec_param.kdist_periph.id    = 1;
  //register_param.sec_param.kdist_periph.sign  = 0;

  dm_register(&m_dm_app_id, &register_param);  //app_id is a global variable 
  }

Now upon DM_EVT_CONNECTION, I would attempt dm_security_setup_req(), which then triggered DM_EVT_SECURITY_SETUP_COMPLETE. I had to use setup_req() again right after this (not sure why...), which then triggered DM_EVT_LINK_SECURED. It was here that I check my security level using dm_security_status_req(), which showed me that I'm still sm:1 lv:1.

I've also tried using the sd_ble_gap_encrypt() function, which triggers BLE_GAP_EVT_CONN_SEC_UPDATE. In here, I've also found myself to still be at sm:1 lv:1.

If "pairing isn't supported", how do I create an "authenticated link" so that I may write to the bp monitor's characteristic? What is the relation of authenticate() and encrypt()? Can I use one without the other?

Also, I am still new when it comes to BLE encryption. When using the sd_ble_gap_encrypt() function, specifically regarding the "ble_gap_master_id_t" and "ble_gap_enc_info_t" structs that the function takes as inputs, how do we populate those input parameters? Where does the LTK come from?

Also for reference, after i run sd_ble_gap_authenticate(), the following data is extracted from the BLE_GAP_EVT_AUTH_STATUS:

auth_status = 0x85  //this is the Authenticated Link Required error
error_src = 1
bonded = 1
sm1_levels.... lv1 = 1, lv2 = 1, lv3 = 1
sm2_levels.... lv1 = 1, lv2 = 1, lv3 = 1
kdist_periph.... enc = 1, id = 1, sign = 1
kdist_central... enc = 0, id = 1, sign = 1

I thank you in advance for your time in helping me with this matter.

Best, Tien Tran

  • When you are using nRF Connect on Android, are you pairing? If not, it is a bit strange that you are able to write. Are you sure you are writing to the same characteristic value in both cases? It is a bit difficult to say why the peripheral returns pairing not supported, but it could be that it doesn't like the security parameters you are trying to pair with. If you are pairing with the nRF connect, and you have access to a sniffer (for example nRF Sniffer) I would do a sniffer trace of both connections and see if there are any differences in regards to the pairing process.

    PS. You should use sd_ble_gap_authenticate() when you want to pair/bond. If you bond you will share encryption keys that can be used in a later connecting, and then you will use sd_ble_gap_encrypt().

  • Here's what I did exactly on the nRF Connect android app. Just copying the log:

    Connected to 5C:D6:1F:20:0B:A5 
    Services discovered        //After this line, I wrote to characteristic
    Deviced bonded
    Data written to **characteristic uuid**, value: (0x) F1-01  //start command
    "(0x) F1-01" sent
    Data written to **characteristic uuid**, value: (0x) F1-02  //stop command
    "(0x) F1-02" sent
    

    So it looks like right after I "wrote" to the characteristic, my phone automatically bonded with the bp monitor. If it can bond, this means it should be able to pair correct?

    I will keep messing around with the parameters, and thank you also for the information about gap_encrypt()

  • Why do you set MITM to 1 and then no IO capability and no OOB, how would you plan to do MITM bonding ? I assume that why the peripheral rejected pairing .

    register_param.sec_param.mitm         = SEC_PARAM_MITM;            // mitm    = 1
    register_param.sec_param.io_caps      = SEC_PARAM_IO_CAPABILITIES; // io cap  = 3  (none)
    register_param.sec_param.oob          = SEC_PARAM_OOB;             // oob     = 0
    
  • Hung Bui, I've been messing around with the parameters mainly because I've been desperate... haha but I have tried it also with oob = 0, no IO cap, and MITM set to 0. Still the exact same error unfortunately.

  • I assume that the blood pressure device require lv3 bonding, meaning you need MITM.

    Could you try MITM =1 and keyboard and display enabled ?

Related