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

Disabling bootloader security without customization

I'm trying out DFU functionality using nRF52840-PreviewDK and UART transport

It looks like I can disable the requirement for a signature when downloading an APP or SD (SoftDevice) using NRF_DFU_REQUIRE_SIGNED_APP_UPDATE.

It looks like I can disable downgrade prevention of the APP using NRF_DFU_APP_DOWNGRADE_PREVENTION

It looks like I can downgrade the SD regardless of the NRF_DFU_APP_DOWNGRADE_PREVENTION setting (at least for UART transport, which is the only thing I've tried)

However, the signature requirement and downgrade prevention appear to still be in place when downloading a new BL (BootLoader).  The documentation seems to confirm that's what is expected.

Is there a way to disable these checks on the bootloader without customizing the bootloader?

I saw something about --debug-mode.  I haven't tried this but will that bypass both signatures and downgrade prevention of the bootloader?

How about NRF_FSTORAGE_PARAM_CHECK_DISABLED?  I notice this is different in the open bootloader code vs the secure bootloader?  I read the description but I'm still not sure I understand what this setting does.

  • HI Douglas, 

    when creating a DFU firmware image using the --debug-mode option of nrfutil, you're only skipping the version check for hardware and firmware, see https://github.com/NordicSemiconductor/pc-nrfutil#generate

    This can be seen in nrf_dfu_ver_validation_check() from nrf_dfu_validation.c

    nrf_dfu_result_t nrf_dfu_ver_validation_check(dfu_init_command_t const * p_init)
    {
        nrf_dfu_result_t ret_val = NRF_DFU_RES_CODE_SUCCESS;
        if (!fw_type_ok(p_init))
        {
            NRF_LOG_ERROR("Invalid firmware type.");
            ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_INIT_COMMAND_INVALID);
        }
        else if (!fw_hash_type_ok(p_init))
        {
            NRF_LOG_ERROR("Invalid hash type.");
            ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_WRONG_HASH_TYPE);
        }
        else if (!NRF_DFU_DEBUG ||
                (NRF_DFU_DEBUG && ((p_init->has_is_debug == false) || (p_init->is_debug == false))))
        {
            if (p_init->has_hw_version == false)
            {
                NRF_LOG_ERROR("No HW version.");
                ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_INIT_COMMAND_INVALID);
            }
            else if (p_init->hw_version != NRF_DFU_HW_VERSION)
            {
                NRF_LOG_WARNING("Faulty HW version.");
                ret_val = EXT_ERR( NRF_DFU_EXT_ERROR_HW_VERSION_FAILURE);
            }
    
            else if (!sd_req_ok(p_init))
            {
                NRF_LOG_WARNING("SD req not met.");
                ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_SD_VERSION_FAILURE);
            }
            else if (p_init->has_fw_version)
            {
                if (!fw_version_ok(p_init))
                {
                    NRF_LOG_WARNING("FW version too low.");
                    ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_FW_VERSION_FAILURE);
                }
            }
            else
            {
                if (fw_version_required(p_init->type))
                {
                    NRF_LOG_ERROR("FW version missing.");
                    ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_INIT_COMMAND_INVALID);
                }
            }
        }
        return ret_val;
    }

    which in turn is called by nrf_dfu_validation_prevalidate(), which checks the signature _before_ calling nrf_dfu_ver_validation_check(). 

    nrf_dfu_result_t nrf_dfu_validation_prevalidate(void)
    {
        nrf_dfu_result_t                 ret_val        = NRF_DFU_RES_CODE_SUCCESS;
        dfu_command_t            const * p_command      = &m_packet.command;
        dfu_signature_type_t             signature_type = DFU_SIGNATURE_TYPE_MIN;
        uint8_t                  const * p_signature    = NULL;
        uint32_t                         signature_len  = 0;
    
        if (m_packet.has_signed_command)
        {
            p_command      = &m_packet.signed_command.command;
            signature_type =  m_packet.signed_command.signature_type;
            p_signature    =  m_packet.signed_command.signature.bytes;
            signature_len  =  m_packet.signed_command.signature.size;
        }
    
        // Validate signature.
        if (signature_required(p_command->init.type))
        {
            ret_val = nrf_dfu_validation_signature_check(signature_type,
                                                         p_signature,
                                                         signature_len,
                                                         m_init_packet_data_ptr,
                                                         m_init_packet_data_len);
        }
    
        // Validate versions.
        if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
        {
            ret_val = nrf_dfu_ver_validation_check(&p_command->init);
        }
    
        if (ret_val != NRF_DFU_RES_CODE_SUCCESS)
        {
            NRF_LOG_WARNING("Prevalidation failed.");
            NRF_LOG_DEBUG("Init command:");
            NRF_LOG_HEXDUMP_DEBUG(m_init_packet_data_ptr, m_init_packet_data_len);
        }
    
        return ret_val;
    }

    If you want to disable the signature check and version requirement for the bootloader you will have to modify the source. 

    Best regards

    Bjørn

  • Bjørn

    Hi Bjorn,

    I am confused about how nrf_dfu_validation_prevalidate() verify signature. According to my understanding, the signature from init packet is generated based on the firmware to be updated. The nrf_dfu_validation_signature_check() function will compare if the hash calculated from firmware is the same with the hash from signature. However, the firmware is not available during the prevalidation. To this end, I do not know how the signature is verified.

    From source code, nrf_dfu_validation_prevalidate() call nrf_dfu_validation_signature_check() function with m_init_packet_data_ptr as one of the input. m_init_packet_data_ptr will then be used to calculate the hash, which is obviously the hash from init packet instead of firmware to be updated.

    I might misunderstand some part of the code. Really appreciate if you can explain this to me. Thanks for your time.

Related