From 77e762328092222038a98fe75e2a9276b91ec822 Mon Sep 17 00:00:00 2001 From: Michele Bigi Date: Wed, 19 Aug 2026 17:41:44 +0200 Subject: [PATCH] BLE provisioning: drop PoP (Security0); bump nvs partition 24 KiB -> 64 KiB BLE provisioning used protocomm Security1 with the device serial number as proof-of-possession, on the reasoning that pairing should require reading something off the physical unit. In practice the companion app has no easy way to read that serial without a manual step, so it was deriving the PoP from the BLE advertising name instead (DigiRadio-XXXX -> XXXX) -- but that name is broadcast openly to any scanner, so it was never actually secret. The PoP added app/firmware coupling (an exact-match string derived independently on both sides) without adding real secrecy, and a mismatch there was silently blocking provisioning entirely. Switched to Security0 (no PoP, no encryption) -- the same trust level as the SoftAP setup path this runs alongside, which is already an open network. Separately, bumped the nvs partition from 24 KiB to 64 KiB. The small original size was a suspected contributor to intermittent NvsAudioProfileStore::saveProfile() store_failed under this project's accumulated write traffic (wifi creds, station_list, audio_profile_json, last_preset) -- flagged but not applied in an earlier commit today. otadata/nvs_keys/phy_init shift forward to make room; they still fit before ota_0's existing 64 KiB alignment boundary, so ota_0/ota_1/dsp stay at their original offsets. Applied via idf.py erase-flash flash (required whenever partition offsets move) and verified: fresh boot enters SoftAP + BLE setup mode with no partition-table warnings, and the previously-saved FM ANTCAP calibration (stored in the 24AA025E48 EEPROM, unaffected by the NVS partition change) still applies automatically after re-provisioning Wi-Fi. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_0178rASQ6ZETPMUamvpoR2KR --- .../components/net/include/net/BleProvisioning.hpp | 10 +++++++--- Software/components/net/src/BleProvisioning.cpp | 12 +++++------- Software/partitions.csv | 14 ++++++++++---- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/Software/components/net/include/net/BleProvisioning.hpp b/Software/components/net/include/net/BleProvisioning.hpp index 84a7807..0a3595c 100644 --- a/Software/components/net/include/net/BleProvisioning.hpp +++ b/Software/components/net/include/net/BleProvisioning.hpp @@ -31,15 +31,19 @@ namespace net::ble_provisioning { * @dname start * @param store Secure store the received credentials are saved * to (same store POST /api/wifi writes to). - * @param deviceIdentity Supplies the BLE advertising name (softApSsid) - * and the proof-of-possession string (serialNumber). + * @param deviceIdentity Supplies the BLE advertising name (softApSsid). * @return Ok once provisioning is advertising, or NetError::BleProvisioningFailed. * @pubstate Starts the onboard ESP32-S3 BLE radio (independent of the BT1035 * UART module) and a process-lifetime wifi_provisioning manager * singleton. On a successful join, saves credentials to store and * reboots, mirroring wifiPostHandler's POST /api/wifi behaviour. * Runs alongside the existing SoftAP + HTTP provisioning route, - * not instead of it — either path can complete setup. + * not instead of it — either path can complete setup. Uses + * protocomm Security0 (no proof-of-possession, no encryption): + * a PoP derived from the BLE advertising name would be visible to + * anyone scanning anyway, so it added app/firmware coupling + * without adding real secrecy — same trust level as the open + * SoftAP setup path this runs alongside. * * @author Michele Bigi * @date 2026-08-18 diff --git a/Software/components/net/src/BleProvisioning.cpp b/Software/components/net/src/BleProvisioning.cpp index 9552c12..23ae3d9 100644 --- a/Software/components/net/src/BleProvisioning.cpp +++ b/Software/components/net/src/BleProvisioning.cpp @@ -125,10 +125,9 @@ start(core::ISecureStore& store, const core::DeviceIdentity& deviceIdentity) gStore = &store; gPendingCreds.reset(); - // Copies kept for the lifetime of provisioning: wifi_prov_mgr_start_ - // provisioning only borrows these pointers, it does not take ownership. + // Copy kept for the lifetime of provisioning: wifi_prov_mgr_start_ + // provisioning only borrows this pointer, it does not take ownership. static const std::string serviceName(deviceIdentity.softApSsid()); - static const std::string pop(deviceIdentity.serialNumber()); const wifi_prov_mgr_config_t config{ .scheme = wifi_prov_scheme_ble, @@ -141,7 +140,7 @@ start(core::ISecureStore& store, const core::DeviceIdentity& deviceIdentity) return std::unexpected(NetError::BleProvisioningFailed); } - if (wifi_prov_mgr_start_provisioning(WIFI_PROV_SECURITY_1, pop.c_str(), + if (wifi_prov_mgr_start_provisioning(WIFI_PROV_SECURITY_0, nullptr, serviceName.c_str(), nullptr) != ESP_OK) { ESP_LOGE(kTag, "wifi_prov_mgr_start_provisioning failed"); @@ -149,9 +148,8 @@ start(core::ISecureStore& store, const core::DeviceIdentity& deviceIdentity) return std::unexpected(NetError::BleProvisioningFailed); } - ESP_LOGI(kTag, - "BLE provisioning advertising as %s (proof-of-possession: " - "device serial number)", + ESP_LOGI(kTag, "BLE provisioning advertising as %s (no PoP, same trust " + "level as the open SoftAP)", serviceName.c_str()); return {}; } diff --git a/Software/partitions.csv b/Software/partitions.csv index 622266a..295e45b 100644 --- a/Software/partitions.csv +++ b/Software/partitions.csv @@ -3,11 +3,17 @@ # dsp: updatable ADAU1701 program blob (task 3.1). # nvs_keys: NVS encryption keys (secure-store slice). # First flash after this layout: idf.py erase-flash flash (wired), not OTA. +# nvs: bumped 24 KiB -> 64 KiB (2026-08-19) — the small original size was a +# suspected contributor to intermittent NvsAudioProfileStore::saveProfile() +# store_failed under this project's accumulated write traffic (wifi creds, +# station_list, audio_profile_json, last_preset). otadata/nvs_keys/phy_init +# shift forward to make room; they still fit before ota_0's existing 64 KiB +# alignment boundary (0x20000), so ota_0/ota_1/dsp offsets are unchanged. # Name, Type, SubType, Offset, Size, Flags -nvs, data, nvs, 0x9000, 0x6000, -otadata, data, ota, 0xf000, 0x2000, -nvs_keys, data, nvs_keys, 0x11000, 0x1000, -phy_init, data, phy, 0x12000, 0x1000, +nvs, data, nvs, 0x9000, 0x10000, +otadata, data, ota, 0x19000, 0x2000, +nvs_keys, data, nvs_keys, 0x1b000, 0x1000, +phy_init, data, phy, 0x1c000, 0x1000, ota_0, app, ota_0, 0x20000, 0x400000, ota_1, app, ota_1, 0x420000, 0x400000, dsp, data, 0x40, 0x820000, 0x40000,