nRF5 SDK  v17.0.2
Choose documentation:
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
Validation

Before a Device Firmware Update is carried out, the new image should be validated. Some information (for example, the compatibility) can be checked before the actual firmware is transferred (prevalidation). Other information, for example the hash of the image, should be validated after the transfer (postvalidation).

The provided firmware package must include the firmware image and an init packet that can be used to prevalidate the image. The format of the init packet and the actual validation process is defined by the DFU bootloader implementation. See Init packet for documentation about the validation that is used in the BLE Secure DFU Bootloader example.

To be compatible, the validation (which is part of the DFU bootloader implementation) and the image creation (usually done with an external tool) must use the same init packet format. A convenient way of ensuring the common format is to define the required contents of the init packet in a protocol buffer file. In this way, the packet format can be defined once and then be used in different places. See the BLE Secure DFU Bootloader example for an example implementation.

Init packet

When performing a DFU, you must provide a package (in zip format) that contains the firmware image, an init packet, and a manifest file that indicates the package format. The init packet contains information about the firmware image that is used to validate the image, and it must be signed to ensure that the update comes from a trusted source.

Nordic provides the command line tool nrfutil to create firmware packages with an init packet in a format defined by a protocol buffer file. See Creating a firmware package with nrfutil for information about how to use nrfutil to create a firmware package that is compatible with the BLE Secure DFU Bootloader example. If you change the format of the init packet in your DFU bootloader implementation, see the nrfutil documentation for instructions on how to update the tool. Alternatively, you can create your own tool to create the firmware package.

The required contents of the init packet are defined in the protocol buffer file dfu-cc.proto. The following fields of the init packet are checked during the validation of the init packet:

Type Field name Description
Type of the image type The image can be an application image, SoftDevice image, bootloader image, or a combined image of bootloader and SoftDevice.
Hash of the image hash The hash consists of two fields: an integer that specifies the used hash function and a byte array that contains the hash of the complete package.
Firmware version fw_version This integer represents the firmware version of either the bootloader or the application image in the package. (The SoftDevice version is specified in a separate field.)
Hardware version hw_version This integer represents the required hardware version of the device.
Allowed versions of the SoftDevice sd_req[] This array of integers represents what SoftDevice firmware IDs are accepted for the image. Up to 16 allowed SoftDevice versions may be specified.
Size of the new SoftDevice, bootloader, or application sd_size, bl_size, app_size These integer values specify the size of the SoftDevice, bootloader, or application.
Signature type signature_type The type of signature that the init packet is signed with. The DFU code supports ECDSA_P256_SHA256 out of the box.
Signature signature See Cryptography library - nrf_crypto for more information.
Debugging is_debug When this flag is set, version validation (see Validation) is skipped. This flag is only honored in the debug projects. The non-debug projects always validate versions.

Creating a firmware package with nrfutil

To create a zip file that contains the firmware image (or images) and the corresponding init packet, use the nrfutil tool (version 2.2.0 or later). This tool is available as a standalone Python package from the Nordic Semiconductor nrfutil GitHub repository or can be installed from pypi with pip install nrfutil. See the nrfutil documentation for more information. Run nrfutil pkg generate --help to display help about creating a zip file.

You can add the following firmware images in binary or hexadecimal format to the zip file:

  • --application image: an image of an application
  • --bootloader image: an image of a bootloader
  • --softdevice image: an image of a SoftDevice

You can also combine several images in one zip file. Note that, depending on the combination of images, the created zip file might contain two firmware packages (one for the bootloader and/or SoftDevice and one for the application) and the DFU process will be carried out in two steps. If you include both a bootloader and a SoftDevice in your firmware package, those two images will be merged together. An application, however, will always be updated separately after the other updates are completed.

In addition to the images, specify the information that you want to add to the init packet. The following options are available:

Option Example value Description
--debug-mode n/a Add this flag to skip version validation.
--key-file file c:\vault\priv.pemA private (signing) key in PEM format that is used to cryptographically sign the firmware image (see Working with keys).
--application-version version 0xff The version of the application image.
--bootloader-version version 0xff The version of the bootloader image.
--hw-version version 52 The version of the hardware that should accept the image.
--sd-req sd_list 0x87,0x8C,0xAE,0xAF,0xB0A comma-separated list of FWID values of installed, on-target SoftDevices that are valid to be used with the new image. Run nrfutil pkg generate --help to display a list of possible values.

For SD + BL + App updates, remember to also specify the --sd-id field.

See the nrfutil documentation for additional information about nrfutil and about the required steps if you want to customize the init packet.

Validation

Validation of the image includes checks to verify that the image originates from a trusted source and that it is compatible with the device and the current firmware and hardware. If the flag is_debug is set in the init packet, the debug version of the example skips version validation.

These checks are implemented in the Validation module. Verification is done in the following order:

  1. Signature of the packet, signature.
    To be able to verify the signature, the validation code needs the public key that corresponds to the private key that was used to sign the init packet.
    This key is located in the file dfu_public_key.c.
  2. Firmware type, fw_type. Version checking can be enabled/disabled with the NRF_DFU_APP_DOWNGRADE_PREVENTION config.
  3. Hardware version, hw_version.
  4. SoftDevice version, sd_req.
  5. Firmware version, fw_version.
  6. Firmware size to see whether the update will fit. Dual-bank and single-bank updates shows the memory layout for the secure DFU bootloader, which indicates which sizes will be accepted.

If one of these verification steps fails, an error code is sent via the transport.

Version numbers

There are three types of version numbers:

  • Hardware version: The hardware version is determined by the device. In the example implementation, the hardware of the device is specified by the NRF_DFU_HW_VERSION macro in the sdk_config file. For the nRF52 Series, the default version number is defined to be 52. However, you should not use this default version number in a product, but use your own version numbering scheme.
  • SoftDevice firmware ID: The SoftDevice firmware ID is stored inside the SoftDevice HEX file and is retrieved through the macro SD_FWID_GET.
  • Firmware version: The firmware version refers to either the bootloader version or the application version, depending on the transferred image. The current version numbers are stored in the bootloader settings page. The application version (nrf_dfu_settings_t::app_version) and the bootloader version (nrf_dfu_settings_t::bootloader_version) can be retrieved from the global variable s_dfu_settings.
    Note
    Note that the version numbers are erased and zero-initialized when the bootloader image is programmed. Therefore, after you first program the bootloader, you must generate a bootloader settings page with the current version numbers. See Bootloader Settings page and the nrfutil documentation for more information.

Acceptance rules for versions

Unless version validation is skipped, the dfu_handle_prevalidate() function applies the following acceptance rules to determine whether the image is accepted:

  • Hardware version: If the hardware version that is specified in the init packet matches the hardware of the device, the image is accepted.
  • SoftDevice Firmware ID: If one of the specified firmware IDs matches the ID of the current SoftDevice, the image is accepted. A firmware ID of 0x00 in the sd_req list means "The update does not depend on the SoftDevice". See section Updates without a SoftDevice for the implications of this.
  • Firmware version: If the image contains a bootloader, the image is accepted if the new firmware version is greater than (>) the existing version of the bootloader. If the image contains an application, the image is accepted if the new firmware version is greater than or equal to (>=) the existing version of the application. If the image contains a SoftDevice and no SoftDevice is already present, the fw_version is checked against the existing application's version to determine whether the update can overwrite it.

Updates without a SoftDevice

When the bootloader itself does not need the SoftDevice, it can also process updates without SoftDevices. These updates are recognized by the special sd_req value 0x00 as described below.

  • If the update contains an application, the application is placed after the MBR where the SoftDevice is usually placed. If there is a SoftDevice present, the sd_req list must also contain its firmware ID to be allowed to overwrite it.
  • If the update contains only a SoftDevice, it can only be applied if there is no SoftDevice present already. The update must also contain a fw_version which must be checked against the current application's version to be allowed to overwrite it.
  • If the update contains a bootloader, the current SoftDevice is ignored. The SoftDevice is deleted only if the current bootloader does not need it and the space is needed for banking the update.

An empty sd_req list is equivalent to an sd_req list containing a single 0x00.

Updating between different SoftDevice families

By default, the bootloader rejects all SoftDevice updates that are not the same family as the current SoftDevice. An example is an update containing S132 when the current SoftDevice is S112. Such updates are rejected by default because they might cause unpredictable behavior.

You can however work around this restriction and allow an update between SoftDevice families. To do this, edit the code directly in softdevice_info_ok() in the nrf_dfu_validation.c file. Edit the piece of code that uses SD_ID_GET. The "SoftDevice ID" or "SD_ID" refers to the SoftDevice family. For example, ID == 140 indicates that the SoftDevice family is S140. Add additional checks as necessary.

Signature verification

When the update is signed and verification of the signature passes, the bootloader can be sure that the update is correct bit-for-bit, and that the holder of the private key has approved the contents. This means you can have full control over the updates that are applied to your device, as long as the private key is kept secret. The bootloader contains a copy of the public key only. This key can be used to verify a signature, but to create new signatures, the private key is needed. By default, the Secure Bootloader requires valid signatures for all updates, but it is possible to turn this requirement off by modifying the configuration NRF_DFU_REQUIRE_SIGNED_APP_UPDATE (the Open Bootloader also showcases this).

Note
It is highly recommended to always require signatures for all updates.

For the purposes of NRF_DFU_REQUIRE_SIGNED_APP_UPDATE, the SoftDevice is considered a part of the application, unless the bootloader itself needs the SoftDevice (i.e. the bootloader defines BLE_STACK_SUPPORT_REQD).
For example, the BLE bootloader uses the SoftDevice to receive the update over BLE so it defines BLE_STACK_SUPPORT_REQD. In this case, the SoftDevice is considered part of the bootloader, and as such, it is not affected by NRF_DFU_REQUIRE_SIGNED_APP_UPDATE.