u-blox / ubxlib

Portable C libraries which provide APIs to build applications with u-blox products and services. Delivered as add-on to existing microcontroller and RTOS SDKs.
Apache License 2.0
287 stars 82 forks source link

Problems selecting cipher suites #211

Closed tobiasadolph closed 4 months ago

tobiasadolph commented 4 months ago

Hello, we are using a SARA-R422S modem. When connecting to a server we need to modify the supported cipher suites on the modem as our server doesn't support the default ones by the modem. Unfortunately we can't get it to work.

First we created our own default security TLS settings based on U_SECURITY_TLS_SETTINGS_DEFAULT from ubxlib:

#define EXTENDED_U_SECURITY_TLS_SETTINGS_DEFAULT {U_SECURITY_TLS_VERSION_ANY, /* tlsVersion */                          \
                                                NULL, /* Root CA name */                                              \
                                                NULL, /* Client CA name */                                            \
                                                NULL, /* Private key name */                                          \
                                                U_SECURITY_TLS_CERTIFICATE_CHECK_NONE,                                \
                                                NULL, /* Private key PW */                                            \
                                                {/* Cipher suites */                                                  \
                                                 35, /* Number of cipher suites in list */                             \
                                                 {                                                                    \
                                                     U_SECURITY_TLS_CIPHER_SUITE_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, \
                                                     U_SECURITY_TLS_CIPHER_SUITE_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, \
                                                     U_SECURITY_TLS_CIPHER_SUITE_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, \
                                                     U_SECURITY_TLS_CIPHER_SUITE_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, \
                                                     U_SECURITY_TLS_CIPHER_SUITE_ECDHE_ECDSA_WITH_AES_128_CCM,        \
                                                     U_SECURITY_TLS_CIPHER_SUITE_ECDHE_ECDSA_WITH_AES_256_CCM,        \
                                                     U_SECURITY_TLS_CIPHER_SUITE_ECDHE_RSA_WITH_AES_128_CBC_SHA256,   \
                                                     U_SECURITY_TLS_CIPHER_SUITE_ECDHE_RSA_WITH_AES_256_CBC_SHA384,   \
                                                     U_SECURITY_TLS_CIPHER_SUITE_ECDHE_RSA_WITH_AES_128_GCM_SHA256,   \
                                                     U_SECURITY_TLS_CIPHER_SUITE_ECDHE_RSA_WITH_AES_256_GCM_SHA384,   \
                                                     U_SECURITY_TLS_CIPHER_SUITE_ECDHE_PSK_WITH_AES_128_CBC_SHA256,   \
                                                     U_SECURITY_TLS_CIPHER_SUITE_ECDHE_PSK_WITH_AES_256_CBC_SHA384,   \
                                                     U_SECURITY_TLS_CIPHER_SUITE_DHE_DSS_WITH_AES_128_CBC_SHA256,     \
                                                     U_SECURITY_TLS_CIPHER_SUITE_DHE_RSA_WITH_AES_128_CBC_SHA256,     \
                                                     U_SECURITY_TLS_CIPHER_SUITE_DHE_RSA_WITH_AES_256_CBC_SHA256,     \
                                                     U_SECURITY_TLS_CIPHER_SUITE_DHE_RSA_WITH_AES_128_GCM_SHA256,     \
                                                     U_SECURITY_TLS_CIPHER_SUITE_DHE_RSA_WITH_AES_256_GCM_SHA384,     \
                                                     U_SECURITY_TLS_CIPHER_SUITE_DHE_PSK_WITH_AES_128_CBC_SHA256,     \
                                                     U_SECURITY_TLS_CIPHER_SUITE_DHE_PSK_WITH_AES_256_CBC_SHA384,     \
                                                     U_SECURITY_TLS_CIPHER_SUITE_DHE_PSK_WITH_AES_128_GCM_SHA256,     \
                                                     U_SECURITY_TLS_CIPHER_SUITE_DHE_PSK_WITH_AES_256_GCM_SHA384,     \
                                                     U_SECURITY_TLS_CIPHER_SUITE_DHE_PSK_WITH_AES_128_CCM,            \
                                                     U_SECURITY_TLS_CIPHER_SUITE_DHE_PSK_WITH_AES_256_CCM,            \
                                                     U_SECURITY_TLS_CIPHER_SUITE_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,  \
                                                     U_SECURITY_TLS_CIPHER_SUITE_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,  \
                                                     U_SECURITY_TLS_CIPHER_SUITE_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,  \
                                                     U_SECURITY_TLS_CIPHER_SUITE_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,  \
                                                     U_SECURITY_TLS_CIPHER_SUITE_ECDH_RSA_WITH_AES_128_CBC_SHA256,    \
                                                     U_SECURITY_TLS_CIPHER_SUITE_ECDH_RSA_WITH_AES_256_CBC_SHA384,    \
                                                     U_SECURITY_TLS_CIPHER_SUITE_ECDH_RSA_WITH_AES_128_GCM_SHA256,    \
                                                     U_SECURITY_TLS_CIPHER_SUITE_ECDH_RSA_WITH_AES_256_GCM_SHA384,    \
                                                     U_SECURITY_TLS_CIPHER_SUITE_RSA_PSK_WITH_AES_128_CBC_SHA256,     \
                                                     U_SECURITY_TLS_CIPHER_SUITE_RSA_PSK_WITH_AES_256_CBC_SHA384,     \
                                                     U_SECURITY_TLS_CIPHER_SUITE_RSA_PSK_WITH_AES_128_GCM_SHA256,     \
                                                     U_SECURITY_TLS_CIPHER_SUITE_RSA_PSK_WITH_AES_256_GCM_SHA384,     \
                                                 }},                                                                  \
                                                {NULL, 0}, /* PSK */                                                  \
                                                {NULL, 0}, /* PSK ID */                                               \
                                                false, /* pskGeneratedByRoT */                                        \
                                                NULL, /* Expected server URL */                                       \
                                                NULL, /* SNI */                                                       \
                                                false, /* Session resumption */                                       \
                                                false, /* use device certificate */                                   \
                                                false}; /* include CA certificates */

To increase the array of uSecurityTlsCipherSuiteIana_t in uSecurityTlsCipherSuites_t we increased the define U_SECURITY_TLS_MAX_NUM_CIPHER_SUITES accordingly.

Based on our custom default tls settings we now try to connect to a server: (Simplified code snipped)

int Socket = socket(AF_INET, U_SOCK_TYPE_STREAM, U_SOCK_PROTOCOL_TCP);
if (Socket >= 0)
{
    UBXLIB_fcntlSetFlags(F_SETFL, O_NONBLOCK)

    uSecurityTlsSettings_t TlsSettings = EXTENDED_U_SECURITY_TLS_SETTINGS_DEFAULT;
    TlsSettings.tlsVersionMin = U_SECURITY_TLS_VERSION_1_2;
    TlsSettings.certificateCheck = U_SECURITY_TLS_CERTIFICATE_CHECK_ROOT_CA_URL_DATE;
    TlsSettings.pExpectedServerUrl = HostName;
    TlsSettings.pSni = HostName;
    TlsSettings.pClientPrivateKeyName = ClientSecret;
    TlsSettings.pClientCertificateName = ClientCertificate;

    int32_t SockSecurityResult = uSockSecurity(Socket, &TlsSettings);

    int ConnectResult = connect(Socket, SockAddr, SockAddrLen);

AT log for uSockSecurity():

U_SOCK: socket created, descriptor 0, network handle 0x20013BA0, socket handle 0.
AT+USECPRF=0

+CREG: 5,"67B7","01DF8A07",7

+CEREG: 5,"67B7","1DF8A07",7,,,,

OK
AT+USECPRF=0,1,3

OK
AT+USECPRF=0,5,"User"

OK
AT+USECPRF=0,6,"User secret"

OK
AT+USECPRF=0,2,99,"c0","23"

OK
AT+USECPRF=0,2,99,"c0","24"

OK
AT+USECPRF=0,2,99,"c0","2b"

OK
AT+USECPRF=0,2,99,"c0","2c"

OK
AT+USECPRF=0,2,99,"c0","ac"

OK
AT+USECPRF=0,2,99,"c0","ad"

OK
AT+USECPRF=0,2,99,"c0","27"

OK
AT+USECPRF=0,2,99,"c0","28"

OK
AT+USECPRF=0,2,99,"c0","2f"

OK
AT+USECPRF=0,2,99,"c0","30"

OK
AT+USECPRF=0,2,99,"c0","37"

OK
AT+USECPRF=0,2,99,"c0","38"

OK
AT+USECPRF=0,2,99,"00","40"

OK
AT+USECPRF=0,2,99,"00","67"

OK
AT+USECPRF=0,2,99,"00","6b"

OK
AT+USECPRF=0,2,99,"00","9e"

OK
AT+USECPRF=0,2,99,"00","9f"

OK
AT+USECPRF=0,2,99,"00","b2"

OK
AT+USECPRF=0,2,99,"00","b3"

OK
AT+USECPRF=0,2,99,"00","aa"

OK
AT+USECPRF=0,2,99,"00","ab"

OK
AT+USECPRF=0,2,99,"c0","a6"

OK
AT+USECPRF=0,2,99,"c0","a7"

OK
AT+USECPRF=0,2,99,"c0","25"

OK
AT+USECPRF=0,2,99,"c0","26"

OK
AT+USECPRF=0,2,99,"c0","2d"

OK
AT+USECPRF=0,2,99,"c0","2e"

OK
AT+USECPRF=0,2,99,"c0","29"

OK
AT+USECPRF=0,2,99,"c0","2a"

OK
AT+USECPRF=0,2,99,"c0","31"

OK
AT+USECPRF=0,2,99,"c0","32"

OK
AT+USECPRF=0,2,99,"00","b6"

OK
AT+USECPRF=0,2,99,"00","b7"

OK
AT+USECPRF=0,2,99,"00","ac"

OK
AT+USECPRF=0,2,99,"00","ad"

OK
AT+USECPRF=0,4,"REMOVED"

OK
AT+USECPRF=0,0,3

OK
AT+USECPRF=0,10,"REMOVED"

OK
AT+USOSEC=0,1,0

OK

When sniffing our connection with wireshark we noticed the client hello only includes the last cipher suite in the list U_SECURITY_TLS_CIPHER_SUITE_RSA_PSK_WITH_AES_256_GCM_SHA384 and not the whole list:

image

How do we properly setup the cipher suite list on our modem? Thank you very much in advance for the help.

RobMeades commented 4 months ago

Hi, and thanks for posting. Unfortunately I think you're issue is likely that SARA-R422S only supports setting of a single user-configurable cipher suite. From the interface manual:

image

<legacy_cs>=100 is the "add cipher suite" operation; without it the ubxlib code can only do <legacy_cs>=99 which replaces the single cipher suite with the one specified (this is not very clear in the AT manual, you have to infer it from the fact that the words "list of" appear in the bit about 100 but not in the bit about 99):

image

We could make this clearer by adding a function bool uCellSecTlsMoreThanOneCipherSuite() which the uSecurity API could call to see if more than one is supported, then it could return an error to you rather than blindly replacing one with the next. I will do that.

Doesn't help you of course, not sure what to suggest.

tobiasadolph commented 4 months ago

Thank you very much for the blazing fast response. That is indeed unfortunate news.

So for my understanding, the modem supports a list of cipher suites by default, but doesn't support a custom list. Then only one cipher suite is support at the same time? This isn't a behavior I expected, but it is what it is. Any chance this will be changed with a future software update of the modem?

Do you see any other way than trying to connect with one cipher suites all by one until one works? Maybe caching the result could help for the next connection.

In addition, I think your proposed change of the API is a good idea 👍

RobMeades commented 4 months ago

Now you're getting into the sticky details of TLS negotiation, which I can't say I'm 100% sure of. I would have thought that the set of "automatically" supported cipher suites would be sent to the server in the "Client Hello" and, if there were some cross-over between what your server supports and the ones in that list, then it would propose those back again and things would work. I guess from what you're saying that is not the case.

I can probably run Wireshark on our test echo server and run a TLS test with SARA-R422S to find out what does happen, will take a look. I will also see if I can't rustle up someone who actually knows what they are talking about...

tobiasadolph commented 4 months ago

I already did the Wireshark capture. By default our modem sends these 37 cipher suites in the client hello:

image

These are also mentioned in the AT commands manual and marked with and (D) for the SARA-R422S modem.

image

As these default ones don't overlap with the desired server (server is not in our control) the TLS handshake failes because no shared cipher was found

RobMeades commented 4 months ago

wireshark.log

Aha, yes, just did that same thing and obtained the Wireshark log [attached] from our echo server, which indeed looks the same as yours. Darn. Is your server newer or older, i.e. might there be a chance that a later FW revision of SARA-R422S happens to pick up later cipher suites which might work? What FW version do you have (response to ATI9, should be queried and printed-out by ubxlib near boot)?

tobiasadolph commented 4 months ago

At the moment we have the FW version 00.12,A00.00.

ATI9

00.12,A00.00

OK

The server is rather new.

Assuming the default cipher suites mentioned in the manual don't change, I don't see how a update could fix this. The modem will send the list of 37 supported suites and when these don't match with the server the connection will be terminated by the server. All the other supported cipher suites by the modem will never be used as long as they are not included in the client hello. The server has to assume the client only supports the 37 listed.

RobMeades commented 4 months ago

Indeed, it would have to be the default set that was changed or expanded to help you out.

I assume it is not viable to find one single cipher suite which you know your server supports and so could choose just that? I guess that would be a bit risky anyway, should a flaw be found in that suite and you are left without a choice.

tobiasadolph commented 4 months ago

Problem is, we have to connect to different servers. I could check whether we have and match between those, but that's not really a future prove option. These cipher suites can change at any time on the server side assuming they might me considered insecure in the future or any other reason... .

RobMeades commented 4 months ago

Understood. I've asked the application engineer internally who owns SARA-R422 if he knows of any ways this might be made to work; will get back to you.

tobiasadolph commented 4 months ago

Perfect, thank you very much.

When there is no other way we might have to implement some kind of mechanism on our side to try out the cipher suites one by one in every connect as mention above.

RobMeades commented 4 months ago

The application engineer confirms that you would need to try your list of cipher suites one at a time with the server to determine which is acceptable. I guess the "acceptable" cipher suite could be cached so that you don't try unacceptable ones again needlessly for a given server but it is, unfortunately, a pain.

RobMeades commented 4 months ago

Oh, and he doesn't believe the set of initial cipher suites have changed but he does recommend using the latest module FW, which can be found here:

https://www.u-blox.com/en/product/sara-r4-series?legacy=Current#Documentation-&-resources

tobiasadolph commented 4 months ago

Ok, thanks for the update. Then we have to implement the proposed workaround. Do you have any plans on when the proposed API change will be implemented? Maybe we can additionally update the ubxlib in this step.

Regarding the update. I have an old modem with 00B hardware on my desk which can't be updated to my knowledge. But a colleague of mine tested it with the 01B hardware and the problem remains.

Thanks for your support!

RobMeades commented 4 months ago

But a colleague of mine tested it with the 01B hardware and the problem remains.

Understood. The API change has been tested and is in review now, should be here very shortly.

RobMeades commented 4 months ago

Now pushed to master here in commit 27c75a8b3ec24762d9dd1bbe402c8de0a73cb505 with a comment-only update to the same code in commit b747695052aad1884196d66d057d51b307dde59e.

tobiasadolph commented 4 months ago

That was fast 😀 I will close this issue as I know how to proceed and thanks again for your effort