From 9468622c3eed291c999cb988231f5e874d573102 Mon Sep 17 00:00:00 2001 From: sqozz Date: Sat, 17 Nov 2018 16:59:33 +0100 Subject: [PATCH] Add PoC --- .gitignore | 1 + README.md | 3 + data/.empty | 0 le_x3_11_2018.pem | 27 ++++++++ ota_test.ino | 161 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 192 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 data/.empty create mode 100644 le_x3_11_2018.pem create mode 100644 ota_test.ino diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..60baa9c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +data/* diff --git a/README.md b/README.md new file mode 100644 index 0000000..f8aa97b --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +openssl s_client -showcerts -servername letsencrypt.org -connect letsencrypt.org:443 //Local WebServer used to serve the configuration portal +#include //https://github.com/tzapu/WiFiManager WiFi Configuration Magic +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEVICE_NAME "OTA TEST DEVICE" +#define TZ 1 // (utc+) TZ in hours +#define DST_MN 0 // use 60mn for summer time in some countries +#define TZ_MN ((TZ)*60) +#define TZ_SEC ((TZ)*3600) +#define DST_SEC ((DST_MN)*60) + +ESP8266WiFiMulti WiFiMulti; +BearSSL::CertStore certStore; +WiFiManager wifiManager; +String config_password; + +class SPIFFSCertStoreFile : public BearSSL::CertStoreFile { + public: + SPIFFSCertStoreFile(const char *name) { + _name = name; + }; + virtual ~SPIFFSCertStoreFile() override {}; + + // The main API + virtual bool open(bool write = false) override { + _file = SPIFFS.open(_name, write ? "w" : "r"); + return _file; + } + virtual bool seek(size_t absolute_pos) override { + return _file.seek(absolute_pos, SeekSet); + } + virtual ssize_t read(void *dest, size_t bytes) override { + return _file.readBytes((char*)dest, bytes); + } + virtual ssize_t write(void *dest, size_t bytes) override { + return _file.write((uint8_t*)dest, bytes); + } + virtual void close() override { + _file.close(); + } + + private: + File _file; + const char *_name; +}; + +SPIFFSCertStoreFile certs_idx("/certs.idx"); // auto generated. No upload required +SPIFFSCertStoreFile certs_ar("/certs.ar"); // use fetch_le_root_crt.py and then upload + +// Set time via NTP, as required for x.509 validation +void setClock() { + configTime(TZ_SEC, DST_SEC, "pool.ntp.org", "time.nist.gov"); + + Serial.print(F("Waiting for NTP time sync: ")); + time_t now = time(nullptr); + while (now < 8 * 3600 * 2) { + yield(); + delay(500); + Serial.print(F(".")); + now = time(nullptr); + } + + Serial.println(F("")); + struct tm timeinfo; + gmtime_r(&now, &timeinfo); + Serial.print(F("Current time: ")); + Serial.print(asctime(&timeinfo)); +} + +void setup() { + Serial.begin(115200); + // USE_SERIAL.setDebugOutput(true); + Serial.println(); + Serial.println(); + Serial.println(); + + for (uint8_t t = 4; t > 0; t--) { + Serial.printf("[SETUP] WAIT %d...\n", t); + Serial.flush(); + delay(1000); + } + + WiFi.mode(WIFI_STA); + + SPIFFS.begin(); + + int numCerts = certStore.initCertStore(&certs_idx, &certs_ar); + Serial.print(F("Number of CA certs read: ")); Serial.println(numCerts); + if (numCerts == 0) { + Serial.println(F("No certs found. Did you run certs-from-mozill.py and upload the SPIFFS directory before running?")); + // TODO: bailout? + } + + if (SPIFFS.exists("/config_password.txt")) { + File f = SPIFFS.open("/config_password.txt", "r"); + if (f && f.size()) { + while (f.available()){ + config_password += char(f.read()); + } + f.close(); + } + wifiManager.autoConnect(DEVICE_NAME, config_password.c_str()); + } else { + Serial.println(F("Failed to find file. Upload config_password.txt with the configuration password included")); + // TODO: bailout? + } +} + +void loop() { + checkUpdate(); + delay(10000); +} + +void checkUpdate() { + // wait for WiFi connection + if ((WiFiMulti.run() == WL_CONNECTED)) { + setClock(); + + BearSSL::WiFiClientSecure client; + bool mfln = client.probeMaxFragmentLength("companioncu.be", 443, 1024); // server must be the same as in ESPhttpUpdate.update() + Serial.printf("MFLN supported: %s\n", mfln ? "yes" : "no"); + if (mfln) { + client.setBufferSizes(1024, 1024); + } + client.setCertStore(&certStore); + + // The line below is optional. It can be used to blink the LED on the board during flashing + // The LED will be on during download of one buffer of data from the network. The LED will + // be off during writing that buffer to flash + // On a good connection the LED should flash regularly. On a bad connection the LED will be + // on much longer than it will be off. Other pins than LED_BUILTIN may be used. The second + // value is used to put the LED on. If the LED is on with HIGH, that value should be passed + ESPhttpUpdate.setLedPin(LED_BUILTIN, LOW); + + t_httpUpdate_return ret = ESPhttpUpdate.update(client, "https://iotupdates.companioncu.be/update"); + // Or: + //t_httpUpdate_return ret = ESPhttpUpdate.update(client, "server", 443, "file.bin"); + + + switch (ret) { + case HTTP_UPDATE_FAILED: + Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str()); + break; + + case HTTP_UPDATE_NO_UPDATES: + Serial.println("HTTP_UPDATE_NO_UPDATES"); + break; + + case HTTP_UPDATE_OK: + Serial.println("HTTP_UPDATE_OK"); + break; + } + } +}