Movatterモバイル変換


[0]ホーム

URL:


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

Commit77ab98f

Browse files
lucasssvazgithub-actions[bot]pre-commit-ci-lite[bot]
authored
feat(ota): Add support for signed binaries (#11968)
* feat(ota): Add support for signed binaries* change(tools): Push generated binaries to PR* fix(ota): Use pointer rather than class* ci(pre-commit): Apply automatic fixes* change(tools): Push generated binaries to PR* fix(pre-commit): Fix spelling---------Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
1 parentc6b7dca commit77ab98f

File tree

24 files changed

+2249
-7
lines changed

24 files changed

+2249
-7
lines changed

‎.github/workflows/build_py_tools.yml‎

Lines changed: 3 additions & 1 deletion
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
@@ -108,7 +110,7 @@ jobs:
108110
-name:Install dependencies
109111
run:|
110112
python -m pip install --upgrade pip
111-
pip install pyinstaller requests
113+
pip install pyinstaller requests cryptography
112114
113115
-name:Build with PyInstaller
114116
shell:bash

‎CMakeLists.txt‎

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

240240
set(ARDUINO_LIBRARY_Update_SRCS
241241
libraries/Update/src/Updater.cpp
242-
libraries/Update/src/HttpsOTAUpdate.cpp)
242+
libraries/Update/src/HttpsOTAUpdate.cpp
243+
libraries/Update/src/Updater_Signing.cpp)
243244

244245
set(ARDUINO_LIBRARY_USB_SRCS
245246
libraries/USB/src/USBHID.cpp

‎libraries/ArduinoOTA/examples/BasicOTA/BasicOTA.ino‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,6 @@ void setup() {
3838
// Hostname defaults to esp3232-[MAC]
3939
// ArduinoOTA.setHostname("myesp32");
4040

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

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp