espilon-source/espilon_bot/components/core/WiFi.c
Eun0us 8b6c1cd53d ε - ChaCha20-Poly1305 AEAD + HKDF crypto upgrade + C3PO rewrite + docs
Crypto:
- Replace broken ChaCha20 (static nonce) with ChaCha20-Poly1305 AEAD
- HKDF-SHA256 key derivation from per-device factory NVS master keys
- Random 12-byte nonce per message (ESP32 hardware RNG)
- crypto_init/encrypt/decrypt API with mbedtls legacy (ESP-IDF v5.3.2)
- Custom partition table with factory NVS (fctry at 0x10000)

Firmware:
- crypto.c full rewrite, messages.c device_id prefix + AEAD encrypt
- crypto_init() at boot with esp_restart() on failure
- Fix command_t initializations across all modules (sub/help fields)
- Clean CMakeLists dependencies for ESP-IDF v5.3.2

C3PO (C2):
- Rename tools/c2 + tools/c3po -> tools/C3PO
- Per-device CryptoContext with HKDF key derivation
- KeyStore (keys.json) for master key management
- Transport parses device_id:base64(...) wire format

Tools:
- New tools/provisioning/provision.py for factory NVS key generation
- Updated flasher with mbedtls config for v5.3.2

Docs:
- Update all READMEs for new crypto, C3PO paths, provisioning
- Update roadmap, architecture diagrams, security sections
- Update CONTRIBUTING.md project structure
2026-02-10 21:28:45 +01:00

173 lines
4.5 KiB
C

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "lwip/sockets.h"
#include "lwip/netdb.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "c2.pb.h"
#include "pb_decode.h"
#include "freertos/semphr.h"
#include "utils.h"
int sock = -1;
SemaphoreHandle_t sock_mutex = NULL;
#ifdef CONFIG_NETWORK_WIFI
static const char *TAG = "CORE_WIFI";
#define RX_BUF_SIZE 4096
#define RECONNECT_DELAY_MS 5000
/* =========================================================
* WiFi init
* ========================================================= */
void wifi_init(void)
{
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
esp_netif_create_default_wifi_ap();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
wifi_config_t wifi_config = {
.sta = {
.ssid = CONFIG_WIFI_SSID,
.password = CONFIG_WIFI_PASS,
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(esp_wifi_connect());
ESP_LOGI(TAG, "Connecting to WiFi SSID=%s", CONFIG_WIFI_SSID);
}
/* =========================================================
* TCP connect
* ========================================================= */
static bool tcp_connect(void)
{
struct sockaddr_in server_addr = {0};
int new_sock = lwip_socket(AF_INET, SOCK_STREAM, 0);
if (new_sock < 0) {
ESP_LOGE(TAG, "socket() failed");
return false;
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(CONFIG_SERVER_PORT);
server_addr.sin_addr.s_addr = inet_addr(CONFIG_SERVER_IP);
if (lwip_connect(new_sock,
(struct sockaddr *)&server_addr,
sizeof(server_addr)) != 0) {
ESP_LOGE(TAG, "connect() failed");
lwip_close(new_sock);
return false;
}
xSemaphoreTake(sock_mutex, portMAX_DELAY);
sock = new_sock;
xSemaphoreGive(sock_mutex);
ESP_LOGI(TAG, "Connected to %s:%d",
CONFIG_SERVER_IP,
CONFIG_SERVER_PORT);
return true;
}
/* =========================================================
* Handle incoming frame
* ========================================================= */
static void handle_frame(const uint8_t *buf, size_t len)
{
if (len == 0 || len >= RX_BUF_SIZE) {
ESP_LOGW(TAG, "Frame too large or empty (%d bytes), dropping", (int)len);
return;
}
/* buf is already null-terminated by strtok in tcp_rx_loop,
and c2_decode_and_exec makes its own 1024-byte copy. */
c2_decode_and_exec((const char *)buf);
}
/* =========================================================
* TCP RX loop
* ========================================================= */
static void tcp_rx_loop(void)
{
static uint8_t rx_buf[RX_BUF_SIZE];
xSemaphoreTake(sock_mutex, portMAX_DELAY);
int current_sock = sock;
xSemaphoreGive(sock_mutex);
if (current_sock < 0) return;
int len = lwip_recv(current_sock, rx_buf, sizeof(rx_buf) - 1, 0);
if (len <= 0) {
ESP_LOGW(TAG, "RX failed / disconnected");
xSemaphoreTake(sock_mutex, portMAX_DELAY);
lwip_close(sock);
sock = -1;
xSemaphoreGive(sock_mutex);
return;
}
/* IMPORTANT: string termination for strtok */
rx_buf[len] = '\0';
char *line = strtok((char *)rx_buf, "\n");
while (line) {
handle_frame((uint8_t *)line, strlen(line));
line = strtok(NULL, "\n");
}
}
/* =========================================================
* Main TCP client task
* ========================================================= */
void tcp_client_task(void *pvParameters)
{
if (!sock_mutex)
sock_mutex = xSemaphoreCreateMutex();
while (1) {
if (!tcp_connect()) {
vTaskDelay(pdMS_TO_TICKS(RECONNECT_DELAY_MS));
continue;
}
msg_info(TAG, CONFIG_DEVICE_ID, NULL);
ESP_LOGI(TAG, "Handshake done");
while (sock >= 0) {
tcp_rx_loop();
vTaskDelay(1);
}
ESP_LOGW(TAG, "Disconnected, retrying...");
vTaskDelay(pdMS_TO_TICKS(RECONNECT_DELAY_MS));
}
}
#endif /* CONFIG_NETWORK_WIFI */