From 47b0f9750860c33a792eaba1b4b13eef2213fb20 Mon Sep 17 00:00:00 2001 From: Alexandre B Date: Fri, 13 Jun 2025 23:58:48 -0400 Subject: [PATCH] tls --- .vscode/settings.json | 5 + ESP-IDF_MQQTS_v5-4/.devcontainer/Dockerfile | 13 ++ .../.devcontainer/devcontainer.json | 21 +++ .../.vscode/c_cpp_properties.json | 23 +++ ESP-IDF_MQQTS_v5-4/.vscode/launch.json | 15 ++ ESP-IDF_MQQTS_v5-4/.vscode/settings.json | 13 ++ ESP-IDF_MQQTS_v5-4/CMakeLists.txt | 9 + ESP-IDF_MQQTS_v5-4/README.md | 70 ++++++++ ESP-IDF_MQQTS_v5-4/main/CMakeLists.txt | 2 + ESP-IDF_MQQTS_v5-4/main/Kconfig.projbuild | 26 +++ ESP-IDF_MQQTS_v5-4/main/app_main.c | 165 ++++++++++++++++++ ESP-IDF_MQQTS_v5-4/main/idf_component.yml | 3 + .../main/mqtt_eclipseprojects_io.pem | 30 ++++ ESP-IDF_MQQTS_v5-4/pytest_mqtt_ssl.py | 129 ++++++++++++++ ESP-IDF_MQQTS_v5-4/sdkconfig.ci | 22 +++ 15 files changed, 546 insertions(+) create mode 100644 .vscode/settings.json create mode 100644 ESP-IDF_MQQTS_v5-4/.devcontainer/Dockerfile create mode 100644 ESP-IDF_MQQTS_v5-4/.devcontainer/devcontainer.json create mode 100644 ESP-IDF_MQQTS_v5-4/.vscode/c_cpp_properties.json create mode 100644 ESP-IDF_MQQTS_v5-4/.vscode/launch.json create mode 100644 ESP-IDF_MQQTS_v5-4/.vscode/settings.json create mode 100644 ESP-IDF_MQQTS_v5-4/CMakeLists.txt create mode 100644 ESP-IDF_MQQTS_v5-4/README.md create mode 100644 ESP-IDF_MQQTS_v5-4/main/CMakeLists.txt create mode 100644 ESP-IDF_MQQTS_v5-4/main/Kconfig.projbuild create mode 100644 ESP-IDF_MQQTS_v5-4/main/app_main.c create mode 100644 ESP-IDF_MQQTS_v5-4/main/idf_component.yml create mode 100644 ESP-IDF_MQQTS_v5-4/main/mqtt_eclipseprojects_io.pem create mode 100644 ESP-IDF_MQQTS_v5-4/pytest_mqtt_ssl.py create mode 100644 ESP-IDF_MQQTS_v5-4/sdkconfig.ci diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..47a29bb28 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "idf.espIdfPathWin": "C:\\Users\\alex\\esp\\v5.4\\esp-idf", + "idf.toolsPathWin": "c:\\Users\\alex\\esp\\", + "idf.pythonInstallPath": "c:\\Users\\alex\\esp\\tools\\idf-python\\3.11.2\\python.exe" +} \ No newline at end of file diff --git a/ESP-IDF_MQQTS_v5-4/.devcontainer/Dockerfile b/ESP-IDF_MQQTS_v5-4/.devcontainer/Dockerfile new file mode 100644 index 000000000..dafb8adbb --- /dev/null +++ b/ESP-IDF_MQQTS_v5-4/.devcontainer/Dockerfile @@ -0,0 +1,13 @@ +ARG DOCKER_TAG=latest +FROM espressif/idf:${DOCKER_TAG} + +ENV LC_ALL=C.UTF-8 +ENV LANG=C.UTF-8 + +RUN apt-get update -y && apt-get install udev -y + +RUN echo "source /opt/esp/idf/export.sh > /dev/null 2>&1" >> ~/.bashrc + +ENTRYPOINT [ "/opt/esp/entrypoint.sh" ] + +CMD ["/bin/bash", "-c"] \ No newline at end of file diff --git a/ESP-IDF_MQQTS_v5-4/.devcontainer/devcontainer.json b/ESP-IDF_MQQTS_v5-4/.devcontainer/devcontainer.json new file mode 100644 index 000000000..b80178618 --- /dev/null +++ b/ESP-IDF_MQQTS_v5-4/.devcontainer/devcontainer.json @@ -0,0 +1,21 @@ +{ + "name": "ESP-IDF QEMU", + "build": { + "dockerfile": "Dockerfile" + }, + "customizations": { + "vscode": { + "settings": { + "terminal.integrated.defaultProfile.linux": "bash", + "idf.espIdfPath": "/opt/esp/idf", + "idf.toolsPath": "/opt/esp", + "idf.gitPath": "/usr/bin/git" + }, + "extensions": [ + "espressif.esp-idf-extension", + "espressif.esp-idf-web" + ] + } + }, + "runArgs": ["--privileged"] +} \ No newline at end of file diff --git a/ESP-IDF_MQQTS_v5-4/.vscode/c_cpp_properties.json b/ESP-IDF_MQQTS_v5-4/.vscode/c_cpp_properties.json new file mode 100644 index 000000000..8cf8f4d8e --- /dev/null +++ b/ESP-IDF_MQQTS_v5-4/.vscode/c_cpp_properties.json @@ -0,0 +1,23 @@ +{ + "configurations": [ + { + "name": "ESP-IDF", + "compilerPath": "${config:idf.toolsPathWin}tools\\xtensa-esp-elf\\esp-14.2.0_20241119\\xtensa-esp-elf\\bin\\xtensa-esp32-elf-gcc.exe", + "compileCommands": "${config:idf.buildPath}/compile_commands.json", + "includePath": [ + "${config:idf.espIdfPath}/components/**", + "${config:idf.espIdfPathWin}/components/**", + "${workspaceFolder}/**" + ], + "browse": { + "path": [ + "${config:idf.espIdfPath}/components", + "${config:idf.espIdfPathWin}/components", + "${workspaceFolder}" + ], + "limitSymbolsToIncludedHeaders": true + } + } + ], + "version": 4 +} diff --git a/ESP-IDF_MQQTS_v5-4/.vscode/launch.json b/ESP-IDF_MQQTS_v5-4/.vscode/launch.json new file mode 100644 index 000000000..2511a38aa --- /dev/null +++ b/ESP-IDF_MQQTS_v5-4/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "gdbtarget", + "request": "attach", + "name": "Eclipse CDT GDB Adapter" + }, + { + "type": "espidf", + "name": "Launch", + "request": "launch" + } + ] +} \ No newline at end of file diff --git a/ESP-IDF_MQQTS_v5-4/.vscode/settings.json b/ESP-IDF_MQQTS_v5-4/.vscode/settings.json new file mode 100644 index 000000000..316d21dd7 --- /dev/null +++ b/ESP-IDF_MQQTS_v5-4/.vscode/settings.json @@ -0,0 +1,13 @@ +{ + "C_Cpp.intelliSenseEngine": "default", + "idf.espIdfPathWin": "C:\\Users\\alex\\esp\\v5.4\\esp-idf", + "idf.pythonInstallPath": "c:\\Users\\alex\\esp\\tools\\idf-python\\3.11.2\\python.exe", + "idf.openOcdConfigs": [ + "board/esp32c3-builtin.cfg" + ], + "idf.portWin": "COM10", + "idf.toolsPathWin": "c:\\Users\\alex\\esp\\", + "idf.customExtraVars": { + "IDF_TARGET": "esp32c3" + } +} diff --git a/ESP-IDF_MQQTS_v5-4/CMakeLists.txt b/ESP-IDF_MQQTS_v5-4/CMakeLists.txt new file mode 100644 index 000000000..a9faded54 --- /dev/null +++ b/ESP-IDF_MQQTS_v5-4/CMakeLists.txt @@ -0,0 +1,9 @@ +# The following four lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(ESP-IDF_MQQTS_v5-4) + +target_add_binary_data(mqtt_ssl.elf "main/mqtt_eclipseprojects_io.pem" TEXT) diff --git a/ESP-IDF_MQQTS_v5-4/README.md b/ESP-IDF_MQQTS_v5-4/README.md new file mode 100644 index 000000000..0407edad9 --- /dev/null +++ b/ESP-IDF_MQQTS_v5-4/README.md @@ -0,0 +1,70 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | + +# ESP-MQTT SSL Sample application + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example connects to the broker mqtt.eclipseprojects.io using ssl transport and as a demonstration subscribes/unsubscribes and send a message on certain topic. +(Please note that the public broker is maintained by the community so may not be always available, for details please see this [disclaimer](https://iot.eclipse.org/getting-started/#sandboxes)) + +It uses ESP-MQTT library which implements mqtt client to connect to mqtt broker. + +## How to use example + +### Hardware Required + +This example can be executed on any ESP32 board, the only required interface is WiFi and connection to internet. + +### Configure the project + +* Open the project configuration menu (`idf.py menuconfig`) +* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. + +PEM certificate for this example could be extracted from an openssl `s_client` command connecting to mqtt.eclipseprojects.io. +In case a host operating system has `openssl` and `sed` packages installed, one could execute the following command to download and save the root certificate to a file (Note for Windows users: Both Linux like environment or Windows native packages may be used). +``` +echo "" | openssl s_client -showcerts -connect mqtt.eclipseprojects.io:8883 | sed -n "1,/Root/d; /BEGIN/,/END/p" | openssl x509 -outform PEM >mqtt_eclipse_org.pem +``` +Please note that this is not a general command for downloading a root certificate for an arbitrary host; +this command works with mqtt.eclipseprojects.io as the site provides root certificate in the chain, which then could be extracted +with text operation. + +### Build and Flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +``` +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +``` +I (3714) event: sta ip: 192.168.0.139, mask: 255.255.255.0, gw: 192.168.0.2 +I (3714) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE +I (3964) MQTT_CLIENT: Sending MQTT CONNECT message, type: 1, id: 0000 +I (4164) MQTTS_EXAMPLE: MQTT_EVENT_CONNECTED +I (4174) MQTTS_EXAMPLE: sent publish successful, msg_id=41464 +I (4174) MQTTS_EXAMPLE: sent subscribe successful, msg_id=17886 +I (4174) MQTTS_EXAMPLE: sent subscribe successful, msg_id=42970 +I (4184) MQTTS_EXAMPLE: sent unsubscribe successful, msg_id=50241 +I (4314) MQTTS_EXAMPLE: MQTT_EVENT_PUBLISHED, msg_id=41464 +I (4484) MQTTS_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=17886 +I (4484) MQTTS_EXAMPLE: sent publish successful, msg_id=0 +I (4684) MQTTS_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=42970 +I (4684) MQTTS_EXAMPLE: sent publish successful, msg_id=0 +I (4884) MQTT_CLIENT: deliver_publish, message_length_read=19, message_length=19 +I (4884) MQTTS_EXAMPLE: MQTT_EVENT_DATA +TOPIC=/topic/qos0 +DATA=data +I (5194) MQTT_CLIENT: deliver_publish, message_length_read=19, message_length=19 +I (5194) MQTTS_EXAMPLE: MQTT_EVENT_DATA +TOPIC=/topic/qos0 +DATA=data +``` + diff --git a/ESP-IDF_MQQTS_v5-4/main/CMakeLists.txt b/ESP-IDF_MQQTS_v5-4/main/CMakeLists.txt new file mode 100644 index 000000000..61fac40e6 --- /dev/null +++ b/ESP-IDF_MQQTS_v5-4/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "app_main.c" + INCLUDE_DIRS ".") diff --git a/ESP-IDF_MQQTS_v5-4/main/Kconfig.projbuild b/ESP-IDF_MQQTS_v5-4/main/Kconfig.projbuild new file mode 100644 index 000000000..5e9357d1a --- /dev/null +++ b/ESP-IDF_MQQTS_v5-4/main/Kconfig.projbuild @@ -0,0 +1,26 @@ +menu "Example Configuration" + + config BROKER_URI + string "Broker URL" + default "mqtts://mqtt.eclipseprojects.io:8883" + help + URL of an mqtt broker which this example connects to. + + config BROKER_CERTIFICATE_OVERRIDE + string "Broker certificate override" + default "" + help + Please leave empty if broker certificate included from a textfile; otherwise fill in a base64 part of PEM + format certificate + + config BROKER_CERTIFICATE_OVERRIDDEN + bool + default y if BROKER_CERTIFICATE_OVERRIDE != "" + + config BROKER_BIN_SIZE_TO_SEND + # This option is not visible and is used only to set parameters for example tests + # Here we configure the data size to send and to be expected in the python script + int + default 20000 + +endmenu diff --git a/ESP-IDF_MQQTS_v5-4/main/app_main.c b/ESP-IDF_MQQTS_v5-4/main/app_main.c new file mode 100644 index 000000000..20cf1808f --- /dev/null +++ b/ESP-IDF_MQQTS_v5-4/main/app_main.c @@ -0,0 +1,165 @@ +/* MQTT over SSL Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include +#include +#include "esp_system.h" +#include "esp_partition.h" +#include "nvs_flash.h" +#include "esp_event.h" +#include "esp_netif.h" +#include "protocol_examples_common.h" + +#include "esp_log.h" +#include "mqtt_client.h" +#include "esp_tls.h" +#include "esp_ota_ops.h" +#include + +static const char *TAG = "mqtts_example"; + + +#if CONFIG_BROKER_CERTIFICATE_OVERRIDDEN == 1 +static const uint8_t mqtt_eclipseprojects_io_pem_start[] = "-----BEGIN CERTIFICATE-----\n" CONFIG_BROKER_CERTIFICATE_OVERRIDE "\n-----END CERTIFICATE-----"; +#else +extern const uint8_t mqtt_eclipseprojects_io_pem_start[] asm("_binary_mqtt_eclipseprojects_io_pem_start"); +#endif +extern const uint8_t mqtt_eclipseprojects_io_pem_end[] asm("_binary_mqtt_eclipseprojects_io_pem_end"); + +// +// Note: this function is for testing purposes only publishing part of the active partition +// (to be checked against the original binary) +// +static void send_binary(esp_mqtt_client_handle_t client) +{ + esp_partition_mmap_handle_t out_handle; + const void *binary_address; + const esp_partition_t *partition = esp_ota_get_running_partition(); + esp_partition_mmap(partition, 0, partition->size, ESP_PARTITION_MMAP_DATA, &binary_address, &out_handle); + // sending only the configured portion of the partition (if it's less than the partition size) + int binary_size = MIN(CONFIG_BROKER_BIN_SIZE_TO_SEND, partition->size); + int msg_id = esp_mqtt_client_publish(client, "/topic/binary", binary_address, binary_size, 0, 0); + ESP_LOGI(TAG, "binary sent with msg_id=%d", msg_id); +} + +/* + * @brief Event handler registered to receive MQTT events + * + * This function is called by the MQTT client event loop. + * + * @param handler_args user data registered to the event. + * @param base Event base for the handler(always MQTT Base in this example). + * @param event_id The id for the received event. + * @param event_data The data for the event, esp_mqtt_event_handle_t. + */ +static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) +{ + ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32, base, event_id); + esp_mqtt_event_handle_t event = event_data; + esp_mqtt_client_handle_t client = event->client; + int msg_id; + switch ((esp_mqtt_event_id_t)event_id) { + case MQTT_EVENT_CONNECTED: + ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); + msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + + msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + + msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1"); + ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id); + break; + case MQTT_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); + break; + + case MQTT_EVENT_SUBSCRIBED: + ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); + msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); + ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); + break; + case MQTT_EVENT_UNSUBSCRIBED: + ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); + break; + case MQTT_EVENT_PUBLISHED: + ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); + break; + case MQTT_EVENT_DATA: + ESP_LOGI(TAG, "MQTT_EVENT_DATA"); + printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); + printf("DATA=%.*s\r\n", event->data_len, event->data); + if (strncmp(event->data, "send binary please", event->data_len) == 0) { + ESP_LOGI(TAG, "Sending the binary"); + send_binary(client); + } + break; + case MQTT_EVENT_ERROR: + ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); + if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) { + ESP_LOGI(TAG, "Last error code reported from esp-tls: 0x%x", event->error_handle->esp_tls_last_esp_err); + ESP_LOGI(TAG, "Last tls stack error number: 0x%x", event->error_handle->esp_tls_stack_err); + ESP_LOGI(TAG, "Last captured errno : %d (%s)", event->error_handle->esp_transport_sock_errno, + strerror(event->error_handle->esp_transport_sock_errno)); + } else if (event->error_handle->error_type == MQTT_ERROR_TYPE_CONNECTION_REFUSED) { + ESP_LOGI(TAG, "Connection refused error: 0x%x", event->error_handle->connect_return_code); + } else { + ESP_LOGW(TAG, "Unknown error type: 0x%x", event->error_handle->error_type); + } + break; + default: + ESP_LOGI(TAG, "Other event id:%d", event->event_id); + break; + } +} + +static void mqtt_app_start(void) +{ + const esp_mqtt_client_config_t mqtt_cfg = { + .broker = { + .address.uri = CONFIG_BROKER_URI, + .verification.certificate = (const char *)mqtt_eclipseprojects_io_pem_start + }, + }; + + ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size()); + esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg); + /* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */ + esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL); + esp_mqtt_client_start(client); +} + +void app_main(void) +{ + ESP_LOGI(TAG, "[APP] Startup.."); + ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size()); + ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version()); + + esp_log_level_set("*", ESP_LOG_INFO); + esp_log_level_set("esp-tls", ESP_LOG_VERBOSE); + esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE); + esp_log_level_set("mqtt_example", ESP_LOG_VERBOSE); + esp_log_level_set("transport_base", ESP_LOG_VERBOSE); + esp_log_level_set("transport", ESP_LOG_VERBOSE); + esp_log_level_set("outbox", ESP_LOG_VERBOSE); + + ESP_ERROR_CHECK(nvs_flash_init()); + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. + * Read "Establishing Wi-Fi or Ethernet Connection" section in + * examples/protocols/README.md for more information about this function. + */ + ESP_ERROR_CHECK(example_connect()); + + mqtt_app_start(); +} diff --git a/ESP-IDF_MQQTS_v5-4/main/idf_component.yml b/ESP-IDF_MQQTS_v5-4/main/idf_component.yml new file mode 100644 index 000000000..718194867 --- /dev/null +++ b/ESP-IDF_MQQTS_v5-4/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + protocol_examples_common: + path: ${IDF_PATH}/examples/common_components/protocol_examples_common diff --git a/ESP-IDF_MQQTS_v5-4/main/mqtt_eclipseprojects_io.pem b/ESP-IDF_MQQTS_v5-4/main/mqtt_eclipseprojects_io.pem new file mode 100644 index 000000000..43b222a60 --- /dev/null +++ b/ESP-IDF_MQQTS_v5-4/main/mqtt_eclipseprojects_io.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw +WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg +RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP +R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx +sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm +NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg +Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG +/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB +Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA +FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw +AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw +Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB +gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W +PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl +ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz +CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm +lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4 +avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2 +yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O +yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids +hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+ +HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv +MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX +nLRbwHOoq7hHwg== +-----END CERTIFICATE----- diff --git a/ESP-IDF_MQQTS_v5-4/pytest_mqtt_ssl.py b/ESP-IDF_MQQTS_v5-4/pytest_mqtt_ssl.py new file mode 100644 index 000000000..c16b89cbb --- /dev/null +++ b/ESP-IDF_MQQTS_v5-4/pytest_mqtt_ssl.py @@ -0,0 +1,129 @@ +# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import logging +import os +import re +import ssl +import sys +from threading import Event, Thread + +import paho.mqtt.client as mqtt +import pexpect +import pytest +from pytest_embedded import Dut + +event_client_connected = Event() +event_stop_client = Event() +event_client_received_correct = Event() +event_client_received_binary = Event() +message_log = '' + + +# The callback for when the client receives a CONNACK response from the server. +def on_connect(client, userdata, flags, rc): # type: (mqtt.Client, str, bool, str) -> None + _ = (userdata, flags) + print('Connected with result code ' + str(rc)) + event_client_connected.set() + client.subscribe('/topic/qos0') + + +def mqtt_client_task(client): # type: (mqtt.Client) -> None + while not event_stop_client.is_set(): + client.loop() + + +# The callback for when a PUBLISH message is received from the server. +def on_message(client, userdata, msg): # type: (mqtt.Client, tuple, mqtt.client.MQTTMessage) -> None + global message_log + global event_client_received_correct + global event_client_received_binary + if msg.topic == '/topic/binary': + binary, bin_size = userdata + print('Receiving binary from esp and comparing with {}, size {}...'.format(binary, bin_size)) + with open(binary, 'rb') as f: + bin = f.read() + if bin[:bin_size] == msg.payload[:bin_size]: + print('...matches!') + event_client_received_binary.set() + return + recv_binary = binary + '.received' + with open(recv_binary, 'w') as fw: + fw.write(msg.payload) + raise ValueError('Received binary (saved as: {}) does not match the original file: {}'.format(recv_binary, binary)) + + payload = msg.payload.decode() + if not event_client_received_correct.is_set() and payload == 'data': + client.subscribe('/topic/binary') + client.publish('/topic/qos0', 'send binary please') + if msg.topic == '/topic/qos0' and payload == 'data': + event_client_received_correct.set() + message_log += 'Received data:' + msg.topic + ' ' + payload + '\n' + + +@pytest.mark.esp32 +@pytest.mark.ethernet +def test_examples_protocol_mqtt_ssl(dut): # type: (Dut) -> None + broker_url = '' + broker_port = 0 + """ + steps: + 1. join AP and connects to ssl broker + 2. Test connects a client to the same broker + 3. Test evaluates python client received correct qos0 message + 4. Test ESP32 client received correct qos0 message + 5. Test python client receives binary data from running partition and compares it with the binary + """ + binary_file = os.path.join(dut.app.binary_path, 'mqtt_ssl.bin') + bin_size = os.path.getsize(binary_file) + logging.info('[Performance][mqtt_ssl_bin_size]: %s KB', bin_size // 1024) + + # Look for host:port in sdkconfig + try: + value = re.search(r'\:\/\/([^:]+)\:([0-9]+)', dut.app.sdkconfig.get('BROKER_URI')) + assert value is not None + broker_url = value.group(1) + broker_port = int(value.group(2)) + bin_size = min(int(dut.app.sdkconfig.get('BROKER_BIN_SIZE_TO_SEND')), bin_size) + except Exception: + print('ENV_TEST_FAILURE: Cannot find broker url in sdkconfig') + raise + client = None + # 1. Test connects to a broker + try: + client = mqtt.Client() + client.on_connect = on_connect + client.on_message = on_message + client.user_data_set((binary_file, bin_size)) + client.tls_set(None, + None, + None, cert_reqs=ssl.CERT_NONE, tls_version=ssl.PROTOCOL_TLSv1_2, ciphers=None) + client.tls_insecure_set(True) + print('Connecting...') + client.connect(broker_url, broker_port, 60) + except Exception: + print('ENV_TEST_FAILURE: Unexpected error while connecting to broker {}: {}:'.format(broker_url, sys.exc_info()[0])) + raise + # Starting a py-client in a separate thread + thread1 = Thread(target=mqtt_client_task, args=(client,)) + thread1.start() + try: + print('Connecting py-client to broker {}:{}...'.format(broker_url, broker_port)) + if not event_client_connected.wait(timeout=30): + raise ValueError('ENV_TEST_FAILURE: Test script cannot connect to broker: {}'.format(broker_url)) + try: + ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=30)[0] + print('Connected to AP with IP: {}'.format(ip_address)) + except pexpect.TIMEOUT: + print('ENV_TEST_FAILURE: Cannot connect to AP') + raise + print('Checking py-client received msg published from esp...') + if not event_client_received_correct.wait(timeout=30): + raise ValueError('Wrong data received, msg log: {}'.format(message_log)) + print('Checking esp-client received msg published from py-client...') + dut.expect(r'DATA=send binary please', timeout=30) + print('Receiving binary data from running partition...') + if not event_client_received_binary.wait(timeout=30): + raise ValueError('Binary not received within timeout') + finally: + event_stop_client.set() + thread1.join() diff --git a/ESP-IDF_MQQTS_v5-4/sdkconfig.ci b/ESP-IDF_MQQTS_v5-4/sdkconfig.ci new file mode 100644 index 000000000..e8d4a52f6 --- /dev/null +++ b/ESP-IDF_MQQTS_v5-4/sdkconfig.ci @@ -0,0 +1,22 @@ +CONFIG_BROKER_URI="mqtts://${EXAMPLE_MQTT_BROKER_SSL}" +CONFIG_BROKER_CERTIFICATE_OVERRIDE="${EXAMPLE_MQTT_BROKER_CERTIFICATE}" +CONFIG_MQTT_USE_CUSTOM_CONFIG=y +CONFIG_MQTT_TCP_DEFAULT_PORT=1883 +CONFIG_MQTT_SSL_DEFAULT_PORT=8883 +CONFIG_MQTT_WS_DEFAULT_PORT=80 +CONFIG_MQTT_WSS_DEFAULT_PORT=443 +CONFIG_MQTT_BUFFER_SIZE=16384 +CONFIG_MQTT_TASK_STACK_SIZE=6144 +CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y +CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384 +CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096 +CONFIG_EXAMPLE_CONNECT_ETHERNET=y +CONFIG_EXAMPLE_CONNECT_WIFI=n +CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y +CONFIG_EXAMPLE_ETH_PHY_IP101=y +CONFIG_EXAMPLE_ETH_MDC_GPIO=23 +CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 +CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 +CONFIG_EXAMPLE_ETH_PHY_ADDR=1 +CONFIG_EXAMPLE_CONNECT_IPV6=y +CONFIG_LWIP_CHECK_THREAD_SAFETY=y