|
27 | 27 | #ifdef BOARD_HAS_ECCX08
|
28 | 28 | #include "tls/BearSSLTrustAnchors.h"
|
29 | 29 | #include "tls/utility/CryptoUtil.h"
|
| 30 | + #include "tls/utility/SHA256.h" |
30 | 31 | #endif
|
31 | 32 |
|
| 33 | +#undef max |
| 34 | +#undef min |
| 35 | +#include <algorithm> |
| 36 | + |
32 | 37 | #include "utility/ota/OTAStorage_SNU.h"
|
33 | 38 | #include "utility/ota/OTAStorage_SFU.h"
|
34 | 39 | #include "utility/ota/OTAStorage_SSU.h"
|
@@ -119,6 +124,85 @@ int ArduinoIoTCloudTCP::begin(String brokerAddress, uint16_t brokerPort)
|
119 | 124 | _brokerAddress = brokerAddress;
|
120 | 125 | _brokerPort = brokerPort;
|
121 | 126 |
|
| 127 | +#ifdef OTA_ENABLED |
| 128 | + /* Calculate the SHA256 checksum over the firmware stored in the flash of the |
| 129 | + * MCU. Note: As we don't know the length per-se we read chunks of the flash |
| 130 | + * until we detect one containing only 0xFF (= flash erased). This only works |
| 131 | + * for firmware updated via OTA and second stage bootloaders (SxU family) |
| 132 | + * because only those erase the complete flash before performing an update. |
| 133 | + * Since the SHA256 firmware image is only required for the cloud servers to |
| 134 | + * perform a version check after the OTA update this is a acceptable trade off. |
| 135 | + */ |
| 136 | + SHA256 sha256; |
| 137 | + sha256.begin(); |
| 138 | + |
| 139 | + uint32_t const APP_START_ADDR = 0x2000; /* Start after the bootloader. */ |
| 140 | + #undef FLASH_SIZE |
| 141 | + uint32_t const FLASH_READ_SIZE = 0x40000 - APP_START_ADDR; |
| 142 | + uint32_t const FLASH_READ_CHUNK_SIZE = 64; |
| 143 | + |
| 144 | + uint32_t flash_addr = APP_START_ADDR; |
| 145 | + for(; flash_addr < FLASH_READ_SIZE; flash_addr += FLASH_READ_CHUNK_SIZE) |
| 146 | + { |
| 147 | + /* Read from the MCU's flash. */ |
| 148 | + uint8_t buf[FLASH_READ_CHUNK_SIZE]; |
| 149 | + memcpy(buf, reinterpret_cast<const void *>(flash_addr), FLASH_READ_CHUNK_SIZE); |
| 150 | + |
| 151 | + /* Check if the next segment is erased, that is if all bytes within |
| 152 | + * a read segment are 0xFF -> then we've reached the end of the |
| 153 | + * firmware. |
| 154 | + */ |
| 155 | + uint8_t buf_2[FLASH_READ_CHUNK_SIZE]; |
| 156 | + memcpy(buf_2, reinterpret_cast<const void *>(flash_addr + FLASH_READ_CHUNK_SIZE), FLASH_READ_CHUNK_SIZE); |
| 157 | + size_t valid_bytes_in_buf = 0; |
| 158 | + DBG_VERBOSE("[%X]", flash_addr); |
| 159 | + char msg[4]; |
| 160 | + for(size_t i=0; i<FLASH_READ_CHUNK_SIZE; i++) |
| 161 | + { |
| 162 | + snprintf(msg, 4, "%02X", buf[i]); |
| 163 | + Serial.print(msg); |
| 164 | + } |
| 165 | + Serial.println(); |
| 166 | + |
| 167 | + |
| 168 | + if (std::all_of(buf_2, buf_2+FLASH_READ_CHUNK_SIZE, [](uint8_t const elem) { return (elem == 0xFF); })) |
| 169 | + { |
| 170 | + /* Eliminate trailing 0xFF. */ |
| 171 | + for(valid_bytes_in_buf = FLASH_READ_CHUNK_SIZE; valid_bytes_in_buf > 0; valid_bytes_in_buf--) { |
| 172 | + if (buf[valid_bytes_in_buf-1] != 0xFF) |
| 173 | + break; |
| 174 | + } |
| 175 | + /* Update with the remaining bytes. */ |
| 176 | + DBG_VERBOSE("End of firmware, %d valid bytes in last read segment", valid_bytes_in_buf); |
| 177 | + sha256.update(buf, valid_bytes_in_buf); |
| 178 | + break; |
| 179 | + } |
| 180 | + else |
| 181 | + { |
| 182 | + /* Otherwise update the SHA256 hash. */ |
| 183 | + sha256.update(buf, FLASH_READ_CHUNK_SIZE); |
| 184 | + } |
| 185 | + } |
| 186 | + Serial.println(); |
| 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 | + /* Update the property. */ |
| 200 | + _ota_img_sha256 = sha256_str; |
| 201 | + /* Do some debug printout. */ |
| 202 | + DBG_VERBOSE("SHA256: %d bytes read", flash_addr); |
| 203 | + DBG_VERBOSE("SHA256: HASH(%d) = %s", strlen(_ota_img_sha256.c_str()), _ota_img_sha256.c_str()); |
| 204 | +#endif /* OTA_ENABLED */ |
| 205 | + |
122 | 206 | #ifdef BOARD_HAS_ECCX08
|
123 | 207 | if (!ECCX08.begin()) { DBG_ERROR("Cryptography processor failure. Make sure you have a compatible board."); return 0; }
|
124 | 208 | if (!CryptoUtil::readDeviceId(ECCX08, getDeviceId(), ECCX08Slot::DeviceId)) { DBG_ERROR("Cryptography processor read failure."); return 0; }
|
@@ -187,6 +271,8 @@ void ArduinoIoTCloudTCP::update()
|
187 | 271 | _mqtt_data_request_retransmit = false;
|
188 | 272 | }
|
189 | 273 |
|
| 274 | + //DBG_VERBOSE("SHA256: HASH(%d) = %s", strlen(_ota_img_sha256.c_str()), _ota_img_sha256.c_str()); |
| 275 | + |
190 | 276 | // MTTQClient connected!, poll() used to retrieve data from MQTT broker
|
191 | 277 | _mqttClient.poll();
|
192 | 278 |
|
|
0 commit comments