Skip to content

Commit 6bb59ef

Browse files
authored
Merge branch 'espressif:master' into master
2 parents 2908dba + a39d1bd commit 6bb59ef

27 files changed

+319
-140
lines changed

‎.flake8‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
doctests = True
66
# W503 and W504 are mutually exclusive. PEP 8 recommends line break before.
77
ignore = W503,E203
8-
max-complexity = 20
8+
max-complexity = 30
99
max-line-length = 120
1010
select = E,W,F,C,N

‎.github/pytools/Sign-File.ps1‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ function FindSignTool{
1919
if (Test-Path-Path $SignTool-PathType Leaf){
2020
return$SignTool
2121
}
22-
$sdkVers="10.0.22000.0","10.0.20348.0","10.0.19041.0","10.0.17763.0"
22+
$sdkVers="10.0.22000.0","10.0.20348.0","10.0.19041.0","10.0.17763.0","10.0.14393.0","10.0.15063.0","10.0.16299.0","10.0.17134.0","10.0.26100.0"
2323
Foreach ($verin$sdkVers)
2424
{
2525
$SignTool="${env:ProgramFiles(x86)}\Windows Kits\10\bin\${ver}\x64\signtool.exe"

‎.github/scripts/get_affected.py‎

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -626,11 +626,9 @@ def find_affected_sketches(changed_files: list[str]) -> None:
626626
q=queue.Queue()
627627

628628
ifcomponent_mode:
629-
print(f"Affected IDF component examples:", file=sys.stderr)
630629
# Get all available component examples once for efficiency
631630
all_examples=list_idf_component_examples()
632631
else:
633-
print(f"Affected sketches:", file=sys.stderr)
634632
all_examples= []
635633

636634
forfileinchanged_files:
@@ -648,11 +646,9 @@ def find_affected_sketches(changed_files: list[str]) -> None:
648646
# Check if this file belongs to an IDF component example
649647
forexampleinall_examples:
650648
iffile.startswith(example+"/") andexamplenotinaffected_sketches:
651-
print(example, file=sys.stderr)
652649
affected_sketches.append(example)
653650
else:
654651
iffile.endswith('.ino') andfilenotinaffected_sketches:
655-
print(file, file=sys.stderr)
656652
affected_sketches.append(file)
657653

658654
# Continue with reverse dependency traversal
@@ -687,18 +683,24 @@ def find_affected_sketches(changed_files: list[str]) -> None:
687683
ifshould_traverse:
688684
q.put(dependency)
689685
ifdependency_exampleanddependency_examplenotinaffected_sketches:
690-
print(dependency_example, file=sys.stderr)
691686
affected_sketches.append(dependency_example)
692687
else:
693688
q.put(dependency)
694689
ifdependency.endswith('.ino') anddependencynotinaffected_sketches:
695-
print(dependency, file=sys.stderr)
696690
affected_sketches.append(dependency)
697691

698692
ifcomponent_mode:
699693
print(f"Total affected IDF component examples: {len(affected_sketches)}", file=sys.stderr)
694+
ifaffected_sketches:
695+
print("Affected IDF component examples:", file=sys.stderr)
696+
forexampleinaffected_sketches:
697+
print(f" {example}", file=sys.stderr)
700698
else:
701699
print(f"Total affected sketches: {len(affected_sketches)}", file=sys.stderr)
700+
ifaffected_sketches:
701+
print("Affected sketches:", file=sys.stderr)
702+
forsketchinaffected_sketches:
703+
print(f" {sketch}", file=sys.stderr)
702704

703705
defsave_dependencies_as_json(output_file: str="dependencies.json") ->None:
704706
"""

‎.github/scripts/merge_packages.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717

1818

1919
defload_package(filename):
20-
pkg=json.load(open(filename))["packages"][0]
20+
withopen(filename) asf:
21+
pkg=json.load(f)["packages"][0]
2122
print("Loaded package{0} from{1}".format(pkg["name"], filename), file=sys.stderr)
2223
print("{0} platform(s),{1} tools".format(len(pkg["platforms"]), len(pkg["tools"])), file=sys.stderr)
2324
returnpkg

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

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
constchar *ssid = "..........";
2121
constchar *password = "..........";
22+
uint32_t last_ota_time = 0;
2223

2324
voidsetup(){
2425
Serial.begin(115200);
@@ -40,9 +41,13 @@ void setup(){
4041
// No authentication by default
4142
// ArduinoOTA.setPassword("admin");
4243

43-
// Password can be set with it's md5 value as well
44-
// MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
45-
// ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");
44+
// Password can be set with plain text (will be hashed internally)
45+
// The authentication uses PBKDF2-HMAC-SHA256 with 10,000 iterations
46+
// ArduinoOTA.setPassword("admin");
47+
48+
// Or set password with pre-hashed value (SHA256 hash of "admin")
49+
// SHA256(admin) = 8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918
50+
// ArduinoOTA.setPasswordHash("8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918");
4651

4752
ArduinoOTA
4853
.onStart([](){
@@ -60,7 +65,10 @@ void setup(){
6065
Serial.println("\nEnd");
6166
})
6267
.onProgress([](unsignedint progress, unsignedint total){
63-
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
68+
if (millis() - last_ota_time > 500){
69+
Serial.printf("Progress: %u%%\n", (progress / (total / 100)));
70+
last_ota_time = millis();
71+
}
6472
})
6573
.onError([](ota_error_t error){
6674
Serial.printf("Error[%u]: ", error);

‎libraries/ArduinoOTA/src/ArduinoOTA.cpp‎

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
#include"ArduinoOTA.h"
2020
#include"NetworkClient.h"
2121
#include"ESPmDNS.h"
22-
#include"MD5Builder.h"
22+
#include"SHA2Builder.h"
23+
#include"PBKDF2_HMACBuilder.h"
2324
#include"Update.h"
2425

2526
// #define OTA_DEBUG Serial
@@ -72,18 +73,20 @@ String ArduinoOTAClass::getHostname(){
7273

7374
ArduinoOTAClass &ArduinoOTAClass::setPassword(constchar *password){
7475
if (_state == OTA_IDLE && password){
75-
MD5Builder passmd5;
76-
passmd5.begin();
77-
passmd5.add(password);
78-
passmd5.calculate();
76+
// Hash the password with SHA256 for storage (not plain text)
77+
SHA256Builder pass_hash;
78+
pass_hash.begin();
79+
pass_hash.add(password);
80+
pass_hash.calculate();
7981
_password.clear();
80-
_password = passmd5.toString();
82+
_password = pass_hash.toString();
8183
}
8284
return *this;
8385
}
8486

8587
ArduinoOTAClass &ArduinoOTAClass::setPasswordHash(constchar *password){
8688
if (_state == OTA_IDLE && password){
89+
// Store the pre-hashed password directly
8790
_password.clear();
8891
_password = password;
8992
}
@@ -188,17 +191,18 @@ void ArduinoOTAClass::_onRx(){
188191
_udp_ota.read();
189192
_md5 = readStringUntil('\n');
190193
_md5.trim();
191-
if (_md5.length() != 32){
194+
if (_md5.length() != 32){// MD5 produces 32 character hex string for firmware integrity
192195
log_e("bad md5 length");
193196
return;
194197
}
195198

196199
if (_password.length()){
197-
MD5Builder nonce_md5;
198-
nonce_md5.begin();
199-
nonce_md5.add(String(micros()));
200-
nonce_md5.calculate();
201-
_nonce = nonce_md5.toString();
200+
// Generate a random challenge (nonce)
201+
SHA256Builder nonce_sha256;
202+
nonce_sha256.begin();
203+
nonce_sha256.add(String(micros()) + String(random(1000000)));
204+
nonce_sha256.calculate();
205+
_nonce = nonce_sha256.toString();
202206

203207
_udp_ota.beginPacket(_udp_ota.remoteIP(), _udp_ota.remotePort());
204208
_udp_ota.printf("AUTH %s", _nonce.c_str());
@@ -222,20 +226,37 @@ void ArduinoOTAClass::_onRx(){
222226
_udp_ota.read();
223227
String cnonce = readStringUntil('');
224228
String response = readStringUntil('\n');
225-
if (cnonce.length() != 32 || response.length() != 32){
229+
if (cnonce.length() != 64 || response.length() != 64){// SHA256 produces 64 character hex string
226230
log_e("auth param fail");
227231
_state = OTA_IDLE;
228232
return;
229233
}
230234

231-
String challenge = _password + ":" + String(_nonce) + ":" + cnonce;
232-
MD5Builder _challengemd5;
233-
_challengemd5.begin();
234-
_challengemd5.add(challenge);
235-
_challengemd5.calculate();
236-
String result = _challengemd5.toString();
237-
238-
if (result.equals(response)){
235+
// Verify the challenge/response using PBKDF2-HMAC-SHA256
236+
// The client should derive a key using PBKDF2-HMAC-SHA256 with:
237+
// - password: the OTA password (or its hash if using setPasswordHash)
238+
// - salt: nonce + cnonce
239+
// - iterations: 10000 (or configurable)
240+
// Then hash the challenge with the derived key
241+
242+
String salt = _nonce + ":" + cnonce;
243+
SHA256Builder sha256;
244+
// Use the stored password hash for PBKDF2 derivation
245+
PBKDF2_HMACBuilder pbkdf2(&sha256, _password, salt, 10000);
246+
247+
pbkdf2.begin();
248+
pbkdf2.calculate();
249+
String derived_key = pbkdf2.toString();
250+
251+
// Create challenge: derived_key + nonce + cnonce
252+
String challenge = derived_key + ":" + _nonce + ":" + cnonce;
253+
SHA256Builder challenge_sha256;
254+
challenge_sha256.begin();
255+
challenge_sha256.add(challenge);
256+
challenge_sha256.calculate();
257+
String expected_response = challenge_sha256.toString();
258+
259+
if (expected_response.equals(response)){
239260
_udp_ota.beginPacket(_udp_ota.remoteIP(), _udp_ota.remotePort());
240261
_udp_ota.print("OK");
241262
_udp_ota.endPacket();
@@ -266,7 +287,8 @@ void ArduinoOTAClass::_runUpdate(){
266287
_state = OTA_IDLE;
267288
return;
268289
}
269-
Update.setMD5(_md5.c_str());
290+
291+
Update.setMD5(_md5.c_str()); // Note: Update library still uses MD5 for firmware integrity, this is separate from authentication
270292

271293
if (_start_callback){
272294
_start_callback();

‎libraries/ArduinoOTA/src/ArduinoOTA.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class ArduinoOTAClass{
5454
//Sets the password that will be required for OTA. Default NULL
5555
ArduinoOTAClass &setPassword(constchar *password);
5656

57-
//Sets the password as above but in the form MD5(password). Default NULL
57+
//Sets the password as above but in the form SHA256(password). Default NULL
5858
ArduinoOTAClass &setPasswordHash(constchar *password);
5959

6060
//Sets the partition label to write to when updating SPIFFS. Default NULL

‎libraries/BLE/src/BLE2902.h‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,6 @@ This class will be removed in a future version.")]] BLE2902 : public BLEDescript
5656
boolgetIndications();
5757
voidsetNotifications(bool flag);
5858
voidsetIndications(bool flag);
59-
60-
private:
61-
friendclassBLECharacteristic;
6259
}; // BLE2902
6360

6461
#endif/* CONFIG_BLUEDROID_ENABLED || CONFIG_NIMBLE_ENABLED */

‎libraries/BLE/src/BLE2904.h‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,6 @@ class BLE2904 : public BLEDescriptor{
9595
voidsetUnit(uint16_t unit);
9696

9797
private:
98-
friendclassBLECharacteristic;
99-
10098
/***************************************************************************
10199
* Common private properties *
102100
***************************************************************************/

‎libraries/BLE/src/BLEAddress.cpp‎

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,8 @@ BLEAddress::BLEAddress(){
5959
* @param [in] otherAddress The other address to compare against.
6060
* @return True if the addresses are equal.
6161
*/
62-
boolBLEAddress::equals(BLEAddress otherAddress){
63-
#if defined(CONFIG_NIMBLE_ENABLED)
64-
if (m_addrType != otherAddress.m_addrType){
65-
returnfalse;
66-
}
67-
#endif
68-
returnmemcmp(otherAddress.getNative(), m_address, ESP_BD_ADDR_LEN) == 0;
62+
boolBLEAddress::equals(const BLEAddress &otherAddress) const{
63+
return *this == otherAddress;
6964
}
7065

7166
bool BLEAddress::operator==(const BLEAddress &otherAddress) const{
@@ -116,9 +111,9 @@ uint8_t *BLEAddress::getNative(){
116111
*
117112
* @return The string representation of the address.
118113
*/
119-
String BLEAddress::toString(){
120-
auto size = 18;
121-
char*res = (char *)malloc(size);
114+
String BLEAddress::toString() const{
115+
constexprsize_t size = 18;
116+
char res[size];
122117

123118
#if defined(CONFIG_BLUEDROID_ENABLED)
124119
snprintf(res, size, "%02x:%02x:%02x:%02x:%02x:%02x", m_address[0], m_address[1], m_address[2], m_address[3], m_address[4], m_address[5]);
@@ -129,7 +124,6 @@ String BLEAddress::toString(){
129124
#endif
130125

131126
String ret(res);
132-
free(res);
133127
return ret;
134128
}
135129

@@ -158,7 +152,7 @@ BLEAddress::BLEAddress(esp_bd_addr_t address){
158152
*
159153
* @param [in] stringAddress The hex representation of the address.
160154
*/
161-
BLEAddress::BLEAddress(String stringAddress){
155+
BLEAddress::BLEAddress(constString &stringAddress){
162156
if (stringAddress.length() != 17){
163157
return;
164158
}
@@ -193,7 +187,7 @@ BLEAddress::BLEAddress(ble_addr_t address){
193187
m_addrType = address.type;
194188
}
195189

196-
uint8_tBLEAddress::getType(){
190+
uint8_tBLEAddress::getType() const{
197191
return m_addrType;
198192
}
199193

@@ -209,7 +203,7 @@ uint8_t BLEAddress::getType(){
209203
* @param [in] stringAddress The hex representation of the address.
210204
* @param [in] type The address type.
211205
*/
212-
BLEAddress::BLEAddress(String stringAddress, uint8_t type){
206+
BLEAddress::BLEAddress(constString &stringAddress, uint8_t type){
213207
if (stringAddress.length() != 17){
214208
return;
215209
}

0 commit comments

Comments
(0)