From 70fb28feb2d5312304d7fa3e597679ba8c8e8dc1 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Tue, 25 Feb 2020 17:35:36 +0100 Subject: [PATCH] Bootloader: Verify signatures --- lib/dfu-bootloader.c | 133 +++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 82 deletions(-) diff --git a/lib/dfu-bootloader.c b/lib/dfu-bootloader.c index bec2c33..cb314d8 100644 --- a/lib/dfu-bootloader.c +++ b/lib/dfu-bootloader.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -31,21 +32,19 @@ #define DEBUG(x...) do { } while (0) #endif +// Offsets to firmware header fields (see tools/dfu-sign.c) +#define HDR_LENGTH 0x1c +#define HDR_FLASH_IN_PROGRESS 0x20 + byte usbd_control_buffer[1024]; static enum dfu_state usbdfu_state = STATE_DFU_IDLE; -struct prog_info { +static struct { byte buf[sizeof(usbd_control_buffer)]; u16 blocknum; u16 len; -}; - -static struct prog_info prog_page; - -// The first page of application code is programmed last, -// so that we are able to detect incompletely uploaded firmware. -static struct prog_info prog_header; +} prog; static char usb_serial_number[13]; @@ -117,20 +116,7 @@ const struct usb_config_descriptor config = { .interface = ifaces, }; -#if 0 // FIXME -static u32 adhoc_checksum(u32 start, uint len) -{ - u32 end = start + len; - u32 sum = 0; - while (start < end) { - sum *= 259309; - sum += *(volatile u32 *)start; - start += 4; - } - return sum; -} -#endif - +// FIXME: Rename usbdfu_ to dfu_ static byte usbdfu_getstatus(usbd_device *usbd_dev UNUSED, u32 *bwPollTimeout) { switch (usbdfu_state) { @@ -147,46 +133,31 @@ static byte usbdfu_getstatus(usbd_device *usbd_dev UNUSED, u32 *bwPollTimeout) } } -static void program_page(struct prog_info *prog, bool need_erase) -{ - flash_unlock(); - u32 baseaddr = BOOTLOADER_APP_START + prog->blocknum * dfu_function.wTransferSize; - DEBUG("DFU: Block %u -> %08x + %u\n", prog->blocknum, (uint) baseaddr, prog->len); - if (need_erase) - flash_erase_page(baseaddr); - for (uint i = 0; i < prog->len; i += 2) { - u16 data = *(u16 *)(prog->buf + i); - flash_program_half_word(baseaddr + i, data); - } - flash_lock(); -#if 0 - u32 s1 = adhoc_checksum((u32) prog->buf, prog->len); - u32 s2 = adhoc_checksum(baseaddr, prog->len); - DEBUG("\t%08x %08x\n", (uint) s1, (uint) s2); - if (s1 != s2) - DEBUG("\t!!!!!!!!!!!!!!!!!!!!!!!!!\n"); -#endif -} - static void usbdfu_getstatus_complete(usbd_device *usbd_dev UNUSED, struct usb_setup_data *req UNUSED) { switch (usbdfu_state) { case STATE_DFU_DNBUSY: - if (prog_page.blocknum == 0) { - // The first block will be programmed last - prog_header = prog_page; - flash_unlock(); - flash_erase_page(BOOTLOADER_APP_START); - flash_lock(); - } else - program_page(&prog_page, true); + if (prog.blocknum == 0) + *(u16*)(prog.buf + HDR_FLASH_IN_PROGRESS) = 0xffff; + flash_unlock(); + u32 baseaddr = BOOTLOADER_APP_START + prog.blocknum * dfu_function.wTransferSize; + DEBUG("DFU: Block %u -> %08x + %u\n", prog.blocknum, (uint) baseaddr, prog.len); + flash_erase_page(baseaddr); + for (uint i = 0; i < prog.len; i += 2) { + u16 data = *(u16 *)(prog.buf + i); + flash_program_half_word(baseaddr + i, data); + } + flash_lock(); usbdfu_state = STATE_DFU_DNLOAD_IDLE; return; case STATE_DFU_MANIFEST: // At the very end, program the first page - program_page(&prog_header, false); + // FIXME + flash_unlock(); + flash_program_half_word(BOOTLOADER_APP_START + 0x20, 0); + flash_lock(); usbdfu_state = STATE_DFU_MANIFEST_WAIT_RESET; - return; /* Will never return. */ + return; default: return; } @@ -209,9 +180,9 @@ static enum usbd_request_return_codes usbdfu_control_request(usbd_device *usbd_d usbdfu_state = STATE_DFU_MANIFEST_SYNC; } else { /* Copy download data for use on GET_STATUS. */ - prog_page.blocknum = req->wValue; - prog_page.len = *len; - memcpy(prog_page.buf, *buf, *len); + prog.blocknum = req->wValue; + prog.len = *len; + memcpy(prog.buf, *buf, *len); usbdfu_state = STATE_DFU_DNLOAD_SYNC; } return USBD_REQ_HANDLED; @@ -335,10 +306,8 @@ static void clock_plain_hsi(void) rcc_set_usbpre(RCC_CFGR_USBPRE_PLL_VCO_CLK_DIV3); } -int main(void) +static void reset_peripherals(void) { - usbd_device *usbd_dev; - // Turn off clock to all peripherals and reset them RCC_AHBENR = 0x00000014; RCC_APB1ENR = 0; @@ -347,6 +316,13 @@ int main(void) RCC_APB2RSTR = 0x0038fffd; RCC_APB1RSTR = 0; RCC_APB2RSTR = 0; +} + +int main(void) +{ + usbd_device *usbd_dev; + + reset_peripherals(); // Flash programming requires running on the internal oscillator my_rcc_clock_setup_in_hsi_out_48mhz(); @@ -354,6 +330,7 @@ int main(void) rcc_periph_clock_enable(RCC_GPIOA); rcc_periph_clock_enable(RCC_GPIOC); rcc_periph_clock_enable(RCC_USB); + rcc_periph_clock_enable(RCC_CRC); #ifdef DEBUG_USART // Currently, only USART1 is supported @@ -404,47 +381,39 @@ int main(void) restart: ; uint timeout = 5000; - while (timeout) { + while (timeout || (usbdfu_state != STATE_DFU_IDLE && usbdfu_state != STATE_DFU_MANIFEST_WAIT_RESET)) { usbd_poll(usbd_dev); - if (systick_get_countflag()) { + if (timeout && systick_get_countflag()) { timeout--; if (!(timeout & 0x3f)) debug_led_toggle(); } } - volatile u32 *app = (volatile u32 *) BOOTLOADER_APP_START; + u32 *app = (u32 *) BOOTLOADER_APP_START; u32 sp = app[0]; u32 pc = app[1]; - -#if 0 - uint len = 7140; - u32 sum = adhoc_checksum(BOOTLOADER_APP_START, len); - DEBUG("DFU: Checksum=%08x, len=%u\n", (uint) sum, len); -#endif - - DEBUG("DFU: Starting application (sp=%08x, pc=%08x)\n", (uint) sp, (uint) pc); - if ((sp & 0x2ffe0000) != 0x20000000) { - DEBUG("DFU: Suspicious SP, refusing to start\n"); + u32 len = app[HDR_LENGTH/4]; + u16 flash_in_progress = *(u16 *)(BOOTLOADER_APP_START + HDR_FLASH_IN_PROGRESS); + + crc_reset(); + u32 crc = crc_calculate_block(app, len/4); + u32 want_crc = *(u32 *)(BOOTLOADER_APP_START + len); + DEBUG("DFU: fip=%04x, crc=%08x, want=%08x, len=%u\n", (uint) flash_in_progress, (uint) crc, (uint) want_crc, (uint) len); + if (flash_in_progress || crc != want_crc) { + DEBUG("DFU: Bad firmware\n"); goto restart; } + DEBUG("DFU: Starting application (sp=%08x, pc=%08x)\n", (uint) sp, (uint) pc); + #ifdef DEBUG_USART while (!usart_get_flag(DEBUG_USART, USART_FLAG_TC)) ; #endif debug_led(0); - rcc_periph_clock_disable(RCC_GPIOA); - rcc_periph_clock_disable(RCC_GPIOC); - rcc_periph_clock_disable(RCC_USB); - rcc_periph_clock_disable(RCC_USART1); - - rcc_periph_reset_pulse(RST_GPIOA); - rcc_periph_reset_pulse(RST_GPIOC); - rcc_periph_reset_pulse(RST_USB); - rcc_periph_reset_pulse(RST_USART1); - + reset_peripherals(); clock_plain_hsi(); /* Set vector table base address. */ -- 2.39.2