From c524124e1e2b13431bdbef796ea489bfd8d851b2 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Tue, 30 Mar 2021 19:17:03 +0200 Subject: [PATCH] TLS support for private keys on ESP32 --- tasmota/tasmota_globals.h | 1 + tasmota/xdrv_02_mqtt.ino | 45 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/tasmota/tasmota_globals.h b/tasmota/tasmota_globals.h index 110277cc2..2eb37309d 100644 --- a/tasmota/tasmota_globals.h +++ b/tasmota/tasmota_globals.h @@ -260,6 +260,7 @@ const uint16_t LOG_BUFFER_SIZE = 4000; // Max number of characters in lo #define TASM_FILE_SETTINGS_LKG "/.settings.lkg" // Last Known Good Settings binary blob #define TASM_FILE_DRIVER "/.drvset%03d" #define TASM_FILE_SENSOR "/.snsset%03d" +#define TASM_FILE_TLSKEY "/tlskey" // TLS private key #define TASM_FILE_ZIGBEE "/zb" // Zigbee settings blob as used by CC2530 on ESP32 #define TASM_FILE_AUTOEXEC "/autoexec.bat" // Commands executed after restart #define TASM_FILE_CONFIG "/config.sys" // Settings executed after restart diff --git a/tasmota/xdrv_02_mqtt.ino b/tasmota/xdrv_02_mqtt.ino index c31b2f4a7..2625bf04e 100644 --- a/tasmota/xdrv_02_mqtt.ino +++ b/tasmota/xdrv_02_mqtt.ino @@ -1138,16 +1138,21 @@ void CmndStateRetain(void) { \*********************************************************************************************/ #if defined(USE_MQTT_TLS) && defined(USE_MQTT_AWS_IOT) +#ifdef ESP32 +static uint8_t * tls_spi_start = nullptr; +const static size_t tls_spi_len = 0x0400; // 1kb blocs +const static size_t tls_block_offset = 0x0000; // don't need offset in FS +#else // const static uint16_t tls_spi_start_sector = EEPROM_LOCATION + 4; // 0xXXFF // const static uint8_t* tls_spi_start = (uint8_t*) ((tls_spi_start_sector * SPI_FLASH_SEC_SIZE) + 0x40200000); // 0x40XFF000 const static uint16_t tls_spi_start_sector = 0xFF; // Force last bank of first MB const static uint8_t* tls_spi_start = (uint8_t*) 0x402FF000; // 0x402FF000 const static size_t tls_spi_len = 0x1000; // 4kb blocs const static size_t tls_block_offset = 0x0400; +#endif const static size_t tls_block_len = 0x0400; // 1kb const static size_t tls_obj_store_offset = tls_block_offset + sizeof(tls_dir_t); - inline void TlsEraseBuffer(uint8_t *buffer) { memset(buffer + tls_block_offset, 0xFF, tls_block_len); } @@ -1166,6 +1171,22 @@ static br_x509_certificate CHAIN[] = { // load a copy of the tls_dir from flash into ram // and calculate the appropriate data structures for AWS_IoT_Private_Key and AWS_IoT_Client_Certificate void loadTlsDir(void) { +#ifdef ESP32 + // We load the file in RAM and use it as if it was in Flash. The buffer is never deallocated once we loaded TLS keys + AWS_IoT_Private_Key = nullptr; + AWS_IoT_Client_Certificate = nullptr; + if (TfsFileExists(TASM_FILE_TLSKEY)) { + if (tls_spi_start == nullptr){ + tls_spi_start = (uint8_t*) malloc(tls_block_len); + if (tls_spi_start == nullptr) { + return; + } + } + TfsLoadFile(TASM_FILE_TLSKEY, tls_spi_start, tls_block_len); + } else { + return; // file does not exist, do nothing + } +#endif memcpy_P(&tls_dir, tls_spi_start + tls_block_offset, sizeof(tls_dir)); // calculate the addresses for Key and Cert in Flash @@ -1204,7 +1225,11 @@ void CmndTlsKey(void) { AddLog(LOG_LEVEL_ERROR, ALLOCATE_ERROR); return; } - memcpy_P(spi_buffer, tls_spi_start, tls_spi_len); + if (tls_spi_start != nullptr) { // safeguard for ESP32 + memcpy_P(spi_buffer, tls_spi_start, tls_spi_len); + } else { + memset(spi_buffer, 0, tls_spi_len); // safeguard for ESP32, removed by compiler for ESP8266 + } // remove any white space from the base64 RemoveSpace(XdrvMailbox.data); @@ -1229,10 +1254,17 @@ void CmndTlsKey(void) { // address of writable tls_dir in buffer tls_dir_write = (tls_dir_t*) (spi_buffer + tls_block_offset); + bool save_file = false; // for ESP32, do we need to write file if (1 == XdrvMailbox.index) { // Try to write Private key // Start by erasing all +#ifdef ESP32 + if (TfsFileExists(TASM_FILE_TLSKEY)) { + TfsDeleteFile(TASM_FILE_TLSKEY); // delete file + } +#else TlsEraseBuffer(spi_buffer); // Erase any previously stored data +#endif if (bin_len > 0) { if (bin_len != 32) { // no private key was previously stored, abort @@ -1246,6 +1278,7 @@ void CmndTlsKey(void) { entry->start = 0; entry->len = bin_len; memcpy(spi_buffer + tls_obj_store_offset + entry->start, bin_buf, entry->len); + save_file = true; } else { // if lenght is zero, simply erase this SPI flash area } @@ -1270,11 +1303,18 @@ void CmndTlsKey(void) { entry->start = (tls_dir_write->entry[0].start + tls_dir_write->entry[0].len + 3) & ~0x03; // align to 4 bytes boundary entry->len = bin_len; memcpy(spi_buffer + tls_obj_store_offset + entry->start, bin_buf, entry->len); + save_file = true; } +#ifdef ESP32 + if (save_file) { + TfsSaveFile(TASM_FILE_TLSKEY, spi_buffer, tls_spi_len); + } +#else if (ESP.flashEraseSector(tls_spi_start_sector)) { ESP.flashWrite(tls_spi_start_sector * SPI_FLASH_SEC_SIZE, (uint32_t*) spi_buffer, SPI_FLASH_SEC_SIZE); } +#endif free(spi_buffer); free(bin_buf); } @@ -1295,6 +1335,7 @@ uint32_t bswap32(uint32_t x) { ((x >> 24) & 0x000000ff ); } void CmndTlsDump(void) { + if (tls_spi_start == nullptr) { return; } // safeguard for ESP32, removed by compiler for ESP8266 uint32_t start = (uint32_t)tls_spi_start + tls_block_offset; uint32_t end = start + tls_block_len -1; for (uint32_t pos = start; pos < end; pos += 0x10) {