From 4fbe58f736eba87c8216071f628f7445e5ffbc4d Mon Sep 17 00:00:00 2001 From: ruv Date: Fri, 11 Sep 2026 09:19:33 -0400 Subject: [PATCH] fix(firmware): keep onboarding digest compatible with ESP-IDF 6 --- ...DR-348-native-macos-usb-node-onboarding.md | 24 +++++++++++++++---- .../2026-08-31-macos-usb-node-onboarding.md | 14 +++++++++-- firmware/esp32-csi-node/README.md | 8 +++++-- .../esp32-csi-node/main/serial_onboarding.c | 22 ++++++++++------- 4 files changed, 50 insertions(+), 18 deletions(-) diff --git a/docs/adr/ADR-348-native-macos-usb-node-onboarding.md b/docs/adr/ADR-348-native-macos-usb-node-onboarding.md index 400a4ccc..f1bb9652 100644 --- a/docs/adr/ADR-348-native-macos-usb-node-onboarding.md +++ b/docs/adr/ADR-348-native-macos-usb-node-onboarding.md @@ -2,9 +2,9 @@ ## Status -Accepted and physically qualified with one attached ESP32 S3 and an unsigned -Mac Catalyst development build. ESP32 C6 qualification and signed distribution -remain release gates. +Accepted and physically qualified with one attached ESP32 S3 and one attached +ESP32 C6 through an unsigned Mac Catalyst development build. Signed +distribution remains a release gate. ## Context @@ -20,7 +20,7 @@ application diagnostics or provisioning receipts. ## Decision -1. Firmware 0.8.9 adds a bounded line protocol over the physical USB serial +1. Firmware 0.8.12 provides a bounded line protocol over the physical USB serial channel. A discovery request carries a random 128 bit nonce. The device response binds that nonce to chip family, firmware version, current node identity, private server target, configuration state, and a pseudonymous @@ -52,6 +52,14 @@ application diagnostics or provisioning receipts. exact chip and port check, a private backup, a matching image, and captured boot evidence. Release publication remains a separate maintainer action. +8. The device digest uses the PSA Crypto SHA 256 interface on ESP IDF 5.4 and + 6.0. This keeps the stable domain separated identity while avoiding the + legacy Mbed TLS hash API removed by ESP IDF 6. + +9. ESP32 C6 mmWave UART defaults use GPIO 4 and GPIO 5. Startup rejects any + configured mmWave pin pair that overlaps the active console RX or TX pins. + This preserves the onboarding input path after a failed mmWave probe. + ## Security and privacy consequences The app gains Mac App Sandbox USB and serial device access, but not general file @@ -67,7 +75,7 @@ rescanned over USB. ## Acceptance test -Connect an ESP32 with firmware 0.8.9 to a Mac that is already receiving RuView +Connect an ESP32 with firmware 0.8.12 to a Mac that is already receiving RuView nodes. Use only the macOS Add Sensor workflow to preserve WiFi, assign the lowest unused identity, and set the Mac private address. Pass when the UI reports the expected chip and firmware, the reassigned node remains fresh for @@ -77,3 +85,9 @@ and no credential appears in app logs or the provisioning receipt. The 2026-08-31 physical run passed on an ESP32 S3. The measured witness is in `docs/validation/2026-08-31-macos-usb-node-onboarding.md`. + +The 2026-09-11 physical run passed on an ESP32 C6 over +`cu.usbserial-3120`. The Mac app flashed the image, received the nonce bound +hello receipt, preserved node identity 3, committed the server route, and +verified fresh server evidence at minus 34 dBm. The run also exposed and fixed +the GPIO 17 console RX conflict described above. diff --git a/docs/validation/2026-08-31-macos-usb-node-onboarding.md b/docs/validation/2026-08-31-macos-usb-node-onboarding.md index f513b5a9..83cc68ca 100644 --- a/docs/validation/2026-08-31-macos-usb-node-onboarding.md +++ b/docs/validation/2026-08-31-macos-usb-node-onboarding.md @@ -46,5 +46,15 @@ firmware image built under ESP-IDF 5.4, and the application image occupied ## Remaining gates -Physical ESP32 C6, new WiFi credential entry, signed Mac distribution, and -cross platform serial bridges remain unmeasured. +New WiFi credential entry, signed Mac distribution, and cross platform serial +bridges remain unmeasured. + +## ESP32 C6 follow up + +On 2026-09-11, an ESP32 C6 on `cu.usbserial-3120` completed the Mac app flash, +hello, configure, and verify sequence with firmware 0.8.12. The app preserved +the existing node identity 3 and verified fresh sensing server evidence at +minus 34 dBm. The board returned `RUVIEW_HELLO_OK_V1` within the bounded serial +exchange after the C6 mmWave defaults moved from the UART0 RX conflict on GPIO +17 to GPIO 4 and GPIO 5. This closes only the physical C6 onboarding gate. It +does not qualify new WiFi credential entry or signed distribution. diff --git a/firmware/esp32-csi-node/README.md b/firmware/esp32-csi-node/README.md index 28c0833b..1e5e7081 100644 --- a/firmware/esp32-csi-node/README.md +++ b/firmware/esp32-csi-node/README.md @@ -19,9 +19,9 @@ This firmware captures WiFi Channel State Information (CSI) from an ESP32-S3 (pr > | **Fall detection** | Phase acceleration threshold | Configurable sensitivity | > | **Programmable sensing** | WASM modules loaded over HTTP | Hot-swap, no reflash | -## Development firmware 0.8.9: guided Mac onboarding +## Firmware 0.8.12: guided Mac onboarding -The unreleased 0.8.9 source adds the protocol used by the RuView macOS Add +Firmware 0.8.12 adds the protocol used by the RuView macOS Add Sensor workflow. A directly attached S3 or C6 can identify itself through a nonce bound USB serial receipt, preserve its current WiFi settings, accept an unused node ID and private LAN server address, then reboot. The Mac app does @@ -34,6 +34,10 @@ credentials are bounded, committed only in NVS, and never included in the receipt or diagnostic output. See [ADR 348](../../docs/adr/ADR-348-native-macos-usb-node-onboarding.md). +On ESP32 C6, the default optional mmWave UART uses GPIO 4 and GPIO 5. Firmware +refuses any mmWave configuration that overlaps the active console pins. This +prevents a sensor probe from taking over UART0 RX and disabling Mac onboarding. + ## Firmware 0.8.8 in plain language Release 0.8.8 makes the sensing stream more internally consistent and easier diff --git a/firmware/esp32-csi-node/main/serial_onboarding.c b/firmware/esp32-csi-node/main/serial_onboarding.c index af560ddc..2566984d 100644 --- a/firmware/esp32-csi-node/main/serial_onboarding.c +++ b/firmware/esp32-csi-node/main/serial_onboarding.c @@ -16,8 +16,8 @@ #include "esp_timer.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "mbedtls/sha256.h" #include "nvs.h" +#include "psa/crypto.h" static const char *TAG = "serial_onboard"; static nvs_config_t s_current_config; @@ -43,20 +43,24 @@ static void device_digest(char output[17]) uint8_t base_mac[6] = {0}; uint8_t digest[32] = {0}; static const uint8_t domain[] = "ruview-device-v1"; - mbedtls_sha256_context context; - mbedtls_sha256_init(&context); - if (esp_efuse_mac_get_default(base_mac) == ESP_OK && - mbedtls_sha256_starts(&context, 0) == 0 && - mbedtls_sha256_update(&context, domain, sizeof(domain) - 1) == 0 && - mbedtls_sha256_update(&context, base_mac, sizeof(base_mac)) == 0 && - mbedtls_sha256_finish(&context, digest) == 0) { + uint8_t digest_input[sizeof(domain) - 1 + sizeof(base_mac)]; + size_t digest_length = 0; + memcpy(digest_input, domain, sizeof(domain) - 1); + const esp_err_t mac_result = esp_efuse_mac_get_default(base_mac); + if (mac_result == ESP_OK) { + memcpy(digest_input + sizeof(domain) - 1, base_mac, sizeof(base_mac)); + } + if (mac_result == ESP_OK && + psa_crypto_init() == PSA_SUCCESS && + psa_hash_compute(PSA_ALG_SHA_256, digest_input, sizeof(digest_input), + digest, sizeof(digest), &digest_length) == PSA_SUCCESS && + digest_length == sizeof(digest)) { for (size_t index = 0; index < 8; index++) { snprintf(output + index * 2, 3, "%02x", digest[index]); } } else { memcpy(output, "0000000000000000", 17); } - mbedtls_sha256_free(&context); } static void emit_hello(const char *nonce)