From 94828d825bc7f293aaf4a42555dcee1a8020c58e Mon Sep 17 00:00:00 2001 From: "jacob.eva" Date: Mon, 13 May 2024 22:25:24 +0100 Subject: [PATCH] Add firmware hash calculation to RAK4631 + more --- Boards.h | 10 +-- Device.h | 155 ++++++++++++++++++++++++++++++++++++++++++++- Makefile | 9 ++- RNode_Firmware.ino | 8 ++- ROM.h | 3 + Utilities.h | 39 +++++++----- sx126x.cpp | 2 +- 7 files changed, 199 insertions(+), 27 deletions(-) diff --git a/Boards.h b/Boards.h index e9c069e..23f9191 100644 --- a/Boards.h +++ b/Boards.h @@ -41,7 +41,7 @@ #define BOARD_RNODE_NG_21 0x41 #define BOARD_RNODE_NG_22 0x42 #define BOARD_GENERIC_NRF52 0x50 - #define BOARD_RAK4630 0x51 + #define BOARD_RAK4631 0x51 #if defined(__AVR_ATmega1284P__) #define PLATFORM PLATFORM_AVR @@ -61,7 +61,7 @@ #endif #ifndef MODEM - #if BOARD_MODEL == BOARD_RAK4630 + #if BOARD_MODEL == BOARD_RAK4631 #define MODEM SX1262 #elif BOARD_MODEL == BOARD_GENERIC_NRF52 #define MODEM SX1262 @@ -392,9 +392,9 @@ #endif #elif MCU_VARIANT == MCU_NRF52 - #if BOARD_MODEL == BOARD_RAK4630 + #if BOARD_MODEL == BOARD_RAK4631 #define HAS_EEPROM false - #define HAS_DISPLAY true + #define HAS_DISPLAY false #define HAS_BLUETOOTH false #define HAS_BLE true #define HAS_CONSOLE false @@ -407,7 +407,7 @@ #define CONFIG_UART_BUFFER_SIZE 6144 #define CONFIG_QUEUE_SIZE 6144 #define CONFIG_QUEUE_MAX_LENGTH 200 - #define EEPROM_SIZE 200 + #define EEPROM_SIZE 296 #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED #define BLE_MANUFACTURER "RAK Wireless" #define BLE_MODEL "RAK4640" diff --git a/Device.h b/Device.h index e354847..1f027dd 100644 --- a/Device.h +++ b/Device.h @@ -20,10 +20,29 @@ #include "esp_ota_ops.h" #include "esp_flash_partitions.h" #include "esp_partition.h" + +#elif MCU_VARIANT == MCU_NRF52 +#include "Adafruit_nRFCrypto.h" + +// size of chunk to retrieve from flash sector +#define CHUNK_SIZE 128 + +#define END_SECTION_SIZE 256 + +#if defined(NRF52840_XXAA) +// https://learn.adafruit.com/introducing-the-adafruit-nrf52840-feather/hathach-memory-map +// each section follows along from one another, in this order +// this is always at the start of the memory map +#define APPLICATION_START 0x26000 + +#define USER_DATA_START 0xED000 +#endif + #endif // Forward declaration from Utilities.h void eeprom_update(int mapped_addr, uint8_t byte); +void eeprom_flush(); uint8_t eeprom_read(uint32_t addr); void hard_reset(void); @@ -112,12 +131,115 @@ void device_save_firmware_hash() { for (uint8_t i = 0; i < DEV_HASH_LEN; i++) { eeprom_update(dev_fwhash_addr(i), dev_firmware_hash_target[i]); } + eeprom_flush(); if (!fw_signature_validated) hard_reset(); } -#if MCU_VARIANT == MCU_ESP32 +#if MCU_VARIANT == MCU_NRF52 +void calculate_region_hash(unsigned long long start, unsigned long long end, uint8_t* return_hash) { + // this function calculates the hash digest of a region of memory, + // currently it is only designed to work for the application region + uint8_t chunk[CHUNK_SIZE] = {0}; + + // to store potential last chunk of program + uint8_t chunk_next[CHUNK_SIZE] = {0}; + nRFCrypto_Hash hash; + + hash.begin(CRYS_HASH_SHA256_mode); + + bool finish = false; + uint8_t size; + bool application = true; + int end_count = 0; + unsigned long length = 0; + + while (start < end - 1 ) { + const void* src = (const void*)start; + if (start + CHUNK_SIZE >= end) { + size = (end - 1) - start; + } + else { + size = CHUNK_SIZE; + } + + memcpy(chunk, src, CHUNK_SIZE); + + // check if we've reached the end of the program + // if we're checking the application region + if (application) { + for (int i = 0; i < CHUNK_SIZE; i++) { + if (chunk[i] == 0xFF) { + bool matched = true; + end_count = 1; + // check if rest of chunk is FFs as well, only if FF is not + // at the end of chunk + if (i < CHUNK_SIZE - 1) { + for (int x = 0; x < CHUNK_SIZE - i; x++) { + if (chunk[i+x] != 0xFF) { + matched = false; + break; + } + end_count++; + } + } + + if (matched) { + while (end_count < END_SECTION_SIZE) { + // check if bytes in next chunk up to total + // required are also FFs + for (int x = 1; x <= ceil(END_SECTION_SIZE / CHUNK_SIZE); x++) { + const void* src_next = (const void*)start + CHUNK_SIZE*x; + if ((END_SECTION_SIZE - end_count) > CHUNK_SIZE) { + size = CHUNK_SIZE; + } else { + size = END_SECTION_SIZE - end_count; + } + memcpy(chunk_next, src_next, size); + for (int y = 0; y < size; y++) { + if (chunk_next[y] != 0xFF) { + matched = false; + break; + } + end_count++; + } + + if (!matched) { + break; + } + } + if (!matched) { + break; + } + } + + if (matched) { + finish = true; + size = i; + break; + } + } + } + } + } + + if (finish) { + hash.update(chunk, size); + length += size; + break; + } else { + hash.update(chunk, size); + } + + start += CHUNK_SIZE; + length += CHUNK_SIZE; + } + hash.end(return_hash); +} +#endif + void device_validate_partitions() { device_load_firmware_hash(); + #if MCU_VARIANT == MCU_ESP32 esp_partition_t partition; partition.address = ESP_PARTITION_TABLE_OFFSET; partition.size = ESP_PARTITION_TABLE_MAX_LEN; @@ -128,6 +250,10 @@ void device_validate_partitions() { partition.type = ESP_PARTITION_TYPE_APP; esp_partition_get_sha256(&partition, dev_bootloader_hash); esp_partition_get_sha256(esp_ota_get_running_partition(), dev_firmware_hash); + #elif MCU_VARIANT == MCU_NRF52 + // todo, add bootloader, partition table, or softdevice? + calculate_region_hash(APPLICATION_START, USER_DATA_START, dev_firmware_hash); + #endif #if VALIDATE_FIRMWARE for (uint8_t i = 0; i < DEV_HASH_LEN; i++) { if (dev_firmware_hash_target[i] != dev_firmware_hash[i]) { @@ -137,15 +263,15 @@ void device_validate_partitions() { } #endif } -#endif bool device_firmware_ok() { return fw_signature_validated; } -#if MCU_VARIANT == MCU_ESP32 +#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52 bool device_init() { if (bt_ready) { + #if MCU_VARIANT == MCU_ESP32 for (uint8_t i=0; i= 8) { + if (written_bytes >= 4) { file.close(); file.open(EEPROM_FILE, FILE_O_WRITE); written_bytes = 0; @@ -1245,15 +1263,6 @@ void eeprom_update(int mapped_addr, uint8_t byte) { #endif } -#if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52 -void eeprom_flush() { - // sync file contents to flash - file.close(); - file.open(EEPROM_FILE, FILE_O_WRITE); - written_bytes = 0; -} -#endif - void eeprom_write(uint8_t addr, uint8_t byte) { if (!eeprom_info_locked() && addr >= 0 && addr < EEPROM_RESERVED) { eeprom_update(eeprom_addr(addr), byte); @@ -1293,7 +1302,7 @@ bool eeprom_product_valid() { #elif PLATFORM == PLATFORM_ESP32 if (rval == PRODUCT_RNODE || rval == BOARD_RNODE_NG_20 || rval == BOARD_RNODE_NG_21 || rval == PRODUCT_HMBRW || rval == PRODUCT_TBEAM || rval == PRODUCT_T32_10 || rval == PRODUCT_T32_20 || rval == PRODUCT_T32_21 || rval == PRODUCT_H32_V2 || rval == PRODUCT_H32_V3) { #elif PLATFORM == PLATFORM_NRF52 - if (rval == PRODUCT_HMBRW) { + if (rval == PRODUCT_RAK4631 || rval == PRODUCT_HMBRW) { #else if (false) { #endif @@ -1331,8 +1340,8 @@ bool eeprom_model_valid() { if (model == MODEL_C4 || model == MODEL_C9) { #elif BOARD_MODEL == BOARD_HELTEC32_V3 if (model == MODEL_C5 || model == MODEL_CA) { - #elif BOARD_MODEL == BOARD_RAK4630 - if (model == MODEL_FF) { + #elif BOARD_MODEL == BOARD_RAK4631 + if (model == MODEL_11 || model == MODEL_12) { #elif BOARD_MODEL == BOARD_HUZZAH32 if (model == MODEL_FF) { #elif BOARD_MODEL == BOARD_GENERIC_ESP32 diff --git a/sx126x.cpp b/sx126x.cpp index a425e00..d371251 100644 --- a/sx126x.cpp +++ b/sx126x.cpp @@ -717,7 +717,7 @@ void sx126x::sleep() void sx126x::enableTCXO() { #if HAS_TCXO - #if BOARD_MODEL == BOARD_RAK4630 || BOARD_MODEL == BOARD_HELTEC32_V3 + #if BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_HELTEC32_V3 uint8_t buf[4] = {MODE_TCXO_3_3V_6X, 0x00, 0x00, 0xFF}; #elif BOARD_MODEL == BOARD_TBEAM uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF};