Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 5517c9b

Browse files
feat(ota): Add support for signed binaries
1 parent fc8ce8f commit 5517c9b

File tree

20 files changed

+2290
-3
lines changed

20 files changed

+2290
-3
lines changed

‎.github/workflows/build_py_tools.yml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ on:
88
- "tools/espota.py"
99
- "tools/gen_esp32part.py"
1010
- "tools/gen_insights_package.py"
11+
- "tools/bin_signing.py"
1112

1213
permissions:
1314
contents: write
@@ -44,6 +45,7 @@ jobs:
4445
tools/espota.py
4546
tools/gen_esp32part.py
4647
tools/gen_insights_package.py
48+
tools/bin_signing.py
4749
4850
- name: List all changed files
4951
shell: bash

‎CMakeLists.txt‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,8 @@ set(ARDUINO_LIBRARY_Ticker_SRCS libraries/Ticker/src/Ticker.cpp)
229229

230230
set(ARDUINO_LIBRARY_Update_SRCS
231231
libraries/Update/src/Updater.cpp
232-
libraries/Update/src/HttpsOTAUpdate.cpp)
232+
libraries/Update/src/HttpsOTAUpdate.cpp
233+
libraries/Update/src/Updater_Signing.cpp)
233234

234235
set(ARDUINO_LIBRARY_USB_SRCS
235236
libraries/USB/src/USBHID.cpp
Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
# SignedOTA - Secure OTA Updates with Signature Verification
2+
3+
This example demonstrates how to perform secure OTA updates with cryptographic signature verification using the ArduinoOTA library.
4+
5+
## Overview
6+
7+
**SignedOTA** adds an extra layer of security to Arduino OTA updates by requiring all firmware to be cryptographically signed with your private key. This protects against:
8+
9+
- ✅ Unauthorized firmware updates
10+
- ✅ Man-in-the-middle attacks
11+
- ✅ Compromised networks
12+
- ✅ Firmware tampering
13+
- ✅ Supply chain attacks
14+
15+
Even if an attacker gains access to your network, they **cannot** install unsigned firmware on your devices.
16+
17+
## Features
18+
19+
- **RSA & ECDSA Support**: RSA-2048/3072/4096 and ECDSA-P256/P384
20+
- **Multiple Hash Algorithms**: SHA-256, SHA-384, SHA-512
21+
- **Arduino IDE Compatible**: Works with standard Arduino OTA workflow
22+
- **Optional Password Protection**: Add password authentication in addition to signature verification
23+
- **Easy Integration**: Just a few lines of code
24+
25+
## Requirements
26+
27+
- **ESP32 Arduino Core 3.3.0+**
28+
- **Python 3.6+** with `cryptography` library
29+
- **OTA-capable partition scheme** (e.g., "Minimal SPIFFS (1.9MB APP with OTA)")
30+
31+
## Quick Start Guide
32+
33+
### 1. Generate Cryptographic Keys
34+
35+
```bash
36+
# Navigate to Arduino ESP32 tools directory
37+
cd <ARDUINO_ROOT>/tools
38+
39+
# Install Python dependencies
40+
pip install cryptography
41+
42+
# Generate RSA-2048 key pair (recommended)
43+
python bin_signing.py --generate-key rsa-2048 --out private_key.pem
44+
45+
# Extract public key
46+
python bin_signing.py --extract-pubkey private_key.pem --out public_key.pem
47+
```
48+
49+
**⚠️ IMPORTANT: Keep `private_key.pem` secure! Anyone with this key can sign firmware for your devices.**
50+
51+
### 2. Setup the Example
52+
53+
1. Copy `public_key.h` (generated in step 1) to this sketch directory
54+
2. Open `SignedOTA.ino` in Arduino IDE
55+
3. Configure WiFi credentials:
56+
```cpp
57+
const char *ssid = "YourWiFiSSID";
58+
const char *password = "YourWiFiPassword";
59+
```
60+
4. Select appropriate partition scheme:
61+
- **Tools → Partition Scheme → "Minimal SPIFFS (1.9MB APP with OTA)"**
62+
63+
### 3. Upload Initial Firmware
64+
65+
1. Connect your ESP32 via USB
66+
2. Upload the sketch normally
67+
3. Open Serial Monitor (115200 baud)
68+
4. Note the device IP address
69+
70+
### 4. Build & Sign Firmware for OTA Update Example
71+
72+
**Option A: Using Arduino IDE**
73+
74+
```bash
75+
# Export compiled binary
76+
# In Arduino IDE: Sketch → Export Compiled Binary
77+
78+
# Sign the firmware
79+
cd <ARDUINO_ROOT>/tools
80+
python bin_signing.py \
81+
--bin /path/to/SignedOTA.ino.bin \
82+
--key private_key.pem \
83+
--out firmware_signed.bin
84+
```
85+
86+
**Option B: Using arduino-cli**
87+
88+
```bash
89+
# Compile and export
90+
arduino-cli compile --fqbn esp32:esp32:esp32 --export-binaries SignedOTA
91+
92+
# Sign the firmware
93+
cd <ARDUINO_ROOT>/tools
94+
python bin_signing.py \
95+
--bin build/esp32.esp32.esp32/SignedOTA.ino.bin \
96+
--key private_key.pem \
97+
--out firmware_signed.bin
98+
```
99+
100+
### 5. Upload Signed Firmware via OTA
101+
102+
Upload the signed firmware using `espota.py`:
103+
104+
```bash
105+
python <ARDUINO_ROOT>/tools/espota.py -i <device-ip> -f firmware_signed.bin
106+
```
107+
108+
The device will automatically:
109+
1. Receive the signed firmware (firmware + signature)
110+
2. Hash only the firmware portion
111+
3. Verify the signature
112+
4. Install if valid, reject if invalid
113+
114+
**Note**: You can also use the Update library's `Signed_OTA_Update` example for HTTP-based OTA updates.
115+
116+
## Configuration Options
117+
118+
### Hash Algorithms
119+
120+
Choose one in `SignedOTA.ino`:
121+
122+
```cpp
123+
#define USE_SHA256 // Default, fastest
124+
// #define USE_SHA384
125+
// #define USE_SHA512
126+
```
127+
128+
**Must match** the `--hash` parameter when signing:
129+
130+
```bash
131+
python bin_signing.py --bin firmware.bin --key private.pem --out signed.bin --hash sha256
132+
```
133+
134+
### Signature Algorithms
135+
136+
Choose one in `SignedOTA.ino`:
137+
138+
```cpp
139+
#define USE_RSA // For RSA keys
140+
// #define USE_ECDSA // For ECDSA keys
141+
```
142+
143+
### Optional Password Protection
144+
145+
Add password authentication **in addition to** signature verification:
146+
147+
```cpp
148+
const char *ota_password = "yourpassword"; // Set password
149+
// const char *ota_password = nullptr; // Disable password
150+
```
151+
152+
## How It Works
153+
154+
```
155+
┌─────────────────┐
156+
│ Build Firmware │
157+
└────────┬────────┘
158+
159+
160+
┌─────────────────┐
161+
│ Sign Firmware │ ← Uses your private key
162+
│ (bin_signing) │
163+
└────────┬────────┘
164+
165+
166+
┌─────────────────────────┐
167+
│ firmware_signed.bin │
168+
│ [firmware][signature] │
169+
└────────┬────────────────┘
170+
171+
▼ OTA Upload
172+
┌─────────────────────────┐
173+
│ ESP32 Device │
174+
│ ┌──────────────────┐ │
175+
│ │ Verify Signature │ │ ← Uses your public key
176+
│ │ ✓ or ✗ │ │
177+
│ └──────────────────┘ │
178+
│ │ │
179+
│ ✓ Valid? │
180+
│ ├─ Yes: Install │
181+
│ └─ No: Reject │
182+
└─────────────────────────┘
183+
```
184+
185+
## Troubleshooting
186+
187+
### "Begin Failed" Error
188+
189+
**Cause**: Signature verification setup failed, or partition scheme issue
190+
191+
**Solutions**:
192+
1. Check partition scheme (use "Minimal SPIFFS (1.9MB APP with OTA)")
193+
2. Verify `public_key.h` is in the sketch directory
194+
3. Check hash and signature algorithm match your key type
195+
196+
### "End Failed" Error
197+
198+
**Cause**: Signature verification failed
199+
200+
**Solutions**:
201+
1. Ensure firmware was signed with the **correct private key**
202+
2. Verify hash algorithm matches (SHA-256, SHA-384, SHA-512)
203+
3. Check firmware wasn't corrupted during signing/transfer
204+
4. Confirm you signed the **correct** `.bin` file
205+
206+
### "Receive Failed" Error
207+
208+
**Cause**: Network timeout or connection issue
209+
210+
**Solutions**:
211+
1. Check WiFi signal strength
212+
2. Ensure device is reachable on the network
213+
3. Try increasing timeout: `ArduinoOTA.setTimeout(5000)`
214+
215+
### Upload Fails
216+
217+
**Issue**: OTA upload fails or times out
218+
219+
**Solutions**:
220+
1. Verify device is on the same network
221+
2. Check firewall settings aren't blocking port 3232
222+
3. Ensure WiFi signal strength is adequate
223+
4. If using password protection, ensure the password is correct
224+
5. Try: `python <ARDUINO_ROOT>/tools/espota.py -i <device-ip> -f firmware_signed.bin -d`
225+
226+
## Security Considerations
227+
228+
### Best Practices
229+
230+
**Keep private key secure**: Never commit to git, store encrypted
231+
**Use strong keys**: RSA-2048+ or ECDSA-P256+
232+
**Use HTTPS when possible**: For additional transport security
233+
**Add password authentication**: Extra layer of protection
234+
**Rotate keys periodically**: Generate new keys every 1-2 years
235+
236+
### What This Protects Against
237+
238+
- ✅ Unsigned firmware installation
239+
- ✅ Firmware signed with wrong key
240+
- ✅ Tampered/corrupted firmware
241+
- ✅ Network-based attacks (when combined with password)
242+
243+
### What This Does NOT Protect Against
244+
245+
- ❌ Physical access (USB flashing still works)
246+
- ❌ Downgrade attacks (no version checking by default)
247+
- ❌ Replay attacks (no timestamp/nonce by default)
248+
- ❌ Key compromise (if private key is stolen)
249+
250+
### Additional Security
251+
252+
For production deployments, consider:
253+
254+
1. **Add version checking** to prevent downgrades
255+
2. **Add timestamp validation** to prevent replay attacks
256+
3. **Use secure boot** for additional protection
257+
4. **Store keys in HSM** or secure key management system
258+
5. **Implement key rotation** mechanism
259+
260+
## Advanced Usage
261+
262+
### Using ECDSA Instead of RSA
263+
264+
ECDSA keys are smaller and faster:
265+
266+
```bash
267+
# Generate ECDSA-P256 key
268+
python bin_signing.py --generate-key ecdsa-p256 --out private_key.pem
269+
python bin_signing.py --extract-pubkey private_key.pem --out public_key.pem
270+
```
271+
272+
In `SignedOTA.ino`:
273+
274+
```cpp
275+
#define USE_SHA256
276+
#define USE_ECDSA // Instead of USE_RSA
277+
```
278+
279+
### Using SHA-384 or SHA-512
280+
281+
For higher security:
282+
283+
```bash
284+
# Sign with SHA-384
285+
python bin_signing.py --bin firmware.bin --key private.pem --out signed.bin --hash sha384
286+
```
287+
288+
In `SignedOTA.ino`:
289+
290+
```cpp
291+
#define USE_SHA384 // Instead of USE_SHA256
292+
#define USE_RSA
293+
```
294+
295+
### Custom Partition Label
296+
297+
To update a specific partition:
298+
299+
```cpp
300+
ArduinoOTA.setPartitionLabel("my_partition");
301+
```
302+
303+
## Support
304+
305+
For issues and questions:
306+
307+
- Update Library README: `libraries/Update/README.md`
308+
- ESP32 Arduino Core: https://github.com/espressif/arduino-esp32
309+
- Forum: https://github.com/espressif/arduino-esp32/discussions
310+
311+
## License
312+
313+
This library is part of the Arduino-ESP32 project and is licensed under the Apache License 2.0.
314+

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /