使用 MQTT 代理在 ESP8266 Wemos D1 Mini 上进行 SSL 证书验证

SSL certificate verification on ESP8266 Wemos D1 Mini with MQTT broker

我有一个 raspberry pi 3,其操作系统是 raspbian stretch。我已经按照本教程在 raspberry pi 上安装并完全配置了 MQTT 代理:https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-the-mosquitto-mqtt-messaging-broker-on-ubuntu-16-04 经纪人方面一切正常。证书在 60 天后更新,您只能通过本地主机连接到端口 1883,其他端口(8883 和 8083)是开放的,但只能使用 TLS 1.2 版访问,后者也可以使用 websockets。下面你可以找到我配置mosquitto的代码(/etc/mosquitto/conf.d/default.conf).

allow_anonymous false
password_file /etc/mosquitto/passwd

listener 1883 localhost

listener 8883
certfile /etc/letsencrypt/live/home.kamidesigns.be/cert.pem
cafile /etc/letsencrypt/live/home.kamidesigns.be/chain.pem
keyfile /etc/letsencrypt/live/home.kamidesigns.be/privkey.pem
tls_version tlsv1.2

listener 8083
protocol websockets
certfile /etc/letsencrypt/live/home.kamidesigns.be/cert.pem
cafile /etc/letsencrypt/live/home.kamidesigns.be/chain.pem
keyfile /etc/letsencrypt/live/home.kamidesigns.be/privkey.pem
tls_version tlsv1.2

我还买了一个 ESP8266 Wemos D1 Mini 以安全的方式连接到这个代理。我将此 link 中的 pubsubclient 库用于我的 MQTT 客户端:https://github.com/knolleary/pubsubclient。 我使用此 link: https://github.com/esp8266/Arduino 的主分支进行安全 SSL 连接。下面是我用于编写 Wemos D1 Mini

的代码
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <time.h>

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

}

const char* ssid = "ssid";
const char* password = "wifipassword";

const char* host = "home.kamidesigns.be";
const int port = 8883;

WiFiClientSecure espClient;
PubSubClient client(host, port, callback, espClient);

long lastMsg = 0;
char msg[50];
int value = 0;

void setup() {
  Serial.begin(115200);
  Serial.println();
  Serial.print("connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  // Synchronize time useing SNTP. This is necessary to verify that
  // the TLS certificates offered by the server are currently valid.
  Serial.print("Setting time using SNTP");
  configTime(8 * 3600, 0, "pool.ntp.org", "time.nist.gov");
  time_t now = time(nullptr);
  while (now < 1000) {
    delay(500);
    Serial.print(".");
    now = time(nullptr);
  }
  Serial.println("");
  struct tm timeinfo;
  gmtime_r(&now, &timeinfo);
  Serial.print("Current time: ");
  Serial.print(asctime(&timeinfo));
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("ESP8266LightController","username","password")) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("outTopic", "hello world");
      // ... and resubscribe
      client.subscribe("inTopic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

当我启动我的 Wemos D1 时,串行监视器显示: 连接到 ssid .. 已连接 WiFi IP地址: 192.168.0.213 使用 SNTP 设置时间。 当前时间:2017年10月14日星期六02:26:25 正在尝试 MQTT 连接...已连接

这很好,这正是我想要的,但我对我的 Wemos D1 如何能够在不验证服务器证书链的情况下连接到端口 8883 感到困惑?请记住,我从未将证书上传到 Wemos D1 或将证书实施到代码中,但它仍然可以连接。

2 个选项之一

  1. WiFiClientSecure 包含 public 个 CA 证书列表,并且正在根据此列表验证您的证书
  2. WiFiClientSecure 默认不验证远程证书。

查看此 issue 看起来选项 2 最有可能,因为它意味着您必须在连接后自行验证证书。