Files
esp32-core/libraries/ArduinoOTA/examples/SignedOTA/SignedOTA.ino
T
2026-05-22 21:52:50 +03:00

205 lines
7.1 KiB
Arduino

/*
* SignedOTA Example - Secure OTA Updates with Signature Verification
*
* This example demonstrates how to perform OTA updates with cryptographic
* signature verification using ArduinoOTA library.
*
* IMPORTANT: This example requires firmware to be signed with bin_signing.py
*
* NOTE: Signature verification support is enabled via the build_opt.h file
* in this directory.
*
* Setup:
* 1. Generate keys:
* python <ARDUINO_ROOT>/tools/bin_signing.py --generate-key rsa-2048 --out private_key.pem
* python <ARDUINO_ROOT>/tools/bin_signing.py --extract-pubkey private_key.pem --out public_key.pem
*
* 2. Copy public_key.h to this sketch directory
*
* 3. Configure WiFi credentials below
*
* 4. Upload this sketch to your device
*
* 5. Build your firmware and sign it:
* arduino-cli compile --fqbn esp32:esp32:esp32 --export-binaries SignedOTA
* python <ARDUINO_ROOT>/tools/bin_signing.py --bin build/<file>.bin --key private_key.pem --out firmware_signed.bin
*
* 6. Upload signed firmware using espota.py or Arduino IDE (after modifying espota.py to handle signed binaries)
* python <ARDUINO_ROOT>/tools/espota.py -i <device-ip> -f firmware_signed.bin
*
* For more information, see the Update library's Signed_OTA_Update example
* and README.md in the Update library folder.
*
* Created by lucasssvaz
*/
#include <WiFi.h>
#include <ESPmDNS.h>
#include <NetworkUdp.h>
#include <ArduinoOTA.h>
// Include your public key (generated with bin_signing.py)
#include "public_key.h"
// ==================== CONFIGURATION ====================
// WiFi credentials
const char *ssid = "..........";
const char *password = "..........";
// Optional: Set a password for OTA authentication
// This is in ADDITION to signature verification
// ArduinoOTA password protects the OTA connection
// Signature verification ensures firmware authenticity
const char *ota_password = nullptr; // Set to nullptr to disable, or "yourpassword" to enable
// Choose hash algorithm (must match what you use with bin_signing.py --hash)
// Uncomment ONE of these:
#define USE_SHA256 // Default, recommended
// #define USE_SHA384
// #define USE_SHA512
// Choose signature algorithm (must match your key type)
// Uncomment ONE of these:
#define USE_RSA // Recommended (works with rsa-2048, rsa-3072, rsa-4096)
// #define USE_ECDSA // Works with ecdsa-p256, ecdsa-p384
// =======================================================
uint32_t last_ota_time = 0;
void setup() {
Serial.begin(115200);
Serial.println("\n\n=================================");
Serial.println("SignedOTA - Secure OTA Updates");
Serial.println("=================================\n");
Serial.println("Booting...");
// Connect to WiFi
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("Connection Failed! Rebooting...");
delay(5000);
ESP.restart();
}
Serial.println("WiFi Connected!");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// ==================== SIGNATURE VERIFICATION SETUP ====================
// Select hash algorithm
#ifdef USE_SHA256
int hashType = HASH_SHA256;
Serial.println("Using SHA-256 hash");
#elif defined(USE_SHA384)
int hashType = HASH_SHA384;
Serial.println("Using SHA-384 hash");
#elif defined(USE_SHA512)
int hashType = HASH_SHA512;
Serial.println("Using SHA-512 hash");
#else
#error "Please define a hash algorithm (USE_SHA256, USE_SHA384, or USE_SHA512)"
#endif
// Create verifier object
#ifdef USE_RSA
static UpdaterRSAVerifier sign(PUBLIC_KEY, PUBLIC_KEY_LEN, hashType);
Serial.println("Using RSA signature verification");
#elif defined(USE_ECDSA)
static UpdaterECDSAVerifier sign(PUBLIC_KEY, PUBLIC_KEY_LEN, hashType);
Serial.println("Using ECDSA signature verification");
#else
#error "Please define a signature type (USE_RSA or USE_ECDSA)"
#endif
// Install signature verification BEFORE ArduinoOTA.begin()
ArduinoOTA.setSignature(&sign);
Serial.println("✓ Signature verification enabled");
// =======================================================================
// Optional: Set hostname
// ArduinoOTA.setHostname("myesp32");
// Optional: Set OTA password (in addition to signature verification)
if (ota_password != nullptr) {
ArduinoOTA.setPassword(ota_password);
Serial.println("✓ OTA password protection enabled");
}
// Configure OTA callbacks
ArduinoOTA
.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH) {
type = "sketch";
} else { // U_SPIFFS
type = "filesystem";
}
Serial.println("\n=================================");
Serial.println("OTA Update Starting: " + type);
Serial.println("=================================");
Serial.println("⚠️ Signature will be verified!");
})
.onEnd([]() {
Serial.println("\n=================================");
Serial.println("✅ OTA Update Complete!");
Serial.println("✅ Signature Verified!");
Serial.println("=================================");
Serial.println("Rebooting...");
})
.onProgress([](unsigned int progress, unsigned int total) {
if (millis() - last_ota_time > 500) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
last_ota_time = millis();
}
})
.onError([](ota_error_t error) {
Serial.println("\n=================================");
Serial.println("❌ OTA Update Failed!");
Serial.println("=================================");
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) {
Serial.println("Authentication Failed");
Serial.println("Check your OTA password");
} else if (error == OTA_BEGIN_ERROR) {
Serial.println("Begin Failed");
Serial.println("This could be:");
Serial.println("- Signature verification setup failed");
Serial.println("- Not enough space for update");
Serial.println("- Invalid partition");
} else if (error == OTA_CONNECT_ERROR) {
Serial.println("Connect Failed");
} else if (error == OTA_RECEIVE_ERROR) {
Serial.println("Receive Failed");
} else if (error == OTA_END_ERROR) {
Serial.println("End Failed");
Serial.println("This could be:");
Serial.println("- ❌ SIGNATURE VERIFICATION FAILED!");
Serial.println("- Firmware not signed with correct key");
Serial.println("- Firmware corrupted during transfer");
Serial.println("- MD5 checksum mismatch");
}
Serial.println("=================================");
});
// Start ArduinoOTA service
ArduinoOTA.begin();
Serial.println("\n=================================");
Serial.println("✓ OTA Server Ready");
Serial.println("=================================");
Serial.printf("Hostname: %s.local\n", ArduinoOTA.getHostname().c_str());
Serial.printf("IP: %s\n", WiFi.localIP().toString().c_str());
Serial.println("Port: 3232");
Serial.println("\n⚠️ Only signed firmware will be accepted!");
Serial.println("=================================\n");
}
void loop() {
ArduinoOTA.handle();
}