int main() { static char address[5]; sd_mbr_command(&startSdCmd); sd_softdevice_vector_table_base_set(BOOTLOADER_ADDRESS); // If the master boot switch has detected short or no click: boot the firmware if (((NRF_POWER->GPREGRET&0x86U) != 0x82U) && ((NRF_POWER->GPREGRET&0x40U) != 0x40U) && (*(uint32_t *)FW_ADDRESS != 0xFFFFFFFFU) ) { start_firmware(); } if (NRF_POWER->GPREGRET&0x40U) { address[4] = 0xb1; memcpy(&address[0], (char*)&NRF_FICR->DEVICEADDR[0], 4); esbSetAddress(address); } NRF_POWER->GPREGRET &= ~(0x60U); // Enable the radio LNA nrf_gpio_cfg_output(RADIO_PAEN_PIN); nrf_gpio_pin_set(RADIO_PAEN_PIN); // Initialize timer module. APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, false); ble_init(); /* NRF_CLOCK->LFCLKSRC = CLOCK_LFCLKSTAT_SRC_Synth; NRF_CLOCK->TASKS_LFCLKSTART = 1UL; while(!NRF_CLOCK->EVENTS_LFCLKSTARTED); */ systickInit(); buttonInit(buttonIdle); #ifndef DEBUG_TIMESLOT //sd_ppi_channel_assign(0, &(NRF_TIMER1->EVENTS_COMPARE[0]), &(NRF_GPIOTE->TASKS_OUT[0])); //sd_ppi_channel_enable_set(PPI_CHEN_CH0_Msk); //NRF_PPI->CH[0].EEP = &(NRF_TIMER1->EVENTS_COMPARE[0]); //NRF_PPI->CH[0].TEP = &(NRF_GPIOTE->TASKS_OUT[0]); //NRF_PPI->CHENSET = 1; #endif // Start (or continue) to blink the LED at 0.5Hz //NRF_TIMER1->TASKS_STOP = 1; //NRF_TIMER1->MODE = TIMER_MODE_MODE_Timer; //NRF_TIMER1->PRESCALER = 7; //NRF_TIMER1->BITMODE = TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos; //NRF_TIMER1->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Msk; // | TIMER_SHORTS_COMPARE1_CLEAR_Msk; //NRF_TIMER1->TASKS_CLEAR = 1; NRF_TIMER1->CC[0] = 1*SEC; //0x1E84 ; NRF_TIMER1->CC[1] = 2*SEC; nrf_gpio_cfg_output(LED_PIN); nrf_gpiote_task_config(0, LED_PIN, NRF_GPIOTE_POLARITY_TOGGLE, NRF_GPIOTE_INITIAL_VALUE_LOW); NRF_TIMER1->TASKS_START = 1; // Enable 500mA USB input and enable battery charging nrf_gpio_cfg_output(PM_EN1); nrf_gpio_pin_set(PM_EN1); nrf_gpio_cfg_output(PM_EN2); nrf_gpio_pin_clear(PM_EN2); nrf_gpio_cfg_output(PM_CHG_EN); nrf_gpio_pin_clear(PM_CHG_EN); // Power STM32, hold reset nrf_gpio_cfg_output(PM_VCCEN_PIN); nrf_gpio_pin_set(PM_VCCEN_PIN); nrf_gpio_cfg_output(STM_NRST_PIN); nrf_gpio_pin_clear(STM_NRST_PIN); // Set flow control and activate pull-down on RX data pin nrf_gpio_cfg_output(UART_TX_PIN); nrf_gpio_pin_set(UART_TX_PIN); nrf_gpio_cfg_output(UART_RTS_PIN); nrf_gpio_pin_set(UART_RTS_PIN); nrf_gpio_cfg_input(UART_RX_PIN, NRF_GPIO_PIN_PULLDOWN); nrf_gpio_pin_set(STM_NRST_PIN); //systickInit(); //syslinkInit(); //buttonInit(); // nrf_gpio_cfg_input(BUTTON_PIN, NRF_GPIO_PIN_PULLUP); mainLoop(); while(1); }
/*! \fn main(void) * \brief Main function * \note For our security chain to be valid, EEP_BOOT_PWD_SET in eeprom needs to be set to BOOTLOADER_PWDOK_KEY */ int main(void) { /* Fetch bootkey in eeprom */ uint16_t current_bootkey_val = eeprom_read_word((uint16_t*)EEP_BOOTKEY_ADDR); // Bootkey in EEPROM uint8_t new_aes_key[AES_KEY_LENGTH/8]; // New AES encryption key uint8_t cur_aes_key[AES_KEY_LENGTH/8]; // AES encryption key uint8_t firmware_data[SPM_PAGESIZE]; // One page of firmware data aes256_context temp_aes_context; // AES context uint8_t cur_cbc_mac[16]; // Current CBCMAC val uint8_t temp_data[16]; // Temporary 16 bytes array RET_TYPE flash_init_result; // Flash initialization result uint16_t firmware_start_address = UINT16_MAX - MAX_FIRMWARE_SIZE - sizeof(cur_cbc_mac) - sizeof(cur_aes_key) + 1; // Start address of firmware in external memory uint16_t firmware_end_address = UINT16_MAX - sizeof(cur_cbc_mac) - sizeof(cur_aes_key) + 1; // End address of firmware in external memory /* Just in case we are going to disable the watch dog timer and disable interrupts */ cli(); wdt_reset(); wdt_clear_flag(); wdt_change_enable(); wdt_stop(); /* Check fuses: 2k words, SPIEN, BOD 4.3V, BOOTRST programming & ver disabled >> http://www.engbedded.com/fusecalc/ */ if ((boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS) != 0xFF) || (boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS) != 0xD8) || (boot_lock_fuse_bits_get(GET_EXTENDED_FUSE_BITS) != 0xF8) || (boot_lock_fuse_bits_get(GET_LOCK_BITS) != 0xFC)) { while(1); } /* If security isn't set in place yet, no point in launching the bootloader */ if (eeprom_read_byte((uint8_t*)EEP_BOOT_PWD_SET) != BOOTLOADER_PWDOK_KEY) { start_firmware(); } /* Check if the device is booting normally, if the bootloader was called, or unknown state */ if (current_bootkey_val == CORRECT_BOOTKEY) { /* Security system set, correct bootkey for firmware */ start_firmware(); } else if (current_bootkey_val != BOOTLOADER_BOOTKEY) { /* Security system set, bootkey isn't the bootloader one nor the main fw one... */ while(1); } /* By default, brick the device so it's an all or nothing update procedure */ eeprom_write_word((uint16_t*)EEP_BOOTKEY_ADDR, BRICKED_BOOTKEY); /* Init IOs */ UHWCON = 0x01; // Enable USB 3.3V LDO initFlashIOs(); // Init EXT Flash IOs spiUsartBegin(); // Init SPI Controller DDR_ACC_SS |= (1 << PORTID_ACC_SS); // Setup PORT for the Accelerometer SS PORT_ACC_SS |= (1 << PORTID_ACC_SS); // Setup PORT for the Accelerometer SS DDR_OLED_SS |= (1 << PORTID_OLED_SS); // Setup PORT for the OLED SS PORT_OLED_SS |= (1 << PORTID_OLED_SS); // Setup PORT for the OLED SS for (uint16_t i = 0; i < 20000; i++) asm volatile ("NOP"); /* Disable I2C block of the Accelerometer */ PORT_ACC_SS &= ~(1 << PORTID_ACC_SS); spiUsartTransfer(0x23); spiUsartTransfer(0x02); PORT_ACC_SS |= (1 << PORTID_ACC_SS); /* Check Flash */ flash_init_result = checkFlashID(); if (flash_init_result != RETURN_OK) { while(1); } for (uint8_t pass_number = 0; pass_number < 2; pass_number++) { /* Init CBCMAC encryption context*/ eeprom_read_block((void*)cur_aes_key, (void*)EEP_BOOT_PWD, sizeof(cur_aes_key)); memset((void*)cur_cbc_mac, 0x00, sizeof(cur_cbc_mac)); memset((void*)temp_data, 0x00, sizeof(temp_data)); aes256_init_ecb(&temp_aes_context, cur_aes_key); // Compute CBCMAC for between the start of the graphics zone until the max addressing space (65536) - the size of the CBCMAC for (uint16_t i = GRAPHIC_ZONE_START; i < (UINT16_MAX - sizeof(cur_cbc_mac) + 1); i += sizeof(cur_cbc_mac)) { // Read data from external flash flashRawRead(temp_data, i, sizeof(temp_data)); // If we got to the part containing to firmware if ((i >= firmware_start_address) && (i < firmware_end_address)) { // Append firmware data to current buffer uint16_t firmware_data_address = i - firmware_start_address; memcpy(firmware_data + (firmware_data_address & SPM_PAGE_SIZE_BYTES_BM), temp_data, sizeof(temp_data)); // If we have a full page in buffer, flash it firmware_data_address += sizeof(cur_cbc_mac); if (((firmware_data_address & SPM_PAGE_SIZE_BYTES_BM) == 0x0000) && (pass_number == 1)) { boot_program_page(firmware_data_address - SPM_PAGESIZE, firmware_data); } } // If we got to the part containing the encrypted new aes key (end of the for()) if (i >= firmware_end_address) { memcpy(new_aes_key + i - firmware_end_address, temp_data, sizeof(temp_data)); } // Continue computation of CBCMAC aesXorVectors(cur_cbc_mac, temp_data, sizeof(temp_data)); aes256_encrypt_ecb(&temp_aes_context, cur_cbc_mac); } // Read CBCMAC in memory and compare it with the computed value flashRawRead(temp_data, (UINT16_MAX - sizeof(cur_cbc_mac) + 1), sizeof(cur_cbc_mac)); if (pass_number == 0) { // First pass, compare CBCMAC and see if we do the next pass or start the firmware if (sideChannelSafeMemCmp(temp_data, cur_cbc_mac, sizeof(cur_cbc_mac)) != 0) { // No match, start the main firmware eeprom_write_word((uint16_t*)EEP_BOOTKEY_ADDR, CORRECT_BOOTKEY); start_firmware(); } else { // Otherwise, next pass! } } else { // Second pass, compare CBCMAC and then update AES keys if (sideChannelSafeMemCmp(temp_data, cur_cbc_mac, sizeof(cur_cbc_mac)) == 0) { // Fetch the encrypted new aes key from flash, decrypt it, store it aes256_decrypt_ecb(&temp_aes_context, new_aes_key); aes256_decrypt_ecb(&temp_aes_context, new_aes_key+16); eeprom_write_block((void*)new_aes_key, (void*)EEP_BOOT_PWD, sizeof(new_aes_key)); eeprom_write_word((uint16_t*)EEP_BOOTKEY_ADDR, CORRECT_BOOTKEY); start_firmware(); } else { // Fail, erase everything! >> maybe just write a while(1) in the future? for (uint16_t i = 0; i < MAX_FIRMWARE_SIZE; i += SPM_PAGESIZE) { boot_page_erase(i); boot_spm_busy_wait(); } while(1); } } } }