Skip to content

Commit

Permalink
Move mbedtls entropy and random ctx init to platform specific code
Browse files Browse the repository at this point in the history
Define also sys_mbedtls.h header and sys_mbedtls_get_entropy_context_lock and
sys_mbedtls_get_ctr_drbg_context_lock functions.

Signed-off-by: Davide Bettio <davide@uninstall.it>
  • Loading branch information
bettio committed Dec 5, 2023
1 parent 67874ce commit 2052e3d
Show file tree
Hide file tree
Showing 8 changed files with 402 additions and 23 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
generic_unix, ESP32 and RP2040 platforms.

### Added

Expand All @@ -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
- Added `crypto:strong_rand_bytes/1` using Mbed-TLS (only on generic_unix, ESP32 and RP2040
platforms)

### Removed

Expand Down
31 changes: 10 additions & 21 deletions src/libAtomVM/otp_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <globalcontext.h>
#include <interop.h>
#include <nifs.h>
#include <sys_mbedtls.h>
#include <term.h>
#include <term_typedef.h>

Expand Down Expand Up @@ -575,35 +576,23 @@ term nif_crypto_strong_rand_bytes(Context *ctx, int argc, term argv[])
RAISE_ERROR(BADARG_ATOM);
}

static bool initialized = false;
static mbedtls_entropy_context entropy_ctx;
static mbedtls_ctr_drbg_context rnd_ctx;

if (!initialized) {
mbedtls_entropy_init(&entropy_ctx);

mbedtls_ctr_drbg_init(&rnd_ctx);

const char *seed = "AtomVM Mbed-TLS initial seed.";
int seed_len = strlen(seed);
int seed_err = mbedtls_ctr_drbg_seed(
&rnd_ctx, mbedtls_entropy_func, &entropy_ctx, (const unsigned char *) seed, seed_len);
if (UNLIKELY(seed_err != 0)) {
abort();
}
}

int ensure_size = term_binary_heap_size(out_len);
if (UNLIKELY(memory_ensure_free(ctx, ensure_size) != MEMORY_GC_OK)) {
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}

mbedtls_ctr_drbg_context *rnd_ctx = sys_mbedtls_get_ctr_drbg_context_lock(ctx->global);
if (IS_NULL_PTR(rnd_ctx)) {
RAISE_ERROR(make_crypto_error(__FILE__, __LINE__, "Failed CTR_DRBG init", ctx));
}

term out_bin = term_create_uninitialized_binary(out_len, &ctx->heap, ctx->global);
unsigned char *out = (unsigned char *) term_binary_data(out_bin);

int err = mbedtls_ctr_drbg_random(&rnd_ctx, out, out_len);
if (err != 0) {
abort();
int err = mbedtls_ctr_drbg_random(rnd_ctx, out, out_len);
sys_mbedtls_ctr_drbg_context_unlock(ctx->global);
if (UNLIKELY(err != 0)) {
RAISE_ERROR(make_crypto_error(__FILE__, __LINE__, "Failed random", ctx));
}

return out_bin;
Expand Down
38 changes: 38 additions & 0 deletions src/libAtomVM/sys_mbedtls.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* This file is part of AtomVM.
*
* Copyright 2023 Davide Bettio <davide@uninstall.it>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
*/

#ifndef _SYS_MBEDTLS_H_
#define _SYS_MBEDTLS_H_

#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>

mbedtls_entropy_context *sys_mbedtls_get_entropy_context_lock(GlobalContext *global);
void sys_mbedtls_entropy_context_unlock(GlobalContext *global);
int sys_mbedtls_entropy_func(void *entropy, unsigned char *buf, size_t size);

mbedtls_ctr_drbg_context *sys_mbedtls_get_ctr_drbg_context_lock(GlobalContext *global);

/**
* @warning do not call this function when already owning the entropy context
*/
void sys_mbedtls_ctr_drbg_context_unlock(GlobalContext *global);

#endif
20 changes: 20 additions & 0 deletions src/platforms/esp32/components/avm_sys/include/esp32_sys.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,17 @@
#include <spi_flash_mmap.h>
#endif

#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>

#include <sys/poll.h>
#include <stdbool.h>
#include <time.h>

#ifndef AVM_NO_SMP
#include "smp.h"
#endif

#include "sys.h"

#define REGISTER_PORT_DRIVER(NAME, INIT_CB, DESTROY_CB, CREATE_CB) \
Expand Down Expand Up @@ -94,6 +102,18 @@ struct ESP32PlatformData
EventListener *socket_listener;
struct SyncList sockets;
struct ListHead ready_connections;

#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);
Expand Down
99 changes: 99 additions & 0 deletions src/platforms/esp32/components/avm_sys/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,27 @@
#include "soc/soc_caps.h"
#endif

#if defined(MBEDTLS_VERSION_NUMBER) && (MBEDTLS_VERSION_NUMBER >= 0x03000000)
#include <mbedtls/build_info.h>
#else
#include <mbedtls/config.h>
#endif

// Platform uses listeners
#include "listeners.h"

#define EVENT_QUEUE_LEN 16

#define TAG "sys"

#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

static Context *port_driver_create_port(const char *port_name, GlobalContext *global, term opts);

static void *select_thread_loop(void *);
Expand Down Expand Up @@ -241,6 +255,9 @@ void sys_init_platform(GlobalContext *glb)
AVM_ABORT();
}
#endif

platform->entropy_is_initialized = false;
platform->random_is_initialized = false;
}

void sys_free_platform(GlobalContext *glb)
Expand All @@ -256,6 +273,15 @@ void sys_free_platform(GlobalContext *glb)
AVM_ABORT();
}
}

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);
}

Expand Down Expand Up @@ -759,3 +785,76 @@ term esp_err_to_term(GlobalContext *glb, esp_err_t status)
return term_from_int(status);
}
}

int sys_mbedtls_entropy_func(void *entropy, unsigned char *buf, size_t size)
{
#ifndef MBEDTLS_THREADING_C
struct ESP32PlatformData *platform
= CONTAINER_OF(entropy, struct ESP32PlatformData, 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 ESP32PlatformData *platform = global->platform_data;

SMP_MUTEX_LOCK(platform->entropy_mutex);

if (!platform->entropy_is_initialized) {
// mbedtls_entropy_init will gather entropy for us using esp_fill_random()
// however it will be pseudorandom when wifi/bluetooth/RF is not enabled.
//
// TODO: when radio is not active bootloader_random_enable() must be enabled for gathering
// entropy. However, "enable function is not safe to use if any other subsystem is
// accessing the RF subsystem or the ADC at the same time".
mbedtls_entropy_init(&platform->entropy_ctx);
platform->entropy_is_initialized = true;
}

return &platform->entropy_ctx;
}

void sys_mbedtls_entropy_context_unlock(GlobalContext *global)
{
struct ESP32PlatformData *platform = global->platform_data;
SMP_MUTEX_UNLOCK(platform->entropy_mutex);
}

mbedtls_ctr_drbg_context *sys_mbedtls_get_ctr_drbg_context_lock(GlobalContext *global)
{
struct ESP32PlatformData *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 ESP32 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 ESP32PlatformData *platform = global->platform_data;
SMP_MUTEX_UNLOCK(platform->random_mutex);
}
Loading

0 comments on commit 2052e3d

Please sign in to comment.