| nRF5 SDK v12.0.0 |

Choose documentation: | nRF5 SDK | S130 SoftDevice API | S132 SoftDevice API | S212 SoftDevice API | S332 SoftDevice API

All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
BLE Secure DFU Bootloader
This example requires one of the following SoftDevices: S130, S132

Important: Before you run this example, make sure to program the SoftDevice.

The BLE Secure DFU Bootloader example uses the Bootloader modules to implement a bootloader with secure Device Firmware Update (DFU) functionality.

The example bootloader accepts images that contain a new bootloader, SoftDevice, application, or any combination of these. To protect the target device against malicious attackers trying to impersonate the rightful sender of the firmware update, the init packet of the firmware package must be signed.

# Setup

You can find the source code and the project file of the example in the following folder: `<InstallFolder>\examples\dfu\bootloader_secure`

Button assignments - in addition to those defined in BSP BLE Button Assignments:

- Button 4: Holding this button during startup makes the device enter DFU mode.

# 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 stems from a trusted source.

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 four 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. Supported signature types are ECDSA_P256_SHA256 and ED25519. This example uses ECDSA_P256_SHA256.
Signature | `signature` | See Cryptography library 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

To create a zip file that contains the firmware image (or images) and the corresponding init packet, use the `nrfutil` tool (version 1.5.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.pem` | A 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,0x88` | A comma-separated list of FWID values of installed, on-target SoftDevices that are valid to be used with the new image.

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 `dfu_handle_prevalidate()` function. Verification is done in the following order:

1. Hardware version, `hw_version`.
2. SoftDevice version, `sd_req`.
3. Firmware version, `fw_version`.
4. The hash of the packet is obtained using `hash_data`.
5. 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 named `pk`[] and is located in the file `dfu_req_handling.c`.
6. Available space: Enough space left on the device to perform the transfer is verified. 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 returned.

## 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. For the nRF51 Series, the default version number is defined to be 51. Similarly, the default hardware version number for the nRF52 Series is 52. However, you should not use these default version numbers 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 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.
- 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 bootloader.

# Testing

You can either create your own firmware package for testing or use one of the provided packages that are located in subfolders of `<InstallFolder>\examples\dfu\ble_dfu_send_hex`. The provided packages have been generated using a private key that corresponds to the default public key in the project. This public key must not be used in production.

Test the BLE Secure DFU Bootloader application by performing the following steps:

1. If you want to create your own firmware package for testing:
   1. Create a private key for the example. See Working with keys for instructions.
      Note
        The private key should be kept with very limited distribution, because it can be used to create valid firmware images to update your device. It must never be lost, because without the key, there is no way to create new DFU images.
   2. Create a public key in code format and store it in a file named `dfu_public_key.c`. See Working with keys for instructions.
   3. Copy the `dfu_public_key.c` file to the project folder, replacing the existing file.
   4. Prepare a firmware package (in zip format) that you want to use. See Creating a firmware package for instructions.
   5. Generate a HEX file that contains the Bootloader settings page. See the nrfutil documentation for instructions.
2. Compile the bootloader.
3. If you generated a bootloader settings HEX file, use mergehex (part of the nRF5x Command Line Tools, see the mergehex documentation) to merge the bootloader HEX file and the bootloader settings HEX file.
4. Program the HEX file. See Programming the bootloader.
5. Make sure that the device enters DFU mode. DFU mode is indicated by LED 3 being lit. If a valid application is installed on the device, hold Button 4 during startup to prevent the bootloader from starting the application and force it to enter DFU mode instead.
6. Use either nrfutil or a mobile app to perform the DFU:
   - With nrfutil:
     1. Connect an nRF51 or nRF52 Development Kit board to your computer. This board serves as connectivity IC to do the DFU on the device that contains the DFU bootloader.
     2. Enter the following command to start the DFU process over BLE, where package.zip is the name of the firmware package that you want to upload: `nrfutil dfu ble -f -pkg package.zip`
     3. nrfutil will ask you to choose a serial port. The port you specify must correspond to the port of the development kit that you connected.
     4. To choose a specific target device, use nrfutil's `-n` or `-a` options. For more information, enter `nrfutil dfu ble --help`.
   - With the nRF Toolbox app (Android: 1.17 or later, iOS: 4 or later) or the nRF Connect app (4.4 or later, Android only at this time):
     1. Transfer the zip firmware package that you want to upload to the mobile device:
        - On iOS: Connect the mobile device to your computer and open iTunes. Select the mobile device and then Apps > nRF Toolbox (or nRF Connect). Then you can drag and drop a file directly into the application's internal storage. Alternatively, send an email attachment to the app from the mobile device itself. See the app's documentation for more information.
        - On Android: Connect the mobile device to your computer. Enable file transfer between the computer and the device and copy the zip file into a folder of your choice.
     2. Use the nRF Toolbox or nRF Connect app to select a target device and a zip package and to start the process.
7. Observe that the device resets and runs the new application, bootloader, or SoftDevice.