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

nRF51 OTA BLE DFU | flash space erased before init packet validation.

Hi!

I'm developing on nRF51 with SDK 11 and trying to extend our application with buttonless BLE DFU support. Due to limited flash memory, we could only use single bank ble bootloader. Right now the bootloader works fine but we want to make it more secure and safe, so that it can't be easily attacked and brick.

At first attempt, I tried to use the init packet validation to stop random DFU update requests. I found that for all legacy BLE DFU (single or dual), the app space is erased before the init packet is received and checked. So essentially, anyone with a valid/non-valid DFU package can erase the original application on the device.

So I've also tried to modify the state machine in dfu_single_bank.c to erase the flash after init packet prevalidation is successful. But the DFU transfer would stuck at 0% percent (with the correct init packet).

I'm wondering:

  1. If anyone have successfully changed the DFU state machine this way.
  2. Or are there other solutions to make legacy DFU more secure without having to switch to secure DFU (need more flash and requrie higher SDK than we have now)?
Parents
  • Hi ,

     

    Could you let me know what exactly you modified ? 

    As far as I understand, the flash erasing of the original application only happens after the start packet is received and application version and image size verified. The function dfu_prepare_func_app_erase () is called inside "case DFU_STATE_IDLE: " in dfu_start_pkt_handle() in dfu_single_bank.c

  • Hi Hung,

    I tried to put the dfu_prepare_func_app_erase() call after dfu_init_prevalidate() in dfu_init_pkt_complete(). I also changed the states correspondingly. My guess is that the clear can take arbitrary amount of time and the state could be messed up between DFU_STATE_RDY ( changed by pstorage_callback_handler() ) and DFU_STATE_RX_DATA_PKT.

    However, I found a way to only enable communication with DFU service when a certain value has been written to a characteristic and therefore effectively disable DFU functionality to public. So I'll leave the dfu_single_bank.c as it is.

  • Hi drmd, 

     

    My mistake, I was thinking of the start packet not the init packet. 

    You are right that when erasing the old application, the bootloader need to wait for the erasing to be finished (max 90ms/page ). There is a call back called dfu_cb_handler() in dfu_transport_ble.c that you can use. Currently it's used to send the notification for the START packet after the erasing is done .

     

    What you can do is to modify it, so that the notification about the INIT packet complete ( ble_dfu_response_send(p_dfu, BLE_DFU_INIT_PROCEDURE, resp_val);)  to be delayed instead of the START packet, until the flash erasing is finished. 

     

    What you planing to do is also fine, I assume what you do is to verify the DFU master before allowing the bootloader to process the Start packet. 

    Note that, this trick can easily be recorded and replayed. So this approach is not really safe from attacker. It might be used to avoid accidental DFU update.

     

     

     

  • So I managed to make the change that Hung suggested. And it works the way I want it to: if the init packet validation fails, the device can restart and run the original application without problem.

    All I needed to modify is dfu_single_bank.c and dfu_transport_ble.c (attached).

    single_bank_new_states.zip

Reply Children
No Data
Related