esp8266 / Arduino

ESP8266 core for Arduino
GNU Lesser General Public License v2.1
16.03k stars 13.34k forks source link

httpUpdateSigned example sketch does not compile when saved to another directory #7393

Closed Bartvelp closed 4 years ago

Bartvelp commented 4 years ago

Basic Infos

Platform

Settings in IDE

Problem Description

When compiling the example sketch httpUpdateSigned everything works as expected, but when saving this exact sketch to another directory, I get the following error:

c:/users/bgros/appdata/local/arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/2.5.0-4-b40a506/bin/../lib/gcc/xtensa-lx106-elf/4.8.2/../../../../xtensa-lx106-elf/bin/ld.exe: C:\Users\bgros\AppData\Local\Temp\arduino_cache_163614\core\core_9580e9c509319566761fbf5ce0073bc6.a(Updater.cpp.o):(.text._ZN12UpdaterClassC2Ev+0x0): undefined reference to `esp8266::updaterSigningVerifier'

c:/users/bgros/appdata/local/arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/2.5.0-4-b40a506/bin/../lib/gcc/xtensa-lx106-elf/4.8.2/../../../../xtensa-lx106-elf/bin/ld.exe: C:\Users\bgros\AppData\Local\Temp\arduino_cache_163614\core\core_9580e9c509319566761fbf5ce0073bc6.a(Updater.cpp.o):(.text._ZN12UpdaterClassC2Ev+0x4): undefined reference to `esp8266::updaterSigningHash'

collect2.exe: error: ld returned 1 exit status

exit status 1

When compiling with the VScode Arduino extension, the project compiles successfully, but gives a hardware watchdog timer reset when trying to verify the hash. If I omit setting the hash everything works fine

MCVE Sketch

/*
   httpUpdateSigned.ino - Earle F. Philhower, III
   Released into the Public Domain

   For use while building under Linux or Mac.

   Automatic code signing is not supported on Windows, so this example
   DOES NOT WORK UNDER WINDOWS.

   Shows how to use a public key extracted from your private certificate to
   only allow updates that you have signed to be applied over HTTP.  Remote
   updates will require your private key to sign them, but of course
   **ANYONE WITH PHYSICAL ACCESS CAN UPDATE THE 8266 VIA THE SERIAL PORT**.
*/

#include <Arduino.h>

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>

#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>

#ifndef STASSID
#define STASSID "XXXX"
#define STAPSK  "XXXX"
#endif

ESP8266WiFiMulti WiFiMulti;

#define MANUAL_SIGNING 0 // Changing this to 1 does not change anything

// This example is now configured to use the automated signing support
// present in the Arduino IDE by having a "private.key" and "public.key"
// in the sketch folder.  You can also programmatically enable signing
// using the method shown here.

// This key is taken from the server public certificate in BearSSL examples
// You should make your own private/public key pair and guard the private
// key (never upload it to the 8266).
const char pubkey[] PROGMEM = R"EOF(
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyW5a4OO7xd6pRDTETO7h
vEMBOr/wCqcTi/gi2/99rPnVvT7IH/qGSiYMxpGFKCXVqS4rU5k2XspALEquyGse
Uav5hqsgHO6CQFFALqXzUVNCsJA9V6raUFhBaIqqCKmWzmeAkV+avM/zDQR9Wj1Q
TCmi997sJJ5ICQc8cGSdvrhisUSbfPpKI9Ql4FApOZRABBBuZKhN9ujIzTv3OIAa
rpQVfACKKuv7a2N2qU0uxRDojeO6odT1c6AZv6BlcF76GQGTo+/oBhqPdbAQuaBy
cuWNgTnDQd6KUzV0E4it2fNG+cHN4kEvofN6gHx8IbOrXwFttlpAH/o7bcfCnUVh
TQIDAQAB
-----END PUBLIC KEY-----
)EOF";
#if MANUAL_SIGNING
BearSSL::PublicKey *signPubKey = nullptr;
BearSSL::HashSHA256 *hash;
BearSSL::SigningVerifier *sign;
#endif

void setup() {

  Serial.begin(115200);
  // 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);
  WiFiMulti.addAP(STASSID, STAPSK);

  #if MANUAL_SIGNING
  signPubKey = new BearSSL::PublicKey(pubkey);
  hash = new BearSSL::HashSHA256();
  sign = new BearSSL::SigningVerifier(signPubKey);
  #endif
}

void loop() {
  // wait for WiFi connection
  if ((WiFiMulti.run() == WL_CONNECTED)) {

    WiFiClient client;

    #if MANUAL_SIGNING
    // Ensure all updates are signed appropriately.  W/o this call, all will be accepted.
    Update.installSignature(hash, sign);
    #endif
    // If the key files are present in the build directory, signing will be
    // enabled using them automatically

    ESPhttpUpdate.setLedPin(LED_BUILTIN, LOW);

    t_httpUpdate_return ret = ESPhttpUpdate.update(client, "http://192.168.1.118:8080/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;
    }
  }
  delay(10000);
}

Debug Messages

I suspected it may be due to the key files that are present in the example sketch but not in the saved example sketch, but copying them to the directory did not solve the issue. This method seems to have been added in this pull request: https://github.com/esp8266/Arduino/pull/6398/files by @dok-net

Bartvelp commented 4 years ago

Still don't know what caused this issue, but when pasting the public key in the project directory, arduino uses signing.py to add verification itself. It then failes to actually sign the binairy, but I can just do that by hand, using the same signing.py. Weird issue though, should still be checked out imo. Can anybody reproduce?

earlephilhower commented 4 years ago

@Bartvelp, for signing you need a private.key and the corresponding public.key.

W/o the private key, signing can't work and won't be enabled. So the main thing you're experiencing is expected and the only possible thing for the Arduino IDE to do. You need both in the dir if you're going to build signed apps or apps which require signing.

Also, of course, if you're really signing apps then you should generate your own key pair and use that in place of the (unsafe...private.key is public) ones in the example.

When I copied over the example with the two key files, I did get a xxx.bin.legacy_sig and an xxx.signed. Note that the IDE generates these in the temp build directory, where it makes the .bin file, so you need to poke there to get them.

As for the non-Arduino IDE build errors, unfortunately we can't really help. Some IDEs don't parse the platform.txt file properly.