Mbedtls linker issues

Hi, I’m having trouble with the linker when using AES functions provided by mbedtls:

undefined reference to 'mbedtls_aes_setkey_enc'
undefined reference to 'mbedtls_aes_crypt_cfb128'
undefined reference to 'mbedtls_aes_init'
undefined reference to 'mbedtls_aes_free'

My sdkconfig options:

CONFIG_MBEDTLS_HARDWARE_AES=y
CONFIG_MBEDTLS_AES_C=y

SOLUTION:
change sdkconfig to

# CONFIG_MBEDTLS_HARDWARE_AES is not set
1 Like

I also have a linker issue with mbedtls
undefined reference to `mbedtls_cipher_cmac’

How do I change the sdkconfig.h file in VS Code (with platformIO extension)? It does not appear in the project/scr folder.
I have read ESP32, how to make changes to sdkconfig? and read through @maxgerhardt 's link to the platformio documentation, but I don’t know how to perform the equivalent actions in VSC.

Are you using framework = arduino or espidf in your project? (When using the first one, manual changes to the sdkconfig.h file will have no effect since ESP-IDF is not recompiled from source.)

I am using framework = arduino since this is what I am familiar with.
I don’t know if changing the sdkconfig.h file is what I need to do either. I am trying to get my head around the mbedtls libraries. Are they built in to platformIO or an installed library?
I understand that the compiler is finding the <mbedtls/cmac.h> file, but the linker is not finding the corresponding .c file. What I do not understand is where the .c files are supposed to be.
I was able to do some aes encryption with <mbedtls/aes.h> but I do not see the .c files for that lib either.
They must exist somewhere?

That may be a misconfiguration on the Arduino-ESP32 side – they compile ESP-IDF with certain settings (as exposed in the sdkconfig.h file) and then include that as a precompiled static library (.a) into Arduino-ESP32. mbedtls is included in ESP-IDF and so it may be possible that the standard configuration deactivates the compilation of that module (by not defining MBEDTLS_CMAC_C in the mbedtls config header file).

An easier way (compared to going back to the base and recompiling ESP-IDF with the right settings, which believe me is hell) would be if you grabbed just the CMAC implementation file from mbedtls and added it in your project’s src/ folder. That is at mbedtls/library/cmac.c at development · Mbed-TLS/mbedtls · GitHub. Make sure to remove the #if defined(MBEDTLS_CMAC_C) test (line 43 and 1087) to force compilation, otherwise the file will be internally blank. That should give you back the implementation that is missing.

If you just use the mbedtls CMAC functions stand-alone by calling into them directly it should be no problem. Note that since the original mbedtls configuration was without CMAC, other modules (such as the TLS client or server) had no knoweldge of the CMAC module at their compile time, and so adding the cmac file in posterium won’t magically enable CMAC ciphersuites e.g… For that, a clean recompile is needed.

1 Like

An entirely different approach would be to test whether your problem still exists in the latest Arduino core. PlatformIO lags behind and uses Arduino-ESP32 1.0.6, whereas 2.0.1 is the latest stable. Use the platformio.ini instructions at https://github.com/platformio/platform-espressif32/issues/619#issuecomment-976525911 to switch to an experimental support version for 2.0.1 and see if it just goes away.

Alas… tried the switch to latest Arduino core…
I did get past the ld.exe: final link failed: problem
but the link error remains: undefined reference to mbedtls_cipher_cmac
Its weird because it does compile cmac.c.o
From the build terminal:

Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/esp32dev.html
PLATFORM: Espressif 32 (3.3.1+sha.33ff413) > Espressif ESP32 Dev Module
HARDWARE: ESP32 240MHz, 320KB RAM, 4MB Flash
DEBUG: Current (esp-prog) External (esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
PACKAGES:
 - framework-arduinoespressif32 2.0.1
 - tool-esptoolpy 1.30200.211025 (3.2.0)
 - toolchain-xtensa-esp32 8.4.0+2021r1
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 34 compatible libraries
Scanning dependencies...
Dependency Graph
|-- <mbedtls> 2.23.0
Building in release mode
Compiling .pio\build\esp32dev\src\main.cpp.o
Generating partitions .pio\build\esp32dev\partitions.bin
Compiling .pio\build\esp32dev\lib7b9\mbedtls\aes.c.o

then further down:

Compiling .pio\build\esp32dev\lib7b9\mbedtls\cmac.c.o

Oh okay, wait that looks like the project has mbedlts in the lib/ folder now, but hopefully only the cmac.c source file or also other files?

It’s not in the /lib folder no.
But it is in the .pio\build\esp32dev\lib7b9 folder
not the cmac.c file, only cmac.c.o
I do not see the source file anywhere

When you run the project task Advanced → Verbose Build, what is the path shown next to the mbedlts library in the dependency graph?

I actually worked through your original suggestion @maxgerhardt of copy/pasting the cmac.c to the /src folder and managed to get a successful build :grinning:
When I tried it originally, it felt like I was chasing all kinds of errors, but when I tried it again now I was able to work through them all.

The trick was to find a file called esp_config.h and add #define CONFIG_MBEDTLS_CMAC_C at the top. This causes the comiler to define MBEDTLS_CMAC_C which causes cipher.h to declare a variable called cmac_ctx which is needed in a few places.

I suppose if you are not using a ESP32, you would do this in config.h rather.

1 Like

Great that it works now – that however that requires a modification of framework files. Can you try to revert your changes to esp_config.h and replace it by adding

build_flags = -DCONFIG_MBEDTLS_CMAC_C

in the platformio.ini (docs)? Then the project can be replicated more easily and still work.

Yes, removing the define from esp_config.h and adding the build flag above does indeed work!
What does the D prefix do?

Per docs above, the -D <name> flag means to GCC that a (global) define is added when each file is compiled. So instead of having to write it explicitly in the file we can just tell the compiler to auto-add that #define.

1 Like