Skip to content

feat: build against mbedtls-rs-sys#64

Draft
scootermon wants to merge 4 commits intoesp-rs:mainfrom
inomotech-foss:feat/external-mbedtls
Draft

feat: build against mbedtls-rs-sys#64
scootermon wants to merge 4 commits intoesp-rs:mainfrom
inomotech-foss:feat/external-mbedtls

Conversation

@scootermon
Copy link
Contributor

@scootermon scootermon commented Mar 7, 2026

See: esp-rs/mbedtls-rs#111

Closes: #61

I tested this using the good old SRP example and everything appears to be working nicely :)

EDIT: Patch no longer needed due to submodule update.

See #64 (comment)

This currently requires a patch to the openthread submodule:

diff --git a/src/core/crypto/mbedtls.cpp b/src/core/crypto/mbedtls.cpp
index 11d39dd21..a05d5cbe1 100644
--- a/src/core/crypto/mbedtls.cpp
+++ b/src/core/crypto/mbedtls.cpp
@@ -46,6 +46,7 @@
 #include "common/code_utils.hpp"
 #include "common/error.hpp"
 #include "common/heap.hpp"
+#include "common/logging.hpp"
 #include "common/random.hpp"
 
 namespace ot {

This is because our mbedtls is compiled with MBEDTLS_DEBUG_C enabled.
Apparently this hasn't been tested in a while. This define causes OpenThread's code to use OPENTHREAD_CONFIG_LOG_LEVEL, which is undefined without the include.

We probably want to disable the debug stuff for release builds anyway, but we should still fix this issue in OT's code.

@scootermon
Copy link
Contributor Author

scootermon commented Mar 7, 2026

So apparently the build issue has already been fixed upstream in openthread/openthread#11766. This PR was merged about a month after the 2025-06-12 reference tag :/

EDIT: Now the CI is unhappy because it managed to uncover a latent issue in the mbedtls-rs code :) See: esp-rs/mbedtls-rs#113

@scootermon
Copy link
Contributor Author

scootermon commented Mar 8, 2026

So OpenThread configures its vendored MbedTLS to use the OT heap (which is backed by a static variable).
Our MbedTLS currently simply relies on the global calloc / free.

Since we want to allow mbedtls-rs to remain general purpose I feel like we should use the following approach:

Compile mbedtls with MBEDTLS_PLATFORM_MEMORY. This removes the need for calloc and free from mbedtls. Instead, it now relies on us calling mbedtls_platform_set_calloc_free to provide these functions. This is exactly what OT already does with its vendored copy of mbedtls!

In an ideal world we could now offer the option to attach mbedtls to the OT heap again using mbedtls_platform_set_calloc_free(Heap::CAlloc, Heap::Free). Unfortunately Heap::CAlloc and Heap::Free are OT internal functions. There are no public C bindings for OT's heap.

So step two is then to also tell OT OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE, which replaces its own heap implementation with otPlatCAlloc and otPlatFree. This allows us to fully shift the dynamic memory management into Rust and gives full control to the user without having to fuss around with compile-time options.
The user could decide to use the global allocator for both mbedtls and OT, or a dedicated buffer-backed allocator for each of them.

This will be quite the undertaking, so as an intermediary solution we can start with only enabling MBEDTLS_PLATFORM_MEMORY and telling OT to take ownership of mbedtls by setting OPENTHREAD_CONFIG_ENABLE_BUILTIN_MBEDTLS_MANAGEMENT. This define controls whether OT ends up injecting its allocation functions into mbedtls:

https://github.com/openthread/openthread/blob/1b43fe6694d6c13ab02648a94fa138534b27dd56/src/core/crypto/mbedtls.cpp#L62-L64

@ivmarkov
Copy link
Collaborator

This will be quite the undertaking, so as an intermediary solution we can start with only enabling MBEDTLS_PLATFORM_MEMORY and telling OT to take ownership of mbedtls by setting OPENTHREAD_CONFIG_ENABLE_BUILTIN_MBEDTLS_MANAGEMENT. This define controls whether OT ends up injecting its allocation functions into mbedtls:

I agree with that.
Enabling MBEDTLS_PLATFORM_MEMORY by default in mbedtls-rs-sys should be harmless, because if the user doesn't call mbedtls_platform_set_calloc_free explicitly, by default mbedtls_calloc / mbedtls_free would resolve to the platform calloc / free (because we DON'T enable MBEDTLS_PLATFORM_NO_STD_FUNCTIONS).

@scootermon scootermon force-pushed the feat/external-mbedtls branch from 18c5008 to 1d3ebdc Compare March 12, 2026 15:46
@scootermon scootermon force-pushed the feat/external-mbedtls branch from 1d3ebdc to 01a1928 Compare March 12, 2026 15:57
@scootermon
Copy link
Contributor Author

Enabling MBEDTLS_PLATFORM_MEMORY by default in mbedtls-rs-sys should be harmless, because if the user doesn't call mbedtls_platform_set_calloc_free explicitly, by default mbedtls_calloc / mbedtls_free would resolve to the platform calloc / free (because we DON'T enable MBEDTLS_PLATFORM_NO_STD_FUNCTIONS).

Without MBEDTLS_PLATFORM_NO_STD_FUNCTIONS we're still forced to provide calloc and free at link time. For NRF using tinyrlibc this means we're force to define a global allocator despite knowing it will never be used.

…5722cc

This is the merge commit that includes the compilation fix.
We don't end up using these symbols at runtime as they get
replaced by the OpenThread implementation. But they need to exist
at link time to satisfy the linker.
@scootermon scootermon force-pushed the feat/external-mbedtls branch from 01a1928 to d66b83c Compare March 12, 2026 17:35
@ivmarkov
Copy link
Collaborator

ivmarkov commented Mar 12, 2026

Enabling MBEDTLS_PLATFORM_MEMORY by default in mbedtls-rs-sys should be harmless, because if the user doesn't call mbedtls_platform_set_calloc_free explicitly, by default mbedtls_calloc / mbedtls_free would resolve to the platform calloc / free (because we DON'T enable MBEDTLS_PLATFORM_NO_STD_FUNCTIONS).

Without MBEDTLS_PLATFORM_NO_STD_FUNCTIONS we're still forced to provide calloc and free at link time. For NRF using tinyrlibc this means we're force to define a global allocator despite knowing it will never be used.

Hm, yeah you are right.
I guess we then need to enable MBEDTLS_PLATFORM_NO_STD_FUNCTIONS by default and see what would break / not work?
The calloc/free case is clear, and it is very easy to polyfill/fix buy the user - she just needs to call mbedtls_set_calloc_free with their own calloc/free which can be the tinyrlibc ones.

But what other calls need to be explicitly done? Ideally, just this one ^^^. the *printf stuff is stubbed out with empty ones, I think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Compile against mbedtls-rs-sys crate instead of using openthread's vendored version

2 participants