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);
}

  • 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. 

Related