"No-thrills" raw Rust bindings to the 3.X branch of the MbedTLS library.
no_std compatible and thus suitable for use on baremetal MCUs.
- Power
esp-mbedtls- a type-safe, async and blocking API specifically and only for TLS IO (the original purpose of MbedTLS); - Use the generated
.alibs with other C libraries depending onMbedTLScrypto algorithms (e.g. OpenThread) thus taking advantage of the hardware-acceleration capabilities this crate exposes (See "Hooking" below); - Use - from Rust - as a generic library for crypto algorithms (e.g. digests, AES, RSA etc.). Alternative to
RustCrypto.
- Provide type-safe bindings for the crypto algorithms in MbedTLS
- The above use cases are too few and a bit corner-case to justify the effort
(*) NOTE: Name to be changed soon as this crate is no longer ESP-specific.
For user-convenience, the MbedTLS C library also comes pre-built for the following Rust targets:
rsicv32imc-unknown-none-elfrsicv32imac-unknown-none-elfxtensa-esp32-none-elfxtensa-esp32s2-none-elfxtensa-esp32s3-none-elf- (PRs for other Rust baremetal targets appreciated!)
For other MCU baremetal targets as well as for STD platforms, the MbedTLS C library will be compiled on the fly with clang (by default), or with GCC (if the use-gcc feature is enabled).
Note that for the latter, you DO need to have the GCC cross-compiler flavor for your MCU pre-installed and on your $PATH, while with clang ANY clang instance would do, as clang is natively a cross-compiler. clang is anyway always necessary during on-the-fly compilation for the Rust bindings' generation, so that's why it is used by default for compiling the MbedTLS C library as well.
The on-the-fly compilation process also needs cmake and ninja pre-installed (for now).
ESP-IDF is also supported and in that case esp-mbedtls-sys becomes just an alias for esp-idf-sys and uses the MbedTLS library which is built-in inside ESP-IDF.
NOTE:: on-the-fly compilation can be forced by using the force-generate-bindings feature.
Putting aside the new PSA Crypto driver layer, MbedTLS 3.X has a relatively simplistic approach ("_ALT" macros) towards hardware acceleration. Say, you want the SHA-1 algorithm beging accelerated. You then need to:
- Instruct MbedTLS - at C compile-time to compile-out its built-in SHA-1 implementation by defining the
MBEDTLS_SHA1_ALTmacro; - Provide your own mbedtls_sha1_* functions at link time which need to match the signatures of the MbedTLS SHA-1 implementation;
- Provide your own
mbedtls_sha1_contextstructure to MbedTLS - at C compile-time - in a custom C header file (the structure is treated as opaque by MbedTLS).
Needless to say, this is a lot of lift-and-shift for Rust developers, especially if they plan to plug-in Rust-based hardware accelerated routines.
For that reason, esp-mbedtls-sys provides the so called Hooking mechanism. Currently, only for some MbedTLS crypto-functions, but the list is expected to grow a bit possibly including EC curves and AES.
In essence Hooking relies on the "_ALT" functionality in MbedTLS and specifically does the following:
- It replaces e.g. the
mbedtls_sha1_contextof MbedTLS with a custom one which is just a sequence of bytes (called a "work area" throughout esp-mbedtls-sys)- The exact number of bytes of the work area depends on the concrete algorithm being hooked, but the size IS hard-coded yet chosen large enough to be "good enough" for any Rust based HW-accel implementation
- In case the unthinkable happens and the size is not large enough, it must be extended with a PR, or the Rust accel needs to manage its own storage and use the sequence of bytes in
mbedtls_sha1_contextas a pointer of sorts - How the Rust HW accel implementation uses the sequence of bytes is up to the implementation, but the expectation is that it would emplace its own Rust type(s) in there, following the rules of Rust for proper memory allgnment; the
WorkAreatype provided by esp-mbedtls-sys provides helpers for that
- There is a dyn-compatible trait for each hook (algorithm to be HW accelerated) provided by esp-mbedtls-sys that the Rust developer needs to implement. For e.g. SHA-1, the trait is called
MbedtlsSha1. User is expected to call e.g.hook_sha1(&'static dyn MbedtlsSha1)with their own implementation early in their program initialization code- If
hook_XXXis not called for a particular hook algorithm, MbedTLS would function just fine but would fallback to either its own software implementation of the algorithm, or to aRustCryptobased one provided out of the box. Sadly, for most hooks it is just not possible to fallback to the MbedTLS original C software impl, as it is completely erased from the source code when the "_ALT" macro functionality is used
- If
Finally, when hooking stateless algorithms that do their job with a single function call (like mbedtls_mpi_mod_exp), there is no notion of a "work area" as the crypto algorithm does not really have an externally-observable state, in that it finishes all its operation in one go.
Laboriously checking the integer result when calling each mbedtls_* function is deemed unergonomic enough so that esp-mbedtls-sys provides:
- A Rust
core::error::Errorwrapper over the integer codes of MbedTLS:MbedtlsError - A small macro -
merr!that turns MbedTLS error codes into aResult<i32, MbedtlsError>whereOk(i32)is returned for non-negative error codes, andErr(MbedtlsError)is returned for negative error codes
The backwards-incompatible MbedTLS 4.0 released in Oct 2025 finally splits the "I'm a generic library for crypto algorithms" use case from the "I'm a library for doing TLS IO" use case into two separate libraries:
- TF-PSA-Crypto - for "I'm a generic library for crypto algorithms" - implementing the PSA API and having a special new driver layer for HW accel
- MBedTLS - for "I'm a library for doing TLS IO" - and for now - relying specifically on the TF-PSA-Crypto for doing that rather than capable of using any library implementing the PSA API
Whether, and how exactly a migration to MbedTLS 4.0 would happen is still unclear but that's on the table once it starts to see wider use overall.
One way would be to have a new crate - tf-psa-crypto-sys which provides raw bindings to TF-PSA-Crypto (and somehow still does hooking). esp-mbedtls-sys would then only provide bindings for the "I'm a library for doing TLS IO" which is what MBedTLS 4.0 is.