Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Nus client and write to secure characteristic

Hi,

I have modified the nus service and added two new characteristics called txs and rxs which support read and write protection.

on the peripheral i have set BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM for txs and rxs

The service is working as expected from NRF connect for android.

Now I have modified the nus client service as well and implemented my own ble_nus_c_string_send_secure, which writes to the secure characteristic.

I have bonded the central device with nus client to peripheral with nus service.

the ble_nus_c_string_send command works and peripheral receives the string, but ble_nus_c_string_send_secure command returns NRF_SUCCESS but peripheral does not receive the string.

Am I missing something?

for writing to a secured characteristic, do I have to pass more to the sd_ble_gattc_write function?

Thanks,

Raghav

Parents
  • Hello,

    So, what does your implementation look like? What is the difference between ble_nus_c_string_send and ble_nus_c_string_send_secure? Do they write to the same characteristic, or does it write to the new characteristics, rxs? Is the rxs set up properly on the peripheral?

     

    It is a bit difficult to say what the issue may be only with a brief description of your implementation. Could you upload at least the implementation of ble_nus_c_string_send_secure()?

     

    Best regards,

    Edvin

  • Hi Edvin,

    I will attach files that I have changed and this is how I have configured the NUS service on the peripheral

    BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(&nus_init.nus_rxs_attr_md.cccd_write_perm);
    BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(&nus_init.nus_rxs_attr_md.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(&nus_init.nus_rxs_attr_md.write_perm);
    
    BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(&nus_init.nus_txs_attr_md.cccd_write_perm);
    BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(&nus_init.nus_txs_attr_md.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(&nus_init.nus_txs_attr_md.write_perm);


    Please check the function ble_nus_c_string_send_secure in the nus client
  • /**
     * Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
     * 
     * All rights reserved.
     * 
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     * 
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     * 
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     * 
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     * 
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     * 
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     * 
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     * 
     */
    
    #include "sdk_common.h"
    #if NRF_MODULE_ENABLED(BLE_NUS_C)
    #include <stdlib.h>
    
    #include "ble.h"
    #include "ble_nus_c.h"
    #include "ble_gattc.h"
    #include "ble_srv_common.h"
    #include "app_error.h"
    
    #define NRF_LOG_MODULE_NAME ble_nus_c
    #include "nrf_log.h"
    NRF_LOG_MODULE_REGISTER();
    
    void ble_nus_c_on_db_disc_evt(ble_nus_c_t * p_ble_nus_c, ble_db_discovery_evt_t * p_evt)
    {
        ble_nus_c_evt_t nus_c_evt;
        memset(&nus_c_evt,0,sizeof(ble_nus_c_evt_t));
    
        ble_gatt_db_char_t * p_chars = p_evt->params.discovered_db.charateristics;
    
        // Check if the NUS was discovered.
        if (    (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE)
            &&  (p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_NUS_SERVICE)
            &&  (p_evt->params.discovered_db.srv_uuid.type == p_ble_nus_c->uuid_type))
        {
            for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
            {
                switch (p_chars[i].characteristic.uuid.uuid)
                {
                    case BLE_UUID_NUS_RX_CHARACTERISTIC:
                        nus_c_evt.handles.nus_rx_handle = p_chars[i].characteristic.handle_value;
                        break;
    
                    case BLE_UUID_NUS_TX_CHARACTERISTIC:
                        nus_c_evt.handles.nus_tx_handle = p_chars[i].characteristic.handle_value;
                        nus_c_evt.handles.nus_tx_cccd_handle = p_chars[i].cccd_handle;
                        break;
    
                    case BLE_UUID_NUS_RXS_CHARACTERISTIC:
                        nus_c_evt.handles.nus_rxs_handle = p_chars[i].characteristic.handle_value;
                        break;
    
                    case BLE_UUID_NUS_TXS_CHARACTERISTIC:
                        nus_c_evt.handles.nus_txs_handle = p_chars[i].characteristic.handle_value;
                        nus_c_evt.handles.nus_txs_cccd_handle = p_chars[i].cccd_handle;
                        break;
    
                    default:
                        break;
                }
            }
            if (p_ble_nus_c->evt_handler != NULL)
            {
                nus_c_evt.conn_handle = p_evt->conn_handle;
                nus_c_evt.evt_type    = BLE_NUS_C_EVT_DISCOVERY_COMPLETE;
                p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt);
            }
        }
    }
    
    /**@brief     Function for handling Handle Value Notification received from the SoftDevice.
     *
     * @details   This function will uses the Handle Value Notification received from the SoftDevice
     *            and checks if it is a notification of the NUS TX characteristic from the peer. If
     *            it is, this function will decode the data and send it to the
     *            application.
     *
     * @param[in] p_ble_nus_c Pointer to the NUS Client structure.
     * @param[in] p_ble_evt   Pointer to the BLE event received.
     */
    static void on_hvx(ble_nus_c_t * p_ble_nus_c, ble_evt_t const * p_ble_evt)
    {
        // HVX can only occur from client sending.
        if (   (p_ble_nus_c->handles.nus_tx_handle != BLE_GATT_HANDLE_INVALID)
            && (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_nus_c->handles.nus_tx_handle || p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_nus_c->handles.nus_txs_handle)
            && (p_ble_nus_c->evt_handler != NULL))
        {
            ble_nus_c_evt_t ble_nus_c_evt;
            if(p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_nus_c->handles.nus_txs_handle) {
              ble_nus_c_evt.evt_type = BLE_NUS_C_EVT_NUS_TXS_EVT;
            } else {
              ble_nus_c_evt.evt_type = BLE_NUS_C_EVT_NUS_TX_EVT;
            }
            ble_nus_c_evt.p_data   = (uint8_t *)p_ble_evt->evt.gattc_evt.params.hvx.data;
            ble_nus_c_evt.data_len = p_ble_evt->evt.gattc_evt.params.hvx.len;
    
            p_ble_nus_c->evt_handler(p_ble_nus_c, &ble_nus_c_evt);
            NRF_LOG_DEBUG("Client sending data.");
        }
    }
    
    uint32_t ble_nus_c_init(ble_nus_c_t * p_ble_nus_c, ble_nus_c_init_t * p_ble_nus_c_init)
    {
        uint32_t      err_code;
        ble_uuid_t    uart_uuid;
        ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;
    
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c_init);
    
        err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_ble_nus_c->uuid_type);
        VERIFY_SUCCESS(err_code);
    
        uart_uuid.type = p_ble_nus_c->uuid_type;
        uart_uuid.uuid = BLE_UUID_NUS_SERVICE;
    
        p_ble_nus_c->conn_handle           = BLE_CONN_HANDLE_INVALID;
        p_ble_nus_c->evt_handler           = p_ble_nus_c_init->evt_handler;
        p_ble_nus_c->handles.nus_tx_handle = BLE_GATT_HANDLE_INVALID;
        p_ble_nus_c->handles.nus_rx_handle = BLE_GATT_HANDLE_INVALID;
        p_ble_nus_c->handles.nus_txs_handle = BLE_GATT_HANDLE_INVALID;
        p_ble_nus_c->handles.nus_rxs_handle = BLE_GATT_HANDLE_INVALID;
    
        return ble_db_discovery_evt_register(&uart_uuid);
    }
    
    void ble_nus_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ble_nus_c_t * p_ble_nus_c = (ble_nus_c_t *)p_context;
    
        if ((p_ble_nus_c == NULL) || (p_ble_evt == NULL))
        {
            return;
        }
    
        if ( (p_ble_nus_c->conn_handle != BLE_CONN_HANDLE_INVALID)
           &&(p_ble_nus_c->conn_handle != p_ble_evt->evt.gap_evt.conn_handle)
           )
        {
            return;
        }
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GATTC_EVT_HVX:
                on_hvx(p_ble_nus_c, p_ble_evt);
                break;
    
            case BLE_GAP_EVT_DISCONNECTED:
                if (p_ble_evt->evt.gap_evt.conn_handle == p_ble_nus_c->conn_handle
                        && p_ble_nus_c->evt_handler != NULL)
                {
                    ble_nus_c_evt_t nus_c_evt;
    
                    nus_c_evt.evt_type = BLE_NUS_C_EVT_DISCONNECTED;
    
                    p_ble_nus_c->conn_handle = BLE_CONN_HANDLE_INVALID;
                    p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt);
                }
                break;
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    /**@brief Function for creating a message for writing to the CCCD. */
    static uint32_t cccd_configure(uint16_t conn_handle, uint16_t cccd_handle, bool enable)
    {
        uint8_t buf[BLE_CCCD_VALUE_LEN];
    
        buf[0] = enable ? BLE_GATT_HVX_NOTIFICATION : 0;
        buf[1] = 0;
    
        ble_gattc_write_params_t const write_params =
        {
            .write_op = BLE_GATT_OP_WRITE_REQ,
            .flags    = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE,
            .handle   = cccd_handle,
            .offset   = 0,
            .len      = sizeof(buf),
            .p_value  = buf
        };
    
        return sd_ble_gattc_write(conn_handle, &write_params);
    }
    
    
    uint32_t ble_nus_c_tx_notif_enable(ble_nus_c_t * p_ble_nus_c)
    {
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
    
        if ( (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
           ||(p_ble_nus_c->handles.nus_tx_cccd_handle == BLE_GATT_HANDLE_INVALID)
           )
        {
            return NRF_ERROR_INVALID_STATE;
        }
        return cccd_configure(p_ble_nus_c->conn_handle,p_ble_nus_c->handles.nus_tx_cccd_handle, true);
    }
    
    uint32_t ble_nus_c_txs_notif_enable(ble_nus_c_t * p_ble_nus_c)
    {
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
    
        if ( (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
           ||(p_ble_nus_c->handles.nus_txs_cccd_handle == BLE_GATT_HANDLE_INVALID)
           )
        {
            return NRF_ERROR_INVALID_STATE;
        }
        return cccd_configure(p_ble_nus_c->conn_handle,p_ble_nus_c->handles.nus_txs_cccd_handle, true);
    }
    
    uint32_t ble_nus_c_string_send(ble_nus_c_t * p_ble_nus_c, uint8_t * p_string, uint16_t length)
    {
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
    
        if (length > BLE_NUS_MAX_DATA_LEN)
        {
            NRF_LOG_WARNING("Content too long.");
            return NRF_ERROR_INVALID_PARAM;
        }
        if (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
        {
            NRF_LOG_WARNING("Connection handle invalid.");
            return NRF_ERROR_INVALID_STATE;
        }
    
        ble_gattc_write_params_t const write_params =
        {
            .write_op = BLE_GATT_OP_WRITE_CMD,
            .flags    = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE,
            .handle   = p_ble_nus_c->handles.nus_rx_handle,
            .offset   = 0,
            .len      = length,
            .p_value  = p_string
        };
    
        return sd_ble_gattc_write(p_ble_nus_c->conn_handle, &write_params);
    }
    
    uint32_t ble_nus_c_string_send_secure(ble_nus_c_t * p_ble_nus_c, uint8_t * p_string, uint16_t length)
    {
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
    
        if (length > BLE_NUS_MAX_DATA_LEN)
        {
            NRF_LOG_WARNING("Content too long.");
            return NRF_ERROR_INVALID_PARAM;
        }
        if (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
        {
            NRF_LOG_WARNING("Connection handle invalid.");
            return NRF_ERROR_INVALID_STATE;
        }
    
        ble_gattc_write_params_t const write_params =
        {
            .write_op = BLE_GATT_OP_WRITE_CMD,
            .flags    = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE,
            .handle   = p_ble_nus_c->handles.nus_rxs_handle,
            .offset   = 0,
            .len      = length,
            .p_value  = p_string
        };
    
        return sd_ble_gattc_write(p_ble_nus_c->conn_handle, &write_params);
    }
    
    uint32_t ble_nus_c_handles_assign(ble_nus_c_t               * p_ble_nus,
                                      uint16_t                    conn_handle,
                                      ble_nus_c_handles_t const * p_peer_handles)
    {
        VERIFY_PARAM_NOT_NULL(p_ble_nus);
    
        p_ble_nus->conn_handle = conn_handle;
        if (p_peer_handles != NULL)
        {
            p_ble_nus->handles.nus_tx_cccd_handle = p_peer_handles->nus_tx_cccd_handle;
            p_ble_nus->handles.nus_tx_handle      = p_peer_handles->nus_tx_handle;
            p_ble_nus->handles.nus_rx_handle      = p_peer_handles->nus_rx_handle;
            p_ble_nus->handles.nus_txs_cccd_handle = p_peer_handles->nus_txs_cccd_handle;
            p_ble_nus->handles.nus_txs_handle      = p_peer_handles->nus_txs_handle;
            p_ble_nus->handles.nus_rxs_handle      = p_peer_handles->nus_rxs_handle;
        }
        return NRF_SUCCESS;
    }
    #endif // NRF_MODULE_ENABLED(BLE_NUS_C)
    

  • Hello,

    I wasn't able to compile with your ble_nus_c and ble_nus files, until I moved the BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM to inside the ble_nus.c file. Where did you place them?

     

     

    Did you actually encrypt the link? Does any of the devices initiate encryption, and do you respond to it in the other device?

     

    Best regards,

    Edvin

  • I called the BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM in the nus_init function in the main.c

    FYI, this is from nRF SDK 15.0.

    I am not sure how I can encrypt the link, Since the peripheral works with nrf connect for android, I am assuming the app takes care of encrypting the link. I was assuming since I am using peer manager and I am connected to a lesc bonded peer, the encryption works automatically.  

    Can you give me sample of how to encrypt the link on the central device?

    Thanks

  • Hello,

    You need to handle the encryotion at one point.

    since there are several levels on encryption (MITM is the highest one), it is not enough to bond.

     

    Please see this example, which uses LESC:

    https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v13.0.0%2Fble_sdk_app_multirole_lesc.html

     

    Best regards,

    Edvin

  • Hi,

    I have modified the lesc example and added the nus service instead of the hrs.

    I have established the bond between central and peripheral and made sure in the event BLE_GAP_EVT_AUTH_STATUSlv4 is set to 1.

    I connect to bonded peripheral, start discovery, once discovered I call assign handles on nus_c and then enable notification for txs characteristic and trying to send to rxs characteristic using ble_nus_c_string_send_secure function. 

    The function returns NRF_SUCCESS but the message is not received by the peripheral.

    Is there anything else to be done?

Reply
  • Hi,

    I have modified the lesc example and added the nus service instead of the hrs.

    I have established the bond between central and peripheral and made sure in the event BLE_GAP_EVT_AUTH_STATUSlv4 is set to 1.

    I connect to bonded peripheral, start discovery, once discovered I call assign handles on nus_c and then enable notification for txs characteristic and trying to send to rxs characteristic using ble_nus_c_string_send_secure function. 

    The function returns NRF_SUCCESS but the message is not received by the peripheral.

    Is there anything else to be done?

Children
Related