Add Authenticated HTTPS Admin Foundation
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
/* SPDX-License-Identifier: GPL-3.0-only */
|
||||
/* Pre-radio seeding and serialized access to the device-wide CTR_DRBG. */
|
||||
|
||||
#include "secure_random.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "bootloader_random.h"
|
||||
#include "esp_random.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
|
||||
static SemaphoreHandle_t s_random_mutex;
|
||||
static mbedtls_ctr_drbg_context s_drbg;
|
||||
static bool s_drbg_ready;
|
||||
static uint32_t s_generate_calls;
|
||||
|
||||
static int pre_radio_entropy(void *context, unsigned char *output, size_t length)
|
||||
{
|
||||
(void)context;
|
||||
|
||||
/* This callback is deliberately reachable only from secure_random_init(). */
|
||||
bootloader_random_enable();
|
||||
esp_fill_random(output, length);
|
||||
bootloader_random_disable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
esp_err_t secure_random_init(void)
|
||||
{
|
||||
static const unsigned char personalization[] =
|
||||
"esp32-serial-swiss-army-knife";
|
||||
|
||||
if (s_drbg_ready) {
|
||||
return ESP_OK;
|
||||
}
|
||||
if (s_random_mutex == NULL) {
|
||||
s_random_mutex = xSemaphoreCreateMutex();
|
||||
if (s_random_mutex == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
}
|
||||
|
||||
xSemaphoreTake(s_random_mutex, portMAX_DELAY);
|
||||
esp_err_t error = ESP_OK;
|
||||
if (!s_drbg_ready) {
|
||||
mbedtls_ctr_drbg_init(&s_drbg);
|
||||
int result = mbedtls_ctr_drbg_seed(&s_drbg,
|
||||
pre_radio_entropy,
|
||||
NULL,
|
||||
personalization,
|
||||
sizeof(personalization) - 1U);
|
||||
if (result == 0) {
|
||||
/* Reseeding would re-enter a pre-radio-only entropy path after RF starts. */
|
||||
mbedtls_ctr_drbg_set_reseed_interval(&s_drbg, INT_MAX);
|
||||
s_generate_calls = 0U;
|
||||
s_drbg_ready = true;
|
||||
} else {
|
||||
mbedtls_ctr_drbg_free(&s_drbg);
|
||||
error = ESP_FAIL;
|
||||
}
|
||||
}
|
||||
xSemaphoreGive(s_random_mutex);
|
||||
return error;
|
||||
}
|
||||
|
||||
esp_err_t secure_random_fill(void *output, size_t length)
|
||||
{
|
||||
if (length == 0U) {
|
||||
return ESP_OK;
|
||||
}
|
||||
if (output == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (!s_drbg_ready || s_random_mutex == NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
unsigned char *cursor = (unsigned char *)output;
|
||||
esp_err_t error = ESP_OK;
|
||||
|
||||
xSemaphoreTake(s_random_mutex, portMAX_DELAY);
|
||||
while (length > 0U) {
|
||||
/* CTR_DRBG limits each request even though the public API need not. */
|
||||
size_t chunk = length;
|
||||
if (chunk > MBEDTLS_CTR_DRBG_MAX_REQUEST) {
|
||||
chunk = MBEDTLS_CTR_DRBG_MAX_REQUEST;
|
||||
}
|
||||
/*
|
||||
* Mbed TLS stores its reseed counter in a signed int. Fail closed one
|
||||
* call before INT_MAX so it can neither overflow nor invoke the
|
||||
* pre-radio-only entropy callback during the device's lifetime.
|
||||
*/
|
||||
if (s_generate_calls >= (uint32_t)INT_MAX - 1U) {
|
||||
error = ESP_ERR_INVALID_STATE;
|
||||
break;
|
||||
}
|
||||
if (mbedtls_ctr_drbg_random(&s_drbg, cursor, chunk) != 0) {
|
||||
error = ESP_FAIL;
|
||||
break;
|
||||
}
|
||||
++s_generate_calls;
|
||||
cursor += chunk;
|
||||
length -= chunk;
|
||||
}
|
||||
xSemaphoreGive(s_random_mutex);
|
||||
return error;
|
||||
}
|
||||
|
||||
int secure_random_mbedtls(void *context, unsigned char *output, size_t length)
|
||||
{
|
||||
(void)context;
|
||||
return secure_random_fill(output, length) == ESP_OK
|
||||
? 0
|
||||
: MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED;
|
||||
}
|
||||
|
||||
void secure_wipe(void *data, size_t size)
|
||||
{
|
||||
volatile uint8_t *byte = (volatile uint8_t *)data;
|
||||
|
||||
if (byte == NULL) {
|
||||
return;
|
||||
}
|
||||
while (size-- > 0U) {
|
||||
*byte++ = 0U;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user