Skip to content

Abort called ctx: bearssl #5815

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
4 of 6 tasks
NikoVonLas opened this issue Feb 23, 2019 · 27 comments
Closed
4 of 6 tasks

Abort called ctx: bearssl #5815

NikoVonLas opened this issue Feb 23, 2019 · 27 comments
Labels
waiting for feedback Waiting on additional info. If it's not received, the issue may be closed.

Comments

@NikoVonLas
Copy link

NikoVonLas commented Feb 23, 2019

Basic Infos

  • This issue complies with the issue POLICY doc.
  • I have read the documentation at readthedocs and the issue is not addressed there.
  • I have tested that the issue is present in current master branch (aka latest git).
  • I have searched the issue tracker for a similar issue.
  • If there is a stack dump, I have decoded it.
  • I have filled out all fields below.

Platform

  • Hardware: LoLin Nodemcu3
  • Core Version: 2.3.0
  • Development Env: Arduino IDE - 1.8.19.0_x86
  • Operating System: Windows

Settings in IDE

  • Module: Nodemcu
  • Flash Mode: dio
  • Flash Size: 4MB
  • lwip Variant: v2 Higher Bandwidth
  • Reset Method: nodemcu
  • Flash Frequency: 40Mhz
  • CPU Frequency: 80Mhz
  • Upload Using: SERIAL
  • Upload Speed: 115200

Problem Description

When i use WiFiClientSecure with HTTPClient - it fails when i try send GET request on my server.
Certs stored in spiffs generating by standart tools.

MCVE Sketch

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <ESP8266NetBIOS.h>
#include <ESP8266FtpServer.h>
#include <ESP8266SSDP.h>
#include <ArduinoJson.h>
#include <FS.h>
#include <SoftwareSerial.h>
#include <EEPROM.h>
#include <DNSServer.h>
#include <time.h>
#include <CertStoreBearSSL.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>

~~~~~~~~~~~~~~~~~~~~~~
Some code here
~~~~~~~~~~~~~~~~~~~~~~

const char* version = "v4.3";
const char* host = "https://antiit.ru";
const uint16_t httpsPort = 443;
const char* update_file = "/arduino/color-music-wifi.json";
const char* update_path = "/arduino/firmware";

IPAddress ip(192, 168, 1, 60);
IPAddress gate(192, 168, 1, 1);
IPAddress NMask(255, 255, 255, 0);
IPAddress dns(8, 8, 8, 8);

ESP8266WebServer server(80);
FtpServer ftpSrv;
SoftwareSerial ArduinoSerial(D7,D6);
DNSServer dnsServer;
BearSSL::CertStore certStore;

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");
SPIFFSCertStoreFile certs_ar("/certs.ar");

~~~~~~~~~~~~~~~~~~~~~~
Some code here
~~~~~~~~~~~~~~~~~~~~~~

void checkUpdate() {
  HTTPClient http;
  BearSSL::WiFiClientSecure *client = new BearSSL::WiFiClientSecure();
  client->setCertStore(&certStore);
  String file = (String) host + (String) update_file;
  if (http.begin(*client, file)) {
    int httpCode = http.GET();
    Serial.println(ESP.getFreeHeap());
    if (httpCode > 0) {
      Serial.print(F("[HTTP] GET CODE: "));
      Serial.println(httpCode);
      if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
        String payload = http.getString();
        Serial.println(payload);
        StaticJsonDocument<300> doc;
        auto err = deserializeJson(doc, payload);
        if (err) {
          doc.clear();
          Serial.print(F("JSON deserialize ERROR: "));
          Serial.println(err.c_str());
          server.send(200, "text/plain", "JSON ERROR");
        } else {
          if (doc["version"] != version){
            Serial.println(F("Need for update!"));
            server.send(200, "text/plain", "UPDATE STARTED DONT TURN OFF COLOR MUSIC!");
            t_httpUpdate_return ret = ESPhttpUpdate.update(*client, doc["host"], (uint16_t) doc["port"], doc["bin"], version);
            switch (ret) {
              case HTTP_UPDATE_FAILED:
                Serial.print(F("HTTP_UPDATE_FAILED Error ("));
                Serial.print(ESPhttpUpdate.getLastError());
                Serial.print(F("): "));
                Serial.print(ESPhttpUpdate.getLastErrorString().c_str());
                server.send(200, "text/plain", "UPDATE ERROR");
                break;
              case HTTP_UPDATE_NO_UPDATES:
                Serial.println(F("HTTP_UPDATE_NO_UPDATES"));
                server.send(200, "text/plain", "HTTP_UPDATE_NO_UPDATES");
                break;
              case HTTP_UPDATE_OK:
                Serial.println(F("HTTP_UPDATE_OK"));
                server.send(200, "text/plain", "HTTP_UPDATE_OK");
                //ret = ESPhttpUpdate.updateSpiffs(client, "http://server/spiffs.bin");
                break;
            }
           } else {
            server.send(200, "text/plain", "OK");
          }
        }
      } else {
        server.send(200, "text/plain", http.errorToString(httpCode).c_str());
      }
    } else {
      Serial.print(F("[HTTP] GET ERROR: "));
      Serial.println(http.errorToString(httpCode).c_str());
    }
  } else {
    Serial.println(F("[HTTP] Unable to connect!"));
    server.send(200, "text/plain", "HTTP ERROR");
  }
  http.end();
  client->stop();
  server.client().stop();
}

void setup(void) {
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  ArduinoSerial.begin(19200);
  readSettings();
  WiFi.hostname("colormusic");
  WiFi.mode(WIFI_STA);
  WiFi.config(ip, gate, NMask, gate, dns);
  WiFi.begin(ssid, pass);
  int tryNum = 1;
  while (WiFi.status() != WL_CONNECTED) {
    Serial.println(F("Try connect to WiFi"));
    if (tryNum == 10){
      break;
    } else {
      digitalWrite(led, 1);
      delay(500);
      digitalWrite(led, 0);
      tryNum++;
    }
  }
  if (WiFi.status() == WL_CONNECTED) {
    Serial.println(F("Connected to WiFi"));
    WiFi.setAutoReconnect(true);
    Serial.println(WiFi.gatewayIP());
    Serial.println(WiFi.subnetMask());
    Serial.print("DNS #1, #2 IP: ");
    WiFi.dnsIP().printTo(Serial);
    Serial.print(", ");
    WiFi.dnsIP(1).printTo(Serial);
    Serial.println();
  } else {
    Serial.println(F("Not connected to WiFi"));
    Serial.println(F("Starting Access Point"));
    WiFi.hostname("colormusic");
    WiFi.mode(WIFI_AP);
    WiFi.softAP("ColorMusic", "ColorMusicPassword");
    delay(500);
    WiFi.softAPConfig(gate, gate, NMask);
    AP_MODE = true;
  }
  MDNS.begin("colormusic");
  MDNS.addService("http", "tcp", 80);
  Serial.println(F("Started MDNS"));
  NBNS.begin("colormusic");
  Serial.println(F("Started NETBIOS"));
  dnsServer.setTTL(300);
  dnsServer.setErrorReplyCode(DNSReplyCode::ServerFailure);
  dnsServer.start(53, "colormusic.local", WiFi.localIP());
  Serial.println(F("Started DNS server"));
  SSDP.setHTTPPort(80);
  SSDP.setName("Color music");
  SSDP.setSerialNumber(ESP.getChipId());
  SSDP.setURL("/");
  SSDP.setSchemaURL("description.xml");
  SSDP.setModelName("Gyver Color Music with Niko WiFi mod");
  SSDP.setModelNumber(version);
  SSDP.setModelURL("https://alexgyver.ru/colormusic/");
  SSDP.setManufacturer("AlexGyver and NikoVonlas");
  SSDP.setManufacturerURL("https://alexgyver.ru/");
  SSDP.setDeviceType("upnp:rootdevice");
  SSDP.begin();
  Serial.println(F("Started SSDP"));
  getSettings();
  Serial.println(F("Get settings"));
  delay(300);
  serialTick();
  server.on("/", []() {
    handleRoot();
  });
  server.on("/settings", []() {
    handleSettings();
  });
  server.on("/update", []() {
    checkUpdate();
  });
  server.on("/home.tpl", []() {
    handleTpl("home");
  });
  server.on("/info.json", []() {
    handleInfoJson();
  });
  server.on("/description.xml", []() {
    SSDP.schema(server.client());
  });
  server.onNotFound(handleNotFound);
  if (SPIFFS.begin()) {
    Serial.println(F("Started SPIFFS"));
    if (FTP) {
      ftpSrv.begin("ColorMusic", "ColorMusicPassword");
      Serial.println(F("Started FTP"));
    }
    server.begin();
    Serial.println(F("Started Web Server:"));
    Serial.println(WiFi.localIP());
    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?"));
    }
  } else {
    Serial.println(F("ERROR! NO SPIFFS!"));
  }
}

void loop(void) {
  dnsServer.processNextRequest();
  MDNS.update();
  serialTick();
  if (FTP) {
    ftpSrv.handleFTP();
  }
  server.handleClient();
  if (!AP_MODE) {
    setClock();
  }
}

void setClock() {
  configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov");
  time_t now = time(nullptr);
  while (now < 8 * 3600 * 2) {
    yield();
    delay(1000);
    Serial.println(F("Waiting for NTP time sync"));
    now = time(nullptr);
  }
  struct tm timeinfo;
  gmtime_r(&now, &timeinfo);
}

Debug Messages

Abort called

>>>stack>>>

ctx: bearssl
sp: 3fff4760 end: 3fff4d70 offset: 01b0
3fff4910:  3fff3374 00000000 3fffb864 4020f8b3  
3fff4920:  00000001 402100f5 3fffb87c 40100e60  
3fff4930:  3fff1214 00001422 00001422 40100a1c  
3fff4940:  3fff3374 3fffb83c 3fff2374 00000000  
3fff4950:  3fff3374 00000000 3fff2374 40210111  
3fff4960:  00000001 3fffac5c 3ffefb0c 00000000  
3fff4970:  00000001 40229218 0000000c 00000000  
3fff4980:  3fff2374 3fffac5c 3ffefb48 40210160  
3fff4990:  9c16d28c 3fffac5c 3ffefb48 4020bf4f  
3fff49a0:  39edc623 51b5c73e 2e9b200c 00c76dea  
3fff49b0:  64e0d459 e8583ee9 5405f3b3 abcd07f0  
3fff49c0:  0001a908 0000034e 0c52ce81 e8835f2e  
3fff49d0:  fb3306d5 40ce6c77 1f9e32ea 3fffa068  
3fff49e0:  3fffa114 3fffa044 00000000 4023e95a  
3fff49f0:  a3d99d62 1b256f91 19b1902f 7ef63d46  
3fff4a00:  877aa61b 6d7aa3b9 a525fa18 e0158791  
3fff4a10:  582f16f2 deadbeef 00000b00 00000000  
3fff4a20:  f278140d 8ba47f98 fdb4fa04 69e96570  
3fff4a30:  40272523 a2aa7d1c 5829bc0a cdd864b0  
3fff4a40:  3fffa05c 00000096 000006c7 3fffa070  
3fff4a50:  fbc2dae7 6ed0f60e 8e040635 8cd207b7  
3fff4a60:  3fffa074 3fffaa44 3fffa844 3fff5b64  
3fff4a70:  00000130 deadbeef deadbeef 40270ef3  
3fff4a80:  00000000 3fff5a08 3fff5724 4023f172  
3fff4a90:  00000096 3fff5a08 000008f0 40239158  
3fff4aa0:  deadbeef deadbeef deadbeef deadbeef  
3fff4ab0:  deadbe96 deadbeef deadbeef deadbeef  
3fff4ac0:  deadbeef deadbeef deadbeef deadbeef  
3fff4ad0:  deadbeef deadbeef deadbeef deadbeef  
3fff4ae0:  deadbeef deadbeef deadbeef deadbeef  
3fff4af0:  deadbeef deadbeef deadbeef deadbeef  
3fff4b00:  deadbeef deadbeef deadbeef deadbeef  
3fff4b10:  deadbeef deadbeef deadbeef deadbeef  
3fff4b20:  deadbeef deadbeef deadbeef deadbeef  
3fff4b30:  deadbeef deadbeef deadbeef deadbeef  
3fff4b40:  deadbeef deadbeef deadbeef deadbeef  
3fff4b50:  deadbeef deadbeef deadbeef deadbeef  
3fff4b60:  deadbeef deadbeef deadbeef deadbeef  
3fff4b70:  deadbeef deadbeef deadbeef deadbeef  
3fff4b80:  deadbeef deadbeef deadbeef deadbeef  
3fff4b90:  deadbeef deadbeef deadbeef deadbeef  
3fff4ba0:  deadbeef deadbeef deadbeef deadbeef  
3fff4bb0:  deadbeef deadbeef deadbeef deadbeef  
3fff4bc0:  deadbeef deadbeef deadbeef deadbeef  
3fff4bd0:  deadbeef deadbeef deadbeef deadbeef  
3fff4be0:  deadbeef deadbeef deadbeef deadbeef  
3fff4bf0:  deadbeef deadbeef deadbeef deadbeef  
3fff4c00:  deadbeef deadbeef deadbeef deadbeef  
3fff4c10:  deadbeef deadbeef deadbeef deadbeef  
3fff4c20:  deadbeef deadbeef deadbeef deadbeef  
3fff4c30:  deadbeef deadbeef deadbeef deadbeef  
3fff4c40:  deadbeef deadbeef deadbeef deadbeef  
3fff4c50:  deadbeef deadbeef deadbeef deadbeef  
3fff4c60:  deadbeef deadbeef deadbeef deadbeef  
3fff4c70:  deadbeef deadbeef deadbeef deadbeef  
3fff4c80:  deadbeef deadbeef deadbeef deadbeef  
3fff4c90:  deadbeef deadbeef deadbeef deadbeef  
3fff4ca0:  deadbeef deadbeef deadbeef deadbeef  
3fff4cb0:  deadbeef deadbeef deadbeef deadbeef  
3fff4cc0:  deadbeef 40270ef3 deadbeef deadbeef  
3fff4cd0:  3fff5728 3fff57ac deadbeef deadbeef  
3fff4ce0:  3fff5708 3fff4f24 3fff5728 deadbeef  
3fff4cf0:  deadbeef 3fff4f08 00000096 deadbeef  
3fff4d00:  deadbeef deadbeef deadbeef 3fff5924  
3fff4d10:  3fff5a24 00000000 3fff4f24 40237180  
3fff4d20:  3fff5708 00000a01 deadbeef deadbeef  
3fff4d30:  00000250 00000005 deadbeef 3fff0fcc  
3fff4d40:  00000008 00000000 3fff4f24 40237665  
3fff4d50:  000000d6 deadbeef deadbeef deadbeef  
3fff4d60:  deadbeef 00000000 3fff36dc 4020f66c  

ctx: cont
sp: 3ffffb30 end: 3fffffc0 offset: 0000
3ffffb30:  00000008 00000000 00000001 4020eb81  
3ffffb40:  00000a01 00000005 6fb4e7d7 00000000  
3ffffb50:  40237cd4 40237c7c 3fff4f24 4023778a  
3ffffb60:  3fff5424 3fff33cc 3fff4f24 00000000  
3ffffb70:  00000001 00000001 3fff36dc 4020ed90  
3ffffb80:  00000001 3fff33cc 3fff36dc 4020ef73  
3ffffb90:  00000000 3ffffbf0 4021da34 3fffefa0  
3ffffba0:  00000000 00000000 00000000 40201627  
3ffffbb0:  00000d50 3fff2304 3fff36dc 4020dc6d  
3ffffbc0:  000001bb 4021cd3f 3ffffdf8 00000000  
3ffffbd0:  000001bb 3fff36dc 3fff33cc 00000000  
3ffffbe0:  000001bb 3fff36dc 3fff33cc 4020f03a  
3ffffbf0:  402200b8 6910ec57 3ffffdd8 4021f3e4  
3ffffc00:  00000001 3fff36dc 3ffffdd8 40210760  
3ffffc10:  3ffffc90 00000001 3ffffc5c 40100e60  
3ffffc20:  3fff4d7c 00000000 3ffffdd8 40210f3c  
3ffffc30:  00000030 3ffffc90 3ffffdd8 4021cd18  
3ffffc40:  3fff1214 0000017b 0000017b 40100a1c  
3ffffc50:  3ffe8847 3fff36dc 3ffffc90 40100e60  
3ffffc60:  00000000 00000000 3ffffc90 40212150  
3ffffc70:  00000001 3fff36dc 3fff0f98 40210fea  
3ffffc80:  00000001 3fff36dc 3fff292c 4020ae52  
3ffffc90:  00000000 00000000 00000000 00000001  
3ffffca0:  4025996e 3ffed960 3fff1864 3ffed960  
3ffffcb0:  00000002 00000000 00000020 4010182a  
3ffffcc0:  3ffea1f2 4025891b 3ffed960 3fff2494  
3ffffcd0:  00000005 00000000 00000020 4010182a  
3ffffce0:  3ffea1f5 40104c2b 3ffedc08 4010182a  
3ffffcf0:  40102541 3ffedc08 3ffedc30 fffffffe  
3ffffd00:  ffffffe5 07594ef0 3ffee6d4 40102712  
3ffffd10:  3ffeaaa0 00000000 00000000 40102712  
3ffffd20:  00000002 00000000 00000020 4010182a  
3ffffd30:  3ffea1f2 40104c10 3ffed960 0p⸮⸮⸮
@liebman
Copy link
Contributor

liebman commented Feb 24, 2019

I had exactly the same problem. If you decode your stack then you would find your running out of heap (allocation failure) in bearssl processing the cert file data. I've gone back to either supplying the correct cert directly or setting "insecure" depending on my use case. Ideally I'd love to be able to supply a cert bundle but the way its currently implemented there is not enough free heap.

@NikoVonLas
Copy link
Author

@liebman And solution is store in certs.ar only my site CA cert(IdenTrust’s DST Root CA X3 for LetsEncrypt SSL)?

@liebman
Copy link
Contributor

liebman commented Feb 24, 2019

My current usage does not require security so I'm setting insecure currently. :-( I think one of the examples show how to work with a single cert (and not use certs.ar at all).

@devyte
Copy link
Collaborator

devyte commented Feb 25, 2019

Set debug OOM and debug port to confirm.
Also, you need to decode your stack dump. Pasting a raw stack dump here is useless, because only you can decode it.

@devyte devyte added the waiting for feedback Waiting on additional info. If it's not received, the issue may be closed. label Feb 25, 2019
@earlephilhower
Copy link
Collaborator

For a single SSL connection, there is no need for a certstore. Just take the single root CA and add it as a trust anchor and you're all set with much less code, faster runtime, and less memory demands.

That said, this does not look to be a stack overflow because there is >5000 bytes allocated for the BSSL context and your dump shows only ~1100 bytes used. So the OOM debug suggestion would be a good starting point, after getting a decode, of course.

@NikoVonLas
Copy link
Author

NikoVonLas commented Feb 25, 2019

@earlephilhower Im add only 2 certs from Lets Encrypt, but get same error.
@devyte Here decoded stack with setted port and OOM debug and last stable core (2.5):

Exception 28: LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads
PC: 0x4020c19d: BearSSL::CertStore::findHashedTA(void*, void*, unsigned int) at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\libraries\ESP8266WiFi\src\CertStoreBearSSL.cpp line 177
EXCVADDR: 0x00000000

Decoding stack results
0x4023f813: br_x509_minimal_run at src/x509/x509_minimal.c line 1217
0x402400ce: xm_append at src/x509/x509_minimal.c line 285
0x4023a0b4: br_ssl_hs_client_run at src/ssl/ssl_hs_client.c line 1863
0x402012c4: ets_printf_P at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\core_esp8266_postmortem.c line 76
0x402012b8: ets_printf_P at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\core_esp8266_postmortem.c line 76
0x40100718: vPortFree at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\heap.c line 59
0x40203a9f: spiffs_object_find_object_index_header_by_name_v at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\spiffs\spiffs_nucleus.c line 1673
0x40201312: print_stack at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\core_esp8266_postmortem.c line 190
0x402014b0: __wrap_system_restart_local at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\core_esp8266_postmortem.c line 151
0x4020c19d: BearSSL::CertStore::findHashedTA(void*, void*, unsigned int) at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\libraries\ESP8266WiFi\src\CertStoreBearSSL.cpp line 177
0x4020c19d: BearSSL::CertStore::findHashedTA(void*, void*, unsigned int) at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\libraries\ESP8266WiFi\src\CertStoreBearSSL.cpp line 177
0x4020c19d: BearSSL::CertStore::findHashedTA(void*, void*, unsigned int) at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\libraries\ESP8266WiFi\src\CertStoreBearSSL.cpp line 177
0x4020c19d: BearSSL::CertStore::findHashedTA(void*, void*, unsigned int) at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\libraries\ESP8266WiFi\src\CertStoreBearSSL.cpp line 177
0x4020c19d: BearSSL::CertStore::findHashedTA(void*, void*, unsigned int) at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\libraries\ESP8266WiFi\src\CertStoreBearSSL.cpp line 177
0x4020c195: BearSSL::CertStore::findHashedTA(void*, void*, unsigned int) at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\libraries\ESP8266WiFi\src\CertStoreBearSSL.cpp line 176
0x40101214: free at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\umm_malloc\umm_malloc.c line 1760
0x402103b4: brssl::read_certificates(char const*, unsigned int, unsigned int*) at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\libraries\ESP8266WiFi\src\BearSSLHelpers.cpp line 343
0x40100ac0: _umm_free at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\umm_malloc\umm_malloc.c line 1300
0x40101214: free at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\umm_malloc\umm_malloc.c line 1760
0x4022a029: operator delete(void*) at ../../../../../dl/gcc-xtensa/libstdc++-v3/libsupc++/del_op.cc line 48
0x40210504: BearSSL::X509List::append(unsigned char const*, unsigned int) at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\libraries\ESP8266WiFi\src\BearSSLHelpers.cpp line 792
0x40201a8d: malloc at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\heap.c line 93
0x40100ff6: umm_malloc at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\umm_malloc\umm_malloc.c line 1681
0x40100ac0: _umm_free at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\umm_malloc\umm_malloc.c line 1300
0x40101214: free at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\umm_malloc\umm_malloc.c line 1760
0x4020c195: BearSSL::CertStore::findHashedTA(void*, void*, unsigned int) at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\libraries\ESP8266WiFi\src\CertStoreBearSSL.cpp line 176
0x4023f813: br_x509_minimal_run at src/x509/x509_minimal.c line 1217
0x402400ce: xm_append at src/x509/x509_minimal.c line 285
0x4023a0b4: br_ssl_hs_client_run at src/ssl/ssl_hs_client.c line 1863
0x402380dc: jump_handshake at src/ssl/ssl_engine.c line 1081

@earlephilhower
Copy link
Collaborator

That error, by inspection, is the result of either
a) OOM while attempting to allocate an X509 from returned data, or
b) returned x509 data is invalid from cert store reader, so the constructor aborts
and not related directly to the CertStore.

cs->_x509 = new X509List(der, ci.length);
free(der);
br_x509_trust_anchor *ta = (br_x509_trust_anchor*)cs->_x509->getTrustAnchors();
memcpy(ta->dn.data, ci.sha256, sizeof(ci.sha256));
ta->dn.len = sizeof(ci.sha256);

Please run with memory debugging enabled, I have a feeling you'll find it throwing OOM warnings right before this crash.

@earlephilhower
Copy link
Collaborator

Also, my suggestion was not to reduce the # of certs in the cert store (that's basically immaterial as only a single one will be read into memory anyway so 1 or 1,000 take the same heap), but doing away with the cert store completely. Just use a conn->setTrustAnchor(myx509cert) (from memory, check examples for exact format/params).

@NikoVonLas
Copy link
Author

NikoVonLas commented Feb 25, 2019

@earlephilhower Ok, got it. Memory debugging is TLS_MEM option?

With SSL + TLS_MEM + HTTP_CLIENT:

Exception 28: LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads
PC: 0x4020c01d: BearSSL::CertStore::findHashedTA(void*, void*, unsigned int) at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\libraries\ESP8266WiFi\src\CertStoreBearSSL.cpp line 177
EXCVADDR: 0x00000000

Decoding stack results
0x4023f8af: br_x509_minimal_run at src/x509/x509_minimal.c line 1217
0x4024016a: xm_append at src/x509/x509_minimal.c line 285
0x4023a150: br_ssl_hs_client_run at src/ssl/ssl_hs_client.c line 1863
0x402012cc: ets_printf_P at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\core_esp8266_postmortem.c line 76
0x402012c0: ets_printf_P at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\core_esp8266_postmortem.c line 76
0x40100718: vPortFree at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\heap.c line 59
0x40203927: spiffs_object_find_object_index_header_by_name_v at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\spiffs\spiffs_nucleus.c line 1673
0x4020131a: print_stack at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\core_esp8266_postmortem.c line 190
0x402014b8: __wrap_system_restart_local at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\core_esp8266_postmortem.c line 151
0x4020c01d: BearSSL::CertStore::findHashedTA(void*, void*, unsigned int) at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\libraries\ESP8266WiFi\src\CertStoreBearSSL.cpp line 177
0x40206581: spiffs_phys_rd at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\spiffs\spiffs_cache.c line 153
0x4020c01d: BearSSL::CertStore::findHashedTA(void*, void*, unsigned int) at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\libraries\ESP8266WiFi\src\CertStoreBearSSL.cpp line 177
0x4020c01d: BearSSL::CertStore::findHashedTA(void*, void*, unsigned int) at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\libraries\ESP8266WiFi\src\CertStoreBearSSL.cpp line 177
0x4020c01d: BearSSL::CertStore::findHashedTA(void*, void*, unsigned int) at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\libraries\ESP8266WiFi\src\CertStoreBearSSL.cpp line 177
0x40203c5c: spiffs_page_data_check at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\spiffs\spiffs_nucleus.c line 20
0x4020c01d: BearSSL::CertStore::findHashedTA(void*, void*, unsigned int) at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\libraries\ESP8266WiFi\src\CertStoreBearSSL.cpp line 177
0x4020c015: BearSSL::CertStore::findHashedTA(void*, void*, unsigned int) at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\libraries\ESP8266WiFi\src\CertStoreBearSSL.cpp line 176
0x401011fc: free at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\umm_malloc\umm_malloc.c line 1760
0x402101e8: brssl::read_certificates(char const*, unsigned int, unsigned int*) at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\libraries\ESP8266WiFi\src\BearSSLHelpers.cpp line 343
0x40100aa8: _umm_free at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\umm_malloc\umm_malloc.c line 1300
0x401011fc: free at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\umm_malloc\umm_malloc.c line 1760
0x4022a0b9: operator delete(void*) at ../../../../../dl/gcc-xtensa/libstdc++-v3/libsupc++/del_op.cc line 48
0x40210324: BearSSL::X509List::append(unsigned char const*, unsigned int) at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\libraries\ESP8266WiFi\src\BearSSLHelpers.cpp line 792
0x40100aa8: _umm_free at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\umm_malloc\umm_malloc.c line 1300
0x401011fc: free at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\cores\esp8266\umm_malloc\umm_malloc.c line 1760
0x4020c015: BearSSL::CertStore::findHashedTA(void*, void*, unsigned int) at D:\Documents\ArduinoData\packages\esp8266\hardware\esp8266\2.5.0\libraries\ESP8266WiFi\src\CertStoreBearSSL.cpp line 176
0x4023f8af: br_x509_minimal_run at src/x509/x509_minimal.c line 1217
0x4024016a: xm_append at src/x509/x509_minimal.c line 285
0x4023a150: br_ssl_hs_client_run at src/ssl/ssl_hs_client.c line 1863

@earlephilhower
Copy link
Collaborator

Don't remember exactly, but why not enable the entire lot (2nd to last item or so) just in case?

@NikoVonLas
Copy link
Author

NikoVonLas commented Feb 25, 2019

@earlephilhower When i set all debug options - i dont get any exceptions o_O but get "connection refused" when try to update.
UPD:
Sory, i get connection refused, in same line when try send GET request.

pm open,type:2 0
WS:ac
:rn 442
:ref 1
WS:av
:ref 2
:ur 2
New client
:ref 2
:ur 2
request: GET /update HTTP/1.1
method: GET url: /update search: 
headerName: Host
headerValue: 192.168.1.60
headerName: Connection
headerValue: keep-alive
headerName: Cache-Control
headerValue: max-age=0
headerName: Upgrade-Insecure-Requests
headerValue: 1
headerName: User-Agent
headerValue: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36
headerName: DNT
headerValue: 1
headerName: Accept
headerValue: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
headerName: Accept-Encoding
headerValue: gzip, deflate
headerName: Accept-Language
headerValue: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7
:c0 1, 442
args: 
args count: 0
args: 
args count: 0
Request: /update
Arguments: 
final list of key/value pairs:
24968
24968
[HTTP-Client][begin] url: https://antiit.ru/arduino/color-music-wifi.json
[HTTP-Client][begin] host: antiit.ru port: 443 url: /arduino/color-music-wifi.json
[hostByName] request IP for: antiit.ru
[hostByName] Host: antiit.ru IP: 87.236.16.105
:ref 1
:wr 214 0
:oom(1560)@?
:wrc 214 214 -1
:wr 214 0
:oom(1560)@?
:wrc 214 214 -1
:wr 214 0
:oom(1560)@?
:wrc 214 214 -1
:wr 214 0
:oom(1560)@?
:wrc 214 214 -1
:wr 214 0
:oom(1560)@?
:wrc 214 214 -1
:oom(456)@?
:oom(528)@?
:oom(464)@?
:oom(524)@?
:oom(464)@?
:oom(504)@?
:oom(464)@?
:oom(520)@?
:oom(536)@?
:oom(520)@?
:oom(520)@?
:oom(520)@?
:oom(520)@?
:oom(536)@?
:oom(520)@?
:oom(464)@?
:oom(504)@?
:oom(464)@?
:oom(524)@?
:oom(464)@?
:oom(528)@?
:oom(456)@?
:wr 214 0
:oom(1560)@?
:wrc 214 214 -1
:wr 214 0
:oom(1560)@?
:wrc 214 214 -1
:wr 214 0
:oom(1560)@?
:wrc 214 214 -1
:wr 214 0
:oom(1560)@?
:wrc 214 214 -1
:wr 214 0
:oom(1560)@?
:wrc 214 214 -1
:wr 214 0
:oom(1560)@?
:wrc 214 214 -1
:wr 214 0
:oom(1560)@?
:wrc 214 214 -1
:wtmo
[HTTP-Client] failed connect to antiit.ru:443
[HTTP-Client][returnError] error(-1): connection refused

@earlephilhower
Copy link
Collaborator

Debug mode is running out of memory, too. That's the :oom() bit that shows up everywhere. So it's pretty sure a heap problem.

You could try enabling just "OOM" debugging which may use a little less extra heap and try again. But I think that if you're at the state where just using debug causes heap exhaustion, that's a big red flag...

....
:wr 214 0
:oom(1560)@?
:wrc 214 214 -1
:wr 214 0
:oom(1560)@?
....

@earlephilhower
Copy link
Collaborator

Added #5819 to add in a debug message and check in CertStore for new returning nullptr.

@NikoVonLas
Copy link
Author

@earlephilhower Ok, now i minimized sketch and heap, and now i get "⸮⸮fL⸮⸮⸮⸮DH�⸮" symbols and after that ESP is restarting. OOM debug enabled.

@earlephilhower
Copy link
Collaborator

You have some other problem with your HW or code causing that, enabling debug doesn't cause random chars to come out after boot.

In any case you're obviously out of RAM and there's not much I can suggest. I didn't look at your code until just now but I see:

ESP8266WebServer server(80);
FtpServer ftpSrv;
SoftwareSerial ArduinoSerial(D7,D6);
DNSServer dnsServer;
BearSSL::CertStore certStore;

just for globals, and things like JSON parsers/etc. on the dynamic side. That's pushing it too far to work with the 40-50KB of heap total available (and no MMU so no way to defrag it). You may want to see if you can only do one of those at a time, to free up memory.

@NikoVonLas
Copy link
Author

@earlephilhower
I use ESP.getFreeHeap() function before http.begin, after it and after GET request.
And i get two only two of it in console. It show 37280 free bytes in heap.

This is minimized sketch:

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266WebServer.h>
#include <ArduinoJson.h>
#include <FS.h>
#include <SoftwareSerial.h>
#include <time.h>
#include <CertStoreBearSSL.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>

String content;

const int led = LED_BUILTIN;
const char *ssid = "ssid";
const char *pass = "pass";
const char* version = "v4.3";
const char* host = "https://antiit.ru";
const uint16_t httpsPort = 443;
const char* update_file = "/arduino/color-music-wifi.json";
const char* update_path = "/arduino/firmware";

IPAddress ip(192, 168, 1, 60);
IPAddress gate(192, 168, 1, 1);
IPAddress NMask(255, 255, 255, 0);
IPAddress dns(8, 8, 8, 8);
boolean AP_MODE         = false;
ESP8266WebServer server(80);
SoftwareSerial ArduinoSerial(D7,D6);
BearSSL::CertStore certStore;

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");
SPIFFSCertStoreFile certs_ar("/certs.ar");

void checkUpdate() {
  HTTPClient http;
  BearSSL::WiFiClientSecure *client = new BearSSL::WiFiClientSecure();
  Serial.println(ESP.getFreeHeap());
  client->setCertStore(&certStore);
  Serial.println(ESP.getFreeHeap());
  String file = (String) host + (String) update_file;
  if (http.begin(*client, file)) {
    int httpCode = http.GET();
    Serial.println(ESP.getFreeHeap());
    if (httpCode > 0) {
      Serial.print(F("[HTTP] GET CODE: "));
      Serial.println(httpCode);
      if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
        String payload = http.getString();
        Serial.println(payload);
        StaticJsonDocument<300> doc;
        auto err = deserializeJson(doc, payload);
        if (err) {
          doc.clear();
          Serial.print(F("JSON deserialize ERROR: "));
          Serial.println(err.c_str());
          server.send(200, "text/plain", "JSON ERROR");
        } else {
          if (doc["version"] != version){
            Serial.println(F("Need for update!"));
            server.send(200, "text/plain", "UPDATE STARTED DONT TURN OFF COLOR MUSIC!");
            t_httpUpdate_return ret = ESPhttpUpdate.update(*client, doc["host"], (uint16_t) doc["port"], doc["bin"], version);
            switch (ret) {
              case HTTP_UPDATE_FAILED:
                Serial.print(F("HTTP_UPDATE_FAILED Error ("));
                Serial.print(ESPhttpUpdate.getLastError());
                Serial.print(F("): "));
                Serial.print(ESPhttpUpdate.getLastErrorString().c_str());
                server.send(200, "text/plain", "UPDATE ERROR");
                break;
              case HTTP_UPDATE_NO_UPDATES:
                Serial.println(F("HTTP_UPDATE_NO_UPDATES"));
                server.send(200, "text/plain", "HTTP_UPDATE_NO_UPDATES");
                break;
              case HTTP_UPDATE_OK:
                Serial.println(F("HTTP_UPDATE_OK"));
                server.send(200, "text/plain", "HTTP_UPDATE_OK");
                //ret = ESPhttpUpdate.updateSpiffs(client, "http://server/spiffs.bin");
                break;
            }
           } else {
            server.send(200, "text/plain", "OK");
          }
        }
      } else {
        server.send(200, "text/plain", http.errorToString(httpCode).c_str());
      }
    } else {
      Serial.print(F("[HTTP] GET ERROR: "));
      Serial.println(http.errorToString(httpCode).c_str());
    }
  } else {
    Serial.println(F("[HTTP] Unable to connect!"));
    server.send(200, "text/plain", "HTTP ERROR");
  }
  http.end();
  client->stop();
  server.client().stop();
}

void setup(void) {
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  ArduinoSerial.begin(19200);
  WiFi.hostname("colormusic");
  WiFi.mode(WIFI_STA);
  WiFi.config(ip, gate, NMask, gate, dns);
  WiFi.begin(ssid, pass);
  int tryNum = 1;
  while (WiFi.status() != WL_CONNECTED) {
    Serial.println(F("Try connect to WiFi"));
    if (tryNum == 10){
      break;
    } else {
      digitalWrite(led, 1);
      delay(500);
      digitalWrite(led, 0);
      tryNum++;
    }
  }
  if (WiFi.status() == WL_CONNECTED) {
    Serial.println(F("Connected to WiFi"));
    WiFi.setAutoReconnect(true);
    Serial.println(WiFi.gatewayIP());
    Serial.println(WiFi.subnetMask());
    Serial.print("DNS #1, #2 IP: ");
    WiFi.dnsIP().printTo(Serial);
    Serial.print(", ");
    WiFi.dnsIP(1).printTo(Serial);
    Serial.println();
  } else {
    Serial.println(F("Not connected to WiFi"));
    Serial.println(F("Starting Access Point"));
    WiFi.hostname("colormusic");
    WiFi.mode(WIFI_AP);
    WiFi.softAP("ColorMusic", "ColorMusicPassword");
    delay(500);
    WiFi.softAPConfig(gate, gate, NMask);
    AP_MODE = true;
  }
  Serial.println(F("Get settings"));
  server.on("/update", []() {
    checkUpdate();
  });
  if (SPIFFS.begin()) {
    Serial.println(F("Started SPIFFS"));
    server.begin();
    Serial.println(F("Started Web Server:"));
    Serial.println(WiFi.localIP());
    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?"));
    }
  } else {
    Serial.println(F("ERROR! NO SPIFFS!"));
  }
}

void loop(void) {
  server.handleClient();
  if (!AP_MODE) {
    setClock();
  }
}

void setClock() {
  configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov");
  time_t now = time(nullptr);
  while (now < 8 * 3600 * 2) {
    yield();
    delay(1000);
    Serial.println(F("Waiting for NTP time sync"));
    now = time(nullptr);
  }
  struct tm timeinfo;
  gmtime_r(&now, &timeinfo);
}

@earlephilhower
Copy link
Collaborator

Unfortunately that's not what the :oom messages are reporting when debug is enabled, though.

You may have fragmentation going on where you have lots of space total, but without any contiguous, large-enough memory region to satisfy a request for ~500 bytes is what it showed before.

What does OOM debug output look like with your minified sketch?

Also, you've got core 2.3.0 listed as the version. That's obviously an oversight since only 2.4+ had BearSSL. Are you running git head or 2.5.0-rel?

@NikoVonLas
Copy link
Author

NikoVonLas commented Feb 25, 2019

@earlephilhower

Here decoded stack with setted port and OOM debug and last stable core (2.5):

I updated core to 2.5 two hours ago.
In minimized sketch i dont get any OOM messages.
(And i go googling articles about defragmentation(?) heap)

@earlephilhower
Copy link
Collaborator

While you're reading, can you dump the all-debug output and whatever decoded crash dump you get with the sketch you just posted a couple comments back? Since we'll obviously have different certstores (I'll just run the whole-shebang one from the example) it's not fully reproducbile by anyone but you.

@NikoVonLas
Copy link
Author

NikoVonLas commented Feb 26, 2019

@earlephilhower Get it.

With many but not all options(OOM and TLS_MEM included):

SDK:3.0.0-dev(c0f7b44)/Core:2.5.0=20500000/lwIP:STABLE-2_1_2_RELEASE/glue:1.1/BearSSL:6778687
sta config unchangedscandone
Try connect to WiFi
wifi evt: 2
scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 5 (10)
add 0
aid 4
cnt 
Try connect to WiFi

connected with AntiIT, channel 12
ip:192.168.1.60,mask:255.255.255.0,gw:192.168.1.1
ip:192.168.1.60,mask:255.255.255.0,gw:192.168.1.1
wifi evt: 0
wifi evt: 3
Connected to WiFi
192.168.1.1
255.255.255.0
DNS #1, #2 IP: 192.168.1.1, 8.8.8.8
Get settings
SPIFFSImpl: allocating %zd+%z d+%z  d=%z   d bytes
SPIFFSImpl: mounting fs @300000, size=fb000, block=2000, page=100
SPIFFSImpl: mount rc=0
Started SPIFFS
Started Web Server:
192.168.1.60
SPIFFS_close: fd=2
SPIFFS_close: fd=2
SPIFFS_close: fd=1
SPIFFS_close: fd=1
Number of CA certs read: 2
Waiting for NTP time sync
pm open,type:2 0
WS:ac
:rn 442
:ref 1
WS:av
:ref 2
:ur 2
New client
:ref 2
:ur 2
request: GET /update HTTP/1.1
method: GET url: /update search: 
headerName: Host
headerValue: 192.168.1.60
headerName: Connection
headerValue: keep-alive
headerName: Cache-Control
headerValue: max-age=0
headerName: Upgrade-Insecure-Requests
headerValue: 1
headerName: User-Agent
headerValue: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36
headerName: DNT
headerValue: 1
headerName: Accept
headerValue: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
headerName: Accept-Encoding
headerValue: gzip, deflate
headerName: Accept-Language
headerValue: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7
:c0 1, 442
args: 
args count: 0
args: 
args count: 0
Request: /update
Arguments: 
final list of key/value pairs:
34432
34432
[HTTP-Client][begin] url: https://antiit.ru/arduino/color-music-wifi.json
[HTTP-Client][begin] host: antiit.ru port: 443 url: /arduino/color-music-wifi.json
[hostByName] request IP for: antiit.ru
[hostByName] Host: antiit.ru IP: 87.236.16.105
:ref 1
:wr 214 0
:wrc 214 214 0
:ack 214
:rn 1440
:rch 1440, 1440
:rch 2880, 131
:rd 5, 3011, 0
:rdi 1440, 5
:rd 93, 3011, 5
:rdi 1435, 93
:rd 5, 3011, 98
:rdi 1342, 5
:rd 2561, 3011, 103
:rdi 1337, 1337
:c 1337, 1440, 3011
:rdi 1440, 1224
SPIFFS_close: fd=1
SPIFFS_close: fd=1
SPIFFS_close: fd=2
SPIFFS_close: fd=2
⸮⸮⸮⸮

Thats all. Nothing after.

@earlephilhower
Copy link
Collaborator

The code doesn't compile in your post. It still has a StaticJSONDocument in it.

@NikoVonLas
Copy link
Author

NikoVonLas commented Feb 26, 2019

@earlephilhower I use ArduinoJson 6 last beta. Or you mean JSON be in heap and i go out of memory?
Sry for my English ><

@earlephilhower
Copy link
Collaborator

earlephilhower commented Feb 26, 2019

JSON decoding is really bad memory-wise, can eat tons of space and fragment like mad because it makes lots of Strings.

Obviously you're running something, though, so please put in full debugging (including OOM) in. You were having OOM errors before, so it only makes sense to have them enabled especially if there's JSON stuff.

@NikoVonLas
Copy link
Author

@earlephilhower Ok, now i made so simple sketch as i can:

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <FS.h>
#include <time.h>
#include <CertStoreBearSSL.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>

String content;

const int led = LED_BUILTIN;
const char *ssid = "ssid";
const char *pass = "pass";
const char* version = "v4.3";
const char* host = "https://antiit.ru";
const uint16_t httpsPort = 443;
const char* update_file = "/arduino/color-music-wifi.json";
const char* update_path = "/arduino/firmware";

IPAddress ip(192, 168, 1, 60);
IPAddress gate(192, 168, 1, 1);
IPAddress NMask(255, 255, 255, 0);
IPAddress dns(8, 8, 8, 8);
BearSSL::CertStore certStore;

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");
SPIFFSCertStoreFile certs_ar("/certs.ar");

void checkUpdate() {
  HTTPClient http;
  BearSSL::WiFiClientSecure *client = new BearSSL::WiFiClientSecure();
  Serial.println(ESP.getFreeHeap());
  client->setCertStore(&certStore);
  Serial.println(ESP.getFreeHeap());
  String file = (String) host + (String) update_file;
  if (http.begin(*client, file)) {
    int httpCode = http.GET();
    Serial.println(ESP.getFreeHeap());
    if (httpCode > 0) {
      Serial.print(F("[HTTP] GET CODE: "));
      Serial.println(httpCode);
      if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
        String payload = http.getString();
        Serial.println(payload);
      } else {
        Serial.println(http.errorToString(httpCode).c_str());
      }
    } else {
      Serial.print(F("[HTTP] GET ERROR: "));
      Serial.println(http.errorToString(httpCode).c_str());
    }
  } else {
    Serial.println(F("[HTTP] Unable to connect!"));
  }
  http.end();
  client->stop();
}

void setup(void) {
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  WiFi.hostname("colormusic");
  WiFi.mode(WIFI_STA);
  WiFi.config(ip, gate, NMask, gate, dns);
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.println(F("Try connect to WiFi"));
    digitalWrite(led, 1);
    delay(500);
    digitalWrite(led, 0);
  }
  Serial.println(F("Connected to WiFi"));
  WiFi.setAutoReconnect(true);
  Serial.println(WiFi.gatewayIP());
  Serial.println(WiFi.subnetMask());
  Serial.print("DNS #1, #2 IP: ");
  WiFi.dnsIP().printTo(Serial);
  Serial.print(", ");
  WiFi.dnsIP(1).printTo(Serial);
  Serial.println();
  if (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?"));
    }
  } else {
    Serial.println(F("ERROR! NO SPIFFS!"));
  }
}

void loop(void) {
  setClock();
  delay(1000 * 30);
  checkUpdate();
  delay(1000*60*60);
}

void setClock() {
  configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov");
  time_t now = time(nullptr);
  while (now < 8 * 3600 * 2) {
    yield();
    delay(1000);
    Serial.println(F("Waiting for NTP time sync"));
    now = time(nullptr);
  }
  struct tm timeinfo;
  gmtime_r(&now, &timeinfo);
}

I turn on all debug options:

SDK:3.0.0-dev(c0f7b44)/Core:2.5.0=20500000/lwIP:STABLE-2_1_2_RELEASE/glue:1.1/BearSSL:6778687
sta config unchangedscandone
Try connect to WiFi
wifi evt: 2
scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 5 (10)
add 0
aid 4
cnt 
Try connect to WiFi

connected with AntiIT, channel 12
ip:192.168.1.60,mask:255.255.255.0,gw:192.168.1.1
ip:192.168.1.60,mask:255.255.255.0,gw:192.168.1.1
wifi evt: 0
wifi evt: 3
Connected to WiFi
192.168.1.1
255.255.255.0
DNS #1, #2 IP: 192.168.1.1, 8.8.8.8
SPIFFSImpl: allocating %zd+%z d+%z  d=%z   d bytes
SPIFFSImpl: mounting fs @300000, size=fb000, block=2000, page=100
SPIFFSImpl: mount rc=0
SPIFFS_close: fd=2
SPIFFS_close: fd=2
SPIFFS_close: fd=1
SPIFFS_close: fd=1
Number of CA certs read: 2
Waiting for NTP time sync
pm open,type:2 0
38672
38672
[HTTP-Client][begin] url: https://antiit.ru/arduino/color-music-wifi.json
[HTTP-Client][begin] host: antiit.ru port: 443 url: /arduino/color-music-wifi.json
[hostByName] request IP for: antiit.ru
[hostByName] Host: antiit.ru IP: 87.236.16.105
:ref 1
:wr 214 0
:wrc 214 214 0
:ack 214
:rn 1440
:rd 5, 1440, 0
:rdi 1440, 5
:rd 93, 1440, 5
:rdi 1435, 93
:rch 1440, 1440
:rch 2880, 131
:rd 5, 3011, 98
:rdi 1342, 5
:rd 2561, 3011, 103
:rdi 1337, 1337
:c 1337, 1440, 3011
:rdi 1440, 1224
SPIFFS_close: fd=1
SPIFFS_close: fd=1
SPIFFS_close: fd=2
SPIFFS_close: fd=2
?�)⸮

@earlephilhower
Copy link
Collaborator

Well, that's not a crash, obviously. Could you try at 115200 baud vs 9600 for serial, just to see if those are actually the serial port spitting chars out at a higher rate because of something?

@d-a-v, @devyte , any ideas? I'd say memory corruption, but a crash would be expected at that point...

@NikoVonLas
Copy link
Author

@earlephilhower On 115200:

SDK:3.0.0-dev(c0f7b44)/Core:2.5.0=20500000/lwIP:STABLE-2_1_2_RELEASE/glue:1.1/BearSSL:6778687
sta config unchangedscandone
Try connect to WiFi
wifi evt: 2
scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 5 (10)
add 0
aid 4
cnt 
Try connect to WiFi

connected with AntiIT, channel 12
ip:192.168.1.60,mask:255.255.255.0,gw:192.168.1.1
ip:192.168.1.60,mask:255.255.255.0,gw:192.168.1.1
wifi evt: 0
wifi evt: 3
Connected to WiFi
192.168.1.1
255.255.255.0
DNS #1, #2 IP: 192.168.1.1, 8.8.8.8
SPIFFSImpl: allocating %zd+%z d+%z  d=%z   d bytes
SPIFFSImpl: mounting fs @300000, size=fb000, block=2000, page=100
SPIFFSImpl: mount rc=0
SPIFFS_close: fd=2
SPIFFS_close: fd=2
SPIFFS_close: fd=1
SPIFFS_close: fd=1
Number of CA certs read: 2
Waiting for NTP time sync
pm open,type:2 0
38672
38672
[HTTP-Client][begin] url: https://antiit.ru/arduino/color-music-wifi.json
[HTTP-Client][begin] host: antiit.ru port: 443 url: /arduino/color-music-wifi.json
[hostByName] request IP for: antiit.ru
[hostByName] Host: antiit.ru IP: 87.236.16.105
:ref 1
:wr 214 0
:wrc 214 214 0
:ack 214
:rn 1440
:rch 1440, 1440
:rch 2880, 131
:rd 5, 3011, 0
:rdi 1440, 5
:rd 93, 3011, 5
:rdi 1435, 93
:rd 5, 3011, 98
:rdi 1342, 5
:rd 2561, 3011, 103
:rdi 1337, 1337
:c 1337, 1440, 3011
:rdi 1440, 1224
SPIFFS_close: fd=1
SPIFFS_close: fd=1
SPIFFS_close: fd=2
SPIFFS_close: fd=2

 ets Jan  8 2013,rst cause:4, boot mode:(3,6)

wdt reset
load 0x4010f000, len 1384, room 16 
tail 8
chksum 0x2d
csum 0x2d
v951aeffa
~ld

And reboot.

@devyte
Copy link
Collaborator

devyte commented Feb 26, 2019

I see one memory leak and two fishy cases that merit checks for stack corruption.
Mem leak is:
BearSSL::WiFiClientSecure *client = new BearSSL::WiFiClientSecure();
and there is no delete. This certainly would explain the oom.

Fishy cases:
SPIFFS has a max filename length of something like 30 chars. I don't remember if it's 30, 31, or 32, ad ID don't remember if that includes the nullterm char. The update_file filename has 30chars, + nullterm makes it 31 in size. That's at the limit, so it merits looking at.
The json doc object that receives is static and declared of size 300. The object size is not the same as the json size, but is actually higher. I don't know the size of the incoming json, but it could potentially overflow what static json buffer. Whatever else, using a static buffer of 300 on the stack is not a good idea, and if the incoming json decodes into more than 300 bytes, it will certainly cause stack corruption. Such usage is not safe for several reasons.

In addition, the original sketch shown has huge delays that don't let services, such as MDNS, work properly.

Closing due to user error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
waiting for feedback Waiting on additional info. If it's not received, the issue may be closed.
Projects
None yet
Development

No branches or pull requests

4 participants