Skip to content

Commit 1ab8b3f

Browse files
committed
Move SHA256 code into OTA files
1 parent 30e0f5c commit 1ab8b3f

7 files changed

+151
-129
lines changed

src/ArduinoIoTCloudTCP.cpp

+21-124
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
#ifdef HAS_TCP
2525
#include <ArduinoIoTCloudTCP.h>
26+
2627
#ifdef BOARD_HAS_ECCX08
2728
#include "tls/BearSSLTrustAnchors.h"
2829
#include "tls/utility/CryptoUtil.h"
@@ -34,45 +35,18 @@
3435
#endif
3536

3637
#ifdef BOARD_HAS_OFFLOADED_ECCX08
37-
#include <ArduinoECCX08.h>
38-
#include "tls/utility/CryptoUtil.h"
39-
#endif
40-
41-
#ifdef BOARD_STM32H7
42-
# include "tls/utility/SHA256.h"
43-
# include <stm32h7xx_hal_rtc_ex.h>
44-
# include <WiFi.h>
45-
#endif
46-
47-
#if defined (ARDUINO_ARCH_ESP32) && OTA_ENABLED
48-
# include "tls/utility/SHA256.h"
49-
#include "esp_spi_flash.h"
50-
#include "esp_ota_ops.h"
51-
#include "esp_image_format.h"
52-
#endif
53-
54-
#if defined (ARDUINO_NANO_RP2040_CONNECT) || \
55-
(defined (ARDUINO_ARCH_SAMD) && OTA_ENABLED)
56-
#include "utility/ota/FlashSHA256.h"
38+
#include <ArduinoECCX08.h>
39+
#include "tls/utility/CryptoUtil.h"
5740
#endif
5841

5942
#if OTA_ENABLED
60-
#include "utility/ota/OTA.h"
43+
#include "utility/ota/OTA.h"
6144
#endif
6245

6346
#include <algorithm>
6447
#include "cbor/CBOREncoder.h"
65-
6648
#include "utility/watchdog/Watchdog.h"
6749

68-
/******************************************************************************
69-
* EXTERN
70-
******************************************************************************/
71-
72-
#ifdef BOARD_STM32H7
73-
extern RTC_HandleTypeDef RTCHandle;
74-
#endif
75-
7650
/******************************************************************************
7751
LOCAL MODULE FUNCTIONS
7852
******************************************************************************/
@@ -164,100 +138,8 @@ int ArduinoIoTCloudTCP::begin(bool const enable_watchdog, String brokerAddress,
164138
#endif /* AVR */
165139

166140
#if OTA_ENABLED && !defined(__AVR__)
167-
#if defined(BOARD_STM32H7)
168-
/* The length of the application can be retrieved the same way it was
169-
* communicated to the bootloader, that is by writing to the non-volatile
170-
* storage registers of the RTC.
171-
*/
172-
SHA256 sha256;
173-
uint32_t const app_start = 0x8040000;
174-
uint32_t const app_size = HAL_RTCEx_BKUPRead(&RTCHandle, RTC_BKP_DR3);
175-
176-
sha256.begin();
177-
uint32_t b = 0;
178-
uint32_t bytes_read = 0; for(uint32_t a = app_start;
179-
bytes_read < app_size;
180-
bytes_read += sizeof(b), a += sizeof(b))
181-
{
182-
/* Read the next chunk of memory. */
183-
memcpy(&b, reinterpret_cast<const void *>(a), sizeof(b));
184-
/* Feed it to SHA256. */
185-
sha256.update(reinterpret_cast<uint8_t *>(&b), sizeof(b));
186-
}
187-
/* Retrieve the final hash string. */
188-
uint8_t sha256_hash[SHA256::HASH_SIZE] = {0};
189-
sha256.finalize(sha256_hash);
190-
String sha256_str;
191-
std::for_each(sha256_hash,
192-
sha256_hash + SHA256::HASH_SIZE,
193-
[&sha256_str](uint8_t const elem)
194-
{
195-
char buf[4];
196-
snprintf(buf, 4, "%02X", elem);
197-
sha256_str += buf;
198-
});
199-
DEBUG_VERBOSE("SHA256: %d bytes (of %d) read", bytes_read, app_size);
200-
#elif defined(ARDUINO_ARCH_SAMD)
201-
/* Calculate the SHA256 checksum over the firmware stored in the flash of the
202-
* MCU. Note: As we don't know the length per-se we read chunks of the flash
203-
* until we detect one containing only 0xFF (= flash erased). This only works
204-
* for firmware updated via OTA and second stage bootloaders (SxU family)
205-
* because only those erase the complete flash before performing an update.
206-
* Since the SHA256 firmware image is only required for the cloud servers to
207-
* perform a version check after the OTA update this is a acceptable trade off.
208-
* The bootloader is excluded from the calculation and occupies flash address
209-
* range 0 to 0x2000, total flash size of 0x40000 bytes (256 kByte).
210-
*/
211-
String const sha256_str = FlashSHA256::calc(0x2000, 0x40000 - 0x2000);
212-
#elif defined(ARDUINO_NANO_RP2040_CONNECT)
213-
/* The maximum size of a RP2040 OTA update image is 1 MByte (that is 1024 *
214-
* 1024 bytes or 0x100'000 bytes).
215-
*/
216-
String const sha256_str = FlashSHA256::calc(XIP_BASE, 0x100000);
217-
#elif defined(ARDUINO_ARCH_ESP32)
218-
SHA256 sha256;
219-
220-
uint32_t lengthLeft = ESP.getSketchSize();
221-
222-
const esp_partition_t *running = esp_ota_get_running_partition();
223-
if (!running) {
224-
DEBUG_ERROR("Partition could not be found");
225-
}
226-
const size_t bufSize = SPI_FLASH_SEC_SIZE;
227-
std::unique_ptr<uint8_t[]> buf(new uint8_t[bufSize]);
228-
uint32_t offset = 0;
229-
if(!buf.get()) {
230-
DEBUG_ERROR("Not enough memory to allocate buffer");
231-
}
232-
233-
sha256.begin();
234-
while( lengthLeft > 0) {
235-
size_t readBytes = (lengthLeft < bufSize) ? lengthLeft : bufSize;
236-
if (!ESP.flashRead(running->address + offset, reinterpret_cast<uint32_t*>(buf.get()), (readBytes + 3) & ~3)) {
237-
DEBUG_ERROR("Could not read buffer from flash");
238-
}
239-
sha256.update(buf.get(), readBytes);
240-
lengthLeft -= readBytes;
241-
offset += readBytes;
242-
}
243-
/* Retrieve the final hash string. */
244-
uint8_t sha256_hash[SHA256::HASH_SIZE] = {0};
245-
sha256.finalize(sha256_hash);
246-
String sha256_str;
247-
std::for_each(sha256_hash,
248-
sha256_hash + SHA256::HASH_SIZE,
249-
[&sha256_str](uint8_t const elem)
250-
{
251-
char buf[4];
252-
snprintf(buf, 4, "%02X", elem);
253-
sha256_str += buf;
254-
});
255-
DEBUG_VERBOSE("SHA256: %d bytes (of %d) read", ESP.getSketchSize() - lengthLeft, ESP.getSketchSize());
256-
#else
257-
# error "No method for SHA256 checksum calculation over application image defined for this architecture."
258-
#endif
259-
DEBUG_VERBOSE("SHA256: HASH(%d) = %s", strlen(sha256_str.c_str()), sha256_str.c_str());
260-
_ota_img_sha256 = sha256_str;
141+
_ota_img_sha256 = getOTAImageSHA256();
142+
DEBUG_VERBOSE("SHA256: HASH(%d) = %s", strlen(_ota_img_sha256.c_str()), _ota_img_sha256.c_str());
261143
#endif /* OTA_ENABLED */
262144

263145
#if defined(BOARD_HAS_ECCX08) || defined(BOARD_HAS_OFFLOADED_ECCX08) || defined(BOARD_HAS_SE050)
@@ -902,6 +784,21 @@ void ArduinoIoTCloudTCP::onOTARequest()
902784
_ota_error = esp32_onOTARequest(_ota_url.c_str());
903785
#endif
904786
}
787+
788+
String ArduinoIoTCloudTCP::getOTAImageSHA256()
789+
{
790+
#if defined (ARDUINO_ARCH_SAMD)
791+
return samd_getOTAImageSHA256();
792+
#elif defined (ARDUINO_NANO_RP2040_CONNECT)
793+
return rp2040_connect_getOTAImageSHA256();
794+
#elif defined (BOARD_STM32H7)
795+
return portenta_h7_getOTAImageSHA256();
796+
#elif defined (ARDUINO_ARCH_ESP32)
797+
return esp32_getOTAImageSHA256();
798+
#else
799+
# error "No method for SHA256 checksum calculation over application image defined for this architecture."
800+
#endif
801+
}
905802
#endif
906803

907804
void ArduinoIoTCloudTCP::updateThingTopics()

src/ArduinoIoTCloudTCP.h

+1
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass
202202

203203
#if OTA_ENABLED
204204
void onOTARequest();
205+
String getOTAImageSHA256();
205206
void sendDevicePropertyToCloud(String const name);
206207
#endif
207208

src/utility/ota/OTA-esp32.cpp

+48-1
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,13 @@
2222
#include <AIoTC_Config.h>
2323

2424
#if defined ARDUINO_ARCH_ESP32 && OTA_ENABLED
25+
2526
#include "OTA.h"
2627
#include <Arduino_DebugUtils.h>
27-
#include <Arduino_ESP_OTA.h>
28+
#include <Arduino_ESP32_OTA.h>
29+
#include "tls/utility/SHA256.h"
30+
31+
#include <esp_ota_ops.h>
2832

2933
/******************************************************************************
3034
* FUNCTION DEFINITION
@@ -64,4 +68,47 @@ int esp32_onOTARequest(char const * ota_url)
6468
return static_cast<int>(OTAError::None);
6569
}
6670

71+
String esp32_getOTAImageSHA256()
72+
{
73+
SHA256 sha256;
74+
75+
uint32_t lengthLeft = ESP.getSketchSize();
76+
77+
const esp_partition_t *running = esp_ota_get_running_partition();
78+
if (!running) {
79+
DEBUG_ERROR("Partition could not be found");
80+
}
81+
const size_t bufSize = SPI_FLASH_SEC_SIZE;
82+
std::unique_ptr<uint8_t[]> buf(new uint8_t[bufSize]);
83+
uint32_t offset = 0;
84+
if(!buf.get()) {
85+
DEBUG_ERROR("Not enough memory to allocate buffer");
86+
}
87+
88+
sha256.begin();
89+
while( lengthLeft > 0) {
90+
size_t readBytes = (lengthLeft < bufSize) ? lengthLeft : bufSize;
91+
if (!ESP.flashRead(running->address + offset, reinterpret_cast<uint32_t*>(buf.get()), (readBytes + 3) & ~3)) {
92+
DEBUG_ERROR("Could not read buffer from flash");
93+
}
94+
sha256.update(buf.get(), readBytes);
95+
lengthLeft -= readBytes;
96+
offset += readBytes;
97+
}
98+
/* Retrieve the final hash string. */
99+
uint8_t sha256_hash[SHA256::HASH_SIZE] = {0};
100+
sha256.finalize(sha256_hash);
101+
String sha256_str;
102+
std::for_each(sha256_hash,
103+
sha256_hash + SHA256::HASH_SIZE,
104+
[&sha256_str](uint8_t const elem)
105+
{
106+
char buf[4];
107+
snprintf(buf, 4, "%02X", elem);
108+
sha256_str += buf;
109+
});
110+
DEBUG_VERBOSE("SHA256: %d bytes (of %d) read", ESP.getSketchSize() - lengthLeft, ESP.getSketchSize());
111+
return sha256_str;
112+
}
113+
67114
#endif /* ARDUINO_ARCH_ESP32 */

src/utility/ota/OTA-nano-rp2040.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "mbed.h"
3333
#include "FATFileSystem.h"
3434
#include "FlashIAPBlockDevice.h"
35+
#include "utility/ota/FlashSHA256.h"
3536

3637
/******************************************************************************
3738
* FUNCTION DEFINITION
@@ -249,4 +250,12 @@ int rp2040_connect_onOTARequest(char const * ota_url)
249250
return static_cast<int>(OTAError::None);
250251
}
251252

253+
String rp2040_connect_getOTAImageSHA256()
254+
{
255+
/* The maximum size of a RP2040 OTA update image is 1 MByte (that is 1024 *
256+
* 1024 bytes or 0x100'000 bytes).
257+
*/
258+
return FlashSHA256::calc(XIP_BASE, 0x100000);
259+
}
260+
252261
#endif /* ARDUINO_NANO_RP2040_CONNECT */

src/utility/ota/OTA-portenta-h7.cpp

+47
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,18 @@
2929
#include <Arduino_Portenta_OTA.h>
3030
#include <Arduino_ConnectionHandler.h>
3131

32+
#include <stm32h7xx_hal_rtc_ex.h>
33+
34+
#include "tls/utility/SHA256.h"
35+
3236
#include "../watchdog/Watchdog.h"
3337

38+
/******************************************************************************
39+
* EXTERN
40+
******************************************************************************/
41+
42+
extern RTC_HandleTypeDef RTCHandle;
43+
3444
/******************************************************************************
3545
* FUNCTION DEFINITION
3646
******************************************************************************/
@@ -96,4 +106,41 @@ int portenta_h7_onOTARequest(char const * ota_url, const bool use_ethernet)
96106
NVIC_SystemReset();
97107
}
98108

109+
String portenta_h7_getOTAImageSHA256()
110+
{
111+
/* The length of the application can be retrieved the same way it was
112+
* communicated to the bootloader, that is by writing to the non-volatile
113+
* storage registers of the RTC.
114+
*/
115+
SHA256 sha256;
116+
uint32_t const app_start = 0x8040000;
117+
uint32_t const app_size = HAL_RTCEx_BKUPRead(&RTCHandle, RTC_BKP_DR3);
118+
119+
sha256.begin();
120+
uint32_t b = 0;
121+
uint32_t bytes_read = 0; for(uint32_t a = app_start;
122+
bytes_read < app_size;
123+
bytes_read += sizeof(b), a += sizeof(b))
124+
{
125+
/* Read the next chunk of memory. */
126+
memcpy(&b, reinterpret_cast<const void *>(a), sizeof(b));
127+
/* Feed it to SHA256. */
128+
sha256.update(reinterpret_cast<uint8_t *>(&b), sizeof(b));
129+
}
130+
/* Retrieve the final hash string. */
131+
uint8_t sha256_hash[SHA256::HASH_SIZE] = {0};
132+
sha256.finalize(sha256_hash);
133+
String sha256_str;
134+
std::for_each(sha256_hash,
135+
sha256_hash + SHA256::HASH_SIZE,
136+
[&sha256_str](uint8_t const elem)
137+
{
138+
char buf[4];
139+
snprintf(buf, 4, "%02X", elem);
140+
sha256_str += buf;
141+
});
142+
DEBUG_VERBOSE("SHA256: %d bytes (of %d) read", bytes_read, app_size);
143+
return sha256_str;
144+
}
145+
99146
#endif /* BOARD_STM32H7 */

src/utility/ota/OTA-samd.cpp

+20-4
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,18 @@
1515
a commercial license, send an email to [email protected].
1616
*/
1717

18-
#ifdef ARDUINO_ARCH_SAMD
19-
2018
/******************************************************************************
2119
* INCLUDE
2220
******************************************************************************/
2321

24-
#include "OTA.h"
22+
#include <AIoTC_Config.h>
2523

26-
#include <Arduino_DebugUtils.h>
24+
#if defined (ARDUINO_ARCH_SAMD) && OTA_ENABLED
2725

26+
#include "OTA.h"
27+
#include <Arduino_DebugUtils.h>
2828
#include "../watchdog/Watchdog.h"
29+
#include "utility/ota/FlashSHA256.h"
2930

3031
#if OTA_STORAGE_SNU
3132
# include <SNU.h>
@@ -65,4 +66,19 @@ int samd_onOTARequest(char const * ota_url)
6566
return static_cast<int>(OTAError::DownloadFailed);
6667
}
6768

69+
String samd_getOTAImageSHA256()
70+
{
71+
/* Calculate the SHA256 checksum over the firmware stored in the flash of the
72+
* MCU. Note: As we don't know the length per-se we read chunks of the flash
73+
* until we detect one containing only 0xFF (= flash erased). This only works
74+
* for firmware updated via OTA and second stage bootloaders (SxU family)
75+
* because only those erase the complete flash before performing an update.
76+
* Since the SHA256 firmware image is only required for the cloud servers to
77+
* perform a version check after the OTA update this is a acceptable trade off.
78+
* The bootloader is excluded from the calculation and occupies flash address
79+
* range 0 to 0x2000, total flash size of 0x40000 bytes (256 kByte).
80+
*/
81+
return FlashSHA256::calc(0x2000, 0x40000 - 0x2000);
82+
}
83+
6884
#endif /* ARDUINO_ARCH_SAMD */

0 commit comments

Comments
 (0)