Implement role-aware HTTPS and SSH authentication

This commit is contained in:
2026-08-30 01:31:05 +02:00
parent cd235445c7
commit 0c058b6a8f
16 changed files with 707 additions and 331 deletions
+1 -112
View File
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-3.0-only */
/* Canonical NVS storage for HTTPS identity and shared admin credentials. */
/* Canonical NVS storage for HTTPS identity and legacy recovery credentials. */
#include "web_security.h"
@@ -699,117 +699,6 @@ esp_err_t web_security_copy_tls_material(
return error;
}
esp_err_t web_security_copy_username(char *output, size_t capacity,
size_t *output_length)
{
if (s_security_mutex == NULL) {
return ESP_ERR_INVALID_STATE;
}
xSemaphoreTake(s_security_mutex, portMAX_DELAY);
esp_err_t error = ESP_ERR_INVALID_STATE;
if (s_material_ready) {
if (output_length == NULL || (output == NULL && capacity != 0U)) {
error = ESP_ERR_INVALID_ARG;
} else {
*output_length = s_material.username_length;
if (output == NULL) {
error = capacity == 0U ? ESP_OK : ESP_ERR_INVALID_ARG;
} else if (capacity <= s_material.username_length) {
error = ESP_ERR_INVALID_SIZE;
} else {
memcpy(output, s_material.username, s_material.username_length);
output[s_material.username_length] = '\0';
error = ESP_OK;
}
}
}
xSemaphoreGive(s_security_mutex);
return error;
}
static esp_err_t credential_digest(const uint8_t *username, size_t username_length,
const uint8_t *password, size_t password_length,
uint8_t digest[WEB_SECURITY_SHA256_LENGTH])
{
uint8_t canonical[4U + WEB_SECURITY_USERNAME_CAPACITY +
WEB_SECURITY_PASSWORD_CAPACITY] = {0};
size_t offset = 0U;
canonical[offset++] = (uint8_t)(username_length >> 8U);
canonical[offset++] = (uint8_t)username_length;
if (username_length > 0U) {
memcpy(canonical + offset, username, username_length);
offset += username_length;
}
canonical[offset++] = (uint8_t)(password_length >> 8U);
canonical[offset++] = (uint8_t)password_length;
if (password_length > 0U) {
memcpy(canonical + offset, password, password_length);
offset += password_length;
}
int result = mbedtls_sha256(canonical, offset, digest, 0);
secure_wipe(canonical, sizeof(canonical));
return result == 0 ? ESP_OK : ESP_FAIL;
}
esp_err_t web_security_authenticate_admin(const uint8_t *username,
size_t username_length,
const uint8_t *password,
size_t password_length,
bool *authenticated)
{
if (authenticated == NULL ||
(username == NULL && username_length != 0U) ||
(password == NULL && password_length != 0U)) {
return ESP_ERR_INVALID_ARG;
}
*authenticated = false;
if (s_security_mutex == NULL) {
return ESP_ERR_INVALID_STATE;
}
if (username_length > WEB_SECURITY_USERNAME_CAPACITY ||
password_length > WEB_SECURITY_PASSWORD_CAPACITY) {
return ESP_OK;
}
uint8_t supplied_digest[WEB_SECURITY_SHA256_LENGTH] = {0};
uint8_t expected_digest[WEB_SECURITY_SHA256_LENGTH] = {0};
xSemaphoreTake(s_security_mutex, portMAX_DELAY);
esp_err_t error = ESP_ERR_INVALID_STATE;
if (s_material_ready) {
error = credential_digest(username, username_length,
password, password_length,
supplied_digest);
if (error == ESP_OK) {
error = credential_digest(s_material.username,
s_material.username_length,
s_material.password,
s_material.password_length,
expected_digest);
}
if (error == ESP_OK) {
*authenticated = constant_time_equal(supplied_digest,
expected_digest,
sizeof(expected_digest));
}
}
xSemaphoreGive(s_security_mutex);
secure_wipe(supplied_digest, sizeof(supplied_digest));
secure_wipe(expected_digest, sizeof(expected_digest));
return error;
}
esp_err_t web_security_authenticate_basic(const uint8_t *username,
size_t username_length,
const uint8_t *password,
size_t password_length,
bool *authenticated)
{
return web_security_authenticate_admin(username, username_length,
password, password_length,
authenticated);
}
static void copy_credentials_locked(web_security_credentials_t *credentials,
const web_security_blob_t *blob)