sphinx-key: implement wifi reset

additional-author: evan feenstra

this is an access mode that expects just the wifi config params,
without the seed
This commit is contained in:
irriden
2023-08-01 19:50:37 +00:00
parent af5da5ef60
commit fe2b518a77
9 changed files with 161 additions and 44 deletions

View File

@@ -70,9 +70,9 @@ cd ../sphinx-key &&
if [ $MODE = "release" ]
then
cargo build --release
cargo build --release --bin sphinx-key
else
cargo build
cargo build --bin sphinx-key
fi &&
esptool.py --chip esp32-c3 elf2image ../target/riscv32imc-esp-espidf/$MODE/sphinx-key &&

View File

@@ -23,7 +23,8 @@ pub struct Params {
#[allow(unused_variables, deprecated)]
pub fn config_server(
mutex: Arc<(Mutex<Option<(Config, [u8; 32])>>, Condvar)>,
mutex: Arc<(Mutex<Option<(Config, Option<[u8; 32]>)>>, Condvar)>,
has_stored_seed: bool,
) -> Result<idf::Server> {
let (sk1, pk1) = ecdh_keypair();
@@ -47,6 +48,9 @@ pub fn config_server(
let dto = serde_json::from_str::<ConfigDTO>(&params.config)?;
let conf_seed_tuple = decrypt_seed(dto, sk1)?;
if !has_stored_seed && conf_seed_tuple.1.is_none() {
return Err(anyhow::anyhow!("seed required"));
}
let mut wait = mutex.0.lock().unwrap();
*wait = Some(conf_seed_tuple);

View File

@@ -33,14 +33,12 @@ pub fn start_client(
}))?;
info!("Wifi configured");
wifi.start()?;
info!("Wifi started");
wifi.connect()?;
info!("Wifi connected");
wifi.wait_netif_up()?;
info!("Wifi netif up");
let ip_info = wifi.wifi().sta_netif().get_ip_info()?;
info!("Wifi DHCP info: {:?}", ip_info);
loop {
match try_connection(&mut wifi) {
Ok(_) => break,
Err(e) => info!("error: {}, trying wifi connection again!", e),
}
}
// let status = wifi.get_status();
// println!("=> wifi STATUS {:?}", status);
@@ -66,6 +64,18 @@ pub fn start_client(
Ok(wifi)
}
fn try_connection(wifi: &mut BlockingWifi<EspWifi<'static>>) -> Result<()> {
wifi.start()?;
info!("Wifi started");
wifi.connect()?;
info!("Wifi connected");
wifi.wait_netif_up()?;
info!("Wifi netif up");
let ip_info = wifi.wifi().sta_netif().get_ip_info()?;
info!("Wifi DHCP info: {:?}", ip_info);
Ok(())
}
pub fn start_access_point(
modem: impl peripheral::Peripheral<P = esp_idf_hal::modem::Modem> + 'static,
default_nvs: EspDefaultNvsPartition,

View File

@@ -30,9 +30,9 @@ pub struct ConfigDTO {
pub broker: String,
pub ssid: String,
pub pass: String,
pub pubkey: String,
pub seed: String, // encrypted (56 bytes)
pub network: String,
pub pubkey: Option<String>,
pub seed: Option<String>, // encrypted (56 bytes)
}
/*
@@ -55,15 +55,20 @@ pub fn ecdh_keypair() -> (SecretKey, PublicKey) {
s.generate_keypair(&mut thread_rng())
}
pub fn decrypt_seed(dto: ConfigDTO, sk1: SecretKey) -> Result<(Config, [u8; 32])> {
let their_pk = hex::decode(dto.pubkey)?;
let their_pk_bytes: [u8; PUBLIC_KEY_LEN] = their_pk[..PUBLIC_KEY_LEN].try_into()?;
let shared_secret = derive_shared_secret_from_slice(their_pk_bytes, sk1.secret_bytes())?;
// decrypt seed
let cipher_seed = hex::decode(dto.seed)?;
let cipher: [u8; PAYLOAD_LEN] = cipher_seed[..PAYLOAD_LEN].try_into()?;
let seed = decrypt(cipher, shared_secret)?;
pub fn decrypt_seed(dto: ConfigDTO, sk1: SecretKey) -> Result<(Config, Option<[u8; 32]>)> {
let mut seed = None;
if let Some(pubkey) = dto.pubkey {
if let Some(seed_in) = dto.seed {
let their_pk = hex::decode(pubkey)?;
let their_pk_bytes: [u8; PUBLIC_KEY_LEN] = their_pk[..PUBLIC_KEY_LEN].try_into()?;
let shared_secret =
derive_shared_secret_from_slice(their_pk_bytes, sk1.secret_bytes())?;
// decrypt seed
let cipher_seed = hex::decode(seed_in)?;
let cipher: [u8; PAYLOAD_LEN] = cipher_seed[..PAYLOAD_LEN].try_into()?;
seed = Some(decrypt(cipher, shared_secret)?);
}
}
Ok((
Config {
broker: dto.broker,
@@ -78,18 +83,23 @@ pub fn decrypt_seed(dto: ConfigDTO, sk1: SecretKey) -> Result<(Config, [u8; 32])
pub fn start_config_server_and_wait(
modem: impl peripheral::Peripheral<P = esp_idf_hal::modem::Modem> + 'static,
default_nvs: EspDefaultNvsPartition,
) -> Result<(BlockingWifi<EspWifi<'static>>, Config, [u8; 32])> {
has_stored_seed: bool,
) -> Result<(BlockingWifi<EspWifi<'static>>, Config, Option<[u8; 32]>)> {
let mutex = Arc::new((Mutex::new(None), Condvar::new()));
#[allow(clippy::redundant_clone)]
#[allow(unused_mut)]
let mut wifi = conn::wifi::start_access_point(modem, default_nvs.clone())?;
let httpd = conn::http::config_server(mutex.clone());
let httpd = conn::http::config_server(mutex.clone(), has_stored_seed)?;
let mut wait = mutex.0.lock().unwrap();
log::info!("Waiting for data from the phone!");
if has_stored_seed {
log::info!("Waiting for wifi details from the phone!");
} else {
log::info!("Waiting for seed and data from the phone!");
}
let config_seed_tuple: &(Config, [u8; 32]) = loop {
let config_seed_tuple: &(Config, Option<[u8; 32]>) = loop {
if let Some(conf) = &*wait {
break conf;
} else {

View File

@@ -4,7 +4,8 @@ mod ota;
mod periph;
mod status;
use crate::core::control::{controller_from_seed, FlashPersister};
use crate::core::control::controller_from_seed;
pub use crate::core::control::FlashPersister;
use crate::core::{config::*, events::*};
use crate::periph::button::button_loop;
use crate::periph::led::led_control_loop;
@@ -43,11 +44,6 @@ fn main() -> Result<()> {
// LED control thread
led_control_loop(pins.gpio0, peripherals.rmt.channel0, led_rx);
// BUTTON thread
// button_loop(pins.gpio9, led_tx.clone());
// thread::sleep(Duration::from_secs(100));
led_tx.send(Status::MountingSDCard).unwrap();
println!("About to mount the sdcard...");
while let Err(_e) = mount_sd_card() {
@@ -59,12 +55,17 @@ fn main() -> Result<()> {
// let default_nav_partition = EspDefaultNvs.take().unwrap();
let default_nvs = EspDefaultNvsPartition::take()?;
// let default_nvs = Arc::new();
let mut flash = FlashPersister::new(default_nvs.clone());
let flash_per = FlashPersister::new(default_nvs.clone());
let flash_arc = Arc::new(Mutex::new(flash_per));
// BUTTON thread
button_loop(pins.gpio9, led_tx.clone(), flash_arc.clone());
let mut flash = flash_arc.lock().unwrap();
if let Ok(exist) = flash.read_config() {
let seed = flash.read_seed().expect("no seed...");
let id = flash.read_id().expect("no id...");
let policy = flash.read_policy().unwrap_or_default();
let velocity = flash.read_velocity().ok();
drop(flash);
println!(
"=============> START CLIENT NOW <============== {:?}",
exist
@@ -95,7 +96,6 @@ fn main() -> Result<()> {
led_tx.send(Status::ConnectingToMqtt).unwrap();
let flash_arc = Arc::new(Mutex::new(flash));
loop {
if let Ok(()) = make_and_launch_client(
exist.clone(),
@@ -116,13 +116,24 @@ fn main() -> Result<()> {
} else {
led_tx.send(Status::WifiAccessPoint).unwrap();
println!("=============> START SERVER NOW AND WAIT <==============");
match start_config_server_and_wait(peripherals.modem, default_nvs.clone()) {
Ok((_wifi, config, seed)) => {
let stored_seed = flash.read_seed().ok();
match start_config_server_and_wait(
peripherals.modem,
default_nvs.clone(),
stored_seed.is_some(),
) {
Ok((_wifi, config, seed_opt)) => {
flash.write_config(config).expect("could not store config");
flash.write_seed(seed).expect("could not store seed");
flash
.write_id(random_word(ID_LEN))
.expect("could not store id");
if stored_seed.is_none() {
match seed_opt {
Some(s) => flash.write_seed(s).expect("could not store seed"),
None => panic!("SEED REQUIRED!!!"),
}
flash
.write_id(random_word(ID_LEN))
.expect("could not store id");
}
drop(flash);
println!("CONFIG SAVED");
unsafe { esp_idf_sys::esp_restart() };
}

View File

@@ -1,7 +1,9 @@
use crate::status::Status;
use crate::FlashPersister;
use esp_idf_hal::gpio;
use esp_idf_hal::gpio::*;
use std::sync::mpsc;
use sphinx_signer::sphinx_glyph::control::ControlPersist;
use std::sync::{mpsc, Arc, Mutex};
use std::thread;
use std::time::Duration;
@@ -11,7 +13,11 @@ const PAUSE: u16 = 50;
// progression is waiting -> *starting -> reset1a -> reset1 -> reset2a -> reset2 -> reset3
// state machine initialized at starting
pub fn button_loop(gpio9: gpio::Gpio9, tx: mpsc::Sender<Status>) {
pub fn button_loop(
gpio9: gpio::Gpio9,
tx: mpsc::Sender<Status>,
flash_arc: Arc<Mutex<FlashPersister>>,
) {
thread::spawn(move || {
let mut button = PinDriver::input(gpio9).unwrap();
button.set_pull(Pull::Up).unwrap();
@@ -21,6 +27,17 @@ pub fn button_loop(gpio9: gpio::Gpio9, tx: mpsc::Sender<Status>) {
let mut machine = Machine::new(tx, Status::Starting);
loop {
// we are using thread::sleep here to make sure the watchdog isn't triggered
if machine.state == Status::Reset3 {
let mut flash = flash_arc.lock().unwrap();
if let Err(_e) = flash.remove_config() {
log::error!("could not clear wifi config");
drop(flash);
} else {
log::info!("restarting esp!");
drop(flash);
unsafe { esp_idf_sys::esp_restart() };
}
}
thread::sleep(Duration::from_millis(PAUSE.into()));
if button.is_high() {
if pressed {

View File

@@ -64,9 +64,9 @@ then
fi
if [ $MODE = "release" ]
then
cargo build --release
cargo build --release --bin sphinx-key
else
cargo build
cargo build --bin sphinx-key
fi &&
esptool.py --chip esp32-c3 elf2image ../target/riscv32imc-esp-espidf/$MODE/sphinx-key &&
esptool.py --chip esp32c3 -b 460800 --before=default_reset --after=hard_reset write_flash --flash_mode dio --flash_freq 40m --flash_size 4MB 0x90000 ../target/riscv32imc-esp-espidf/$MODE/sphinx-key.bin &&

View File

@@ -33,6 +33,10 @@ sphinx-crypter = { git = "https://github.com/stakwork/sphinx-rs.git" }
name = "config"
path = "src/config.rs"
[[bin]]
name = "wifi"
path = "src/wifi.rs"
[[bin]]
name = "config-server"
path = "src/server.rs"

61
tester/src/wifi.rs Normal file
View File

@@ -0,0 +1,61 @@
use dotenv::dotenv;
use serde::{Deserialize, Serialize};
use std::env;
use std::time::Duration;
use sphinx_signer::sphinx_glyph::control::Config;
const URL: &str = "http://192.168.71.1";
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ConfigResponse {
pub success: bool,
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
dotenv().ok();
let url: String = env::var("URL").unwrap_or(URL.to_string());
let ssid: String = env::var("SSID").expect("no ssid");
let pass: String = env::var("PASS").expect("no pass");
let broker: String = env::var("BROKER").expect("no broker");
let network: String = env::var("NETWORK").unwrap_or("regtest".to_string());
if !(network == "bitcoin"
|| network == "mainnet"
|| network == "testnet"
|| network == "signet"
|| network == "regtest")
{
panic!("invalid network string");
}
println!("network {:?}", network);
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(10))
.build()
.expect("couldnt build reqwest client");
let config = Config {
ssid,
pass,
broker,
network,
};
let conf_string = serde_json::to_string(&config)?;
let conf_encoded = urlencoding::encode(&conf_string).to_owned();
let res = client
.post(format!("{}/{}={}", url, "config?config", conf_encoded))
.send()
.await?;
let conf_res: ConfigResponse = res.json().await?;
if conf_res.success {
println!("SUCCESS!")
}
Ok(())
}