rboot: Add cryptographic digest support for OTA images & SHA256 example
This commit is contained in:
parent
03559de5cb
commit
53b2b50241
5 changed files with 88 additions and 6 deletions
|
@ -1,5 +1,5 @@
|
||||||
PROGRAM=ota_basic
|
PROGRAM=ota_basic
|
||||||
OTA=1
|
OTA=1
|
||||||
EXTRA_COMPONENTS=extras/rboot-ota
|
EXTRA_COMPONENTS=extras/rboot-ota extras/mbedtls
|
||||||
include ../../common.mk
|
include ../../common.mk
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,14 @@
|
||||||
*
|
*
|
||||||
* NOT SUITABLE TO PUT ON THE INTERNET OR INTO A PRODUCTION ENVIRONMENT!!!!
|
* NOT SUITABLE TO PUT ON THE INTERNET OR INTO A PRODUCTION ENVIRONMENT!!!!
|
||||||
*/
|
*/
|
||||||
|
#include <string.h>
|
||||||
#include "espressif/esp_common.h"
|
#include "espressif/esp_common.h"
|
||||||
#include "esp/uart.h"
|
#include "esp/uart.h"
|
||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
#include "esp8266.h"
|
#include "esp8266.h"
|
||||||
#include "ssid_config.h"
|
#include "ssid_config.h"
|
||||||
|
#include "mbedtls/sha256.h"
|
||||||
|
|
||||||
#include "ota-tftp.h"
|
#include "ota-tftp.h"
|
||||||
#include "rboot.h"
|
#include "rboot.h"
|
||||||
|
@ -21,6 +23,9 @@
|
||||||
#define TFTP_IMAGE_FILENAME1 "firmware1.bin"
|
#define TFTP_IMAGE_FILENAME1 "firmware1.bin"
|
||||||
#define TFTP_IMAGE_FILENAME2 "firmware2.bin"
|
#define TFTP_IMAGE_FILENAME2 "firmware2.bin"
|
||||||
|
|
||||||
|
/* Output of the command 'sha256sum firmware1.bin' */
|
||||||
|
static const char *FIRMWARE1_SHA256 = "88199daff8b9e76975f685ec7f95bc1df3c61bd942a33a54a40707d2a41e5488";
|
||||||
|
|
||||||
void tftp_client_task(void *pvParameters)
|
void tftp_client_task(void *pvParameters)
|
||||||
{
|
{
|
||||||
printf("TFTP client task starting...\n");
|
printf("TFTP client task starting...\n");
|
||||||
|
@ -43,10 +48,44 @@ void tftp_client_task(void *pvParameters)
|
||||||
int res = ota_tftp_download(TFTP_IMAGE_SERVER, TFTP_PORT, TFTP_IMAGE_FILENAME1, 1000, slot);
|
int res = ota_tftp_download(TFTP_IMAGE_SERVER, TFTP_PORT, TFTP_IMAGE_FILENAME1, 1000, slot);
|
||||||
printf("ota_tftp_download %s result %d\n", TFTP_IMAGE_FILENAME1, res);
|
printf("ota_tftp_download %s result %d\n", TFTP_IMAGE_FILENAME1, res);
|
||||||
if(res == 0) {
|
if(res == 0) {
|
||||||
printf("Rebooting into slot %d...\n", slot);
|
printf("Looks valid, calculating SHA256...\n");
|
||||||
|
uint32_t length;
|
||||||
|
bool valid = rboot_verify_image(conf.roms[slot], &length, NULL);
|
||||||
|
static mbedtls_sha256_context ctx;
|
||||||
|
mbedtls_sha256_init(&ctx);
|
||||||
|
mbedtls_sha256_starts(&ctx, 0);
|
||||||
|
valid = valid && rboot_digest_image(conf.roms[slot], length, (rboot_digest_update_fn)mbedtls_sha256_update, &ctx);
|
||||||
|
static uint8_t hash_result[32];
|
||||||
|
mbedtls_sha256_finish(&ctx, hash_result);
|
||||||
|
mbedtls_sha256_free(&ctx);
|
||||||
|
|
||||||
|
if(!valid)
|
||||||
|
{
|
||||||
|
printf("Not valid after all :(\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Image SHA256 = ");
|
||||||
|
bool valid = true;
|
||||||
|
for(int i = 0; i < sizeof(hash_result); i++) {
|
||||||
|
char hexbuf[3];
|
||||||
|
snprintf(hexbuf, 3, "%02x", hash_result[i]);
|
||||||
|
printf(hexbuf);
|
||||||
|
if(strncmp(hexbuf, FIRMWARE1_SHA256+i*2, 2))
|
||||||
|
valid = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
if (valid) {
|
||||||
|
printf("SHA256 Matches. Rebooting into slot %d...\n", slot);
|
||||||
rboot_set_current_rom(slot);
|
rboot_set_current_rom(slot);
|
||||||
sdk_system_restart();
|
sdk_system_restart();
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
printf("Downloaded image SHA256 didn't match expected '%s'\n", FIRMWARE1_SHA256);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
vTaskDelay(5000 / portTICK_RATE_MS);
|
vTaskDelay(5000 / portTICK_RATE_MS);
|
||||||
|
|
||||||
printf("Downloading %s to slot %d...\n", TFTP_IMAGE_FILENAME2, slot);
|
printf("Downloading %s to slot %d...\n", TFTP_IMAGE_FILENAME2, slot);
|
||||||
|
@ -77,5 +116,5 @@ void user_init(void)
|
||||||
sdk_wifi_station_set_config(&config);
|
sdk_wifi_station_set_config(&config);
|
||||||
|
|
||||||
ota_tftp_init_server(TFTP_PORT);
|
ota_tftp_init_server(TFTP_PORT);
|
||||||
xTaskCreate(&tftp_client_task, (signed char *)"tftp_client", 1024, NULL, 2, NULL);
|
xTaskCreate(&tftp_client_task, (signed char *)"tftp_client", 2048, NULL, 2, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -369,7 +369,9 @@ static err_t tftp_receive_data(struct netconn *nc, size_t write_offs, size_t lim
|
||||||
it so the client gets an indication if things were successful.
|
it so the client gets an indication if things were successful.
|
||||||
*/
|
*/
|
||||||
const char *err = "Unknown validation error";
|
const char *err = "Unknown validation error";
|
||||||
if(!rboot_verify_image(start_offs, *received_len, &err)) {
|
uint32_t image_length;
|
||||||
|
if(!rboot_verify_image(start_offs, &image_length, &err)
|
||||||
|
|| image_length != *received_len) {
|
||||||
tftp_send_error(nc, TFTP_ERR_ILLEGAL, err);
|
tftp_send_error(nc, TFTP_ERR_ILLEGAL, err);
|
||||||
return ERR_VAL;
|
return ERR_VAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -355,6 +355,20 @@ bool rboot_verify_image(uint32_t initial_offset, uint32_t *image_length, const c
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool rboot_digest_image(uint32_t offset, uint32_t image_length, rboot_digest_update_fn update_fn, void *update_ctx)
|
||||||
|
{
|
||||||
|
uint8_t buf[32] __attribute__((aligned(4)));
|
||||||
|
for(int i = 0; i < image_length; i += sizeof(buf)) {
|
||||||
|
if(sdk_spi_flash_read(offset+i, buf, sizeof(buf)))
|
||||||
|
return false;
|
||||||
|
uint32_t digest_len = sizeof(buf);
|
||||||
|
if(i + digest_len > image_length)
|
||||||
|
digest_len = image_length - i;
|
||||||
|
update_fn(update_ctx, buf, digest_len);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -144,6 +144,33 @@ uint32_t rboot_get_slot_offset(uint8_t slot);
|
||||||
**/
|
**/
|
||||||
bool rboot_verify_image(uint32_t offset, uint32_t *image_length, const char **error_message);
|
bool rboot_verify_image(uint32_t offset, uint32_t *image_length, const char **error_message);
|
||||||
|
|
||||||
|
|
||||||
|
/* @description Digest callback prototype, designed to be compatible with
|
||||||
|
mbedtls digest functions (SHA, MD5, etc.)
|
||||||
|
|
||||||
|
See the ota_basic example to see an example of calculating the
|
||||||
|
SHA256 digest of an OTA image.
|
||||||
|
*/
|
||||||
|
typedef void (*rboot_digest_update_fn)(void * ctx, void *data, size_t data_len);
|
||||||
|
|
||||||
|
/** @description Calculate a digest over the image at the offset specified
|
||||||
|
|
||||||
|
@note This function is actually a generic function that hashes SPI
|
||||||
|
flash contents, doesn't know anything about rboot image format. Use
|
||||||
|
rboot_verify_image to ensure a well-formed OTA image.
|
||||||
|
|
||||||
|
@param offset - Starting offset of image to hash (should be 4 byte aligned.)
|
||||||
|
|
||||||
|
@param image_length - Length of image to hash (should be 4 byte aligned.)
|
||||||
|
|
||||||
|
@param update_fn - Function to update digest (see rboot_digest_update_fn for details)
|
||||||
|
|
||||||
|
@param update_ctx - Context argument for digest update function.
|
||||||
|
|
||||||
|
@return True if digest completes successfully, false if digest function failed part way through
|
||||||
|
**/
|
||||||
|
bool rboot_digest_image(uint32_t offset, uint32_t image_length, rboot_digest_update_fn update_fn, void *update_ctx);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue