mirror of
https://github.com/esphome/esphome.git
synced 2024-11-27 17:27:59 +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 import automation
|
||||||
from esphome.automation import Condition
|
from esphome.automation import Condition
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
|
@ -36,6 +38,7 @@ from esphome.const import (
|
||||||
CONF_REBOOT_TIMEOUT,
|
CONF_REBOOT_TIMEOUT,
|
||||||
CONF_RETAIN,
|
CONF_RETAIN,
|
||||||
CONF_SHUTDOWN_MESSAGE,
|
CONF_SHUTDOWN_MESSAGE,
|
||||||
|
CONF_SSL_FINGERPRINT,
|
||||||
CONF_STATE_TOPIC,
|
CONF_STATE_TOPIC,
|
||||||
CONF_TOPIC,
|
CONF_TOPIC,
|
||||||
CONF_TOPIC_PREFIX,
|
CONF_TOPIC_PREFIX,
|
||||||
|
@ -196,6 +199,13 @@ def validate_config(value):
|
||||||
return out
|
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(
|
CONFIG_SCHEMA = cv.All(
|
||||||
cv.Schema(
|
cv.Schema(
|
||||||
{
|
{
|
||||||
|
@ -244,6 +254,9 @@ CONFIG_SCHEMA = cv.All(
|
||||||
),
|
),
|
||||||
validate_message_just_topic,
|
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_KEEPALIVE, default="15s"): cv.positive_time_period_seconds,
|
||||||
cv.Optional(
|
cv.Optional(
|
||||||
CONF_REBOOT_TIMEOUT, default="15min"
|
CONF_REBOOT_TIMEOUT, default="15min"
|
||||||
|
@ -383,10 +396,19 @@ async def to_code(config):
|
||||||
|
|
||||||
cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
|
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:
|
if CONF_CERTIFICATE_AUTHORITY in config:
|
||||||
cg.add_define("USE_MQTT_SECURE_CLIENT")
|
cg.add_define("USE_MQTT_SECURE_CLIENT")
|
||||||
cg.add(var.set_ca_certificate(config[CONF_CERTIFICATE_AUTHORITY]))
|
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:
|
if CONF_CLIENT_CERTIFICATE in config:
|
||||||
cg.add(var.set_cl_certificate(config[CONF_CLIENT_CERTIFICATE]))
|
cg.add(var.set_cl_certificate(config[CONF_CLIENT_CERTIFICATE]))
|
||||||
cg.add(var.set_cl_key(config[CONF_CLIENT_CERTIFICATE_KEY]))
|
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()) {
|
if (this->ca_certificate_str_.has_value()) {
|
||||||
this->ca_certificate_.append(this->ca_certificate_str_.value().c_str());
|
this->ca_certificate_.append(this->ca_certificate_str_.value().c_str());
|
||||||
this->wifi_client_.setTrustAnchors(&this->ca_certificate_);
|
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
|
#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_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_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:
|
protected:
|
||||||
void initialize_();
|
void initialize_();
|
||||||
|
@ -119,6 +120,7 @@ class MQTTBackendESP8266 final : public MQTTBackend {
|
||||||
std::string lwt_message_;
|
std::string lwt_message_;
|
||||||
std::string client_id_;
|
std::string client_id_;
|
||||||
optional<std::string> ca_certificate_str_;
|
optional<std::string> ca_certificate_str_;
|
||||||
|
optional<std::array<uint8_t, 20>> ssl_fingerprint_;
|
||||||
BearSSL::X509List ca_certificate_;
|
BearSSL::X509List ca_certificate_;
|
||||||
bool skip_cert_cn_check_{false};
|
bool skip_cert_cn_check_{false};
|
||||||
|
|
||||||
|
|
|
@ -132,14 +132,25 @@ class MQTTClientComponent : public Component {
|
||||||
bool is_discovery_enabled() const;
|
bool is_discovery_enabled() const;
|
||||||
bool is_discovery_ip_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_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); }
|
void set_skip_cert_cn_check(bool skip_check) { this->mqtt_backend_.set_skip_cert_cn_check(skip_check); }
|
||||||
|
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
void set_cl_certificate(const char *cert) { this->mqtt_backend_.set_cl_certificate(cert); }
|
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); }
|
void set_cl_key(const char *key) { this->mqtt_backend_.set_cl_key(key); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const Availability &get_availability();
|
const Availability &get_availability();
|
||||||
|
|
||||||
/** Set the topic prefix that will be prepended to all topics together with "/". This will, in most cases,
|
/** 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_SPI_ID = "spi_id"
|
||||||
CONF_SPIKE_REJECTION = "spike_rejection"
|
CONF_SPIKE_REJECTION = "spike_rejection"
|
||||||
CONF_SSID = "ssid"
|
CONF_SSID = "ssid"
|
||||||
CONF_SSL_FINGERPRINTS = "ssl_fingerprints"
|
CONF_SSL_FINGERPRINT = "ssl_fingerprint"
|
||||||
CONF_STARTUP_DELAY = "startup_delay"
|
CONF_STARTUP_DELAY = "startup_delay"
|
||||||
CONF_STATE = "state"
|
CONF_STATE = "state"
|
||||||
CONF_STATE_CLASS = "state_class"
|
CONF_STATE_CLASS = "state_class"
|
||||||
|
|
|
@ -17,7 +17,7 @@ from esphome.const import (
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
CONF_PASSWORD,
|
CONF_PASSWORD,
|
||||||
CONF_PORT,
|
CONF_PORT,
|
||||||
CONF_SSL_FINGERPRINTS,
|
CONF_SSL_FINGERPRINT,
|
||||||
CONF_TOPIC,
|
CONF_TOPIC,
|
||||||
CONF_TOPIC_PREFIX,
|
CONF_TOPIC_PREFIX,
|
||||||
CONF_USERNAME,
|
CONF_USERNAME,
|
||||||
|
@ -99,7 +99,7 @@ def prepare(
|
||||||
elif username:
|
elif username:
|
||||||
client.username_pw_set(username, password)
|
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
|
CONF_CERTIFICATE_AUTHORITY
|
||||||
):
|
):
|
||||||
tls_version = ssl.PROTOCOL_TLS # pylint: disable=no-member
|
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"SHA1 Fingerprint: {color(Fore.CYAN, sha1)}")
|
||||||
safe_print(
|
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
|
return 0
|
||||||
|
|
Loading…
Reference in a new issue