diff --git a/CHANGELOG.md b/CHANGELOG.md index d8be68f3e4..2897e0ec47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Crypto functions on generic_unix platform now rely on MbedTLS instead of OpenSSL - Platform function providing time used by timers was changed from `sys_monotonic_millis` to `sys_monotonic_time_u64`, `sys_monotonic_time_u64_to_ms` and `sys_monotonic_time_ms_to_u64`. - Implement `atomvm:random/0` and `atomvm:rand_bytes/1` on top of `crypto:strong_rand_bytes/1` on - generic_unix platform and ESP32 + generic_unix, ESP32 and RP2040 platforms. ### Added @@ -41,7 +41,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added support for `crypto:one_time/4,5` on Unix and Pico as well as for `crypto:hash/2` on Pico - Added ability to configure STM32 Nucleo boards onboard UART->USB-COM using the `-DBOARD=nucleo` cmake option - Added STM32 cmake option `-DAVM_CFG_CONSOLE=` to select a different uart peripheral for the system console -- Added `crypto:strong_rand_bytes/1` using Mbed-TLS (only on generic_unix and ESP32 platforms) +- Added `crypto:strong_rand_bytes/1` using Mbed-TLS (only on generic_unix, ESP32 and RP2040 + platforms) ### Removed diff --git a/src/platforms/rp2040/src/lib/rp2040_sys.h b/src/platforms/rp2040/src/lib/rp2040_sys.h index 58917ce723..0b3b74c801 100644 --- a/src/platforms/rp2040/src/lib/rp2040_sys.h +++ b/src/platforms/rp2040/src/lib/rp2040_sys.h @@ -30,6 +30,9 @@ #include #include +#include +#include + #pragma GCC diagnostic pop #include "sys.h" @@ -112,6 +115,18 @@ struct RP2040PlatformData cond_t event_poll_cond; #endif queue_t event_queue; + +#ifndef AVM_NO_SMP + Mutex *entropy_mutex; +#endif + mbedtls_entropy_context entropy_ctx; + bool entropy_is_initialized; + +#ifndef AVM_NO_SMP + Mutex *random_mutex; +#endif + mbedtls_ctr_drbg_context random_ctx; + bool random_is_initialized; }; typedef void (*port_driver_init_t)(GlobalContext *global); diff --git a/src/platforms/rp2040/src/lib/sys.c b/src/platforms/rp2040/src/lib/sys.c index f2702923d8..256bdc16c8 100644 --- a/src/platforms/rp2040/src/lib/sys.c +++ b/src/platforms/rp2040/src/lib/sys.c @@ -44,6 +44,12 @@ #include #endif +#if defined(MBEDTLS_VERSION_NUMBER) && (MBEDTLS_VERSION_NUMBER >= 0x03000000) +#include +#else +#include +#endif + // libAtomVM #include #include @@ -57,6 +63,14 @@ // Platform uses listeners #include "listeners.h" +#ifndef AVM_NO_SMP +#define SMP_MUTEX_LOCK(mtx) smp_mutex_lock(mtx) +#define SMP_MUTEX_UNLOCK(mtx) smp_mutex_unlock(mtx) +#else +#define SMP_MUTEX_LOCK(mtx) +#define SMP_MUTEX_UNLOCK(mtx) +#endif + struct PortDriverDefListItem *port_driver_list; struct NifCollectionDefListItem *nif_collection_list; @@ -75,6 +89,9 @@ void sys_init_platform(GlobalContext *glb) cyw43_arch_init(); otp_socket_init(glb); #endif + + platform->entropy_is_initialized = false; + platform->random_is_initialized = false; } void sys_free_platform(GlobalContext *glb) @@ -85,6 +102,15 @@ void sys_free_platform(GlobalContext *glb) struct RP2040PlatformData *platform = glb->platform_data; queue_free(&platform->event_queue); + + if (platform->random_is_initialized) { + mbedtls_ctr_drbg_free(&platform->random_ctx); + } + + if (platform->entropy_is_initialized) { + mbedtls_entropy_free(&platform->entropy_ctx); + } + free(platform); #ifndef AVM_NO_SMP @@ -387,3 +413,70 @@ void sys_unregister_listener_from_event(GlobalContext *global, listener_event_t } synclist_unlock(&global->listeners); } + +int sys_mbedtls_entropy_func(void *entropy, unsigned char *buf, size_t size) +{ +#ifndef MBEDTLS_THREADING_C + struct RP2040PlatformData *platform + = CONTAINER_OF(entropy, struct RP2040PlatformData, entropy_ctx); + SMP_MUTEX_LOCK(platform->entropy_mutex); + int result = mbedtls_entropy_func(entropy, buf, size); + SMP_MUTEX_UNLOCK(platform->entropy_mutex); + + return result; +#else + return mbedtls_entropy_func(entropy, buf, size); +#endif +} + +mbedtls_entropy_context *sys_mbedtls_get_entropy_context_lock(GlobalContext *global) +{ + struct RP2040PlatformData *platform = global->platform_data; + + SMP_MUTEX_LOCK(platform->entropy_mutex); + + if (!platform->entropy_is_initialized) { + mbedtls_entropy_init(&platform->entropy_ctx); + platform->entropy_is_initialized = true; + } + + return &platform->entropy_ctx; +} + +void sys_mbedtls_entropy_context_unlock(GlobalContext *global) +{ + struct RP2040PlatformData *platform = global->platform_data; + SMP_MUTEX_UNLOCK(platform->entropy_mutex); +} + +mbedtls_ctr_drbg_context *sys_mbedtls_get_ctr_drbg_context_lock(GlobalContext *global) +{ + struct RP2040PlatformData *platform = global->platform_data; + + SMP_MUTEX_LOCK(platform->random_mutex); + + if (!platform->random_is_initialized) { + mbedtls_ctr_drbg_init(&platform->random_ctx); + + mbedtls_entropy_context *entropy_ctx = sys_mbedtls_get_entropy_context_lock(global); + // Safe to unlock it now, sys_mbedtls_entropy_func will lock it again later + sys_mbedtls_entropy_context_unlock(global); + + const char *seed = "AtomVM RP2040 Mbed-TLS initial seed."; + int seed_len = strlen(seed); + int seed_err = mbedtls_ctr_drbg_seed(&platform->random_ctx, sys_mbedtls_entropy_func, + entropy_ctx, (const unsigned char *) seed, seed_len); + if (UNLIKELY(seed_err != 0)) { + abort(); + } + platform->random_is_initialized = true; + } + + return &platform->random_ctx; +} + +void sys_mbedtls_ctr_drbg_context_unlock(GlobalContext *global) +{ + struct RP2040PlatformData *platform = global->platform_data; + SMP_MUTEX_UNLOCK(platform->random_mutex); +}