uint32_t dfu_init_prevalidate(uint8_t * p_init_data, uint32_t init_data_len) { uint32_t i = 0; static uint32_t err_code; nrf_sec_data_t init_data; nrf_sec_ecc_signature_t signature; // In order to support encryption then any init packet decryption function / library // should be called from here or implemented at this location. // Length check to ensure valid data are parsed. if (init_data_len < sizeof(dfu_init_packet_t)) { return NRF_ERROR_INVALID_LENGTH; } // Current template uses clear text data so they can be casted for pre-check. dfu_init_packet_t * p_init_packet = (dfu_init_packet_t *)p_init_data; m_extended_packet_length = ((uint32_t)p_init_data + init_data_len) - (uint32_t)&p_init_packet->softdevice[p_init_packet->softdevice_len]; if (m_extended_packet_length < DFU_INIT_PACKET_EXT_LENGTH_MIN) { return NRF_ERROR_INVALID_LENGTH; } if (((uint32_t)p_init_data + init_data_len) < (uint32_t)&p_init_packet->softdevice[p_init_packet->softdevice_len]) { return NRF_ERROR_INVALID_LENGTH; } memcpy(&m_extended_packet, &p_init_packet->softdevice[p_init_packet->softdevice_len], m_extended_packet_length); /** [DFU init application version] */ // To support application versioning, this check should be updated. // This template allows for any application to be installed. However, // customers can place a revision number at the bottom of the application // to be verified by the bootloader. This can be done at a location // relative to the application, for example the application start // address + 0x0100. /** [DFU init application version] */ // First check to verify the image to be transfered matches the device type. // If no Device type is present in DFU_DEVICE_INFO then any image will be accepted. if ((DFU_DEVICE_INFO->device_type != DFU_DEVICE_TYPE_EMPTY) && (p_init_packet->device_type != DFU_DEVICE_INFO->device_type)) { return NRF_ERROR_INVALID_DATA; } // Second check to verify the image to be transfered matches the device revision. // If no Device revision is present in DFU_DEVICE_INFO then any image will be accepted. if ((DFU_DEVICE_INFO->device_rev != DFU_DEVICE_REVISION_EMPTY) && (p_init_packet->device_rev != DFU_DEVICE_INFO->device_rev)) { return NRF_ERROR_INVALID_DATA; } // Third check: Check the array of supported SoftDevices by this application. // If the installed SoftDevice does not match any SoftDevice in the list then an // error is returned. while (i < p_init_packet->softdevice_len) { if (p_init_packet->softdevice[i] == DFU_SOFTDEVICE_ANY || p_init_packet->softdevice[i++] == SD_FWID_GET(MBR_SIZE)) { // Found a match. Break the loop. break; } // No matching SoftDevice found - Return NRF_ERROR_INVALID_DATA. return NRF_ERROR_INVALID_DATA; } // Check that we have the correct identifier indicating that ECDS is used if(*(uint32_t*)&m_extended_packet[DFU_INIT_PACKET_POS_EXT_IDENTIFIER] != DFU_INIT_PACKET_USES_ECDS) { return NRF_ERROR_INVALID_DATA; } // init_data consists of the regular init-packet and all the extended packet data excluding the signing key init_data.length = (init_data_len - m_extended_packet_length) + DFU_INIT_PACKET_EXT_LENGTH_SIGNED; init_data.p_data = p_init_data; signature.p_r = &m_extended_packet[DFU_INIT_PACKET_POS_EXT_INIT_SIGNATURE_R]; signature.r_len = DFU_SIGNATURE_R_LENGTH; signature.p_s = &m_extended_packet[DFU_INIT_PACKET_POS_EXT_INIT_SIGNATURE_S]; signature.s_len = DFU_SIGNATURE_S_LENGTH; err_code = nrf_sec_svc_verify(&init_data, &Q ,&signature, NRF_SEC_NIST256_SHA256); return err_code; }
uint32_t dfu_init_prevalidate(uint8_t * p_init_data, uint32_t init_data_len) { uint32_t i = 0; // In order to support signing or encryption then any init packet decryption function / library // should be called from here or implemented at this location. // Length check to ensure valid data are parsed. if (init_data_len < sizeof(dfu_init_packet_t)) { return NRF_ERROR_INVALID_LENGTH; } // Current template uses clear text data so they can be casted for pre-check. dfu_init_packet_t * p_init_packet = (dfu_init_packet_t *)p_init_data; m_extended_packet_length = ((uint32_t)p_init_data + init_data_len) - (uint32_t)&p_init_packet->softdevice[p_init_packet->softdevice_len]; if (m_extended_packet_length < DFU_INIT_PACKET_EXT_LENGTH_MIN) { return NRF_ERROR_INVALID_LENGTH; } if (((uint32_t)p_init_data + init_data_len) < (uint32_t)&p_init_packet->softdevice[p_init_packet->softdevice_len]) { return NRF_ERROR_INVALID_LENGTH; } memcpy(m_extended_packet, &p_init_packet->softdevice[p_init_packet->softdevice_len], m_extended_packet_length); /** [DFU init application version] */ // To support application versioning, this check should be updated. // This template allows for any application to be installed. However, // customers can place a revision number at the bottom of the application // to be verified by the bootloader. This can be done at a location // relative to the application, for example the application start // address + 0x0100. /** [DFU init application version] */ // First check to verify the image to be transfered matches the device type. // If no Device type is present in DFU_DEVICE_INFO then any image will be accepted. if ((DFU_DEVICE_INFO->device_type != DFU_DEVICE_TYPE_EMPTY) && (p_init_packet->device_type != DFU_DEVICE_INFO->device_type)) { return NRF_ERROR_INVALID_DATA; } // Second check to verify the image to be transfered matches the device revision. // If no Device revision is present in DFU_DEVICE_INFO then any image will be accepted. if ((DFU_DEVICE_INFO->device_rev != DFU_DEVICE_REVISION_EMPTY) && (p_init_packet->device_rev != DFU_DEVICE_INFO->device_rev)) { return NRF_ERROR_INVALID_DATA; } // Third check: Check the array of supported SoftDevices by this application. // If the installed SoftDevice does not match any SoftDevice in the list then an // error is returned. while (i < p_init_packet->softdevice_len) { if (p_init_packet->softdevice[i] == DFU_SOFTDEVICE_ANY || p_init_packet->softdevice[i++] == SD_FWID_GET(MBR_SIZE)) { return NRF_SUCCESS; } } // No matching SoftDevice found - Return NRF_ERROR_INVALID_DATA. return NRF_ERROR_INVALID_DATA; }
/** @brief Function to execute the continuation of a SoftDevice update. * * @param[in] src_addr Source address of the SoftDevice to copy from. * @param[in] p_bank Pointer to the bank where the SoftDevice resides. * * @retval NRF_SUCCESS Continuation was successful. * @retval NRF_ERROR_INVALID_LENGTH Invalid len * @retval NRF_ERROR_NO_MEM if UICR.NRFFW[1] is not set (i.e. is 0xFFFFFFFF). * @retval NRF_ERROR_INVALID_PARAM if an invalid command is given. * @retval NRF_ERROR_INTERNAL indicates that the contents of the memory blocks where not verified correctly after copying. * @retval NRF_ERROR_NULL If the content of the memory blocks differs after copying. */ static uint32_t nrf_dfu_sd_continue_impl(uint32_t src_addr, nrf_dfu_bank_t * p_bank) { uint32_t ret_val = NRF_SUCCESS; uint32_t target_addr = SOFTDEVICE_REGION_START + s_dfu_settings.write_offset; uint32_t length_left = align_to_page(s_dfu_settings.sd_size - s_dfu_settings.write_offset, CODE_PAGE_SIZE); uint32_t split_size = align_to_page(length_left / 4, CODE_PAGE_SIZE); NRF_LOG_INFO("Enter nrf_bootloader_dfu_sd_continue\r\n"); // This can be a continuation due to a power failure src_addr += s_dfu_settings.write_offset; if (s_dfu_settings.sd_size != 0 && s_dfu_settings.write_offset == s_dfu_settings.sd_size) { NRF_LOG_INFO("SD already copied\r\n"); return NRF_SUCCESS; } NRF_LOG_INFO("Updating SD. Old SD ver: 0x%04x\r\n", SD_FWID_GET(MBR_SIZE)); do { NRF_LOG_INFO("Copying [0x%08x-0x%08x] to [0x%08x-0x%08x]: Len: 0x%08x\r\n", src_addr, src_addr + split_size, target_addr, target_addr + split_size, split_size); // Copy a chunk of the SD. Size in words ret_val = nrf_dfu_mbr_copy_sd((uint32_t*)target_addr, (uint32_t*)src_addr, split_size); if (ret_val != NRF_SUCCESS) { NRF_LOG_INFO("Failed to copy SD: target: 0x%08x, src: 0x%08x, len: 0x%08x\r\n", target_addr, src_addr, split_size); return ret_val; } NRF_LOG_INFO("Finished copying [0x%08x-0x%08x] to [0x%08x-0x%08x]: Len: 0x%08x\r\n", src_addr, src_addr + split_size, target_addr, target_addr + split_size, split_size); // Validate copy. Size in words ret_val = nrf_dfu_mbr_compare((uint32_t*)target_addr, (uint32_t*)src_addr, split_size); if (ret_val != NRF_SUCCESS) { NRF_LOG_INFO("Failed to Compare SD: target: 0x%08x, src: 0x%08x, len: 0x%08x\r\n", target_addr, src_addr, split_size); return ret_val; } NRF_LOG_INFO("Validated 0x%08x-0x%08x to 0x%08x-0x%08x: Size: 0x%08x\r\n", src_addr, src_addr + split_size, target_addr, target_addr + split_size, split_size); target_addr += split_size; src_addr += split_size; if (split_size > length_left) { length_left = 0; } else { length_left -= split_size; } NRF_LOG_INFO("Finished with the SD update.\r\n"); // Save the updated point of writes in case of power loss s_dfu_settings.write_offset = s_dfu_settings.sd_size - length_left; (void)nrf_dfu_settings_write(NULL); } while (length_left > 0); return ret_val; }