/* SPDX-License-Identifier: GPL-3.0-only */ /* Persistent HTTPS identity and shared network-administration credentials. */ #pragma once #include #include #include #include "esp_err.h" #ifdef __cplusplus extern "C" { #endif #define WEB_SECURITY_NVS_NAMESPACE "web_sec" #define WEB_SECURITY_NVS_BLOB_KEY "material" #define WEB_SECURITY_USERNAME_CAPACITY 16U #define WEB_SECURITY_PASSWORD_CAPACITY 32U #define WEB_SECURITY_PASSWORD_LENGTH 24U #define WEB_SECURITY_PRIVATE_KEY_DER_CAPACITY 256U #define WEB_SECURITY_CERTIFICATE_DER_CAPACITY 1024U #define WEB_SECURITY_SHA256_LENGTH 32U #define WEB_SECURITY_COMMON_NAME_CAPACITY 32U #define WEB_SECURITY_DNS_NAME_CAPACITY 40U #define WEB_SECURITY_CERT_NOT_BEFORE "20250101000000" #define WEB_SECURITY_CERT_NOT_AFTER "20491231235959" typedef enum { WEB_SECURITY_LOAD_STORED = 0, WEB_SECURITY_LOAD_GENERATED_MISSING = 1, } web_security_load_result_t; /* * This intentionally contains a displayable secret. UART callers should call * secure_wipe() on it immediately after rendering the length-delimited fields. */ typedef struct { size_t username_length; size_t password_length; char username[WEB_SECURITY_USERNAME_CAPACITY + 1U]; char password[WEB_SECURITY_PASSWORD_CAPACITY + 1U]; } web_security_credentials_t; typedef struct { uint32_t material_generation; uint8_t sha256_fingerprint[WEB_SECURITY_SHA256_LENGTH]; char common_name[WEB_SECURITY_COMMON_NAME_CAPACITY]; char dns_name[WEB_SECURITY_DNS_NAME_CAPACITY]; uint8_t ipv4_address[4]; char not_before[sizeof(WEB_SECURITY_CERT_NOT_BEFORE)]; char not_after[sizeof(WEB_SECURITY_CERT_NOT_AFTER)]; } web_security_certificate_metadata_t; /* * NVS must already be initialized. Missing material is generated and saved; * an existing wrong-version blob returns ESP_ERR_INVALID_VERSION, while any * malformed or cryptographically inconsistent blob returns * ESP_ERR_INVALID_RESPONSE and is never overwritten. Call before radio startup * so secure_random_init() can seed from the pre-radio entropy source. */ esp_err_t web_security_init(web_security_load_result_t *load_result); /* * Query with both outputs NULL/capacities zero. Certificate and key are copied * under one lock so a concurrent rotation can never produce a mismatched pair. */ esp_err_t web_security_copy_tls_material( uint8_t *certificate, size_t certificate_capacity, size_t *certificate_length, uint8_t *private_key, size_t private_key_capacity, size_t *private_key_length); esp_err_t web_security_copy_username(char *output, size_t capacity, size_t *output_length); /* Protocol-neutral authentication for the shared HTTPS and SSH administrator. */ 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); /* Compatibility name for decoded HTTP Basic components. */ 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); /* Explicit secret-bearing API intended for a physically attached UART CLI. */ esp_err_t web_security_show_credentials(web_security_credentials_t *credentials); esp_err_t web_security_get_certificate_metadata( web_security_certificate_metadata_t *metadata); /* Mutations become visible only after a complete blob has committed to NVS. */ esp_err_t web_security_rotate_credentials(web_security_credentials_t *new_credentials); esp_err_t web_security_rotate_certificate(void); /* Explicitly replaces missing, valid, or incompatible stored material. */ esp_err_t web_security_reset_all(web_security_credentials_t *new_credentials); #ifdef __cplusplus } #endif