SSLClient
SSLClient copied to clipboard
Uable to connect mqtt broker
Hi, I am using A7600 with esp32 to connect AWS mqtt! But I got the error message below: [ 26256][E][ssl_client.cpp:728] perform_ssl_handshake(): mbedtls_ssl_get_record_expansion returned -0xffffffe3 [ 26263][E][ssl_client.cpp:45] _handle_error(): [start_ssl_client():353]: (29) UNKNOWN ERROR CODE (001D) [ 26264][E][SSLClient.cpp:235] connect(): start_ssl_client failed: 0
This is my code
`TinyGsmClient base_client(modem, 0); SSLClient secure_layer(&base_client); PubSubClient mqtt(secure_layer);
while (!mqtt.connect(mqttid.c_str())) { mqtt.setServer(broker, 8883); mqtt.setCallback(mqttCallback); mqtt.setKeepAlive(60); mqtt.setBufferSize(2048); Serial.println("Connecting to AWS IoT..."); Serial.println("AWS2_FreeHeap : " + String(ESP.getFreeHeap())); if (mqtt.connect(String(THINGNAME).c_str())) { Serial.println("Connected to AWS IoT!"); Serial.println("Topic:"); Serial.println(THINGNAME); } else { Serial.print("Failed to connect to AWS IoT, rc="); Serial.println(mqtt.state()); delay(2000); } }`
This is my certificate's format
Hi, I don't have the sim module you are using but if you post your full code I can try it later against my aws account.
Hi @RobertByrnes , I'm having the exact same issue.
I can get the entire pipeline to work when I'm leveraging alkonosst/SSLClientESP32, although it's incredibly slow (4s for publish, 6s for loop). But I'd like to use govorox's as it's more widely used and hopefully is faster.
I too am getting :
Initializing modem...
Modem Info: Manufacturer: SIMCOM INCORPORATED Model: SIMCOM_SIM7600G-H Revision: SIM7600G_V2.0.2 IMEI: 862636052660071 +GCAP: +CGSM
Waiting for network... Network connected
Connecting to id success
GPRS connected
GPS enabled
Connecting to AWS IOT: [ 21347][E][ssl_client.cpp:728] perform_ssl_handshake(): mbedtls_ssl_get_record_expansion returned -0xffffffe3
[ 21358][E][ssl_client.cpp:45] _handle_error(): [start_ssl_client():353]: (29) UNKNOWN ERROR CODE (001D)
[ 21358][E][SSLClient.cpp:235] connect(): start_ssl_client failed: 0
[ 33401][E][ssl_client.cpp:728] perform_ssl_handshake(): mbedtls_ssl_get_record_expansion returned -0xffffffe3
[ 33412][E][ssl_client.cpp:45] _handle_error(): [start_ssl_client():353]: (29) UNKNOWN ERROR CODE (001D)
[ 33412][E][SSLClient.cpp:235] connect(): start_ssl_client failed: 0
... still not connected
My main file is:
#include <configs/certificate.h>
// bricks
#include <bricks/SIMCOM.hpp>
// libs
#include <Arduino.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <SSLClient.h>
SSLClient secure(&SIMCOM::client);
PubSubClient pubsub(secure);
void publishMessage()
{
StaticJsonDocument<200> doc;
doc["humidity"] = "hello there!";
doc["temperature"] = 123;
char jsonBuffer[256];
serializeJson(doc, jsonBuffer); // print to pubsub
pubsub.publish(AWS_IOT_PUBLISH_TOPIC, jsonBuffer);
}
void messageHandler(char *topic, byte *payload, unsigned int length)
{
Serial.print("incoming: ");
Serial.println(topic);
StaticJsonDocument<200> doc;
deserializeJson(doc, payload);
const char *message = doc["message"];
Serial.println(message);
}
void setup()
{
Serial.begin(115200);
secure.setCACert(AWS_CERT_CA);
secure.setCertificate(AWS_CERT_CRT);
secure.setPrivateKey(AWS_CERT_PRIVATE);
Serial.println("Started...");
SIMCOM::init();
// Connect to the MQTT broker on the AWS endpoint we defined earlier
pubsub.setServer(AWS_IOT_ENDPOINT, 8883);
// Create a message handler
pubsub.setCallback(messageHandler);
Serial.print("Connecting to AWS IOT: ");
if (pubsub.connect(THINGNAME)) {
// Subscribe to a topic
Serial.println("AWS IoT Connected!");
} else {
while (!pubsub.connected()) {
pubsub.connect(THINGNAME);
Serial.println("... still not connected");
}
}
pubsub.subscribe(AWS_IOT_SUBSCRIBE_TOPIC, MQTTQOS1);
}
void loop()
{
publishMessage();
pubsub.loop();
delay(1000);
}
and, yep this works with alkonosst/SSLClientESP32, so I know the URL, port, and certs are okay... Certs are in the format of:
static const char AWS_CERT_CA[] PROGMEM =
"-----BEGIN CERTIFICATE-----\r\n"
"MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF\r\n"
...
"-----END CERTIFICATE-----\r\n";
static const char AWS_CERT_CRT[] PROGMEM =
"-----BEGIN CERTIFICATE-----""\n"
"MIIDWjCCAkKgAwIBAgIVAKPQbOtfpI4/8pcCYPJVZ8/pN2zSMA0GCSqGSIb3DQEB""\n"
...
"-----END CERTIFICATE-----";
static const char AWS_CERT_PRIVATE[] PROGMEM =
"-----BEGIN RSA PRIVATE KEY-----""\n"
"MIIEpgIBAAKCAQEA10ESwd+HUTP8y1aQVcApc4Bjk9DQ+UejnNMrqtfZD5zoDKKI""\n"
...
"-----END RSA PRIVATE KEY-----";
My SIMCOM init is just a wrapper around the normal SIMCOM initializers (I'm using TinyGSM on a SIM7600G)
...
TinyGsm modem(SerialAT);
TinyGsmClient client(modem, 0);
...
/**
* @brief Initialize the SIMCOM module against the configs, and connect to network.
*
* @returns true if successful, otherwise false
*/
bool init()
{
SerialAT.begin(AT_BAUD, SERIAL_8N1, UART_RX, UART_TX);
delay(6000);
// This can take quite some time
Serial.println("Initializing modem... ");
while (!modem.init())
{
}
String modemInfo = modem.getModemInfo();
Serial.print("Modem Info: ");
Serial.println(modemInfo);
Serial.print("Waiting for network... ");
if (!modem.waitForNetwork())
{
Serial.println(" fail");
return false;
}
if (modem.isNetworkConnected())
{
Serial.println("Network connected");
}
// Enable full functionality
modem.setPhoneFunctionality(1);
// Turn on the GPRS
Serial.print(F("Connecting to "));
Serial.print(APN_4G);
if (!modem.gprsConnect(APN_4G))
{
Serial.println(" fail");
return false;
}
Serial.println(" success");
if (modem.isGprsConnected())
{
Serial.println("GPRS connected");
}
// Update the internal clock (good for SSL)
modem.NTPServerSync();
// Turn on the GPS
modem.disableGPS();
delay(500);
if (modem.enableGPS())
{
Serial.println("GPS enabled");
}
return true;
}
Have you got any ideas? I was also trying to build a TinyGsmClientSecure client for SIM7600G in TinyGsm, but I was getting a few errors on MQTT (worked wonderfully on HTTPS), so I thought I'd try an SSL layer first instead...
Edit: I'm on an ESP32 S3 R3 (the Pico ESP32 board from Waveshare. This has worked wonders for a range of https related stuff with tinygsm+sim7600!)
So I'm not completely alone in experiencing literally the exact same error as posted in the very beginning of this issue, namely:
[ 6623][V][ssl_client.cpp:722] perform_ssl_handshake(): Protocol is TLSv1.2 Ciphersuite is TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384
[ 6634][E][ssl_client.cpp:728] perform_ssl_handshake(): mbedtls_ssl_get_record_expansion returned -0xffffffe3
....a lot of connection closing messages...
[ 6737][E][ssl_client.cpp:45] _handle_error(): [start_ssl_client():353]: (29) UNKNOWN ERROR CODE (001D)
[ 6746][V][SSLClient.cpp:232] connect(): Return value from start_ssl_client: 0
[ 6753][E][SSLClient.cpp:235] connect(): start_ssl_client failed: 0
[ 6759][D][SSLClient.cpp:90] stop(): Stopping ssl client
It appears to be directly caused by use of a client certificate/key, as the server logs indicate the SSL CA is complete by this point. Heck, the function failing is literally the one that uses the client cert/key! https://github.com/govorox/SSLClient/blob/eee87188d2a63f115681c836083d4cbc9f45e76d/src/ssl_client.cpp#L691-L735
It fails on both WiFiClient and TinyGsmClient (as I've made my code able to switch between the two at will) exactly the same.
So far, ArduinoBearSSL also fails.
And yes, after running dangerously low on hair, I did finally try SSLClientESP32 whose successful connection was the most beautiful sight I've seen in over two weeks at this point. I literally just imported the library, changed the #include and the define, and compiled the project--to success.
I don't understand the difference, as the SSLClientESP32 repo was forked from SSLClient here. Both use mbedTLS under the hood.
The only potential clue I see is the commonality with the only other SSL library that has worked: the default WiFiClientSecure on the Arduino-ESP32 core. Apart from both using mbedTLS, both also come with certificate packs. I sincerely hope there isn't anything to that--because if so, then the certs we provide are being ignored or are insufficient in some way. I shall have to disable the cert packs in that library and see if success turns into failure. For science.
Whoa, wait a minute....!
A significant amount of code is missing in the above "perform_ssl_handshake" routine. Notice the "cli_cert" and "cli_key" parameters? Apart from a null-check at line 721, they are not used anywhere in the routine! https://github.com/govorox/SSLClient/blob/eee87188d2a63f115681c836083d4cbc9f45e76d/src/ssl_client.cpp#L721
In the (working) SSLClientESP32, there are numerous search results for "cli_cert", including mbedTLS conversion and processing routines, as seen here:
https://github.com/alkonosst/SSLClientESP32/blob/7906f386a8f7db88ae89824c1fe058cef62869e2/src/ssl_lib_client.cpp#L256-L278
I have to conclude that the client cert/key functionality was never tested here with SSLClient; the code here required to support said functionality is completely missing!
OK, so looking closer...maybe everything's not missing. The client cert/key conversion routines are further up, and present: https://github.com/govorox/SSLClient/blob/eee87188d2a63f115681c836083d4cbc9f45e76d/src/ssl_client.cpp#L539-L567
But something else is missing/wrong, as the SSLClientESP32 uses the same "mbedtls_ssl_get_record_expansion" call that fails here in SSLClient--but it doesn't fail there. And the "perform_ssl_handshake" is apparently only using the "cli_cert" and "cli_key" to indicate whether they were used? It doesn't make any sense; SSLClientESP32 uses flags for this (to determine whether to free the memory consumed by converting the certs).
I'm not much help with this SSL stuff--it's gargantuan complicated. But something's definitely wrong here.
@Matt-Stedman-HardStuff
I can get the entire pipeline to work when I'm leveraging alkonosst/SSLClientESP32, although it's incredibly slow (4s for publish, 6s for loop). But I'd like to use govorox's as it's more widely used and hopefully is faster.
I am suspecting part of the problem here to be how the libraries interact with each other. I'm similarly stacking an SSLClient on top of TinyGSM, but utilizing the StreamDebugger to see what's going on. For whatever reason, all of the SSL libraries I've thus far tried read data from the modem through an eyedropper--almost literally. Regardless of the amount of data available to read from the modem (i.e. 1460 bytes), they read it 63 bytes at a time, incurring a horrendous speed penalty by way of the transport methodology.
I'm running the modem serial at 115200, but the above problem results in molasses speeds. (Just to read the SSL handshake in takes ~30 seconds, and then the server times out and closes the connection.) Gonna have to figure out where this nonsensical bottleneck is, and fix it...! Over WiFi, the SSL handshake takes ~2 seconds with SSLClientESP32.
Oh, and a size comparison...SSLClientESP32 is definitely the biggest of all of the ones so far. Size of compressed firmware with the entire rest of my application stack in it, so the size is not as important as the difference:
- ~550KB: no SSL Stack
- 647.3KB: ArduinoBearSSL
- 650.6KB: WiFiClientSecure (NOT usable with TinyGSM)
- 661.2KB: SSLClientESP32
@WebDust21 @TONYCHOU81905 @Matt-Stedman-HardStuff - digitaldragon/[email protected]
works for me, and it also fixed a buffer issue that was present in previous versions.
@RobertByrnes - I get the same issue as above for digitaldragon/[email protected]
[ 33274][E][ssl_client.cpp:728] perform_ssl_handshake(): mbedtls_ssl_get_record_expansion returned -0xffffffe3
[ 33282][E][ssl_client.cpp:45] _handle_error(): [start_ssl_client():353]: (29) UNKNOWN ERROR CODE (001D)
[ 33282][E][SSLClient.cpp:235] connect(): start_ssl_client failed: 0
@WebDust21 - I use this library with AWS IoT and TinyGSM as it was the least painful one. I haven't tested the speed though as I'm only using this for low speed IoT communications
@WebDust21 - I use this library with AWS IoT and TinyGSM as it was the least painful one. I haven't tested the speed though as I'm only using this for low speed IoT communications
My findings with alkonosst/SSLClientESP32@^2.0.3: it actually leverages the mbedTLS implementation provided in the Arduino-ESP32 core, instead of bringing an entirely separate one in. That ends up not helping the total binary size, as it's still the largest of all of the available options...but it's the simplest wrapper.
The main huge speed bottleneck I encountered (initial testing was >30 seconds for SSL handshake--which would fail because the server would abort the connection) was due to the default TinyGSM buffer size of 64 bytes. When you're transferring 4KB+ for the SSL handshake, it takes an extremely long time to do it 63 bytes at a time.
After setting the TinyGSM default buffer to 1436 bytes (i.e. a typical MTU) with
-DTINY_GSM_RX_BUFFER=1436
...I promptly ran into another issue: the default Arduino-ESP32 serial FIFO buffer size of 256 bytes, resulting in most of the data being lost. (Plus a TinyGSM bug that would cause it to wait for nonexistent data for close to 2 minutes at a time.) Setting the serial FIFO buffer size to 1436 bytes * 1.2 (for some extra headroom)...
Serial.setRxBufferSize(TINY_GSM_RX_BUFFER * 1.2);
...solved the issue; now the SSL handshake takes ~5 seconds tops.
@deeja Very good info to know...now I want to diff the two versions and see what changed to break it!
This is great info in this thread! Haven't had a lot of time recently but feeling a pulling it all together update very soon.
Please consider adding PR for any changes - even if it is just in the README.md to document best practice based on your findings.
Cheers....
@deeja @WebDust21 @TONYCHOU81905 @Matt-Stedman-HardStuff
@WebDust21 Fair enough. This is roughly how I wrapped my call.
#define TINY_GSM_RX_BUFFER 1024
TinyGsmClient networkClient(modem);
SSLClient sslClient(&networkClient);
PubSubClient mqttClient(AWS_IOT_ENDPOINT, AWS_IOT_PORT, provisionCallback, &sslClient, Serial);
// Wrapper
SSLClient sslClient(&networkClient);
sslClient->setCACert(AWS_CA_CERTIFICATE);
sslClient->setCertificate(AWS_CERTIFICATE);
sslClient->setPrivateKey(AWS_PRIVATEKEY);
Interestingly I am getting this in 1.1.16 but the connection still works :
[ 29129][E][ssl_client.cpp:431] start_ssl_client(): mbedtls_ssl_get_record_expansion returned -0xffffffe3
[ 29129][I][SSLClient.cpp:241] connect(): SSL connection established
Just a note to everyone that might be trying to get SSL working via a SIM7600 and leveraging TinyGSM, @floBik and I (though mostly @floBik) managed to leverage the SIM7600's in-built SSL functionality, which seems to work for HTTPS and MQTTS.
Currently the PR is still awaiting approval, but you can reference or fork via https://github.com/Matt-Stedman-HardStuff/TinyGSM
This means you can use the SIMCOM module and SSL without needing this govorox/SSLClient (sorry @govorox 😂)
@Matt-Stedman-HardStuff - I'll keep an eye on that PR
Just a note to everyone that might be trying to get SSL working via a SIM7600 and leveraging TinyGSM, @floBik and I (though mostly @floBik) managed to leverage the SIM7600's in-built SSL functionality, which seems to work for HTTPS and MQTTS.
Currently the PR is still awaiting approval, but you can reference or fork via https://github.com/Matt-Stedman-HardStuff/TinyGSM
This means you can use the SIMCOM module and SSL without needing this govorox/SSLClient (sorry @govorox 😂)
Problem for me is that the SIM7080 modules I have, cannot successfully complete an SSL connection over either SSL TCP or MQTT. (The latter is unsurprising, as it runs over a TCP connection.) I'm also using TinyGSM--but I've also pulled it into the project as a direct import, and have made quite a few modifications to TinyGSM. (Including other modifications, I cobbled in client cert/key functionality.) The modem's SSL functionality works to a part, as it is is able to connect to "easy" servers (with client cert/key), but not the one server I need it to. (Which most ESP32 SSL libraries fail to connect to as well.)
https://github.com/govorox/SSLClient/pull/78 @deeja @WebDust21 @TONYCHOU81905 Please see this PR and the comments in issue #71 This may now be fixed
closed as solved by v1.2.0