mirror of
https://github.com/esphome/esphome.git
synced 2024-11-27 09:18:00 +01:00
restored fingerprint functionality
WiFiClientSecure only supports checking a single fingerprint, so support for multiple fingerprints was removed
This commit is contained in:
parent
b56eeec9d9
commit
d7652bb18a
6 changed files with 48 additions and 10 deletions
|
@ -1,3 +1,5 @@
|
|||
import re
|
||||
|
||||
from esphome import automation
|
||||
from esphome.automation import Condition
|
||||
import esphome.codegen as cg
|
||||
|
@ -36,6 +38,7 @@ from esphome.const import (
|
|||
CONF_REBOOT_TIMEOUT,
|
||||
CONF_RETAIN,
|
||||
CONF_SHUTDOWN_MESSAGE,
|
||||
CONF_SSL_FINGERPRINT,
|
||||
CONF_STATE_TOPIC,
|
||||
CONF_TOPIC,
|
||||
CONF_TOPIC_PREFIX,
|
||||
|
@ -196,6 +199,13 @@ def validate_config(value):
|
|||
return out
|
||||
|
||||
|
||||
def validate_fingerprint(value):
|
||||
value = cv.string(value)
|
||||
if re.match(r"^[0-9a-f]{40}$", value) is None:
|
||||
raise cv.Invalid("fingerprint must be valid SHA1 hash")
|
||||
return value
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
|
@ -244,6 +254,9 @@ CONFIG_SCHEMA = cv.All(
|
|||
),
|
||||
validate_message_just_topic,
|
||||
),
|
||||
cv.Optional(CONF_SSL_FINGERPRINT): cv.All(
|
||||
cv.only_on_esp8266, cv.string, validate_fingerprint
|
||||
),
|
||||
cv.Optional(CONF_KEEPALIVE, default="15s"): cv.positive_time_period_seconds,
|
||||
cv.Optional(
|
||||
CONF_REBOOT_TIMEOUT, default="15min"
|
||||
|
@ -383,10 +396,19 @@ async def to_code(config):
|
|||
|
||||
cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
|
||||
|
||||
if CONF_SSL_FINGERPRINT in config:
|
||||
cg.add_define("USE_MQTT_SECURE_CLIENT")
|
||||
fingerprint = config[CONF_SSL_FINGERPRINT]
|
||||
arr = [cg.RawExpression(f"0x{fingerprint[i:i + 2]}") for i in range(0, 40, 2)]
|
||||
cg.add(var.set_ssl_fingerprint(arr))
|
||||
|
||||
if CONF_SKIP_CERT_CN_CHECK in config:
|
||||
cg.add_define("USE_MQTT_SECURE_CLIENT")
|
||||
cg.add(var.set_skip_cert_cn_check(config[CONF_SKIP_CERT_CN_CHECK]))
|
||||
|
||||
if CONF_CERTIFICATE_AUTHORITY in config:
|
||||
cg.add_define("USE_MQTT_SECURE_CLIENT")
|
||||
cg.add(var.set_ca_certificate(config[CONF_CERTIFICATE_AUTHORITY]))
|
||||
cg.add(var.set_skip_cert_cn_check(config[CONF_SKIP_CERT_CN_CHECK]))
|
||||
if CONF_CLIENT_CERTIFICATE in config:
|
||||
cg.add(var.set_cl_certificate(config[CONF_CLIENT_CERTIFICATE]))
|
||||
cg.add(var.set_cl_key(config[CONF_CLIENT_CERTIFICATE_KEY]))
|
||||
|
|
|
@ -22,9 +22,12 @@ void MQTTBackendESP8266::initialize_() {
|
|||
if (this->ca_certificate_str_.has_value()) {
|
||||
this->ca_certificate_.append(this->ca_certificate_str_.value().c_str());
|
||||
this->wifi_client_.setTrustAnchors(&this->ca_certificate_);
|
||||
if (this->skip_cert_cn_check_) {
|
||||
this->wifi_client_.setInsecure();
|
||||
}
|
||||
}
|
||||
if (this->ssl_fingerprint_.has_value()) {
|
||||
this->wifi_client_.setFingerprint(this->ssl_fingerprint_.value().data());
|
||||
}
|
||||
if (this->skip_cert_cn_check_) {
|
||||
this->wifi_client_.setInsecure();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -93,6 +93,7 @@ class MQTTBackendESP8266 final : public MQTTBackend {
|
|||
|
||||
void set_ca_certificate(const std::string &cert) { this->ca_certificate_str_ = cert; }
|
||||
void set_skip_cert_cn_check(bool skip_check) { this->skip_cert_cn_check_ = skip_check; }
|
||||
void set_ssl_fingerprint(const std::array<uint8_t, 20> &fingerprint) { this->ssl_fingerprint_ = fingerprint; };
|
||||
|
||||
protected:
|
||||
void initialize_();
|
||||
|
@ -119,6 +120,7 @@ class MQTTBackendESP8266 final : public MQTTBackend {
|
|||
std::string lwt_message_;
|
||||
std::string client_id_;
|
||||
optional<std::string> ca_certificate_str_;
|
||||
optional<std::array<uint8_t, 20>> ssl_fingerprint_;
|
||||
BearSSL::X509List ca_certificate_;
|
||||
bool skip_cert_cn_check_{false};
|
||||
|
||||
|
|
|
@ -132,14 +132,25 @@ class MQTTClientComponent : public Component {
|
|||
bool is_discovery_enabled() const;
|
||||
bool is_discovery_ip_enabled() const;
|
||||
|
||||
/** Add a SSL fingerprint to use for TCP SSL connections to the MQTT broker.
|
||||
*
|
||||
* @warning This is *not* secure and *not* how SSL is usually done. You'll have to add
|
||||
* a separate fingerprint for every certificate you use. Additionally, the hashing
|
||||
* algorithm used here due to the constraints of the MCU, SHA1, is known to be insecure.
|
||||
*
|
||||
* @param fingerprint The SSL fingerprint as a 20 value long std::array.
|
||||
*/
|
||||
#ifdef USE_ESP8266
|
||||
void set_ssl_fingerprint(const std::array<uint8_t, 20> &fingerprint) {
|
||||
this->mqtt_backend_.set_ssl_fingerprint(fingerprint);
|
||||
};
|
||||
#endif
|
||||
void set_ca_certificate(const char *cert) { this->mqtt_backend_.set_ca_certificate(cert); }
|
||||
void set_skip_cert_cn_check(bool skip_check) { this->mqtt_backend_.set_skip_cert_cn_check(skip_check); }
|
||||
|
||||
#ifdef USE_ESP32
|
||||
void set_cl_certificate(const char *cert) { this->mqtt_backend_.set_cl_certificate(cert); }
|
||||
void set_cl_key(const char *key) { this->mqtt_backend_.set_cl_key(key); }
|
||||
#endif
|
||||
|
||||
const Availability &get_availability();
|
||||
|
||||
/** Set the topic prefix that will be prepended to all topics together with "/". This will, in most cases,
|
||||
|
|
|
@ -789,7 +789,7 @@ CONF_SPI = "spi"
|
|||
CONF_SPI_ID = "spi_id"
|
||||
CONF_SPIKE_REJECTION = "spike_rejection"
|
||||
CONF_SSID = "ssid"
|
||||
CONF_SSL_FINGERPRINTS = "ssl_fingerprints"
|
||||
CONF_SSL_FINGERPRINT = "ssl_fingerprint"
|
||||
CONF_STARTUP_DELAY = "startup_delay"
|
||||
CONF_STATE = "state"
|
||||
CONF_STATE_CLASS = "state_class"
|
||||
|
|
|
@ -17,7 +17,7 @@ from esphome.const import (
|
|||
CONF_NAME,
|
||||
CONF_PASSWORD,
|
||||
CONF_PORT,
|
||||
CONF_SSL_FINGERPRINTS,
|
||||
CONF_SSL_FINGERPRINT,
|
||||
CONF_TOPIC,
|
||||
CONF_TOPIC_PREFIX,
|
||||
CONF_USERNAME,
|
||||
|
@ -99,7 +99,7 @@ def prepare(
|
|||
elif username:
|
||||
client.username_pw_set(username, password)
|
||||
|
||||
if config[CONF_MQTT].get(CONF_SSL_FINGERPRINTS) or config[CONF_MQTT].get(
|
||||
if config[CONF_MQTT].get(CONF_SSL_FINGERPRINT) or config[CONF_MQTT].get(
|
||||
CONF_CERTIFICATE_AUTHORITY
|
||||
):
|
||||
tls_version = ssl.PROTOCOL_TLS # pylint: disable=no-member
|
||||
|
@ -267,6 +267,6 @@ def get_fingerprint(config):
|
|||
|
||||
safe_print(f"SHA1 Fingerprint: {color(Fore.CYAN, sha1)}")
|
||||
safe_print(
|
||||
f"Copy the string above into mqtt.ssl_fingerprints section of {CORE.config_path}"
|
||||
f"Add the following line to the mqtt section of {CORE.config_path}:\n {CONF_SSL_FINGERPRINT}: {sha1}"
|
||||
)
|
||||
return 0
|
||||
|
|
Loading…
Reference in a new issue