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

Replace existing Private Key in Bootloader with new one using DFU

Hello!

I have some devices with a custom built PCB on my desk, all of which have my own custom firmware on it.

Sadly the devices don't have access to the debug pins so I can only update via bluetooth.

When I first flashed these devices I flashed a full firmware package (bootloader, softdevice and application) which was based on a different firmware (let's call it OLD) I wrote some time ago.

This firmware package also includes the Secure BLE DFU Service so my plan was to update the devices later with the new firmware I am developing right now.

All good so far, I've done this before, no troubles yet.

Now I have finished to prepare my new firmware (let's call it NEW) and it's almost ready for production.

I realized that the bootloader I flashed before includes the private key of the OLD firmware.

I wanted to replace the private key in the NEW firmware to prevent the user from being able to flash the wrong firmware onto the wrong device, potentially killing it.

But now I have run into the problem that I am actually trying to avoid.

I have to update the existing firmware via bluetooth but I am unable to do so because my NEW firmware uses a new private key.

I have tried to create a temporary DFU distribution package containing the NEW bootloader (which has been compiled with the NEW private key) but signed with the OLD key.

Sadly that does not work. When trying this on an open PCB I have access to the RTT log I can see the following error output

00> :INFO:Image verified 
00> :INFO:Prevalidate FAILED!
00> :INFO:Sending Response: [0x4, 0x4]

So I guess replacing the bootloader with a different one is not possible?

Or am I missing something?

Would be a really really big shame if the devices I have flashed before are now at a dead end :( 

Any help is appreciated!

Also, big shout out to the Nordic staff and support team! The SDK and documentation you provide is great, as is the support you offer!

Parents
  • Hi 

    Just one clarification: the bootloader contains the public key, which is derived from the private key and the private key is used to sign the firmware packages. 

     

    When I first flashed these devices I flashed a full firmware package (bootloader, softdevice and application) which was based on a different firmware (let's call it OLD) I wrote some time ago.

     Ok, so this bootloader contains the old public key. If you want to update the firmware on this device you need to sign the firmware package with the old private key that the old public key was derived from. 

    I have tried to create a temporary DFU distribution package containing the NEW bootloader (which has been compiled with the NEW private key) but signed with the OLD key.

    Sadly that does not work. When trying this on an open PCB I have access to the RTT log I can see the following error output

    00> :INFO:Image verified
    00> :INFO:Prevalidate FAILED!
    00> :INFO:Sending Response: [0x4, 0x4]

    So I guess replacing the bootloader with a different one is not possible?

    Or am I missing something?

     If the  firmware package that contains the new bootloader that uses the new public key is signed with old private key that the old public key in the old bootloader was derived from, then this should work fine. 

    Note that the prevalidation step might fail due to the version numbers used when generating the firmware package using nrfutil, i.e. sd-req,  application-version, bootloader-version etc, see Validation and Acceptance rules for versions

    Can you post the nrfutil command you used to generate the fimware package with the new bootloader? Also please state which SoftDevice version  that is present on the nRF device and which Softdevice version that is used by the new bootloader. 

    Best regards

    Bjørn

  • This command was used to generate the .hex-file for the OLD we flashed onto the device using nrfjprog initially

    .\nrfutil4.exe settings generate --family NRF52 --application logger_app.hex --application-version 3 --bootloader-version 2 --bl-settings-version 1 settings.hex --no-backup
    .\mergehex.exe -m sd3.hex logger_app.hex boot_fixed_rtt.hex -o output_tmp.hex
    .\mergehex.exe -m output_tmp.hex settings.hex -o output.hex
    sd3.hex = s132_nrf52_3.0.0_softdevice.hex

    And we used the following command to create the .zip-DFU-package to successfully update the application-part of the OLD firmware via bluetooth

    .\nrfutil4.exe pkg generate --application ..\Firmware\_build\logger_app.hex --key-file ..\Firmware\priv.pem DFU_package.zip --hw-version 52 --sd-req 0x8C --application-version 3

    priv.pem = the OLD private key

    And then I tried to create the NEW DFU package in different ways.

    DFU package to replace the app-part only (works, basically the same as above). This caused the devices to crash on startup because the new app is no longer compatible with the old bootloader / softdevice

    res\nrfutil4.exe pkg generate --application build/NEW_App.out.hex --key-file REDACTED\Firmware\priv.pem DFU_App_w_oldkey.zip --hw-version 52 --sd-req 0x8C --application-version 3

    Next I tried to create a DFU package containing the NEW bootloader and NEW softdevice using the following command (again using the old key)

    .\res\nrfutil4.exe pkg generate --bootloader res/bootloader.hex --bootloader-version 3 --softdevice sdk/components/softdevice/s132/hex/s132_nrf52_6.1.1_softdevice.hex --sd-id 0xB7 --key-file REDACTED\Firmware\priv.pem DFU_BL_SD_w_oldkey.zip --hw-version 52 --sd-req 0x8C

    And that's the package I am unable to send and update with

  • Ah, missed that. Yes, then it shouldnt be the bootloader version. The remaining checks are then the bootloader size check, if the new bootloader is larger than the old one, then the prevalidation will fail. 

    #elif defined ( NRF52 )
        if (p_init->bl_size > NRF_MBR_PARAMS_PAGE_ADDRESS - BOOTLOADER_START_ADDR)
    #endif
        {
            return NRF_DFU_RES_CODE_INSUFFICIENT_RESOURCES;
        }

    and the available flash space check. 

    // Find the location to place the DFU updates
    err_code = nrf_dfu_find_cache(m_firmware_size_req, false, &m_firmware_start_addr);
    if (err_code != NRF_SUCCESS)
    {
        return NRF_DFU_RES_CODE_INSUFFICIENT_RESOURCES;
    }

    The S132 v3.x.x requires 124kB ( 0x1F000 bytes). 

    The S132 v6.1.1 requires 152 kB (0x26000 bytes)( 148kB without the MBR) . 

    The Secure Bootloader should not exceed 24kB, but If its the debug bootloader the size is 0xB000 and the start address is 0x73000. 

    So there should be 0x1F000 - 0x73000( debug bootloader start address) = 0x54000 ( 336kB available) so more than enough space for a BL and the S132 v6.1.1

     

    mikoay said:
    In theory I should be able to just create a new bootloader with the old SDK, old signing key and debug this one to see what's going wrong, right?

     Yes, that should be possible.  

    mikoay said:
    Is there any chance that the bootloader he compiled just doesn't allow to update itself or the softdevice? Certainly he could have broken something, but could it be that some setting he overlooked prevented this from being possible?

    Your former colleague may have heavily modified the old bootloader, but in general most customers modify the bootloader as little as possible. 

  • When opening the original firmware in the nRF Connect Programmer tool I can see the following layout

    Orange = MBR, 0x0 to 0x964

    Blue = Softdevice, 0x1000 to 0x1E740

    Green = Application, 0x1F000 to 0x3940C

    Red = Bootloader, 0x73000 to 0x7B1BC

    Black = Unkown (maybe the settings?), 0x7F000 to 0x7F05C

    So my old bootloader does exceed the 24kB you were talking about before by 12kB as it is 32kB in size.
    Could this cause such an issue?

    I checked, the new bootloader only takes 22kB.

    Also, the old softdevice takes 124kB of size, the new one needs 152kB. (as you said and I confirmed)

    When updating from the old one to the new one I'd expect the softdevice update to overwrite the application part of the old firmware, causing the application the device to become invalid.

    What would happen in such a case? Would the device be staying in DFU mode until I also send the new application?

  • mikoay said:

    Orange = MBR, 0x0 to 0x964

    Blue = Softdevice, 0x1000 to 0x1E740

    Green = Application, 0x1F000 to 0x3940C

    Red = Bootloader, 0x73000 to 0x7B1BC

    Black = Unkown (maybe the settings?), 0x7F000 to 0x7F05C

     Correct, black is the settings page. 

    The available flash memory for a dual bank update would in this case be 0x73000-0x3A000 = 0x39000 ( 228kB) so there should be plenty of room for the S132 v6.1.1 wihtout the MBR ( 148kB) + Bootloader (22kB) = 170kB. 

    We also need to take into account the DFU_APP_DATA_RESERVED settings, which reserves N number of pages below the bootloader for application data( e.g. bonding information). This is by default set to 3 pages, so that means that the actual available memory will be 0x70000-0x3A000 = 0x36000 ( 216kB). Which should still be more than enough. 

    mikoay said:
    So my old bootloader does exceed the 24kB you were talking about before by 12kB as it is 32kB in size.
    Could this cause such an issue?

     As long as the old bootloader is larger than the new bootloader there is no issue. But you need to make sure that the new bootloader is compiled with the same start address as the old one, i.e. 0x73000

    mikoay said:

    When updating from the old one to the new one I'd expect the softdevice update to overwrite the application part of the old firmware, causing the application the device to become invalid.

    What would happen in such a case? Would the device be staying in DFU mode until I also send the new application?

     The bootloader will only erase the old application if the space from the first unused flash page after the old application to the start of the reserved page section is smaller than the size of the firmware image with the SD+BL. In this case its not, so the BL will perform a dual bank update, i.e. keep the old application in flash. 

    If the old application is incompatible with the new softdevice, then it will be invalidated and the nRF device will stay in bootloader mode after the SD+ BL update is completed and wait for a new application update. 

  • I think there we might have the problem. Neutral face

    The old bootloader starts at 0x73000

    The new bootloader starts at 0x78000

    So if I understood you correctly that's one of the requirements to be able to properly update the bootloader, right?

    In other words, I am out of luck and I can't replace the old bootloader with the new one?

  • Yes, the new bootloader must be able to fit between 0x73000 and 0x7E000( start address of the MBR parameter page). The new bootloader is using S132 v6.1.1, so I assume this is the bootloader from SDK v15.3.0. The non-debug bootloader should only require 24kB, i.e. start address 0x78000 and size 0x6000 bytes , but If its the debug bootloader the size is 0xB000 and the start address is 0x73000. 

    Have you modified the debug bootloader? Can you switch to the non-debug bootloader?

Reply
  • Yes, the new bootloader must be able to fit between 0x73000 and 0x7E000( start address of the MBR parameter page). The new bootloader is using S132 v6.1.1, so I assume this is the bootloader from SDK v15.3.0. The non-debug bootloader should only require 24kB, i.e. start address 0x78000 and size 0x6000 bytes , but If its the debug bootloader the size is 0xB000 and the start address is 0x73000. 

    Have you modified the debug bootloader? Can you switch to the non-debug bootloader?

Children
No Data
Related