diff --git a/get-started/csi_recv_router/main/app_main.c b/get-started/csi_recv_router/main/app_main.c index 2189720..ff856d4 100644 --- a/get-started/csi_recv_router/main/app_main.c +++ b/get-started/csi_recv_router/main/app_main.c @@ -33,6 +33,7 @@ #include "esp_task_wdt.h" #include "esp_pm.h" #include "esp_heap_caps.h" +#include "esp_random.h" #include "esp_ota_ops.h" #include "esp_https_ota.h" #include "esp_partition.h" @@ -222,6 +223,8 @@ static int64_t s_alert_heap_last = 0; /* --- NVS helpers --- */ +static esp_err_t config_save_str(const char *key, const char *value); + static void config_load_nvs(void) { /* Start with Kconfig defaults */ @@ -340,6 +343,18 @@ static void config_load_nvs(void) ESP_LOGI(TAG, "NVS: no saved config, using defaults"); } + /* Auto-generate auth secret on first boot */ + if (s_auth_secret[0] == '\0') { + uint8_t rand_bytes[16]; + esp_fill_random(rand_bytes, sizeof(rand_bytes)); + for (int i = 0; i < 16; i++) { + snprintf(s_auth_secret + i * 2, 3, "%02x", rand_bytes[i]); + } + s_auth_secret[32] = '\0'; + config_save_str("auth_secret", s_auth_secret); + ESP_LOGW(TAG, "AUTH: generated secret: %s (note this for remote access)", s_auth_secret); + } + /* Boot counter — always increment, even on first boot */ nvs_handle_t bh; if (nvs_open("csi_config", NVS_READWRITE, &bh) == ESP_OK) { @@ -1437,6 +1452,19 @@ static const char *auth_verify(const char *input, char *reply, size_t reply_size return cmd; } +/* --- Privileged command check --- */ + +static bool cmd_requires_auth(const char *cmd) +{ + if (strncmp(cmd, "OTA ", 4) == 0) return true; + if (strcmp(cmd, "FACTORY") == 0) return true; + if (strcmp(cmd, "REBOOT") == 0) return true; + if (strncmp(cmd, "TARGET ", 7) == 0) return true; + if (strncmp(cmd, "AUTH ", 5) == 0) return true; + if (strncmp(cmd, "HOSTNAME ", 9) == 0) return true; + return false; +} + /* --- Command handler --- */ static void reboot_after_delay(void *arg) @@ -2443,12 +2471,27 @@ static void cmd_task(void *arg) ESP_LOGI(TAG, "CMD rx: \"%s\"", rx_buf); - const char *verified = auth_verify(rx_buf, reply_buf, sizeof(reply_buf)); + /* Authenticate: HMAC grants full access; plain commands are read-only */ + const char *cmd = rx_buf; + bool authed = false; int reply_len; - if (verified) { - reply_len = cmd_handle(verified, reply_buf, sizeof(reply_buf)); - } else { + + if (strncmp(rx_buf, "HMAC:", 5) == 0) { + cmd = auth_verify(rx_buf, reply_buf, sizeof(reply_buf)); + if (cmd) { + authed = true; + } + } else if (s_auth_secret[0] == '\0') { + authed = true; + } + + if (!cmd) { + /* HMAC verification failed — error set by auth_verify */ reply_len = strlen(reply_buf); + } else if (!authed && cmd_requires_auth(cmd)) { + reply_len = snprintf(reply_buf, sizeof(reply_buf), "ERR AUTH required"); + } else { + reply_len = cmd_handle(cmd, reply_buf, sizeof(reply_buf)); } sendto(sock, reply_buf, reply_len, 0, (struct sockaddr *)&src_addr, src_len); diff --git a/get-started/csi_recv_router/sdkconfig.defaults b/get-started/csi_recv_router/sdkconfig.defaults index f40fcf0..1ff04a1 100644 --- a/get-started/csi_recv_router/sdkconfig.defaults +++ b/get-started/csi_recv_router/sdkconfig.defaults @@ -82,3 +82,8 @@ CONFIG_ESP_WIFI_IRAM_OPT=n # CONFIG_PM_ENABLE=y CONFIG_FREERTOS_USE_TICKLESS_IDLE=y + +# +# WiFi Authentication (reject open/WEP APs) +# +CONFIG_EXAMPLE_WIFI_AUTH_WPA2_WPA3_PSK=y