Dear Mbed TLS team,
I am at the early steps of trying to integrate Mbed TLS with LWIP for our project (imx rt 1024 NXP micro, arm M7, running FreeRTOS and LWIP). I understand the basics of TLS, but I am far from an expert.
Let me first apologise for the lengthy first email. I am afraid to leave out details. Feel free to skip directly to the end marked with: ============================= My questions: =============================
Some background / translation of how I think it (should) work:
From a distance, I understand that LWIP has an abstraction layer on their TCP module, which can be used to integrate Mbed TLS. In fact, LWIP already did this, all I need to do is enable some directives (LWIP_ALTCP_TLS and LWIP_ALTCP_TLS_MBEDTLS). The implemented integration assumes a somewhat older version of Mbed TLS, so I have to adjust a couple to cope with the breaking changes from Mbed TLS 2.x to Mbed TLS 3.6.2.
But other than that, integrating Mbed TLS would mean: - figure out which options i want to enable in Mbed TLS - cross compile it for our arm toolchain - extend our build scripts to compile against 3 static Mbed TLS libraries - figure out how to read the CA certificates, and provide them to Mbed TLS - test and fail, and hopefully be man enough to solve the challenges ahead...
I haven't achieved much yet, but at least I managed to compile Mbed TLS with our toolchain and recompile our project against the linked libraries. This steps fails though, I get a bunch of linker errors :
[100%] Linking CXX executable app.axf /opt/gcc-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /home/dev/app/source/iobox-app/../../thirdparty/mbedtls/build/library/libmbedtls.a(ssl_msg.c.obj): in function `mbedtls_ssl_encrypt_buf': /home/dev/app/thirdparty/mbedtls/library/ssl_msg.c:1211:(.text.mbedtls_ssl_encrypt_buf+0x1b4): undefined reference to `mbedtls_cipher_auth_encrypt_ext' /opt/gcc-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /home/dev/app/source/iobox-app/../../thirdparty/mbedtls/build/library/libmbedtls.a(ssl_msg.c.obj): in function `mbedtls_ssl_decrypt_buf': /home/dev/app/thirdparty/mbedtls/library/ssl_msg.c:1638:(.text.mbedtls_ssl_decrypt_buf+0x180): undefined reference to `mbedtls_cipher_auth_decrypt_ext' /opt/gcc-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /home/dev/app/source/iobox-app/../../thirdparty/mbedtls/build/library/libmbedtls.a(ssl_msg.c.obj): in function `mbedtls_ssl_transform_free': /home/dev/app/thirdparty/mbedtls/library/ssl_msg.c:6213:(.text.mbedtls_ssl_transform_free+0x14): undefined reference to `mbedtls_cipher_free' /opt/gcc-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /home/dev/app/thirdparty/mbedtls/library/ssl_msg.c:6214:(.text.mbedtls_ssl_transform_free+0x1e): undefined reference to `mbedtls_cipher_free' /opt/gcc-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /home/dev/app/source/iobox-app/../../thirdparty/mbedtls/build/library/libmbedtls.a(ssl_tls.c.obj): in function `mbedtls_ssl_transform_init': /home/dev/app/thirdparty/mbedtls/library/ssl_tls.c:1028:(.text.mbedtls_ssl_transform_init+0x18): undefined reference to `mbedtls_cipher_init' /opt/gcc-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /home/dev/app/thirdparty/mbedtls/library/ssl_tls.c:1029:(.text.mbedtls_ssl_transform_init+0x22): undefined reference to `mbedtls_cipher_init' /opt/gcc-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /home/dev/app/source/iobox-app/../../thirdparty/mbedtls/build/library/libmbedtls.a(ssl_tls.c.obj): in function `mbedtls_ssl_get_mode_from_ciphersuite': /home/dev/app/thirdparty/mbedtls/library/ssl_tls.c:2453:(.text.mbedtls_ssl_get_mode_from_ciphersuite+0x12): undefined reference to `mbedtls_cipher_info_from_type' /opt/gcc-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /home/dev/app/source/iobox-app/../../thirdparty/mbedtls/build/library/libmbedtls.a(ssl_tls.c.obj): in function `mbedtls_ssl_parse_finished': /home/dev/app/thirdparty/mbedtls/library/ssl_tls.c:8680:(.text.mbedtls_ssl_parse_finished+0xac): undefined reference to `mbedtls_ct_memcmp' /opt/gcc-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /home/dev/app/source/iobox-app/../../thirdparty/mbedtls/build/library/libmbedtls.a(ssl_tls.c.obj): in function `ssl_tls12_populate_transform': /home/dev/app/thirdparty/mbedtls/library/ssl_tls.c:8878:(.text.ssl_tls12_populate_transform+0xa6): undefined reference to `mbedtls_cipher_info_from_type' /opt/gcc-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /home/dev/app/thirdparty/mbedtls/library/ssl_tls.c:9136:(.text.ssl_tls12_populate_transform+0x454): undefined reference to `mbedtls_cipher_setup' /opt/gcc-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /home/dev/app/thirdparty/mbedtls/library/ssl_tls.c:9142:(.text.ssl_tls12_populate_transform+0x476): undefined reference to `mbedtls_cipher_setup' /opt/gcc-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /home/dev/app/thirdparty/mbedtls/library/ssl_tls.c:9148:(.text.ssl_tls12_populate_transform+0x4a8): undefined reference to `mbedtls_cipher_setkey' /opt/gcc-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /home/dev/app/thirdparty/mbedtls/library/ssl_tls.c:9155:(.text.ssl_tls12_populate_transform+0x4da): undefined reference to `mbedtls_cipher_setkey' /opt/gcc-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: CMakeFiles/app.dir/home/dev/app/thirdparty/lwip/src/apps/altcp_tls/altcp_tls_mbedtls.c.obj: in function `altcp_mbedtls_sndbuf': /home/dev/app/thirdparty/lwip/src/apps/altcp_tls/altcp_tls_mbedtls.c:1192:(.text.altcp_mbedtls_sndbuf+0x7e): undefined reference to `mbedtls_ssl_get_max_frag_len' /opt/gcc-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /home/dev/app/source/iobox-app/../../thirdparty/mbedtls/build/library/libmbedtls.a(ssl_tls12_server.c.obj): in function `ssl_parse_client_psk_identity': /home/dev/app/thirdparty/mbedtls/library/ssl_tls12_server.c:3638:(.text.ssl_parse_client_psk_identity+0xb6): undefined reference to `mbedtls_ct_memcmp'
The distinct list undefined references of the above:
undefined reference to `mbedtls_cipher_auth_encrypt_ext' undefined reference to `mbedtls_cipher_auth_decrypt_ext' undefined reference to `mbedtls_cipher_free' undefined reference to `mbedtls_cipher_init' undefined reference to `mbedtls_cipher_info_from_type' undefined reference to `mbedtls_ct_memcmp' undefined reference to `mbedtls_cipher_setup' undefined reference to `mbedtls_cipher_setup' undefined reference to `mbedtls_cipher_setkey' undefined reference to `mbedtls_cipher_setkey' undefined reference to `mbedtls_ssl_get_max_frag_len'
All except the last one are coming from Mbed TSL internally, so I *guess* this means I am missing options? Or maybe I am still having too many? The last one is called from the LWIP integration of Mbed TLS, and I could "sweep this under the carpet" by disabling "MBEDTLS_SSL_MAX_FRAGMENT_LENGTH". But I haven't looked further in what I cause if I do not support "RFC 6066 max_fragment_length extension in SSL"
My Mbed TLS configuration:
I followed the suggestion of your documentation, and went for a minimal example configuration. Pure on intuition, I went for "config-ccm-psk-dtls1_2.h". Because the file name suggests it brings TSL 1.2 which is basically all I need. I think. I did had to make the following changes in order to be able to compile it:
1. Comment out two defines in order to get rid of module requiring "windows or unix" //#define MBEDTLS_NET_C //#define MBEDTLS_TIMING_C
2. Add a define, again to get rid of the compiler error "require windows or unix" #define MBEDTLS_NO_PLATFORM_ENTROPY
After applying these small changes to the include/mbedtls/mbedtls_config.h I was able to cross compile (and link) Mbed TLS with arm-none-eabi toolchain.
Once I adjusted the build scripts to lnk against the Mbed TLS static libraries, I finally ended up with the earlier mentioned linker errors.
============================= My questions: =============================
1. Does my starting point configuration make sense? As mentioned earlier, pure intuition made me try the "config-ccm-psk-dtls1_2.h" configuration example, which after some modifications compiled and produced 3 static libraries. but, this bit in the example header worries me a bit:
* Distinguishing features: * - Optimized for small code size, low bandwidth (on an unreliable transport), * and low RAM usage. * - No asymmetric cryptography (no certificates, no Diffie-Hellman key * exchange). * - Fully modern and secure (provided the pre-shared keys are generated and * stored securely). * - Very low record overhead with CCM-8. * - Includes several optional DTLS features typically used in IoT.
What does "no asymmetric cryptography" exactly mean? Isn't that the pure basis of TLS altogether? If I want to achieve HTTPS using TLS, is this a good starting point?
2. Undefined references: wrong configuration, or should I supply some of the implementations? As mentioned before, I have quite a few linking errors related to the cipher module. I tried to find answers in the documentation, but came up empty. I assume (again...) that I should be able to get rid of these linking errors by enabling more features in Mbed TLS. But I honestly get lost in #define's. And maybe it's documented somewhere, but I couldn't find it.
3. Root CA provided by me? I assume I *need* to provide at least one root CA for Mbed TLS to be able to verify the public key provided by the server, at some point, right? I would expect some callback I need to implement where such a root CA was read (in my case, i would have to read if from flash). Am I misunderstanding Mbed TLS on this aspect also? Or did I just miss the obvious spot where to Mbed TLS requests a root CA?
4. More examples available for typical microcontroller projects (FreeRTOS/LWIP)? My experience so far is: - Mbed TLS is well documented - LWIP is no longer actively maintained, and lacks documentation in general - Google finds a painful amount of LWIP/TLS integrations which are based on really old implementations of both, which does more harm than good for me - Chat GPT knows everything, even when it doesn't, which is a really great recipe to get on the wrong track... It doesn't seem rather helpful on my integration questions for Mbed TLS/LWIP. Disclaimer: could be that my lack of knowledge is causing gpt to come up with wrong answers of course...
I understand that my email is (too?) long, and that the chance somebody will actually find the time to help me out is limited. I expect nothing, I hope for everything :)
ANY help is more than welcome. Good references, links to official documentation I missed, or in the best case: answers to my questions/uncertainties. Many thanks in advance.
Best regards, Bas
Hello,
Here's a partial answer.
On 05/12/2024 12:49, Bas Prins via mbed-tls wrote: (…)
But other than that, integrating Mbed TLS would mean:
- figure out which options i want to enable in Mbed TLS
- cross compile it for our arm toolchain
- extend our build scripts to compile against 3 static Mbed TLS libraries
- figure out how to read the CA certificates, and provide them to Mbed TLS
- test and fail, and hopefully be man enough to solve the challenges
ahead...
That does seem like a reasonable plan, yes.
undefined reference to `mbedtls_cipher_auth_encrypt_ext' undefined reference to `mbedtls_cipher_auth_decrypt_ext' undefined reference to `mbedtls_cipher_free' undefined reference to `mbedtls_cipher_init' undefined reference to `mbedtls_cipher_info_from_type' undefined reference to `mbedtls_ct_memcmp' undefined reference to `mbedtls_cipher_setup' undefined reference to `mbedtls_cipher_setup' undefined reference to `mbedtls_cipher_setkey' undefined reference to `mbedtls_cipher_setkey'
All of those are TLS code that is not finding crypto functions. I notice mbedtls_ct_memcmp which is compiled unconditionally, so it's not just a problem with configuration. Two things I can think of. First, make sure your build scripts are up-to-date: old build scripts might be missing constant_time.o which didn't exist in ancient versions of the library. Second, make sure your linker command is in the right order: -lmbedtls -lmbedx509 -lmbedcrypto to allow tls functions to call x509/crypto functions, and x509 to call crypto functions.
undefined reference to `mbedtls_ssl_get_max_frag_len'
That function no longer exists in Mbed TLS 3.x, please upgrade your application code. See the migration guide at https://github.com/Mbed-TLS/mbedtls/blob/mbedtls-3.6/docs/3.0-migration-guid...
I followed the suggestion of your documentation, and went for a minimal example configuration. Pure on intuition, I went for "config-ccm-psk-dtls1_2.h". Because the file name suggests it brings TSL 1.2 which is basically all I need. I think.
That configuration is a good example for doing TLS with only pre-shared keys, but not if you use certificates. If you use certificates, I would suggest config-suite-b.h as a starting point. It does TLS 1.2 with a certain set of parameters and has comments to guide you on common things you may want to tweak.
What does "no asymmetric cryptography" exactly mean? Isn't that the pure basis of TLS altogether? If I want to achieve HTTPS using TLS, is this a good starting point?
On the world wide web, clients needs to be able to communicate with servers that they have no prior knowledge of. Asymmetric cryptography is required for that. But the TLS protocol can also be used without asymmetric cryptography in some specialized environments, e.g. when a few clients are talking to a single server that they have previously been paired with (IoT “dust” talking to a local gateway). In such environment, it's practical to use pre-shared symmetric keys (PSK). If that's not your use case, you can ignore the existence of PSK.
- Undefined references: wrong configuration, or should I supply some
of the implementations? As mentioned before, I have quite a few linking errors related to the cipher module. I tried to find answers in the documentation, but came up empty. I assume (again...) that I should be able to get rid of these linking errors by enabling more features in Mbed TLS. But I honestly get lost in #define's. And maybe it's documented somewhere, but I couldn't find it.
At first glance the linker errors don't look to me like a configuration problem, but I'm not sure. We try to arrange for an #error from check_config.h for inconsistent configurations, but that doesn't catch all possibilities.
- Root CA provided by me?
I assume I *need* to provide at least one root CA for Mbed TLS to be able to verify the public key provided by the server, at some point, right? I would expect some callback I need to implement where such a root CA was read (in my case, i would have to read if from flash). Am I misunderstanding Mbed TLS on this aspect also? Or did I just miss the obvious spot where to Mbed TLS requests a root CA?
Yes, you'll need to provide at least one root CA. That's mbedtls_ssl_conf_ca_chain() (or other functions in more complicated scenarios). I do notice that the documentation doesn't mention the common phrase “root CA”: it talks about “fully trusted top-level CAs”, which means the same thing but is not the common term. I'll propose a documentation improvement.
Best regards,
mbed-tls@lists.trustedfirmware.org