Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Signature on BL updated by DFU

There doesn't seem to be any validation of the image when updating the bootloader by secure DFU. nrfutil has no switch to generate any crc or ecdsa_signature. The code uses VALIDATE_CRC, but the expected value is calculated on the received image in boot_validate_extract, so when this is later verified in nrf_dfu_validation_boot_validate the result is always success.

There is also a bug in postvalidate_sd_bl causing the boot validation of BL to always fail for a combined SD+BL image. The second call to boot_validation_extract should have index=1 if there was also a SD in the image.

I'm using nRf52832 with SDK 15.3.0.

Best Regards

Sven

  • Hi,

    There doesn't seem to be any validation of the image when updating the bootloader by secure DFU. nrfutil has no switch to generate any crc or ecdsa_signature. The code uses VALIDATE_CRC, but the expected value is calculated on the received image in boot_validate_extract, so when this is later verified in nrf_dfu_validation_boot_validate the result is always success.

    You are right that this is not used for the bootloader. That makes sense, though. The key point is that the validation in nrf_dfu_validation_boot_validate() is not done during the DFU upgrade, but for every boot. There are several ways the bootloader van check (or not check) the validity of the application before deciding to boot it. But there is no corresponding way for the bootloader to check itself, nor would it make much sense. The bootloader image is still checked and the signature must be valid for an update of the bootloader (same as for SoftDevice and application, unless you use the open bootloader).

    There is also a bug in postvalidate_sd_bl causing the boot validation of BL to always fail for a combined SD+BL image. The second call to boot_validation_extract should have index=1 if there was also a SD in the image.

    I do not see a problem with index=0, and also it works as expected. Can you elaborate? Note that the bl_start and bl_size variables are adjusted if there is a SD (line 892-893). Is that what you did not spot?

  • For a bootloader update I only see the ECDSA signature of the init packet being verified before download, I cant find any verification of the image
    (except for verifying CRC for the objects to ensure correct transfer). Are you saying there is ECDSA signature check for the bootloader code at every startup ? My concern is with intentional tampering with the bootloader image in a signed DFU package. Before activating the bootloader image it should be authenticated.

    When I generate a DFU package with the command:
    nrfutil pkg generate --key-file private.key --sd-boot-validation VALIDATE_ECDSA_P256_SHA256 --bootloader-version 2 --hw-version 52 --sd-req 0xB7 --softdevice sd.hex --bootloader bl.hex sd_bl.zip
    The binary consist of first SD then BL.

    The entire image is first transfered. Then the SD part is verified:

    boot_validation_extract(... index=0, sd_start, sd_len ...)  p_init->boot_validation[0] = VALIDATE_ECDSA_P256_SHA256 which is what was specified in the init packet. This succeeds.

    10 lines down the BL the BL part is verified:

    boot_validation_extract(... index=0, bl_start, bl_len ...)  In this function p_init->boot_validation[0] is still VALIDATE_ECDSA_P256_SHA256, and the signature of the bootloader image is compared to the expected signature of the SD (boot_validation[0].bytes.bytes). This fails.

  • Hi,

    sjerlhagen said:
    For a bootloader update I only see the ECDSA signature of the init packet being verified before download, I cant find any verification of the image
    (except for verifying CRC for the objects to ensure correct transfer).

    Yes, the init packet itself is validated before the firmware is downloaded. But the init packet is also used to validate the received firmware before it is activated. In details:

    • When a whole firmware image is received on_data_obj_execute_request_sched() in nrf_dfu_req_handler.c calls nrf_dfu_validation_activation_prepare() in dfu_validation.c.
    • nrf_dfu_validation_activation_prepare() calls postvalidate(),
    • which calls fw_hash_ok(), and this takes both the init packet and received data as input. It uses nrf_dfu_validation_hash_ok() and only returns true if the hash of the received firmware matches the hash in the signed init packet (which was validated at the beginning of the DFU process).
    • Subsequently, postvalidate_sd_bl() is called, but at that point, the received firmware is already validated as described above.
    sjerlhagen said:
    Are you saying there is ECDSA signature check for the bootloader code at every startup ?

    No. (But you can optionally do that for the application.)

    sjerlhagen said:
    My concern is with intentional tampering with the bootloader image in a signed DFU package. Before activating the bootloader image it should be authenticated.

    Absolutely. That is handled by the bootloader.

    sjerlhagen said:
    boot_validation_extract(... index=0, bl_start, bl_len ...)  In this function p_init->boot_validation[0] is still VALIDATE_ECDSA_P256_SHA256, and the signature of the bootloader image is compared to the expected signature of the SD (boot_validation[0].bytes.bytes). This fails.

    It should not be so. Can you show all the modifications you have done to the bootloader?

  • I see, I did not catch this additional whole image hash verification. This is ok.

    In postvalidate_sd_bl I did the following changes:

    Added  uint8_t  index = 0;

    Changed the bold parts below in the postvalidate_sd_bl function:

    if (!boot_validation_extract(&boot_validation_sd, p_init, index, start_addr, p_init->sd_size, VALIDATE_CRC))
    {
    return false;
    }

    bl_start += p_init->sd_size;
    bl_size -= p_init->sd_size;
    index++;
    }
    if (with_bl)
    {
    if (!boot_validation_extract(&boot_validation_bl, p_init, index, bl_start, bl_size, NO_VALIDATION))

  • I see. Please revert your change. This works with the unmodified bootloader.

Related