TLS handshake failing for MQTTS in QEMU

sgmustadio
Posts: 7
Joined: Thu Mar 04, 2021 4:33 am

TLS handshake failing for MQTTS in QEMU

Postby sgmustadio » Fri Feb 21, 2025 12:01 am

I've got a Docker container running ESP-IDF (for development) along with a Mosquitto server for testing MQTT messaging. I can successfully connect and pub/sub to the Mosquitto broker with open MQTT (non-TLS) in QEMU as well as on a physical device. My full application can be found here: https://github.com/ShawnHymel/course-io ... ain/main.c

Here is my code for connecting over TCP on my physical device. The hostname is the IP address of my computer on my local network. This works.

Code: Select all

    esp_mqtt_client_config_t mqtt_cfg = {
        .broker.address.hostname = "<MY LOCAL IP ADDRESS>",
        .broker.address.transport = MQTT_TRANSPORT_OVER_TCP,
        .broker.address.port = 1883,
        .credentials.username = "iot",
        .credentials.authentication.password = "mosquitto"
    };

    // Initialize MQTT client
    esp_mqtt_client_handle_t mqtt_client = esp_mqtt_client_init(&mqtt_cfg);

    // Register event handler
    esp_ret = esp_mqtt_client_register_event(mqtt_client,
                                             ESP_EVENT_ANY_ID, 
                                             mqtt_event_handler, 
                                             NULL);
    if (esp_ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to register MQTT event handler (%d)", esp_ret);
        ESP_ERROR_CHECK(esp_mqtt_client_destroy(mqtt_client));
        abort();
    }

    // Start MQTT client
    esp_ret = esp_mqtt_client_start(mqtt_client);
    if (esp_ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to start MQTT client (%d)", esp_ret);
        ESP_ERROR_CHECK(esp_mqtt_client_destroy(mqtt_client));
        abort();
    }
   
   ...
Here is the esp_mqtt config for connecting over TCP in QEMU. This works.

Code: Select all

    esp_mqtt_client_config_t mqtt_cfg = {
        .broker.address.hostname = "10.0.2.2",
        .broker.address.transport = MQTT_TRANSPORT_OVER_TCP,
        .broker.address.port = 1883,
        .credentials.username = "iot",
        .credentials.authentication.password = "mosquitto"
    };
Here is the esp_mqtt config for connecting over SSL/TLS on the physical ESP32. This works.

Code: Select all

    esp_mqtt_client_config_t mqtt_cfg = {
        .broker.address.hostname = "<MY LOCAL IP ADDRESS>",
        .broker.address.transport = MQTT_TRANSPORT_OVER_SSL,
        .broker.address.port = 8883,
        .broker.verification.use_global_ca_store = false,
        .broker.verification.certificate = (const char *)mqtt_ca_cert_start,
        .broker.verification.certificate_len = mqtt_ca_cert_end - mqtt_ca_cert_start,
        .broker.verification.skip_cert_common_name_check = false,
        .broker.verification.common_name = "localhost",
        .credentials.username = "iot",
        .credentials.authentication.password = "mosquitto",
    };

Here is the esp_mqtt config for connecting over SSL/TLS in QEMU. This does NOT work.

Code: Select all

    esp_mqtt_client_config_t mqtt_cfg = {
        .broker.address.hostname = "10.0.2.2",
        .broker.address.transport = MQTT_TRANSPORT_OVER_SSL,
        .broker.address.port = 8883,
        .broker.verification.use_global_ca_store = false,
        .broker.verification.certificate = (const char *)mqtt_ca_cert_start,
        .broker.verification.certificate_len = mqtt_ca_cert_end - mqtt_ca_cert_start,
        .broker.verification.skip_cert_common_name_check = false,
        .broker.verification.common_name = "localhost",
        .credentials.username = "iot",
        .credentials.authentication.password = "mosquitto",
    };

With mbedTLS logging on verbose, here is what I see in the terminal:

Code: Select all

I (2245) mqtts_demo: Starting MQTT demo
I (2265) eth_qemu: Starting Ethernet...
I (2295) esp_eth.netif.netif_glue: 00:00:00:00:00:03
I (2295) esp_eth.netif.netif_glue: ethernet attached to netif
I (2395) network_wrapper: Waiting for WiFi to connect...
I (2395) eth_qemu: Ethernet started
I (2405) eth_qemu: Ethernet link up
I (2405) eth_qemu: Ethernet MAC address: 00:00:00:00:00:03
I (2405) network_wrapper: Connected to WiFi
I (2405) network_wrapper: Waiting for IP address...
I (3405) esp_netif_handlers: eth ip: 10.0.2.15, mask: 255.255.255.0, gw: 10.0.2.2
I (3405) eth_qemu: Ethernet IPv4 address obtained
I (3405) eth_qemu:   IP address: 10.0.2.15
I (3405) eth_qemu:   Netmask: 255.255.255.0
I (3405) eth_qemu:   Gateway: 10.0.2.2
I (12405) network_wrapper: Connected to IPv4 network
I (12405) mqtts_demo: Connecting to MQTT broker...
I (12455) mbedtls: ssl_tls.c:4606 => handshake

I (12455) mbedtls: ssl_msg.c:2353 => flush output

I (12455) mbedtls: ssl_msg.c:2362 <= flush output

I (12465) mbedtls: ssl_tls.c:4525 client state: MBEDTLS_SSL_HELLO_REQUEST

I (12465) mbedtls: ssl_msg.c:2353 => flush output

I (12465) mbedtls: ssl_msg.c:2362 <= flush output

I (12465) mbedtls: ssl_tls.c:4525 client state: MBEDTLS_SSL_CLIENT_HELLO

I (12465) mbedtls: ssl_client.c:919 => write client hello

--- Error: read failed: socket disconnected
--- Waiting for the device to reconnect................................
Even though the handshake succeeds in the real device, it gets to "write client hello" and then disconnects for some reason in QEMU. Does anyone have any clue as to why this is happening?

sgmustadio
Posts: 7
Joined: Thu Mar 04, 2021 4:33 am

Re: TLS handshake failing for MQTTS in QEMU

Postby sgmustadio » Sat Feb 22, 2025 2:59 am

After some tinkering, I believe this to be a bug within the ESP-IDF framework. The code runs fine if the target is set to ESP32 or ESP32C3, but it fails (as above) for the ESP32S3. I filed an issue here: https://github.com/espressif/esp-idf/issues/15446

Who is online

Users browsing this forum: dizcza, ESP_Roland and 86 guests