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

Using encryption between central and peripheral.

Hi there,

I am working with softdevice v5.0.0, and trying to have central and peripheral do encryption.

The peripheral has a r/w characteristic, and another one with read with notify (cccd r/w), but no write.

When I enable BOND, LESC and the usual encryption options in peer manager, it seems to work with permisions ENC_NO_MITM or NO_ACCESS on the characteristics read or write. But if I set the cccd write with ENC_NO_MITM, that seems to break the notifications. Setting the cccd read with ENC_NO_MITM makes the SD complain with invalid params.

I have seen those permissions in some examples, and the code I have comes from an old SD v4.0.2 I belive.

Is there anything obvious I should be looking at, or any constrains I am breaking?

Regards

Parents
  • Hi,

    This should work, I just verified it with the hrs example from SDK 14.2.0 (s132 v5). Can you check which softdevice function it is that returns invalid param? 

    Regards,

    Vidar

  • Hi Vidar,

    This is the initialization code in the peripheral:

    static uint32_t button_char_add(ble_mydev_t * p_mydev, const ble_mydev_init_t * p_mydev_init)
    {
        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;
    
        memset(&cccd_md, 0, sizeof(cccd_md));
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
        cccd_md.vloc = BLE_GATTS_VLOC_STACK;
    
        memset(&char_md, 0, sizeof(char_md));
    
        char_md.char_props.read   = 1;
        char_md.char_props.notify = 1;
        char_md.p_char_user_desc  = NULL;
        char_md.p_char_pf         = NULL;
        char_md.p_user_desc_md    = NULL;
        char_md.p_cccd_md         = &cccd_md;
        char_md.p_sccd_md         = NULL;
    
        ble_uuid.type = p_mydev->uuid_type;
        ble_uuid.uuid = MYDEV_UUID_BUTTON_CHAR;
    
        memset(&attr_md, 0, sizeof(attr_md));
    
        BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
        attr_md.vloc    = BLE_GATTS_VLOC_STACK;
        attr_md.rd_auth = 0;
        attr_md.wr_auth = 0;
        attr_md.vlen    = 0;
    
        memset(&attr_char_value, 0, sizeof(attr_char_value));
    
        attr_char_value.p_uuid    = &ble_uuid;
        attr_char_value.p_attr_md = &attr_md;
        attr_char_value.init_len  = sizeof(uint8_t);
        attr_char_value.init_offs = 0;
        attr_char_value.max_len   = sizeof(uint8_t);
        attr_char_value.p_value   = NULL;
    
        return sd_ble_gatts_characteristic_add(p_mydev->service_handle,
                                               &char_md,
                                               &attr_char_value,
                                               &p_mydev->button_char_handles);
    }
    
    
    uint32_t ble_mydev_init(ble_mydev_t * p_mydev, const ble_mydev_init_t * p_mydev_init)
    {
        uint32_t   err_code;
        ble_uuid_t ble_uuid;
    
        // Initialize service structure.
        p_mydev->led_write_handler = p_mydev_init->led_write_handler;
    
        // Add service.
        ble_uuid128_t base_uuid = {MYDEV_UUID_BASE};
        err_code = sd_ble_uuid_vs_add(&base_uuid, &p_mydev->uuid_type);
        VERIFY_SUCCESS(err_code);
    
        ble_uuid.type = p_mydev->uuid_type;
        ble_uuid.uuid = MYDEV_UUID_SERVICE;
    
        err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_mydev->service_handle);
        VERIFY_SUCCESS(err_code);
    
        // Add characteristics.
        err_code = button_char_add(p_mydev, p_mydev_init);
        VERIFY_SUCCESS(err_code);
    ...

    If I replace the:

        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);

    with

        BLE_GAP_CONN_SEC_MODE_ENC_NO_MITM(&cccd_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_ENC_NO_MITM(&cccd_md.write_perm);

    The function sd_ble_gatts_characteristic_add will return invalid param.

    If I only replace:

        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);

    with

        BLE_GAP_CONN_SEC_MODE_ENC_NO_MITM(&cccd_md.write_perm);

    Then the notifications for the button won't work anymore.

    I wonder if I am missing some required change either in the peripheral or the central when setting the cccd_md.write_perm as encoded with no mitm protection.

    I know there are examples that do it and work, but comming from an old code base, I have applied the changes that seem required to do it, so I may be missing one of the required changes.

    I would need help to trouble shoot that.

    Regards

Reply
  • Hi Vidar,

    This is the initialization code in the peripheral:

    static uint32_t button_char_add(ble_mydev_t * p_mydev, const ble_mydev_init_t * p_mydev_init)
    {
        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;
    
        memset(&cccd_md, 0, sizeof(cccd_md));
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
        cccd_md.vloc = BLE_GATTS_VLOC_STACK;
    
        memset(&char_md, 0, sizeof(char_md));
    
        char_md.char_props.read   = 1;
        char_md.char_props.notify = 1;
        char_md.p_char_user_desc  = NULL;
        char_md.p_char_pf         = NULL;
        char_md.p_user_desc_md    = NULL;
        char_md.p_cccd_md         = &cccd_md;
        char_md.p_sccd_md         = NULL;
    
        ble_uuid.type = p_mydev->uuid_type;
        ble_uuid.uuid = MYDEV_UUID_BUTTON_CHAR;
    
        memset(&attr_md, 0, sizeof(attr_md));
    
        BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
        attr_md.vloc    = BLE_GATTS_VLOC_STACK;
        attr_md.rd_auth = 0;
        attr_md.wr_auth = 0;
        attr_md.vlen    = 0;
    
        memset(&attr_char_value, 0, sizeof(attr_char_value));
    
        attr_char_value.p_uuid    = &ble_uuid;
        attr_char_value.p_attr_md = &attr_md;
        attr_char_value.init_len  = sizeof(uint8_t);
        attr_char_value.init_offs = 0;
        attr_char_value.max_len   = sizeof(uint8_t);
        attr_char_value.p_value   = NULL;
    
        return sd_ble_gatts_characteristic_add(p_mydev->service_handle,
                                               &char_md,
                                               &attr_char_value,
                                               &p_mydev->button_char_handles);
    }
    
    
    uint32_t ble_mydev_init(ble_mydev_t * p_mydev, const ble_mydev_init_t * p_mydev_init)
    {
        uint32_t   err_code;
        ble_uuid_t ble_uuid;
    
        // Initialize service structure.
        p_mydev->led_write_handler = p_mydev_init->led_write_handler;
    
        // Add service.
        ble_uuid128_t base_uuid = {MYDEV_UUID_BASE};
        err_code = sd_ble_uuid_vs_add(&base_uuid, &p_mydev->uuid_type);
        VERIFY_SUCCESS(err_code);
    
        ble_uuid.type = p_mydev->uuid_type;
        ble_uuid.uuid = MYDEV_UUID_SERVICE;
    
        err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_mydev->service_handle);
        VERIFY_SUCCESS(err_code);
    
        // Add characteristics.
        err_code = button_char_add(p_mydev, p_mydev_init);
        VERIFY_SUCCESS(err_code);
    ...

    If I replace the:

        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);

    with

        BLE_GAP_CONN_SEC_MODE_ENC_NO_MITM(&cccd_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_ENC_NO_MITM(&cccd_md.write_perm);

    The function sd_ble_gatts_characteristic_add will return invalid param.

    If I only replace:

        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);

    with

        BLE_GAP_CONN_SEC_MODE_ENC_NO_MITM(&cccd_md.write_perm);

    Then the notifications for the button won't work anymore.

    I wonder if I am missing some required change either in the peripheral or the central when setting the cccd_md.write_perm as encoded with no mitm protection.

    I know there are examples that do it and work, but comming from an old code base, I have applied the changes that seem required to do it, so I may be missing one of the required changes.

    I would need help to trouble shoot that.

    Regards

Children
  • Hi,

    Read permission must be set to "open" according to the specification (ref. core spec. 5.0, vol 3, Part G, section 3.3.3.3 (table 3.10)). The softdevice enforces this requirement and is probably why you get the invalid param error. However, it should work if you only require authentication for write access. What central are you using for test? In case it's an iOS device, try to 'forget' the device from ios settings -> Bluetooth, enable and disable flight mode (clears device cache on phone), then re-connect.  

    Regards,

    Vidar

  • Hi Vidar,

    Yes, I was suspecting that the read should be kept open, but did not know where to look for proper documentation, as the infocenter only mentions some vague constrains for the API, and there is no source code to check what they actually are.

    So I am using two nRF52832 devices, one is a central, the other is the peripheral.

    The code for the central, AFAIK does not have anything about the encryption, other than configuring the peer manager to support LESC, as I do in both devices.

    I have made sure that I test with the device peer data clear, otherwise the peer manager will issue a SEC_FAILED event.

    Despite all that, if I do the change for the cccd write to ENC_NO_MITM, then the button notifications are not received in the central anymore.

    Let me know what bits do you want me to check.

    Regards

  • Hi,

    On the central side, is the notification being enabled after the link is secured? Otherwise the CCCD write request will return BLE_GATT_STATUS_ATTERR_INSUF_AUTHENTICATION and notification will not get enabled (MSC write). 

  • The answer is quite likely to be no. I enable it in the discovery complete event, just after calling pm_conn_secure.

    So is it just a matter of moving that to the pm conn sec succeeded event?

    Regards

  • That was it!

    Moving the notification enable to the PM event for conn sec succeeded makes it work.

    ---

    I wonder if there might be other things that I should move to the PM events, rather than leave them in the existing events, for example, all the gatt local and remote databases stored by PM, should the discovery be done differently, e.g. after the conn sec succeeded or the db applied events? Currently I am doing it on BLE_CONNECTED, which might not be the right thing to do.

Related