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

Static Passkey, using and testing

Hi,

I am using nRF51822, S130, SDK12.

Now trying to add a level of security with a static passkey, I have done the following adaptation to my code -

Added to void gap_params_init(void)

uint8_t passkey[] = STATIC_PASSKEY;
m_static_pin_option.gap_opt.passkey.p_passkey = passkey; //gap_opt
err_code = sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &m_static_pin_option);
APP_ERROR_CHECK(err_code);

#define STATIC_PASSKEY "123456" /**< Static pin. */

#define SEC_PARAM_BOND 1 /**< Perform bonding. */
#define SEC_PARAM_MITM 0 /**< 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_NONE /**< 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. */

Further adjustments to code described below..

I am using nRF Connect on my mobile phone and pygatt on my PC (using BlueGiga) to test my application, 

So far strangely pygatt works just fine although I have not configured the PASSKEY on my pygatt application and also, as far as I read it does not support security,

The nRF Connect however fails to connect. 

I would like to know 

1. If I have configured the softdevice correctly to support static passkey, and if not , what should I do - or - where can I find example for my SDK, softdevice configuration

2. Why is the pygatt working and the nRF Connect not

3. where in the nRF Connect mobile app does one configure the static passkey

4. Is there another recommended to test my secure application with.

Thanks!

------------------------------------------------------

Other adaptation to my code -

Added to main() the command:

peer_manager_init(erase_bonds);

Added to main.c the following routines

/**@brief Function for starting advertising.
*/
static void advertising_start(void)
{
uint32_t err_code = ble_advertising_start(BLE_ADV_MODE_FAST);

APP_ERROR_CHECK(err_code);
}

/**@brief Function for handling Peer Manager events.
*
* @param[in] p_evt Peer Manager event.
*/
static void pm_evt_handler(pm_evt_t const * p_evt)
{
ret_code_t err_code;

switch (p_evt->evt_id)
{
case PM_EVT_BONDED_PEER_CONNECTED:
{
app_trace_log("Connected to a previously bonded device.\r\n");
} break;

case PM_EVT_CONN_SEC_SUCCEEDED:
{
app_trace_log("Connection secured. Role: %d. conn_handle: %d, Procedure: %d\r\n",
ble_conn_state_role(p_evt->conn_handle),
p_evt->conn_handle,
p_evt->params.conn_sec_succeeded.procedure);
} break;

case PM_EVT_CONN_SEC_FAILED:
{
/* Often, when securing fails, it shouldn't be restarted, for security reasons.
* Other times, it can be restarted directly.
* Sometimes it can be restarted, but only after changing some Security Parameters.
* Sometimes, it cannot be restarted until the link is disconnected and reconnected.
* Sometimes it is impossible, to secure the link, or the peer device does not support it.
* How to handle this error is highly application dependent. */
} break;

case PM_EVT_CONN_SEC_CONFIG_REQ:
{
// Reject pairing request from an already bonded peer.
pm_conn_sec_config_t conn_sec_config = {.allow_repairing = false};
pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config);
} break;

case PM_EVT_STORAGE_FULL:
{
// Run garbage collection on the flash.
err_code = fds_gc();
if (err_code == FDS_ERR_BUSY || err_code == FDS_ERR_NO_SPACE_IN_QUEUES)
{
// Retry.
}
else
{
APP_ERROR_CHECK(err_code);
}
} break;

case PM_EVT_PEERS_DELETE_SUCCEEDED:
{
advertising_start();
} break;

case PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED:
{
// The local database has likely changed, send service changed indications.
pm_local_database_has_changed();
} break;

case PM_EVT_PEER_DATA_UPDATE_FAILED:
{
// Assert.
APP_ERROR_CHECK(p_evt->params.peer_data_update_failed.error);
} break;

case PM_EVT_PEER_DELETE_FAILED:
{
// Assert.
APP_ERROR_CHECK(p_evt->params.peer_delete_failed.error);
} break;

case PM_EVT_PEERS_DELETE_FAILED:
{
// Assert.
APP_ERROR_CHECK(p_evt->params.peers_delete_failed_evt.error);
} break;

case PM_EVT_ERROR_UNEXPECTED:
{
// Assert.
APP_ERROR_CHECK(p_evt->params.error_unexpected.error);
} break;

case PM_EVT_CONN_SEC_START:
case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
case PM_EVT_PEER_DELETE_SUCCEEDED:
case PM_EVT_LOCAL_DB_CACHE_APPLIED:
case PM_EVT_SERVICE_CHANGED_IND_SENT:
case PM_EVT_SERVICE_CHANGED_IND_CONFIRMED:
default:
break;
}
}


/**@brief Function for the Peer Manager initialization.
*
* @param[in] erase_bonds Indicates whether bonding information should be cleared from
* persistent storage during initialization of the Peer Manager.
*/
static void peer_manager_init(bool erase_bonds)
{
ble_gap_sec_params_t sec_param;
ret_code_t err_code;

err_code = pm_init();
APP_ERROR_CHECK(err_code);

if (erase_bonds)
{
err_code = pm_peers_delete();
APP_ERROR_CHECK(err_code);
}

memset(&sec_param, 0, sizeof(ble_gap_sec_params_t));

// Security parameters to be used for all security procedures.
sec_param.bond = SEC_PARAM_BOND;
sec_param.mitm = SEC_PARAM_MITM;
sec_param.lesc = SEC_PARAM_LESC;
sec_param.keypress = SEC_PARAM_KEYPRESS;
sec_param.io_caps = SEC_PARAM_IO_CAPABILITIES;
sec_param.oob = SEC_PARAM_OOB;
sec_param.min_key_size = SEC_PARAM_MIN_KEY_SIZE;
sec_param.max_key_size = SEC_PARAM_MAX_KEY_SIZE;
sec_param.kdist_own.enc = 1;
sec_param.kdist_own.id = 1;
sec_param.kdist_peer.enc = 1;
sec_param.kdist_peer.id = 1;

err_code = pm_sec_params_set(&sec_param);
APP_ERROR_CHECK(err_code);

err_code = pm_register(pm_evt_handler);
APP_ERROR_CHECK(err_code);
}

Parents
  • Hi,

    I suggest that you try with this with the Glucose Application example first, then use that as a reference on what settings to use. SEC_PARAM_MITM must be set to '1' and  SEC_PARAM_IO_CAPABILITIES  must say you have display capabilities. 

    Note that these security parameters define the security capabilities of the device and not the security requirements/level which is set individually for each characteristic. 

  • Thank you Vidar for your answer

    As far as I understood from the code, Glucose Application uses BLE_GAP_OPT_PRIVACY, not BLE_GAP_OPT_PASSKEY, Is that example relevant to using static passkey?

    I don't have display capabilities or keyboard on the peripheral I am developing for, I am connecting a peripheral to a mobile device (first as I said will try to use nRF Connect).

    Will a static passkey not ensure encryption for all characteristics?

    Thanks !

  • I should have pointed out that the glucose app uses a dynamic passkey, not a static one. That is why the BLE_GAP_OPT_PASSKEY isn't used. But the configuration should be similar apart from that.

    Ron said:
    I don't have display capabilities or keyboard on the peripheral I am developing for, I am connecting a peripheral to a mobile device (first as I said will try to use nRF Connect).

    The device must either have a display or a keyboard option to support passkey pairing. The central will not initiate passkey pairing otherwise. But since you're using static passkey the key could be displayed in other ways. It could be printed on a sticker for instance. 

    Ron said:
    Will a static passkey not ensure encryption for all characteristics?

     You need to change the security level in your service initialization to limit access to characteristics. Code snippet below show how the gls measurement characteristic is set to require encryption for write access. 

    static uint32_t glucose_measurement_char_add(ble_gls_t * p_gls)
    {
        ble_gatts_char_md_t char_md;
        ble_gatts_attr_md_t cccd_md;
        ble_gatts_attr_t    attr_char_value;
        ble_uuid_t          ble_uuid;
        ble_gatts_attr_md_t attr_md;
        ble_gls_rec_t       initial_gls_rec_value;
        uint8_t             encoded_gls_meas[MAX_GLM_LEN];
        uint8_t             num_recs;
        memset(&cccd_md, 0, sizeof(cccd_md));
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&cccd_md.write_perm); <---- Notifications can't be enabled unless the link is secured 

    The passkey is not used for encryption, but to protect against man-in-the-middle (MITM) attacks while performing the pairing procedure. And the MITM protection isn't particularly effective when you use a static key and legacy pairing, unfortunately.

    These message sequence charts may help illustrate the different security procedures. It's from the Application's point of view

    Peripheral Security Procedures

  • Thank you Vidar

    So far I have change the GLS to static passkey and connected successfully.

    Since than I have tried to migrate that code into a thin version of my existing application and encountered a hardfault after the sd_ble_gap_authenticate command

    static ret_code_t link_secure_peripheral(uint16_t conn_handle, ble_gap_sec_params_t * p_sec_params)
    {
        // This should never happen for a peripheral.
        NRF_PM_DEBUG_CHECK(p_sec_params != NULL);
    
        // VERIFY_PARAM_NOT_NULL(p_sec_params);
    
        ret_code_t err_code = sd_ble_gap_authenticate(conn_handle, p_sec_params);
    
        return err_code;
    }
    

    Have no idea what causes this and how to fix it.

    Would appreciate your help on that issue as well

    Thanks!

  • Hi,

    I suggest we continue the discussion in the other thread you posted here: https://devzone.nordicsemi.com/f/nordic-q-a/55668/sd_ble_gap_authenticate-causes-hardfault. When you get a hardfault on a SD call it usually means that you're using the wrong interrupt priority levels. 

  • Hey Vidar

    you said 

    The passkey is not used for encryption, but to protect against man-in-the-middle (MITM) attacks

    Is implementing encryption conditioned by pairing and bonding? Does that not requiring passing keys earlier? what key does the encryption use? is there an additional key?

    Thanks!

  • Hi,

    the devices agree on a common encryption key during the pairing/bonding procedure, but that key is not derived or based on the passkey in any way. If you just need encryption you can use the "just works" procedure.

    Relevant message sequence charts:

    Bonding: Just Works

    Bonding: Passkey Entry with static passkey 

    Edit: it may be helpful to take a look at other forum threads that discuss the security aspects of pairing and bonding. This one for instance: https://devzone.nordicsemi.com/f/nordic-q-a/35856/questions-about-lesc-mitm-and-passkey/138175 

Reply Children
  • Hey

    Isn't the passkey (including static passkey) used to protect encryption key exchange as well?

    in this thread - Questions about LESC, MITM and passkey it states that "In LESC passkey pairing, the pairing is safe from MITM attacks, as long as the MITM doesn't know the passkey"

    I understand that using a static passkey the MITM eventually will guess the correct key, the author there suggest using a password, and says that "(they won't be able to decrypt the data and they will not learn the password)", I did not understand why wouldn't a eavesdropper attacker be able to able to learn this password if it can learn my passkey.

    I would appreciate if you would share what to you opinion will be the best way to protect my data given 

    Thanks again!

     

  • Hi,

    Yes, it's used to protect against man in the middle attacks. However, legacy passkey pairing does not protect against passive eavesdropping as opposed to the LE secure pairing procedure, which was discussed in the other thread. A high-end BT sniffer will easily brute force the passkey on the fly and retrieve the encryption keys. Also, note that LE secure pairing is not fully supported on the nRF51 series. 

  • Thanks Vidar

    Do you have any idea why would advertising stop after the fast advertising timeout, it never goes into slow advertising in the GLS example, it just stops.

    Thanks again for your help

  • Hi, 

    This example does not implement slow advertising. Instead, it attempts to enter System OFF mode (deep sleep) when the fast advertising times out, see  BLE_ADV_EVT_IDLE event in on_adv_evt(). I say attempt because it can't enter deep sleep if you are debugging the app while it times out. 

  • Hi Vidar, 

    do you mean that 

            case BLE_ADV_EVT_IDLE:
                sleep_mode_enter();
                break; // BLE_ADV_EVT_IDLE

    I changed the entire routine to 

    static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
    {
        switch (ble_adv_evt)
        {
            case BLE_ADV_EVT_FAST:
    
                break;
            case BLE_ADV_EVT_SLOW:
    
                break;                
            default:
                break;
        }
    }

    as for the advertising_init() I think I added a slow advertisement configuraiton

    static void advertising_init(void)
    {
        uint32_t               err_code;
        ble_advdata_t          advdata;
        ble_adv_modes_config_t options;
    
        // Build and set advertising data.
        memset(&advdata, 0, sizeof(advdata));
    
        advdata.name_type               = BLE_ADVDATA_FULL_NAME;
        advdata.include_appearance      = true;
        advdata.flags                   = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;;
        advdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
        advdata.uuids_complete.p_uuids  = m_adv_uuids;
    
        memset(&options, 0, sizeof(options));
        options.ble_adv_fast_enabled  = true;
        options.ble_adv_fast_interval = APP_ADV_INTERVAL;
        options.ble_adv_fast_timeout  = APP_ADV_TIMEOUT_IN_SECONDS;
    
        options.ble_adv_slow_enabled = true; //BLE_ADV_SLOW_ENABLED; 
        options.ble_adv_slow_interval = MSEC_TO_UNITS(1475, UNIT_0_625_MS);
        options.ble_adv_slow_timeout = 0;	
    	
        err_code = ble_advertising_init(&advdata, NULL, &options, on_adv_evt, NULL);
        APP_ERROR_CHECK(err_code);
    }

    Still the effect is the same, after timeout advertisement stops. 

    Any more directions?

    Thanks again

Related