how to tell if SNI is causing TLS to not work (with LTE-M/NB-IoT)?

I’m trying to get https going with XBee cellular in API mode and always get a transmit status frame with delivery status 85 (Unknown error) back. I’m trying to determine if SNI is the problem.

The user guide says SNI may break things, but it doesn’t describe the exact circumstances or which error will result.

Based on this test:

$ openssl s_client -servername -tlsextdebug -connect 2>/dev/null | grep “server name”
TLS server extension “server name” (id=0), len=0

The server does support SNI. But I would expect that most would at this point. Does support SNI == require SNI == XBee not work?

From other talk on this question:

It sounds like SNI is client-initiated. But the XBee user guide makes it sound like a requirement imposed by servers.

Any advice how to diagnose if SNI is the problem?

1 Like


I looked into this, and I think the error you’re getting is actually due to a cipher suite mismatch.

I was able to confirm using just “openssl s_client -tlsextdebug -connect” that your server is not (apparently) requiring SNI, so that’s not the issue.

Using “nmap -sV --script ssl-enum-ciphers -p 443” I listed the ciphers supported by your server, and these are what I got:

  • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (secp256r1) - A
  • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (secp256r1) - A
  • TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (dh 2048) - A
  • TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (dh 2048) - A
  • TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (secp256r1) - A
  • TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
  • TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (dh 2048) - A
  • TLS_DHE_RSA_WITH_AES_256_CBC_SHA (dh 2048) - A

Comparing that to our documentation ( as well as the u-blox manual, none of those cipher suites are supported. (It does support TLS_RSA_WITH_AES_256_CBC_SHA and _SHA256, but the _DHE does make it different.)

This means that the 0x85 error that you are getting is because the TLS stack in the u-blox modem is not able to negotiate a secure connection with the server. If you reconfigure the server to accept one of the supported cipher suites, it should work fine.

Ok, I think the server now supports the right suite, the output of the nmap command you gave now includes this line:

| TLS_RSA_WITH_AES_256_CBC_SHA - strong

but I still get the same result (status 85).

I don’t think the data is making it to the server at all, I tried this tcpdump command on the server:

tcpdump -i any port 443

and it shows nothing from the time I send a frame to the time the status 85 comes back. It does show stuff when I browse to server with web browser. The same command with port 80 does show stuff when I send a non-encrypted frame (frame tyep 0x20) via XCTU.

Is there some way to get more feedback besides the status 85? A micropython recipe or something? Thanks

Can you confirm what you have the following settings set to:


And can you reply with a copy of the API frame you are using to send? (Hex form - e.g. 7E 00 00 20 …)

Looking at our internal notes, the 0x85 error when using TLS could indicate that the server certificate file is incorrect. Additionally, make sure the server certificate file you are using only has one certificate:

ATTL is 3 (TLSv1.2)
AT$0 is apache-selfsigned.crt;;

Using XCTU File Manager, I can retrieve from remote path /flash/certs/apache-selfsigned.crt

The ‘file’ utility reports it to be a PEM certificate:

$ file apache-selfsigned.crt
apache-selfsigned.crt: PEM certificate

The apache-selfsigned.crt file contains:


I created this certificate using the procedure described here:

It seems to behave as expected from the browser.

The frame hex is:

7E 00 15 23 C4 42 E6 72 AE 01 BB 00 00 00 00 74 65 73 74 5F 64 61 74 61 5B

Does the 0x85 status frame come back immediately, or does it come back after a long delay?

You could try the same connection logic using MicroPython, but I think the error you’ll get there will be more or less the same, since API mode sockets and MicroPython use the same code in the end.

Looking at your certificate (using “openssl x509 -in apache-selfsigned.crt -text -noout”) I see the following:

Subject: C = US, ST = Alaska, L = Fairbanks, O = Netflow, OU = Engineering, CN =, emailAddress =

I can’t say that we’ve ever tested using certificates whose CN fields are IP addresses instead of FQDNs. Does the connection work if you leave the TLS profile empty (AT$0 ;;)? You may have found a bug in the u-blox modem with your certificate.

It does work in API mode with AT$0. IIRC I did originally check in transparent mode but it didn’t work that way.

I still can’t get it to work with a certificate though. I set up DNS service for the server: now points to and is well propagated.

I regenerated the cert/key pair according to again, but with CN = The pair seems to work from the browser.

I uploaded the new certificate to the XBee and reset $0 to apache-selfsigned.crt;;.

The failure now seems different than it was in that the tcpdump -i any port 443 command on the server now always shows activity when XCTU is used to send a frame. But a status 85 frame is still always returned on the XBee.

I appreciate all your help so far. Unfortunately I don’t know what to try next. Thoughts?

The apache2 server says the following when the XBee tries to connect:

[Wed May 22 01:59:17.599721 2019] [ssl:info] [pid 20187:tid 2965328944] [client] AH01964: Connection to child 74 established (server
[Wed May 22 01:59:17.610306 2019] [ssl:debug] [pid 20187:tid 2965328944] ssl_engine_kernel.c(2143): [client] AH02645: Server name not provided via TLS extension (using default/first virtual host)
[Wed May 22 01:59:18.180208 2019] [ssl:debug] [pid 20187:tid 2965328944] ssl_engine_io.c(1308): (70014)End of file found: [client] AH02007: SSL handshake interrupted by system [Hint: Stop button pressed in browser?!]
[Wed May 22 01:59:18.181613 2019] [ssl:info] [pid 20187:tid 2965328944] [client] AH01998: Connection closed to child 74 with abortive shutdown (server

This makes it sound like the XBee is for some reason not actually sending the certificate file, or quitting early instead of sending full contents or something. Coming from the browser I get instead:

[Wed May 22 01:25:14.990415 2019] [ssl:info] [pid 19584:tid 2973721648] [client] AH01964: Connection to child 73 established (server
[Wed May 22 01:25:14.993077 2019] [socache_shmcb:debug] [pid 19584:tid 2973721648] mod_socache_shmcb.c(532): AH00835: socache_shmcb_retrieve (0xf5 -> subcache 21)
[Wed May 22 01:25:14.994602 2019] [socache_shmcb:debug] [pid 19584:tid 2973721648] mod_socache_shmcb.c(884): AH00849: match at idx=0, data=0
[Wed May 22 01:25:14.995733 2019] [socache_shmcb:debug] [pid 19584:tid 2973721648] mod_socache_shmcb.c(542): AH00836: leaving socache_shmcb_retrieve successfully
[Wed May 22 01:25:14.997320 2019] [ssl:debug] [pid 19584:tid 2973721648] ssl_engine_kernel.c(2115): [client] AH02043: SSL virtual host for servername found
[Wed May 22 01:25:14.999636 2019] [ssl:info] [pid 19584:tid 2965328944] [client] AH01964: Connection to child 74 established (server

So it’s a different path on the server because SNI I guess. I’m not sure how to simulate a non-SNI connection to check that from the browser or other tool yet. I think the “default/first virtual host” alluded to should be the right one though, as /etc/apache2/sites-available/default-ssl.conf contains:

            ServerAdmin webmaster@localhost

If anyone at Digi would like access to this server to check out details I’d be happy to give it. Without some more feedback from the client I don’t know what else to try.

This ublox document:

discusses different certification levels. Level 0 is no validation, level 1 is a basic certificate check, level 2 adds an ‘additional URL integrity check’, and level 3 adds on to that a check about the certificate validity date.

Can anyone tell me which of these levels the XBee uses internally? Also, what does the additional URL integrity check entail?