MQTT-TLS could use Amazon IoT

Perfect, thanks @hirotakaster, as you indicated there was a policy missing in my ARN rule. I tried to manually add it but ended up having to provisioning a new IoT object from AWS console for some reason. But now this is working.

For those who might find themselves in a similar position…


Your certificate must be attached to both a thing and a policy. The AWS IoT Onboard -> Configuring a Device wizard should do this for you:

@hirotakaster I’m using Google IoT Core for MQTT data collection with other hardware at the moment. I believe it’s out of beta now and generally available. If I can offer any help in testing on the platform I’d be happy to do so. I’m not sure the authentication method is as simple as AWS though… I intend to dig into it a bit deeper over the next month or so.

1 Like

@hirotakaster Thanks for this amazing library.

I wanted to know what exactly is “sparkclient”. We have this line in the code
// connect to the server
client.connect(“sparkclient”);

I guess the usual syntax is something like
client.connect(clientID,mqttUserName,mqttPass)

Any help regarding this will be very helpful.

Edit:
I just changed the “sparkclient” to something random and it works.
So does this mean userid is of no use in this case because the connection is already established through TLS?

Sorry I am very new to the IoT world and trying to understand how protocols, communication and TLS layer works. Added to this it would be great if someone could explain what the difference the MQTT library and MQTT-TLS library? Do they both have different kind of authentication?
Thanks

@hirotakaster @ian.c Any successful results with Google IoT core? I am currently stuck at JWT creation. Is there any library you all used for JWT creation (RSA256)?

@controlsgeek ,
That’s right,
client.connect(“sparkclient”);
same mean to
client.connect(clientID,mqttUserName,mqttPass)
I think it’s better that clientID is origined of MAC Address, because of MAC address could use for unique ID.

MQTT library is very simple size non-TLS MQTT library, MQTT-TLS could use both of non-TLS/TLS with same authentications.
sorry I don’t have Google IoT Core platform account.

Thanks @hirotakaster
I am also going to try and connect to Siemens Mindsphere. I will keep the post updated with the updates.

I’ve put the Google MQTT integration on the back burner for now. May bring it back at some point but for the time being I worked around by packetizing all my data and sending it through the current Particle-Google PubSub integration then rebuilding it on the cloud side. Not optimal, but enough for my current stage.

@hirotakaster Hi I am just getting started with using this Library on Electron with 0.8.0-rc7 firmware and I wanted to ask a question for some clarity.

I am using your standard MQTT library at the minute and I do not connect to the particle cloud, so I am running:

SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(SEMI_AUTOMATIC);

Cellular.connect();

/** Wait for connected **/
if (!waitFor(Cellular.ready, 60000))
{
    Serial.printf("Cellular not ready, reset\r\n");
    System.reset();
}

/** MQTT Setup **/
client.connect("sparkclient_");

if(!waitFor(client.isConnected, 20000))
{
    Serial.printf("MQTT Client not connected, reset\r\n");
    System.reset();
}

I can publish fine, everything works!

So - I noticed the time-sync in the examples you provide in the TLS Library and I wonder how this is used under the hood? As I do not connect to the particle cloud, I was looking for other options and I spotted @bko’s SparkTimer library but this seems to sync an SparkTime object which I am assuming can’t be fed into your MQTT-TLS library?

Do you (or anyone) know how I can sync the electron properly without particle cloud so that this library will work properly?

60 seconds might be too short for a successful connect. In low signal areas you should allow for up to 300 seconds.

About the time syncing. You can feed any UNIX epoch timestamp (irrespective of origin - e.g. SparkTime::now()) into the RTC of the device via Time.setTime().
But what's the reason behind the refusal to just connect to the Particle cloud once a day (or whatever accuracy you need) just for that till you get a Time.isValid() and then cut the cloud connection again?

3 Likes

Completely agree @ScruffR.

I was originally in automatic mode then when I started using the MQTT library, I saw the electron get to the flashing cyan stage and then never progress my loop. I went to semi automatic with the above code and it works fine on pulsing green so I stopped.

I have some time today so am going to look into it some more to see why it was not fully connecting to Particle Cloud - I’ll try the manual connect now I am in semi mode.

Thanks for the replies!

2 Likes

Is anyone else having a problem compiling the sample?

When I create a blank project, I paste in the code from example 2, then I update the cert/key strings and try to compile. However, I get an error:

It appears that I’m missing a library.

The only #include in the program (that I pasted in) is “#include <MQTT-TLS.h>”

Here’s the rest of the declaration:

43%20PM

Any ideas? It’s gotta be something easy… :angry:

clear cache and compile again.

Thank you Hirotaka.

I cleared cache - no luck. I actually deleted the sketch and created a new one, again using the code from example 2, and then adding the MQTT-TLS library. No luck.

I’m using the Web IDE with Chrome (updated) on an iMac with Mojave (10.14).

At this point, I’m just using “verify” to compile the code.

I added “#include <TlsTcpClient.h>” above the MQTT-tls include, and then got a different error (multiple definitions).

So, I removed the TlsTcpClient include and then the compiler provided the same “undefined reference to TCPClient” error.

I’ve been clearing the cache from the IDE, then also from Chrome. This did not affect the error.

ugh!

other community library could compile on your environment?

If you hit the SHOW RAW button at the bottom of the error list, you may get a more elaborate info about the reasons for these errors.
If you have a multiple definition message, you should get some indication where the two (or more) conflicting definitions are located.

It might be that you have two versions of the library in your project (e.g. as separate file tabs and imported via the library manager).
Or you have some other library importet that happens to also define these objects.

Also what platform and OS version are you targeting?

ok - I think you’re on to something.

The only devices I have claimed are Core and Xenons. I actually don’t have a Photon.

I’ve been trying to compile with a Xenon set. When I switch to a Core, then the error I get is different:

I suppose the library is specific to the Photon? (but GitHub says it was also for the Core. Maybe a revision has made it incompatible with the Core?)

I’ve tried a couple other community libraries. TlsTcpClient gives me the same problems. The Ubidots example works. I tried CommTCP example and that works on both Core and Xenon.

Here’s a link to the project: https://go.particle.io/shared_apps/5bc8a3a61f66363507001e98

(I’ve removed my certificate and private key - we just need to get it to compile)

ok - closing the loop, I just activated a Photon and was able to compile the program.

I switched to a Core and I received the compile error (see above message).

But, I switched back to a Xenon and it compiled!! I’m now curious if it actually would work. Apparently Particle was making some library updates now that the Xenon has moved to shipping / released status.

TLDR: If I do NOT use SYSTEM THREAD I can declare certificates as either “char*” or “const char*”. If I DO use SYSTEM THREAD I can only declare certificates as “const char*”

I am trying to use the library for AWS IOT, and am having difficulty connecting depending on the way I initialize my certificates when in threaded operation.

My code is roughly like the following:

SYSTEM_THREAD(ENABLED);

// aws iot root ca...

#define CLIENT_KEY_CRT_PEM                                              \
"-----BEGIN CERTIFICATE----- \r\n"                                      \
cert stuff.....
"-----END CERTIFICATE-----"
char clientKeyCrtPem[] = CLIENT_KEY_CRT_PEM;    // does NOT work
// const char clientKeyCrtPem[] = CLIENT_KEY_CRT_PEM;    // does work
// String clientKeyCrtPem_str = String(CLIENT_KEY_CRT_PEM);   // does NOT work

#define CLIENT_KEY_PEM                                                  \
"-----BEGIN RSA PRIVATE KEY-----\r\n"                                   \
cert stuff.....
"-----END RSA PRIVATE KEY-----"
char clientKeyPem[] = CLIENT_KEY_PEM;    // does NOT work
// const char clientKeyPem[] = CLIENT_KEY_PEM;   // does work
// String clientKeyPem_str = String(CLIENT_KEY_PEM);  // does NOT work

setup() {
     // other stuff
     client.enableTls(amazonIoTRootCaPem, sizeof(amazonIoTRootCaPem),
                      clientKeyCrtPem, sizeof(clientKeyCrtPem),
                      clientKeyPem, sizeof(clientKeyPem));
}

loop() {
     if (!client.isConnected()) {
          client.connect(my_id);
    }
     // other code....
}

I need to be able to ultimately load certificates from external memory, so I can’t declare them as a global const char array. When I use a non-const char array, I cannot complete the TLS handshake if I am also using SYSTEM THREAD ENABLED. When I use the const char array everything works fine regardless of threading.

Any thoughts on what is going on? I could understand if it just didn’t work in threaded operation, but the const - not const difference has my head spinning.

The most probable reason I'd see for that behaviour may be memory constraints due to extra demand for multi threading leaving too little space for a RAM based certificate (or rather the cert taking too much away from other tasks).

If you compare the memory usage summary of the build process and System.freeMemory() output between the two scenarios you may be able to see the impact of SYSTEM_THREAD(ENABLED) and judge if this can be the cause or not.

2 Likes

TLDR: It’s a problem with overall RAM usage, MQTT-TLS requires minimum 35KB of available RAM to function normally during connection.

Yeah good call, it does seem like that is the case, here are the logs for memory use across a bunch of scenarios. Not about SYSTEM_THREAD, just about the RAM usage.

All with char* certificates (not const char*), so stored in RAM:

SYSTEM_THREAD(DISABLED):

SystemFreeMemory before client.enableTls: 59672
SystemFreeMemory after client.enableTls: 38032
SystemFreeMemory before client.connect: 37976
SystemFreeMemory after client.connect: 31296
WARNING | 18295 | 1542296283 | MQTT Successfully Reconnected

SYSTEM_THREAD(ENABLED), but with a bunch of buffers commented out, no threads created:

SystemFreeMemory before client.enableTls: 54920
SystemFreeMemory after client.enableTls: 33272
SystemFreeMemory before client.connect: 33224
SystemFreeMemory after client.connect: 26512
WARNING | 18295 | 1542296032 | MQTT Successfully Reconnected

SYSTEM_THREAD(ENABLED), with all my normal buffers, no threads created:

SystemFreeMemory before client.enableTls: 48664
SystemFreeMemory after client.enableTls: 27024
SystemFreeMemory before client.connect: 26976
SystemFreeMemory after client.connect: 20408
WARNING | 18295 | 1542296521 | MQTT Successfully Reconnected

SYSTEM_THREAD(ENABLED), with all my normal buffers, 3 threads created:

SystemFreeMemory before client.enableTls: 38096
SystemFreeMemory after client.enableTls: 16456
SystemFreeMemory before client.connect: 16392
SystemFreeMemory after client.connect: 36672
ERROR | 15674 | 1542295991 | MQTT Reconnection Unsuccessful

Digging into the library, here is the memory for different steps of the (unsuccessful) ssl handshake:

DEBUG | 3168 | 1542296885 | Connecting to network...
DEBUG | 4168 | 1542296886 | Connected to network
DEBUG | 5168 | 1542296888 | Connecting to Particle Cloud...
DEBUG | 6168 | 1542296889 | Connected to Particle Cloud
DEBUG | 10070 | 1542296893 | Initializing SD Card...
DEBUG | 10090 | 1542296893 | SD Card Detected
DEBUG | 10090 | 1542296893 | Starting SDcardProcessingThread...
DEBUG | 10091 | 1542296893 | Starting CANbusProcessing input thread...
DEBUG | 10091 | 1542296893 | Beginning CAN Bus...
CAN | Beginning NodeID Scan...
RESET | 10093 | 1542296893 | Last reset with system code: (0) Information is not available
SystemFreeMemory before client.enableTls: 38088
SystemFreeMemory after client.enableTls: 16448
DEBUG | 10268 | 1542296893 | Connection regained, attempting to reconnect to MQTT
SystemFreeMemory before client.connect: 16384
CAN | NodeID Scan Complete.  Discovered NodeIDs:
CAN | No Nodes Discovered
SystemFreeMemory for ssl->state 0: 16320
SystemFreeMemory for ssl->state 1: 16320
SystemFreeMemory for ssl->state 2: 16320
...(repeat x12)...
SystemFreeMemory for ssl->state 2: 16320
SystemFreeMemory for ssl->state 3: 16320
SystemFreeMemory for ssl->state 4: 6280
SystemFreeMemory for ssl->state 5: 6280
SystemFreeMemory for ssl->state 6: 6280
SystemFreeMemory for ssl->state 7: 6280
SystemFreeMemory for ssl->state 8: 6280
SystemFreeMemory for ssl->state 9: 5744
SystemFreeMemory for ssl->state 9: 9192
SystemFreeMemory after client.connect: 36664
WARNING | 15350 | 1542296898 |  TIMING |  checkConnection: client.connect() took 5081ms
ERROR | 15351 | 1542296898 | MQTT Reconnection Unsuccessful
DEBUG | 15354 | 1542296898 | System free memory is: 36632
DEBUG | 15381 | 1542296898 | Connection regained, attempting to reconnect to MQTT
SystemFreeMemory before client.connect: 36664

Here is the freeMemory output for a (successful) ssl handshake:

DEBUG | 3168 | 1542297193 | Connecting to network...
DEBUG | 4168 | 1542297194 | Connected to network
DEBUG | 5168 | 1542297195 | Connecting to Particle Cloud...
DEBUG | 7168 | 1542297197 | Connected to Particle Cloud
RESET | 10070 | 1542297200 | Last reset with system code: (0) Information is not available
WARNING | 10071 | 1542297200 | SD Card not detected or not functioning, using RAM buffer only
SystemFreeMemory before client.enableTls: 48784
SystemFreeMemory after client.enableTls: 27144
DEBUG | 10237 | 1542297200 | Connection regained, attempting to reconnect to MQTT
SystemFreeMemory before client.connect: 27080
SystemFreeMemory for ssl->state 0: 27024
SystemFreeMemory for ssl->state 1: 27024
SystemFreeMemory for ssl->state 2: 27024
...(repeat x12)...
SystemFreeMemory for ssl->state 2: 27024
SystemFreeMemory for ssl->state 3: 27024
SystemFreeMemory for ssl->state 4: 17000
SystemFreeMemory for ssl->state 5: 17000
SystemFreeMemory for ssl->state 6: 17000
SystemFreeMemory for ssl->state 7: 17000
SystemFreeMemory for ssl->state 8: 17000
SystemFreeMemory for ssl->state 9: 16464
SystemFreeMemory for ssl->state 10: 13472
SystemFreeMemory for ssl->state 11: 13472
SystemFreeMemory for ssl->state 12: 13472
...(repeat x12)...
SystemFreeMemory for ssl->state 12: 13472
SystemFreeMemory for ssl->state 13: 13472
SystemFreeMemory for ssl->state 14: 13472
SystemFreeMemory for ssl->state 15: 13472
SystemFreeMemory after client.connect: 20432
WARNING | 18421 | 1542297208 |  TIMING |  checkConnection: client.connect() took 8183ms
WARNING | 18432 | 1542297208 | MQTT Successfully Reconnected
DEBUG | 18435 | 1542297208 | System free memory is: 20392
WARNING | 18696 | 1542297209 | MQTT reconnected, was disconnected for: 8.384000 seconds; signal RSSI: -75dB; Qual: 19/49
DEBUG | 18697 | 1542297209 | Beginning one-time initialization for MQTT network functionality
DEBUG | 19147 | 1542297209 | Going to OPERATIONAL state...
DEBUG | 19147 | 1542297209 | New publishing state: 1 from state: 0
DEBUG | 33645 | 1542297224 | System free memory is: 20392

So essentially from before TLS is enabled to a successful connection you need a minimum of 35KB free RAM, plus a margin of at least 10KB extra, at the very minimum. So looks like I should be shooting for 45KB free RAM minimum prior to starting MQTT. Without TLS it only takes up around 7KB of runtime RAM (for my max packet size). That’s a ton of extra memory, but I suppose it goes with the territory for TLS. Hopefully this helps other folks plan when using this library.

Looks like I’ll just have to really tighten up my RAM usage in other parts of my code in order to have confidence in being able to consistently connect.

1 Like

I believe the MQTT-TLS as it is now uses MBEDTLS 2.07 which uses a 16kByte input and output buffer. With MBEDTLS 2.12 you have the option to set the size of these buffers independently. Getting MQTT-TLS to use this later version of MBEDTLS is not too difficult and allows for a smaller footprint though it still requires good RAM pruning skills elsewhere in your app.

MBEDTLS 2.12: https://github.com/ARMmbed/mbedtls