Skip to content

Commit 91611b0

Browse files
authored
Merge pull request esphome#2545 from esphome/bump-2021.10.0b6
2021.10.0b6
2 parents d6d0370 + ecd1158 commit 91611b0

11 files changed

+140
-29
lines changed

CODEOWNERS

+1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ esphome/components/mcp23x17_base/* @jesserockz
8989
esphome/components/mcp23xxx_base/* @jesserockz
9090
esphome/components/mcp2515/* @danielschramm @mvturnho
9191
esphome/components/mcp9808/* @k7hpn
92+
esphome/components/md5/* @esphome/core
9293
esphome/components/mdns/* @esphome/core
9394
esphome/components/midea/* @dudanov
9495
esphome/components/mitsubishi/* @RubyBailey

esphome/components/md5/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CODEOWNERS = ["@esphome/core"]

esphome/components/md5/md5.cpp

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#include <cstdio>
2+
#include <cstring>
3+
#include "md5.h"
4+
#include "esphome/core/helpers.h"
5+
6+
namespace esphome {
7+
namespace md5 {
8+
9+
void MD5Digest::init() {
10+
memset(this->digest_, 0, 16);
11+
MD5Init(&this->ctx_);
12+
}
13+
14+
void MD5Digest::add(const uint8_t *data, size_t len) { MD5Update(&this->ctx_, data, len); }
15+
16+
void MD5Digest::calculate() { MD5Final(this->digest_, &this->ctx_); }
17+
18+
void MD5Digest::get_bytes(uint8_t *output) { memcpy(output, this->digest_, 16); }
19+
20+
void MD5Digest::get_hex(char *output) {
21+
for (size_t i = 0; i < 16; i++) {
22+
sprintf(output + i * 2, "%02x", this->digest_[i]);
23+
}
24+
}
25+
26+
bool MD5Digest::equals_bytes(const char *expected) {
27+
for (size_t i = 0; i < 16; i++) {
28+
if (expected[i] != this->digest_[i]) {
29+
return false;
30+
}
31+
}
32+
return true;
33+
}
34+
35+
bool MD5Digest::equals_hex(const char *expected) {
36+
for (size_t i = 0; i < 16; i++) {
37+
auto high = parse_hex(expected[i * 2]);
38+
auto low = parse_hex(expected[i * 2 + 1]);
39+
if (!high.has_value() || !low.has_value()) {
40+
return false;
41+
}
42+
auto value = (*high << 4) | *low;
43+
if (value != this->digest_[i]) {
44+
return false;
45+
}
46+
}
47+
return true;
48+
}
49+
50+
} // namespace md5
51+
} // namespace esphome

esphome/components/md5/md5.h

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#pragma once
2+
3+
#include "esphome/core/defines.h"
4+
5+
#ifdef USE_ESP_IDF
6+
#include "esp32/rom/md5_hash.h"
7+
#define MD5_CTX_TYPE MD5Context
8+
#endif
9+
10+
#if defined(USE_ARDUINO) && defined(USE_ESP32)
11+
#include "rom/md5_hash.h"
12+
#define MD5_CTX_TYPE MD5Context
13+
#endif
14+
15+
#if defined(USE_ARDUINO) && defined(USE_ESP8266)
16+
#include <md5.h>
17+
#define MD5_CTX_TYPE md5_context_t
18+
#endif
19+
20+
namespace esphome {
21+
namespace md5 {
22+
23+
class MD5Digest {
24+
public:
25+
MD5Digest() = default;
26+
~MD5Digest() = default;
27+
28+
/// Initialize a new MD5 digest computation.
29+
void init();
30+
31+
/// Add bytes of data for the digest.
32+
void add(const uint8_t *data, size_t len);
33+
void add(const char *data, size_t len) { this->add((const uint8_t *) data, len); }
34+
35+
/// Compute the digest, based on the provided data.
36+
void calculate();
37+
38+
/// Retrieve the MD5 digest as bytes.
39+
/// The output must be able to hold 16 bytes or more.
40+
void get_bytes(uint8_t *output);
41+
42+
/// Retrieve the MD5 digest as hex characters.
43+
/// The output must be able to hold 32 bytes or more.
44+
void get_hex(char *output);
45+
46+
/// Compare the digest against a provided byte-encoded digest (16 bytes).
47+
bool equals_bytes(const char *expected);
48+
49+
/// Compare the digest against a provided hex-encoded digest (32 bytes).
50+
bool equals_hex(const char *expected);
51+
52+
protected:
53+
MD5_CTX_TYPE ctx_{};
54+
uint8_t digest_[16];
55+
};
56+
57+
} // namespace md5
58+
} // namespace esphome

esphome/components/ota/__init__.py

+2-10
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
CODEOWNERS = ["@esphome/core"]
1717
DEPENDENCIES = ["network"]
18-
AUTO_LOAD = ["socket"]
18+
AUTO_LOAD = ["socket", "md5"]
1919

2020
CONF_ON_STATE_CHANGE = "on_state_change"
2121
CONF_ON_BEGIN = "on_begin"
@@ -35,20 +35,12 @@
3535
OTAErrorTrigger = ota_ns.class_("OTAErrorTrigger", automation.Trigger.template())
3636

3737

38-
def validate_password_support(value):
39-
if CORE.using_arduino:
40-
return value
41-
if CORE.using_esp_idf:
42-
raise cv.Invalid("Password support is not implemented yet for ESP-IDF")
43-
raise NotImplementedError
44-
45-
4638
CONFIG_SCHEMA = cv.Schema(
4739
{
4840
cv.GenerateID(): cv.declare_id(OTAComponent),
4941
cv.Optional(CONF_SAFE_MODE, default=True): cv.boolean,
5042
cv.SplitDefault(CONF_PORT, esp8266=8266, esp32=3232): cv.port,
51-
cv.Optional(CONF_PASSWORD): cv.All(cv.string, validate_password_support),
43+
cv.Optional(CONF_PASSWORD): cv.string,
5244
cv.Optional(
5345
CONF_REBOOT_TIMEOUT, default="5min"
5446
): cv.positive_time_period_milliseconds,

esphome/components/ota/ota_backend_arduino_esp32.h

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ namespace esphome {
99
namespace ota {
1010

1111
class ArduinoESP32OTABackend : public OTABackend {
12+
public:
1213
OTAResponseTypes begin(size_t image_size) override;
1314
void set_update_md5(const char *md5) override;
1415
OTAResponseTypes write(uint8_t *data, size_t len) override;

esphome/components/ota/ota_backend_esp_idf.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "ota_backend_esp_idf.h"
55
#include "ota_component.h"
66
#include <esp_ota_ops.h>
7+
#include "esphome/components/md5/md5.h"
78

89
namespace esphome {
910
namespace ota {
@@ -24,15 +25,15 @@ OTAResponseTypes IDFOTABackend::begin(size_t image_size) {
2425
}
2526
return OTA_RESPONSE_ERROR_UNKNOWN;
2627
}
28+
this->md5_.init();
2729
return OTA_RESPONSE_OK;
2830
}
2931

30-
void IDFOTABackend::set_update_md5(const char *md5) {
31-
// pass
32-
}
32+
void IDFOTABackend::set_update_md5(const char *expected_md5) { memcpy(this->expected_bin_md5_, expected_md5, 32); }
3333

3434
OTAResponseTypes IDFOTABackend::write(uint8_t *data, size_t len) {
3535
esp_err_t err = esp_ota_write(this->update_handle_, data, len);
36+
this->md5_.add(data, len);
3637
if (err != ESP_OK) {
3738
if (err == ESP_ERR_OTA_VALIDATE_FAILED) {
3839
return OTA_RESPONSE_ERROR_MAGIC;
@@ -45,6 +46,11 @@ OTAResponseTypes IDFOTABackend::write(uint8_t *data, size_t len) {
4546
}
4647

4748
OTAResponseTypes IDFOTABackend::end() {
49+
this->md5_.calculate();
50+
if (!this->md5_.equals_hex(this->expected_bin_md5_)) {
51+
this->abort();
52+
return OTA_RESPONSE_ERROR_UPDATE_END;
53+
}
4854
esp_err_t err = esp_ota_end(this->update_handle_);
4955
this->update_handle_ = 0;
5056
if (err == ESP_OK) {

esphome/components/ota/ota_backend_esp_idf.h

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "ota_component.h"
66
#include "ota_backend.h"
77
#include <esp_ota_ops.h>
8+
#include "esphome/components/md5/md5.h"
89

910
namespace esphome {
1011
namespace ota {
@@ -20,6 +21,8 @@ class IDFOTABackend : public OTABackend {
2021
private:
2122
esp_ota_handle_t update_handle_{0};
2223
const esp_partition_t *partition_;
24+
md5::MD5Digest md5_{};
25+
char expected_bin_md5_[32];
2326
};
2427

2528
} // namespace ota

esphome/components/ota/ota_component.cpp

+12-15
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,12 @@
88
#include "esphome/core/application.h"
99
#include "esphome/core/hal.h"
1010
#include "esphome/core/util.h"
11+
#include "esphome/components/md5/md5.h"
1112
#include "esphome/components/network/util.h"
1213

1314
#include <cerrno>
1415
#include <cstdio>
1516

16-
#ifdef USE_OTA_PASSWORD
17-
#include <MD5Builder.h>
18-
#endif
19-
2017
namespace esphome {
2118
namespace ota {
2219

@@ -173,12 +170,12 @@ void OTAComponent::handle_() {
173170
if (!this->password_.empty()) {
174171
buf[0] = OTA_RESPONSE_REQUEST_AUTH;
175172
this->writeall_(buf, 1);
176-
MD5Builder md5_builder{};
177-
md5_builder.begin();
173+
md5::MD5Digest md5{};
174+
md5.init();
178175
sprintf(sbuf, "%08X", random_uint32());
179-
md5_builder.add(sbuf);
180-
md5_builder.calculate();
181-
md5_builder.getChars(sbuf);
176+
md5.add(sbuf, 8);
177+
md5.calculate();
178+
md5.get_hex(sbuf);
182179
ESP_LOGV(TAG, "Auth: Nonce is %s", sbuf);
183180

184181
// Send nonce, 32 bytes hex MD5
@@ -188,10 +185,10 @@ void OTAComponent::handle_() {
188185
}
189186

190187
// prepare challenge
191-
md5_builder.begin();
192-
md5_builder.add(this->password_.c_str());
188+
md5.init();
189+
md5.add(this->password_.c_str(), this->password_.length());
193190
// add nonce
194-
md5_builder.add(sbuf);
191+
md5.add(sbuf, 32);
195192

196193
// Receive cnonce, 32 bytes hex MD5
197194
if (!this->readall_(buf, 32)) {
@@ -201,11 +198,11 @@ void OTAComponent::handle_() {
201198
sbuf[32] = '\0';
202199
ESP_LOGV(TAG, "Auth: CNonce is %s", sbuf);
203200
// add cnonce
204-
md5_builder.add(sbuf);
201+
md5.add(sbuf, 32);
205202

206203
// calculate result
207-
md5_builder.calculate();
208-
md5_builder.getChars(sbuf);
204+
md5.calculate();
205+
md5.get_hex(sbuf);
209206
ESP_LOGV(TAG, "Auth: Result is %s", sbuf);
210207

211208
// Receive result, 32 bytes hex MD5

esphome/const.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Constants used by esphome."""
22

3-
__version__ = "2021.10.0b5"
3+
__version__ = "2021.10.0b6"
44

55
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
66

esphome/core/defines.h

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#define USE_LOGGER
2727
#define USE_MDNS
2828
#define USE_NUMBER
29+
#define USE_OTA_PASSWORD
2930
#define USE_OTA_STATE_CALLBACK
3031
#define USE_POWER_SUPPLY
3132
#define USE_PROMETHEUS

0 commit comments

Comments
 (0)