Accessing Pelion Device Cloud via a NB-IoT cellular modem

01 Apr 2019

I have an U-blox Sara N2 NB-IoT cellular modem connected with a ST Nucleo F207ZG dev board via UART. There is a limitation of 512 bytes per transmit when using the embedded UDP-stack in the modem. Both my DTLS client and the Pelion server support the SSL extension max_fragment_length and this is enabled in the client and presented to the server during the "client hello" handshake stage. The SSL handshake gets as far as the server-originated change cipher spec. but fails due to the outgoing message size being too large for the modem UDP-send command.

Am I wasting my time trying to get certificate-based SSL handshaking to work on such a constrained device, and should I be looking at PSK exchange instead? If anyone has successfully implemented certificate-based exchange in such a constrained setup I ask that they get in touch. ie. what mbedTLS configuration should I be using? I am currently using mbed OS 5.11.

03 Apr 2019

Hi Lindsay,

thanks for your question!

there is a slight mismatch between what you try to achieve and what the MaxFragmentLength (MFL) extension guarantees: If I understand you correctly, you need to ensure that the UDP payload of UDP datagrams doesn't exceed 512 Bytes, while the MFL extension only guarantees that the DTLS payload isn't larger than 512 Bytes. Due to the additional overhead of DTLS headers and encryption, an MFL of 512 Bytes can therefore still lead to datagrams of size > 512 Bytes (realistically: 560 Bytes) being generated.

What you should use instead is mbedtls_ssl_set_mtu(), which informs Mbed TLS about the MTU of the underlying transport. If you configure an MTU of 512 Bytes here, Mbed TLS will incorporate record expansion to make sure that it only uses as much DTLS payload to ensure that the total datagram size doesn't exceed 512 Bytes.

The point of failure you describe is still puzzling, though: Is the CRT you're sending smaller than 512 Bytes, so that no fragmentation is necessary? Otherwise, I'd expect you run into problems already when the server is trying to send the Certificate message, which happens before the ChangeCipherSpec.

Please also consult the corresponding Mbed TLS Knowledge Base article for extensive documentation of MFL vs. MTU, and let us know if setting the MTU to 512 Bytes through mbedtls_ssl_set_mtu() resolves your issue.

Best,

Hanno, Mbed TLS team member

04 Apr 2019

Thank you for your answer Hanno. I am aware of the KB article and I already studied it in some detail.

Yes, I noticed that payload + header is the issue during the ChangeCipherSpec handshake phase as the resulting "flight" is > 512 bytes.

If I only set MTU to 512 (no max_fragment_length negotiation), DTLS fails earlier in the handshake when DTLS tries to send our own Certificate. But when negotiating only max_fragment_length (ie. MTU not set to 512 bytes, I assume it uses the default) the SSL handshake actually proceeds to the ChangeCipherSpec (state 12 in mbedTLS).

I will try again with setting MTU only and report back more findings.

04 Apr 2019

Hi Lindsay,

do you have access to the logfiles and/or error codes? That would be helpful in understanding why the Certificate message cannot be sent.

Kind regards,

Hanno

04 Apr 2019

I tried upload some debug output but the file import complains about file format (I tried with .log and .txt filetypes).

Setting only MTU to 512 results in the client being stuck in the client hello phase. It looks like the server keeps sending a hello verify request (msg id: 3) and therefore client continues to reissue it's client hello.

So we are actually stopping earlier in the handshake than I thought.

04 Apr 2019

Hi Lindsay,

fragmented ClientHello messages are not supported (reassembling it would require state on the server before the Client has demonstrated reachability) - could you increase the MTU again and check the size of your ClientHello? If it's beyond 500 Bytes, you'd need to trim down the ClientHello, e.g. by trimming down the list of suggested ciphersuites.

Best,

Hanno

04 Apr 2019

I will increase the minimum required MTU for IPv4 (576 bytes) and report back.

08 Apr 2019

According to the mbedTLS documentation setting the MTU should limit the size of the outgoing datagrams. However, the PAL is applying this also to incoming datagrams. This is a problem. In my use case, mbedTLS will therefore only ask for 512 bytes at a time. As a result server hello parsing fails as there is insufficient data in the receive buffer. I can ignore the size request at the socket level, and relate only to the pending bytes in the socket buffer. The question is how mbedTLS will handle receiving more data than it currently requests.

09 Apr 2019

I have posted some log output on our Dropbox account:

https://www.dropbox.com/s/1hm49z5rs0dyacm/XCOM_20190409_124445.log?dl=0

Our DTLS client awaits the ChangeCipherSpec, but it seems the server reissues it's certificate for whatever reason. The DTLS client now seems to respect the MTU limit. I also had to modify pal_plat_TLS.c in simple-mbed-cloud-client as it was applying MTU limiting to receive operations, which I believe it shouldn't.

11 Apr 2019
  • nudge*. Is it possible to get further support on this matter?
23 Apr 2019

Hi Lindsay,

apologies for replying only now.

I wasn't aware of influence of the MTU on the PAL level, and on first sight I'm not sure it's correct - I'll follow up with the PAL team.

It is not clear to me if your temporary changes to PAL TLS fixed your issues or not - could you please comment, and potentially attach the log files to your post?

Thank you,

Regards,

Hanno, Mbed TLS team member