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

How to specify signing the key with MCUBoot

Hello,

I am using NCS v1.5.0 and an nRF9160 on a custom board, my application has a custom SPM and the secondary slot for the firmware image upgrade is stored on an external flash.

I generated a private key, and I am passing it to the MCUBoot as CONFIG_BOOT_SIGNATURE_KEY_FILE="C:/workspace/repos/DNG/keys/development_private.pem". This key appears to be used because I see during the build process:

=== child image mcuboot - begin ===
Including boilerplate (Zephyr base): C:/Nordic/v1.5.0/zephyr/cmake/app/boilerplate.cmake
-- Application: C:/Nordic/v1.5.0/bootloader/mcuboot/boot/zephyr
-- Using NCS Toolchain 1.5.0 for building. (C:/Nordic/v1.5.0/toolchain/cmake)
-- Zephyr version: 2.4.99 (C:/Nordic/v1.5.0/zephyr)
-- Found Python3: C:/Nordic/v1.5.0/toolchain/opt/bin/python.exe (found suitable exact version "3.8.2") found components: Interpreter
-- Found west (found suitable version "0.9.0", minimum required is "0.7.1")
-- Board: dng_nrf9160
-- Cache files will be written to: C:/Nordic/v1.5.0/zephyr/.cache
-- Found dtc: C:/Nordic/v1.5.0/toolchain/opt/bin/dtc.exe (found suitable version "1.4.7", minimum required is "1.4.6")
-- Found toolchain: gnuarmemb (C:/Nordic/v1.5.0/toolchain/opt)
-- Found BOARD.dts: C:/workspace/repos/DNG/boards/arm/dng_nrf9160/dng_nrf9160.dts
-- Found devicetree overlay: C:/Nordic/v1.5.0/bootloader/mcuboot/boot/zephyr/dts.overlay
-- Generated zephyr.dts: C:/workspace/repos/DNG/build/mcuboot/zephyr/zephyr.dts
-- Generated devicetree_unfixed.h: C:/workspace/repos/DNG/build/mcuboot/zephyr/include/generated/devicetree_unfixed.h
-- Generated device_extern.h: C:/workspace/repos/DNG/build/mcuboot/zephyr/include/generated/device_extern.h
Parsing C:/Nordic/v1.5.0/bootloader/mcuboot/boot/zephyr/Kconfig
Loaded configuration 'C:/workspace/repos/DNG/boards/arm/dng_nrf9160/dng_nrf9160_defconfig'
Merged configuration 'C:/Nordic/v1.5.0/bootloader/mcuboot/boot/zephyr/prj.conf'
Merged configuration 'C:/workspace/repos/DNG/mcuboot.conf'
Configuration saved to 'C:/workspace/repos/DNG/build/mcuboot/zephyr/.config'
Kconfig header saved to 'C:/workspace/repos/DNG/build/mcuboot/zephyr/include/generated/autoconf.h'
-- The C compiler identification is GNU 9.2.1
-- The CXX compiler identification is GNU 9.2.1
-- The ASM compiler identification is GNU
-- Found assembler: C:/Nordic/v1.5.0/toolchain/opt/bin/arm-none-eabi-gcc.exe
MCUBoot bootloader key file: C:/workspace/repos/DNG/keys/development_private.pem
-- Configuring done
-- Generating done
-- Build files have been written to: C:/workspace/repos/DNG/build/mcuboot
=== child image mcuboot - end ===

The problem is that on startup, MCUBoot complains that it cannot find the image:


*** Booting Zephyr OS build v2.4.99-ncs1 ***
[00:00:00.380,249] <inf> mcuboot: Starting bootloader
[00:00:00.380,920] <wrn> mcuboot: Failed reading sectors; BOOT_MAX_IMG_SECTORS=256 - too small?
[00:00:00.380,981] <err> mcuboot: Image in the primary slot is not valid!
[00:00:00.380,981] <err> mcuboot: Unable to find bootable image

I suspect this is related to the signing keys used, but I cannot understand why or where the problem is occuring. 

I tried adding CONFIG_BOOT_SIGNATURE_KEY_FILE="C:/workspace/repos/DNG/keys/development_private.pem" to the application prj.conf, but got this warning:

warning: BOOT_SIGNATURE_KEY_FILE (defined at C:/Nordic/v1.5.0/nrf\modules\Kconfig.mcuboot:10) was
assigned the value 'C:/workspace/repos/DNG/keys/development_private.pem' but got the value ''. Check
these unsatisfied dependencies: (!MCUBOOT_BUILD_STRATEGY_FROM_SOURCE) (=n). See
docs.zephyrproject.org/.../CONFIG_BOOT_SIGNATURE_KEY_FILE.html and/or
look up BOOT_SIGNATURE_KEY_FILE in the menuconfig/guiconfig interface. The Application Development
Primer, Setting Configuration Values, and Kconfig - Tips and Best Practices sections of the manual
might be helpful too.

The project configurations and options are in this zip file: 8081.project.zip

My understanding is that the build system is given the private key (through the option CONFIG_BOOT_SIGNATURE_KEY_FILE) and then:

1. the MCUBoot build process generates the *public key*, converts it to a C array and it gets hardcoded in the bootloader firmware

2. the application build system uses the *private key* to sign the image using the image tool

3. finally, the bootloader and the signed application (my application + custom SPM) are merged into a single hex file

4. the command "west flash" flashes the combined bootloader + app hex

Is this correct ? If so, how can I specify the private key to the build process of MCUBoot and my application ?

I found similar issues in this link and also this one, but the anwsers were not clear to me.

Parents
  • Hi,

     

    Thank you for providing a sample. I needed to override your configuration slightly, as I'm testing on a DK.

    This means that you will get a JEDEC ID error check printed on runtime if you do not change back to your configuration in the boards/arm/dng_nrf9160/dng_nrf9160_common.dts

     

    the secondary slot for the firmware image upgrade is stored on an external flash.

     The external flash setup is usually the reason for this error message in mcuboot, and it highly likely does not have anything to do with your signing process.

     You need to adjust mcuboot.conf::CONFIG_BOOT_MAX_IMG_SECTORS.

    The calculation is:

    flash_size / sector_size = CONFIG_BOOT_MAX_IMG_SECTORS.

     

    for a 1M flash, with 4k pages, this means it should be the default value of 256. In your case, you have set 8M, which needs a value of '2048'.

    However:

    What will be printed when the primary and secondary has different sizes is this:

    *** Booting Zephyr OS build v2.4.99-ncs1  ***
    [00:00:00.400,848] <inf> mcuboot: Starting bootloader
    [00:00:00.402,801] <wrn> mcuboot: Cannot upgrade: not a compatible amount of sectors
    

     

    After looking at the build-folder/partitions.yml, you can read out the range (start+size) of the mcuboot_primary_app, and adjust your secondary to the same.

    prj.conf: CONFIG_PM_EXTERNAL_FLASH_BASE and SIZE

    pm_static: "mcuboot_secondary:"

     

    I may have butchered your project slightly (and added prints to the main app), my apologies for this:

    272717.zip

     

    I also included the build folder, with a merged.hex which runs on the nRF9160-DK (note: we have slightly different flash! remember to change back the configuration).

     

    Kind regards,

    Håkon

  • Hello Hakon,

    Thanks for the fast response and correcting my project configurations. I am now able to build, flash and boot my application. I still have two questions. The first is about the external flash organization.

    In my case, the external flash is divided in two parts. One for logs and application config items, and another for storing the new firmware image. When you edited the file pm_static.yml to become:

    external_flash:
      address: 0xf0000
      device: mx25r6435f
      end_address: 0x00100000
      region: external_flash
      size: 0x10000
    
    mcuboot_secondary:
      address: 0x0
      device: mx25r6435f
      end_address: 0xf0000
      placement:
        align:
          start: 0x000
      region: external_flash
      size: 0x0f0000

    The firmware image slot is placed at the start of the external flash. Is this mandatory or can I place the image slot anywhere else in external flash ?

    The second question is related to the MCUBoot keys. I uncommented CONFIG_BOOT_SIGNATURE_KEY_FILE in mcuboot.conf, and the build process appears to have used my own private key. However on boot I got:

    *** Booting Zephyr OS build v2.4.99-ncs1 ***
    [00:00:00.377,990] <inf> mcuboot: Starting bootloader
    [00:00:00.378,997] <inf> mcuboot: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
    [00:00:00.379,943] <inf> mcuboot: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
    [00:00:00.379,943] <inf> mcuboot: Boot source: none
    [00:00:00.381,378] <inf> mcuboot: Swap type: none
    [00:00:00.471,130] <err> mcuboot: Image in the primary slot is not valid!
    [00:00:00.471,130] <err> mcuboot: Unable to find bootable image

    So, what is the proper way to specifiy the private signing key ? Is it through the CONFIG_BOOT_SIGNATURE_KEY_FILE  option ? Or should I specify it in the command line ? Should I sign the image myself, or is it done by the build process ? 

    Best regards,

      Nelson

Reply
  • Hello Hakon,

    Thanks for the fast response and correcting my project configurations. I am now able to build, flash and boot my application. I still have two questions. The first is about the external flash organization.

    In my case, the external flash is divided in two parts. One for logs and application config items, and another for storing the new firmware image. When you edited the file pm_static.yml to become:

    external_flash:
      address: 0xf0000
      device: mx25r6435f
      end_address: 0x00100000
      region: external_flash
      size: 0x10000
    
    mcuboot_secondary:
      address: 0x0
      device: mx25r6435f
      end_address: 0xf0000
      placement:
        align:
          start: 0x000
      region: external_flash
      size: 0x0f0000

    The firmware image slot is placed at the start of the external flash. Is this mandatory or can I place the image slot anywhere else in external flash ?

    The second question is related to the MCUBoot keys. I uncommented CONFIG_BOOT_SIGNATURE_KEY_FILE in mcuboot.conf, and the build process appears to have used my own private key. However on boot I got:

    *** Booting Zephyr OS build v2.4.99-ncs1 ***
    [00:00:00.377,990] <inf> mcuboot: Starting bootloader
    [00:00:00.378,997] <inf> mcuboot: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
    [00:00:00.379,943] <inf> mcuboot: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
    [00:00:00.379,943] <inf> mcuboot: Boot source: none
    [00:00:00.381,378] <inf> mcuboot: Swap type: none
    [00:00:00.471,130] <err> mcuboot: Image in the primary slot is not valid!
    [00:00:00.471,130] <err> mcuboot: Unable to find bootable image

    So, what is the proper way to specifiy the private signing key ? Is it through the CONFIG_BOOT_SIGNATURE_KEY_FILE  option ? Or should I specify it in the command line ? Should I sign the image myself, or is it done by the build process ? 

    Best regards,

      Nelson

Children
  • Hi Nelson,

     

    NelsonGoncalves said:

    Thanks for the fast response and correcting my project configurations. I am now able to build, flash and boot my application. I still have two questions. The first is about the external flash organization.

    In my case, the external flash is divided in two parts. One for logs and application config items, and another for storing the new firmware image. When you edited the file pm_static.yml to become:

    NelsonGoncalves said:

    The firmware image slot is placed at the start of the external flash. Is this mandatory or can I place the image slot anywhere else in external flash ?

    You can offset the flash as you'd like, as long as the size of the primary and secondary is equal. Note that you need to adjust this in the pm_static.yml and prj.conf.

     

    Example where I add a 0x20000 offset. pm_static.yml:

    external_flash:
      address: 0x0000
      device: mx25r6435f
      end_address: 0x00200000
      region: external_flash
      size: 0x200000
    
    mcuboot_secondary:
      address: 0x200000
      device: mx25r6435f
      end_address: 0x2f0000
      placement:
        align:
          start: 0x200000
      region: external_flash
      size: 0x0f0000
    

    prj.conf:

    ...
    CONFIG_PM_EXTERNAL_FLASH_BASE=0x200000
    CONFIG_PM_EXTERNAL_FLASH_SIZE=0x00f0000
    ...

     

    NelsonGoncalves said:

    The second question is related to the MCUBoot keys. I uncommented CONFIG_BOOT_SIGNATURE_KEY_FILE in mcuboot.conf, and the build process appears to have used my own private key. However on boot I got:

    *** Booting Zephyr OS build v2.4.99-ncs1 ***
    [00:00:00.377,990] <inf> mcuboot: Starting bootloader
    [00:00:00.378,997] <inf> mcuboot: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
    [00:00:00.379,943] <inf> mcuboot: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
    [00:00:00.379,943] <inf> mcuboot: Boot source: none
    [00:00:00.381,378] <inf> mcuboot: Swap type: none
    [00:00:00.471,130] <err> mcuboot: Image in the primary slot is not valid!
    [00:00:00.471,130] <err> mcuboot: Unable to find bootable image

    So, what is the proper way to specifiy the private signing key ? Is it through the CONFIG_BOOT_SIGNATURE_KEY_FILE  option ? Or should I specify it in the command line ? Should I sign the image myself, or is it done by the build process ? 

     This must be set in mcuboot.conf, not in prj.conf.

    Note that if you have a space or a special character like "\" in your path, it must be escaped, as this needs to be in C-string format.

    Let's say that you have the key.pem located in C:\key.pem, then the string must be:

    CONFIG_BOOT_SIGNATURE_KEY_FILE="c:\\key.pem"

     

    If you have issues, you can go into menuconfig for mcuboot, setting the above mentioned config to point to your pem file, then "Save minimal config (advanced)" (shift + d in menuconfig) and look at the stored defconfig file.

    This will format the string for you.

     

    Kind regards,

    Håkon

     

Related