mirror of
https://github.com/esphome/esphome.git
synced 2025-09-22 05:02:23 +01:00
Merge branch 'sha256_ota' into integration
This commit is contained in:
@@ -266,11 +266,13 @@ void ESPHomeOTAComponent::handle_data_() {
|
|||||||
// TODO: Remove this entire ifdef block in 2026.1.0
|
// TODO: Remove this entire ifdef block in 2026.1.0
|
||||||
if (client_supports_sha256) {
|
if (client_supports_sha256) {
|
||||||
sha256::SHA256 sha_hasher;
|
sha256::SHA256 sha_hasher;
|
||||||
auth_success = this->perform_hash_auth_(&sha_hasher, this->password_, 16, ota::OTA_RESPONSE_REQUEST_SHA256_AUTH);
|
auth_success = this->perform_hash_auth_(&sha_hasher, this->password_, 16, ota::OTA_RESPONSE_REQUEST_SHA256_AUTH,
|
||||||
|
LOG_STR("SHA256"));
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGW(TAG, "Using MD5 auth for compatibility (deprecated)");
|
ESP_LOGW(TAG, "Using MD5 auth for compatibility (deprecated)");
|
||||||
md5::MD5Digest md5_hasher;
|
md5::MD5Digest md5_hasher;
|
||||||
auth_success = this->perform_hash_auth_(&md5_hasher, this->password_, 8, ota::OTA_RESPONSE_REQUEST_AUTH);
|
auth_success =
|
||||||
|
this->perform_hash_auth_(&md5_hasher, this->password_, 8, ota::OTA_RESPONSE_REQUEST_AUTH, LOG_STR("MD5"));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// Strict mode: SHA256 required on capable platforms (future default)
|
// Strict mode: SHA256 required on capable platforms (future default)
|
||||||
@@ -512,12 +514,15 @@ void ESPHomeOTAComponent::yield_and_feed_watchdog_() {
|
|||||||
delay(1);
|
delay(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ESPHomeOTAComponent::log_auth_warning_(const LogString *action, const LogString *hash_name) {
|
||||||
|
ESP_LOGW(TAG, "Auth: %s %s failed", LOG_STR_ARG(action), LOG_STR_ARG(hash_name));
|
||||||
|
}
|
||||||
|
|
||||||
// Non-template function definition to reduce binary size
|
// Non-template function definition to reduce binary size
|
||||||
bool ESPHomeOTAComponent::perform_hash_auth_(HashBase *hasher, const std::string &password, size_t nonce_size,
|
bool ESPHomeOTAComponent::perform_hash_auth_(HashBase *hasher, const std::string &password, size_t nonce_size,
|
||||||
uint8_t auth_request) {
|
uint8_t auth_request, const LogString *name) {
|
||||||
// Get sizes from the hasher
|
// Get sizes from the hasher
|
||||||
const size_t hex_size = hasher->get_hex_size();
|
const size_t hex_size = hasher->get_hex_size();
|
||||||
const char *name = hasher->get_name();
|
|
||||||
|
|
||||||
// Use fixed-size buffers for the maximum possible hash size (SHA256 = 64 chars)
|
// Use fixed-size buffers for the maximum possible hash size (SHA256 = 64 chars)
|
||||||
// This avoids dynamic allocation overhead
|
// This avoids dynamic allocation overhead
|
||||||
@@ -560,11 +565,11 @@ bool ESPHomeOTAComponent::perform_hash_auth_(HashBase *hasher, const std::string
|
|||||||
// Use hex_buffer1 for nonce
|
// Use hex_buffer1 for nonce
|
||||||
hasher->get_hex(hex_buffer1);
|
hasher->get_hex(hex_buffer1);
|
||||||
hex_buffer1[hex_size] = '\0';
|
hex_buffer1[hex_size] = '\0';
|
||||||
ESP_LOGV(TAG, "Auth: %s Nonce is %s", name, hex_buffer1);
|
ESP_LOGV(TAG, "Auth: %s Nonce is %s", LOG_STR_ARG(name), hex_buffer1);
|
||||||
|
|
||||||
// Send nonce
|
// Send nonce
|
||||||
if (!this->writeall_(reinterpret_cast<uint8_t *>(hex_buffer1), hex_size)) {
|
if (!this->writeall_(reinterpret_cast<uint8_t *>(hex_buffer1), hex_size)) {
|
||||||
ESP_LOGW(TAG, "Auth: Writing %s nonce failed", name);
|
this->log_auth_warning_(LOG_STR("Writing nonce"), name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -575,11 +580,11 @@ bool ESPHomeOTAComponent::perform_hash_auth_(HashBase *hasher, const std::string
|
|||||||
|
|
||||||
// Receive cnonce into hex_buffer2
|
// Receive cnonce into hex_buffer2
|
||||||
if (!this->readall_(reinterpret_cast<uint8_t *>(hex_buffer2), hex_size)) {
|
if (!this->readall_(reinterpret_cast<uint8_t *>(hex_buffer2), hex_size)) {
|
||||||
ESP_LOGW(TAG, "Auth: Reading %s cnonce failed", name);
|
this->log_auth_warning_(LOG_STR("Reading cnonce"), name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
hex_buffer2[hex_size] = '\0';
|
hex_buffer2[hex_size] = '\0';
|
||||||
ESP_LOGV(TAG, "Auth: %s CNonce is %s", name, hex_buffer2);
|
ESP_LOGV(TAG, "Auth: %s CNonce is %s", LOG_STR_ARG(name), hex_buffer2);
|
||||||
|
|
||||||
// Add cnonce to hash
|
// Add cnonce to hash
|
||||||
hasher->add(hex_buffer2, hex_size);
|
hasher->add(hex_buffer2, hex_size);
|
||||||
@@ -588,21 +593,21 @@ bool ESPHomeOTAComponent::perform_hash_auth_(HashBase *hasher, const std::string
|
|||||||
hasher->calculate();
|
hasher->calculate();
|
||||||
hasher->get_hex(hex_buffer1);
|
hasher->get_hex(hex_buffer1);
|
||||||
hex_buffer1[hex_size] = '\0';
|
hex_buffer1[hex_size] = '\0';
|
||||||
ESP_LOGV(TAG, "Auth: %s Result is %s", name, hex_buffer1);
|
ESP_LOGV(TAG, "Auth: %s Result is %s", LOG_STR_ARG(name), hex_buffer1);
|
||||||
|
|
||||||
// Receive response - reuse hex_buffer2
|
// Receive response - reuse hex_buffer2
|
||||||
if (!this->readall_(reinterpret_cast<uint8_t *>(hex_buffer2), hex_size)) {
|
if (!this->readall_(reinterpret_cast<uint8_t *>(hex_buffer2), hex_size)) {
|
||||||
ESP_LOGW(TAG, "Auth: Reading %s response failed", name);
|
this->log_auth_warning_(LOG_STR("Reading response"), name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
hex_buffer2[hex_size] = '\0';
|
hex_buffer2[hex_size] = '\0';
|
||||||
ESP_LOGV(TAG, "Auth: %s Response is %s", name, hex_buffer2);
|
ESP_LOGV(TAG, "Auth: %s Response is %s", LOG_STR_ARG(name), hex_buffer2);
|
||||||
|
|
||||||
// Compare
|
// Compare
|
||||||
bool matches = memcmp(hex_buffer1, hex_buffer2, hex_size) == 0;
|
bool matches = memcmp(hex_buffer1, hex_buffer2, hex_size) == 0;
|
||||||
|
|
||||||
if (!matches) {
|
if (!matches) {
|
||||||
ESP_LOGW(TAG, "Auth failed! %s passwords do not match", name);
|
ESP_LOGW(TAG, "Auth failed! %s passwords do not match", LOG_STR_ARG(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
return matches;
|
return matches;
|
||||||
|
@@ -31,12 +31,14 @@ class ESPHomeOTAComponent : public ota::OTAComponent {
|
|||||||
protected:
|
protected:
|
||||||
void handle_handshake_();
|
void handle_handshake_();
|
||||||
void handle_data_();
|
void handle_data_();
|
||||||
bool perform_hash_auth_(HashBase *hasher, const std::string &password, size_t nonce_size, uint8_t auth_request);
|
bool perform_hash_auth_(HashBase *hasher, const std::string &password, size_t nonce_size, uint8_t auth_request,
|
||||||
|
const LogString *name);
|
||||||
bool readall_(uint8_t *buf, size_t len);
|
bool readall_(uint8_t *buf, size_t len);
|
||||||
bool writeall_(const uint8_t *buf, size_t len);
|
bool writeall_(const uint8_t *buf, size_t len);
|
||||||
void log_socket_error_(const LogString *msg);
|
void log_socket_error_(const LogString *msg);
|
||||||
void log_read_error_(const LogString *what);
|
void log_read_error_(const LogString *what);
|
||||||
void log_start_(const LogString *phase);
|
void log_start_(const LogString *phase);
|
||||||
|
void log_auth_warning_(const LogString *action, const LogString *hash_name);
|
||||||
void cleanup_connection_();
|
void cleanup_connection_();
|
||||||
void yield_and_feed_watchdog_();
|
void yield_and_feed_watchdog_();
|
||||||
|
|
||||||
|
@@ -53,9 +53,6 @@ class MD5Digest : public HashBase {
|
|||||||
/// Get the size of the hex output (32 for MD5)
|
/// Get the size of the hex output (32 for MD5)
|
||||||
size_t get_hex_size() const override { return 32; }
|
size_t get_hex_size() const override { return 32; }
|
||||||
|
|
||||||
/// Get the algorithm name for logging
|
|
||||||
const char *get_name() const override { return "MD5"; }
|
|
||||||
|
|
||||||
/// Compare the digest against a provided byte-encoded digest (16 bytes).
|
/// Compare the digest against a provided byte-encoded digest (16 bytes).
|
||||||
bool equals_bytes(const uint8_t *expected);
|
bool equals_bytes(const uint8_t *expected);
|
||||||
|
|
||||||
|
@@ -40,9 +40,6 @@ class SHA256 : public esphome::HashBase {
|
|||||||
/// Get the size of the hex output (64 for SHA256)
|
/// Get the size of the hex output (64 for SHA256)
|
||||||
size_t get_hex_size() const override { return 64; }
|
size_t get_hex_size() const override { return 64; }
|
||||||
|
|
||||||
/// Get the algorithm name for logging
|
|
||||||
const char *get_name() const override { return "SHA256"; }
|
|
||||||
|
|
||||||
bool equals_bytes(const uint8_t *expected);
|
bool equals_bytes(const uint8_t *expected);
|
||||||
bool equals_hex(const char *expected);
|
bool equals_hex(const char *expected);
|
||||||
|
|
||||||
|
@@ -25,9 +25,6 @@ class HashBase {
|
|||||||
|
|
||||||
/// Get the size of the hex output (32 for MD5, 64 for SHA256)
|
/// Get the size of the hex output (32 for MD5, 64 for SHA256)
|
||||||
virtual size_t get_hex_size() const = 0;
|
virtual size_t get_hex_size() const = 0;
|
||||||
|
|
||||||
/// Get the algorithm name for logging
|
|
||||||
virtual const char *get_name() const = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
Reference in New Issue
Block a user